summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrbran <git@rubens.io>2025-01-27 13:43:35 -0300
committerMason Reed <mason@vector35.com>2025-01-27 12:22:47 -0500
commit37f4ee46a40eee23cd039ae8329c9157a86aff65 (patch)
treecda7901a60f948613b6b8e76f2ae9edc12559c5b
parent123bb13826f68cbfa3158e2ebf30ca59a143afb1 (diff)
Update idb_import to 0.1.8
-rw-r--r--Cargo.lock27
-rw-r--r--plugins/idb_import/Cargo.toml2
-rw-r--r--plugins/idb_import/src/lib.rs34
-rw-r--r--plugins/idb_import/src/types.rs318
4 files changed, 221 insertions, 160 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4ffbf5ef..3a287568 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1413,14 +1413,14 @@ dependencies = [
[[package]]
name = "idb-rs"
-version = "0.1.6"
-source = "git+https://github.com/Vector35/idb-rs?tag=0.1.6#1c79c0e80688751119e1067876c38f2d26b84706"
+version = "0.1.8"
+source = "git+https://github.com/Vector35/idb-rs?tag=0.1.8#fcbea391c383b333500a89d36a4b87ab7031d9cb"
dependencies = [
"anyhow",
"bincode",
"clap",
"flate2",
- "itertools 0.13.0",
+ "num_enum",
"serde",
]
@@ -1776,6 +1776,27 @@ dependencies = [
]
[[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "objc-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/plugins/idb_import/Cargo.toml b/plugins/idb_import/Cargo.toml
index 66119081..3b63027f 100644
--- a/plugins/idb_import/Cargo.toml
+++ b/plugins/idb_import/Cargo.toml
@@ -11,5 +11,5 @@ crate-type = ["cdylib"]
anyhow = { version = "1.0.86", features = ["backtrace"] }
binaryninja.workspace = true
binaryninjacore-sys.workspace = true
-idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.6" }
+idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.8" }
log = "0.4" \ No newline at end of file
diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs
index ddd22ea5..70bbf07c 100644
--- a/plugins/idb_import/src/lib.rs
+++ b/plugins/idb_import/src/lib.rs
@@ -10,7 +10,7 @@ use binaryninja::debuginfo::{
use idb_rs::id0::{ID0Section, IDBParam1, IDBParam2};
use idb_rs::til::section::TILSection;
-use idb_rs::til::Type as TILType;
+use idb_rs::til::TypeVariant as TILTypeVariant;
use log::{error, trace, warn, LevelFilter};
@@ -92,9 +92,7 @@ impl std::io::Seek for BinaryViewReader<'_> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
let new_offset = match pos {
std::io::SeekFrom::Start(offset) => Some(offset),
- std::io::SeekFrom::End(end) => u64::try_from(self.bv.len())
- .unwrap()
- .checked_add_signed(end),
+ std::io::SeekFrom::End(end) => self.bv.len().checked_add_signed(end),
std::io::SeekFrom::Current(next) => self.offset.checked_add_signed(next),
};
let new_offset =
@@ -148,9 +146,9 @@ fn parse_til_info(
bv: debug_file,
offset: 0,
};
- let file = std::io::BufReader::new(file);
+ let mut file = std::io::BufReader::new(file);
trace!("Parsing the TIL section");
- let til = TILSection::parse(file)?;
+ let til = TILSection::read(&mut file, idb_rs::IDBSectionCompression::None)?;
import_til_section(debug_info, debug_file, &til, progress)
}
@@ -168,26 +166,26 @@ pub fn import_til_section(
TranslateTypeResult::NotYet => {
panic!(
"type could not be processed `{}`: {:#?}",
- &String::from_utf8_lossy(&ty.name),
+ ty.name.as_utf8_lossy(),
&ty.og_ty
);
}
TranslateTypeResult::Error(error) => {
error!(
"Unable to parse type `{}`: {error}",
- &String::from_utf8_lossy(&ty.name)
+ ty.name.as_utf8_lossy(),
);
}
TranslateTypeResult::PartiallyTranslated(_, error) => {
if let Some(error) = error {
error!(
"Unable to parse type `{}` correctly: {error}",
- &String::from_utf8_lossy(&ty.name)
+ ty.name.as_utf8_lossy(),
);
} else {
warn!(
"Type `{}` maybe not be fully translated",
- &String::from_utf8_lossy(&ty.name)
+ ty.name.as_utf8_lossy(),
);
}
}
@@ -200,11 +198,8 @@ pub fn import_til_section(
if let TranslateTypeResult::Translated(bn_ty)
| TranslateTypeResult::PartiallyTranslated(bn_ty, _) = &ty.ty
{
- if !debug_info.add_type(String::from_utf8_lossy(&ty.name), bn_ty, &[/* TODO */]) {
- error!(
- "Unable to add type `{}`",
- &String::from_utf8_lossy(&ty.name)
- )
+ if !debug_info.add_type(ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) {
+ error!("Unable to add type `{}`", ty.name.as_utf8_lossy())
}
}
}
@@ -214,11 +209,8 @@ pub fn import_til_section(
if let TranslateTypeResult::Translated(bn_ty)
| TranslateTypeResult::PartiallyTranslated(bn_ty, _) = &ty.ty
{
- if !debug_info.add_type(String::from_utf8_lossy(&ty.name), bn_ty, &[/* TODO */]) {
- error!(
- "Unable to fix type `{}`",
- &String::from_utf8_lossy(&ty.name)
- )
+ if !debug_info.add_type(ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) {
+ error!("Unable to fix type `{}`", ty.name.as_utf8_lossy())
}
}
}
@@ -273,7 +265,7 @@ fn parse_id0_section_info(
});
match (label, &ty, bnty) {
- (_, Some(TILType::Function(_)), bnty) => {
+ (_, Some(ty), bnty) if matches!(&ty.type_variant, TILTypeVariant::Function(_)) => {
if bnty.is_none() {
error!("Unable to convert the function type at {addr:#x}",)
}
diff --git a/plugins/idb_import/src/types.rs b/plugins/idb_import/src/types.rs
index 1552049f..98706429 100644
--- a/plugins/idb_import/src/types.rs
+++ b/plugins/idb_import/src/types.rs
@@ -1,19 +1,25 @@
use std::collections::HashMap;
+use std::num::{NonZeroU16, NonZeroU8};
use anyhow::{anyhow, Result};
-use binaryninja::architecture::CoreArchitecture;
+use binaryninja::architecture::{Architecture, ArchitectureExt, CoreArchitecture};
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
+use binaryninja::calling_convention::CoreCallingConvention;
use binaryninja::confidence::Conf;
use binaryninja::rc::Ref;
use binaryninja::types::{
EnumerationBuilder, FunctionParameter, MemberAccess, MemberScope, StructureBuilder,
StructureType, Type,
};
+use idb_rs::til::function::CallingConvention as TILCallingConvention;
+use idb_rs::til::pointer::Pointer as TILPointer;
use idb_rs::til::{
array::Array as TILArray, function::Function as TILFunction, r#enum::Enum as TILEnum,
- r#struct::Struct as TILStruct, r#struct::StructMember as TILStructMember, section::TILSection,
- union::Union as TILUnion, TILTypeInfo, Type as TILType, Typedef as TILTypedef,
+ r#struct::Struct as TILStruct, r#struct::StructMember as TILStructMember,
+ r#union::Union as TILUnion, section::TILSection, TILTypeInfo, Type as TILType,
+ TypeVariant as TILTypeVariant,
};
+use idb_rs::IDBString;
#[derive(Debug, Clone)]
pub enum BnTypeError {
@@ -29,6 +35,9 @@ pub enum BnTypeError {
/// Error for members
Struct(Vec<(usize, BnTypeError)>),
Union(Vec<(usize, BnTypeError)>),
+
+ // can't create function due to missing CallingConvention
+ MissingArchCC,
}
#[derive(Default, Debug, Clone)]
@@ -66,6 +75,7 @@ impl std::fmt::Display for BnTypeError {
Ok(())
}
BnTypeError::Pointer(error) => write!(f, "Pointer: {error}"),
+ BnTypeError::MissingArchCC => write!(f, "Arch is missing a default CallingConvention"),
}
}
}
@@ -93,7 +103,7 @@ impl From<Result<Ref<Type>, BnTypeError>> for TranslateTypeResult {
pub struct TranslatesIDBType<'a> {
// sanitized name from IDB
- pub name: Vec<u8>,
+ pub name: IDBString,
// the result, if converted
pub ty: TranslateTypeResult,
pub og_ty: &'a TILTypeInfo,
@@ -106,39 +116,21 @@ pub struct TranslateIDBTypes<'a, F: Fn(usize, usize) -> Result<(), ()>> {
pub til: &'a TILSection,
// note it's mapped 1:1 with the same index from til types.chain(symbols)
pub types: Vec<TranslatesIDBType<'a>>,
- // ordinals with index to types
- pub types_by_ord: HashMap<u64, usize>,
- // original names with index to types
- pub types_by_name: HashMap<Vec<u8>, usize>,
}
impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
- fn find_typedef_by_ordinal(&self, ord: u64) -> Option<TranslateTypeResult> {
- self.types_by_ord
- .get(&ord)
- .map(|idx| self.find_typedef(&self.types[*idx]))
- }
-
fn find_typedef_by_name(&self, name: &[u8]) -> Option<TranslateTypeResult> {
if name.is_empty() {
// TODO this is my assumption, maybe an empty names Typedef means something else.
return Some(TranslateTypeResult::Translated(Type::void()));
}
- if let Some(other_ty) = self
- .types_by_name
- .get(name)
- .map(|idx| self.find_typedef(&self.types[*idx]))
- {
- return Some(other_ty);
- }
-
// check for types that ar usually not defined directly
match name {
b"Unkown" | b"uint8_t" => Some(TranslateTypeResult::Translated(Type::int(1, false))),
b"IUnkown" | b"int8_t" => Some(TranslateTypeResult::Translated(Type::int(1, true))),
b"SHORT" | b"USHORT" => Some(TranslateTypeResult::Translated(Type::int(
- self.til.size_short.get() as usize,
+ self.til.sizeof_short().get().into(),
name == b"SHORT",
))),
b"int16_t" => Some(TranslateTypeResult::Translated(Type::int(2, true))),
@@ -162,7 +154,7 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
TranslateTypeResult::PartiallyTranslated(og_ty, error) => {
TranslateTypeResult::PartiallyTranslated(
- Type::named_type_from_type(String::from_utf8_lossy(&ty.name), og_ty),
+ Type::named_type_from_type(ty.name.as_utf8_lossy(), og_ty),
error
.as_ref()
.map(|x| BnTypeError::Typedef(Box::new(x.clone())))
@@ -170,33 +162,39 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
)
}
TranslateTypeResult::Translated(og_ty) => TranslateTypeResult::Translated(
- Type::named_type_from_type(String::from_utf8_lossy(&ty.name), og_ty),
+ Type::named_type_from_type(ty.name.as_utf8_lossy(), og_ty),
),
}
}
- fn translate_pointer(&self, ty: &TILType) -> TranslateTypeResult {
- match self.translate_type(ty) {
+ fn translate_pointer(&self, ty: &TILPointer) -> TranslateTypeResult {
+ match self.translate_type(&ty.typ) {
TranslateTypeResult::Translated(trans) => {
- TranslateTypeResult::Translated(Type::pointer(&self.arch, &trans))
+ TranslateTypeResult::Translated(self.inner_translate_pointer(ty, &trans))
}
TranslateTypeResult::PartiallyTranslated(trans, error) => {
TranslateTypeResult::PartiallyTranslated(
- Type::pointer(&self.arch, &trans),
+ self.inner_translate_pointer(ty, &trans),
error.map(|e| BnTypeError::Pointer(Box::new(e))),
)
}
TranslateTypeResult::Error(error) => TranslateTypeResult::PartiallyTranslated(
- Type::pointer(&self.arch, &Type::void()),
+ self.inner_translate_pointer(ty, &Type::void()),
Some(error),
),
TranslateTypeResult::NotYet => TranslateTypeResult::PartiallyTranslated(
- Type::pointer(&self.arch, &Type::void()),
+ self.inner_translate_pointer(ty, &Type::void()),
None,
),
}
}
+ fn inner_translate_pointer(&self, ty: &TILPointer, trans: &Type) -> Ref<Type> {
+ // TODO handle ty.shifted
+ // TODO handle ty.modifier
+ Type::pointer_with_options(&self.arch, trans, ty.typ.is_const, ty.typ.is_volatile, None)
+ }
+
fn translate_function(&self, fun: &TILFunction) -> TranslateTypeResult {
let mut is_partial = false;
let mut errors: BnTypeFunctionError = Default::default();
@@ -246,12 +244,33 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
let loc = None;
let name = arg_name
.as_ref()
- .map(|name| String::from_utf8_lossy(name).to_string())
+ .map(|name| name.as_utf8_lossy().to_string())
.unwrap_or_else(|| format!("arg_{i}"));
bn_args.push(FunctionParameter::new(arg, name, loc));
}
- let ty = Type::function(&return_ty, bn_args, false);
+ let var_args = matches!(fun.calling_convention, Some(TILCallingConvention::Ellipsis));
+ let cc = fun
+ .calling_convention
+ .and_then(|cc| convert_cc(&self.arch, cc))
+ .or_else(|| self.arch.get_default_calling_convention())
+ .or_else(|| {
+ self.arch
+ .calling_conventions()
+ .iter()
+ .next()
+ .map(|x| x.clone())
+ });
+ let Some(cc) = cc else {
+ return TranslateTypeResult::Error(BnTypeError::MissingArchCC);
+ };
+ let ty = Type::function_with_opts(
+ &return_ty,
+ &bn_args,
+ var_args,
+ cc,
+ Conf::new(0, binaryninja::confidence::MIN_CONFIDENCE),
+ );
if is_partial {
let error = (errors.ret.is_some() || !errors.args.is_empty())
.then_some(BnTypeError::Function(errors));
@@ -262,15 +281,17 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
}
+ // TODO can binja handle 0 sized array? There is a better translation?
fn translate_array(&self, array: &TILArray) -> TranslateTypeResult {
match self.translate_type(&array.elem_type) {
TranslateTypeResult::NotYet => TranslateTypeResult::NotYet,
- TranslateTypeResult::Translated(ty) => {
- TranslateTypeResult::Translated(Type::array(&ty, array.nelem.into()))
- }
+ TranslateTypeResult::Translated(ty) => TranslateTypeResult::Translated(Type::array(
+ &ty,
+ array.nelem.map(NonZeroU16::get).unwrap_or(0).into(),
+ )),
TranslateTypeResult::PartiallyTranslated(ty, error) => {
TranslateTypeResult::PartiallyTranslated(
- Type::array(&ty, array.nelem.into()),
+ Type::array(&ty, array.nelem.map(NonZeroU16::get).unwrap_or(0).into()),
error.map(Box::new).map(BnTypeError::Array),
)
}
@@ -291,8 +312,8 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
let mut members = members_slice
.iter()
- .map(|ty| match &ty.member_type {
- TILType::Bitfield(b) => b,
+ .map(|ty| match &ty.member_type.type_variant {
+ TILTypeVariant::Bitfield(b) => b,
_ => unreachable!(),
})
.enumerate();
@@ -307,7 +328,7 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
member
.name
.as_ref()
- .map(|name| String::from_utf8_lossy(name).to_string())
+ .map(|name| name.as_utf8_lossy().to_string())
.unwrap_or_else(|| format!("bitfield_{}", offset + start_idx))
} else {
format!("bitfield_{}_{}", offset + start_idx, offset + (i - 1))
@@ -318,13 +339,13 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
for (i, member) in members {
// starting a new field
- let max_bits = u32::try_from(current_field_bytes).unwrap() * 8;
+ let max_bits = u32::from(current_field_bytes.get()) * 8;
// this bitfield start a a new field, or can't contain other bitfields
// finish the previous and start a new
if current_field_bytes != member.nbytes
|| max_bits < current_field_bits + u32::from(member.width)
{
- create_field(start_idx, i, current_field_bytes);
+ create_field(start_idx, i, current_field_bytes.get().into());
current_field_bytes = member.nbytes;
current_field_bits = 0;
start_idx = i;
@@ -335,38 +356,41 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
if current_field_bits != 0 {
- create_field(start_idx, members_slice.len(), current_field_bytes);
+ create_field(
+ start_idx,
+ members_slice.len(),
+ current_field_bytes.get().into(),
+ );
}
}
- fn translate_struct(
- &self,
- members: &[TILStructMember],
- effective_alignment: u16,
- ) -> TranslateTypeResult {
- if members.is_empty() {
+ fn translate_struct(&self, ty_struct: &TILStruct) -> TranslateTypeResult {
+ if ty_struct.members.is_empty() {
// binary ninja crashes if you create an empty struct, because it divide by 0
return TranslateTypeResult::Translated(Type::void());
}
let mut is_partial = false;
let mut structure = StructureBuilder::new();
- structure.alignment(effective_alignment.into());
+ if let Some(align) = ty_struct.alignment {
+ structure.alignment(align.get().into());
+ }
+ structure.packed(ty_struct.is_unaligned && ty_struct.is_uknown_8);
let mut errors = vec![];
let mut first_bitfield_seq = None;
- for (i, member) in members.iter().enumerate() {
- match (&member.member_type, first_bitfield_seq) {
+ for (i, member) in ty_struct.members.iter().enumerate() {
+ match (&member.member_type.type_variant, first_bitfield_seq) {
// accumulate the bitfield to be condensated
- (TILType::Bitfield(_bit), None) => {
+ (TILTypeVariant::Bitfield(_bit), None) => {
first_bitfield_seq = Some(i);
continue;
}
- (TILType::Bitfield(_bit), Some(_)) => continue,
+ (TILTypeVariant::Bitfield(_bit), Some(_)) => continue,
// condensate the bitfields into byte-wide fields
(_, Some(start_idx)) => {
first_bitfield_seq = None;
- let members_bitrange = &members[start_idx..i];
+ let members_bitrange = &ty_struct.members[start_idx..i];
self.condensate_bitfields_from_struct(
start_idx,
members_bitrange,
@@ -392,15 +416,16 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
return TranslateTypeResult::Error(BnTypeError::Struct(errors));
}
};
+ //TODO handle member.alignment
let name = member
.name
.as_ref()
- .map(|name| String::from_utf8_lossy(name).to_string())
+ .map(|name| name.as_utf8_lossy().to_string())
.unwrap_or_else(|| format!("member_{i}"));
structure.append(&mem, name, MemberAccess::NoAccess, MemberScope::NoScope);
}
if let Some(start_idx) = first_bitfield_seq {
- let members_bitrange = &members[start_idx..];
+ let members_bitrange = &ty_struct.members[start_idx..];
self.condensate_bitfields_from_struct(start_idx, members_bitrange, &mut structure);
}
let bn_ty = Type::structure(&structure.finalize());
@@ -413,20 +438,16 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
}
- fn translate_union(
- &self,
- members: &[(Option<Vec<u8>>, TILType)],
- _effective_alignment: u16,
- ) -> TranslateTypeResult {
+ fn translate_union(&self, ty_union: &TILUnion) -> TranslateTypeResult {
let mut is_partial = false;
let mut structure = StructureBuilder::new();
structure.structure_type(StructureType::UnionStructureType);
let mut errors = vec![];
- for (i, (member_name, member_type)) in members.iter().enumerate() {
+ for (i, (member_name, member_type)) in ty_union.members.iter().enumerate() {
// bitfields can be translated into complete fields
- let mem = match member_type {
- TILType::Bitfield(field) => field_from_bytes(field.nbytes),
- member_type => match self.translate_type(member_type) {
+ let mem = match &member_type.type_variant {
+ TILTypeVariant::Bitfield(field) => field_from_bytes(field.nbytes.get().into()),
+ _ => match self.translate_type(member_type) {
TranslateTypeResult::Translated(ty) => ty,
TranslateTypeResult::Error(error) => {
errors.push((i, error));
@@ -445,7 +466,7 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
let name = member_name
.as_ref()
- .map(|name| String::from_utf8_lossy(name).to_string())
+ .map(|name| name.as_utf8_lossy().to_string())
.unwrap_or_else(|| format!("member_{i}"));
structure.append(&mem, name, MemberAccess::NoAccess, MemberScope::NoScope);
}
@@ -461,114 +482,123 @@ impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
}
}
- fn translate_enum(members: &[(Option<Vec<u8>>, u64)], bytesize: u64) -> Ref<Type> {
+ fn translate_enum(&self, ty_enum: &TILEnum) -> Ref<Type> {
let mut eb = EnumerationBuilder::new();
- for (i, (name, bytesize)) in members.iter().enumerate() {
+ for (i, (name, member_value)) in ty_enum.members.iter().enumerate() {
let name = name
.as_ref()
- .map(|name| String::from_utf8_lossy(name).to_string())
+ .map(|name| name.as_utf8_lossy().to_string())
.unwrap_or_else(|| format!("member_{i}"));
- eb.insert(name, *bytesize);
+ eb.insert(name, *member_value);
}
Type::enumeration(
&eb.finalize(),
// TODO: This looks bad, look at the comment in [`Type::width`].
- (bytesize as usize).try_into().unwrap(),
- Conf::new(false, 0),
+ // TODO check the default size of enum
+ ty_enum
+ .storage_size
+ .map(|x| x.into())
+ .or(self.til.header.size_enum.map(|x| x.into()))
+ .unwrap_or(4.try_into().unwrap()),
+ ty_enum.is_signed,
)
}
- fn translate_basic(mdata: &idb_rs::til::Basic) -> Ref<Type> {
+ fn translate_basic(&self, mdata: &idb_rs::til::Basic) -> Ref<Type> {
match *mdata {
idb_rs::til::Basic::Void => Type::void(),
idb_rs::til::Basic::Unknown { bytes: 0 } => Type::void(),
idb_rs::til::Basic::Unknown { bytes } => Type::array(&Type::char(), bytes.into()),
- idb_rs::til::Basic::Bool { bytes } if bytes.get() == 1 => Type::bool(),
+ idb_rs::til::Basic::Bool if self.til.header.size_bool.get() == 1 => Type::bool(),
+ idb_rs::til::Basic::BoolSized { bytes } if bytes.get() == 1 => Type::bool(),
// NOTE Binja don't have any representation for bool other then the default
- idb_rs::til::Basic::Bool { bytes } => Type::int(bytes.get().into(), false),
+ idb_rs::til::Basic::BoolSized { bytes } => Type::int(bytes.get().into(), false),
+ idb_rs::til::Basic::Bool /*if self.til.header.size_bool.get() != 1*/ => Type::int(self.til.header.size_bool.get().into(), false),
idb_rs::til::Basic::Char => Type::char(),
// TODO what exacly is Segment Register?
idb_rs::til::Basic::SegReg => Type::char(),
- idb_rs::til::Basic::Int { bytes, is_signed } => {
+ idb_rs::til::Basic::IntSized { bytes, is_signed } => {
// default into signed
let is_signed = is_signed.as_ref().copied().unwrap_or(true);
Type::int(bytes.get().into(), is_signed)
}
+ idb_rs::til::Basic::Int { is_signed } => {
+ let is_signed = is_signed.as_ref().copied().unwrap_or(true);
+ Type::int(self.til.header.size_int.get().into(), is_signed)
+ },
+ idb_rs::til::Basic::Short { is_signed } => {
+ let is_signed = is_signed.as_ref().copied().unwrap_or(true);
+ Type::int(self.til.sizeof_short().get().into(), is_signed)
+ },
+ idb_rs::til::Basic::Long { is_signed } => {
+ let is_signed = is_signed.as_ref().copied().unwrap_or(true);
+ Type::int(self.til.sizeof_long().get().into(), is_signed)
+ },
+ idb_rs::til::Basic::LongLong { is_signed } => {
+ let is_signed = is_signed.as_ref().copied().unwrap_or(true);
+ Type::int(self.til.sizeof_long_long().get().into(), is_signed)
+ },
+ idb_rs::til::Basic::LongDouble => {
+ // TODO is size_long_double architecture dependent?
+ Type::float(self.til.header.size_long_double.map(NonZeroU8::get).unwrap_or(8).into())
+ },
idb_rs::til::Basic::Float { bytes } => Type::float(bytes.get().into()),
}
}
pub fn translate_type(&self, ty: &TILType) -> TranslateTypeResult {
- match &ty {
+ match &ty.type_variant {
// types that are always translatable
- TILType::Basic(meta) => TranslateTypeResult::Translated(Self::translate_basic(meta)),
- TILType::Bitfield(bit) => TranslateTypeResult::Translated(field_from_bytes(bit.nbytes)),
- TILType::Enum(TILEnum::NonRef {
- members, bytesize, ..
- }) => TranslateTypeResult::Translated(Self::translate_enum(members, *bytesize)),
- TILType::Typedef(TILTypedef::Ordinal(ord)) => self
- .find_typedef_by_ordinal((*ord).into())
- .unwrap_or_else(|| TranslateTypeResult::Error(BnTypeError::OrdinalNotFound(*ord))),
- TILType::Typedef(TILTypedef::Name(name)) => {
- self.find_typedef_by_name(name).unwrap_or_else(|| {
- TranslateTypeResult::Error(BnTypeError::NameNotFound(
- String::from_utf8_lossy(name).to_string(),
- ))
- })
+ TILTypeVariant::Basic(meta) => {
+ TranslateTypeResult::Translated(self.translate_basic(meta))
+ }
+ TILTypeVariant::Bitfield(bit) => {
+ TranslateTypeResult::Translated(field_from_bytes(bit.nbytes.get().into()))
}
+ TILTypeVariant::Enum(ty_enum) => {
+ TranslateTypeResult::Translated(self.translate_enum(ty_enum))
+ }
+ TILTypeVariant::Typeref(typeref) => match &typeref.typeref_value {
+ idb_rs::til::TyperefValue::Ref(idx) => self.find_typedef(&self.types[*idx]),
+ idb_rs::til::TyperefValue::UnsolvedName(name) => self
+ .find_typedef_by_name(name.as_ref().map(|x| x.as_bytes()).unwrap_or(&[]))
+ .unwrap_or_else(|| {
+ TranslateTypeResult::Error(BnTypeError::NameNotFound(
+ name.as_ref()
+ .map(|x| x.as_utf8_lossy().to_string())
+ .unwrap_or(String::new()),
+ ))
+ }),
+ idb_rs::til::TyperefValue::UnsolvedOrd(ord) => {
+ TranslateTypeResult::Error(BnTypeError::OrdinalNotFound(*ord))
+ }
+ },
- // may not be translatable imediatly, but the size is known and can be
- // updated after alBasicers are finished
- TILType::Union(TILUnion::Ref { ref_type, .. })
- | TILType::Struct(TILStruct::Ref { ref_type, .. })
- | TILType::Enum(TILEnum::Ref { ref_type, .. }) => self.translate_pointer(ref_type),
- TILType::Pointer(ty) => self.translate_pointer(&ty.typ),
- TILType::Function(fun) => self.translate_function(fun),
+ TILTypeVariant::Pointer(ty) => self.translate_pointer(ty),
+ TILTypeVariant::Function(fun) => self.translate_function(fun),
// can only be partially solved if all fields are solved or partially solved
- TILType::Array(array) => self.translate_array(array),
- TILType::Struct(TILStruct::NonRef {
- members,
- effective_alignment,
- ..
- }) => self.translate_struct(members, *effective_alignment),
- TILType::Union(TILUnion::NonRef {
- members,
- effective_alignment,
- ..
- }) => self.translate_union(members, *effective_alignment),
+ TILTypeVariant::Array(array) => self.translate_array(array),
+ TILTypeVariant::Struct(ty_struct) => self.translate_struct(ty_struct),
+ TILTypeVariant::Union(ty_union) => self.translate_union(ty_union),
}
}
}
pub fn translate_ephemeral_type(debug_file: &BinaryView, ty: &TILType) -> TranslateTypeResult {
// in case we need to translate types
+ let header = idb_rs::til::ephemeral_til_header();
let translator = TranslateIDBTypes {
arch: debug_file.default_arch().unwrap(/* TODO */),
progress: |_, _| Ok(()),
// TODO it's unclear what to do here
til: &TILSection {
- format: 12,
- title: Vec::new(),
- description: Vec::new(),
- id: 0,
- cm: 0,
- def_align: 1,
+ header,
symbols: vec![],
- type_ordinal_alias: None,
types: vec![],
- size_i: 4.try_into().unwrap(),
- size_b: 1.try_into().unwrap(),
- size_short: 2.try_into().unwrap(),
- size_long: 4.try_into().unwrap(),
- size_long_long: 8.try_into().unwrap(),
- size_long_double: None,
macros: None,
- is_universal: false,
},
types: vec![],
- types_by_ord: HashMap::new(),
- types_by_name: HashMap::new(),
};
translator.translate_type(ty)
@@ -589,9 +619,8 @@ pub fn translate_til_types(
for (i, (ty, is_symbol)) in all_types.enumerate() {
// TODO sanitized the input
// TODO find out how the namespaces used by TIL works
- let name = ty.name.to_owned();
types.push(TranslatesIDBType {
- name,
+ name: ty.name.clone(),
is_symbol,
og_ty: ty,
ty: TranslateTypeResult::NotYet,
@@ -612,8 +641,8 @@ pub fn translate_til_types(
)
}
}
- if !ty.name.is_empty() {
- let dup2 = types_by_name.insert(ty.name.to_owned(), i);
+ if !ty.name.as_bytes().is_empty() {
+ let dup2 = types_by_name.insert(ty.name.as_bytes().to_owned(), i);
if let Some(old) = dup2 {
let old_type = &types[old];
let new_type = types.last().unwrap();
@@ -622,7 +651,7 @@ pub fn translate_til_types(
"dup name {}:{}: {}:\n{:?}\n{:?}",
old_type.is_symbol,
new_type.is_symbol,
- &String::from_utf8_lossy(&ty.name),
+ &ty.name.as_utf8_lossy(),
&old_type.og_ty,
&new_type.og_ty,
)
@@ -635,10 +664,8 @@ pub fn translate_til_types(
progress,
til,
types,
- types_by_ord,
- types_by_name,
};
- if (&translator.progress)(0, total).is_err() {
+ if (translator.progress)(0, total).is_err() {
return Err(anyhow!("IDB import aborted"));
}
@@ -682,7 +709,7 @@ pub fn translate_til_types(
// means we acomplilshed nothing during this loop, there is no point in trying again
break;
}
- if (&translator.progress)(num_translated, total).is_err() {
+ if (translator.progress)(num_translated, total).is_err() {
// error means the user aborted the progress
break;
}
@@ -698,3 +725,24 @@ fn field_from_bytes(bytes: i32) -> Ref<Type> {
nelem => Type::array(&Type::char(), nelem.try_into().unwrap()),
}
}
+
+fn convert_cc<A: Architecture + ArchitectureExt>(
+ arch: &A,
+ in_cc: TILCallingConvention,
+) -> Option<Ref<CoreCallingConvention>> {
+ match in_cc {
+ TILCallingConvention::Cdecl => arch.get_cdecl_calling_convention(),
+ TILCallingConvention::Ellipsis => arch.get_cdecl_calling_convention(),
+ TILCallingConvention::Stdcall => arch.get_stdcall_calling_convention(),
+ TILCallingConvention::Fastcall => arch.get_fastcall_calling_convention(),
+ TILCallingConvention::Voidarg
+ | TILCallingConvention::Pascal
+ | TILCallingConvention::Thiscall
+ | TILCallingConvention::Swift
+ | TILCallingConvention::Golang
+ | TILCallingConvention::Reserved3
+ | TILCallingConvention::Uservars
+ | TILCallingConvention::Userpurge
+ | TILCallingConvention::Usercall => None,
+ }
+}