diff options
| author | rbran <git@rubens.io> | 2025-01-27 13:43:35 -0300 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-01-27 12:22:47 -0500 |
| commit | 37f4ee46a40eee23cd039ae8329c9157a86aff65 (patch) | |
| tree | cda7901a60f948613b6b8e76f2ae9edc12559c5b | |
| parent | 123bb13826f68cbfa3158e2ebf30ca59a143afb1 (diff) | |
Update idb_import to 0.1.8
| -rw-r--r-- | Cargo.lock | 27 | ||||
| -rw-r--r-- | plugins/idb_import/Cargo.toml | 2 | ||||
| -rw-r--r-- | plugins/idb_import/src/lib.rs | 34 | ||||
| -rw-r--r-- | plugins/idb_import/src/types.rs | 318 |
4 files changed, 221 insertions, 160 deletions
@@ -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, + } +} |
