Compare commits

...

45 Commits

Author SHA1 Message Date
Luke Street 0899e6779c Add alt shortcut support to many elements 2024-12-01 22:36:15 -07:00
LagoLunatic 95528fa8d2 Found a better place to clear the autoscroll flag
DiffViewState::post_update is where the flag gets set, so clearing it right before that at the start of the function seems to make the most sense, instead of doing it in App::update.
2024-12-01 22:36:15 -07:00
LagoLunatic 517b84e766 Simplify clearing of the autoscroll flag, remove &mut State 2024-12-01 22:36:15 -07:00
LagoLunatic 45dd73f5a9 Fix auto-scrolling to highlighted symbol only working for the left side
The flag is cleared after one scroll to avoid doing it continuously, but this breaks when we need to scroll to both the left and the right symbol at the same time. So now each side has its own flag to keep track of this state independently.
2024-12-01 22:36:15 -07:00
LagoLunatic d7d7a7f14a Add escape as an alternative to back hotkey 2024-12-01 22:36:15 -07:00
LagoLunatic 441b30070e Split function diff view: Enable PageUp/PageDown/Home/End for scrolling 2024-12-01 22:36:15 -07:00
LagoLunatic 28bd7182d1 Add hotkeys to change target and base functions 2024-12-01 22:36:13 -07:00
LagoLunatic 3f03a75825 Add space as alternative to enter hotkey
This is for consistency with egui's builtint enter/space hotkey for interacting with the focused widget.
2024-12-01 22:36:05 -07:00
LagoLunatic 4fb64a3ad4 Add Ctrl+F/S shortcuts for focusing the object and symbol filter text edits 2024-12-01 22:36:05 -07:00
LagoLunatic 77c104c67b Fix some hotkeys stealing input from focused widgets
e.g. The symbol list was stealing the W/S key presses when typing into the symbol filter text edit.

If the user actually wants to use these shortcuts while a widget is focused, they can simply press the escape key to unfocus all widgets and then press the shortcut.
2024-12-01 22:36:05 -07:00
LagoLunatic 046f3d6999 Auto-scroll the keyboard-selected symbols into view if offscreen 2024-12-01 22:36:05 -07:00
LagoLunatic 2427b06584 Do not clear highlighted symbol when hovering mouse over an unpaired symbol 2024-12-01 22:36:05 -07:00
LagoLunatic 157e99de6f Do not clear highlighted symbol when backing out of diff view 2024-12-01 22:36:05 -07:00
LagoLunatic b571787732 Add hotkeys to select the next symbol above/below the current one in the listing 2024-12-01 22:36:05 -07:00
LagoLunatic dbf86ec3cf Add scroll hotkeys 2024-12-01 22:36:05 -07:00
LagoLunatic acc1189150 Add enter and back hotkeys 2024-12-01 22:36:05 -07:00
LagoLunatic 123253c322 Update .gitignore 2024-12-01 22:36:05 -07:00
LagoLunatic ef680a5e7d Fix missing dependency feature for objdiff-gui 2024-12-01 22:36:05 -07:00
Luke Street 7aa878b48e Update all dependencies & clippy fixes 2024-12-01 22:22:35 -07:00
Luke Street a119d9a6dd Add scratch preset_id field for decomp.me
Resolves #133
2024-11-07 09:27:13 -07:00
robojumper ebf653816a Combine nested otherwise empty directories in objects view (#137) 2024-11-07 08:21:39 -07:00
Luke Street 424434edd6 Experimental ARM64 support
Based on yaxpeax-arm, but with a heavy dose of
custom code to work around its limitations.

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

* Add missing deps to every feature

* Add missing `dep:`s

* Gate even more deps behind features

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

* Fix wasm

---------

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

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

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

* Don't attempt to interpret wrongly sized data

* Reference data display improvment issue

* Log failure to display a symbol's value
2024-10-14 22:03:30 -06:00
Luke Street 72ea1c8911 ci: Use rust-lld on Windows 2024-10-12 18:57:49 -06:00
Luke Street d4a540857d ci: Add Rust workspace cache 2024-10-12 18:41:42 -06:00
Luke Street 676488433f Fix resolving symbols for section-relative relocations
Also fixes MIPS `j` handling when jumping within the function.

Reworks `ObjReloc` struct to be a little more sensible.
2024-10-11 18:09:18 -06:00
Luke Street 83de98b5ee Version v2.3.1 2024-10-10 22:58:33 -06:00
Luke Street c1ba4e91d1 ci: Setup python venv for cargo-zigbuild 2024-10-10 22:39:31 -06:00
Luke Street 575900024d Avoid resetting diff state on unit config reload 2024-10-10 22:31:04 -06:00
Luke Street cbe299e859 Fix logic issue with 0-sized symbols
Fixes #119
2024-10-10 22:20:48 -06:00
Luke Street 741d93e211 Add symbol mapping feature (#118)
This allows users to "map" (or "link") symbols with different names so that they can be compared without having to update either the target or base objects. Symbol mappings are persisted in objdiff.json, so generators will need to ensure that they're preserved when updating. (Example: https://github.com/encounter/dtk-template/commit/d1334bb79e71af1a7b3b090bffda4adc483f722c)

Resolves #117
2024-10-09 21:44:18 -06:00
Luke Street 603dbd6882 Round match percent down before display
Ensures that 100% isn't displayed until it's a
perfect match.
2024-10-07 20:17:56 -06:00
Luke Street 6fb0a63de2 Click on empty space in row to clear highlight
Resolves #116
2024-10-07 19:53:16 -06:00
Luke Street ab2e84a2c6 Deprioritize generated GCC symbols in find_section_symbol
Resolves #115
2024-10-07 19:49:52 -06:00
Luke Street 9596051cb4 Allow collapsing sidebar in symbols view 2024-10-07 19:46:16 -06:00
48 changed files with 6764 additions and 1651 deletions
+5
View File
@@ -0,0 +1,5 @@
[target.x86_64-pc-windows-msvc]
linker = "rust-lld"
[target.aarch64-pc-windows-msvc]
linker = "rust-lld"
+17 -1
View File
@@ -30,6 +30,8 @@ jobs:
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
components: clippy components: clippy
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
- name: Cargo check - name: Cargo check
run: cargo check --all-features --all-targets run: cargo check --all-features --all-targets
- name: Cargo clippy - name: Cargo clippy
@@ -85,6 +87,8 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Rust toolchain - name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
- name: Cargo test - name: Cargo test
run: cargo test --release --all-features run: cargo test --release --all-features
@@ -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 }}
+1 -5
View File
@@ -3,10 +3,6 @@ target/
**/*.rs.bk **/*.rs.bk
generated/ generated/
# cargo-mobile
.cargo/
/gen
# macOS # macOS
.DS_Store .DS_Store
@@ -22,4 +18,4 @@ android.keystore
*.frag *.frag
*.vert *.vert
*.metal *.metal
.vscode/launch.json .vscode/
Generated
+782 -419
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -13,7 +13,7 @@ strip = "debuginfo"
codegen-units = 1 codegen-units = 1
[workspace.package] [workspace.package]
version = "2.2.2" version = "2.4.0"
authors = ["Luke Street <luke@street.dev>"] authors = ["Luke Street <luke@street.dev>"]
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
+1
View File
@@ -20,6 +20,7 @@ Supports:
- MIPS (N64, PS1, PS2, PSP) - MIPS (N64, PS1, PS2, PSP)
- x86 (COFF only at the moment) - x86 (COFF only at the moment)
- ARM (GBA, DS, 3DS) - ARM (GBA, DS, 3DS)
- ARM64 (Switch, experimental)
See [Usage](#usage) for more information. See [Usage](#usage) for more information.
+7
View File
@@ -133,6 +133,13 @@
}, },
"metadata": { "metadata": {
"ref": "#/$defs/metadata" "ref": "#/$defs/metadata"
},
"symbol_mappings": {
"type": "object",
"description": "Manual symbol mappings from target to base.",
"additionalProperties": {
"type": "string"
}
} }
} }
}, },
+3 -3
View File
@@ -70,10 +70,10 @@ 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" },
{ id = "RUSTSEC-2024-0384", reason = "Unmaintained indirect dependency" },
] ]
# If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library. # If this is false, then it uses a built-in git library.
@@ -98,7 +98,7 @@ allow = [
"BSL-1.0", "BSL-1.0",
"CC0-1.0", "CC0-1.0",
"MPL-2.0", "MPL-2.0",
"Unicode-DFS-2016", "Unicode-3.0",
"Zlib", "Zlib",
"0BSD", "0BSD",
"OFL-1.1", "OFL-1.1",
@@ -240,7 +240,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
+1 -1
View File
@@ -20,7 +20,7 @@ enable-ansi-support = "0.2"
memmap2 = "0.9" memmap2 = "0.9"
objdiff-core = { path = "../objdiff-core", features = ["all"] } objdiff-core = { path = "../objdiff-core", features = ["all"] }
prost = "0.13" prost = "0.13"
ratatui = "0.28" ratatui = "0.29"
rayon = "1.10" rayon = "1.10"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
+39 -23
View File
@@ -102,26 +102,32 @@ pub fn run(args: Args) -> Result<()> {
let unit_path = let unit_path =
PathBuf::from_str(u).ok().and_then(|p| fs::canonicalize(p).ok()); PathBuf::from_str(u).ok().and_then(|p| fs::canonicalize(p).ok());
let Some(object) = project_config.objects.iter_mut().find_map(|obj| { let Some(object) = project_config
if obj.name.as_deref() == Some(u) { .units
.as_deref_mut()
.unwrap_or_default()
.iter_mut()
.find_map(|obj| {
if obj.name.as_deref() == Some(u) {
resolve_paths(obj);
return Some(obj);
}
let up = unit_path.as_deref()?;
resolve_paths(obj); resolve_paths(obj);
return Some(obj);
}
let up = unit_path.as_deref()?; if [&obj.base_path, &obj.target_path]
.into_iter()
.filter_map(|p| p.as_ref().and_then(|p| p.canonicalize().ok()))
.any(|p| p == up)
{
return Some(obj);
}
resolve_paths(obj); None
})
if [&obj.base_path, &obj.target_path] else {
.into_iter()
.filter_map(|p| p.as_ref().and_then(|p| p.canonicalize().ok()))
.any(|p| p == up)
{
return Some(obj);
}
None
}) else {
bail!("Unit not found: {}", u) bail!("Unit not found: {}", u)
}; };
@@ -129,7 +135,13 @@ pub fn run(args: Args) -> Result<()> {
} else if let Some(symbol_name) = &args.symbol { } else if let Some(symbol_name) = &args.symbol {
let mut idx = None; let mut idx = None;
let mut count = 0usize; let mut count = 0usize;
for (i, obj) in project_config.objects.iter_mut().enumerate() { for (i, obj) in project_config
.units
.as_deref_mut()
.unwrap_or_default()
.iter_mut()
.enumerate()
{
resolve_paths(obj); resolve_paths(obj);
if obj if obj
@@ -148,7 +160,7 @@ pub fn run(args: Args) -> Result<()> {
} }
match (count, idx) { match (count, idx) {
(0, None) => bail!("Symbol not found: {}", symbol_name), (0, None) => bail!("Symbol not found: {}", symbol_name),
(1, Some(i)) => &mut project_config.objects[i], (1, Some(i)) => &mut project_config.units_mut()[i],
(2.., Some(_)) => bail!( (2.., Some(_)) => bail!(
"Multiple instances of {} were found, try specifying a unit", "Multiple instances of {} were found, try specifying a unit",
symbol_name symbol_name
@@ -303,7 +315,7 @@ fn find_function(obj: &ObjInfo, name: &str) -> Option<SymbolRef> {
None None
} }
#[allow(dead_code)] #[expect(dead_code)]
struct FunctionDiffUi { struct FunctionDiffUi {
relax_reloc_diffs: bool, relax_reloc_diffs: bool,
left_highlight: HighlightKind, left_highlight: HighlightKind,
@@ -758,7 +770,7 @@ impl FunctionDiffUi {
self.scroll_y += self.per_page / if half { 2 } else { 1 }; self.scroll_y += self.per_page / if half { 2 } else { 1 };
} }
#[allow(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn print_sym( fn print_sym(
&self, &self,
out: &mut Text<'static>, out: &mut Text<'static>,
@@ -832,10 +844,14 @@ impl FunctionDiffUi {
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()] base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
} }
} }
DiffText::Symbol(sym) => { DiffText::Symbol(sym, diff) => {
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name); let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
label_text = name.clone(); label_text = name.clone();
base_color = Color::White; if let Some(diff) = diff {
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
} else {
base_color = Color::White;
}
} }
DiffText::Spacing(n) => { DiffText::Spacing(n) => {
line.spans.push(Span::raw(" ".repeat(n))); line.spans.push(Span::raw(" ".repeat(n)));
+6 -4
View File
@@ -94,7 +94,7 @@ fn generate(args: GenerateArgs) -> Result<()> {
}; };
info!( info!(
"Generating report for {} units (using {} threads)", "Generating report for {} units (using {} threads)",
project.objects.len(), project.units().len(),
if args.deduplicate { 1 } else { rayon::current_num_threads() } if args.deduplicate { 1 } else { rayon::current_num_threads() }
); );
@@ -103,7 +103,7 @@ fn generate(args: GenerateArgs) -> Result<()> {
let mut existing_functions: HashSet<String> = HashSet::new(); let mut existing_functions: HashSet<String> = HashSet::new();
if args.deduplicate { if args.deduplicate {
// If deduplicating, we need to run single-threaded // If deduplicating, we need to run single-threaded
for object in &mut project.objects { for object in project.units.as_deref_mut().unwrap_or_default() {
if let Some(unit) = report_object( if let Some(unit) = report_object(
object, object,
project_dir, project_dir,
@@ -116,7 +116,9 @@ fn generate(args: GenerateArgs) -> Result<()> {
} }
} else { } else {
let vec = project let vec = project
.objects .units
.as_deref_mut()
.unwrap_or_default()
.par_iter_mut() .par_iter_mut()
.map(|object| { .map(|object| {
report_object( report_object(
@@ -132,7 +134,7 @@ fn generate(args: GenerateArgs) -> Result<()> {
} }
let measures = units.iter().flat_map(|u| u.measures.into_iter()).collect(); let measures = units.iter().flat_map(|u| u.measures.into_iter()).collect();
let mut categories = Vec::new(); let mut categories = Vec::new();
for category in &project.progress_categories { for category in project.progress_categories() {
categories.push(ReportCategory { categories.push(ReportCategory {
id: category.id.clone(), id: category.id.clone(),
name: category.name.clone(), name: category.name.clone(),
+29 -23
View File
@@ -16,36 +16,38 @@ documentation = "https://docs.rs/objdiff-core"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[features] [features]
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "bindings"] all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "arm64", "bindings"]
any-arch = [] # 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 = ["globset", "semver", "serde_json", "serde_yaml"] config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
dwarf = ["gimli"] dwarf = ["dep:gimli"]
mips = ["any-arch", "rabbitizer"] mips = ["any-arch", "dep:rabbitizer"]
ppc = ["any-arch", "cwdemangle", "cwextab", "ppc750cl"] ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"] x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
arm = ["any-arch", "cpp_demangle", "unarm", "arm-attr"] arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
bindings = ["serde_json", "prost", "pbjson"] arm64 = ["any-arch", "dep:cpp_demangle", "dep:yaxpeax-arch", "dep:yaxpeax-arm"]
wasm = ["bindings", "console_error_panic_hook", "console_log"] bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["all"] features = ["all"]
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
byteorder = "1.5" bimap = { version = "0.6", features = ["serde"], optional = true }
filetime = "0.2" byteorder = { version = "1.5", optional = true }
flagset = "0.4" filetime = { version = "0.2", optional = true }
log = "0.4" flagset = { version = "0.4", optional = true }
memmap2 = "0.9" log = { version = "0.4", optional = true }
num-traits = "0.2" 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 } 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 }
@@ -75,6 +77,10 @@ msvc-demangler = { version = "0.10", optional = true }
unarm = { version = "1.6", optional = true } unarm = { version = "1.6", optional = true }
arm-attr = { version = "0.1", optional = true } arm-attr = { version = "0.1", optional = true }
# arm64
yaxpeax-arch = { version = "0.3", default-features = false, features = ["std"], optional = true }
yaxpeax-arm = { version = "0.3", default-features = false, features = ["std"], optional = true }
[build-dependencies] [build-dependencies]
prost-build = "0.13" prost-build = { version = "0.13", optional = true }
pbjson-build = "0.7" pbjson-build = { version = "0.7", optional = true }
+1
View File
@@ -11,4 +11,5 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl). - **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86). - **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm). - **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
- **`bindings`**: Enables serialization and deserialization of objdiff data structures. - **`bindings`**: Enables serialization and deserialization of objdiff data structures.
+7 -2
View File
@@ -1,6 +1,11 @@
use std::path::{Path, PathBuf};
fn main() { fn main() {
#[cfg(feature = "bindings")]
compile_protos();
}
#[cfg(feature = "bindings")]
fn compile_protos() {
use std::path::{Path, PathBuf};
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos"); let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos");
let descriptor_path = root.join("proto_descriptor.bin"); let descriptor_path = root.join("proto_descriptor.bin");
println!("cargo:rerun-if-changed={}", descriptor_path.display()); println!("cargo:rerun-if-changed={}", descriptor_path.display());
+5 -7
View File
@@ -124,11 +124,9 @@ impl ObjArch for ObjArchArm {
.get(&SectionIndex(section_index)) .get(&SectionIndex(section_index))
.map(|x| x.as_slice()) .map(|x| x.as_slice())
.unwrap_or(&fallback_mappings); .unwrap_or(&fallback_mappings);
let first_mapping_idx = let first_mapping_idx = mapping_symbols
match mapping_symbols.binary_search_by_key(&start_addr, |x| x.address) { .binary_search_by_key(&start_addr, |x| x.address)
Ok(idx) => idx, .unwrap_or_else(|idx| idx - 1);
Err(idx) => idx - 1,
};
let first_mapping = mapping_symbols[first_mapping_idx].mapping; let first_mapping = mapping_symbols[first_mapping_idx].mapping;
let mut mappings_iter = let mut mappings_iter =
@@ -215,7 +213,7 @@ impl ObjArch for ObjArchArm {
address: address as u64, address: address as u64,
size: (parser.address - address) as u8, size: (parser.address - address) as u8,
op: ins.opcode_id(), op: ins.opcode_id(),
mnemonic: parsed_ins.mnemonic.to_string(), mnemonic: Cow::Borrowed(parsed_ins.mnemonic),
args, args,
reloc, reloc,
branch_dest, branch_dest,
@@ -234,7 +232,7 @@ impl ObjArch for ObjArchArm {
section: &ObjSection, section: &ObjSection,
address: u64, address: u64,
reloc: &Relocation, reloc: &Relocation,
) -> anyhow::Result<i64> { ) -> Result<i64> {
let address = address as usize; let address = address as usize;
Ok(match reloc.flags() { Ok(match reloc.flags() {
// ARM calls // ARM calls
File diff suppressed because it is too large Load Diff
+14 -7
View File
@@ -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,
@@ -119,7 +119,7 @@ impl ObjArch for ObjArchMips {
let op = instruction.unique_id as u16; let op = instruction.unique_id as u16;
ops.push(op); ops.push(op);
let mnemonic = instruction.opcode_name().to_string(); let mnemonic = instruction.opcode_name();
let is_branch = instruction.is_branch(); let is_branch = instruction.is_branch();
let branch_offset = instruction.branch_offset(); let branch_offset = instruction.branch_offset();
let mut branch_dest = if is_branch { let mut branch_dest = if is_branch {
@@ -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;
@@ -195,7 +202,7 @@ impl ObjArch for ObjArchMips {
address: cur_addr as u64, address: cur_addr as u64,
size: 4, size: 4,
op, op,
mnemonic, mnemonic: Cow::Borrowed(mnemonic),
args, args,
reloc: reloc.cloned(), reloc: reloc.cloned(),
branch_dest, branch_dest,
+9 -1
View File
@@ -12,6 +12,8 @@ use crate::{
#[cfg(feature = "arm")] #[cfg(feature = "arm")]
mod arm; mod arm;
#[cfg(feature = "arm64")]
mod arm64;
#[cfg(feature = "mips")] #[cfg(feature = "mips")]
pub mod mips; pub mod mips;
#[cfg(feature = "ppc")] #[cfg(feature = "ppc")]
@@ -34,7 +36,11 @@ pub enum DataType {
impl DataType { impl DataType {
pub fn display_bytes<Endian: ByteOrder>(&self, bytes: &[u8]) -> Option<String> { pub fn display_bytes<Endian: ByteOrder>(&self, bytes: &[u8]) -> Option<String> {
if self.required_len().is_some_and(|l| bytes.len() < l) { // TODO: Attempt to interpret large symbols as arrays of a smaller type,
// fallback to intrepreting it as bytes.
// https://github.com/encounter/objdiff/issues/124
if self.required_len().is_some_and(|l| bytes.len() != l) {
log::warn!("Failed to display a symbol value for a symbol whose size doesn't match the instruction referencing it.");
return None; return None;
} }
@@ -161,6 +167,8 @@ pub fn new_arch(object: &File) -> Result<Box<dyn ObjArch>> {
Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?), Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?),
#[cfg(feature = "arm")] #[cfg(feature = "arm")]
Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?), Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?),
#[cfg(feature = "arm64")]
Architecture::Aarch64 => Box::new(arm64::ObjArchArm64::new(object)?),
arch => bail!("Unsupported architecture: {arch:?}"), arch => bail!("Unsupported architecture: {arch:?}"),
}) })
} }
+1 -1
View File
@@ -143,7 +143,7 @@ impl ObjArch for ObjArchPpc {
insts.push(ObjIns { insts.push(ObjIns {
address: cur_addr as u64, address: cur_addr as u64,
size: 4, size: 4,
mnemonic: simplified.mnemonic.to_string(), mnemonic: Cow::Borrowed(simplified.mnemonic),
args, args,
reloc: reloc.cloned(), reloc: reloc.cloned(),
op: ins.op as u16, op: ins.op as u16,
+4 -3
View File
@@ -51,7 +51,7 @@ impl ObjArch for ObjArchX86 {
address: 0, address: 0,
size: 0, size: 0,
op: 0, op: 0,
mnemonic: String::new(), mnemonic: Cow::Borrowed("<invalid>"),
args: vec![], args: vec![],
reloc: None, reloc: None,
branch_dest: None, branch_dest: None,
@@ -76,7 +76,7 @@ impl ObjArch for ObjArchX86 {
address, address,
size: instruction.len() as u8, size: instruction.len() as u8,
op, op,
mnemonic: String::new(), mnemonic: Cow::Borrowed("<invalid>"),
args: vec![], args: vec![],
reloc: reloc.cloned(), reloc: reloc.cloned(),
branch_dest: None, branch_dest: None,
@@ -242,7 +242,8 @@ impl FormatterOutput for InstructionFormatterOutput {
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) { fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
self.formatted.push_str(text); self.formatted.push_str(text);
self.ins.mnemonic = text.to_string(); // TODO: can iced-x86 guarantee 'static here?
self.ins.mnemonic = Cow::Owned(text.to_string());
} }
fn write_number( fn write_number(

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