objdiff Documentation

repository·main·Indexed 19 days ago

https://github.com/encounter/objdiff

A toolset for comparing object files in decompilation projects to identify differences between versions of compiled code. It includes objdiff-cli for performing diffs in one-shot or interactive TUI modes and generating progress reports, and objdiff-core, the central engine providing analysis capabilities. Supported architectures include x86, ARM64, ARM, MIPS, PowerPC, and SuperH.

Tokens
16.5K
Snippets
65
Records
78
Agent score
66%

What's inside objdiff

  1. Overview of objdiff-core

    main
    objdiff-core is the central engine of the objdiff toolset. It provides the core logic required for comparing object files within decompilation projects. Developers building on top of objdiff should use this crate to access the fundamental comparison and object file analysis capabilities.
  2. How the Arch trait works

    main

    The Arch trait is the core abstraction for handling architecture-specific logic in objdiff. It allows the library to support multiple instruction sets (like x86, ARM, MIPS, etc.) through a unified interface.

    Key responsibilities of an Arch implementation include:

    • Instruction Scanning: Using scan_instructions_internal to identify instruction boundaries, opcodes, and potential branch destinations.
    • Instruction Display: Using display_instruction to format mnemonics and arguments for the UI.
    • Detailed Comparison: Using process_instruction to parse instruction arguments for deep diffing.
    • Data Analysis: Providing data_flow_analysis and guess_data_type to interpret how instructions interact with data.
    • UI Enrichment: Providing symbol_hover, symbol_context, instruction_hover, and instruction_context to supply metadata to the user interface.

    Implementations of Arch are typically instantiated via the new_arch helper function, which selects the correct architecture based on the provided object::File.

    pub trait Arch: Any + Debug + Send + Sync {
        fn scan_instructions_internal(
            &self,
            address: u64,
            code: &[u8],
            section_index: usize,
            relocations: &[Relocation],
            diff_config: &DiffObjConfig,
        ) -> Result<Vec<InstructionRef>>;
    
        fn display_instruction(
            &self,
            resolved: ResolvedInstructionRef,
            diff_config: &DiffObjConfig,
            cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
        ) -> Result<()>;
    
        // ... other methods
    }
  3. Configure the objdiff GUI application

    main

    The objdiff GUI uses a configuration structure (stored via eframe::Storage) to manage project directories, build settings, and diffing preferences. The configuration is serialized using the RON (Rusty Object Notation) format.

    Key configuration areas include:

    • Project & Build Paths: project_dir, target_obj_dir, and base_obj_dir define where source and object files reside.
    • Build Automation: custom_make and custom_args allow specifying custom build commands. rebuild_on_changes and watch_patterns (using globset globs) control automatic rebuilding.
    • Object Configuration: selected_obj defines the specific object file being compared, including its target_path, base_path, and scratch settings.
    • Diffing Preferences: diff_obj_config controls how assembly and relocations are displayed (e.g., x86_formatter, mips_abi, arm_arch_version).
  4. Implement cancellation in background jobs

    main

    Jobs can be cancelled by sending a signal through the JobState::cancel channel. To support cancellation, the background task logic must periodically check the receiver.

    When a job is cancelled, the status field in JobStatus is set to "Cancelled" and the task returns an error. The should_cancel helper function can be used to check if a cancellation signal has been sent via a Receiver<()>.

  5. Project configuration structure and options

    main

    The project configuration (loaded via try_project_config) supports several key fields that control how objdiff behaves within a specific directory:

    • custom_make: Custom make command.
    • custom_args: Arguments for the custom make command.
    • target_dir: The directory where target object files are located (relative to the project directory).
    • base_dir: The base directory for object files (relative to the project directory).
    • build_base: Boolean flag indicating if the base directory should be built.
    • build_target: Boolean flag indicating if the target directory should be built.
    • watch_patterns: A list of glob patterns for files to watch.
    • ignore_patterns: A list of glob patterns for files to ignore.
    • units: A list of object units defined in the project.
    • options: Project-wide options applied to DiffObjConfig via apply_project_options.

    Individual units within the units list can also define their own options, which are applied specifically to that unit's diff configuration.

  6. Trigger background jobs in the GUI

    main

    The objdiff-gui manages background tasks (like building, updating, or creating scratch files) using a JobQueue. To run a task, you push a Job variant onto the JobQueue with a closure that executes the task. These tasks use an egui_waker to request UI repaints when background work completes or progresses, ensuring the interface stays responsive and updated.

    Common jobs include:

    • Job::ObjDiff: Runs the core objdiff build process.
    • Job::CreateScratch: Generates a scratch configuration for a specific function.
    • Job::Update: Handles checking for updates or performing the update itself.
  7. Understand the `ObjectDiff` data structure

    main

    An ObjectDiff represents the complete diffing results for a single object file. It contains:

    • symbols: A Vec<SymbolDiff> containing the diff results for every symbol in the object.
    • sections: A Vec<SectionDiff> containing the diff results for every section in the object.
    • mapping_symbols: A Vec<MappingSymbolDiff> used when selecting_left or selecting_right is configured. This contains the results of comparing specific selected symbols against their potential matches in the other object.
  8. Redirect output to a file or stdout

    main

    The CLI allows you to specify an output destination.

    • To write to a file, provide the file path as an argument.
    • To write to standard output (stdout), use the special character - or omit the output path if the implementation allows.

    Note: When using Proto format with a file, the utility uses memory mapping for efficient writing. When using Proto with stdout, it writes the encoded byte vector directly.

  9. Understand Job types and results

    main

    The Job enum defines the supported background operations in objdiff-core. Each job type corresponds to a specific variant in the JobResult enum returned upon completion.

    Supported Jobs:

    • Job::ObjDiff: Returns JobResult::ObjDiff(Option<Box<ObjDiffResult>>)
    • Job::CheckUpdate: Returns JobResult::CheckUpdate(Option<Box<CheckUpdateResult>>)
    • Job::Update: Returns JobResult::Update(Box<UpdateResult>)
    • Job::CreateScratch: Returns JobResult::CreateScratch(Option<Box<CreateScratchResult>>)

    Note: JobResult::None is used as a sentinel value when a job fails or has no meaningful data to return.

  10. Configure the graphics backend

    main

    The objdiff-gui allows users to specify a preferred graphics backend via a configuration file. This is useful for troubleshooting display issues or switching between APIs like Vulkan, Metal, or DirectX 12.

    Changing the backend requires a restart of the application. If the application fails to start after a change, you can reset the configuration by deleting the graphics configuration file located at the path specified in the Graphics window.

    ### Available Backends
    - `Auto` (Default)
    - `Vulkan`
    - `Metal`
    - `Dx12` (DirectX 12)
    - `OpenGL`
    - `OpenGLES`
  11. Configure symbol mappings with `MappingConfig`

    main

    The MappingConfig struct allows you to control how symbols are paired during a diff. This is useful when symbols have different names in different objects but represent the same entity.

    Key fields:

    • mappings: A BTreeMap<String, String> for manual symbol-to-symbol name mappings (Left Name $\rightarrow$ Right Name).
    • selecting_left: An Option<String> specifying a symbol name in the left object. When set, the engine will automatically attempt to find and match all compatible symbols in the right object to this specific symbol, providing match percentages for them.
    • selecting_right: An Option<String> specifying a symbol name in the right object. When set, the engine will attempt to find and match all compatible symbols in the left object to this specific symbol.
    let mapping_config = MappingConfig {
        mappings: BTreeMap::from([("foo".to_string(), "bar".to_string())]),
        selecting_left: Some("main".to_string()),
        selecting_right: None,
    };
  12. Manage application configuration with AppConfig

    main

    The AppConfig struct holds the persistent settings for the objdiff GUI. It includes paths for the project, target, and base object directories, build settings, and file watching patterns.

    Key fields include:

    • project_dir: The root directory of the current project.
    • target_obj_dir: The directory containing the 'target' object files.
    • base_obj_dir: The directory containing the 'base' object files.
    • watch_patterns: A list of Glob patterns used to trigger rebuilds on file changes.
    • ignore_patterns: A list of Glob patterns to exclude from watching.
    • rebuild_on_changes: A boolean that, when true, automatically re-runs the build and diff when watched files are modified.
    #[derive(Clone, serde::Deserialize, serde::Serialize)]
    pub struct AppConfig {
        pub version: u32,
        pub custom_make: Option<String>,
        pub custom_args: Option<Vec<String>>,
        pub selected_wsl_distro: Option<String>,
        pub project_dir: Option<Utf8PlatformPathBuf>,
        pub target_obj_dir: Option<Utf8PlatformPathBuf>,
        pub base_obj_dir: Option<Utf8PlatformPathBuf>,
        pub selected_obj: Option<ObjectConfig>,
        pub build_base: bool,
        pub build_target: bool,
        pub rebuild_on_changes: bool,
        pub auto_update_check: bool,
        pub watch_patterns: Vec<Glob>,
        pub ignore_patterns: Vec<Glob>,
        pub recent_projects: Vec<String>,
        pub diff_obj_config: DiffObjConfig,
    }