mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-20 10:25:26 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2b7a9ef25 | |||
| 2cf9cf24d6 | |||
|
|
5ef3416457 | ||
|
|
6ff8d002f7 | ||
| 9ca157d717 | |||
|
|
67b63311fc | ||
| 72ea1c8911 | |||
| d4a540857d | |||
| 676488433f | |||
| 83de98b5ee | |||
| c1ba4e91d1 | |||
| 575900024d | |||
| cbe299e859 |
5
.cargo/config.toml
Normal file
5
.cargo/config.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
linker = "rust-lld"
|
||||||
|
|
||||||
|
[target.aarch64-pc-windows-msvc]
|
||||||
|
linker = "rust-lld"
|
||||||
18
.github/workflows/build.yaml
vendored
18
.github/workflows/build.yaml
vendored
@@ -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
|
||||||
|
|
||||||
@@ -142,11 +146,19 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install cargo-zigbuild
|
- name: Install cargo-zigbuild
|
||||||
if: matrix.build == 'zigbuild'
|
if: matrix.build == 'zigbuild'
|
||||||
run: pip install ziglang==0.13.0 cargo-zigbuild==0.19.1
|
run: |
|
||||||
|
python3 -m venv .venv
|
||||||
|
. .venv/bin/activate
|
||||||
|
echo PATH=$PATH >> $GITHUB_ENV
|
||||||
|
pip install ziglang==0.13.0 cargo-zigbuild==0.19.1
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
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 }}
|
||||||
@@ -198,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
.gitignore
vendored
4
.gitignore
vendored
@@ -3,10 +3,6 @@ target/
|
|||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
generated/
|
generated/
|
||||||
|
|
||||||
# cargo-mobile
|
|
||||||
.cargo/
|
|
||||||
/gen
|
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
|||||||
30
Cargo.lock
generated
30
Cargo.lock
generated
@@ -1526,15 +1526,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
@@ -1551,9 +1551,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1562,21 +1562,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
@@ -2861,7 +2861,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "2.3.0"
|
version = "2.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@@ -2883,7 +2883,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "2.3.0"
|
version = "2.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
@@ -2923,7 +2923,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "2.3.0"
|
version = "2.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ strip = "debuginfo"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "2.3.0"
|
version = "2.3.4"
|
||||||
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"
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ feature-depth = 1
|
|||||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||||
# output a note when they are encountered.
|
# output a note when they are encountered.
|
||||||
ignore = [
|
ignore = [
|
||||||
"RUSTSEC-2024-0370",
|
|
||||||
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
|
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
|
||||||
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
|
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
|
||||||
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
||||||
@@ -240,7 +239,7 @@ allow-git = []
|
|||||||
|
|
||||||
[sources.allow-org]
|
[sources.allow-org]
|
||||||
# github.com organizations to allow git sources for
|
# github.com organizations to allow git sources for
|
||||||
github = ["encounter"]
|
github = ["notify-rs"]
|
||||||
# gitlab.com organizations to allow git sources for
|
# gitlab.com organizations to allow git sources for
|
||||||
gitlab = []
|
gitlab = []
|
||||||
# bitbucket.org organizations to allow git sources for
|
# bitbucket.org organizations to allow git sources for
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "bindings"]
|
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "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"]
|
bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
|
||||||
wasm = ["bindings", "console_error_panic_hook", "console_log"]
|
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 +33,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 }
|
||||||
|
|
||||||
@@ -77,5 +77,5 @@ unarm = { version = "1.6", optional = true }
|
|||||||
arm-attr = { version = "0.1", optional = true }
|
arm-attr = { version = "0.1", 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,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());
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ impl ObjArch for ObjArchMips {
|
|||||||
&self,
|
&self,
|
||||||
address: u64,
|
address: u64,
|
||||||
code: &[u8],
|
code: &[u8],
|
||||||
_section_index: usize,
|
section_index: usize,
|
||||||
relocations: &[ObjReloc],
|
relocations: &[ObjReloc],
|
||||||
line_info: &BTreeMap<u64, u32>,
|
line_info: &BTreeMap<u64, u32>,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
@@ -140,11 +140,18 @@ impl ObjArch for ObjArchMips {
|
|||||||
| OperandType::cpu_label
|
| OperandType::cpu_label
|
||||||
| OperandType::cpu_branch_target_label => {
|
| OperandType::cpu_branch_target_label => {
|
||||||
if let Some(reloc) = reloc {
|
if let Some(reloc) = reloc {
|
||||||
if matches!(&reloc.target_section, Some(s) if s == ".text")
|
// If the relocation target is within the current function, we can
|
||||||
&& reloc.target.address > start_address
|
// convert it into a relative branch target. Note that we check
|
||||||
&& reloc.target.address < end_address
|
// target_address > start_address instead of >= so that recursive
|
||||||
|
// tail calls are not considered branch targets.
|
||||||
|
let target_address =
|
||||||
|
reloc.target.address.checked_add_signed(reloc.addend);
|
||||||
|
if reloc.target.orig_section_index == Some(section_index)
|
||||||
|
&& matches!(target_address, Some(addr) if addr > start_address && addr < end_address)
|
||||||
{
|
{
|
||||||
args.push(ObjInsArg::BranchDest(reloc.target.address));
|
let target_address = target_address.unwrap();
|
||||||
|
args.push(ObjInsArg::BranchDest(target_address));
|
||||||
|
branch_dest = Some(target_address);
|
||||||
} else {
|
} else {
|
||||||
push_reloc(&mut args, reloc)?;
|
push_reloc(&mut args, reloc)?;
|
||||||
branch_dest = None;
|
branch_dest = None;
|
||||||
|
|||||||
@@ -34,7 +34,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,9 +70,13 @@ impl FunctionDiff {
|
|||||||
// let (_section, symbol) = object.section_symbol(symbol_ref);
|
// let (_section, symbol) = object.section_symbol(symbol_ref);
|
||||||
// Symbol::from(symbol)
|
// Symbol::from(symbol)
|
||||||
// });
|
// });
|
||||||
let instructions = symbol_diff.instructions.iter().map(InstructionDiff::from).collect();
|
let instructions = symbol_diff
|
||||||
|
.instructions
|
||||||
|
.iter()
|
||||||
|
.map(|ins_diff| InstructionDiff::new(object, ins_diff))
|
||||||
|
.collect();
|
||||||
Self {
|
Self {
|
||||||
symbol: Some(Symbol::from(symbol)),
|
symbol: Some(Symbol::new(symbol)),
|
||||||
// diff_symbol,
|
// diff_symbol,
|
||||||
instructions,
|
instructions,
|
||||||
match_percent: symbol_diff.match_percent,
|
match_percent: symbol_diff.match_percent,
|
||||||
@@ -90,8 +94,8 @@ impl DataDiff {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjSymbol> for Symbol {
|
impl Symbol {
|
||||||
fn from(value: &'a ObjSymbol) -> Self {
|
pub fn new(value: &ObjSymbol) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: value.name.to_string(),
|
name: value.name.to_string(),
|
||||||
demangled_name: value.demangled_name.clone(),
|
demangled_name: value.demangled_name.clone(),
|
||||||
@@ -122,29 +126,29 @@ fn symbol_flags(value: ObjSymbolFlagSet) -> u32 {
|
|||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjIns> for Instruction {
|
impl Instruction {
|
||||||
fn from(value: &'a ObjIns) -> Self {
|
pub fn new(object: &ObjInfo, instruction: &ObjIns) -> Self {
|
||||||
Self {
|
Self {
|
||||||
address: value.address,
|
address: instruction.address,
|
||||||
size: value.size as u32,
|
size: instruction.size as u32,
|
||||||
opcode: value.op as u32,
|
opcode: instruction.op as u32,
|
||||||
mnemonic: value.mnemonic.clone(),
|
mnemonic: instruction.mnemonic.clone(),
|
||||||
formatted: value.formatted.clone(),
|
formatted: instruction.formatted.clone(),
|
||||||
arguments: value.args.iter().map(Argument::from).collect(),
|
arguments: instruction.args.iter().map(Argument::new).collect(),
|
||||||
relocation: value.reloc.as_ref().map(Relocation::from),
|
relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
|
||||||
branch_dest: value.branch_dest,
|
branch_dest: instruction.branch_dest,
|
||||||
line_number: value.line,
|
line_number: instruction.line,
|
||||||
original: value.orig.clone(),
|
original: instruction.orig.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjInsArg> for Argument {
|
impl Argument {
|
||||||
fn from(value: &'a ObjInsArg) -> Self {
|
pub fn new(value: &ObjInsArg) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: Some(match value {
|
value: Some(match value {
|
||||||
ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()),
|
ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()),
|
||||||
ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::from(v)),
|
ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::new(v)),
|
||||||
ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}),
|
ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}),
|
||||||
ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest),
|
ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest),
|
||||||
}),
|
}),
|
||||||
@@ -152,8 +156,8 @@ impl<'a> From<&'a ObjInsArg> for Argument {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ObjInsArgValue> for ArgumentValue {
|
impl ArgumentValue {
|
||||||
fn from(value: &ObjInsArgValue) -> Self {
|
pub fn new(value: &ObjInsArgValue) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: Some(match value {
|
value: Some(match value {
|
||||||
ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v),
|
ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v),
|
||||||
@@ -164,42 +168,39 @@ impl From<&ObjInsArgValue> for ArgumentValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjReloc> for Relocation {
|
impl Relocation {
|
||||||
fn from(value: &ObjReloc) -> Self {
|
pub fn new(object: &ObjInfo, reloc: &ObjReloc) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r#type: match value.flags {
|
r#type: match reloc.flags {
|
||||||
object::RelocationFlags::Elf { r_type } => r_type,
|
object::RelocationFlags::Elf { r_type } => r_type,
|
||||||
object::RelocationFlags::MachO { r_type, .. } => r_type as u32,
|
object::RelocationFlags::MachO { r_type, .. } => r_type as u32,
|
||||||
object::RelocationFlags::Coff { typ } => typ as u32,
|
object::RelocationFlags::Coff { typ } => typ as u32,
|
||||||
object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32,
|
object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
type_name: String::new(), // TODO
|
type_name: object.arch.display_reloc(reloc.flags).into_owned(),
|
||||||
target: Some(RelocationTarget::from(&value.target)),
|
target: Some(RelocationTarget {
|
||||||
|
symbol: Some(Symbol::new(&reloc.target)),
|
||||||
|
addend: reloc.addend,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjSymbol> for RelocationTarget {
|
impl InstructionDiff {
|
||||||
fn from(value: &'a ObjSymbol) -> Self {
|
pub fn new(object: &ObjInfo, instruction_diff: &ObjInsDiff) -> Self {
|
||||||
Self { symbol: Some(Symbol::from(value)), addend: value.addend }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a ObjInsDiff> for InstructionDiff {
|
|
||||||
fn from(value: &'a ObjInsDiff) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
instruction: value.ins.as_ref().map(Instruction::from),
|
instruction: instruction_diff.ins.as_ref().map(|ins| Instruction::new(object, ins)),
|
||||||
diff_kind: DiffKind::from(value.kind) as i32,
|
diff_kind: DiffKind::from(instruction_diff.kind) as i32,
|
||||||
branch_from: value.branch_from.as_ref().map(InstructionBranchFrom::from),
|
branch_from: instruction_diff.branch_from.as_ref().map(InstructionBranchFrom::new),
|
||||||
branch_to: value.branch_to.as_ref().map(InstructionBranchTo::from),
|
branch_to: instruction_diff.branch_to.as_ref().map(InstructionBranchTo::new),
|
||||||
arg_diff: value.arg_diff.iter().map(ArgumentDiff::from).collect(),
|
arg_diff: instruction_diff.arg_diff.iter().map(ArgumentDiff::new).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Option<ObjInsArgDiff>> for ArgumentDiff {
|
impl ArgumentDiff {
|
||||||
fn from(value: &Option<ObjInsArgDiff>) -> Self {
|
pub fn new(value: &Option<ObjInsArgDiff>) -> Self {
|
||||||
Self { diff_index: value.as_ref().map(|v| v.idx as u32) }
|
Self { diff_index: value.as_ref().map(|v| v.idx as u32) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,8 +229,8 @@ impl From<ObjDataDiffKind> for DiffKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom {
|
impl InstructionBranchFrom {
|
||||||
fn from(value: &'a ObjInsBranchFrom) -> Self {
|
pub fn new(value: &ObjInsBranchFrom) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(),
|
instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(),
|
||||||
branch_index: value.branch_idx as u32,
|
branch_index: value.branch_idx as u32,
|
||||||
@@ -237,8 +238,8 @@ impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a ObjInsBranchTo> for InstructionBranchTo {
|
impl InstructionBranchTo {
|
||||||
fn from(value: &'a ObjInsBranchTo) -> Self {
|
pub fn new(value: &ObjInsBranchTo) -> Self {
|
||||||
Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 }
|
Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
DiffObjConfig, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind,
|
DiffObjConfig, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind,
|
||||||
ObjSymbolDiff,
|
ObjSymbolDiff,
|
||||||
},
|
},
|
||||||
obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbol, ObjSymbolFlags, SymbolRef},
|
obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbolFlags, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_code_symbol(
|
pub fn process_code_symbol(
|
||||||
@@ -45,6 +45,8 @@ pub fn no_diff_code(out: &ProcessCodeResult, symbol_ref: SymbolRef) -> Result<Ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_code(
|
pub fn diff_code(
|
||||||
|
left_obj: &ObjInfo,
|
||||||
|
right_obj: &ObjInfo,
|
||||||
left_out: &ProcessCodeResult,
|
left_out: &ProcessCodeResult,
|
||||||
right_out: &ProcessCodeResult,
|
right_out: &ProcessCodeResult,
|
||||||
left_symbol_ref: SymbolRef,
|
left_symbol_ref: SymbolRef,
|
||||||
@@ -60,7 +62,7 @@ pub fn diff_code(
|
|||||||
|
|
||||||
let mut diff_state = InsDiffState::default();
|
let mut diff_state = InsDiffState::default();
|
||||||
for (left, right) in left_diff.iter_mut().zip(right_diff.iter_mut()) {
|
for (left, right) in left_diff.iter_mut().zip(right_diff.iter_mut()) {
|
||||||
let result = compare_ins(config, left, right, &mut diff_state)?;
|
let result = compare_ins(config, left_obj, right_obj, left, right, &mut diff_state)?;
|
||||||
left.kind = result.kind;
|
left.kind = result.kind;
|
||||||
right.kind = result.kind;
|
right.kind = result.kind;
|
||||||
left.arg_diff = result.left_args_diff;
|
left.arg_diff = result.left_args_diff;
|
||||||
@@ -170,12 +172,33 @@ fn resolve_branches(vec: &mut [ObjInsDiff]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn address_eq(left: &ObjSymbol, right: &ObjSymbol) -> bool {
|
fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
|
||||||
left.address as i64 + left.addend == right.address as i64 + right.addend
|
left.target.address as i64 + left.addend == right.target.address as i64 + right.addend
|
||||||
|
}
|
||||||
|
|
||||||
|
fn section_name_eq(
|
||||||
|
left_obj: &ObjInfo,
|
||||||
|
right_obj: &ObjInfo,
|
||||||
|
left_orig_section_index: usize,
|
||||||
|
right_orig_section_index: usize,
|
||||||
|
) -> bool {
|
||||||
|
let Some(left_section) =
|
||||||
|
left_obj.sections.iter().find(|s| s.orig_index == left_orig_section_index)
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(right_section) =
|
||||||
|
right_obj.sections.iter().find(|s| s.orig_index == right_orig_section_index)
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
left_section.name == right_section.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_eq(
|
fn reloc_eq(
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
|
left_obj: &ObjInfo,
|
||||||
|
right_obj: &ObjInfo,
|
||||||
left_reloc: Option<&ObjReloc>,
|
left_reloc: Option<&ObjReloc>,
|
||||||
right_reloc: Option<&ObjReloc>,
|
right_reloc: Option<&ObjReloc>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
@@ -189,23 +212,26 @@ fn reloc_eq(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_matches = left.target.name == right.target.name;
|
let symbol_name_matches = left.target.name == right.target.name;
|
||||||
match (&left.target_section, &right.target_section) {
|
match (&left.target.orig_section_index, &right.target.orig_section_index) {
|
||||||
(Some(sl), Some(sr)) => {
|
(Some(sl), Some(sr)) => {
|
||||||
// Match if section and name or address match
|
// Match if section and name or address match
|
||||||
sl == sr && (name_matches || address_eq(&left.target, &right.target))
|
section_name_eq(left_obj, right_obj, *sl, *sr)
|
||||||
|
&& (symbol_name_matches || address_eq(left, right))
|
||||||
}
|
}
|
||||||
(Some(_), None) => false,
|
(Some(_), None) => false,
|
||||||
(None, Some(_)) => {
|
(None, Some(_)) => {
|
||||||
// Match if possibly stripped weak symbol
|
// Match if possibly stripped weak symbol
|
||||||
name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
|
symbol_name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
|
||||||
}
|
}
|
||||||
(None, None) => name_matches,
|
(None, None) => symbol_name_matches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arg_eq(
|
fn arg_eq(
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
|
left_obj: &ObjInfo,
|
||||||
|
right_obj: &ObjInfo,
|
||||||
left: &ObjInsArg,
|
left: &ObjInsArg,
|
||||||
right: &ObjInsArg,
|
right: &ObjInsArg,
|
||||||
left_diff: &ObjInsDiff,
|
left_diff: &ObjInsDiff,
|
||||||
@@ -227,6 +253,8 @@ fn arg_eq(
|
|||||||
matches!(right, ObjInsArg::Reloc)
|
matches!(right, ObjInsArg::Reloc)
|
||||||
&& reloc_eq(
|
&& reloc_eq(
|
||||||
config,
|
config,
|
||||||
|
left_obj,
|
||||||
|
right_obj,
|
||||||
left_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
left_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
||||||
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
||||||
)
|
)
|
||||||
@@ -257,6 +285,8 @@ struct InsDiffResult {
|
|||||||
|
|
||||||
fn compare_ins(
|
fn compare_ins(
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
|
left_obj: &ObjInfo,
|
||||||
|
right_obj: &ObjInfo,
|
||||||
left: &ObjInsDiff,
|
left: &ObjInsDiff,
|
||||||
right: &ObjInsDiff,
|
right: &ObjInsDiff,
|
||||||
state: &mut InsDiffState,
|
state: &mut InsDiffState,
|
||||||
@@ -283,7 +313,7 @@ fn compare_ins(
|
|||||||
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.args.iter().zip(&right_ins.args) {
|
||||||
if arg_eq(config, 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);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -94,9 +94,9 @@ fn display_reloc_name<E>(
|
|||||||
mut cb: impl FnMut(DiffText) -> Result<(), E>,
|
mut cb: impl FnMut(DiffText) -> Result<(), E>,
|
||||||
) -> Result<(), E> {
|
) -> Result<(), E> {
|
||||||
cb(DiffText::Symbol(&reloc.target))?;
|
cb(DiffText::Symbol(&reloc.target))?;
|
||||||
match reloc.target.addend.cmp(&0i64) {
|
match reloc.addend.cmp(&0i64) {
|
||||||
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.target.addend))),
|
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))),
|
||||||
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.target.addend))),
|
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
diff_generic_section, no_diff_symbol,
|
diff_generic_section, no_diff_symbol,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef},
|
obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef, SECTION_COMMON},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod code;
|
pub mod code;
|
||||||
@@ -29,8 +29,8 @@ pub mod display;
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
strum::VariantArray,
|
strum::VariantArray,
|
||||||
strum::EnumMessage,
|
strum::EnumMessage,
|
||||||
tsify_next::Tsify,
|
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
pub enum X86Formatter {
|
pub enum X86Formatter {
|
||||||
#[default]
|
#[default]
|
||||||
#[strum(message = "Intel (default)")]
|
#[strum(message = "Intel (default)")]
|
||||||
@@ -54,8 +54,8 @@ pub enum X86Formatter {
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
strum::VariantArray,
|
strum::VariantArray,
|
||||||
strum::EnumMessage,
|
strum::EnumMessage,
|
||||||
tsify_next::Tsify,
|
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
pub enum MipsAbi {
|
pub enum MipsAbi {
|
||||||
#[default]
|
#[default]
|
||||||
#[strum(message = "Auto (default)")]
|
#[strum(message = "Auto (default)")]
|
||||||
@@ -79,8 +79,8 @@ pub enum MipsAbi {
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
strum::VariantArray,
|
strum::VariantArray,
|
||||||
strum::EnumMessage,
|
strum::EnumMessage,
|
||||||
tsify_next::Tsify,
|
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
pub enum MipsInstrCategory {
|
pub enum MipsInstrCategory {
|
||||||
#[default]
|
#[default]
|
||||||
#[strum(message = "Auto (default)")]
|
#[strum(message = "Auto (default)")]
|
||||||
@@ -108,8 +108,8 @@ pub enum MipsInstrCategory {
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
strum::VariantArray,
|
strum::VariantArray,
|
||||||
strum::EnumMessage,
|
strum::EnumMessage,
|
||||||
tsify_next::Tsify,
|
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
pub enum ArmArchVersion {
|
pub enum ArmArchVersion {
|
||||||
#[default]
|
#[default]
|
||||||
#[strum(message = "Auto (default)")]
|
#[strum(message = "Auto (default)")]
|
||||||
@@ -133,8 +133,8 @@ pub enum ArmArchVersion {
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
strum::VariantArray,
|
strum::VariantArray,
|
||||||
strum::EnumMessage,
|
strum::EnumMessage,
|
||||||
tsify_next::Tsify,
|
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
pub enum ArmR9Usage {
|
pub enum ArmR9Usage {
|
||||||
#[default]
|
#[default]
|
||||||
#[strum(
|
#[strum(
|
||||||
@@ -154,8 +154,9 @@ pub enum ArmR9Usage {
|
|||||||
#[inline]
|
#[inline]
|
||||||
const fn default_true() -> bool { true }
|
const fn default_true() -> bool { true }
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, tsify_next::Tsify)]
|
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||||
#[tsify(from_wasm_abi)]
|
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||||
|
#[cfg_attr(feature = "wasm", tsify(from_wasm_abi))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct DiffObjConfig {
|
pub struct DiffObjConfig {
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
@@ -339,7 +340,7 @@ impl ObjDiff {
|
|||||||
}
|
}
|
||||||
for (symbol_idx, _) in obj.common.iter().enumerate() {
|
for (symbol_idx, _) in obj.common.iter().enumerate() {
|
||||||
result.common.push(ObjSymbolDiff {
|
result.common.push(ObjSymbolDiff {
|
||||||
symbol_ref: SymbolRef { section_idx: obj.sections.len(), symbol_idx },
|
symbol_ref: SymbolRef { section_idx: SECTION_COMMON, symbol_idx },
|
||||||
target_symbol: None,
|
target_symbol: None,
|
||||||
instructions: vec![],
|
instructions: vec![],
|
||||||
match_percent: None,
|
match_percent: None,
|
||||||
@@ -360,7 +361,7 @@ impl ObjDiff {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn symbol_diff(&self, symbol_ref: SymbolRef) -> &ObjSymbolDiff {
|
pub fn symbol_diff(&self, symbol_ref: SymbolRef) -> &ObjSymbolDiff {
|
||||||
if symbol_ref.section_idx == self.sections.len() {
|
if symbol_ref.section_idx == SECTION_COMMON {
|
||||||
&self.common[symbol_ref.symbol_idx]
|
&self.common[symbol_ref.symbol_idx]
|
||||||
} else {
|
} else {
|
||||||
&self.section_diff(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
&self.section_diff(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
||||||
@@ -369,7 +370,7 @@ impl ObjDiff {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn symbol_diff_mut(&mut self, symbol_ref: SymbolRef) -> &mut ObjSymbolDiff {
|
pub fn symbol_diff_mut(&mut self, symbol_ref: SymbolRef) -> &mut ObjSymbolDiff {
|
||||||
if symbol_ref.section_idx == self.sections.len() {
|
if symbol_ref.section_idx == SECTION_COMMON {
|
||||||
&mut self.common[symbol_ref.symbol_idx]
|
&mut self.common[symbol_ref.symbol_idx]
|
||||||
} else {
|
} else {
|
||||||
&mut self.section_diff_mut(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
&mut self.section_diff_mut(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
||||||
@@ -411,6 +412,8 @@ pub fn diff_objs(
|
|||||||
let left_code = process_code_symbol(left_obj, left_symbol_ref, config)?;
|
let left_code = process_code_symbol(left_obj, left_symbol_ref, config)?;
|
||||||
let right_code = process_code_symbol(right_obj, right_symbol_ref, config)?;
|
let right_code = process_code_symbol(right_obj, right_symbol_ref, config)?;
|
||||||
let (left_diff, right_diff) = diff_code(
|
let (left_diff, right_diff) = diff_code(
|
||||||
|
left_obj,
|
||||||
|
right_obj,
|
||||||
&left_code,
|
&left_code,
|
||||||
&right_code,
|
&right_code,
|
||||||
left_symbol_ref,
|
left_symbol_ref,
|
||||||
@@ -424,6 +427,8 @@ pub fn diff_objs(
|
|||||||
let (prev_obj, prev_out) = prev.as_mut().unwrap();
|
let (prev_obj, prev_out) = prev.as_mut().unwrap();
|
||||||
let prev_code = process_code_symbol(prev_obj, prev_symbol_ref, config)?;
|
let prev_code = process_code_symbol(prev_obj, prev_symbol_ref, config)?;
|
||||||
let (_, prev_diff) = diff_code(
|
let (_, prev_diff) = diff_code(
|
||||||
|
left_obj,
|
||||||
|
right_obj,
|
||||||
&right_code,
|
&right_code,
|
||||||
&prev_code,
|
&prev_code,
|
||||||
right_symbol_ref,
|
right_symbol_ref,
|
||||||
@@ -592,6 +597,8 @@ fn generate_mapping_symbols(
|
|||||||
ObjSectionKind::Code => {
|
ObjSectionKind::Code => {
|
||||||
let target_code = process_code_symbol(target_obj, target_symbol_ref, config)?;
|
let target_code = process_code_symbol(target_obj, target_symbol_ref, config)?;
|
||||||
let (left_diff, _right_diff) = diff_code(
|
let (left_diff, _right_diff) = diff_code(
|
||||||
|
target_obj,
|
||||||
|
base_obj,
|
||||||
&target_code,
|
&target_code,
|
||||||
base_code.as_ref().unwrap(),
|
base_code.as_ref().unwrap(),
|
||||||
target_symbol_ref,
|
target_symbol_ref,
|
||||||
@@ -751,7 +758,7 @@ fn matching_symbols(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (symbol_idx, symbol) in left.common.iter().enumerate() {
|
for (symbol_idx, symbol) in left.common.iter().enumerate() {
|
||||||
let symbol_ref = SymbolRef { section_idx: left.sections.len(), symbol_idx };
|
let symbol_ref = SymbolRef { section_idx: SECTION_COMMON, symbol_idx };
|
||||||
if left_used.contains(&symbol_ref) {
|
if left_used.contains(&symbol_ref) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -783,7 +790,7 @@ fn matching_symbols(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (symbol_idx, symbol) in right.common.iter().enumerate() {
|
for (symbol_idx, symbol) in right.common.iter().enumerate() {
|
||||||
let symbol_ref = SymbolRef { section_idx: right.sections.len(), symbol_idx };
|
let symbol_ref = SymbolRef { section_idx: SECTION_COMMON, symbol_idx };
|
||||||
if right_used.contains(&symbol_ref) {
|
if right_used.contains(&symbol_ref) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -876,7 +883,7 @@ fn find_common_symbol(obj: Option<&ObjInfo>, in_symbol: &ObjSymbol) -> Option<Sy
|
|||||||
let obj = obj?;
|
let obj = obj?;
|
||||||
for (symbol_idx, symbol) in obj.common.iter().enumerate() {
|
for (symbol_idx, symbol) in obj.common.iter().enumerate() {
|
||||||
if symbol.name == in_symbol.name {
|
if symbol.name == in_symbol.name {
|
||||||
return Some(SymbolRef { section_idx: obj.sections.len(), symbol_idx });
|
return Some(SymbolRef { section_idx: SECTION_COMMON, symbol_idx });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ pub mod config;
|
|||||||
pub mod diff;
|
pub mod diff;
|
||||||
#[cfg(feature = "any-arch")]
|
#[cfg(feature = "any-arch")]
|
||||||
pub mod obj;
|
pub mod obj;
|
||||||
|
#[cfg(feature = "any-arch")]
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ pub struct ObjSymbol {
|
|||||||
pub size_known: bool,
|
pub size_known: bool,
|
||||||
pub kind: ObjSymbolKind,
|
pub kind: ObjSymbolKind,
|
||||||
pub flags: ObjSymbolFlagSet,
|
pub flags: ObjSymbolFlagSet,
|
||||||
pub addend: i64,
|
pub orig_section_index: Option<usize>,
|
||||||
/// Original virtual address (from .note.split section)
|
/// Original virtual address (from .note.split section)
|
||||||
pub virtual_address: Option<u64>,
|
pub virtual_address: Option<u64>,
|
||||||
/// Original index in object symbol table
|
/// Original index in object symbol table
|
||||||
@@ -155,7 +155,7 @@ pub struct ObjReloc {
|
|||||||
pub flags: RelocationFlags,
|
pub flags: RelocationFlags,
|
||||||
pub address: u64,
|
pub address: u64,
|
||||||
pub target: ObjSymbol,
|
pub target: ObjSymbol,
|
||||||
pub target_section: Option<String>,
|
pub addend: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
@@ -164,9 +164,11 @@ pub struct SymbolRef {
|
|||||||
pub symbol_idx: usize,
|
pub symbol_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const SECTION_COMMON: usize = usize::MAX - 1;
|
||||||
|
|
||||||
impl ObjInfo {
|
impl ObjInfo {
|
||||||
pub fn section_symbol(&self, symbol_ref: SymbolRef) -> (Option<&ObjSection>, &ObjSymbol) {
|
pub fn section_symbol(&self, symbol_ref: SymbolRef) -> (Option<&ObjSection>, &ObjSymbol) {
|
||||||
if symbol_ref.section_idx == self.sections.len() {
|
if symbol_ref.section_idx == SECTION_COMMON {
|
||||||
let symbol = &self.common[symbol_ref.symbol_idx];
|
let symbol = &self.common[symbol_ref.symbol_idx];
|
||||||
return (None, symbol);
|
return (None, symbol);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use object::{
|
|||||||
endian::LittleEndian as LE,
|
endian::LittleEndian as LE,
|
||||||
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
|
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
|
||||||
read::coff::{CoffFile, CoffHeader, ImageSymbol},
|
read::coff::{CoffFile, CoffHeader, ImageSymbol},
|
||||||
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex,
|
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, Section,
|
||||||
SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
|
SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -41,7 +41,6 @@ fn to_obj_symbol(
|
|||||||
arch: &dyn ObjArch,
|
arch: &dyn ObjArch,
|
||||||
obj_file: &File<'_>,
|
obj_file: &File<'_>,
|
||||||
symbol: &Symbol<'_, '_>,
|
symbol: &Symbol<'_, '_>,
|
||||||
addend: i64,
|
|
||||||
split_meta: Option<&SplitMeta>,
|
split_meta: Option<&SplitMeta>,
|
||||||
) -> Result<ObjSymbol> {
|
) -> Result<ObjSymbol> {
|
||||||
let mut name = symbol.name().context("Failed to process symbol name")?;
|
let mut name = symbol.name().context("Failed to process symbol name")?;
|
||||||
@@ -65,6 +64,7 @@ fn to_obj_symbol(
|
|||||||
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
|
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
|
||||||
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
|
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "ppc")]
|
||||||
if arch
|
if arch
|
||||||
.ppc()
|
.ppc()
|
||||||
.and_then(|a| a.extab.as_ref())
|
.and_then(|a| a.extab.as_ref())
|
||||||
@@ -111,7 +111,7 @@ fn to_obj_symbol(
|
|||||||
size_known: symbol.size() != 0,
|
size_known: symbol.size() != 0,
|
||||||
kind,
|
kind,
|
||||||
flags,
|
flags,
|
||||||
addend,
|
orig_section_index: symbol.section_index().map(|i| i.0),
|
||||||
virtual_address,
|
virtual_address,
|
||||||
original_index: Some(symbol.index().0),
|
original_index: Some(symbol.index().0),
|
||||||
bytes: bytes.to_vec(),
|
bytes: bytes.to_vec(),
|
||||||
@@ -177,19 +177,19 @@ fn symbols_by_section(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.push(to_obj_symbol(arch, obj_file, symbol, 0, split_meta)?);
|
result.push(to_obj_symbol(arch, obj_file, symbol, split_meta)?);
|
||||||
}
|
}
|
||||||
result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
|
result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
|
||||||
let mut iter = result.iter_mut().peekable();
|
let mut iter = result.iter_mut().peekable();
|
||||||
while let Some(symbol) = iter.next() {
|
while let Some(symbol) = iter.next() {
|
||||||
if symbol.kind == ObjSymbolKind::Unknown && symbol.size == 0 {
|
if symbol.size == 0 {
|
||||||
if let Some(next_symbol) = iter.peek() {
|
if let Some(next_symbol) = iter.peek() {
|
||||||
symbol.size = next_symbol.address - symbol.address;
|
symbol.size = next_symbol.address - symbol.address;
|
||||||
} else {
|
} else {
|
||||||
symbol.size = (section.address + section.size) - symbol.address;
|
symbol.size = (section.address + section.size) - symbol.address;
|
||||||
}
|
}
|
||||||
// Set symbol kind if we ended up with a non-zero size
|
// Set symbol kind if we ended up with a non-zero size
|
||||||
if symbol.size > 0 {
|
if symbol.kind == ObjSymbolKind::Unknown && symbol.size > 0 {
|
||||||
symbol.kind = match section.kind {
|
symbol.kind = match section.kind {
|
||||||
ObjSectionKind::Code => ObjSymbolKind::Function,
|
ObjSectionKind::Code => ObjSymbolKind::Function,
|
||||||
ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
|
ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
|
||||||
@@ -217,7 +217,7 @@ fn symbols_by_section(
|
|||||||
ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
|
ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
|
||||||
},
|
},
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
addend: 0,
|
orig_section_index: Some(section.orig_index),
|
||||||
virtual_address: None,
|
virtual_address: None,
|
||||||
original_index: None,
|
original_index: None,
|
||||||
bytes: Vec::new(),
|
bytes: Vec::new(),
|
||||||
@@ -234,7 +234,7 @@ fn common_symbols(
|
|||||||
obj_file
|
obj_file
|
||||||
.symbols()
|
.symbols()
|
||||||
.filter(Symbol::is_common)
|
.filter(Symbol::is_common)
|
||||||
.map(|symbol| to_obj_symbol(arch, obj_file, &symbol, 0, split_meta))
|
.map(|symbol| to_obj_symbol(arch, obj_file, &symbol, split_meta))
|
||||||
.collect::<Result<Vec<ObjSymbol>>>()
|
.collect::<Result<Vec<ObjSymbol>>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,10 +245,18 @@ fn best_symbol<'r, 'data, 'file>(
|
|||||||
symbols: &'r [Symbol<'data, 'file>],
|
symbols: &'r [Symbol<'data, 'file>],
|
||||||
address: u64,
|
address: u64,
|
||||||
) -> Option<&'r Symbol<'data, 'file>> {
|
) -> Option<&'r Symbol<'data, 'file>> {
|
||||||
let closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) {
|
let mut closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) {
|
||||||
Ok(index) => Some(index),
|
Ok(index) => Some(index),
|
||||||
Err(index) => index.checked_sub(1),
|
Err(index) => index.checked_sub(1),
|
||||||
}?;
|
}?;
|
||||||
|
// The binary search may not find the first symbol at the address, so work backwards
|
||||||
|
let target_address = symbols[closest_symbol_index].address();
|
||||||
|
while let Some(prev_index) = closest_symbol_index.checked_sub(1) {
|
||||||
|
if symbols[prev_index].address() != target_address {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closest_symbol_index = prev_index;
|
||||||
|
}
|
||||||
let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None;
|
let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None;
|
||||||
for symbol in symbols.iter().skip(closest_symbol_index) {
|
for symbol in symbols.iter().skip(closest_symbol_index) {
|
||||||
if symbol.address() > address {
|
if symbol.address() > address {
|
||||||
@@ -276,24 +284,15 @@ fn best_symbol<'r, 'data, 'file>(
|
|||||||
fn find_section_symbol(
|
fn find_section_symbol(
|
||||||
arch: &dyn ObjArch,
|
arch: &dyn ObjArch,
|
||||||
obj_file: &File<'_>,
|
obj_file: &File<'_>,
|
||||||
|
section: &Section,
|
||||||
section_symbols: &[Symbol<'_, '_>],
|
section_symbols: &[Symbol<'_, '_>],
|
||||||
target: &Symbol<'_, '_>,
|
|
||||||
address: u64,
|
address: u64,
|
||||||
split_meta: Option<&SplitMeta>,
|
split_meta: Option<&SplitMeta>,
|
||||||
) -> Result<ObjSymbol> {
|
) -> Result<ObjSymbol> {
|
||||||
if let Some(symbol) = best_symbol(section_symbols, address) {
|
if let Some(symbol) = best_symbol(section_symbols, address) {
|
||||||
return to_obj_symbol(
|
return to_obj_symbol(arch, obj_file, symbol, split_meta);
|
||||||
arch,
|
|
||||||
obj_file,
|
|
||||||
symbol,
|
|
||||||
address as i64 - symbol.address() as i64,
|
|
||||||
split_meta,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Fallback to section symbol
|
// Fallback to section symbol
|
||||||
let section_index =
|
|
||||||
target.section_index().ok_or_else(|| anyhow::Error::msg("Unknown section index"))?;
|
|
||||||
let section = obj_file.section_by_index(section_index)?;
|
|
||||||
Ok(ObjSymbol {
|
Ok(ObjSymbol {
|
||||||
name: section.name()?.to_string(),
|
name: section.name()?.to_string(),
|
||||||
demangled_name: None,
|
demangled_name: None,
|
||||||
@@ -303,7 +302,7 @@ fn find_section_symbol(
|
|||||||
size_known: false,
|
size_known: false,
|
||||||
kind: ObjSymbolKind::Section,
|
kind: ObjSymbolKind::Section,
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
addend: address as i64 - section.address() as i64,
|
orig_section_index: Some(section.index().0),
|
||||||
virtual_address: None,
|
virtual_address: None,
|
||||||
original_index: None,
|
original_index: None,
|
||||||
bytes: Vec::new(),
|
bytes: Vec::new(),
|
||||||
@@ -314,7 +313,7 @@ fn relocations_by_section(
|
|||||||
arch: &dyn ObjArch,
|
arch: &dyn ObjArch,
|
||||||
obj_file: &File<'_>,
|
obj_file: &File<'_>,
|
||||||
section: &ObjSection,
|
section: &ObjSection,
|
||||||
section_symbols: &[Symbol<'_, '_>],
|
section_symbols: &[Vec<Symbol<'_, '_>>],
|
||||||
split_meta: Option<&SplitMeta>,
|
split_meta: Option<&SplitMeta>,
|
||||||
) -> Result<Vec<ObjReloc>> {
|
) -> Result<Vec<ObjReloc>> {
|
||||||
let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?;
|
let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?;
|
||||||
@@ -339,37 +338,36 @@ fn relocations_by_section(
|
|||||||
_ => 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?
|
||||||
let target_section = match symbol.section() {
|
let mut addend = if reloc.has_implicit_addend() {
|
||||||
SymbolSection::Common => Some(".comm".to_string()),
|
|
||||||
SymbolSection::Section(idx) => {
|
|
||||||
obj_file.section_by_index(idx).and_then(|s| s.name().map(|s| s.to_string())).ok()
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let addend = if reloc.has_implicit_addend() {
|
|
||||||
arch.implcit_addend(obj_file, section, address, &reloc)?
|
arch.implcit_addend(obj_file, section, address, &reloc)?
|
||||||
} else {
|
} else {
|
||||||
reloc.addend()
|
reloc.addend()
|
||||||
};
|
};
|
||||||
// println!("Reloc: {reloc:?}, symbol: {symbol:?}, addend: {addend:#x}");
|
|
||||||
let target = match symbol.kind() {
|
let target = match symbol.kind() {
|
||||||
SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => {
|
SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => {
|
||||||
to_obj_symbol(arch, obj_file, &symbol, addend, split_meta)
|
to_obj_symbol(arch, obj_file, &symbol, split_meta)?
|
||||||
}
|
}
|
||||||
SymbolKind::Section => {
|
SymbolKind::Section => {
|
||||||
ensure!(addend >= 0, "Negative addend in reloc: {addend}");
|
ensure!(addend >= 0, "Negative addend in section reloc: {addend}");
|
||||||
find_section_symbol(
|
let section_index = symbol
|
||||||
|
.section_index()
|
||||||
|
.ok_or_else(|| anyhow!("Section symbol {symbol:?} has no section index"))?;
|
||||||
|
let section = obj_file.section_by_index(section_index)?;
|
||||||
|
let symbol = find_section_symbol(
|
||||||
arch,
|
arch,
|
||||||
obj_file,
|
obj_file,
|
||||||
section_symbols,
|
§ion,
|
||||||
&symbol,
|
§ion_symbols[section_index.0],
|
||||||
addend as u64,
|
addend as u64,
|
||||||
split_meta,
|
split_meta,
|
||||||
)
|
)?;
|
||||||
|
// Adjust addend to be relative to the selected symbol
|
||||||
|
addend = (symbol.address - section.address()) as i64;
|
||||||
|
symbol
|
||||||
}
|
}
|
||||||
kind => Err(anyhow!("Unhandled relocation symbol type {kind:?}")),
|
kind => bail!("Unhandled relocation symbol type {kind:?}"),
|
||||||
}?;
|
};
|
||||||
relocations.push(ObjReloc { flags, address, target, target_section });
|
relocations.push(ObjReloc { flags, address, target, addend });
|
||||||
}
|
}
|
||||||
Ok(relocations)
|
Ok(relocations)
|
||||||
}
|
}
|
||||||
@@ -434,9 +432,9 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection], obj_data: &[u8])
|
|||||||
let mut text_sections =
|
let mut text_sections =
|
||||||
obj_file.sections().filter(|s| s.kind() == SectionKind::Text);
|
obj_file.sections().filter(|s| s.kind() == SectionKind::Text);
|
||||||
let section_index = text_sections.next().map(|s| s.index().0);
|
let section_index = text_sections.next().map(|s| s.index().0);
|
||||||
let mut lines = section_index.map(|index| {
|
let mut lines = section_index
|
||||||
&mut sections.iter_mut().find(|s| s.orig_index == index).unwrap().line_info
|
.and_then(|index| sections.iter_mut().find(|s| s.orig_index == index))
|
||||||
});
|
.map(|s| &mut s.line_info);
|
||||||
|
|
||||||
let mut rows = program.rows();
|
let mut rows = program.rows();
|
||||||
while let Some((_header, row)) = rows.next_row()? {
|
while let Some((_header, row)) = rows.next_row()? {
|
||||||
@@ -447,13 +445,9 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection], obj_data: &[u8])
|
|||||||
// The next row is the start of a new sequence, which means we must
|
// The next row is the start of a new sequence, which means we must
|
||||||
// advance to the next .text section.
|
// advance to the next .text section.
|
||||||
let section_index = text_sections.next().map(|s| s.index().0);
|
let section_index = text_sections.next().map(|s| s.index().0);
|
||||||
lines = section_index.map(|index| {
|
lines = section_index
|
||||||
&mut sections
|
.and_then(|index| sections.iter_mut().find(|s| s.orig_index == index))
|
||||||
.iter_mut()
|
.map(|s| &mut s.line_info);
|
||||||
.find(|s| s.orig_index == index)
|
|
||||||
.unwrap()
|
|
||||||
.line_info
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,7 +585,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
|
|||||||
size_known: symbol.size_known,
|
size_known: symbol.size_known,
|
||||||
kind: symbol.kind,
|
kind: symbol.kind,
|
||||||
flags: symbol.flags,
|
flags: symbol.flags,
|
||||||
addend: symbol.addend,
|
orig_section_index: symbol.orig_section_index,
|
||||||
virtual_address: if let Some(virtual_address) = symbol.virtual_address {
|
virtual_address: if let Some(virtual_address) = symbol.virtual_address {
|
||||||
Some((virtual_address as i64 + address_change).try_into()?)
|
Some((virtual_address as i64 + address_change).try_into()?)
|
||||||
} else {
|
} else {
|
||||||
@@ -618,7 +612,7 @@ fn combine_sections(section: ObjSection, combine: ObjSection) -> Result<ObjSecti
|
|||||||
flags: reloc.flags,
|
flags: reloc.flags,
|
||||||
address: (reloc.address as i64 + address_change).try_into()?,
|
address: (reloc.address as i64 + address_change).try_into()?,
|
||||||
target: reloc.target, // TODO: Should be updated?
|
target: reloc.target, // TODO: Should be updated?
|
||||||
target_section: reloc.target_section, // TODO: Same as above
|
addend: reloc.addend,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,27 +692,38 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
|
|||||||
let obj_file = File::parse(data)?;
|
let obj_file = File::parse(data)?;
|
||||||
let arch = new_arch(&obj_file)?;
|
let arch = new_arch(&obj_file)?;
|
||||||
let split_meta = split_meta(&obj_file)?;
|
let split_meta = split_meta(&obj_file)?;
|
||||||
let mut sections = filter_sections(&obj_file, split_meta.as_ref())?;
|
|
||||||
let mut name_counts: HashMap<String, u32> = HashMap::new();
|
// Create sorted symbol list for each section
|
||||||
for section in &mut sections {
|
let mut section_symbols = Vec::with_capacity(obj_file.sections().count());
|
||||||
|
for section in obj_file.sections() {
|
||||||
let mut symbols = obj_file
|
let mut symbols = obj_file
|
||||||
.symbols()
|
.symbols()
|
||||||
.filter(|s| s.section_index() == Some(SectionIndex(section.orig_index)))
|
.filter(|s| s.section_index() == Some(section.index()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
symbols.sort_by_key(|s| s.address());
|
symbols.sort_by_key(|s| s.address());
|
||||||
|
let section_index = section.index().0;
|
||||||
|
if section_index >= section_symbols.len() {
|
||||||
|
section_symbols.resize_with(section_index + 1, Vec::new);
|
||||||
|
}
|
||||||
|
section_symbols[section_index] = symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sections = filter_sections(&obj_file, split_meta.as_ref())?;
|
||||||
|
let mut section_name_counts: HashMap<String, u32> = HashMap::new();
|
||||||
|
for section in &mut sections {
|
||||||
section.symbols = symbols_by_section(
|
section.symbols = symbols_by_section(
|
||||||
arch.as_ref(),
|
arch.as_ref(),
|
||||||
&obj_file,
|
&obj_file,
|
||||||
section,
|
section,
|
||||||
&symbols,
|
§ion_symbols[section.orig_index],
|
||||||
split_meta.as_ref(),
|
split_meta.as_ref(),
|
||||||
&mut name_counts,
|
&mut section_name_counts,
|
||||||
)?;
|
)?;
|
||||||
section.relocations = relocations_by_section(
|
section.relocations = relocations_by_section(
|
||||||
arch.as_ref(),
|
arch.as_ref(),
|
||||||
&obj_file,
|
&obj_file,
|
||||||
section,
|
section,
|
||||||
&symbols,
|
§ion_symbols,
|
||||||
split_meta.as_ref(),
|
split_meta.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,15 +267,25 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_selected_obj(&mut self, config: ObjectConfig) {
|
pub fn set_selected_obj(&mut self, config: ObjectConfig) {
|
||||||
if self.config.selected_obj.as_ref().is_some_and(|existing| existing == &config) {
|
let mut unit_changed = true;
|
||||||
|
if let Some(existing) = self.config.selected_obj.as_ref() {
|
||||||
|
if existing == &config {
|
||||||
// Don't reload the object if there were no changes
|
// Don't reload the object if there were no changes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if existing.name == config.name {
|
||||||
|
unit_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
self.config.selected_obj = Some(config);
|
self.config.selected_obj = Some(config);
|
||||||
|
if unit_changed {
|
||||||
self.obj_change = true;
|
self.obj_change = true;
|
||||||
self.queue_build = false;
|
self.queue_build = false;
|
||||||
self.selecting_left = None;
|
self.selecting_left = None;
|
||||||
self.selecting_right = None;
|
self.selecting_right = None;
|
||||||
|
} else {
|
||||||
|
self.queue_build = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_selected_obj(&mut self) {
|
pub fn clear_selected_obj(&mut self) {
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ pub const DEFAULT_COLOR_ROTATION: [Color32; 9] = [
|
|||||||
Color32::from_rgb(255, 0, 0),
|
Color32::from_rgb(255, 0, 0),
|
||||||
Color32::from_rgb(255, 255, 0),
|
Color32::from_rgb(255, 255, 0),
|
||||||
Color32::from_rgb(255, 192, 203),
|
Color32::from_rgb(255, 192, 203),
|
||||||
Color32::from_rgb(0, 0, 255),
|
Color32::from_rgb(128, 128, 255),
|
||||||
Color32::from_rgb(0, 255, 0),
|
Color32::from_rgb(0, 255, 0),
|
||||||
Color32::from_rgb(213, 138, 138),
|
Color32::from_rgb(213, 138, 138),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::default::Default;
|
|||||||
use egui::{text::LayoutJob, Id, Label, Response, RichText, Sense, Widget};
|
use egui::{text::LayoutJob, Id, Label, Response, RichText, Sense, Widget};
|
||||||
use egui_extras::TableRow;
|
use egui_extras::TableRow;
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
arch::ObjArch,
|
|
||||||
diff::{
|
diff::{
|
||||||
display::{display_diff, DiffText, HighlightKind},
|
display::{display_diff, DiffText, HighlightKind},
|
||||||
ObjDiff, ObjInsDiff, ObjInsDiffKind,
|
ObjDiff, ObjInsDiff, ObjInsDiffKind,
|
||||||
@@ -77,7 +76,7 @@ impl FunctionViewState {
|
|||||||
|
|
||||||
fn ins_hover_ui(
|
fn ins_hover_ui(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
arch: &dyn ObjArch,
|
obj: &ObjInfo,
|
||||||
section: &ObjSection,
|
section: &ObjSection,
|
||||||
ins: &ObjIns,
|
ins: &ObjIns,
|
||||||
symbol: &ObjSymbol,
|
symbol: &ObjSymbol,
|
||||||
@@ -120,10 +119,17 @@ fn ins_hover_ui(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(reloc) = &ins.reloc {
|
if let Some(reloc) = &ins.reloc {
|
||||||
ui.label(format!("Relocation type: {}", arch.display_reloc(reloc.flags)));
|
ui.label(format!("Relocation type: {}", obj.arch.display_reloc(reloc.flags)));
|
||||||
ui.colored_label(appearance.highlight_color, format!("Name: {}", reloc.target.name));
|
ui.colored_label(appearance.highlight_color, format!("Name: {}", reloc.target.name));
|
||||||
if let Some(section) = &reloc.target_section {
|
if let Some(orig_section_index) = reloc.target.orig_section_index {
|
||||||
ui.colored_label(appearance.highlight_color, format!("Section: {section}"));
|
if let Some(section) =
|
||||||
|
obj.sections.iter().find(|s| s.orig_index == orig_section_index)
|
||||||
|
{
|
||||||
|
ui.colored_label(
|
||||||
|
appearance.highlight_color,
|
||||||
|
format!("Section: {}", section.name),
|
||||||
|
);
|
||||||
|
}
|
||||||
ui.colored_label(
|
ui.colored_label(
|
||||||
appearance.highlight_color,
|
appearance.highlight_color,
|
||||||
format!("Address: {:x}", reloc.target.address),
|
format!("Address: {:x}", reloc.target.address),
|
||||||
@@ -132,9 +138,10 @@ fn ins_hover_ui(
|
|||||||
appearance.highlight_color,
|
appearance.highlight_color,
|
||||||
format!("Size: {:x}", reloc.target.size),
|
format!("Size: {:x}", reloc.target.size),
|
||||||
);
|
);
|
||||||
if let Some(s) = arch
|
if let Some(s) = obj
|
||||||
|
.arch
|
||||||
.guess_data_type(ins)
|
.guess_data_type(ins)
|
||||||
.and_then(|ty| arch.display_data_type(ty, &reloc.target.bytes))
|
.and_then(|ty| obj.arch.display_data_type(ty, &reloc.target.bytes))
|
||||||
{
|
{
|
||||||
ui.colored_label(appearance.highlight_color, s);
|
ui.colored_label(appearance.highlight_color, s);
|
||||||
}
|
}
|
||||||
@@ -370,7 +377,7 @@ fn asm_col_ui(
|
|||||||
if let Some(ins) = &ins_diff.ins {
|
if let Some(ins) = &ins_diff.ins {
|
||||||
response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol));
|
response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol));
|
||||||
response.on_hover_ui_at_pointer(|ui| {
|
response.on_hover_ui_at_pointer(|ui| {
|
||||||
ins_hover_ui(ui, ctx.obj.arch.as_ref(), section, ins, symbol, appearance)
|
ins_hover_ui(ui, ctx.obj, section, ins, symbol, appearance)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
response
|
response
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ use egui::{
|
|||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
arch::ObjArch,
|
arch::ObjArch,
|
||||||
diff::{display::HighlightKind, ObjDiff, ObjSymbolDiff},
|
diff::{display::HighlightKind, ObjDiff, ObjSymbolDiff},
|
||||||
obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef},
|
obj::{
|
||||||
|
ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef, SECTION_COMMON,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use regex::{Regex, RegexBuilder};
|
use regex::{Regex, RegexBuilder};
|
||||||
|
|
||||||
@@ -651,11 +653,11 @@ pub fn symbol_list_ui(
|
|||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
|
||||||
// Skip sections with all symbols filtered out
|
// Skip sections with all symbols filtered out
|
||||||
if mapping.keys().any(|symbol_ref| symbol_ref.section_idx == usize::MAX) {
|
if mapping.keys().any(|symbol_ref| symbol_ref.section_idx == SECTION_COMMON) {
|
||||||
CollapsingHeader::new(".comm").default_open(true).show(ui, |ui| {
|
CollapsingHeader::new(".comm").default_open(true).show(ui, |ui| {
|
||||||
for (symbol_ref, symbol_diff) in mapping
|
for (symbol_ref, symbol_diff) in mapping
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(symbol_ref, _)| symbol_ref.section_idx == usize::MAX)
|
.filter(|(symbol_ref, _)| symbol_ref.section_idx == SECTION_COMMON)
|
||||||
{
|
{
|
||||||
let symbol = ctx.obj.section_symbol(*symbol_ref).1;
|
let symbol = ctx.obj.section_symbol(*symbol_ref).1;
|
||||||
if let Some(result) = symbol_ui(
|
if let Some(result) = symbol_ui(
|
||||||
|
|||||||
Reference in New Issue
Block a user