mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-15 16:16:15 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a119d9a6dd | |||
|
|
ebf653816a | ||
| 424434edd6 | |||
| 7f14b684bf | |||
| c5da7f7dd5 | |||
| 2fd655850a | |||
| 79bd7317c1 | |||
| 21f8f2407c | |||
| d2b7a9ef25 | |||
| 2cf9cf24d6 | |||
|
|
5ef3416457 | ||
|
|
6ff8d002f7 | ||
| 9ca157d717 | |||
|
|
67b63311fc | ||
| 72ea1c8911 | |||
| d4a540857d |
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"
|
||||
12
.github/workflows/build.yaml
vendored
12
.github/workflows/build.yaml
vendored
@@ -30,6 +30,8 @@ jobs:
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
- name: Cache Rust workspace
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Cargo check
|
||||
run: cargo check --all-features --all-targets
|
||||
- name: Cargo clippy
|
||||
@@ -85,6 +87,8 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Cache Rust workspace
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Cargo test
|
||||
run: cargo test --release --all-features
|
||||
|
||||
@@ -151,6 +155,10 @@ jobs:
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Cache Rust workspace
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: ${{ matrix.target }}
|
||||
- name: Cargo build
|
||||
run: >
|
||||
cargo ${{ matrix.build }} --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
|
||||
@@ -202,6 +210,10 @@ jobs:
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Cache Rust workspace
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: ${{ matrix.target }}
|
||||
- name: Cargo build
|
||||
run: >
|
||||
cargo build --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,10 +3,6 @@ target/
|
||||
**/*.rs.bk
|
||||
generated/
|
||||
|
||||
# cargo-mobile
|
||||
.cargo/
|
||||
/gen
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
|
||||
66
Cargo.lock
generated
66
Cargo.lock
generated
@@ -434,6 +434,18 @@ dependencies = [
|
||||
"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]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@@ -1514,6 +1526,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
@@ -2861,7 +2879,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -2883,7 +2901,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -2919,11 +2937,13 @@ dependencies = [
|
||||
"tsify-next",
|
||||
"unarm",
|
||||
"wasm-bindgen",
|
||||
"yaxpeax-arch",
|
||||
"yaxpeax-arm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -3495,6 +3515,12 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -4290,6 +4316,12 @@ dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tauri-winres"
|
||||
version = "0.1.1"
|
||||
@@ -5525,6 +5557,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-dl"
|
||||
version = "2.21.0"
|
||||
@@ -5598,6 +5639,25 @@ version = "0.8.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "yeslogic-fontconfig-sys"
|
||||
version = "6.0.0"
|
||||
|
||||
@@ -13,7 +13,7 @@ strip = "debuginfo"
|
||||
codegen-units = 1
|
||||
|
||||
[workspace.package]
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -20,6 +20,7 @@ Supports:
|
||||
- MIPS (N64, PS1, PS2, PSP)
|
||||
- x86 (COFF only at the moment)
|
||||
- ARM (GBA, DS, 3DS)
|
||||
- ARM64 (Switch, experimental)
|
||||
|
||||
See [Usage](#usage) for more information.
|
||||
|
||||
|
||||
@@ -844,10 +844,14 @@ impl FunctionDiffUi {
|
||||
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);
|
||||
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) => {
|
||||
line.spans.push(Span::raw(" ".repeat(n)));
|
||||
|
||||
@@ -16,16 +16,17 @@ documentation = "https://docs.rs/objdiff-core"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "bindings"]
|
||||
any-arch = ["bimap"] # Implicit, used to check if any arch is enabled
|
||||
config = ["bimap", "globset", "semver", "serde_json", "serde_yaml"]
|
||||
dwarf = ["gimli"]
|
||||
mips = ["any-arch", "rabbitizer"]
|
||||
ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"]
|
||||
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"]
|
||||
arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"]
|
||||
bindings = ["serde_json", "prost", "pbjson"]
|
||||
wasm = ["bindings", "console_error_panic_hook", "console_log"]
|
||||
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "arm64", "bindings"]
|
||||
any-arch = ["config", "dep:bimap", "dep:strum", "dep:similar", "dep:flagset", "dep:log", "dep:memmap2", "dep:byteorder", "dep:num-traits"] # Implicit, used to check if any arch is enabled
|
||||
config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
|
||||
dwarf = ["dep:gimli"]
|
||||
mips = ["any-arch", "dep:rabbitizer"]
|
||||
ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
|
||||
x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
|
||||
arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
|
||||
arm64 = ["any-arch", "dep:cpp_demangle", "dep:yaxpeax-arch", "dep:yaxpeax-arm"]
|
||||
bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
|
||||
wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["all"]
|
||||
@@ -33,20 +34,20 @@ features = ["all"]
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bimap = { version = "0.6", features = ["serde"], optional = true }
|
||||
byteorder = "1.5"
|
||||
filetime = "0.2"
|
||||
flagset = "0.4"
|
||||
log = "0.4"
|
||||
memmap2 = "0.9"
|
||||
num-traits = "0.2"
|
||||
byteorder = { version = "1.5", optional = true }
|
||||
filetime = { version = "0.2", optional = true }
|
||||
flagset = { version = "0.4", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
memmap2 = { version = "0.9", optional = true }
|
||||
num-traits = { version = "0.2", optional = true }
|
||||
object = { version = "0.36", features = ["read_core", "std", "elf", "pe"], default-features = false }
|
||||
pbjson = { version = "0.7", optional = true }
|
||||
prost = { version = "0.13", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
similar = { version = "2.6", default-features = false }
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
wasm-bindgen = "0.2"
|
||||
tsify-next = { version = "0.5", default-features = false, features = ["js"] }
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
similar = { version = "2.6", default-features = false, optional = true }
|
||||
strum = { version = "0.26", features = ["derive"], optional = true }
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
tsify-next = { version = "0.5", default-features = false, features = ["js"], optional = true }
|
||||
console_log = { version = "1.0", 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 }
|
||||
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]
|
||||
prost-build = "0.13"
|
||||
pbjson-build = "0.7"
|
||||
prost-build = { version = "0.13", optional = true }
|
||||
pbjson-build = { version = "0.7", optional = true }
|
||||
|
||||
@@ -11,4 +11,5 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
|
||||
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
|
||||
- **`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).
|
||||
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
|
||||
- **`bindings`**: Enables serialization and deserialization of objdiff data structures.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
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 descriptor_path = root.join("proto_descriptor.bin");
|
||||
println!("cargo:rerun-if-changed={}", descriptor_path.display());
|
||||
|
||||
@@ -124,11 +124,9 @@ impl ObjArch for ObjArchArm {
|
||||
.get(&SectionIndex(section_index))
|
||||
.map(|x| x.as_slice())
|
||||
.unwrap_or(&fallback_mappings);
|
||||
let first_mapping_idx =
|
||||
match mapping_symbols.binary_search_by_key(&start_addr, |x| x.address) {
|
||||
Ok(idx) => idx,
|
||||
Err(idx) => idx - 1,
|
||||
};
|
||||
let first_mapping_idx = mapping_symbols
|
||||
.binary_search_by_key(&start_addr, |x| x.address)
|
||||
.unwrap_or_else(|idx| idx - 1);
|
||||
let first_mapping = mapping_symbols[first_mapping_idx].mapping;
|
||||
|
||||
let mut mappings_iter =
|
||||
@@ -215,7 +213,7 @@ impl ObjArch for ObjArchArm {
|
||||
address: address as u64,
|
||||
size: (parser.address - address) as u8,
|
||||
op: ins.opcode_id(),
|
||||
mnemonic: parsed_ins.mnemonic.to_string(),
|
||||
mnemonic: Cow::Borrowed(parsed_ins.mnemonic),
|
||||
args,
|
||||
reloc,
|
||||
branch_dest,
|
||||
@@ -234,7 +232,7 @@ impl ObjArch for ObjArchArm {
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
) -> anyhow::Result<i64> {
|
||||
) -> Result<i64> {
|
||||
let address = address as usize;
|
||||
Ok(match reloc.flags() {
|
||||
// ARM calls
|
||||
|
||||
2840
objdiff-core/src/arch/arm64.rs
Normal file
2840
objdiff-core/src/arch/arm64.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -119,7 +119,7 @@ impl ObjArch for ObjArchMips {
|
||||
let op = instruction.unique_id as u16;
|
||||
ops.push(op);
|
||||
|
||||
let mnemonic = instruction.opcode_name().to_string();
|
||||
let mnemonic = instruction.opcode_name();
|
||||
let is_branch = instruction.is_branch();
|
||||
let branch_offset = instruction.branch_offset();
|
||||
let mut branch_dest = if is_branch {
|
||||
@@ -202,7 +202,7 @@ impl ObjArch for ObjArchMips {
|
||||
address: cur_addr as u64,
|
||||
size: 4,
|
||||
op,
|
||||
mnemonic,
|
||||
mnemonic: Cow::Borrowed(mnemonic),
|
||||
args,
|
||||
reloc: reloc.cloned(),
|
||||
branch_dest,
|
||||
|
||||
@@ -12,6 +12,8 @@ use crate::{
|
||||
|
||||
#[cfg(feature = "arm")]
|
||||
mod arm;
|
||||
#[cfg(feature = "arm64")]
|
||||
mod arm64;
|
||||
#[cfg(feature = "mips")]
|
||||
pub mod mips;
|
||||
#[cfg(feature = "ppc")]
|
||||
@@ -34,7 +36,11 @@ pub enum DataType {
|
||||
|
||||
impl DataType {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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)?),
|
||||
#[cfg(feature = "arm")]
|
||||
Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?),
|
||||
#[cfg(feature = "arm64")]
|
||||
Architecture::Aarch64 => Box::new(arm64::ObjArchArm64::new(object)?),
|
||||
arch => bail!("Unsupported architecture: {arch:?}"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ impl ObjArch for ObjArchPpc {
|
||||
insts.push(ObjIns {
|
||||
address: cur_addr as u64,
|
||||
size: 4,
|
||||
mnemonic: simplified.mnemonic.to_string(),
|
||||
mnemonic: Cow::Borrowed(simplified.mnemonic),
|
||||
args,
|
||||
reloc: reloc.cloned(),
|
||||
op: ins.op as u16,
|
||||
|
||||
@@ -51,7 +51,7 @@ impl ObjArch for ObjArchX86 {
|
||||
address: 0,
|
||||
size: 0,
|
||||
op: 0,
|
||||
mnemonic: String::new(),
|
||||
mnemonic: Cow::Borrowed("<invalid>"),
|
||||
args: vec![],
|
||||
reloc: None,
|
||||
branch_dest: None,
|
||||
@@ -76,7 +76,7 @@ impl ObjArch for ObjArchX86 {
|
||||
address,
|
||||
size: instruction.len() as u8,
|
||||
op,
|
||||
mnemonic: String::new(),
|
||||
mnemonic: Cow::Borrowed("<invalid>"),
|
||||
args: vec![],
|
||||
reloc: reloc.cloned(),
|
||||
branch_dest: None,
|
||||
@@ -242,7 +242,8 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||
|
||||
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
|
||||
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(
|
||||
|
||||
@@ -132,7 +132,7 @@ impl Instruction {
|
||||
address: instruction.address,
|
||||
size: instruction.size as u32,
|
||||
opcode: instruction.op as u32,
|
||||
mnemonic: instruction.mnemonic.clone(),
|
||||
mnemonic: instruction.mnemonic.to_string(),
|
||||
formatted: instruction.formatted.clone(),
|
||||
arguments: instruction.args.iter().map(Argument::new).collect(),
|
||||
relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
|
||||
|
||||
@@ -165,6 +165,8 @@ pub struct ScratchConfig {
|
||||
pub ctx_path: Option<PathBuf>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
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"];
|
||||
|
||||
@@ -259,11 +259,17 @@ fn arg_eq(
|
||||
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
|
||||
)
|
||||
}
|
||||
ObjInsArg::BranchDest(_) => {
|
||||
ObjInsArg::BranchDest(_) => match right {
|
||||
// Compare dest instruction idx after diffing
|
||||
left_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
||||
== right_diff.branch_to.as_ref().map(|b| b.ins_idx)
|
||||
}
|
||||
ObjInsArg::BranchDest(_) => {
|
||||
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> {
|
||||
let mut result = InsDiffResult::default();
|
||||
if let (Some(left_ins), Some(right_ins)) = (&left.ins, &right.ins) {
|
||||
if left_ins.args.len() != right_ins.args.len()
|
||||
|| left_ins.op != right_ins.op
|
||||
// Check if any PlainText segments differ (punctuation and spacing)
|
||||
// This indicates a more significant difference than a simple arg mismatch
|
||||
|| !left_ins.args.iter().zip(&right_ins.args).all(|(a, b)| match (a, b) {
|
||||
(ObjInsArg::PlainText(l), ObjInsArg::PlainText(r)) => l == r,
|
||||
_ => true,
|
||||
})
|
||||
{
|
||||
// Count only non-PlainText args
|
||||
let left_args_count = left_ins.iter_args().count();
|
||||
let right_args_count = right_ins.iter_args().count();
|
||||
if left_args_count != right_args_count || left_ins.op != right_ins.op {
|
||||
// Totally different op
|
||||
result.kind = ObjInsDiffKind::Replace;
|
||||
state.diff_count += 1;
|
||||
@@ -312,7 +313,7 @@ fn compare_ins(
|
||||
result.kind = ObjInsDiffKind::OpMismatch;
|
||||
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) {
|
||||
result.left_args_diff.push(None);
|
||||
result.right_args_diff.push(None);
|
||||
@@ -324,8 +325,11 @@ fn compare_ins(
|
||||
let a_str = match a {
|
||||
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||
ObjInsArg::Reloc => String::new(),
|
||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
||||
ObjInsArg::Reloc => left_ins
|
||||
.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) {
|
||||
ObjInsArgDiff { idx: *idx }
|
||||
@@ -338,8 +342,11 @@ fn compare_ins(
|
||||
let b_str = match b {
|
||||
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||
ObjInsArg::Reloc => String::new(),
|
||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
||||
ObjInsArg::Reloc => right_ins
|
||||
.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) {
|
||||
ObjInsArgDiff { idx: *idx }
|
||||
|
||||
@@ -22,7 +22,7 @@ pub enum DiffText<'a> {
|
||||
/// Branch destination
|
||||
BranchDest(u64, Option<&'a ObjInsArgDiff>),
|
||||
/// Symbol name
|
||||
Symbol(&'a ObjSymbol),
|
||||
Symbol(&'a ObjSymbol, Option<&'a ObjInsArgDiff>),
|
||||
/// Number of spaces
|
||||
Spacing(usize),
|
||||
/// End of line
|
||||
@@ -58,20 +58,23 @@ pub fn display_diff<E>(
|
||||
cb(DiffText::Spacing(4))?;
|
||||
}
|
||||
cb(DiffText::Opcode(&ins.mnemonic, ins.op))?;
|
||||
let mut arg_diff_idx = 0; // non-PlainText index
|
||||
for (i, arg) in ins.args.iter().enumerate() {
|
||||
if i == 0 {
|
||||
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 {
|
||||
ObjInsArg::PlainText(s) => {
|
||||
cb(DiffText::Basic(s))?;
|
||||
}
|
||||
ObjInsArg::Arg(v) => {
|
||||
cb(DiffText::Argument(v, diff))?;
|
||||
arg_diff_idx += 1;
|
||||
}
|
||||
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) => {
|
||||
if let Some(dest) = dest.checked_sub(base_addr) {
|
||||
@@ -79,6 +82,7 @@ pub fn display_diff<E>(
|
||||
} else {
|
||||
cb(DiffText::Basic("<unknown>"))?;
|
||||
}
|
||||
arg_diff_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,8 +96,9 @@ pub fn display_diff<E>(
|
||||
fn display_reloc_name<E>(
|
||||
reloc: &ObjReloc,
|
||||
mut cb: impl FnMut(DiffText) -> Result<(), E>,
|
||||
diff: Option<&ObjInsArgDiff>,
|
||||
) -> Result<(), E> {
|
||||
cb(DiffText::Symbol(&reloc.target))?;
|
||||
cb(DiffText::Symbol(&reloc.target, diff))?;
|
||||
match reloc.addend.cmp(&0i64) {
|
||||
Ordering::Greater => 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) {
|
||||
(HighlightKind::Opcode(a), DiffText::Opcode(_, b)) => a == 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, _)) => {
|
||||
a == b
|
||||
}
|
||||
@@ -124,7 +129,7 @@ impl From<DiffText<'_>> for HighlightKind {
|
||||
match value {
|
||||
DiffText::Opcode(_, op) => HighlightKind::Opcode(op),
|
||||
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),
|
||||
_ => HighlightKind::None,
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
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;
|
||||
@@ -29,8 +29,8 @@ pub mod display;
|
||||
serde::Serialize,
|
||||
strum::VariantArray,
|
||||
strum::EnumMessage,
|
||||
tsify_next::Tsify,
|
||||
)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
pub enum X86Formatter {
|
||||
#[default]
|
||||
#[strum(message = "Intel (default)")]
|
||||
@@ -54,8 +54,8 @@ pub enum X86Formatter {
|
||||
serde::Serialize,
|
||||
strum::VariantArray,
|
||||
strum::EnumMessage,
|
||||
tsify_next::Tsify,
|
||||
)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
pub enum MipsAbi {
|
||||
#[default]
|
||||
#[strum(message = "Auto (default)")]
|
||||
@@ -79,8 +79,8 @@ pub enum MipsAbi {
|
||||
serde::Serialize,
|
||||
strum::VariantArray,
|
||||
strum::EnumMessage,
|
||||
tsify_next::Tsify,
|
||||
)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
pub enum MipsInstrCategory {
|
||||
#[default]
|
||||
#[strum(message = "Auto (default)")]
|
||||
@@ -108,8 +108,8 @@ pub enum MipsInstrCategory {
|
||||
serde::Serialize,
|
||||
strum::VariantArray,
|
||||
strum::EnumMessage,
|
||||
tsify_next::Tsify,
|
||||
)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
pub enum ArmArchVersion {
|
||||
#[default]
|
||||
#[strum(message = "Auto (default)")]
|
||||
@@ -133,8 +133,8 @@ pub enum ArmArchVersion {
|
||||
serde::Serialize,
|
||||
strum::VariantArray,
|
||||
strum::EnumMessage,
|
||||
tsify_next::Tsify,
|
||||
)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
pub enum ArmR9Usage {
|
||||
#[default]
|
||||
#[strum(
|
||||
@@ -154,8 +154,9 @@ pub enum ArmR9Usage {
|
||||
#[inline]
|
||||
const fn default_true() -> bool { true }
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, tsify_next::Tsify)]
|
||||
#[tsify(from_wasm_abi)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
|
||||
#[cfg_attr(feature = "wasm", tsify(from_wasm_abi))]
|
||||
#[serde(default)]
|
||||
pub struct DiffObjConfig {
|
||||
pub relax_reloc_diffs: bool,
|
||||
@@ -244,7 +245,7 @@ pub struct ObjInsDiff {
|
||||
pub branch_from: Option<ObjInsBranchFrom>,
|
||||
/// Branches to instruction
|
||||
pub branch_to: Option<ObjInsBranchTo>,
|
||||
/// Arg diffs
|
||||
/// Arg diffs (only contains non-PlainText args)
|
||||
pub arg_diff: Vec<Option<ObjInsArgDiff>>,
|
||||
}
|
||||
|
||||
@@ -339,7 +340,7 @@ impl ObjDiff {
|
||||
}
|
||||
for (symbol_idx, _) in obj.common.iter().enumerate() {
|
||||
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,
|
||||
instructions: vec![],
|
||||
match_percent: None,
|
||||
@@ -360,7 +361,7 @@ impl ObjDiff {
|
||||
|
||||
#[inline]
|
||||
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]
|
||||
} else {
|
||||
&self.section_diff(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
||||
@@ -369,7 +370,7 @@ impl ObjDiff {
|
||||
|
||||
#[inline]
|
||||
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]
|
||||
} else {
|
||||
&mut self.section_diff_mut(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx]
|
||||
@@ -576,7 +577,7 @@ fn generate_mapping_symbols(
|
||||
let Some(base_symbol_ref) = symbol_ref_by_name(base_obj, base_name) else {
|
||||
return Ok(());
|
||||
};
|
||||
let (base_section, base_symbol) = base_obj.section_symbol(base_symbol_ref);
|
||||
let (base_section, _base_symbol) = base_obj.section_symbol(base_symbol_ref);
|
||||
let Some(base_section) = base_section else {
|
||||
return Ok(());
|
||||
};
|
||||
@@ -587,9 +588,7 @@ fn generate_mapping_symbols(
|
||||
for (target_section_index, target_section) in
|
||||
target_obj.sections.iter().enumerate().filter(|(_, s)| s.kind == base_section.kind)
|
||||
{
|
||||
for (target_symbol_index, _target_symbol) in
|
||||
target_section.symbols.iter().enumerate().filter(|(_, s)| s.kind == base_symbol.kind)
|
||||
{
|
||||
for (target_symbol_index, _target_symbol) in target_section.symbols.iter().enumerate() {
|
||||
let target_symbol_ref =
|
||||
SymbolRef { section_idx: target_section_index, symbol_idx: target_symbol_index };
|
||||
match base_section.kind {
|
||||
@@ -757,7 +756,7 @@ fn matching_symbols(
|
||||
}
|
||||
}
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
@@ -789,7 +788,7 @@ fn matching_symbols(
|
||||
}
|
||||
}
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
@@ -882,7 +881,7 @@ fn find_common_symbol(obj: Option<&ObjInfo>, in_symbol: &ObjSymbol) -> Option<Sy
|
||||
let obj = obj?;
|
||||
for (symbol_idx, symbol) in obj.common.iter().enumerate() {
|
||||
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
|
||||
|
||||
@@ -8,4 +8,5 @@ pub mod config;
|
||||
pub mod diff;
|
||||
#[cfg(feature = "any-arch")]
|
||||
pub mod obj;
|
||||
#[cfg(feature = "any-arch")]
|
||||
pub mod util;
|
||||
|
||||
@@ -85,6 +85,9 @@ pub enum ObjInsArg {
|
||||
}
|
||||
|
||||
impl ObjInsArg {
|
||||
#[inline]
|
||||
pub fn is_plain_text(&self) -> bool { matches!(self, ObjInsArg::PlainText(_)) }
|
||||
|
||||
pub fn loose_eq(&self, other: &ObjInsArg) -> bool {
|
||||
match (self, other) {
|
||||
(ObjInsArg::Arg(a), ObjInsArg::Arg(b)) => a.loose_eq(b),
|
||||
@@ -100,7 +103,7 @@ pub struct ObjIns {
|
||||
pub address: u64,
|
||||
pub size: u8,
|
||||
pub op: u16,
|
||||
pub mnemonic: String,
|
||||
pub mnemonic: Cow<'static, str>,
|
||||
pub args: Vec<ObjInsArg>,
|
||||
pub reloc: Option<ObjReloc>,
|
||||
pub branch_dest: Option<u64>,
|
||||
@@ -112,6 +115,14 @@ pub struct ObjIns {
|
||||
pub orig: Option<String>,
|
||||
}
|
||||
|
||||
impl ObjIns {
|
||||
/// Iterate over non-PlainText arguments.
|
||||
#[inline]
|
||||
pub fn iter_args(&self) -> impl DoubleEndedIterator<Item = &ObjInsArg> {
|
||||
self.args.iter().filter(|a| !a.is_plain_text())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
|
||||
pub enum ObjSymbolKind {
|
||||
#[default]
|
||||
@@ -164,9 +175,11 @@ pub struct SymbolRef {
|
||||
pub symbol_idx: usize,
|
||||
}
|
||||
|
||||
pub const SECTION_COMMON: usize = usize::MAX - 1;
|
||||
|
||||
impl ObjInfo {
|
||||
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];
|
||||
return (None, symbol);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ fn to_obj_symbol(
|
||||
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
|
||||
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
|
||||
}
|
||||
#[cfg(feature = "ppc")]
|
||||
if arch
|
||||
.ppc()
|
||||
.and_then(|a| a.extab.as_ref())
|
||||
@@ -334,6 +335,10 @@ fn relocations_by_section(
|
||||
};
|
||||
symbol
|
||||
}
|
||||
RelocationTarget::Absolute => {
|
||||
log::warn!("Ignoring absolute relocation @ {}:{:#x}", section.name, address);
|
||||
continue;
|
||||
}
|
||||
_ => bail!("Unhandled relocation target: {:?}", reloc.target()),
|
||||
};
|
||||
let flags = reloc.flags(); // TODO validate reloc here?
|
||||
@@ -431,9 +436,9 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection], obj_data: &[u8])
|
||||
let mut text_sections =
|
||||
obj_file.sections().filter(|s| s.kind() == SectionKind::Text);
|
||||
let section_index = text_sections.next().map(|s| s.index().0);
|
||||
let mut lines = section_index.map(|index| {
|
||||
&mut sections.iter_mut().find(|s| s.orig_index == index).unwrap().line_info
|
||||
});
|
||||
let mut lines = section_index
|
||||
.and_then(|index| sections.iter_mut().find(|s| s.orig_index == index))
|
||||
.map(|s| &mut s.line_info);
|
||||
|
||||
let mut rows = program.rows();
|
||||
while let Some((_header, row)) = rows.next_row()? {
|
||||
@@ -444,13 +449,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
|
||||
// advance to the next .text section.
|
||||
let section_index = text_sections.next().map(|s| s.index().0);
|
||||
lines = section_index.map(|index| {
|
||||
&mut sections
|
||||
.iter_mut()
|
||||
.find(|s| s.orig_index == index)
|
||||
.unwrap()
|
||||
.line_info
|
||||
});
|
||||
lines = section_index
|
||||
.and_then(|index| sections.iter_mut().find(|s| s.orig_index == index))
|
||||
.map(|s| &mut s.line_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ impl ScratchConfigV1 {
|
||||
c_flags: self.c_flags,
|
||||
ctx_path: self.ctx_path,
|
||||
build_ctx: self.build_ctx.then_some(true),
|
||||
preset_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,21 @@ pub enum ProjectObjectNode {
|
||||
Dir(String, Vec<ProjectObjectNode>),
|
||||
}
|
||||
|
||||
fn join_single_dir_entries(nodes: &mut Vec<ProjectObjectNode>) {
|
||||
for node in nodes {
|
||||
if let ProjectObjectNode::Dir(my_name, my_nodes) = node {
|
||||
join_single_dir_entries(my_nodes);
|
||||
// If this directory consists of a single sub-directory...
|
||||
if let [ProjectObjectNode::Dir(sub_name, sub_nodes)] = &mut my_nodes[..] {
|
||||
// ... join the two names with a path separator and eliminate the layer
|
||||
*my_name += "/";
|
||||
*my_name += sub_name;
|
||||
*my_nodes = std::mem::take(sub_nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_dir<'a>(
|
||||
name: &str,
|
||||
nodes: &'a mut Vec<ProjectObjectNode>,
|
||||
@@ -60,6 +75,14 @@ fn build_nodes(
|
||||
let filename = path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
out_nodes.push(ProjectObjectNode::Unit(filename, idx));
|
||||
}
|
||||
// Within the top-level module directories, join paths. Leave the
|
||||
// top-level name intact though since it's the module name.
|
||||
for node in &mut nodes {
|
||||
if let ProjectObjectNode::Dir(_, sub_nodes) = node {
|
||||
join_single_dir_entries(sub_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
nodes
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct CreateScratchConfig {
|
||||
pub compiler_flags: String,
|
||||
pub function_name: String,
|
||||
pub target_obj: PathBuf,
|
||||
pub preset_id: Option<u32>,
|
||||
}
|
||||
|
||||
impl CreateScratchConfig {
|
||||
@@ -45,6 +46,7 @@ impl CreateScratchConfig {
|
||||
compiler_flags: scratch_config.c_flags.clone().unwrap_or_default(),
|
||||
function_name,
|
||||
target_obj: target_path.to_path_buf(),
|
||||
preset_id: scratch_config.preset_id,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -101,15 +103,18 @@ fn run_create_scratch(
|
||||
let obj_path = project_dir.join(&config.target_obj);
|
||||
let file = reqwest::blocking::multipart::Part::file(&obj_path)
|
||||
.with_context(|| format!("Failed to open {}", obj_path.display()))?;
|
||||
let form = reqwest::blocking::multipart::Form::new()
|
||||
let mut form = reqwest::blocking::multipart::Form::new()
|
||||
.text("compiler", config.compiler.clone())
|
||||
.text("platform", config.platform.clone())
|
||||
.text("compiler_flags", config.compiler_flags.clone())
|
||||
.text("diff_label", config.function_name.clone())
|
||||
.text("diff_flags", diff_flags)
|
||||
.text("context", context.unwrap_or_default())
|
||||
.text("source_code", "// Move related code from Context tab to here")
|
||||
.part("target_obj", file);
|
||||
.text("source_code", "// Move related code from Context tab to here");
|
||||
if let Some(preset) = config.preset_id {
|
||||
form = form.text("preset", preset.to_string());
|
||||
}
|
||||
form = form.part("target_obj", file);
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let response = client
|
||||
.post(formatcp!("{API_HOST}/api/scratch"))
|
||||
|
||||
@@ -205,7 +205,7 @@ pub const DEFAULT_COLOR_ROTATION: [Color32; 9] = [
|
||||
Color32::from_rgb(255, 0, 0),
|
||||
Color32::from_rgb(255, 255, 0),
|
||||
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(213, 138, 138),
|
||||
];
|
||||
|
||||
@@ -292,10 +292,14 @@ fn diff_text_ui(
|
||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||
}
|
||||
}
|
||||
DiffText::Symbol(sym) => {
|
||||
DiffText::Symbol(sym, diff) => {
|
||||
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
|
||||
label_text = name.clone();
|
||||
base_color = appearance.emphasized_text_color;
|
||||
if let Some(diff) = diff {
|
||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||
} else {
|
||||
base_color = appearance.emphasized_text_color;
|
||||
}
|
||||
}
|
||||
DiffText::Spacing(n) => {
|
||||
ui.add_space(n as f32 * space_width);
|
||||
|
||||
@@ -7,7 +7,9 @@ use egui::{
|
||||
use objdiff_core::{
|
||||
arch::ObjArch,
|
||||
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};
|
||||
|
||||
@@ -651,11 +653,11 @@ pub fn symbol_list_ui(
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
// 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| {
|
||||
for (symbol_ref, symbol_diff) in mapping
|
||||
.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;
|
||||
if let Some(result) = symbol_ui(
|
||||
|
||||
Reference in New Issue
Block a user