@@ -152,6 +152,7 @@ impl<R: gimli::Reader> Context<R> {
152152 pub fn from_sections (
153153 debug_abbrev : gimli:: DebugAbbrev < R > ,
154154 debug_addr : gimli:: DebugAddr < R > ,
155+ debug_aranges : gimli:: DebugAranges < R > ,
155156 debug_info : gimli:: DebugInfo < R > ,
156157 debug_line : gimli:: DebugLine < R > ,
157158 debug_line_str : gimli:: DebugLineStr < R > ,
@@ -164,7 +165,7 @@ impl<R: gimli::Reader> Context<R> {
164165 Self :: from_dwarf ( gimli:: Dwarf {
165166 debug_abbrev,
166167 debug_addr,
167- debug_aranges : default_section . clone ( ) . into ( ) ,
168+ debug_aranges,
168169 debug_info,
169170 debug_line,
170171 debug_line_str,
@@ -370,6 +371,16 @@ struct ResDwarf<R: gimli::Reader> {
370371
371372impl < R : gimli:: Reader > ResDwarf < R > {
372373 fn parse ( sections : Arc < gimli:: Dwarf < R > > ) -> Result < Self , Error > {
374+ // Find all the references to compilation units in .debug_aranges.
375+ // Note that we always also iterate through all of .debug_info to
376+ // find compilation units, because .debug_aranges may be missing some.
377+ let mut aranges = Vec :: new ( ) ;
378+ let mut headers = sections. debug_aranges . headers ( ) ;
379+ while let Some ( header) = headers. next ( ) ? {
380+ aranges. push ( ( header. debug_info_offset ( ) , header. offset ( ) ) ) ;
381+ }
382+ aranges. sort_by_key ( |i| i. 0 ) ;
383+
373384 let mut unit_ranges = Vec :: new ( ) ;
374385 let mut res_units = Vec :: new ( ) ;
375386 let mut units = sections. units ( ) ;
@@ -426,13 +437,54 @@ impl<R: gimli::Reader> ResDwarf<R> {
426437 }
427438 }
428439
429- ranges. for_each_range ( & sections, & dw_unit, |range| {
430- unit_ranges. push ( UnitRange {
431- range,
432- unit_id,
433- max_end : 0 ,
434- } ) ;
435- } ) ?;
440+ // Find the address ranges for the CU, using in order of preference:
441+ // - DW_AT_ranges
442+ // - .debug_aranges
443+ // - DW_AT_low_pc/DW_AT_high_pc
444+ //
445+ // Using DW_AT_ranges before .debug_aranges is possibly an arbitrary choice,
446+ // but the feeling is that DW_AT_ranges is more likely to be reliable or complete
447+ // if it is present.
448+ //
449+ // .debug_aranges must be used before DW_AT_low_pc/DW_AT_high_pc because
450+ // it has been observed on macOS that DW_AT_ranges was not emitted even for
451+ // discontiguous CUs.
452+ let i = match ranges. ranges_offset {
453+ Some ( _) => None ,
454+ None => aranges. binary_search_by_key ( & offset, |x| x. 0 ) . ok ( ) ,
455+ } ;
456+ if let Some ( mut i) = i {
457+ // There should be only one set per CU, but in practice multiple
458+ // sets have been observed. This is probably a compiler bug, but
459+ // either way we need to handle it.
460+ while i > 0 && aranges[ i - 1 ] . 0 == offset {
461+ i -= 1 ;
462+ }
463+ for ( _, aranges_offset) in aranges[ i..] . iter ( ) . take_while ( |x| x. 0 == offset) {
464+ let aranges_header = sections. debug_aranges . header ( * aranges_offset) ?;
465+ let mut aranges = aranges_header. entries ( ) ;
466+ while let Some ( arange) = aranges. next ( ) ? {
467+ // Ignore unrelocated ranges (e.g. the function was eliminated
468+ // when linking).
469+ // TODO: allow this if there is a section at address zero.
470+ if arange. address ( ) != 0 && arange. length ( ) != 0 {
471+ unit_ranges. push ( UnitRange {
472+ range : arange. range ( ) ,
473+ unit_id,
474+ max_end : 0 ,
475+ } ) ;
476+ }
477+ }
478+ }
479+ } else {
480+ ranges. for_each_range ( & sections, & dw_unit, |range| {
481+ unit_ranges. push ( UnitRange {
482+ range,
483+ unit_id,
484+ max_end : 0 ,
485+ } ) ;
486+ } ) ?;
487+ }
436488 }
437489
438490 res_units. push ( ResUnit {
0 commit comments