Skip to content

Commit 6dd377c

Browse files
committed
Reduce use of nom.
1 parent 9bad613 commit 6dd377c

File tree

1 file changed

+118
-50
lines changed

1 file changed

+118
-50
lines changed

samply-symbols/src/breakpad/index.rs

Lines changed: 118 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use nom::bytes::complete::{tag, take_while};
88
use nom::character::complete::{hex_digit1, space1};
99
use nom::combinator::{cut, map_res, opt, rest};
1010
use nom::error::{Error, ErrorKind, ParseError};
11-
use nom::multi::separated_list1;
1211
use nom::sequence::{terminated, tuple};
1312
use nom::{Err, IResult};
1413
use object::ReadRef;
@@ -406,17 +405,18 @@ impl BreakpadFuncSymbol {
406405
let first_line = read_line_and_advance(&mut input);
407406
let (_rest, (_address, size, name)) =
408407
func_line(first_line).map_err(|_| BreakpadParseError::ParsingFunc)?;
408+
409+
let mut tokenizer = Tokenizer::new(input);
409410
let mut inlinees = Vec::new();
410411
let mut lines = Vec::new();
411-
while !input.is_empty() {
412-
let line = read_line_and_advance(&mut input);
413-
if line.starts_with(b"INLINE ") {
414-
let (_rest, new_inlinees) =
415-
inline_line(line).map_err(|_| BreakpadParseError::ParsingInline)?;
416-
inlinees.extend(new_inlinees);
417-
} else if let Ok((_rest, line_data)) = func_line_data(line) {
412+
while !tokenizer.eof() {
413+
if tokenizer.consume_token(b"INLINE").is_ok() {
414+
parse_inline_line_remainder(&mut tokenizer, &mut inlinees)
415+
.map_err(|_| BreakpadParseError::ParsingInline)?;
416+
} else if let Ok(line_data) = parse_func_data_line(&mut tokenizer) {
418417
lines.push(line_data);
419418
}
419+
tokenizer.consume_until_after_next_line_break_or_eof();
420420
}
421421
inlinees.sort_unstable_by_key(|inlinee| (inlinee.depth, inlinee.address));
422422
Ok(BreakpadFuncSymbolInfo {
@@ -988,22 +988,20 @@ pub struct Inlinee {
988988
// Matches line data after a FUNC record.
989989
///
990990
/// A line record has the form <hex_addr> <hex_size> <line> <file_id>
991-
fn func_line_data(input: &[u8]) -> IResult<&[u8], SourceLine> {
992-
let (input, (address, size, line, file)) = tuple((
993-
terminated(hex_str::<u64>, space1),
994-
terminated(hex_str::<u32>, space1),
995-
terminated(decimal_u32, space1),
996-
decimal_u32,
997-
))(input)?;
998-
Ok((
999-
input,
1000-
SourceLine {
1001-
address: address as u32,
1002-
size,
1003-
file,
1004-
line,
1005-
},
1006-
))
991+
fn parse_func_data_line(tokenizer: &mut Tokenizer) -> Result<SourceLine, ()> {
992+
let address = tokenizer.consume_hex_u64()?;
993+
tokenizer.consume_space1()?;
994+
let size = tokenizer.consume_hex_u32()?;
995+
tokenizer.consume_space1()?;
996+
let line = tokenizer.consume_decimal_u32()?;
997+
tokenizer.consume_space1()?;
998+
let file = tokenizer.consume_decimal_u32()?;
999+
Ok(SourceLine {
1000+
address: address as u32,
1001+
size,
1002+
file,
1003+
line,
1004+
})
10071005
}
10081006

10091007
// Matches a FUNC record.
@@ -1019,36 +1017,106 @@ fn func_line(input: &[u8]) -> IResult<&[u8], (u32, u32, &[u8])> {
10191017
Ok((input, (address, size, name)))
10201018
}
10211019

1022-
// Matches one entry of the form <address> <size> which is used at the end of an INLINE record
1023-
fn inline_address_range(input: &[u8]) -> IResult<&[u8], (u32, u32)> {
1024-
tuple((terminated(hex_str::<u32>, space1), hex_str::<u32>))(input)
1020+
struct Tokenizer<'a> {
1021+
input: &'a [u8],
1022+
}
1023+
1024+
impl<'a> Tokenizer<'a> {
1025+
pub fn new(input: &'a [u8]) -> Self {
1026+
Self { input }
1027+
}
1028+
1029+
pub fn consume_token(&mut self, token: &[u8]) -> Result<(), ()> {
1030+
if self.input.starts_with(token) {
1031+
self.input = &self.input[token.len()..];
1032+
Ok(())
1033+
} else {
1034+
Err(())
1035+
}
1036+
}
1037+
1038+
pub fn consume_decimal_u32(&mut self) -> Result<u32, ()> {
1039+
let (rest, num) = decimal_u32(self.input).map_err(|_| ())?;
1040+
self.input = rest;
1041+
Ok(num)
1042+
}
1043+
1044+
pub fn consume_hex_u32(&mut self) -> Result<u32, ()> {
1045+
let (rest, num) = hex_str::<u32>(self.input).map_err(|_| ())?;
1046+
self.input = rest;
1047+
Ok(num)
1048+
}
1049+
1050+
pub fn consume_hex_u64(&mut self) -> Result<u64, ()> {
1051+
let (rest, num) = hex_str::<u64>(self.input).map_err(|_| ())?;
1052+
self.input = rest;
1053+
Ok(num)
1054+
}
1055+
1056+
pub fn consume_space1(&mut self) -> Result<(), ()> {
1057+
let Some((first_byte, mut input)) = self.input.split_first() else {
1058+
return Err(());
1059+
};
1060+
if *first_byte != b' ' {
1061+
return Err(());
1062+
}
1063+
while let Some((first_byte, rest)) = input.split_first() {
1064+
if *first_byte == b' ' {
1065+
input = rest;
1066+
} else {
1067+
break;
1068+
}
1069+
}
1070+
self.input = input;
1071+
Ok(())
1072+
}
1073+
1074+
pub fn eof(&self) -> bool {
1075+
self.input.is_empty()
1076+
}
1077+
1078+
pub fn consume_until_after_next_line_break_or_eof(&mut self) {
1079+
let _discarded = read_line_and_advance(&mut self.input);
1080+
}
10251081
}
10261082

1027-
// Matches an INLINE record.
1083+
// Matches an INLINE record, after the INLINE token.
10281084
///
10291085
/// An INLINE record has the form `INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id> [<address> <size>]+`.
1030-
fn inline_line(input: &[u8]) -> IResult<&[u8], impl Iterator<Item = Inlinee>> {
1031-
let (input, _) = terminated(tag("INLINE"), space1)(input)?;
1032-
let (input, (depth, call_line, call_file, origin_id)) = cut(tuple((
1033-
terminated(decimal_u32, space1),
1034-
terminated(decimal_u32, space1),
1035-
terminated(decimal_u32, space1),
1036-
terminated(decimal_u32, space1),
1037-
)))(input)?;
1038-
let (input, address_ranges) = cut(separated_list1(space1, inline_address_range))(input)?;
1039-
Ok((
1040-
input,
1041-
address_ranges
1042-
.into_iter()
1043-
.map(move |(address, size)| Inlinee {
1044-
address,
1045-
size,
1046-
call_file,
1047-
call_line,
1048-
depth,
1049-
origin_id,
1050-
}),
1051-
))
1086+
fn parse_inline_line_remainder(
1087+
tokenizer: &mut Tokenizer,
1088+
inlinees: &mut Vec<Inlinee>,
1089+
) -> Result<(), ()> {
1090+
tokenizer.consume_space1()?;
1091+
let depth = tokenizer.consume_decimal_u32()?;
1092+
tokenizer.consume_space1()?;
1093+
let call_line = tokenizer.consume_decimal_u32()?;
1094+
tokenizer.consume_space1()?;
1095+
let call_file = tokenizer.consume_decimal_u32()?;
1096+
tokenizer.consume_space1()?;
1097+
let origin_id = tokenizer.consume_decimal_u32()?;
1098+
tokenizer.consume_space1()?;
1099+
1100+
loop {
1101+
// <address> <size>
1102+
let address = tokenizer.consume_hex_u32()?;
1103+
tokenizer.consume_space1()?;
1104+
let size = tokenizer.consume_hex_u32()?;
1105+
inlinees.push(Inlinee {
1106+
depth,
1107+
address,
1108+
size,
1109+
call_file,
1110+
call_line,
1111+
origin_id,
1112+
});
1113+
1114+
match tokenizer.consume_space1() {
1115+
Ok(_) => continue,
1116+
Err(_) => break,
1117+
}
1118+
}
1119+
Ok(())
10521120
}
10531121

10541122
#[cfg(test)]

0 commit comments

Comments
 (0)