diff --git a/Cargo.lock b/Cargo.lock index 27939e4..75adfd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,9 +339,9 @@ checksum = "c2e06f9bce634a3c898eb1e5cb949ff63133cbb218af93cc9b38b31d6f3ea285" [[package]] name = "cwextab" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "701f6867c92e1b64ddcc4b416194be3121b8f7ba5352a70ed5fd3295a7d8e0e1" +checksum = "9dd95393b8cc20937e4757d9c22b89d016613e934c60dcb073bd8a5aade79fcf" dependencies = [ "thiserror 2.0.12", ] diff --git a/src/cmd/dol.rs b/src/cmd/dol.rs index f8c6357..769f325 100644 --- a/src/cmd/dol.rs +++ b/src/cmd/dol.rs @@ -838,7 +838,7 @@ fn load_dol_module( }; if config.clean_extab.unwrap_or(false) { log::debug!("Cleaning extab for {}", config.name()); - clean_extab(&mut obj)?; + clean_extab(&mut obj, std::iter::empty())?; } Ok((obj, object_path)) } diff --git a/src/cmd/extab.rs b/src/cmd/extab.rs index 07c0a36..5060c57 100644 --- a/src/cmd/extab.rs +++ b/src/cmd/extab.rs @@ -30,15 +30,18 @@ enum SubCommand { } #[derive(FromArgs, PartialEq, Eq, Debug)] -/// Rewrites extab data in a DOL or ELF file, zeroing out any uninitialized padding bytes. +/// Rewrites extab data in a DOL or ELF file, replacing any uninitialized padding bytes. #[argp(subcommand, name = "clean")] pub struct CleanArgs { #[argp(positional, from_str_fn(native_path))] - /// path to input file + /// Path to input file input: Utf8NativePathBuf, #[argp(positional, from_str_fn(native_path))] - /// path to output file + /// Path to output file output: Utf8NativePathBuf, + #[argp(option, short = 'p')] + /// Data to replace padding bytes with, encoded as a hexadecimal string. If not specified, padding bytes will be zeroed instead. + padding: Option, } pub fn run(args: Args) -> Result<()> { @@ -56,7 +59,13 @@ fn clean_extab(args: CleanArgs) -> Result<()> { let name = args.input.file_stem().unwrap_or_default(); process_dol(file.map()?, name)? }; - let num_cleaned = util::extab::clean_extab(&mut obj)?; + let padding: Vec = match args.padding { + None => Vec::new(), + Some(padding_str) => { + hex::decode(padding_str).context("Failed to decode padding bytes from hex")? + } + }; + let num_cleaned = util::extab::clean_extab(&mut obj, padding.iter().copied())?; tracing::debug!("Cleaned {num_cleaned} extab symbols"); let mut out = buf_writer(&args.output)?; if is_elf { diff --git a/src/util/extab.rs b/src/util/extab.rs index 0c6dfff..13ae8b0 100644 --- a/src/util/extab.rs +++ b/src/util/extab.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use crate::obj::ObjInfo; -pub fn clean_extab(obj: &mut ObjInfo) -> Result { +pub fn clean_extab(obj: &mut ObjInfo, mut padding: impl Iterator) -> Result { let (extab_section_index, extab_section) = obj .sections .iter_mut() @@ -27,19 +27,25 @@ pub fn clean_extab(obj: &mut ObjInfo) -> Result { })?; let mut updated = false; for action in &decoded.exception_actions { - let section_offset = - (symbol.address - extab_section.address) as usize + action.action_offset as usize; - let clean_data = action.get_exaction_bytes(true); - let orig_data = - &mut extab_section.data[section_offset..section_offset + clean_data.len()]; - if orig_data != clean_data { - updated = true; + // Check if the current action has padding + if let Some(padding_offset) = action.get_struct_padding_offset() { + let index = padding_offset as usize; + let section_offset = (symbol.address - extab_section.address) as usize + + action.action_offset as usize; + let mut clean_data: Vec = action.get_exaction_bytes(false); + // Write the two padding bytes + clean_data[index] = padding.next().unwrap_or(0); + clean_data[index + 1] = padding.next().unwrap_or(0); + + let orig_data = + &mut extab_section.data[section_offset..section_offset + clean_data.len()]; orig_data.copy_from_slice(&clean_data); + updated = true; } } if updated { tracing::debug!( - "Removed uninitialized bytes in {} (extab {:#010X}..{:#010X})", + "Replaced uninitialized bytes in {} (extab {:#010X}..{:#010X})", symbol.name, symbol.address, symbol.address + symbol.size