Skip to content

Commit 9e5c739

Browse files
committed
update idb_import idb-rs to 0.1.12
1 parent 31eea4e commit 9e5c739

File tree

4 files changed

+162
-90
lines changed

4 files changed

+162
-90
lines changed

plugins/idb_import/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ crate-type = ["cdylib"]
1212
anyhow = { version = "1.0.86", features = ["backtrace"] }
1313
binaryninja.workspace = true
1414
binaryninjacore-sys.workspace = true
15-
idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.10" }
15+
idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.12" }
1616
log = "0.4"

plugins/idb_import/src/addr_info.rs

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,49 @@ use std::collections::HashMap;
33

44
use anyhow::Result;
55

6-
use idb_rs::id0::ID0Section;
7-
use idb_rs::{til, IDAKind};
6+
use idb_rs::addr_info::all_address_info;
7+
use idb_rs::id0::{ID0Section, Netdelta};
8+
use idb_rs::id1::ID1Section;
9+
use idb_rs::id2::ID2Section;
10+
use idb_rs::{til, Address, IDAKind};
811

912
#[derive(Default)]
1013
pub struct AddrInfo<'a> {
11-
// TODO does binja diferenciate comments types on the API?
12-
pub comments: Vec<&'a [u8]>,
13-
pub label: Option<Cow<'a, str>>,
14+
// TODO does binja differentiate comments types on the API?
15+
pub comments: Vec<Vec<u8>>,
16+
pub label: Option<Cow<'a, [u8]>>,
1417
// TODO make this a ref
1518
pub ty: Option<til::Type>,
1619
}
1720

18-
pub fn get_info<K: IDAKind>(
19-
id0: &ID0Section<K>,
20-
version: u16,
21-
) -> Result<HashMap<K::Usize, AddrInfo<'_>>> {
22-
use idb_rs::id0::FunctionsAndComments::*;
23-
let mut addr_info: HashMap<K::Usize, AddrInfo> = HashMap::new();
24-
25-
// the old style comments, most likely empty on new versions
26-
let old_comments = id0.functions_and_comments()?.filter_map(|fc| match fc {
27-
Err(e) => Some(Err(e)),
28-
Ok(Comment { address, comment }) => Some(Ok((address, comment))),
29-
Ok(Name | Function(_) | Unknown { .. }) => None,
30-
});
31-
for old_comment in old_comments {
32-
let (addr, comment) = old_comment?;
33-
let comment = comment.message();
34-
addr_info.entry(addr).or_default().comments.push(comment);
35-
}
21+
pub fn get_info<'a, K: IDAKind>(
22+
id0: &'a ID0Section<K>,
23+
id1: &ID1Section,
24+
id2: Option<&ID2Section<K>>,
25+
netdelta: Netdelta<K>,
26+
) -> Result<HashMap<Address<K>, AddrInfo<'a>>> {
27+
let mut addr_info: HashMap<Address<K>, AddrInfo> = HashMap::new();
3628

3729
// comments defined on the address information
38-
for info in id0.address_info(version)? {
39-
use idb_rs::id0::AddressInfo::*;
40-
let (addr, info) = info?;
41-
let entry = addr_info.entry(addr).or_default();
42-
match info {
43-
Comment(comments) => entry.comments.push(comments.message()),
44-
Label(name) => {
45-
if let Some(_old) = entry.label.replace(name) {
46-
panic!("Duplicated label for an address should be impossible this is most likelly a programing error")
47-
}
48-
}
49-
TilType(ty) => {
50-
if let Some(_old) = entry.ty.replace(ty) {
51-
panic!("Duplicated type for an address should be impossible this is most likelly a programing error")
52-
}
53-
}
54-
Other { .. } => {}
55-
DefinedStruct(_) => {}
30+
for (info, _info_size) in all_address_info(id0, id1, id2, netdelta) {
31+
let entry = addr_info.entry(info.address()).or_default();
32+
if let Some(comment) = info.comment() {
33+
entry.comments.push(comment.to_vec());
34+
}
35+
if let Some(comment) = info.comment_repeatable() {
36+
entry.comments.push(comment.to_vec());
37+
}
38+
if let Some(comment) = info.comment_pre() {
39+
entry.comments.extend(comment.map(|line| line.to_vec()));
40+
}
41+
if let Some(comment) = info.comment_post() {
42+
entry.comments.extend(comment.map(|line| line.to_vec()));
43+
}
44+
if let Some(label) = info.label()? {
45+
entry.label = Some(label);
46+
}
47+
if let Some(ty) = info.tinfo()? {
48+
entry.ty = Some(ty);
5649
}
5750
}
5851

plugins/idb_import/src/lib.rs

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
mod 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};
38
use types::*;
49
mod addr_info;
510
use 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};
1318
use idb_rs::til::section::TILSection;
1419
use idb_rs::til::TypeVariant as TILTypeVariant;
1520

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

18-
use anyhow::Result;
23+
use anyhow::{anyhow, Result};
1924
use binaryninja::logger::Logger;
2025

2126
struct IDBDebugInfoParser;
@@ -81,9 +86,12 @@ struct BinaryViewReader<'a> {
8186
impl 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(),

plugins/idb_import/src/types.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use binaryninja::types::{
1313
};
1414
use idb_rs::til::function::CallingConvention as TILCallingConvention;
1515
use idb_rs::til::pointer::Pointer as TILPointer;
16+
use idb_rs::til::r#enum::EnumMembers;
1617
use idb_rs::til::{
1718
array::Array as TILArray, function::Function as TILFunction, r#enum::Enum as TILEnum,
1819
r#struct::Struct as TILStruct, r#struct::StructMember as TILStructMember,
@@ -486,14 +487,32 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
486487

487488
fn translate_enum(&self, ty_enum: &TILEnum) -> Ref<Type> {
488489
let mut eb = EnumerationBuilder::new();
489-
for (i, member) in ty_enum.members.iter().enumerate() {
490-
let name = member
491-
.name
492-
.as_ref()
493-
.map(|name| name.as_utf8_lossy().to_string())
494-
.unwrap_or_else(|| format!("member_{i}"));
495-
eb.insert(&name, member.value);
490+
match &ty_enum.members {
491+
EnumMembers::Regular(enum_members) => {
492+
for (i, member) in enum_members.iter().enumerate() {
493+
let name = member
494+
.name
495+
.as_ref()
496+
.map(|name| name.as_utf8_lossy().to_string())
497+
.unwrap_or_else(|| format!("member_{i}"));
498+
eb.insert(&name, member.value);
499+
}
500+
}
501+
EnumMembers::Groups(enum_groups) => {
502+
for group in enum_groups {
503+
// TODO implement groups to the importer
504+
for (i, member) in group.sub_fields.iter().enumerate() {
505+
let name = member
506+
.name
507+
.as_ref()
508+
.map(|name| name.as_utf8_lossy().to_string())
509+
.unwrap_or_else(|| format!("member_{i}"));
510+
eb.insert(&name, member.value);
511+
}
512+
}
513+
}
496514
}
515+
497516
Type::enumeration(
498517
&eb.finalize(),
499518
// TODO: This looks bad, look at the comment in [`Type::width`].

0 commit comments

Comments
 (0)