diff --git a/plugins/idb_import/Cargo.toml b/plugins/idb_import/Cargo.toml index cad56142d6..18e84a93a4 100644 --- a/plugins/idb_import/Cargo.toml +++ b/plugins/idb_import/Cargo.toml @@ -12,5 +12,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.12" } +idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.13" } log = "0.4" diff --git a/plugins/idb_import/src/addr_info.rs b/plugins/idb_import/src/addr_info.rs index 9a05e6d38d..9ac0ef011d 100644 --- a/plugins/idb_import/src/addr_info.rs +++ b/plugins/idb_import/src/addr_info.rs @@ -1,50 +1,54 @@ -use std::borrow::Cow; use std::collections::HashMap; use anyhow::Result; use idb_rs::addr_info::all_address_info; -use idb_rs::id0::{ID0Section, Netdelta}; +use idb_rs::id0::{ID0Section, RootInfo}; use idb_rs::id1::ID1Section; use idb_rs::id2::ID2Section; -use idb_rs::{til, Address, IDAKind}; +use idb_rs::{til, Address, IDAKind, IDBString}; #[derive(Default)] -pub struct AddrInfo<'a> { +pub struct AddrInfo { // TODO does binja differentiate comments types on the API? - pub comments: Vec>, - pub label: Option>, + pub comments: Vec, + pub label: Option, // TODO make this a ref pub ty: Option, } -pub fn get_info<'a, K: IDAKind>( - id0: &'a ID0Section, - id1: &ID1Section, +pub fn get_info( + id0: &ID0Section, + id1: &ID1Section, id2: Option<&ID2Section>, - netdelta: Netdelta, -) -> Result, AddrInfo<'a>>> { + root_info: &RootInfo, +) -> Result, AddrInfo>> { let mut addr_info: HashMap, AddrInfo> = HashMap::new(); // comments defined on the address information + let netdelta = root_info.netdelta(); for (info, _info_size) in all_address_info(id0, id1, id2, netdelta) { let entry = addr_info.entry(info.address()).or_default(); if let Some(comment) = info.comment() { - entry.comments.push(comment.to_vec()); + entry.comments.push(comment.to_idb_string()); } if let Some(comment) = info.comment_repeatable() { - entry.comments.push(comment.to_vec()); + entry.comments.push(comment.to_idb_string()); } if let Some(comment) = info.comment_pre() { - entry.comments.extend(comment.map(|line| line.to_vec())); + entry + .comments + .extend(comment.map(|line| line.to_idb_string())); } if let Some(comment) = info.comment_post() { - entry.comments.extend(comment.map(|line| line.to_vec())); + entry + .comments + .extend(comment.map(|line| line.to_idb_string())); } if let Some(label) = info.label()? { entry.label = Some(label); } - if let Some(ty) = info.tinfo()? { + if let Some(ty) = info.tinfo(root_info)? { entry.ty = Some(ty); } } diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs index b1643ea321..456f77bd18 100644 --- a/plugins/idb_import/src/lib.rs +++ b/plugins/idb_import/src/lib.rs @@ -2,9 +2,11 @@ mod types; use std::borrow::Cow; use std::io::{BufRead, Cursor, Seek}; +use binaryninja::architecture::CoreArchitecture; +use idb_rs::id0::segment_register::SrareasIdx; use idb_rs::id1::ID1Section; -use idb_rs::id2::{ID2Section, ID2SectionVariants}; -use idb_rs::{IDAKind, IDAUsize, IDBFormat}; +use idb_rs::id2::ID2Section; +use idb_rs::{Address, IDAKind, IDAUsize, IDAVariants, IDBFormat, IDBString}; use types::*; mod addr_info; use addr_info::*; @@ -14,13 +16,13 @@ use binaryninja::debuginfo::{ CustomDebugInfoParser, DebugFunctionInfo, DebugInfo, DebugInfoParser, }; -use idb_rs::id0::{ID0Section, ID0SectionVariants}; +use idb_rs::id0::{ID0Section, RootInfo, SegmentIdx}; use idb_rs::til::section::TILSection; use idb_rs::til::TypeVariant as TILTypeVariant; use log::{error, trace, warn, LevelFilter}; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, ensure, Result}; use binaryninja::logger::Logger; struct IDBDebugInfoParser; @@ -135,8 +137,11 @@ fn parse_idb_info( let mut file = std::io::BufReader::new(file); let idb_kind = idb_rs::identify_idb_file(&mut file)?; match idb_kind { - idb_rs::IDBFormats::Separated(sep) => { - parse_idb_info_format(debug_info, bv, debug_file, sep, file, progress) + idb_rs::IDBFormats::Separated(IDAVariants::IDA32(sep32)) => { + parse_idb_info_format(debug_info, bv, debug_file, sep32, file, progress) + } + idb_rs::IDBFormats::Separated(IDAVariants::IDA64(sep64)) => { + parse_idb_info_format(debug_info, bv, debug_file, sep64, file, progress) } idb_rs::IDBFormats::InlineUncompressed(inline) => { parse_idb_info_format(debug_info, bv, debug_file, inline, file, progress) @@ -156,11 +161,11 @@ fn parse_idb_info( } } -fn parse_idb_info_format( +fn parse_idb_info_format( debug_info: &mut DebugInfo, bv: &BinaryView, debug_file: &BinaryView, - format: impl IDBFormat, + format: impl IDBFormat, mut idb_data: impl BufRead + Seek, progress: Box Result<(), ()>>, ) -> Result<()> { @@ -185,21 +190,7 @@ fn parse_idb_info_format( .map(|id2_idx| format.read_id2(&mut idb_data, id2_idx)) .transpose()?; - match (id0, id2) { - (ID0SectionVariants::IDA32(id0), Some(ID2SectionVariants::IDA32(id2))) => { - parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, Some(&id2))? - } - (ID0SectionVariants::IDA32(id0), None) => { - parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, None)? - } - (ID0SectionVariants::IDA64(id0), Some(ID2SectionVariants::IDA64(id2))) => { - parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, Some(&id2))? - } - (ID0SectionVariants::IDA64(id0), None) => { - parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, None)? - } - _ => unreachable!(), - } + parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, id2.as_ref())?; Ok(()) } @@ -289,21 +280,26 @@ pub fn import_til_section( fn parse_id0_section_info( debug_info: &mut DebugInfo, bv: &BinaryView, - debug_file: &BinaryView, + _debug_file: &BinaryView, id0: &ID0Section, - id1: &ID1Section, + id1: &ID1Section, id2: Option<&ID2Section>, ) -> Result<()> { let ida_info_idx = id0.root_node()?; let ida_info = id0.ida_info(ida_info_idx)?; let idb_baseaddr = ida_info.addresses.loading_base.into_u64(); let bv_baseaddr = bv.start(); - let netdelta = ida_info.netdelta(); // just addr this value to the address to translate from ida to bn // NOTE this delta could wrap here and while using translating - let addr_delta = bv_baseaddr.wrapping_sub(idb_baseaddr); + // TODO the base is somethimes zero, whats causes problems, for now I'll + // just use the min address to try calculanting the delta + let addr_delta = if idb_baseaddr == 0 { + bv_baseaddr.wrapping_sub(ida_info.addresses.min_ea.into_raw().into_u64()) + } else { + bv_baseaddr.wrapping_sub(idb_baseaddr) + }; - for (idb_addr, info) in get_info(id0, id1, id2, netdelta)? { + for (idb_addr, info) in get_info(id0, id1, id2, &ida_info)? { let addr = addr_delta.wrapping_add(idb_addr.into_raw().into_u64()); // just in case we change this struct in the future, this line will for us to review this code // TODO merge this data with folder locations @@ -314,12 +310,26 @@ fn parse_id0_section_info( } = info; // TODO set comments to address here for function in &bv.functions_containing(addr) { - function.set_comment_at(addr, &String::from_utf8_lossy(&comments.join(&b"\n"[..]))); + let comments: Vec = comments + .iter() + .map(idb_rs::IDBString::as_utf8_lossy) + .map(Cow::into_owned) + .collect(); + function.set_comment_at(addr, &comments.join("\n")); } - let bnty = ty - .as_ref() - .and_then(|ty| match translate_ephemeral_type(debug_file, ty) { + let srarea_idx = id0.srareas_idx()?; + let segment_idx = id0.segments_idx()?; + let bnty = ty.as_ref().and_then(|ty| { + match translate_ephemeral_type( + bv, + id0, + srarea_idx, + segment_idx, + &ida_info, + idb_addr, + ty, + ) { TranslateTypeResult::Translated(result) => Some(result), TranslateTypeResult::PartiallyTranslated(result, None) => { warn!("Unable to fully translate the type at {addr:#x}"); @@ -334,10 +344,10 @@ fn parse_id0_section_info( error!("Unable to translate the type at {addr:#x}: {bn_type_error}",); None } - }); + } + }); - let label: Option> = - label.as_ref().map(Cow::as_ref).map(String::from_utf8_lossy); + let label: Option> = label.as_ref().map(IDBString::as_utf8_lossy); match (label, &ty, bnty) { (label, Some(ty), bnty) if matches!(&ty.type_variant, TILTypeVariant::Function(_)) => { if bnty.is_none() { @@ -399,6 +409,317 @@ fn parse_id0_section_info( Ok(()) } +fn read_true_false_segreg( + id0: &ID0Section, + addr: Address, + srarea_idx: Option>, + segment_idx: Option>, + segreg_idx: usize, +) -> Result { + // default into false for the thumb value? + let segreg_raw = srarea_idx + .zip(segment_idx) + .map(|(srarea_idx, segment_idx)| { + id0.segment_register_value(addr, srarea_idx, segment_idx, segreg_idx) + }) + .transpose()? + .flatten(); + match segreg_raw.map(::into_u64) { + None | Some(0) => Ok(false), + Some(1) => Ok(true), + Some(2..) => Err(anyhow!("Invalid segment register value")), + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum CpuSize { + B16, + B32, + B64, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum CpuEndian { + Be, + Le, +} + +fn architecture_from_ida( + id0: &ID0Section, + srarea_idx: Option>, + segment_idx: Option>, + root_info: &RootInfo, + addr: Address, +) -> Result> { + let Some(proc) = id0.processor(root_info) else { + return Ok(None); + }; + use idb_rs::processors::*; + let lflags_32 = root_info.lflags.is_program_32b_or_bigger(); + let lflags_64 = root_info.lflags.is_program_64b(); + use CpuSize::*; + let bits = match (lflags_32, lflags_64) { + (true, true) => B64, + (true, false) => B32, + (false, false) => B16, + (false, true) => { + return Err(anyhow!( + "Unknown architecture size without lflags 32b and with 64b flag" + )) + } + }; + use CpuEndian::*; + let endian = if root_info.lflags.is_big_endian() { + Be + } else { + Le + }; + match proc { + Processor::Msp430(Msp430::Msp430) => { + ensure!(bits == B16, "MSP430 with non-16bits size is unknown"); + ensure!(endian == Le, "MSP430 BigEndian is unknown"); + Ok(CoreArchitecture::by_name("msp430")) + } + Processor::Arm(arm) => { + use idb_rs::processors::Arm::*; + match bits { + B64 => return Ok(CoreArchitecture::by_name("aarch64")), + B16 => return Err(anyhow!("ARM 16bits is unknown")), + B32 => {} + } + let is_thumb = read_true_false_segreg( + id0, + addr, + srarea_idx, + segment_idx, + usize::from(ArmReg::T) - ArmReg::SEGMENT_REGISTERS_START, + )?; + match (arm, endian, is_thumb) { + (Arm | ProcAltXScaleL, Be, _) | (Armb | ProcAltXScaleB, Le, _) => { + Err(anyhow!("ARM with conflicting endian: {arm:?} {endian:?}")) + } + + (Arm, Le, false) => Ok(CoreArchitecture::by_name("armv7")), + (Armb, Be, false) => Ok(CoreArchitecture::by_name("armv7eb")), + (Arm, Le, true) => Ok(CoreArchitecture::by_name("thumb2")), + (Armb, Be, true) => Ok(CoreArchitecture::by_name("thumb2eb")), + + // TODO default into armv7/thumb2? + (ProcAltArm710A | ProcAltXScaleL, Le, true) => { + Ok(CoreArchitecture::by_name("thumb2")) + } + (ProcAltArm710A | ProcAltXScaleB, Be, true) => { + Ok(CoreArchitecture::by_name("thumb2eb")) + } + (ProcAltArm710A | ProcAltXScaleL, Le, false) => { + Ok(CoreArchitecture::by_name("armv7")) + } + (ProcAltArm710A | ProcAltXScaleB, Be, false) => { + Ok(CoreArchitecture::by_name("armv7eb")) + } + } + } + Processor::Mips(mips) => { + use idb_rs::processors::Mips::*; + // TODO + // the mips16 pseudoregister is used to switch between standard MIPS and MIPS16 or microMIPS + let is_mips16 = read_true_false_segreg( + id0, + addr, + srarea_idx, + segment_idx, + usize::from(MipsReg::Mips16) - MipsReg::SEGMENT_REGISTERS_START, + )?; + + match (mips, endian, bits, is_mips16) { + (_, _, B16, _) => Err(anyhow!("Mips 16bits is unknown")), + (Mipsl | Mipsrl | R5900L | Octeonl | Tx19Al, Be, _, _) + | (Mipsb | Mipsr | R5900B | Octeonb | Tx19Ab, Le, _, _) => { + Err(anyhow!("Mips with conflicting endian: {mips:?} {endian:?}")) + } + + // TODO there is any MIPS cpu here that don't support mips16? + // TODO binaja don't implement mips16? + ( + Mipsl | Mipsb | Mipsrl | Mipsr | R5900L | R5900B | Octeonl | Octeonb | Psp + | Tx19Al | Tx19Ab, + _, + _, + true, + ) => Ok(None), + + // TODO I don't know what Mipsr means, just leave it unimplemented for now + (Mipsr | Mipsrl, _, _, _) => Ok(None), + + (Mipsl, Le, B32, false) => Ok(CoreArchitecture::by_name("mipsel32")), + (Mipsl, Le, B64, false) => Ok(CoreArchitecture::by_name("mipsel64")), + (Mipsb, Be, B32, false) => Ok(CoreArchitecture::by_name("mips32")), + (Mipsb, Be, B64, false) => Ok(CoreArchitecture::by_name("mips64")), + + (R5900L | R5900B, _, B64, _) => Err(anyhow!("Mips R5900 64bits is unknown")), + + (Tx19Al | Tx19Ab, _, B64, _) => Err(anyhow!("Mips Tx19A 64bits is unknown")), + (Tx19Al | Tx19Ab, _, B32, _) => Ok(None), + + (R5900L, Le, B32, false) => Ok(CoreArchitecture::by_name("r5900l")), + (R5900B, Be, B32, false) => Ok(CoreArchitecture::by_name("r5900b")), + + (Octeonl | Octeonb, _, B32, _) => Err(anyhow!("Mips Octeon 32bits is unknown")), + (Octeonb, Be, B64, false) => Ok(CoreArchitecture::by_name("cavium-mips64")), + (Octeonl, Le, B64, false) => Ok(CoreArchitecture::by_name("cavium-mipsel64")), + + (Psp, Be, _, _) => Err(anyhow!("Mips PSP BigEndian is unknown")), + (Psp, _, B64, _) => Err(anyhow!("Mips PSP 64bits is unknown")), + (Psp, Le, B32, _) => Ok(None), + } + + // TODO identify the translation for + //mips3 + //mipsel3 + } + Processor::Ppc(ppc) => { + use idb_rs::processors::Ppc::*; + let is_vle = read_true_false_segreg( + id0, + addr, + srarea_idx, + segment_idx, + usize::from(PpcReg::Vle) - PpcReg::SEGMENT_REGISTERS_START, + )?; + + match (ppc, endian, bits, is_vle) { + (_, _, B16, _) => Err(anyhow!("PPC 16bits is unknown")), + (Ppcl, Be, _, _) | (Ppc, Le, _, _) => { + Err(anyhow!("PPC with conflicting endian: {ppc:?} {endian:?}")) + } + (Ppcl, Le, _, true) => Err(anyhow!("PPC with VLE Little Endian is unknown")), + // but ghidra declares it, so I'll put this as possible: + // https://github.com/NationalSecurityAgency/ghidra/blob/1ca9e32a5712bc48a603f9e60d8f692220071eb7/Ghidra/Processors/PowerPC/data/languages/ppc_64_isa_vle_be.slaspec + (Ppc, Be, B64, true) => Ok(None), + (Ppc, Be, B32, true) => Ok(CoreArchitecture::by_name("ppcvle")), + (Ppcl, Le, B32, false) => Ok(CoreArchitecture::by_name("ppc_le")), + (Ppc, Be, B32, false) => Ok(CoreArchitecture::by_name("ppc")), + (Ppc, Be, B64, false) => Ok(CoreArchitecture::by_name("ppc64")), + (Ppcl, Le, B64, false) => Ok(CoreArchitecture::by_name("ppc64_le")), + } + // TODO what about those? + //ppc_qpx + //ppc_spe + //ppc_ps + } + Processor::Riscv(Riscv::Riscv) => match (endian, bits) { + (Le, B64) => Ok(CoreArchitecture::by_name("rv64gc")), + (Le, B32) => Ok(CoreArchitecture::by_name("rv32gc")), + (_, B16) => Err(anyhow!("RiscV 16bits is unknown")), + (Be, _) => Err(anyhow!("RiscV BigEndian is unknown")), + }, + Processor::Pc(pc) => { + use Pc::*; + if endian == Be { + return Err(anyhow!( + "Unknown PC BigEndian, all X86 family is LittleEndian" + )); + } + match (pc, bits) { + (ProcAlt8086 | ProcAlt80286R | ProcAlt80286P, B32 | B64) => { + return Err(anyhow!( + "Unknown PC {pc:?} {bits:?}, this cpu is 16bits only" + )) + } + ( + ProcAlt80386R | ProcAlt80386P | ProcAlt80486R | ProcAlt80486P | ProcAlt80586R + | ProcAlt80586P | ProcAlt80686P | P2 | K62 | P3 | Athlon, + B64, + ) => { + return Err(anyhow!( + "Unknown PC {pc:?} {bits:?}, this cpu is 32/16bits only" + )) + } + + // all x86 can execute x86-16 + (_, B16) => Ok(CoreArchitecture::by_name("x86_16")), + // all cpus after 80386 (AKA i386) can execute x86_32 + ( + ProcAlt80386R | ProcAlt80386P | ProcAlt80486R | ProcAlt80486P | ProcAlt80586R + | ProcAlt80586P | ProcAlt80686P | P2 | K62 | P3 | Athlon | P4 | Metapc, + B32, + ) => Ok(CoreArchitecture::by_name("x86_32")), + // only P4 and after can execute x86_64 + (P4 | Metapc, B64) => Ok(CoreArchitecture::by_name("x86_32")), + } + } + Processor::Tricore(Tricore::Tricore) => { + ensure!(bits == B32, "Tricore {bits:?} CPU is unknown"); + ensure!(endian == Le, "Tricore BigEndian is unknown"); + Ok(CoreArchitecture::by_name("tricore")) + } + Processor::Script(_) => Ok(None), + Processor::M740(_) + | Processor::Ia(_) + | Processor::M7900(_) + | Processor::Avr(_) + | Processor::Alpha(_) + | Processor::Nec850(_) + | Processor::Sparc(_) + | Processor::Arc(_) + | Processor::Fr(_) + | Processor::Tms320C3(_) + | Processor::M65816(_) + | Processor::F2Mc(_) + | Processor::Rl78(_) + | Processor::Proc78K0(_) + | Processor::Dsp56K(_) + | Processor::M65(_) + | Processor::Kr1878(_) + | Processor::S390(_) + | Processor::Sam8(_) + | Processor::C166(_) + | Processor::Dalvik(_) + | Processor::Mc68K(_) + | Processor::Tms320C1(_) + | Processor::Spc700(_) + | Processor::I196(_) + | Processor::Mc6812(_) + | Processor::I960(_) + | Processor::M16C(_) + | Processor::Pdp11(_) + | Processor::Tms320C6(_) + | Processor::M32R(_) + | Processor::Java(_) + | Processor::Mc6816(_) + | Processor::Z80(_) + | Processor::Cli(_) + | Processor::Hppa(_) + | Processor::H8(_) + | Processor::Oakdsp(_) + | Processor::Xtensa(_) + | Processor::Pic16(_) + | Processor::H8500(_) + | Processor::Tms32028(_) + | Processor::Proc78K0S(_) + | Processor::Tms320C5(_) + | Processor::Z8(_) + | Processor::Mc8(_) + | Processor::M7700(_) + | Processor::Tms32054(_) + | Processor::Unsp(_) + | Processor::Rx(_) + | Processor::Wasm(_) + | Processor::Sh3(_) + | Processor::St7(_) + | Processor::Ad218X(_) + | Processor::St9(_) + | Processor::Tms32055(_) + | Processor::Pic(_) + | Processor::I860(_) + | Processor::St20(_) + | Processor::I51(_) + | Processor::Xa(_) + | Processor::Ebc(_) + | Processor::Spu(_) => Ok(None), + } +} + #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn CorePluginInit() -> bool { diff --git a/plugins/idb_import/src/types.rs b/plugins/idb_import/src/types.rs index 77c089e910..9f2f132121 100644 --- a/plugins/idb_import/src/types.rs +++ b/plugins/idb_import/src/types.rs @@ -11,16 +11,19 @@ use binaryninja::types::{ EnumerationBuilder, FunctionParameter, MemberAccess, MemberScope, StructureBuilder, StructureType, Type, }; +use idb_rs::id0::segment_register::SrareasIdx; +use idb_rs::id0::{ID0Section, RootInfo, SegmentIdx}; use idb_rs::til::function::CallingConvention as TILCallingConvention; use idb_rs::til::pointer::Pointer as TILPointer; use idb_rs::til::r#enum::EnumMembers; 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, - r#union::Union as TILUnion, section::TILSection, TILTypeInfo, Type as TILType, - TypeVariant as TILTypeVariant, + section::TILSection, udt::UDTMember as TILUDTMember, udt::UDT as TILUDT, TILTypeInfo, + Type as TILType, TypeVariant as TILTypeVariant, }; -use idb_rs::IDBString; +use idb_rs::{Address, IDAKind, IDBString}; + +use crate::architecture_from_ida; #[derive(Debug, Clone)] pub enum BnTypeError { @@ -306,7 +309,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { fn condensate_bitfields_from_struct( &self, offset: usize, - members_slice: &[TILStructMember], + members_slice: &[TILUDTMember], struct_builder: &mut StructureBuilder, ) { if members_slice.is_empty() { @@ -326,7 +329,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { let mut create_field = |start_idx, i, bytes| { let name = if start_idx == i - 1 { - let member: &TILStructMember = &members_slice[i - 1]; + let member: &TILUDTMember = &members_slice[i - 1]; member .name .as_ref() @@ -366,7 +369,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { } } - fn translate_struct(&self, ty_struct: &TILStruct) -> TranslateTypeResult { + fn translate_struct(&self, ty_struct: &TILUDT) -> 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()); @@ -376,7 +379,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { if let Some(align) = ty_struct.alignment { structure.alignment(align.get().into()); } - structure.packed(ty_struct.is_unaligned && ty_struct.is_uknown_8); + structure.packed(ty_struct.is_unaligned && ty_struct.is_unknown_8); let mut errors = vec![]; let mut first_bitfield_seq = None; @@ -440,16 +443,16 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { } } - fn translate_union(&self, ty_union: &TILUnion) -> TranslateTypeResult { + fn translate_union(&self, ty_union: &TILUDT) -> TranslateTypeResult { let mut is_partial = false; let mut structure = StructureBuilder::new(); structure.structure_type(StructureType::UnionStructureType); let mut errors = vec![]; for (i, member) in ty_union.members.iter().enumerate() { // bitfields can be translated into complete fields - let mem = match &member.ty.type_variant { + let mem = match &member.member_type.type_variant { TILTypeVariant::Bitfield(field) => field_from_bytes(field.nbytes.get().into()), - _ => match self.translate_type(&member.ty) { + _ => match self.translate_type(&member.member_type) { TranslateTypeResult::Translated(ty) => ty, TranslateTypeResult::Error(error) => { errors.push((i, error)); @@ -580,21 +583,28 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { 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( + TILTypeVariant::Typeref(typeref) => { + match self.til.get_ref_value_idx(&typeref.typeref_value) { + Some(idx) => self.find_typedef(&self.types[idx]), + None => match &typeref.typeref_value { + idb_rs::til::TyperefValue::Name(name) => { + // search the default non-defined names 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)) + .and_then(|name| self.find_typedef_by_name(name.as_bytes())) + .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::Ordinal(ord) => { + TranslateTypeResult::Error(BnTypeError::OrdinalNotFound(*ord)) + } + }, } - }, + } TILTypeVariant::Pointer(ty) => self.translate_pointer(ty), TILTypeVariant::Function(fun) => self.translate_function(fun), @@ -607,11 +617,23 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { } } -pub fn translate_ephemeral_type(debug_file: &BinaryView, ty: &TILType) -> TranslateTypeResult { +pub fn translate_ephemeral_type( + bv: &BinaryView, + id0: &ID0Section, + srarea_idx: Option>, + segment_idx: Option>, + root_info: &RootInfo, + addr: Address, + ty: &TILType, +) -> TranslateTypeResult { // in case we need to translate types - let header = idb_rs::til::ephemeral_til_header(); + let header = root_info.til_header(); + let arch = architecture_from_ida(id0, srarea_idx, segment_idx, root_info, addr) + .ok() + .flatten(); let translator = TranslateIDBTypes { - arch: debug_file.default_arch().unwrap(/* TODO */), + // TODO find the correct processor using the segment registers + arch: arch.unwrap_or_else(|| bv.default_arch().unwrap(/* TODO */)), progress: |_, _| Ok(()), // TODO it's unclear what to do here til: &TILSection { @@ -630,7 +652,7 @@ pub fn translate_til_types( arch: CoreArchitecture, til: &TILSection, progress: impl Fn(usize, usize) -> Result<(), ()>, -) -> Result> { +) -> Result>> { let total = til.symbols.len() + til.types.len(); let mut types = Vec::with_capacity(total); let mut types_by_ord = HashMap::with_capacity(total);