11mod types;
2+ use std:: path:: Path ;
3+
4+ use binaryninja:: command:: Command ;
5+ use binaryninja:: type_library:: TypeLibrary ;
6+ use binaryninja:: types:: QualifiedName ;
27use types:: * ;
38mod addr_info;
49use addr_info:: * ;
@@ -14,7 +19,7 @@ use idb_rs::til::TypeVariant as TILTypeVariant;
1419
1520use log:: { error, trace, warn, LevelFilter } ;
1621
17- use anyhow:: Result ;
22+ use anyhow:: { anyhow , Context , Result } ;
1823use binaryninja:: logger:: Logger ;
1924
2025struct IDBDebugInfoParser ;
@@ -59,11 +64,11 @@ impl CustomDebugInfoParser for TILDebugInfoParser {
5964 fn parse_info (
6065 & self ,
6166 debug_info : & mut DebugInfo ,
62- _bv : & BinaryView ,
67+ bv : & BinaryView ,
6368 debug_file : & BinaryView ,
6469 progress : Box < dyn Fn ( usize , usize ) -> Result < ( ) , ( ) > > ,
6570 ) -> bool {
66- match parse_til_info ( debug_info, debug_file, progress) {
71+ match parse_til_info ( debug_info, bv , debug_file, progress) {
6772 Ok ( ( ) ) => true ,
6873 Err ( error) => {
6974 error ! ( "Unable to parse TIL file: {error}" ) ;
@@ -73,6 +78,20 @@ impl CustomDebugInfoParser for TILDebugInfoParser {
7378 }
7479}
7580
81+ struct LoadTilFile ;
82+
83+ impl Command for LoadTilFile {
84+ fn action ( & self , view : & BinaryView ) {
85+ if let Err ( error) = interactive_import_til ( view) {
86+ error ! ( "Unable to convert TIL file: {error}" ) ;
87+ }
88+ }
89+
90+ fn valid ( & self , _view : & BinaryView ) -> bool {
91+ true
92+ }
93+ }
94+
7695struct BinaryViewReader < ' a > {
7796 bv : & ' a BinaryView ,
7897 offset : u64 ,
@@ -119,13 +138,26 @@ fn parse_idb_info(
119138 trace ! ( "Parsing a IDB file" ) ;
120139 let file = std:: io:: BufReader :: new ( file) ;
121140 let mut parser = idb_rs:: IDBParser :: new ( file) ?;
141+
142+ let default_arch = bv
143+ . default_arch ( )
144+ . ok_or_else ( || anyhow ! ( "Unable to get the default arch" ) ) ?;
145+ let filename = debug_file. file ( ) . filename ( ) ;
146+ let mut type_lib = TypeLibrary :: new ( default_arch, filename) ;
147+
122148 if let Some ( til_section) = parser. til_section_offset ( ) {
149+ // TODO handle dependency, create a function for that with closures
123150 trace ! ( "Parsing the TIL section" ) ;
124151 let til = parser. read_til_section ( til_section) ?;
125152 // progress 0%-50%
126- import_til_section ( debug_info , debug_file, & til, progress) ?;
153+ import_til_section ( & mut type_lib , debug_file, & til, progress) ?;
127154 }
128155
156+ if !type_lib. finalize ( ) {
157+ return Err ( anyhow ! ( "Unable to finalize TypeLibrary" ) ) ;
158+ } ;
159+ bv. add_type_library ( & type_lib) ;
160+
129161 if let Some ( id0_section) = parser. id0_section_offset ( ) {
130162 trace ! ( "Parsing the ID0 section" ) ;
131163 let id0 = parser. read_id0_section ( id0_section) ?;
@@ -137,7 +169,8 @@ fn parse_idb_info(
137169}
138170
139171fn parse_til_info (
140- debug_info : & mut DebugInfo ,
172+ _debug_info : & mut DebugInfo ,
173+ bv : & BinaryView ,
141174 debug_file : & BinaryView ,
142175 progress : Box < dyn Fn ( usize , usize ) -> Result < ( ) , ( ) > > ,
143176) -> Result < ( ) > {
@@ -147,21 +180,103 @@ fn parse_til_info(
147180 offset : 0 ,
148181 } ;
149182 let mut file = std:: io:: BufReader :: new ( file) ;
183+
184+ let default_arch = bv
185+ . default_arch ( )
186+ . ok_or_else ( || anyhow ! ( "Unable to get the default arch" ) ) ?;
187+ let filename = debug_file. file ( ) . filename ( ) ;
188+ let mut type_lib = TypeLibrary :: new ( default_arch, filename) ;
189+
150190 trace ! ( "Parsing the TIL section" ) ;
151191 let til = TILSection :: read ( & mut file, idb_rs:: IDBSectionCompression :: None ) ?;
152- import_til_section ( debug_info, debug_file, & til, progress)
192+ // TODO handle dependency, create a function for that with closures
193+ import_til_section ( & mut type_lib, debug_file, & til, progress) ?;
194+
195+ if !type_lib. finalize ( ) {
196+ return Err ( anyhow ! ( "Unable to finalize TypeLibrary" ) ) ;
197+ } ;
198+ bv. add_type_library ( & type_lib) ;
199+ Ok ( ( ) )
153200}
154201
155- pub fn import_til_section (
156- debug_info : & mut DebugInfo ,
157- debug_file : & BinaryView ,
202+ fn interactive_import_til ( view : & BinaryView ) -> Result < ( ) > {
203+ let Some ( file) =
204+ binaryninja:: interaction:: get_open_filename_input ( "Select a .til file" , "*.til" )
205+ else {
206+ return Ok ( ( ) ) ;
207+ } ;
208+
209+ let default_arch = view
210+ . default_arch ( )
211+ . ok_or_else ( || anyhow ! ( "Unable to get the default arch" ) ) ?;
212+ let filename = file. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ;
213+ let mut type_lib = TypeLibrary :: new ( default_arch, filename) ;
214+
215+ interactive_import_til_file ( file. as_path ( ) , view, & mut type_lib) ?;
216+ if !type_lib. finalize ( ) {
217+ return Err ( anyhow ! ( "Unable to finalize TypeLibrary" ) ) ;
218+ } ;
219+ view. add_type_library ( & type_lib) ;
220+ Ok ( ( ) )
221+ }
222+
223+ fn interactive_import_til_file (
224+ file : & Path ,
225+ view : & BinaryView ,
226+ type_library : & mut TypeLibrary ,
227+ ) -> Result < ( ) > {
228+ // TODO create a background task to not freeze bn, also create a progress
229+ // user interface feedback
230+ let file = std:: fs:: File :: open ( file) ?;
231+ let mut file = std:: io:: BufReader :: new ( file) ;
232+ let til = TILSection :: read ( & mut file, idb_rs:: IDBSectionCompression :: None ) ?;
233+ for dep in & til. header . dependencies {
234+ let name = dep. as_utf8_lossy ( ) ;
235+ let message = format ! ( "Select the dependency \" {name}.til\" " , ) ;
236+ let Some ( dep_file) = binaryninja:: interaction:: get_open_filename_input ( & message, "*.til" )
237+ else {
238+ return Err ( anyhow ! ( "Unable to get the dependency {name}" ) ) ;
239+ } ;
240+
241+ interactive_import_til_file ( dep_file. as_path ( ) , view, type_library)
242+ . context ( "While importing dependency {name}" ) ?;
243+ }
244+
245+ fn dummy_progress ( _: usize , _: usize ) -> Result < ( ) , ( ) > {
246+ Ok ( ( ) )
247+ }
248+ import_til_section ( type_library, view, & til, dummy_progress)
249+ }
250+
251+ fn import_til_section (
252+ type_library : & mut TypeLibrary ,
253+ view : & BinaryView ,
158254 til : & TILSection ,
159255 progress : impl Fn ( usize , usize ) -> Result < ( ) , ( ) > ,
160256) -> Result < ( ) > {
161- let types = types:: translate_til_types ( debug_file. default_arch ( ) . unwrap ( ) , til, progress) ?;
257+ let default_arch = view
258+ . default_arch ( )
259+ . ok_or_else ( || anyhow ! ( "Unable to get the default arch" ) ) ?;
260+ let types = types:: translate_til_types ( default_arch, til, progress) ?;
162261
163262 // print any errors
263+ print_til_convertsion_errors ( & types) ;
264+
265+ // add all type to the type library
164266 for ty in & types {
267+ if let TranslateTypeResult :: Translated ( bn_ty)
268+ | TranslateTypeResult :: PartiallyTranslated ( bn_ty, _) = & ty. ty
269+ {
270+ let name = QualifiedName :: new ( vec ! [ ty. name. as_utf8_lossy( ) . to_string( ) ] ) ;
271+ type_library. add_named_type ( name, & bn_ty) ;
272+ }
273+ }
274+
275+ Ok ( ( ) )
276+ }
277+
278+ fn print_til_convertsion_errors ( types : & [ TranslatesIDBType ] ) {
279+ for ty in types {
165280 match & ty. ty {
166281 TranslateTypeResult :: NotYet => {
167282 panic ! (
@@ -179,7 +294,7 @@ pub fn import_til_section(
179294 TranslateTypeResult :: PartiallyTranslated ( _, error) => {
180295 if let Some ( error) = error {
181296 error ! (
182- "Unable to parse type `{}` correctly : {error}" ,
297+ "Unable to correctly parse type `{}`: {error}" ,
183298 ty. name. as_utf8_lossy( ) ,
184299 ) ;
185300 } else {
@@ -192,30 +307,6 @@ pub fn import_til_section(
192307 TranslateTypeResult :: Translated ( _) => { }
193308 } ;
194309 }
195-
196- // add all type to binary ninja
197- for ty in & types {
198- if let TranslateTypeResult :: Translated ( bn_ty)
199- | TranslateTypeResult :: PartiallyTranslated ( bn_ty, _) = & ty. ty
200- {
201- if !debug_info. add_type ( ty. name . as_utf8_lossy ( ) , bn_ty, & [ /* TODO */ ] ) {
202- error ! ( "Unable to add type `{}`" , ty. name. as_utf8_lossy( ) )
203- }
204- }
205- }
206-
207- // add a second time to fix the references LOL
208- for ty in & types {
209- if let TranslateTypeResult :: Translated ( bn_ty)
210- | TranslateTypeResult :: PartiallyTranslated ( bn_ty, _) = & ty. ty
211- {
212- if !debug_info. add_type ( ty. name . as_utf8_lossy ( ) , bn_ty, & [ /* TODO */ ] ) {
213- error ! ( "Unable to fix type `{}`" , ty. name. as_utf8_lossy( ) )
214- }
215- }
216- }
217-
218- Ok ( ( ) )
219310}
220311
221312fn parse_id0_section_info (
@@ -330,7 +421,12 @@ pub extern "C" fn CorePluginInit() -> bool {
330421 Logger :: new ( "IDB Import" )
331422 . with_level ( LevelFilter :: Error )
332423 . init ( ) ;
333- DebugInfoParser :: register ( "IDB Parser" , IDBDebugInfoParser ) ;
334- DebugInfoParser :: register ( "TIL Parser" , TILDebugInfoParser ) ;
424+ binaryninja:: command:: register_command (
425+ "Import TIL types" ,
426+ "Convert and import a TIL file into a TypeLibrary" ,
427+ LoadTilFile ,
428+ ) ;
429+ DebugInfoParser :: register ( "idb_parser" , IDBDebugInfoParser ) ;
430+ DebugInfoParser :: register ( "til_parser" , TILDebugInfoParser ) ;
335431 true
336432}
0 commit comments