From 7b28ca1d3c6f2c249bb23b349057b29115497990 Mon Sep 17 00:00:00 2001 From: Chris Kader Date: Fri, 5 Jun 2026 03:22:27 -0500 Subject: [PATCH 1/2] Parse bare BT_UNK and harden function dirtree dump A type byte of 0x00 (BT_UNK with BTMT_SIZE0) is IDA's unknown type of unspecified size, which appears in real databases as function argument and return types. It was being rejected with "forbidden use of BT_UNK", which aborted type parsing for any function that used it. Treat it like BT_UNKNOWN (unknown, unspecified size) instead. Also harden dump-dirtree-funcs so a single function whose label or type fails to parse no longer panics the whole dump: per-function parse errors are tolerated and, if printing a function still fails, the entry is emitted with an inline error note rather than unwrapping. --- src/til.rs | 7 ++++--- src/tools/dump_dirtree_funcs.rs | 24 +++++++++++------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/til.rs b/src/til.rs index 4ba5e05..ed163b4 100644 --- a/src/til.rs +++ b/src/til.rs @@ -392,9 +392,10 @@ impl Basic { // InnerRef fb47f2c2-3c08-4d40-b7ab-3c7736dce31d 0x480874 BT_UNK => { let bytes = match btmt { - BTMT_SIZE0 => { - return Err(anyhow!("forbidden use of BT_UNK")) - } + // A bare `BT_UNK` (type byte 0x00) is IDA's unknown type of unspecified + // size; treat it like `BT_UNKNOWN` rather than rejecting it, since it shows + // up in real databases (e.g. as a function argument/return type). + BTMT_SIZE0 => 0, BTMT_SIZE12 => 2, // BT_UNK_WORD BTMT_SIZE48 => 8, // BT_UNK_QWORD BTMT_SIZE128 => 0, // BT_UNKNOWN diff --git a/src/tools/dump_dirtree_funcs.rs b/src/tools/dump_dirtree_funcs.rs index 0fcf7ce..943cd62 100644 --- a/src/tools/dump_dirtree_funcs.rs +++ b/src/tools/dump_dirtree_funcs.rs @@ -20,13 +20,13 @@ fn dump_inner((id0, id1, id2): Id0Id1Id2Variant) -> Result<()> { if let Some(dirtree) = id0.dirtree_function_address()? { print_dirtree( |entry| { - print_function( - &id0, - &id1, - id2.as_ref(), - Address::from_raw(*entry), - ) - .unwrap() + let address = Address::from_raw(*entry); + if let Err(err) = + print_function(&id0, &id1, id2.as_ref(), address) + { + // Don't let a single unparsable function abort the whole dump. + println!("{:#x}: ", address.into_raw()); + } }, &dirtree, ); @@ -45,14 +45,12 @@ pub fn print_function( let root_info = id0.ida_info(root_info_idx)?; let image_base = root_info.netdelta(); let info = AddressInfo::new(id0, id1, id2, image_base, address); - let name = info - .as_ref() - .and_then(|info| info.label().transpose()) - .transpose()?; + // Tolerate per-function label/type parse failures so one bad entry doesn't abort the dump; + // such a function simply prints without the failing piece. + let name = info.as_ref().and_then(|info| info.label().ok().flatten()); let ty = info .as_ref() - .and_then(|info| info.tinfo(&root_info).transpose()) - .transpose()?; + .and_then(|info| info.tinfo(&root_info).ok().flatten()); print!("{:#x}:", address.into_raw()); match (name, ty) { From 10c7fb7534ebf47acbdc0d953ccb50f5b06603e5 Mon Sep 17 00:00:00 2001 From: Chris Kader Date: Fri, 5 Jun 2026 03:25:06 -0500 Subject: [PATCH 2/2] Tolerate trailing data after IDBParam outside restrictive mode Some databases carry extra bytes after the IDBParam structure. Erroring on that aborted root-info parsing (and therefore the whole import) for those files. Gate the "Data left after the IDBParam" check behind the `restrictive` feature, matching how other strictness checks are handled, so normal parsing tolerates the trailing data. --- src/id0/root_info.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/id0/root_info.rs b/src/id0/root_info.rs index 99a2623..f709642 100644 --- a/src/id0/root_info.rs +++ b/src/id0/root_info.rs @@ -275,7 +275,10 @@ impl RootInfo { match version { // TODO old version may contain extra data at the end with unknown purpose ..=699 => {} - 700.. => ensure!(input.is_empty(), "Data left after the IDBParam",), + 700.. => { + #[cfg(feature = "restrictive")] + ensure!(input.is_empty(), "Data left after the IDBParam"); + } } Ok(param) }