1
- use std:: { collections :: BTreeMap , fs, io:: Cursor , path:: Path } ;
1
+ use std:: { fs, io:: Cursor , path:: Path } ;
2
2
3
3
use anyhow:: { anyhow, bail, ensure, Context , Result } ;
4
4
use byteorder:: { BigEndian , ReadBytesExt } ;
@@ -111,6 +111,7 @@ fn filter_sections(obj_file: &File<'_>, split_meta: Option<&SplitMeta>) -> Resul
111
111
symbols : Vec :: new ( ) ,
112
112
relocations : Vec :: new ( ) ,
113
113
virtual_address,
114
+ line_info : Default :: default ( ) ,
114
115
} ) ;
115
116
}
116
117
result. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
@@ -268,26 +269,40 @@ fn relocations_by_section(
268
269
Ok ( relocations)
269
270
}
270
271
271
- fn line_info ( obj_file : & File < ' _ > ) -> Result < Option < BTreeMap < u64 , u64 > > > {
272
+ fn line_info ( obj_file : & File < ' _ > , sections : & mut [ ObjSection ] ) -> Result < ( ) > {
272
273
// DWARF 1.1
273
- let mut map = BTreeMap :: new ( ) ;
274
274
if let Some ( section) = obj_file. section_by_name ( ".line" ) {
275
- if section. size ( ) == 0 {
276
- return Ok ( None ) ;
277
- }
278
275
let data = section. uncompressed_data ( ) ?;
279
276
let mut reader = Cursor :: new ( data. as_ref ( ) ) ;
280
277
281
- let size = reader. read_u32 :: < BigEndian > ( ) ?;
282
- let base_address = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
283
- while reader. position ( ) < size as u64 {
284
- let line_number = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
285
- let statement_pos = reader. read_u16 :: < BigEndian > ( ) ?;
286
- if statement_pos != 0xFFFF {
287
- log:: warn!( "Unhandled statement pos {}" , statement_pos) ;
278
+ let mut text_sections = obj_file. sections ( ) . filter ( |s| s. kind ( ) == SectionKind :: Text ) ;
279
+ while reader. position ( ) < data. len ( ) as u64 {
280
+ let text_section_index = text_sections
281
+ . next ( )
282
+ . ok_or_else ( || anyhow ! ( "Next text section not found for line info" ) ) ?
283
+ . index ( )
284
+ . 0 ;
285
+ let start = reader. position ( ) ;
286
+ let size = reader. read_u32 :: < BigEndian > ( ) ?;
287
+ let base_address = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
288
+ let Some ( out_section) =
289
+ sections. iter_mut ( ) . find ( |s| s. orig_index == text_section_index)
290
+ else {
291
+ // Skip line info for sections we filtered out
292
+ reader. set_position ( start + size as u64 ) ;
293
+ continue ;
294
+ } ;
295
+ let end = start + size as u64 ;
296
+ while reader. position ( ) < end {
297
+ let line_number = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
298
+ let statement_pos = reader. read_u16 :: < BigEndian > ( ) ?;
299
+ if statement_pos != 0xFFFF {
300
+ log:: warn!( "Unhandled statement pos {}" , statement_pos) ;
301
+ }
302
+ let address_delta = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
303
+ out_section. line_info . insert ( base_address + address_delta, line_number) ;
304
+ log:: debug!( "Line: {:#x} -> {}" , base_address + address_delta, line_number) ;
288
305
}
289
- let address_delta = reader. read_u32 :: < BigEndian > ( ) ? as u64 ;
290
- map. insert ( base_address + address_delta, line_number) ;
291
306
}
292
307
}
293
308
@@ -308,22 +323,48 @@ fn line_info(obj_file: &File<'_>) -> Result<Option<BTreeMap<u64, u64>>> {
308
323
} ;
309
324
let dwarf = dwarf_cow. borrow ( |section| gimli:: EndianSlice :: new ( section, endian) ) ;
310
325
let mut iter = dwarf. units ( ) ;
311
- while let Some ( header) = iter. next ( ) ? {
326
+ if let Some ( header) = iter. next ( ) ? {
312
327
let unit = dwarf. unit ( header) ?;
313
328
if let Some ( program) = unit. line_program . clone ( ) {
329
+ let mut text_sections =
330
+ obj_file. sections ( ) . filter ( |s| s. kind ( ) == SectionKind :: Text ) ;
331
+ let section_index = text_sections
332
+ . next ( )
333
+ . ok_or_else ( || anyhow ! ( "Next text section not found for line info" ) ) ?
334
+ . index ( )
335
+ . 0 ;
336
+ let mut lines = sections
337
+ . iter_mut ( )
338
+ . find ( |s| s. orig_index == section_index)
339
+ . map ( |s| & mut s. line_info ) ;
340
+
314
341
let mut rows = program. rows ( ) ;
315
342
while let Some ( ( _header, row) ) = rows. next_row ( ) ? {
316
- if let Some ( line) = row. line ( ) {
317
- map. insert ( row. address ( ) , line. get ( ) ) ;
343
+ if let ( Some ( line) , Some ( lines) ) = ( row. line ( ) , & mut lines) {
344
+ lines. insert ( row. address ( ) , line. get ( ) ) ;
345
+ }
346
+ if row. end_sequence ( ) {
347
+ // The next row is the start of a new sequence, which means we must
348
+ // advance to the next .text section.
349
+ let section_index = text_sections
350
+ . next ( )
351
+ . ok_or_else ( || anyhow ! ( "Next text section not found for line info" ) ) ?
352
+ . index ( )
353
+ . 0 ;
354
+ lines = sections
355
+ . iter_mut ( )
356
+ . find ( |s| s. orig_index == section_index)
357
+ . map ( |s| & mut s. line_info ) ;
318
358
}
319
359
}
320
360
}
321
361
}
362
+ if iter. next ( ) ?. is_some ( ) {
363
+ log:: warn!( "Multiple units found in DWARF data, only processing the first" ) ;
364
+ }
322
365
}
323
- if map. is_empty ( ) {
324
- return Ok ( None ) ;
325
- }
326
- Ok ( Some ( map) )
366
+
367
+ Ok ( ( ) )
327
368
}
328
369
329
370
pub fn read ( obj_path : & Path ) -> Result < ObjInfo > {
@@ -342,16 +383,9 @@ pub fn read(obj_path: &Path) -> Result<ObjInfo> {
342
383
section. relocations =
343
384
relocations_by_section ( arch. as_ref ( ) , & obj_file, section, split_meta. as_ref ( ) ) ?;
344
385
}
386
+ line_info ( & obj_file, & mut sections) ?;
345
387
let common = common_symbols ( arch. as_ref ( ) , & obj_file, split_meta. as_ref ( ) ) ?;
346
- Ok ( ObjInfo {
347
- arch,
348
- path : obj_path. to_owned ( ) ,
349
- timestamp,
350
- sections,
351
- common,
352
- line_info : line_info ( & obj_file) ?,
353
- split_meta,
354
- } )
388
+ Ok ( ObjInfo { arch, path : obj_path. to_owned ( ) , timestamp, sections, common, split_meta } )
355
389
}
356
390
357
391
pub fn has_function ( obj_path : & Path , symbol_name : & str ) -> Result < bool > {
0 commit comments