From 7ec5467b5ad67e6f0398c47cfc3759eb87466a83 Mon Sep 17 00:00:00 2001 From: omiinaya Date: Tue, 20 Oct 2026 23:51:43 -0400 Subject: [PATCH] Don't abandon the extab search at a gap between sections locate_extab_extabindex() probes for _eti_init_info starting at section_end - ETI_INIT_INFO_SIZE * (num_text_sections + 1) and walks forward, reading a candidate table at each address. A section's size can stop short of the next section: sizes come from _rom_copy_info, whose values are rounded differently from the file's. The first candidate then lands in the gap, read_eti_init_info() fails with "Failed to locate section @ ", and the `?` on it abandoned the search for the whole program -- so extab/extabindex were never named. The result is a game that splits with no exception-table splits at all, or, once anything names extabindex, a hard failure: "Failed to find extab section". Clamp the first candidate to the section start, and treat an unreadable candidate as "not this one" instead of aborting. Also give the end-of-table read in the second loop a message that says what it was doing. Reproduced with v1.8.4 on Sonic Adventure 2 Battle's DOL ("Failed to locate section @ 0x80173124", the program has no extab) and on a DOL with Animal Crossing's section layout (.init 0x80003100 stopping at 0x800055F0, extab 0x80005620, extabindex 0x80005660, _eti_init_info 0x80005684), where the warning is gone after the change. For the Sonic DOL the split output (config.json, splits.txt, symbols.txt) is byte-identical to v1.8.4's. --- src/util/dol.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/util/dol.rs b/src/util/dol.rs index 3ad425a8..bb809a35 100644 --- a/src/util/dol.rs +++ b/src/util/dol.rs @@ -871,16 +871,31 @@ fn locate_extab_extabindex(obj: &mut ObjInfo) -> Result<()> { let dol_section_start = dol_section.address as u32; let dol_section_end = dol_section_start + dol_section.size as u32; let eti_init_info_addr = { - let mut addr = dol_section_end - (ETI_INIT_INFO_SIZE * (num_text_sections + 1)) as u32; + // A section's size can stop short of the next section (the copied-to-RAM size in _rom_copy_info + // is often rounded differently from the file's), leaving gaps in the section map. A candidate + // address that lands in one says nothing about the others: skip it, don't abandon the search. + let lowest = dol_section_end + .saturating_sub((ETI_INIT_INFO_SIZE * (num_text_sections + 1)) as u32) + .max(dol_section_start); + let mut addr = lowest; loop { - let eti_init_info = read_eti_init_info(obj, addr)?; + let eti_init_info = match read_eti_init_info(obj, addr) { + Ok(eti_init_info) => eti_init_info, + Err(_) => { + addr += 4; + if addr > dol_section_end.saturating_sub(ETI_INIT_INFO_SIZE as u32) { + continue 'outer; + } + continue; + } + }; if validate_eti_init_info(obj, &eti_init_info, dol_section_start, dol_section_end)? { log::debug!("Found _eti_init_info @ {addr:#010X}"); break addr; } addr += 4; - if addr > dol_section_end - ETI_INIT_INFO_SIZE as u32 { + if addr > dol_section_end.saturating_sub(ETI_INIT_INFO_SIZE as u32) { continue 'outer; } } @@ -889,7 +904,12 @@ fn locate_extab_extabindex(obj: &mut ObjInfo) -> Result<()> { let eti_init_info_end = { let mut addr = eti_init_info_addr; loop { - let eti_init_info = read_eti_init_info(obj, addr)?; + let Ok(eti_init_info) = read_eti_init_info(obj, addr) else { + bail!( + "Failed to locate _eti_init_info end (start @ {:#010X})", + eti_init_info_addr + ); + }; addr += 16; if eti_init_info.is_zero() { break;