From e3875a3b4e6379166d923b2e4a6555a49ed732d0 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 3 May 2026 19:31:13 -0400 Subject: [PATCH 1/5] Support detecting more symbol names for strings --- objdiff-core/src/arch/ppc/flow_analysis.rs | 2 ++ objdiff-core/src/arch/ppc/mod.rs | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/objdiff-core/src/arch/ppc/flow_analysis.rs b/objdiff-core/src/arch/ppc/flow_analysis.rs index 13f7273a..44b620f2 100644 --- a/objdiff-core/src/arch/ppc/flow_analysis.rs +++ b/objdiff-core/src/arch/ppc/flow_analysis.rs @@ -513,6 +513,8 @@ pub fn ppc_data_flow_analysis( ) } +// Note: This function only supports MWCC ASCII strings. +// Other encodings and other compilers are currently not supported. fn get_string_data(obj: &Object, symbol_index: usize, offset: Simm) -> Option<&str> { if let Some(sym) = obj.symbols.get(symbol_index) && sym.name.starts_with("@stringBase") diff --git a/objdiff-core/src/arch/ppc/mod.rs b/objdiff-core/src/arch/ppc/mod.rs index b8a6bab1..0cefda20 100644 --- a/objdiff-core/src/arch/ppc/mod.rs +++ b/objdiff-core/src/arch/ppc/mod.rs @@ -359,9 +359,12 @@ impl Arch for ArchPpc { fn guess_data_type(&self, resolved: ResolvedInstructionRef, bytes: &[u8]) -> Option { if resolved.relocation.is_some_and(|r| { - r.symbol.name.starts_with("@stringBase") || r.symbol.name.starts_with("$SG") + r.symbol.name.starts_with("@stringBase") + || r.symbol.name.starts_with("@wstringBase") + || r.symbol.name.starts_with("$SG") + || r.symbol.demangled_name == Some("`string'".to_string()) }) { - // Pooled string. + // Compiler-generated symbol name for a string or a pool of strings. return Some(DataType::String); } let opcode = powerpc::Opcode::from(resolved.ins_ref.opcode); From 9e00c2f3acfc7212d99adf0f1a2e4ae25b847db0 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 3 May 2026 19:35:51 -0400 Subject: [PATCH 2/5] Fix string detectiong being broken for encodings that use null terminators --- objdiff-core/src/arch/mod.rs | 39 +++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/objdiff-core/src/arch/mod.rs b/objdiff-core/src/arch/mod.rs index 59da3cca..5d44aaea 100644 --- a/objdiff-core/src/arch/mod.rs +++ b/objdiff-core/src/arch/mod.rs @@ -42,15 +42,15 @@ pub mod x86; pub const OPCODE_INVALID: u16 = u16::MAX; pub const OPCODE_DATA: u16 = u16::MAX - 1; -const SUPPORTED_ENCODINGS: [(&encoding_rs::Encoding, &str); 7] = [ +const SUPPORTED_ENCODINGS_WITH_NULL_TERM: [(&encoding_rs::Encoding, &str); 5] = [ (encoding_rs::UTF_8, "UTF-8"), (encoding_rs::SHIFT_JIS, "Shift JIS"), - (encoding_rs::UTF_16BE, "UTF-16BE"), - (encoding_rs::UTF_16LE, "UTF-16LE"), (encoding_rs::WINDOWS_1252, "Windows-1252"), (encoding_rs::EUC_JP, "EUC-JP"), (encoding_rs::BIG5, "Big5"), ]; +const SUPPORTED_ENCODINGS_NO_NULL_TERM: [(&encoding_rs::Encoding, &str); 2] = + [(encoding_rs::UTF_16BE, "UTF-16BE"), (encoding_rs::UTF_16LE, "UTF-16LE")]; /// Represents the type of data associated with an instruction #[derive(PartialEq)] @@ -174,24 +174,27 @@ impl DataType { strs.push((format!("{bytes:#?}"), None, None)); } DataType::String => { - // Special case to display (ASCII) as the label for ASCII-only strings. - let mut is_ascii = false; - if bytes.is_ascii() - && let Ok(str) = str::from_utf8(bytes) - { - let trimmed = str.trim_end_matches('\0'); - if !trimmed.is_empty() { - let copy_string = escape_special_ascii_characters(trimmed); - strs.push((trimmed.to_string(), Some("ASCII".into()), Some(copy_string))); - is_ascii = true; + if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') { + let str_bytes = &bytes[..nul_idx]; + // Special case to display (ASCII) as the label for ASCII-only strings. + let (cow, _, had_errors) = encoding_rs::UTF_8.decode(str_bytes); + if !had_errors && cow.is_ascii() { + let string = format!("{cow}"); + let copy_string = escape_special_ascii_characters(&string); + strs.push((string, Some("ASCII".into()), Some(copy_string))); + } + for (encoding, encoding_name) in SUPPORTED_ENCODINGS_WITH_NULL_TERM { + let (cow, _, had_errors) = encoding.decode(str_bytes); + // Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible. + if !had_errors && (!encoding.is_ascii_compatible() || !cow.is_ascii()) { + let string = format!("{cow}"); + let copy_string = escape_special_ascii_characters(&string); + strs.push((string, Some(encoding_name.into()), Some(copy_string))); + } } } - for (encoding, encoding_name) in SUPPORTED_ENCODINGS { - // Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible. - if is_ascii && encoding.is_ascii_compatible() { - continue; - } + for (encoding, encoding_name) in SUPPORTED_ENCODINGS_NO_NULL_TERM { let (cow, _, had_errors) = encoding.decode(bytes); if had_errors { continue; From d3b6e2498761c4b7f6b1a066f3089a6adf9596f9 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 3 May 2026 19:46:47 -0400 Subject: [PATCH 3/5] Add test cases for string detection and decoding --- objdiff-core/tests/arch_ppc.rs | 87 ++++++++++++++++++ objdiff-core/tests/common.rs | 21 +++++ .../tests/data/ppc/KinectSharePanel.obj | Bin 0 -> 47532 bytes 3 files changed, 108 insertions(+) create mode 100644 objdiff-core/tests/data/ppc/KinectSharePanel.obj diff --git a/objdiff-core/tests/arch_ppc.rs b/objdiff-core/tests/arch_ppc.rs index 78aaaea9..57ae05e0 100644 --- a/objdiff-core/tests/arch_ppc.rs +++ b/objdiff-core/tests/arch_ppc.rs @@ -122,3 +122,90 @@ fn read_vmx128_coff() { let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config); insta::assert_snapshot!(output); } + +#[test] +#[cfg(feature = "ppc")] +fn decode_sjis_pooled_strings() { + // Test multiple pooled Shift JIS strings separated by a single null byte between entries. (MWCC) + let diff_config = diff::DiffObjConfig { combine_data_sections: true, ..Default::default() }; + let obj = obj::read::parse( + include_object!("data/ppc/m_Do_hostIO.o"), + &diff_config, + diff::DiffSide::Base, + ) + .unwrap(); + common::assert_literal_value( + &obj, + &diff_config, + "createChild__16mDoHIO_subRoot_cFPCcP13JORReflexible", + 15, + "Shift JIS", + "危険:既に登録されているホストIOをふたたび登録しようとしています<%s>\n", + ); + common::assert_literal_value( + &obj, + &diff_config, + "createChild__16mDoHIO_subRoot_cFPCcP13JORReflexible", + 42, + "Shift JIS", + "ホストIOの空きエントリがありません。登録できませんでした。\n", + ); +} + +#[test] +#[cfg(feature = "ppc")] +fn decode_utf16_unpooled_strings() { + // Test unpooled UTF-16BE wide strings with null bytes at the start, end, and in the middle of the string. (MSVC) + let diff_config = diff::DiffObjConfig { combine_data_sections: true, ..Default::default() }; + let obj = obj::read::parse( + include_object!("data/ppc/KinectSharePanel.obj"), + &diff_config, + diff::DiffSide::Base, + ) + .unwrap(); + common::assert_literal_value( + &obj, + &diff_config, + "?OnPostLink@KinectSharePanel@@AAA?AVDataNode@@PAVDataArray@@@Z", + 84, + "UTF-16BE", + "Title Text", + ); + common::assert_literal_value( + &obj, + &diff_config, + "?OnPostLink@KinectSharePanel@@AAA?AVDataNode@@PAVDataArray@@@Z", + 120, + "UTF-16BE", + "http://www.dancecentral.com/content-assets/2012/06/2012E3LogoBox_tn.jpg", + ); +} + +#[test] +#[cfg(feature = "ppc")] +fn decode_ascii_strings_with_null_padding() { + // Test unpooled ASCII strings with more than one null byte at the end. + let diff_config = diff::DiffObjConfig { combine_data_sections: true, ..Default::default() }; + let obj = obj::read::parse( + include_object!("data/ppc/vmx128.obj"), + &diff_config, + diff::DiffSide::Base, + ) + .unwrap(); + common::assert_literal_value( + &obj, + &diff_config, + "?PrintVector@@YAXPBDU__vector4@@@Z", + 24, + "ASCII", + "%s: [%.2f, %.2f, %.2f, %.2f]\n", + ); + common::assert_literal_value( + &obj, + &diff_config, + "?ReservedRegisterExample@@YAXXZ", + 59, + "ASCII", + "Result from vr66", + ); +} diff --git a/objdiff-core/tests/common.rs b/objdiff-core/tests/common.rs index 311c622c..a05633d6 100644 --- a/objdiff-core/tests/common.rs +++ b/objdiff-core/tests/common.rs @@ -50,3 +50,24 @@ macro_rules! include_object { include_bytes_align_as!(u64, $path) }; } + +pub fn assert_literal_value( + obj: &Object, + diff_config: &DiffObjConfig, + function_name: &str, + ins_row_idx: usize, + literal_label: &str, + literal_value: &str, +) { + let symbol_idx = obj.symbols.iter().position(|s| s.name == function_name).unwrap(); + let diff = objdiff_core::diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap(); + let ins_ref = diff.instruction_rows[ins_row_idx].ins_ref.unwrap(); + let resolved = obj.resolve_instruction_ref(symbol_idx, ins_ref).unwrap(); + let literals = objdiff_core::diff::display::display_ins_data_literals(&obj, resolved); + let target_literal = literals + .iter() + .find(|(_, label_override, _)| *label_override == Some(literal_label.to_string())); + assert_ne!(target_literal, None); + let (literal, _, _) = target_literal.unwrap(); + assert_eq!(literal, literal_value); +} diff --git a/objdiff-core/tests/data/ppc/KinectSharePanel.obj b/objdiff-core/tests/data/ppc/KinectSharePanel.obj new file mode 100644 index 0000000000000000000000000000000000000000..b8571db7b88ce9b657bec57efcbd658868c2c302 GIT binary patch literal 47532 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 literal 0 HcmV?d00001 From 6350344c5a2eb064b75d967bf23daf34f1044bef Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 3 May 2026 20:10:34 -0400 Subject: [PATCH 4/5] Fix test helper function sometimes being considered dead code --- objdiff-core/tests/common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/objdiff-core/tests/common.rs b/objdiff-core/tests/common.rs index a05633d6..48a6c342 100644 --- a/objdiff-core/tests/common.rs +++ b/objdiff-core/tests/common.rs @@ -51,6 +51,7 @@ macro_rules! include_object { }; } +#[allow(dead_code)] pub fn assert_literal_value( obj: &Object, diff_config: &DiffObjConfig, From 8874547bba23c0617c0792d4e33500bb638ca3d0 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 3 May 2026 21:17:01 -0400 Subject: [PATCH 5/5] Clippy fixes --- objdiff-core/tests/common.rs | 4 ++-- objdiff-wasm/src/api.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/objdiff-core/tests/common.rs b/objdiff-core/tests/common.rs index 48a6c342..330a5da2 100644 --- a/objdiff-core/tests/common.rs +++ b/objdiff-core/tests/common.rs @@ -61,10 +61,10 @@ pub fn assert_literal_value( literal_value: &str, ) { let symbol_idx = obj.symbols.iter().position(|s| s.name == function_name).unwrap(); - let diff = objdiff_core::diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap(); + let diff = objdiff_core::diff::code::no_diff_code(obj, symbol_idx, diff_config).unwrap(); let ins_ref = diff.instruction_rows[ins_row_idx].ins_ref.unwrap(); let resolved = obj.resolve_instruction_ref(symbol_idx, ins_ref).unwrap(); - let literals = objdiff_core::diff::display::display_ins_data_literals(&obj, resolved); + let literals = objdiff_core::diff::display::display_ins_data_literals(obj, resolved); let target_literal = literals .iter() .find(|(_, label_override, _)| *label_override == Some(literal_label.to_string())); diff --git a/objdiff-wasm/src/api.rs b/objdiff-wasm/src/api.rs index 980273cc..ed1c686a 100644 --- a/objdiff-wasm/src/api.rs +++ b/objdiff-wasm/src/api.rs @@ -225,7 +225,7 @@ impl GuestDisplay for Component { let obj_diff = diff.get::(); let obj = obj_diff.0.as_ref(); let symbol_display = from_symbol_ref(symbol_ref); - diff::display::symbol_context(obj, symbol_display.symbol as usize) + diff::display::symbol_context(obj, symbol_display.symbol) .into_iter() .map(ContextItem::from) .collect() @@ -237,7 +237,7 @@ impl GuestDisplay for Component { let addend = 0; // TODO let override_color = None; // TODO: colorize replaced/deleted/inserted relocations let symbol_display = from_symbol_ref(symbol_ref); - diff::display::symbol_hover(obj, symbol_display.symbol as usize, addend, override_color) + diff::display::symbol_hover(obj, symbol_display.symbol, addend, override_color) .into_iter() .map(HoverItem::from) .collect()