Compare commits

...

16 Commits

Author SHA1 Message Date
Luke Street a119d9a6dd Add scratch preset_id field for decomp.me
Resolves #133
2024-11-07 09:27:13 -07:00
robojumper ebf653816a Combine nested otherwise empty directories in objects view (#137) 2024-11-07 08:21:39 -07:00
Luke Street 424434edd6 Experimental ARM64 support
Based on yaxpeax-arm, but with a heavy dose of
custom code to work around its limitations.

Please report any issues or unhandled relocations.
2024-10-31 17:39:12 -06:00
Luke Street 7f14b684bf Ignore PlainText segments when diffing 2024-10-31 17:27:27 -06:00
Luke Street c5da7f7dd5 Show diff color when symbols differ 2024-10-31 17:26:59 -06:00
Luke Street 2fd655850a Ignore Absolute relocations and log warning 2024-10-31 17:24:49 -06:00
Luke Street 79bd7317c1 Match BranchDest->Reloc with relaxed relocation diffs 2024-10-31 17:24:33 -06:00
Luke Street 21f8f2407c Relax symbol comparison logic
The Ghidra delinker plugin emits functions with type STT_OBJECT,
rather than STT_FUNC. The current logic was preventing these from
being compared based on their symbol type. Relax this condition
for now.
2024-10-29 22:46:02 -06:00
Luke Street d2b7a9ef25 Fix missing common BSS symbols
Resolves #128
2024-10-28 17:54:49 -06:00
Luke Street 2cf9cf24d6 Version v2.3.3 2024-10-20 20:01:35 -07:00
Anghelo Carvajal 5ef3416457 Improve dependency gating on objdiff-core (#126)
* Reduce dependencies for no features

* Add missing deps to every feature

* Add missing `dep:`s

* Gate even more deps behind features

Removes dependency on tsify-next / wasm-bindgen unless
compiling with the wasm feature by using `#[cfg_attr]`

* Fix wasm

---------

Co-authored-by: Luke Street <luke@street.dev>
2024-10-20 19:04:29 -07:00
Aetias 6ff8d002f7 Fix panic when parsing DWARF 2 line info for empty section (#125)
* Fix panic when parsing DWARF 2 line info for empty section

* Fix panic when parsing DWARF 2 line info for empty section
May as well remove both unwraps :p
2024-10-19 09:39:18 -06:00
Luke Street 9ca157d717 Lighten default blue diff color
The old default was very dark and blended in with
the dark theme's background.
2024-10-18 17:51:29 -06:00
Steven Casper 67b63311fc Fix data tooltip panic (#123)
* Fix data tooltip panic

Prevents panicing when attempting to display the data tooltip for a symbol that is too large by just using as many bytes as needed from the begging of the symbol.

* Don't attempt to interpret wrongly sized data

* Reference data display improvment issue

* Log failure to display a symbol's value
2024-10-14 22:03:30 -06:00
Luke Street 72ea1c8911 ci: Use rust-lld on Windows 2024-10-12 18:57:49 -06:00
Luke Street d4a540857d ci: Add Rust workspace cache 2024-10-12 18:41:42 -06:00
30 changed files with 3113 additions and 114 deletions
+5
View File
@@ -0,0 +1,5 @@
[target.x86_64-pc-windows-msvc]
linker = "rust-lld"
[target.aarch64-pc-windows-msvc]
linker = "rust-lld"
+12
View File
@@ -30,6 +30,8 @@ jobs:
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
components: clippy components: clippy
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
- name: Cargo check - name: Cargo check
run: cargo check --all-features --all-targets run: cargo check --all-features --all-targets
- name: Cargo clippy - name: Cargo clippy
@@ -85,6 +87,8 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Rust toolchain - name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
- name: Cargo test - name: Cargo test
run: cargo test --release --all-features run: cargo test --release --all-features
@@ -151,6 +155,10 @@ jobs:
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
targets: ${{ matrix.target }} targets: ${{ matrix.target }}
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Cargo build - name: Cargo build
run: > run: >
cargo ${{ matrix.build }} --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }} cargo ${{ matrix.build }} --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
@@ -202,6 +210,10 @@ jobs:
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
targets: ${{ matrix.target }} targets: ${{ matrix.target }}
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Cargo build - name: Cargo build
run: > run: >
cargo build --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }} cargo build --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
-4
View File
@@ -3,10 +3,6 @@ target/
**/*.rs.bk **/*.rs.bk
generated/ generated/
# cargo-mobile
.cargo/
/gen
# macOS # macOS
.DS_Store .DS_Store
Generated
+63 -3
View File
@@ -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.2" 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.2" 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.2" 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"
+1 -1
View File
@@ -13,7 +13,7 @@ strip = "debuginfo"
codegen-units = 1 codegen-units = 1
[workspace.package] [workspace.package]
version = "2.3.2" 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"
+1
View File
@@ -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.
+6 -2
View File
@@ -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)));
+28 -23
View File
@@ -16,16 +16,17 @@ 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 = ["bimap"] # 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 = ["bimap", "globset", "semver", "serde_json", "serde_yaml"] config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
dwarf = ["gimli"] dwarf = ["dep:gimli"]
mips = ["any-arch", "rabbitizer"] mips = ["any-arch", "dep:rabbitizer"]
ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"] ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"] x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"] arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
bindings = ["serde_json", "prost", "pbjson"] arm64 = ["any-arch", "dep:cpp_demangle", "dep:yaxpeax-arch", "dep:yaxpeax-arm"]
wasm = ["bindings", "console_error_panic_hook", "console_log"] 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"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["all"] features = ["all"]
@@ -33,20 +34,20 @@ features = ["all"]
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
bimap = { version = "0.6", features = ["serde"], optional = true } bimap = { version = "0.6", features = ["serde"], optional = true }
byteorder = "1.5" byteorder = { version = "1.5", optional = true }
filetime = "0.2" filetime = { version = "0.2", optional = true }
flagset = "0.4" flagset = { version = "0.4", optional = true }
log = "0.4" log = { version = "0.4", optional = true }
memmap2 = "0.9" memmap2 = { version = "0.9", optional = true }
num-traits = "0.2" num-traits = { version = "0.2", optional = true }
object = { version = "0.36", features = ["read_core", "std", "elf", "pe"], default-features = false } object = { version = "0.36", features = ["read_core", "std", "elf", "pe"], default-features = false }
pbjson = { version = "0.7", optional = true } pbjson = { version = "0.7", optional = true }
prost = { version = "0.13", optional = true } prost = { version = "0.13", optional = true }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true }
similar = { version = "2.6", default-features = false } similar = { version = "2.6", default-features = false, optional = true }
strum = { version = "0.26", features = ["derive"] } strum = { version = "0.26", features = ["derive"], optional = true }
wasm-bindgen = "0.2" wasm-bindgen = { version = "0.2", optional = true }
tsify-next = { version = "0.5", default-features = false, features = ["js"] } tsify-next = { version = "0.5", default-features = false, features = ["js"], optional = true }
console_log = { version = "1.0", optional = true } console_log = { version = "1.0", optional = true }
console_error_panic_hook = { version = "0.1", optional = true } console_error_panic_hook = { version = "0.1", optional = true }
@@ -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 = "0.13" prost-build = { version = "0.13", optional = true }
pbjson-build = "0.7" pbjson-build = { version = "0.7", optional = true }
+1
View File
@@ -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.
+7 -2
View File
@@ -1,6 +1,11 @@
use std::path::{Path, PathBuf};
fn main() { fn main() {
#[cfg(feature = "bindings")]
compile_protos();
}
#[cfg(feature = "bindings")]
fn compile_protos() {
use std::path::{Path, PathBuf};
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos"); let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos");
let descriptor_path = root.join("proto_descriptor.bin"); let descriptor_path = root.join("proto_descriptor.bin");
println!("cargo:rerun-if-changed={}", descriptor_path.display()); println!("cargo:rerun-if-changed={}", descriptor_path.display());
+5 -7
View File
@@ -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
+2 -2
View File
@@ -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,
+9 -1
View File
@@ -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")]
@@ -34,7 +36,11 @@ pub enum DataType {
impl DataType { impl DataType {
pub fn display_bytes<Endian: ByteOrder>(&self, bytes: &[u8]) -> Option<String> { pub fn display_bytes<Endian: ByteOrder>(&self, bytes: &[u8]) -> Option<String> {
if self.required_len().is_some_and(|l| bytes.len() < l) { // TODO: Attempt to interpret large symbols as arrays of a smaller type,
// fallback to intrepreting it as bytes.
// https://github.com/encounter/objdiff/issues/124
if self.required_len().is_some_and(|l| bytes.len() != l) {
log::warn!("Failed to display a symbol value for a symbol whose size doesn't match the instruction referencing it.");
return None; return None;
} }
@@ -161,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:?}"),
}) })
} }
+1 -1
View File
@@ -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,
+4 -3
View File
@@ -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(
+1 -1
View File
@@ -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)),
+2
View File
@@ -165,6 +165,8 @@ pub struct ScratchConfig {
pub ctx_path: Option<PathBuf>, pub ctx_path: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub build_ctx: Option<bool>, pub build_ctx: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub preset_id: Option<u32>,
} }
pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.json", "objdiff.yml", "objdiff.yaml"]; pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.json", "objdiff.yml", "objdiff.yaml"];
+25 -18
View File
@@ -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 }
+11 -6
View File
@@ -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,
} }

Some files were not shown because too many files have changed in this diff Show More