11mod types;
2- use idb_rs:: { IDAKind , IDAUsize } ;
2+ use std:: borrow:: Cow ;
3+ use std:: io:: { BufRead , Cursor , Seek } ;
4+
5+ use idb_rs:: id1:: ID1Section ;
6+ use idb_rs:: id2:: { ID2Section , ID2SectionVariants } ;
7+ use idb_rs:: { IDAKind , IDAUsize , IDBFormat } ;
38use types:: * ;
49mod addr_info;
510use addr_info:: * ;
@@ -9,13 +14,13 @@ use binaryninja::debuginfo::{
914 CustomDebugInfoParser , DebugFunctionInfo , DebugInfo , DebugInfoParser ,
1015} ;
1116
12- use idb_rs:: id0:: { ID0Section , IDBParam1 , IDBParam2 } ;
17+ use idb_rs:: id0:: { ID0Section , ID0SectionVariants } ;
1318use idb_rs:: til:: section:: TILSection ;
1419use idb_rs:: til:: TypeVariant as TILTypeVariant ;
1520
1621use log:: { error, trace, warn, LevelFilter } ;
1722
18- use anyhow:: Result ;
23+ use anyhow:: { anyhow , Result } ;
1924use binaryninja:: logger:: Logger ;
2025
2126struct IDBDebugInfoParser ;
@@ -81,9 +86,12 @@ struct BinaryViewReader<'a> {
8186impl std:: io:: Read for BinaryViewReader < ' _ > {
8287 fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
8388 if !self . bv . offset_valid ( self . offset ) {
84- return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: UnexpectedEof , "" ) ) ;
89+ return Err ( std:: io:: Error :: new (
90+ std:: io:: ErrorKind :: UnexpectedEof ,
91+ "Unable to read at the current offset in BinaryViewReader" ,
92+ ) ) ;
8593 }
86- let len = BinaryView :: read ( & self . bv , buf, self . offset ) ;
94+ let len = BinaryView :: read ( self . bv , buf, self . offset ) ;
8795 self . offset += u64:: try_from ( len) . unwrap ( ) ;
8896 Ok ( len)
8997 }
@@ -96,10 +104,17 @@ impl std::io::Seek for BinaryViewReader<'_> {
96104 std:: io:: SeekFrom :: End ( end) => self . bv . len ( ) . checked_add_signed ( end) ,
97105 std:: io:: SeekFrom :: Current ( next) => self . offset . checked_add_signed ( next) ,
98106 } ;
99- let new_offset =
100- new_offset. ok_or_else ( || std:: io:: Error :: new ( std:: io:: ErrorKind :: UnexpectedEof , "" ) ) ?;
107+ let new_offset = new_offset. ok_or_else ( || {
108+ std:: io:: Error :: new (
109+ std:: io:: ErrorKind :: UnexpectedEof ,
110+ "Unable to calculate new offset in BinaryViewReader" ,
111+ )
112+ } ) ?;
101113 if !self . bv . offset_valid ( new_offset) {
102- return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: UnexpectedEof , "" ) ) ;
114+ return Err ( std:: io:: Error :: new (
115+ std:: io:: ErrorKind :: UnexpectedEof ,
116+ "Try to set invalid offset in BinaryViewReader" ,
117+ ) ) ;
103118 }
104119 self . offset = new_offset;
105120 Ok ( new_offset)
@@ -118,27 +133,73 @@ fn parse_idb_info(
118133 offset : 0 ,
119134 } ;
120135 trace ! ( "Parsing a IDB file" ) ;
121- let file = std:: io:: BufReader :: new ( file) ;
122- let mut parser = idb_rs:: IDBParserVariants :: new ( file) ?;
123- if let Some ( til_section) = parser. til_section_offset ( ) {
136+ let mut file = std:: io:: BufReader :: new ( file) ;
137+ let idb_kind = idb_rs:: identify_idb_file ( & mut file) ?;
138+ match idb_kind {
139+ idb_rs:: IDBFormats :: Separated ( sep) => {
140+ parse_idb_info_format ( debug_info, bv, debug_file, sep, file, progress)
141+ }
142+ idb_rs:: IDBFormats :: InlineUncompressed ( inline) => {
143+ parse_idb_info_format ( debug_info, bv, debug_file, inline, file, progress)
144+ }
145+ idb_rs:: IDBFormats :: InlineCompressed ( compressed) => {
146+ let mut buf = vec ! [ ] ;
147+ let inline = compressed. decompress_into_memory ( & mut file, & mut buf) ?;
148+ parse_idb_info_format (
149+ debug_info,
150+ bv,
151+ debug_file,
152+ inline,
153+ Cursor :: new ( & buf[ ..] ) ,
154+ progress,
155+ )
156+ }
157+ }
158+ }
159+
160+ fn parse_idb_info_format (
161+ debug_info : & mut DebugInfo ,
162+ bv : & BinaryView ,
163+ debug_file : & BinaryView ,
164+ format : impl IDBFormat ,
165+ mut idb_data : impl BufRead + Seek ,
166+ progress : Box < dyn Fn ( usize , usize ) -> Result < ( ) , ( ) > > ,
167+ ) -> Result < ( ) > {
168+ let Some ( id0_idx) = format. id0_location ( ) else {
169+ return Err ( anyhow ! ( "Unable to find the ID0 section" ) ) ;
170+ } ;
171+ let Some ( id1_idx) = format. id1_location ( ) else {
172+ return Err ( anyhow ! ( "Unable to find the ID1 section" ) ) ;
173+ } ;
174+ let id2_idx = format. id2_location ( ) ;
175+
176+ if let Some ( til_idx) = format. til_location ( ) {
124177 trace ! ( "Parsing the TIL section" ) ;
125- let til = parser . read_til_section ( til_section ) ?;
178+ let til = format . read_til ( & mut idb_data , til_idx ) ?;
126179 // progress 0%-50%
127180 import_til_section ( debug_info, debug_file, & til, progress) ?;
128- }
181+ } ;
129182
130- if let Some ( id0_section) = parser. id0_section_offset ( ) {
131- trace ! ( "Parsing the ID0 section" ) ;
132- let id0 = parser. read_id0_section ( id0_section) ?;
133- // progress 50%-100%
134- match id0 {
135- idb_rs:: IDAVariants :: IDA32 ( id0) => {
136- parse_id0_section_info :: < idb_rs:: IDA32 > ( debug_info, bv, debug_file, & id0) ?
137- }
138- idb_rs:: IDAVariants :: IDA64 ( id0) => {
139- parse_id0_section_info :: < idb_rs:: IDA64 > ( debug_info, bv, debug_file, & id0) ?
140- }
183+ let id0 = format. read_id0 ( & mut idb_data, id0_idx) ?;
184+ let id1 = format. read_id1 ( & mut idb_data, id1_idx) ?;
185+ let id2 = id2_idx
186+ . map ( |id2_idx| format. read_id2 ( & mut idb_data, id2_idx) )
187+ . transpose ( ) ?;
188+
189+ match ( id0, id2) {
190+ ( ID0SectionVariants :: IDA32 ( id0) , Some ( ID2SectionVariants :: IDA32 ( id2) ) ) => {
191+ parse_id0_section_info ( debug_info, bv, debug_file, & id0, & id1, Some ( & id2) ) ?
192+ }
193+ ( ID0SectionVariants :: IDA32 ( id0) , None ) => {
194+ parse_id0_section_info ( debug_info, bv, debug_file, & id0, & id1, None ) ?
195+ }
196+ ( ID0SectionVariants :: IDA64 ( id0) , Some ( ID2SectionVariants :: IDA64 ( id2) ) ) => {
197+ parse_id0_section_info ( debug_info, bv, debug_file, & id0, & id1, Some ( & id2) ) ?
141198 }
199+ ( ID0SectionVariants :: IDA64 ( id0) , None ) => {
200+ parse_id0_section_info ( debug_info, bv, debug_file, & id0, & id1, None ) ?
201+ }
202+ _ => unreachable ! ( ) ,
142203 }
143204
144205 Ok ( ( ) )
@@ -231,23 +292,20 @@ fn parse_id0_section_info<K: IDAKind>(
231292 bv : & BinaryView ,
232293 debug_file : & BinaryView ,
233294 id0 : & ID0Section < K > ,
295+ id1 : & ID1Section ,
296+ id2 : Option < & ID2Section < K > > ,
234297) -> Result < ( ) > {
235- let ( version, idb_baseaddr) = match id0. ida_info ( ) ? {
236- idb_rs:: id0:: IDBParam :: V1 ( IDBParam1 {
237- version, baseaddr, ..
238- } )
239- | idb_rs:: id0:: IDBParam :: V2 ( IDBParam2 {
240- version, baseaddr, ..
241- } ) => ( version, baseaddr. into_u64 ( ) ) ,
242- } ;
243-
298+ let ida_info_idx = id0. root_node ( ) ?;
299+ let ida_info = id0. ida_info ( ida_info_idx) ?;
300+ let idb_baseaddr = ida_info. addresses . loading_base . into_u64 ( ) ;
244301 let bv_baseaddr = bv. start ( ) ;
302+ let netdelta = ida_info. netdelta ( ) ;
245303 // just addr this value to the address to translate from ida to bn
246- // NOTE this delta could wrapp here and while using translating
304+ // NOTE this delta could wrap here and while using translating
247305 let addr_delta = bv_baseaddr. wrapping_sub ( idb_baseaddr) ;
248306
249- for ( idb_addr, info) in get_info ( id0, version ) ? {
250- let addr = addr_delta. wrapping_add ( idb_addr. into_u64 ( ) ) ;
307+ for ( idb_addr, info) in get_info ( id0, id1 , id2 , netdelta ) ? {
308+ let addr = addr_delta. wrapping_add ( idb_addr. into_raw ( ) . into_u64 ( ) ) ;
251309 // just in case we change this struct in the future, this line will for us to review this code
252310 // TODO merge this data with folder locations
253311 let AddrInfo {
@@ -279,6 +337,8 @@ fn parse_id0_section_info<K: IDAKind>(
279337 }
280338 } ) ;
281339
340+ let label: Option < Cow < ' _ , str > > =
341+ label. as_ref ( ) . map ( Cow :: as_ref) . map ( String :: from_utf8_lossy) ;
282342 match ( label, & ty, bnty) {
283343 ( label, Some ( ty) , bnty) if matches ! ( & ty. type_variant, TILTypeVariant :: Function ( _) ) => {
284344 if bnty. is_none ( ) {
@@ -287,7 +347,7 @@ fn parse_id0_section_info<K: IDAKind>(
287347 if !debug_info. add_function ( & DebugFunctionInfo :: new (
288348 None ,
289349 None ,
290- label. map ( |x| x . to_string ( ) ) ,
350+ label. map ( Cow :: into_owned ) ,
291351 bnty,
292352 Some ( addr) ,
293353 None ,
@@ -298,15 +358,15 @@ fn parse_id0_section_info<K: IDAKind>(
298358 }
299359 }
300360 ( label, Some ( _ty) , Some ( bnty) ) => {
301- let label : Option < & str > = label. as_ref ( ) . map ( |x| x . as_ref ( ) ) ;
302- if !debug_info . add_data_variable ( addr , & bnty , label , & [ ] ) {
361+ if !debug_info . add_data_variable ( addr , & bnty , label. as_ref ( ) . map ( Cow :: as_ref) , & [ ] )
362+ {
303363 error ! ( "Unable to add the type at {addr:#x}" )
304364 }
305365 }
306366 ( label, Some ( _ty) , None ) => {
307367 // TODO types come from the TIL sections, can we make all types be just NamedTypes?
308368 error ! ( "Unable to convert type {addr:#x}" ) ;
309- // TODO how to add a label without a type associacted with it?
369+ // TODO how to add a label without a type associated with it?
310370 if let Some ( name) = label {
311371 if !debug_info. add_data_variable (
312372 addr,
@@ -319,7 +379,7 @@ fn parse_id0_section_info<K: IDAKind>(
319379 }
320380 }
321381 ( Some ( name) , None , None ) => {
322- // TODO how to add a label without a type associacted with it?
382+ // TODO how to add a label without a type associated with it?
323383 if !debug_info. add_data_variable (
324384 addr,
325385 & binaryninja:: types:: Type :: void ( ) ,
0 commit comments