Skip to content

Commit 7612a20

Browse files
committed
replace idb_import use of debug_info with type_library
1 parent 71af685 commit 7612a20

File tree

1 file changed

+133
-37
lines changed

1 file changed

+133
-37
lines changed

plugins/idb_import/src/lib.rs

Lines changed: 133 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
mod types;
2+
use std::path::Path;
3+
4+
use binaryninja::command::Command;
5+
use binaryninja::type_library::TypeLibrary;
6+
use binaryninja::types::QualifiedName;
27
use types::*;
38
mod addr_info;
49
use addr_info::*;
@@ -14,7 +19,7 @@ use idb_rs::til::TypeVariant as TILTypeVariant;
1419

1520
use log::{error, trace, warn, LevelFilter};
1621

17-
use anyhow::Result;
22+
use anyhow::{anyhow, Context, Result};
1823
use binaryninja::logger::Logger;
1924

2025
struct 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+
7695
struct 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

139171
fn 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

221312
fn 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

Comments
 (0)