11//! Map the IDB data we parsed into the [`BinaryView`].
22
3- use crate :: parse:: { CommentInfo , FunctionInfo , IDBInfo , LabelInfo , NameInfo , SegmentInfo } ;
3+ use crate :: parse:: {
4+ BaseAddressInfo , CommentInfo , ExportInfo , FunctionInfo , IDBInfo , LabelInfo , NameInfo ,
5+ SegmentInfo ,
6+ } ;
47use crate :: translate:: TILTranslator ;
58use binaryninja:: architecture:: Architecture ;
69use binaryninja:: binary_view:: { BinaryView , BinaryViewBase , BinaryViewExt } ;
710use binaryninja:: qualified_name:: QualifiedName ;
811use binaryninja:: rc:: Ref ;
912use binaryninja:: section:: { SectionBuilder , Semantics } ;
10- use binaryninja:: symbol:: { Symbol , SymbolType } ;
13+ use binaryninja:: symbol:: { Binding , Symbol , SymbolType } ;
1114use binaryninja:: types:: Type ;
1215use idb_rs:: id0:: SegmentType ;
16+ use idb_rs:: til:: TypeVariant ;
1317use std:: collections:: HashSet ;
1418
1519/// Maps IDB data into a [`BinaryView`].
@@ -36,8 +40,28 @@ impl IDBMapper {
3640
3741 // Rebase the address from ida -> binja without this rebased views will fail to map.
3842 let bn_base_address = view. start ( ) ;
39- let ida_base_address = id0. base_address . unwrap_or ( bn_base_address) ;
40- let base_address_delta = bn_base_address. wrapping_sub ( ida_base_address) ;
43+ let base_address_delta = match id0. base_address {
44+ // There is no base address in the IDA file, so we assume everything is relative and rebase.
45+ BaseAddressInfo :: None => bn_base_address,
46+ BaseAddressInfo :: BaseSegment ( start_addr) => bn_base_address. wrapping_sub ( start_addr) ,
47+ BaseAddressInfo :: BaseSection ( section_addr) => {
48+ let bn_section_addr = view
49+ . sections ( )
50+ . iter ( )
51+ . min_by_key ( |s| s. start ( ) )
52+ . map ( |s| s. start ( ) ) ;
53+ match bn_section_addr {
54+ Some ( bn_section) => bn_section. wrapping_sub ( section_addr) ,
55+ None => bn_base_address,
56+ }
57+ }
58+ } ;
59+
60+ tracing:: debug!(
61+ "Rebasing for {:0x} with delta {:0x}" ,
62+ bn_base_address,
63+ base_address_delta
64+ ) ;
4165 let rebase = |addr : u64 | -> u64 { addr. wrapping_add ( base_address_delta) } ;
4266
4367 for segment in & id0. segments {
@@ -70,10 +94,16 @@ impl IDBMapper {
7094 self . map_func_to_view ( view, & til_translator, & rebased_func) ;
7195 }
7296
97+ for export in & id0. exports {
98+ let mut rebased_export = export. clone ( ) ;
99+ rebased_export. address = rebase ( export. address ) ;
100+ self . map_export_to_view ( view, & til_translator, & rebased_export) ;
101+ }
102+
73103 // TODO: The below undo and ignore is not thread safe, this means that the mapper itself
74104 // TODO: should be the only thing running at the time of the mapping process.
75105 let undo = view. file ( ) . begin_undo_actions ( true ) ;
76- for comment in & id0 . comments {
106+ for comment in & self . info . merged_comments ( ) {
77107 let mut rebased_comment = comment. clone ( ) ;
78108 rebased_comment. address = rebase ( comment. address ) ;
79109 self . map_comment_to_view ( view, & rebased_comment) ;
@@ -103,11 +133,11 @@ impl IDBMapper {
103133 }
104134 match til_translator. translate_type_info ( & ty. tinfo ) {
105135 Ok ( bn_ty) => {
106- tracing:: debug!( "Mapping type: {:? }" , ty) ;
136+ tracing:: debug!( "Mapping type: {}" , ty. name ) ;
107137 view. define_auto_type ( & ty_name, "IDA" , & bn_ty) ;
108138 }
109139 Err ( err) => {
110- tracing:: warn!( "Failed to map type {:? }: {}" , ty, err)
140+ tracing:: warn!( "Failed to map type {}: {}" , ty. name , err)
111141 }
112142 }
113143 }
@@ -183,6 +213,11 @@ impl IDBMapper {
183213 pub fn map_segment_to_view ( & self , view : & BinaryView , segment : & SegmentInfo ) {
184214 let semantics = match segment. ty {
185215 SegmentType :: Norm => Semantics :: DefaultSection ,
216+ // One issue is that an IDA section named 'extern' is _actually_ a synthetic section, so we
217+ // should not map it.
218+ SegmentType :: Xtrn if segment. name == "extern" => {
219+ return ;
220+ }
186221 SegmentType :: Xtrn => {
187222 // IDA definition of extern is an actual section like '.idata' whereas extern in BN
188223 // is a synthetic section, do NOT use [`Semantics::External`].
@@ -226,12 +261,62 @@ impl IDBMapper {
226261 view. add_section ( section) ;
227262 }
228263
264+ pub fn map_export_to_view (
265+ & self ,
266+ view : & BinaryView ,
267+ til_translator : & TILTranslator ,
268+ export : & ExportInfo ,
269+ ) {
270+ let within_code_section = view
271+ . sections_at ( export. address )
272+ . iter ( )
273+ . find ( |s| s. semantics ( ) == Semantics :: ReadOnlyCode )
274+ . is_some ( ) ;
275+ let is_func_ty = export
276+ . ty
277+ . as_ref ( )
278+ . is_some_and ( |ty| matches ! ( ty. type_variant, TypeVariant :: Function ( _) ) ) ;
279+
280+ if within_code_section && is_func_ty {
281+ tracing:: debug!( "Mapping function export: {:0x}" , export. address) ;
282+ let func_info = FunctionInfo {
283+ name : Some ( export. name . clone ( ) ) ,
284+ ty : export. ty . clone ( ) ,
285+ address : export. address ,
286+ is_library : false ,
287+ is_no_return : false ,
288+ } ;
289+ self . map_func_to_view ( view, til_translator, & func_info) ;
290+ } else {
291+ tracing:: debug!( "Mapping data export: {:0x}" , export. address) ;
292+ let name_info = NameInfo {
293+ label : Some ( export. name . clone ( ) ) ,
294+ ty : export. ty . clone ( ) ,
295+ address : export. address ,
296+ exported : true ,
297+ } ;
298+ self . map_name_to_view ( view, til_translator, & name_info) ;
299+ }
300+ }
301+
229302 pub fn map_func_to_view (
230303 & self ,
231304 view : & BinaryView ,
232305 til_translator : & TILTranslator ,
233306 func : & FunctionInfo ,
234307 ) {
308+ // We need to skip things that hit the extern section, since they do not have a bearing in the
309+ // actual context of the binary, and can be derived differently between IDA and Binja.
310+ let within_extern_section = view
311+ . sections_at ( func. address )
312+ . iter ( )
313+ . find ( |s| s. semantics ( ) == Semantics :: External )
314+ . is_some ( ) ;
315+ if within_extern_section {
316+ tracing:: debug!( "Skipping function in extern section: {:0x}" , func. address) ;
317+ return ;
318+ }
319+
235320 let Some ( bn_func) = view. add_auto_function ( func. address ) else {
236321 tracing:: warn!( "Failed to add function for {:0x}" , func. address) ;
237322 return ;
@@ -277,6 +362,18 @@ impl IDBMapper {
277362 til_translator : & TILTranslator ,
278363 name : & NameInfo ,
279364 ) {
365+ // We need to skip things that hit the extern section, since they do not have a bearing in the
366+ // actual context of the binary, and can be derived differently between IDA and Binja.
367+ let within_extern_section = view
368+ . sections_at ( name. address )
369+ . iter ( )
370+ . find ( |s| s. semantics ( ) == Semantics :: External )
371+ . is_some ( ) ;
372+ if within_extern_section {
373+ tracing:: debug!( "Skipping name in extern section: {:0x}" , name. address) ;
374+ return ;
375+ }
376+
280377 // Currently, we only want to use name info to map data variables, so skip anything in code.
281378 let within_code_section = view
282379 . sections_at ( name. address )
@@ -289,7 +386,13 @@ impl IDBMapper {
289386 }
290387
291388 if let Some ( label) = & name. label {
292- let symbol = Symbol :: builder ( SymbolType :: Data , & label, name. address ) . create ( ) ;
389+ let binding = name
390+ . exported
391+ . then_some ( Binding :: Global )
392+ . unwrap_or ( Binding :: None ) ;
393+ let symbol = Symbol :: builder ( SymbolType :: Data , & label, name. address )
394+ . binding ( binding)
395+ . create ( ) ;
293396 tracing:: debug!( "Mapping name label: {:0x} => {}" , name. address, symbol) ;
294397 view. define_auto_symbol ( & symbol) ;
295398 }
0 commit comments