@@ -32,9 +32,7 @@ use binaryninja::{
3232 settings:: Settings ,
3333 template_simplifier:: simplify_str_to_str,
3434} ;
35- use dwarfreader:: {
36- create_section_reader, get_endian, is_dwo_dwarf, is_non_dwo_dwarf, is_raw_dwo_dwarf,
37- } ;
35+ use dwarfreader:: { create_section_reader_object, get_endian, is_dwo_dwarf, is_non_dwo_dwarf} ;
3836
3937use functions:: parse_lexical_block;
4038use gimli:: {
@@ -46,6 +44,7 @@ use binaryninja::logger::Logger;
4644use helpers:: { get_build_id, load_debug_info_for_build_id} ;
4745use iset:: IntervalMap ;
4846use log:: { debug, error, warn} ;
47+ use object:: { Object , ObjectSection } ;
4948
5049trait ReaderType : Reader < Offset = usize > { }
5150impl < T : Reader < Offset = usize > > ReaderType for T { }
@@ -388,48 +387,30 @@ fn parse_unit<R: ReaderType>(
388387}
389388
390389fn parse_unwind_section < R : Reader , U : UnwindSection < R > > (
391- view : & BinaryView ,
390+ file : & object :: File ,
392391 unwind_section : U ,
393392) -> gimli:: Result < iset:: IntervalMap < u64 , i64 > >
394393where
395394 <U as UnwindSection < R > >:: Offset : std:: hash:: Hash ,
396395{
397396 let mut bases = gimli:: BaseAddresses :: default ( ) ;
398397
399- // DWARF info is stored relative to the original image base (0 for relocatable images), normalize entries to the original image base
400- let section_adjustment = view. original_image_base ( ) . wrapping_sub ( view. image_base ( ) ) ;
401-
402- if let Some ( section) = view
403- . section_by_name ( ".eh_frame_hdr" )
404- . or ( view. section_by_name ( "__eh_frame_hdr" ) )
405- {
406- bases = bases. set_eh_frame_hdr ( section. start ( ) . wrapping_add ( section_adjustment) ) ;
398+ if let Some ( section) = file. section_by_name ( ".eh_frame_hdr" ) {
399+ bases = bases. set_eh_frame_hdr ( section. address ( ) ) ;
407400 }
408401
409- if let Some ( section) = view
410- . section_by_name ( ".eh_frame" )
411- . or ( view. section_by_name ( "__eh_frame" ) )
412- {
413- bases = bases. set_eh_frame ( section. start ( ) . wrapping_add ( section_adjustment) ) ;
414- } else if let Some ( section) = view
415- . section_by_name ( ".debug_frame" )
416- . or ( view. section_by_name ( "__debug_frame" ) )
417- {
418- bases = bases. set_eh_frame ( section. start ( ) . wrapping_add ( section_adjustment) ) ;
402+ if let Some ( section) = file. section_by_name ( ".eh_frame" ) {
403+ bases = bases. set_eh_frame ( section. address ( ) ) ;
404+ } else if let Some ( section) = file. section_by_name ( ".debug_frame" ) {
405+ bases = bases. set_eh_frame ( section. address ( ) ) ;
419406 }
420407
421- if let Some ( section) = view
422- . section_by_name ( ".text" )
423- . or ( view. section_by_name ( "__text" ) )
424- {
425- bases = bases. set_text ( section. start ( ) . wrapping_add ( section_adjustment) ) ;
408+ if let Some ( section) = file. section_by_name ( ".text" ) {
409+ bases = bases. set_text ( section. address ( ) ) ;
426410 }
427411
428- if let Some ( section) = view
429- . section_by_name ( ".got" )
430- . or ( view. section_by_name ( "__got" ) )
431- {
432- bases = bases. set_got ( section. start ( ) . wrapping_add ( section_adjustment) ) ;
412+ if let Some ( section) = file. section_by_name ( ".got" ) {
413+ bases = bases. set_got ( section. address ( ) ) ;
433414 }
434415
435416 let mut cies = HashMap :: new ( ) ;
@@ -535,58 +516,49 @@ fn get_supplementary_build_id(bv: &BinaryView) -> Option<String> {
535516 }
536517}
537518
538- fn parse_range_data_offsets (
539- bv : & BinaryView ,
540- dwo_file : bool ,
541- ) -> Option < Result < IntervalMap < u64 , i64 > , ( ) > > {
542- if bv. section_by_name ( ".eh_frame" ) . is_some ( ) || bv. section_by_name ( "__eh_frame" ) . is_some ( ) {
543- let eh_frame_endian = get_endian ( bv) ;
544- let eh_frame_section_reader = |section_id : SectionId | -> _ {
545- create_section_reader ( section_id, bv, eh_frame_endian, dwo_file)
546- } ;
547- let mut eh_frame = match gimli:: EhFrame :: load ( eh_frame_section_reader) {
548- Ok ( x) => x,
549- Err ( e) => {
550- log:: error!( "Failed to load EH frame: {}" , e) ;
551- return None ;
552- }
553- } ;
554- if let Some ( view_arch) = bv. default_arch ( ) {
555- if view_arch. name ( ) . as_str ( ) == "aarch64" {
556- eh_frame. set_vendor ( gimli:: Vendor :: AArch64 ) ;
557- }
519+ fn parse_range_data_offsets ( bv : & BinaryView ) -> Result < IntervalMap < u64 , i64 > , String > {
520+ let raw_view = bv. raw_view ( ) . unwrap ( ) ;
521+ let raw_view_data = raw_view. read_vec ( 0 , raw_view. len ( ) as usize ) ;
522+ let file =
523+ object:: File :: parse ( & * raw_view_data) . map_err ( |e| format ! ( "Failed to parse bv: {}" , e) ) ?;
524+ let dwo_file = file. section_by_name ( ".debug_info.dwo" ) . is_some ( ) ;
525+ let endian = match file. endianness ( ) {
526+ object:: Endianness :: Little => gimli:: RunTimeEndian :: Little ,
527+ object:: Endianness :: Big => gimli:: RunTimeEndian :: Big ,
528+ } ;
529+
530+ let section_reader = |section_id : SectionId | -> _ {
531+ create_section_reader_object ( section_id, & file, endian, dwo_file)
532+ } ;
533+
534+ if file. section_by_name ( ".eh_frame" ) . is_some ( ) {
535+ let mut eh_frame = gimli:: EhFrame :: load ( section_reader)
536+ . map_err ( |e| format ! ( "Failed to load EH frame: {}" , e) ) ?;
537+
538+ if file. architecture ( ) == object:: Architecture :: Aarch64 {
539+ eh_frame. set_vendor ( gimli:: Vendor :: AArch64 ) ;
558540 }
559- eh_frame. set_address_size ( bv. address_size ( ) as u8 ) ;
560- Some (
561- parse_unwind_section ( bv, eh_frame)
562- . map_err ( |e| error ! ( "Error parsing .eh_frame: {}" , e) ) ,
563- )
564- } else if bv. section_by_name ( ".debug_frame" ) . is_some ( )
565- || bv. section_by_name ( "__debug_frame" ) . is_some ( )
566- {
567- let debug_frame_endian = get_endian ( bv) ;
568- let debug_frame_section_reader = |section_id : SectionId | -> _ {
569- create_section_reader ( section_id, bv, debug_frame_endian, dwo_file)
570- } ;
571- let mut debug_frame = match gimli:: DebugFrame :: load ( debug_frame_section_reader) {
572- Ok ( x) => x,
573- Err ( e) => {
574- log:: error!( "Failed to load debug frame: {}" , e) ;
575- return None ;
576- }
577- } ;
578- if let Some ( view_arch) = bv. default_arch ( ) {
579- if view_arch. name ( ) . as_str ( ) == "aarch64" {
580- debug_frame. set_vendor ( gimli:: Vendor :: AArch64 ) ;
581- }
541+
542+ if let Some ( address_size) = file. architecture ( ) . address_size ( ) {
543+ eh_frame. set_address_size ( address_size. bytes ( ) ) ;
582544 }
583- debug_frame. set_address_size ( bv. address_size ( ) as u8 ) ;
584- Some (
585- parse_unwind_section ( bv, debug_frame)
586- . map_err ( |e| error ! ( "Error parsing .debug_frame: {}" , e) ) ,
587- )
545+
546+ parse_unwind_section ( & file, eh_frame) . map_err ( |e| format ! ( "Error parsing .eh_frame: {}" , e) )
547+ } else if file. section_by_name ( ".debug_frame" ) . is_some ( ) {
548+ let mut debug_frame = gimli:: DebugFrame :: load ( section_reader)
549+ . map_err ( |e| format ! ( "Failed to load debug frame: {}" , e) ) ?;
550+
551+ if file. architecture ( ) == object:: Architecture :: Aarch64 {
552+ debug_frame. set_vendor ( gimli:: Vendor :: AArch64 ) ;
553+ }
554+
555+ if let Some ( address_size) = file. architecture ( ) . address_size ( ) {
556+ debug_frame. set_address_size ( address_size. bytes ( ) ) ;
557+ }
558+ parse_unwind_section ( & file, debug_frame)
559+ . map_err ( |e| format ! ( "Error parsing .debug_frame: {}" , e) )
588560 } else {
589- None
561+ Ok ( Default :: default ( ) )
590562 }
591563}
592564
@@ -595,75 +567,75 @@ fn parse_dwarf(
595567 debug_bv : & BinaryView ,
596568 supplementary_bv : Option < & BinaryView > ,
597569 progress : Box < dyn Fn ( usize , usize ) -> Result < ( ) , ( ) > > ,
598- ) -> Result < DebugInfoBuilder , ( ) > {
570+ ) -> Result < DebugInfoBuilder , String > {
599571 // TODO: warn if no supplementary file and .gnu_debugaltlink section present
600572
601573 // Determine if this is a DWO
602574 // TODO : Make this more robust...some DWOs follow non-DWO conventions
603575
604576 // Figure out if it's the given view or the raw view that has the dwarf info in it
605- let raw_view = & debug_bv. raw_view ( ) . ok_or ( ( ) ) ?;
606- let view = if is_dwo_dwarf ( debug_bv) || is_non_dwo_dwarf ( debug_bv) {
607- debug_bv
577+ let raw_view = & debug_bv
578+ . raw_view ( )
579+ . ok_or ( "Failed to get raw view for debug binary view" . to_string ( ) ) ?;
580+
581+ let address_size = if is_dwo_dwarf ( debug_bv) || is_non_dwo_dwarf ( debug_bv) {
582+ debug_bv. address_size ( )
608583 } else {
609- raw_view
584+ raw_view. address_size ( )
610585 } ;
611586
612- let dwo_file = is_dwo_dwarf ( view) || is_raw_dwo_dwarf ( view) ;
613-
614- // gimli setup
615- let endian = get_endian ( view) ;
616- let mut section_reader =
617- |section_id : SectionId | -> _ { create_section_reader ( section_id, view, endian, dwo_file) } ;
587+ // Parse this early to reduce peak memory usage
588+ let range_data_offsets = parse_range_data_offsets ( bv) . unwrap_or_default ( ) ;
589+
590+ // Read the raw view to an object::File so relocations get handled for us
591+ let raw_view_data = raw_view. read_vec ( 0 , raw_view. len ( ) as usize ) ;
592+ let debug_file =
593+ object:: File :: parse ( & * raw_view_data) . map_err ( |e| format ! ( "Failed to parse bv: {}" , e) ) ?;
594+ let dwo_file = debug_file. section_by_name ( ".debug_info.dwo" ) . is_some ( ) ;
595+ let endian = match debug_file. endianness ( ) {
596+ object:: Endianness :: Little => gimli:: RunTimeEndian :: Little ,
597+ object:: Endianness :: Big => gimli:: RunTimeEndian :: Big ,
598+ } ;
618599
619- let mut dwarf = match Dwarf :: load ( & mut section_reader) {
620- Ok ( x) => x,
621- Err ( e) => {
622- error ! ( "Failed to load DWARF info: {}" , e) ;
623- return Err ( ( ) ) ;
624- }
600+ let mut section_reader = |section_id : SectionId | -> _ {
601+ create_section_reader_object ( section_id, & debug_file, endian, dwo_file)
625602 } ;
626603
604+ let mut dwarf = Dwarf :: load ( & mut section_reader)
605+ . map_err ( |e| format ! ( "Failed to load DWARF info: {}" , e) ) ?;
606+
627607 if dwo_file {
628608 dwarf. file_type = DwarfFileType :: Dwo ;
629609 } else {
630610 dwarf. file_type = DwarfFileType :: Main ;
631611 }
632612
633613 if let Some ( sup_bv) = supplementary_bv {
614+ let sup_raw_view = sup_bv
615+ . raw_view ( )
616+ . ok_or_else ( || format ! ( "Failed to get raw view for supplementary bv" ) ) ?;
617+ let sup_view_data = sup_raw_view. read_vec ( 0 , sup_raw_view. len ( ) as usize ) ;
618+ let sup_file = object:: File :: parse ( & * sup_view_data)
619+ . map_err ( |e| format ! ( "Failed to parse supplementary bv: {}" , e) ) ?;
634620 let sup_endian = get_endian ( sup_bv) ;
635- let sup_dwo_file = is_dwo_dwarf ( sup_bv ) || is_raw_dwo_dwarf ( sup_bv ) ;
621+ let sup_dwo_file = sup_file . section_by_name ( ".debug_info.dwo" ) . is_some ( ) ;
636622 let sup_section_reader = |section_id : SectionId | -> _ {
637- create_section_reader ( section_id, sup_bv , sup_endian, sup_dwo_file)
623+ create_section_reader_object ( section_id, & sup_file , sup_endian, sup_dwo_file)
638624 } ;
639625 if let Err ( e) = dwarf. load_sup ( sup_section_reader) {
640626 error ! ( "Failed to load supplementary file: {}" , e) ;
641627 }
642628 }
643629
644- let range_data_offsets = match parse_range_data_offsets ( bv, dwo_file) {
645- Some ( x) => x?,
646- None => {
647- if let Some ( raw_view) = bv. raw_view ( ) {
648- if let Some ( offsets) = parse_range_data_offsets ( & raw_view, dwo_file) {
649- offsets?
650- } else {
651- Default :: default ( )
652- }
653- } else {
654- Default :: default ( )
655- }
656- }
657- } ;
658-
659630 // Create debug info builder and recover name mapping first
660631 // Since DWARF is stored as a tree with arbitrary implicit edges among leaves,
661632 // it is not possible to correctly track namespaces while you're parsing "in order" without backtracking,
662633 // so we just do it up front
663634 let mut debug_info_builder = DebugInfoBuilder :: new ( ) ;
664635 debug_info_builder. set_range_data_offsets ( range_data_offsets) ;
665636
666- if let Some ( mut debug_info_builder_context) = DebugInfoBuilderContext :: new ( view, & dwarf) {
637+ if let Some ( mut debug_info_builder_context) = DebugInfoBuilderContext :: new ( address_size, & dwarf)
638+ {
667639 calculate_total_unit_bytes ( & dwarf, & mut debug_info_builder_context) ;
668640
669641 let progress_weights = [ 0.5 , 0.5 ] ;
@@ -770,7 +742,10 @@ impl CustomDebugInfoParser for DWARFParser {
770742 builder. post_process ( bv, debug_info) . commit_info ( debug_info) ;
771743 true
772744 }
773- Err ( _) => false ,
745+ Err ( e) => {
746+ log:: error!( "Failed to parse DWARF: {}" , e) ;
747+ false
748+ }
774749 } ;
775750
776751 if let ( Some ( ext) , true ) = ( external_file, close_external) {
0 commit comments