mirror of https://github.com/encounter/objdiff.git
Compare commits
5 Commits
21f8f2407c
...
424434edd6
Author | SHA1 | Date |
---|---|---|
Luke Street | 424434edd6 | |
Luke Street | 7f14b684bf | |
Luke Street | c5da7f7dd5 | |
Luke Street | 2fd655850a | |
Luke Street | 79bd7317c1 |
|
@ -434,6 +434,18 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block"
|
name = "block"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -1514,6 +1526,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -2861,7 +2879,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
|
@ -2883,7 +2901,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
|
@ -2919,11 +2937,13 @@ dependencies = [
|
||||||
"tsify-next",
|
"tsify-next",
|
||||||
"unarm",
|
"unarm",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
"yaxpeax-arch",
|
||||||
|
"yaxpeax-arm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -3495,6 +3515,12 @@ dependencies = [
|
||||||
"num_enum 0.5.11",
|
"num_enum 0.5.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -4290,6 +4316,12 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-winres"
|
name = "tauri-winres"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -5525,6 +5557,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11-dl"
|
name = "x11-dl"
|
||||||
version = "2.21.0"
|
version = "2.21.0"
|
||||||
|
@ -5598,6 +5639,25 @@ version = "0.8.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26"
|
checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaxpeax-arch"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36274fcc5403da2a7636ffda4d02eca12a1b2b8267b9d2e04447bd2ccfc72082"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaxpeax-arm"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1c6a2af41f88546a08df3bc77aadf7263884d6dffdac5b32dea7dc2df23f241"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"yaxpeax-arch",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yeslogic-fontconfig-sys"
|
name = "yeslogic-fontconfig-sys"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@ strip = "debuginfo"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
|
@ -20,6 +20,7 @@ Supports:
|
||||||
- MIPS (N64, PS1, PS2, PSP)
|
- MIPS (N64, PS1, PS2, PSP)
|
||||||
- x86 (COFF only at the moment)
|
- x86 (COFF only at the moment)
|
||||||
- ARM (GBA, DS, 3DS)
|
- ARM (GBA, DS, 3DS)
|
||||||
|
- ARM64 (Switch, experimental)
|
||||||
|
|
||||||
See [Usage](#usage) for more information.
|
See [Usage](#usage) for more information.
|
||||||
|
|
||||||
|
|
|
@ -844,10 +844,14 @@ impl FunctionDiffUi {
|
||||||
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
|
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DiffText::Symbol(sym) => {
|
DiffText::Symbol(sym, diff) => {
|
||||||
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
||||||
label_text = name.clone();
|
label_text = name.clone();
|
||||||
base_color = Color::White;
|
if let Some(diff) = diff {
|
||||||
|
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
|
||||||
|
} else {
|
||||||
|
base_color = Color::White;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DiffText::Spacing(n) => {
|
DiffText::Spacing(n) => {
|
||||||
line.spans.push(Span::raw(" ".repeat(n)));
|
line.spans.push(Span::raw(" ".repeat(n)));
|
||||||
|
|
|
@ -16,7 +16,7 @@ documentation = "https://docs.rs/objdiff-core"
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "bindings"]
|
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "arm64", "bindings"]
|
||||||
any-arch = ["config", "dep:bimap", "dep:strum", "dep:similar", "dep:flagset", "dep:log", "dep:memmap2", "dep:byteorder", "dep:num-traits"] # Implicit, used to check if any arch is enabled
|
any-arch = ["config", "dep:bimap", "dep:strum", "dep:similar", "dep:flagset", "dep:log", "dep:memmap2", "dep:byteorder", "dep:num-traits"] # Implicit, used to check if any arch is enabled
|
||||||
config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
|
config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
|
||||||
dwarf = ["dep:gimli"]
|
dwarf = ["dep:gimli"]
|
||||||
|
@ -24,6 +24,7 @@ mips = ["any-arch", "dep:rabbitizer"]
|
||||||
ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
|
ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
|
||||||
x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
|
x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
|
||||||
arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
|
arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
|
||||||
|
arm64 = ["any-arch", "dep:cpp_demangle", "dep:yaxpeax-arch", "dep:yaxpeax-arm"]
|
||||||
bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
|
bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
|
||||||
wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"]
|
wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"]
|
||||||
|
|
||||||
|
@ -76,6 +77,10 @@ msvc-demangler = { version = "0.10", optional = true }
|
||||||
unarm = { version = "1.6", optional = true }
|
unarm = { version = "1.6", optional = true }
|
||||||
arm-attr = { version = "0.1", optional = true }
|
arm-attr = { version = "0.1", optional = true }
|
||||||
|
|
||||||
|
# arm64
|
||||||
|
yaxpeax-arch = { version = "0.3", default-features = false, features = ["std"], optional = true }
|
||||||
|
yaxpeax-arm = { version = "0.3", default-features = false, features = ["std"], optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
prost-build = { version = "0.13", optional = true }
|
prost-build = { version = "0.13", optional = true }
|
||||||
pbjson-build = { version = "0.7", optional = true }
|
pbjson-build = { version = "0.7", optional = true }
|
||||||
|
|
|
@ -11,4 +11,5 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
|
||||||
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
|
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
|
||||||
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
|
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
|
||||||
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
|
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
|
||||||
|
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
|
||||||
- **`bindings`**: Enables serialization and deserialization of objdiff data structures.
|
- **`bindings`**: Enables serialization and deserialization of objdiff data structures.
|
||||||
|
|
|
@ -124,11 +124,9 @@ impl ObjArch for ObjArchArm {
|
||||||
.get(&SectionIndex(section_index))
|
.get(&SectionIndex(section_index))
|
||||||
.map(|x| x.as_slice())
|
.map(|x| x.as_slice())
|
||||||
.unwrap_or(&fallback_mappings);
|
.unwrap_or(&fallback_mappings);
|
||||||
let first_mapping_idx =
|
let first_mapping_idx = mapping_symbols
|
||||||
match mapping_symbols.binary_search_by_key(&start_addr, |x| x.address) {
|
.binary_search_by_key(&start_addr, |x| x.address)
|
||||||
Ok(idx) => idx,
|
.unwrap_or_else(|idx| idx - 1);
|
||||||
Err(idx) => idx - 1,
|
|
||||||
};
|
|
||||||
let first_mapping = mapping_symbols[first_mapping_idx].mapping;
|
let first_mapping = mapping_symbols[first_mapping_idx].mapping;
|
||||||
|
|
||||||
let mut mappings_iter =
|
let mut mappings_iter =
|
||||||
|
@ -215,7 +213,7 @@ impl ObjArch for ObjArchArm {
|
||||||
address: address as u64,
|
address: address as u64,
|
||||||
size: (parser.address - address) as u8,
|
size: (parser.address - address) as u8,
|
||||||
op: ins.opcode_id(),
|
op: ins.opcode_id(),
|
||||||
mnemonic: parsed_ins.mnemonic.to_string(),
|
mnemonic: Cow::Borrowed(parsed_ins.mnemonic),
|
||||||
args,
|
args,
|
||||||
reloc,
|
reloc,
|
||||||
branch_dest,
|
branch_dest,
|
||||||
|
@ -234,7 +232,7 @@ impl ObjArch for ObjArchArm {
|
||||||
section: &ObjSection,
|
section: &ObjSection,
|
||||||
address: u64,
|
address: u64,
|
||||||
reloc: &Relocation,
|
reloc: &Relocation,
|
||||||
) -> anyhow::Result<i64> {
|
) -> Result<i64> {
|
||||||
let address = address as usize;
|
let address = address as usize;
|
||||||
Ok(match reloc.flags() {
|
Ok(match reloc.flags() {
|
||||||
// ARM calls
|
// ARM calls
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -119,7 +119,7 @@ impl ObjArch for ObjArchMips {
|
||||||
let op = instruction.unique_id as u16;
|
let op = instruction.unique_id as u16;
|
||||||
ops.push(op);
|
ops.push(op);
|
||||||
|
|
||||||
let mnemonic = instruction.opcode_name().to_string();
|
let mnemonic = instruction.opcode_name();
|
||||||
let is_branch = instruction.is_branch();
|
let is_branch = instruction.is_branch();
|
||||||
let branch_offset = instruction.branch_offset();
|
let branch_offset = instruction.branch_offset();
|
||||||
let mut branch_dest = if is_branch {
|
let mut branch_dest = if is_branch {
|
||||||
|
@ -202,7 +202,7 @@ impl ObjArch for ObjArchMips {
|
||||||
address: cur_addr as u64,
|
address: cur_addr as u64,
|
||||||
size: 4,
|
size: 4,
|
||||||
op,
|
op,
|
||||||
mnemonic,
|
mnemonic: Cow::Borrowed(mnemonic),
|
||||||
args,
|
args,
|
||||||
reloc: reloc.cloned(),
|
reloc: reloc.cloned(),
|
||||||
branch_dest,
|
branch_dest,
|
||||||
|
|
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
|
|
||||||
#[cfg(feature = "arm")]
|
#[cfg(feature = "arm")]
|
||||||
mod arm;
|
mod arm;
|
||||||
|
#[cfg(feature = "arm64")]
|
||||||
|
mod arm64;
|
||||||
#[cfg(feature = "mips")]
|
#[cfg(feature = "mips")]
|
||||||
pub mod mips;
|
pub mod mips;
|
||||||
#[cfg(feature = "ppc")]
|
#[cfg(feature = "ppc")]
|
||||||
|
@ -165,6 +167,8 @@ pub fn new_arch(object: &File) -> Result<Box<dyn ObjArch>> {
|
||||||
Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?),
|
Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?),
|
||||||
#[cfg(feature = "arm")]
|
#[cfg(feature = "arm")]
|
||||||
Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?),
|
Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?),
|
||||||
|
#[cfg(feature = "arm64")]
|
||||||
|
Architecture::Aarch64 => Box::new(arm64::ObjArchArm64::new(object)?),
|
||||||
arch => bail!("Unsupported architecture: {arch:?}"),
|
arch => bail!("Unsupported architecture: {arch:?}"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ impl ObjArch for ObjArchPpc {
|
||||||
insts.push(ObjIns {
|
insts.push(ObjIns {
|
||||||
address: cur_addr as u64,
|
address: cur_addr as u64,
|
||||||
size: 4,
|
size: 4,
|
||||||
mnemonic: simplified.mnemonic.to_string(),
|
mnemonic: Cow::Borrowed(simplified.mnemonic),
|
||||||
args,
|
args,
|
||||||
reloc: reloc.cloned(),
|
reloc: reloc.cloned(),
|
||||||
op: ins.op as u16,
|
op: ins.op as u16,
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl ObjArch for ObjArchX86 {
|
||||||
address: 0,
|
address: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
op: 0,
|
op: 0,
|
||||||
mnemonic: String::new(),
|
mnemonic: Cow::Borrowed("<invalid>"),
|
||||||
args: vec![],
|
args: vec![],
|
||||||
reloc: None,
|
reloc: None,
|
||||||
branch_dest: None,
|
branch_dest: None,
|
||||||
|
@ -76,7 +76,7 @@ impl ObjArch for ObjArchX86 {
|
||||||
address,
|
address,
|
||||||
size: instruction.len() as u8,
|
size: instruction.len() as u8,
|
||||||
op,
|
op,
|
||||||
mnemonic: String::new(),
|
mnemonic: Cow::Borrowed("<invalid>"),
|
||||||
args: vec![],
|
args: vec![],
|
||||||
reloc: reloc.cloned(),
|
reloc: reloc.cloned(),
|
||||||
branch_dest: None,
|
branch_dest: None,
|
||||||
|
@ -242,7 +242,8 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||||
|
|
||||||
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
|
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
|
||||||
self.formatted.push_str(text);
|
self.formatted.push_str(text);
|
||||||
self.ins.mnemonic = text.to_string();
|
// TODO: can iced-x86 guarantee 'static here?
|
||||||
|
self.ins.mnemonic = Cow::Owned(text.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_number(
|
fn write_number(
|
||||||
|
|
|
@ -132,7 +132,7 @@ impl Instruction {
|
||||||
address: instruction.address,
|
address: instruction.address,
|
||||||
size: instruction.size as u32,
|
size: instruction.size as u32,
|
||||||
opcode: instruction.op as u32,
|
opcode: instruction.op as u32,
|
||||||
mnemonic: instruction.mnemonic.clone(),
|
mnemonic: instruction.mnemonic.to_string(),
|
||||||
formatted: instruction.formatted.clone(),
|
formatted: instruction.formatted.clone(),
|
||||||
arguments: instruction.args.iter().map(Argument::new).collect(),
|
arguments: instruction.args.iter().map(Argument::new).collect(),
|
||||||
relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
|
relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
|
||||||
|
|
|
@ -259,11 +259,17 @@ fn arg_eq(
|
||||||
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ObjInsArg::BranchDest(_) => {
|
ObjInsArg::BranchDest(_) => match right {
|
||||||
// Compare dest instruction idx after diffing
|
// Compare dest instruction idx after diffing
|
||||||
left_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
ObjInsArg::BranchDest(_) => {
|
||||||
== right_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
left_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
||||||
}
|
== right_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
||||||
|
}
|
||||||
|
// If relocations are relaxed, match if left is a constant and right is a reloc
|
||||||
|
// Useful for instances where the target object is created without relocations
|
||||||
|
ObjInsArg::Reloc => config.relax_reloc_diffs,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,15 +299,10 @@ fn compare_ins(
|
||||||
) -> Result<InsDiffResult> {
|
) -> Result<InsDiffResult> {
|
||||||
let mut result = InsDiffResult::default();
|
let mut result = InsDiffResult::default();
|
||||||
if let (Some(left_ins), Some(right_ins)) = (&left.ins, &right.ins) {
|
if let (Some(left_ins), Some(right_ins)) = (&left.ins, &right.ins) {
|
||||||
if left_ins.args.len() != right_ins.args.len()
|
// Count only non-PlainText args
|
||||||
|| left_ins.op != right_ins.op
|
let left_args_count = left_ins.iter_args().count();
|
||||||
// Check if any PlainText segments differ (punctuation and spacing)
|
let right_args_count = right_ins.iter_args().count();
|
||||||
// This indicates a more significant difference than a simple arg mismatch
|
if left_args_count != right_args_count || left_ins.op != right_ins.op {
|
||||||
|| !left_ins.args.iter().zip(&right_ins.args).all(|(a, b)| match (a, b) {
|
|
||||||
(ObjInsArg::PlainText(l), ObjInsArg::PlainText(r)) => l == r,
|
|
||||||
_ => true,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
// Totally different op
|
// Totally different op
|
||||||
result.kind = ObjInsDiffKind::Replace;
|
result.kind = ObjInsDiffKind::Replace;
|
||||||
state.diff_count += 1;
|
state.diff_count += 1;
|
||||||
|
@ -312,7 +313,7 @@ fn compare_ins(
|
||||||
result.kind = ObjInsDiffKind::OpMismatch;
|
result.kind = ObjInsDiffKind::OpMismatch;
|
||||||
state.diff_count += 1;
|
state.diff_count += 1;
|
||||||
}
|
}
|
||||||
for (a, b) in left_ins.args.iter().zip(&right_ins.args) {
|
for (a, b) in left_ins.iter_args().zip(right_ins.iter_args()) {
|
||||||
if arg_eq(config, left_obj, right_obj, a, b, left, right) {
|
if arg_eq(config, left_obj, right_obj, a, b, left, right) {
|
||||||
result.left_args_diff.push(None);
|
result.left_args_diff.push(None);
|
||||||
result.right_args_diff.push(None);
|
result.right_args_diff.push(None);
|
||||||
|
@ -324,8 +325,11 @@ fn compare_ins(
|
||||||
let a_str = match a {
|
let a_str = match a {
|
||||||
ObjInsArg::PlainText(arg) => arg.to_string(),
|
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||||
ObjInsArg::Reloc => String::new(),
|
ObjInsArg::Reloc => left_ins
|
||||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
.reloc
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "<unknown>".to_string(), |r| r.target.name.clone()),
|
||||||
|
ObjInsArg::BranchDest(arg) => arg.to_string(),
|
||||||
};
|
};
|
||||||
let a_diff = if let Some(idx) = state.left_args_idx.get(&a_str) {
|
let a_diff = if let Some(idx) = state.left_args_idx.get(&a_str) {
|
||||||
ObjInsArgDiff { idx: *idx }
|
ObjInsArgDiff { idx: *idx }
|
||||||
|
@ -338,8 +342,11 @@ fn compare_ins(
|
||||||
let b_str = match b {
|
let b_str = match b {
|
||||||
ObjInsArg::PlainText(arg) => arg.to_string(),
|
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||||
ObjInsArg::Reloc => String::new(),
|
ObjInsArg::Reloc => right_ins
|
||||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
.reloc
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "<unknown>".to_string(), |r| r.target.name.clone()),
|
||||||
|
ObjInsArg::BranchDest(arg) => arg.to_string(),
|
||||||
};
|
};
|
||||||
let b_diff = if let Some(idx) = state.right_args_idx.get(&b_str) {
|
let b_diff = if let Some(idx) = state.right_args_idx.get(&b_str) {
|
||||||
ObjInsArgDiff { idx: *idx }
|
ObjInsArgDiff { idx: *idx }
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub enum DiffText<'a> {
|
||||||
/// Branch destination
|
/// Branch destination
|
||||||
BranchDest(u64, Option<&'a ObjInsArgDiff>),
|
BranchDest(u64, Option<&'a ObjInsArgDiff>),
|
||||||
/// Symbol name
|
/// Symbol name
|
||||||
Symbol(&'a ObjSymbol),
|
Symbol(&'a ObjSymbol, Option<&'a ObjInsArgDiff>),
|
||||||
/// Number of spaces
|
/// Number of spaces
|
||||||
Spacing(usize),
|
Spacing(usize),
|
||||||
/// End of line
|
/// End of line
|
||||||
|
@ -58,20 +58,23 @@ pub fn display_diff<E>(
|
||||||
cb(DiffText::Spacing(4))?;
|
cb(DiffText::Spacing(4))?;
|
||||||
}
|
}
|
||||||
cb(DiffText::Opcode(&ins.mnemonic, ins.op))?;
|
cb(DiffText::Opcode(&ins.mnemonic, ins.op))?;
|
||||||
|
let mut arg_diff_idx = 0; // non-PlainText index
|
||||||
for (i, arg) in ins.args.iter().enumerate() {
|
for (i, arg) in ins.args.iter().enumerate() {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
cb(DiffText::Spacing(1))?;
|
cb(DiffText::Spacing(1))?;
|
||||||
}
|
}
|
||||||
let diff = ins_diff.arg_diff.get(i).and_then(|o| o.as_ref());
|
let diff = ins_diff.arg_diff.get(arg_diff_idx).and_then(|o| o.as_ref());
|
||||||
match arg {
|
match arg {
|
||||||
ObjInsArg::PlainText(s) => {
|
ObjInsArg::PlainText(s) => {
|
||||||
cb(DiffText::Basic(s))?;
|
cb(DiffText::Basic(s))?;
|
||||||
}
|
}
|
||||||
ObjInsArg::Arg(v) => {
|
ObjInsArg::Arg(v) => {
|
||||||
cb(DiffText::Argument(v, diff))?;
|
cb(DiffText::Argument(v, diff))?;
|
||||||
|
arg_diff_idx += 1;
|
||||||
}
|
}
|
||||||
ObjInsArg::Reloc => {
|
ObjInsArg::Reloc => {
|
||||||
display_reloc_name(ins.reloc.as_ref().unwrap(), &mut cb)?;
|
display_reloc_name(ins.reloc.as_ref().unwrap(), &mut cb, diff)?;
|
||||||
|
arg_diff_idx += 1;
|
||||||
}
|
}
|
||||||
ObjInsArg::BranchDest(dest) => {
|
ObjInsArg::BranchDest(dest) => {
|
||||||
if let Some(dest) = dest.checked_sub(base_addr) {
|
if let Some(dest) = dest.checked_sub(base_addr) {
|
||||||
|
@ -79,6 +82,7 @@ pub fn display_diff<E>(
|
||||||
} else {
|
} else {
|
||||||
cb(DiffText::Basic("<unknown>"))?;
|
cb(DiffText::Basic("<unknown>"))?;
|
||||||
}
|
}
|
||||||
|
arg_diff_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,8 +96,9 @@ pub fn display_diff<E>(
|
||||||
fn display_reloc_name<E>(
|
fn display_reloc_name<E>(
|
||||||
reloc: &ObjReloc,
|
reloc: &ObjReloc,
|
||||||
mut cb: impl FnMut(DiffText) -> Result<(), E>,
|
mut cb: impl FnMut(DiffText) -> Result<(), E>,
|
||||||
|
diff: Option<&ObjInsArgDiff>,
|
||||||
) -> Result<(), E> {
|
) -> Result<(), E> {
|
||||||
cb(DiffText::Symbol(&reloc.target))?;
|
cb(DiffText::Symbol(&reloc.target, diff))?;
|
||||||
match reloc.addend.cmp(&0i64) {
|
match reloc.addend.cmp(&0i64) {
|
||||||
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))),
|
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))),
|
||||||
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))),
|
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))),
|
||||||
|
@ -106,7 +111,7 @@ impl PartialEq<DiffText<'_>> for HighlightKind {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(HighlightKind::Opcode(a), DiffText::Opcode(_, b)) => a == b,
|
(HighlightKind::Opcode(a), DiffText::Opcode(_, b)) => a == b,
|
||||||
(HighlightKind::Arg(a), DiffText::Argument(b, _)) => a.loose_eq(b),
|
(HighlightKind::Arg(a), DiffText::Argument(b, _)) => a.loose_eq(b),
|
||||||
(HighlightKind::Symbol(a), DiffText::Symbol(b)) => a == &b.name,
|
(HighlightKind::Symbol(a), DiffText::Symbol(b, _)) => a == &b.name,
|
||||||
(HighlightKind::Address(a), DiffText::Address(b) | DiffText::BranchDest(b, _)) => {
|
(HighlightKind::Address(a), DiffText::Address(b) | DiffText::BranchDest(b, _)) => {
|
||||||
a == b
|
a == b
|
||||||
}
|
}
|
||||||
|
@ -124,7 +129,7 @@ impl From<DiffText<'_>> for HighlightKind {
|
||||||
match value {
|
match value {
|
||||||
DiffText::Opcode(_, op) => HighlightKind::Opcode(op),
|
DiffText::Opcode(_, op) => HighlightKind::Opcode(op),
|
||||||
DiffText::Argument(arg, _) => HighlightKind::Arg(arg.clone()),
|
DiffText::Argument(arg, _) => HighlightKind::Arg(arg.clone()),
|
||||||
DiffText::Symbol(sym) => HighlightKind::Symbol(sym.name.to_string()),
|
DiffText::Symbol(sym, _) => HighlightKind::Symbol(sym.name.to_string()),
|
||||||
DiffText::Address(addr) | DiffText::BranchDest(addr, _) => HighlightKind::Address(addr),
|
DiffText::Address(addr) | DiffText::BranchDest(addr, _) => HighlightKind::Address(addr),
|
||||||
_ => HighlightKind::None,
|
_ => HighlightKind::None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ pub struct ObjInsDiff {
|
||||||
pub branch_from: Option<ObjInsBranchFrom>,
|
pub branch_from: Option<ObjInsBranchFrom>,
|
||||||
/// Branches to instruction
|
/// Branches to instruction
|
||||||
pub branch_to: Option<ObjInsBranchTo>,
|
pub branch_to: Option<ObjInsBranchTo>,
|
||||||
/// Arg diffs
|
/// Arg diffs (only contains non-PlainText args)
|
||||||
pub arg_diff: Vec<Option<ObjInsArgDiff>>,
|
pub arg_diff: Vec<Option<ObjInsArgDiff>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,9 @@ pub enum ObjInsArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjInsArg {
|
impl ObjInsArg {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_plain_text(&self) -> bool { matches!(self, ObjInsArg::PlainText(_)) }
|
||||||
|
|
||||||
pub fn loose_eq(&self, other: &ObjInsArg) -> bool {
|
pub fn loose_eq(&self, other: &ObjInsArg) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ObjInsArg::Arg(a), ObjInsArg::Arg(b)) => a.loose_eq(b),
|
(ObjInsArg::Arg(a), ObjInsArg::Arg(b)) => a.loose_eq(b),
|
||||||
|
@ -100,7 +103,7 @@ pub struct ObjIns {
|
||||||
pub address: u64,
|
pub address: u64,
|
||||||
pub size: u8,
|
pub size: u8,
|
||||||
pub op: u16,
|
pub op: u16,
|
||||||
pub mnemonic: String,
|
pub mnemonic: Cow<'static, str>,
|
||||||
pub args: Vec<ObjInsArg>,
|
pub args: Vec<ObjInsArg>,
|
||||||
pub reloc: Option<ObjReloc>,
|
pub reloc: Option<ObjReloc>,
|
||||||
pub branch_dest: Option<u64>,
|
pub branch_dest: Option<u64>,
|
||||||
|
@ -112,6 +115,14 @@ pub struct ObjIns {
|
||||||
pub orig: Option<String>,
|
pub orig: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ObjIns {
|
||||||
|
/// Iterate over non-PlainText arguments.
|
||||||
|
#[inline]
|
||||||
|
pub fn iter_args(&self) -> impl DoubleEndedIterator<Item = &ObjInsArg> {
|
||||||
|
self.args.iter().filter(|a| !a.is_plain_text())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
|
||||||
pub enum ObjSymbolKind {
|
pub enum ObjSymbolKind {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
|
@ -335,6 +335,10 @@ fn relocations_by_section(
|
||||||
};
|
};
|
||||||
symbol
|
symbol
|
||||||
}
|
}
|
||||||
|
RelocationTarget::Absolute => {
|
||||||
|
log::warn!("Ignoring absolute relocation @ {}:{:#x}", section.name, address);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
_ => bail!("Unhandled relocation target: {:?}", reloc.target()),
|
_ => bail!("Unhandled relocation target: {:?}", reloc.target()),
|
||||||
};
|
};
|
||||||
let flags = reloc.flags(); // TODO validate reloc here?
|
let flags = reloc.flags(); // TODO validate reloc here?
|
||||||
|
|
|
@ -292,10 +292,14 @@ fn diff_text_ui(
|
||||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DiffText::Symbol(sym) => {
|
DiffText::Symbol(sym, diff) => {
|
||||||
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
||||||
label_text = name.clone();
|
label_text = name.clone();
|
||||||
base_color = appearance.emphasized_text_color;
|
if let Some(diff) = diff {
|
||||||
|
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||||
|
} else {
|
||||||
|
base_color = appearance.emphasized_text_color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DiffText::Spacing(n) => {
|
DiffText::Spacing(n) => {
|
||||||
ui.add_space(n as f32 * space_width);
|
ui.add_space(n as f32 * space_width);
|
||||||
|
|
Loading…
Reference in New Issue