A local diffing tool for decompilation projects
Go to file
LagoLunatic abe68ef2f2
objdiff-gui: Implement keyboard shortcuts (#139)
* Fix missing dependency feature for objdiff-gui

* Update .gitignore

* Add enter and back hotkeys

* Add scroll hotkeys

* Add hotkeys to select the next symbol above/below the current one in the listing

* Do not clear highlighted symbol when backing out of diff view

* Do not clear highlighted symbol when hovering mouse over an unpaired symbol

* Auto-scroll the keyboard-selected symbols into view if offscreen

* 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.

* Add Ctrl+F/S shortcuts for focusing the object and symbol filter text edits

* Add space as alternative to enter hotkey

This is for consistency with egui's builtint enter/space hotkey for interacting with the focused widget.

* Add hotkeys to change target and base functions

* Split function diff view: Enable PageUp/PageDown/Home/End for scrolling

* Add escape as an alternative to back hotkey

* 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.

* Simplify clearing of the autoscroll flag, remove &mut State

* 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-02 21:51:37 -07:00
.cargo ci: Use rust-lld on Windows 2024-10-12 18:57:49 -06:00
.github/workflows ci: Add Rust workspace cache 2024-10-12 18:41:42 -06:00
assets Split into objdiff-core / objdiff-gui; update egui to 0.26.2 2024-02-26 18:48:48 -07:00
objdiff-cli Update all dependencies & clippy fixes 2024-12-01 22:22:35 -07:00
objdiff-core Update all dependencies & clippy fixes 2024-12-01 22:22:35 -07:00
objdiff-gui objdiff-gui: Implement keyboard shortcuts (#139) 2024-12-02 21:51:37 -07:00
objdiff-wasm Version v2.0.0 2024-09-09 20:18:56 -06:00
.gitignore Display decoded rlwinm info to hover tooltip (#141) 2024-12-02 21:40:05 -07:00
Cargo.lock Update all dependencies & clippy fixes 2024-12-01 22:22:35 -07:00
Cargo.toml Experimental ARM64 support 2024-10-31 17:39:12 -06:00
LICENSE-APACHE Version 0.2.0 2022-12-06 17:53:32 -05:00
LICENSE-MIT Version 0.2.0 2022-12-06 17:53:32 -05:00
README.md Experimental ARM64 support 2024-10-31 17:39:12 -06:00
config.schema.json Add symbol mapping feature (#118) 2024-10-09 21:44:18 -06:00
deny.toml Update all dependencies & clippy fixes 2024-12-01 22:22:35 -07:00
rustfmt.toml Initial commit 2022-09-08 17:19:20 -04:00

README.md

objdiff Build Status

A local diffing tool for decompilation projects. Inspired by decomp.me and asm-differ.

Features:

  • Compare entire object files: functions and data.
  • Built-in symbol demangling for C++. (CodeWarrior, Itanium & MSVC)
  • Automatic rebuild on source file changes.
  • Project integration via configuration file.
  • Search and filter all of a project's objects and quickly switch.
  • Click to highlight all instances of values and registers.

Supports:

  • PowerPC 750CL (GameCube, Wii)
  • MIPS (N64, PS1, PS2, PSP)
  • x86 (COFF only at the moment)
  • ARM (GBA, DS, 3DS)
  • ARM64 (Switch, experimental)

See Usage for more information.

Downloads

To build from source, see Building.

GUI

For Linux and macOS, run chmod +x objdiff-* to make the binary executable.

CLI

CLI binaries can be found on the releases page.

Screenshots

Symbol Screenshot Diff Screenshot

Usage

objdiff works by comparing two relocatable object files (.o). The objects are expected to have the same relative path from the "target" and "base" directories.

For example, if the target ("expected") object is located at build/asm/MetroTRK/mslsupp.o and the base ("actual") object is located at build/src/MetroTRK/mslsupp.o, the following configuration would be used:

  • Target build directory: build/asm
  • Base build directory: build/src
  • Object: MetroTRK/mslsupp.o

objdiff will then execute the build system from the project directory to build both objects:

$ make build/asm/MetroTRK/mslsupp.o # Only if "Build target object" is enabled
$ make build/src/MetroTRK/mslsupp.o

The objects will then be compared and the results will be displayed in the UI.

See Configuration for more information.

Configuration

While not required (most settings can be specified in the UI), projects can add an objdiff.json file to configure the tool automatically. The configuration file must be located in the root project directory.

If your project has a generator script (e.g. configure.py), it's recommended to generate the objdiff configuration file as well. You can then add objdiff.json to your .gitignore to prevent it from being committed.

{
  "$schema": "https://raw.githubusercontent.com/encounter/objdiff/main/config.schema.json",
  "custom_make": "ninja",
  "custom_args": [
    "-d",
    "keeprsp"
  ],
  "build_target": false,
  "build_base": true,
  "watch_patterns": [
    "*.c",
    "*.cp",
    "*.cpp",
    "*.cxx",
    "*.h",
    "*.hp",
    "*.hpp",
    "*.hxx",
    "*.s",
    "*.S",
    "*.asm",
    "*.inc",
    "*.py",
    "*.yml",
    "*.txt",
    "*.json"
  ],
  "units": [
    {
      "name": "main/MetroTRK/mslsupp",
      "target_path": "build/asm/MetroTRK/mslsupp.o",
      "base_path": "build/src/MetroTRK/mslsupp.o",
      "metadata": {}
    }
  ]
}

Schema

View config.schema.json for all available options. The below list is a summary of the most important options.

custom_make (optional): By default, objdiff will use make to build the project.
If the project uses a different build system (e.g. ninja), specify it here.
The build command will be [custom_make] [custom_args] path/to/object.o.

custom_args (optional): Additional arguments to pass to the build command prior to the object path.

build_target: If true, objdiff will tell the build system to build the target objects before diffing (e.g. make path/to/target.o).
This is useful if the target objects are not built by default or can change based on project configuration or edits to assembly files.
Requires the build system to be configured properly.

build_base: If true, objdiff will tell the build system to build the base objects before diffing (e.g. make path/to/base.o).
It's unlikely you'll want to disable this, unless you're using an external tool to rebuild the base object on source file changes.

watch_patterns (optional): A list of glob patterns to watch for changes. (Supported syntax)
If any of these files change, objdiff will automatically rebuild the objects and re-compare them.
If not specified, objdiff will use the default patterns listed above.

units (optional): If specified, objdiff will display a list of objects in the sidebar for easy navigation.

name (optional): The name of the object in the UI. If not specified, the object's path will be used.

target_path: Path to the "target" or "expected" object from the project root.
This object is the intended result of the match.

base_path: Path to the "base" or "actual" object from the project root.
This object is built from the current source code.

metadata.auto_generated (optional): Hides the object from the object list, but still includes it in reports.

metadata.complete (optional): Marks the object as "complete" (or "linked") in the object list.
This is useful for marking objects that are fully decompiled. A value of false will mark the object as "incomplete".

Building

Install Rust via rustup.

$ git clone https://github.com/encounter/objdiff.git
$ cd objdiff
$ cargo run --release

Or using cargo install.

$ cargo install --locked --git https://github.com/encounter/objdiff.git objdiff-gui objdiff-cli

The binaries will be installed to ~/.cargo/bin as objdiff and objdiff-cli.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.