mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cebee6766 | |||
| ab0538e9a4 | |||
| b643265809 | |||
| 7a65e07e9b | |||
| 3c4092b965 |
@@ -62,7 +62,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
checks:
|
||||
- advisories
|
||||
# - advisories
|
||||
- bans licenses sources
|
||||
# Prevent new advisories from failing CI
|
||||
continue-on-error: ${{ matrix.checks == 'advisories' }}
|
||||
|
||||
Generated
+4
-4
@@ -3491,7 +3491,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3514,7 +3514,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -3570,7 +3570,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3608,7 +3608,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-wasm"
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objdiff-core",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ default-members = [
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "3.7.0"
|
||||
version = "3.7.1"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -162,7 +162,7 @@ impl ArchArm {
|
||||
}
|
||||
|
||||
impl Arch for ArchArm {
|
||||
fn post_init(&mut self, sections: &[Section], symbols: &[Symbol]) {
|
||||
fn post_init(&mut self, sections: &[Section], symbols: &[Symbol], _symbol_indices: &[usize]) {
|
||||
self.disasm_modes = Self::get_mapping_symbols(sections, symbols);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,9 @@ impl Arch for ArchArm {
|
||||
}
|
||||
|
||||
// Check how many bytes we can/should read
|
||||
let num_code_bytes = if data.len() >= 4 {
|
||||
let bytes_until_next_mapping =
|
||||
next_mapping.map(|m| (m.address - address) as usize).unwrap_or(usize::MAX);
|
||||
let num_code_bytes = if data.len() >= 4 && bytes_until_next_mapping >= 4 {
|
||||
if mode == unarm::ParseMode::Data && address & 3 != 0 {
|
||||
// 32-bit .word value should be aligned on a 4-byte boundary, otherwise use .hword
|
||||
2
|
||||
@@ -366,6 +368,22 @@ impl Arch for ArchArm {
|
||||
(imm22 << 1) << 9 >> 9
|
||||
}
|
||||
|
||||
// Thumb unconditional branch (B, 11-bit offset)
|
||||
elf::R_ARM_THM_PC11 => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let insn = self.endianness.read_u16_bytes(data) as i32;
|
||||
let imm11 = insn & 0x7ff;
|
||||
(imm11 << 1) << 20 >> 20
|
||||
}
|
||||
|
||||
// Thumb conditional branch (B<cond>, 8-bit offset)
|
||||
elf::R_ARM_THM_PC9 => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let insn = self.endianness.read_u16_bytes(data) as i32;
|
||||
let imm8 = insn & 0xff;
|
||||
(imm8 << 1) << 23 >> 23
|
||||
}
|
||||
|
||||
// Data
|
||||
elf::R_ARM_ABS32 => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
@@ -399,6 +417,8 @@ impl Arch for ArchArm {
|
||||
elf::R_ARM_PC24 => Some("R_ARM_PC24"),
|
||||
elf::R_ARM_XPC25 => Some("R_ARM_XPC25"),
|
||||
elf::R_ARM_CALL => Some("R_ARM_CALL"),
|
||||
elf::R_ARM_THM_PC11 => Some("R_ARM_THM_PC11"),
|
||||
elf::R_ARM_THM_PC9 => Some("R_ARM_THM_PC9"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
@@ -418,6 +438,8 @@ impl Arch for ArchArm {
|
||||
elf::R_ARM_PC24 => 4,
|
||||
elf::R_ARM_XPC25 => 4,
|
||||
elf::R_ARM_CALL => 4,
|
||||
elf::R_ARM_THM_PC11 => 2,
|
||||
elf::R_ARM_THM_PC9 => 2,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
@@ -544,7 +566,9 @@ impl unarm::FormatIns for ArgsFormatter<'_> {
|
||||
| RelocationFlags::Elf(elf::R_ARM_THM_PC22)
|
||||
| RelocationFlags::Elf(elf::R_ARM_PC24)
|
||||
| RelocationFlags::Elf(elf::R_ARM_XPC25)
|
||||
| RelocationFlags::Elf(elf::R_ARM_CALL) => {
|
||||
| RelocationFlags::Elf(elf::R_ARM_CALL)
|
||||
| RelocationFlags::Elf(elf::R_ARM_THM_PC11)
|
||||
| RelocationFlags::Elf(elf::R_ARM_THM_PC9) => {
|
||||
return self.write(InstructionPart::reloc());
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -340,7 +340,8 @@ impl dyn Arch {
|
||||
|
||||
pub trait Arch: Any + Debug + Send + Sync {
|
||||
/// Finishes arch-specific initialization that must be done after sections have been combined.
|
||||
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol]) {}
|
||||
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol], _symbol_indices: &[usize]) {
|
||||
}
|
||||
|
||||
/// Generate a list of instructions references (offset, size, opcode) from the given code.
|
||||
///
|
||||
|
||||
@@ -472,12 +472,27 @@ impl Arch for ArchPpc {
|
||||
}
|
||||
Ok(next_address.saturating_sub(symbol.address))
|
||||
}
|
||||
|
||||
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol], symbol_indices: &[usize]) {
|
||||
// Change the indices used as keys from the original symbol indices to the new symbol array indices
|
||||
self.extab = Self::convert_extab_map_indices(self, symbol_indices);
|
||||
}
|
||||
}
|
||||
|
||||
impl ArchPpc {
|
||||
pub fn extab_for_symbol(&self, symbol_index: usize) -> Option<&ExceptionInfo> {
|
||||
self.extab.as_ref()?.get(&symbol_index)
|
||||
}
|
||||
|
||||
pub fn convert_extab_map_indices(
|
||||
&self,
|
||||
symbol_indices: &[usize],
|
||||
) -> Option<BTreeMap<usize, ExceptionInfo>> {
|
||||
let new_map: BTreeMap<usize, ExceptionInfo> =
|
||||
self.extab.as_ref()?.iter().map(|e| (symbol_indices[*e.0 + 1], e.1.clone())).collect();
|
||||
|
||||
Some(new_map)
|
||||
}
|
||||
}
|
||||
|
||||
fn zero_reloc(code: u32, reloc: &Relocation) -> u32 {
|
||||
|
||||
@@ -1089,7 +1089,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig, diff_side: DiffSide) -> Result
|
||||
combine_sections(&mut sections, &mut symbols, config)?;
|
||||
}
|
||||
add_section_symbols(§ions, &mut symbols);
|
||||
arch.post_init(§ions, &symbols);
|
||||
arch.post_init(§ions, &symbols, &symbol_indices);
|
||||
let mut obj = Object {
|
||||
arch,
|
||||
endianness: obj_file.endianness(),
|
||||
|
||||
@@ -57,6 +57,31 @@ fn combine_text_sections() {
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "arm")]
|
||||
fn thumb_short_data_mapping() {
|
||||
// When a .2byte directive is used in Thumb code, the assembler emits
|
||||
// $d/$t mapping symbols for a 2-byte data region. The disassembler must
|
||||
// not read 4 bytes as a .word when the next mapping symbol limits the
|
||||
// data region to 2 bytes.
|
||||
let diff_config = diff::DiffObjConfig::default();
|
||||
let obj = obj::read::parse(
|
||||
include_object!("data/arm/code_1_vblank.o"),
|
||||
&diff_config,
|
||||
diff::DiffSide::Base,
|
||||
)
|
||||
.unwrap();
|
||||
let symbol_idx = obj.symbols.iter().position(|s| s.name == "VBlankDMA_Level1").unwrap();
|
||||
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
|
||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||
// .2byte data followed by Thumb code must not be merged into a 4-byte .word
|
||||
assert!(
|
||||
!output.contains(".word"),
|
||||
"2-byte data regions should not be decoded as 4-byte .word values.\n\
|
||||
The disassembler must respect mapping symbol boundaries."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "arm")]
|
||||
fn trim_trailing_hword() {
|
||||
|
||||
Binary file not shown.
@@ -9,7 +9,7 @@ Object {
|
||||
),
|
||||
extab: Some(
|
||||
{
|
||||
10: ExceptionInfo {
|
||||
1: ExceptionInfo {
|
||||
eti_symbol: ExtabSymbolRef {
|
||||
original_index: 5,
|
||||
name: "@31",
|
||||
@@ -35,7 +35,7 @@ Object {
|
||||
},
|
||||
dtors: [],
|
||||
},
|
||||
11: ExceptionInfo {
|
||||
2: ExceptionInfo {
|
||||
eti_symbol: ExtabSymbolRef {
|
||||
original_index: 7,
|
||||
name: "@52",
|
||||
@@ -95,7 +95,7 @@ Object {
|
||||
},
|
||||
],
|
||||
},
|
||||
12: ExceptionInfo {
|
||||
3: ExceptionInfo {
|
||||
eti_symbol: ExtabSymbolRef {
|
||||
original_index: 9,
|
||||
name: "@60",
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.7.0",
|
||||
"version": "3.7.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.7.0",
|
||||
"version": "3.7.1",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.7.0",
|
||||
"version": "3.7.1",
|
||||
"description": "A local diffing tool for decompilation projects.",
|
||||
"author": {
|
||||
"name": "Luke Street",
|
||||
|
||||
@@ -572,7 +572,7 @@ impl GuestDiffConfig for ResourceDiffConfig {
|
||||
}
|
||||
}
|
||||
|
||||
struct CachedObject(Weak<obj::Object>, u64);
|
||||
struct CachedObject(Weak<obj::Object>, u64, diff::DiffSide);
|
||||
|
||||
struct ObjectCache(RefCell<Vec<CachedObject>>);
|
||||
|
||||
@@ -608,12 +608,13 @@ impl GuestObject for ResourceObject {
|
||||
diff_side: DiffSide,
|
||||
) -> Result<Object, String> {
|
||||
let hash = xxh3_64(&data);
|
||||
let core_diff_side: objdiff_core::diff::DiffSide = diff_side.into();
|
||||
let mut cached = None;
|
||||
OBJECT_CACHE.borrow_mut().retain(|c| {
|
||||
if c.0.strong_count() == 0 {
|
||||
return false;
|
||||
}
|
||||
if c.1 == hash {
|
||||
if c.1 == hash && c.2 == core_diff_side {
|
||||
cached = c.0.upgrade();
|
||||
}
|
||||
true
|
||||
@@ -623,9 +624,9 @@ impl GuestObject for ResourceObject {
|
||||
}
|
||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||
let obj = Rc::new(
|
||||
obj::read::parse(&data, &diff_config, diff_side.into()).map_err(|e| e.to_string())?,
|
||||
obj::read::parse(&data, &diff_config, core_diff_side).map_err(|e| e.to_string())?,
|
||||
);
|
||||
OBJECT_CACHE.borrow_mut().push(CachedObject(Rc::downgrade(&obj), hash));
|
||||
OBJECT_CACHE.borrow_mut().push(CachedObject(Rc::downgrade(&obj), hash, core_diff_side));
|
||||
Ok(Object::new(ResourceObject(obj, hash)))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user