@@ -8,7 +8,6 @@ use nom::bytes::complete::{tag, take_while};
8
8
use nom:: character:: complete:: { hex_digit1, space1} ;
9
9
use nom:: combinator:: { cut, map_res, opt, rest} ;
10
10
use nom:: error:: { Error , ErrorKind , ParseError } ;
11
- use nom:: multi:: separated_list1;
12
11
use nom:: sequence:: { terminated, tuple} ;
13
12
use nom:: { Err , IResult } ;
14
13
use object:: ReadRef ;
@@ -406,17 +405,18 @@ impl BreakpadFuncSymbol {
406
405
let first_line = read_line_and_advance ( & mut input) ;
407
406
let ( _rest, ( _address, size, name) ) =
408
407
func_line ( first_line) . map_err ( |_| BreakpadParseError :: ParsingFunc ) ?;
408
+
409
+ let mut tokenizer = Tokenizer :: new ( input) ;
409
410
let mut inlinees = Vec :: new ( ) ;
410
411
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) {
418
417
lines. push ( line_data) ;
419
418
}
419
+ tokenizer. consume_until_after_next_line_break_or_eof ( ) ;
420
420
}
421
421
inlinees. sort_unstable_by_key ( |inlinee| ( inlinee. depth , inlinee. address ) ) ;
422
422
Ok ( BreakpadFuncSymbolInfo {
@@ -988,22 +988,20 @@ pub struct Inlinee {
988
988
// Matches line data after a FUNC record.
989
989
///
990
990
/// 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
+ } )
1007
1005
}
1008
1006
1009
1007
// Matches a FUNC record.
@@ -1019,36 +1017,106 @@ fn func_line(input: &[u8]) -> IResult<&[u8], (u32, u32, &[u8])> {
1019
1017
Ok ( ( input, ( address, size, name) ) )
1020
1018
}
1021
1019
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
+ }
1025
1081
}
1026
1082
1027
- // Matches an INLINE record.
1083
+ // Matches an INLINE record, after the INLINE token .
1028
1084
///
1029
1085
/// 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 ( ( ) )
1052
1120
}
1053
1121
1054
1122
#[ cfg( test) ]
0 commit comments