Compare commits

...

5 Commits

Author SHA1 Message Date
Luke Street 1205e8ceb4 Version v3.0.0-beta.12 2025-07-29 21:31:12 -06:00
Luke Street c917cad5f0 Strip zeros from end of inferred function sizes
Resolves #3
2025-07-29 21:20:47 -06:00
Luke Street dd653329f5 Fix reading IMAGE_REL_PPC_REFHI/REFLO without PAIR 2025-07-29 20:58:34 -06:00
Luke Street f5d3d5f10a gui: Split OpenGL into OpenGL (glow), OpenGL ES (wgpu) 2025-07-29 20:49:09 -06:00
Luke Street c327ed3ea8 Update to egui 0.32 (& update all deps) 2025-07-28 17:30:52 -06:00
17 changed files with 302 additions and 781 deletions
Generated
+214 -91
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -14,9 +14,9 @@ strip = "debuginfo"
codegen-units = 1
[workspace.package]
version = "3.0.0-beta.11"
version = "3.0.0-beta.12"
authors = ["Luke Street <luke@street.dev>"]
edition = "2024"
license = "MIT OR Apache-2.0"
repository = "https://github.com/encounter/objdiff"
rust-version = "1.85"
rust-version = "1.88"
+2 -2
View File
@@ -15,11 +15,11 @@ publish = false
[dependencies]
anyhow = "1.0"
argp = "0.4"
crossterm = "0.28"
crossterm = "0.29"
enable-ansi-support = "0.2"
memmap2 = "0.9"
objdiff-core = { path = "../objdiff-core", features = ["all"] }
prost = "0.13"
prost = "0.14"
ratatui = "0.29"
rayon = "1.10"
serde = { version = "1.0", features = ["derive"] }
+11 -11
View File
@@ -123,14 +123,14 @@ features = ["all"]
[dependencies]
anyhow = { version = "1.0", default-features = false }
filetime = { version = "0.2", optional = true }
flagset = { version = "0.4", default-features = false, optional = true, git = "https://github.com/enarx/flagset.git", rev = "a1fe9369b3741e43fec45da1998e83b9d78966a2" }
flagset = { version = "0.4", default-features = false, optional = true }
itertools = { version = "0.14", default-features = false, features = ["use_alloc"] }
log = { version = "0.4", default-features = false, optional = true }
memmap2 = { version = "0.9", optional = true }
num-traits = { version = "0.2", default-features = false, optional = true }
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
pbjson = { version = "0.7", default-features = false, optional = true }
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
pbjson = { version = "0.8", default-features = false, optional = true }
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
regex = { version = "1.11", default-features = false, features = [], optional = true }
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
similar = { version = "2.7", default-features = false, features = ["hashbrown"], optional = true, git = "https://github.com/encounter/similar.git", branch = "no_std" }
@@ -142,16 +142,16 @@ semver = { version = "1.0", default-features = false, optional = true }
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
# dwarf
gimli = { version = "0.31", default-features = false, features = ["read"], optional = true }
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
# ppc
cwdemangle = { version = "1.0", optional = true }
cwextab = { version = "1.0", optional = true }
cwextab = { version = "1.1", optional = true }
powerpc = { version = "0.4", optional = true }
rlwinmdec = { version = "1.1", optional = true }
# mips
rabbitizer = { version = "2.0.0-alpha.1", default-features = false, features = ["all_extensions"], optional = true }
rabbitizer = { version = "2.0.0-alpha.4", default-features = false, features = ["all_extensions"], optional = true }
# x86
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
@@ -159,7 +159,7 @@ iced-x86 = { version = "1.21", default-features = false, features = ["decoder",
msvc-demangler = { version = "0.11", optional = true }
# arm
unarm = { version = "1.8", optional = true }
unarm = { version = "1.9", optional = true }
arm-attr = { version = "0.2", optional = true }
# arm64
@@ -167,10 +167,10 @@ yaxpeax-arch = { version = "0.3", default-features = false, optional = true }
yaxpeax-arm = { version = "0.3", default-features = false, optional = true }
# build
notify = { version = "8.0.0", optional = true }
notify = { version = "8.1.0", optional = true }
notify-debouncer-full = { version = "0.5.0", optional = true }
shell-escape = { version = "0.1", optional = true }
tempfile = { version = "3.19", optional = true }
tempfile = { version = "3.20", optional = true }
time = { version = "0.3", optional = true }
encoding_rs = { version = "0.8.35", optional = true }
@@ -189,10 +189,10 @@ self_update = { version = "0.42", optional = true }
[build-dependencies]
heck = { version = "0.5", optional = true }
pbjson-build = { version = "0.7", optional = true }
pbjson-build = { version = "0.8", optional = true }
prettyplease = { version = "0.2", optional = true }
proc-macro2 = { version = "1.0", optional = true }
prost-build = { version = "0.13", optional = true }
prost-build = { version = "0.14", optional = true }
quote = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
+2
View File
@@ -462,6 +462,7 @@ impl Arch for ArchDummy {
fn data_reloc_size(&self, _flags: RelocationFlags) -> usize { 0 }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelocationOverrideTarget {
Keep,
Skip,
@@ -469,6 +470,7 @@ pub enum RelocationOverrideTarget {
Section(object::SectionIndex),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RelocationOverride {
pub target: RelocationOverrideTarget,
pub addend: i64,
+11 -5
View File
@@ -229,13 +229,19 @@ impl Arch for ArchPpc {
typ: pe::IMAGE_REL_PPC_PAIR
})
})
.map_or(Ok(None), |(_, reloc)| match reloc.target() {
object::RelocationTarget::Symbol(index) => Ok(Some(RelocationOverride {
.map_or(
Ok(Some(RelocationOverride {
target: RelocationOverrideTarget::Keep,
addend: index.0 as u16 as i16 as i64,
addend: 0,
})),
target => Err(anyhow!("Unsupported IMAGE_REL_PPC_PAIR target {target:?}")),
}),
|(_, reloc)| match reloc.target() {
object::RelocationTarget::Symbol(index) => Ok(Some(RelocationOverride {
target: RelocationOverrideTarget::Keep,
addend: index.0 as u16 as i16 as i64,
})),
target => Err(anyhow!("Unsupported IMAGE_REL_PPC_PAIR target {target:?}")),
},
),
// Skip PAIR relocations as they are handled by the previous case
object::RelocationFlags::Coff { typ: pe::IMAGE_REL_PPC_PAIR } => {
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Skip, addend: 0 }))
+15 -6
View File
@@ -205,10 +205,18 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
}
iter_idx += 1;
};
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
let section = &sections[section_idx];
section.address + section.size
});
let section = &sections[section_idx];
let mut next_address =
next_symbol.map(|s| s.address).unwrap_or_else(|| section.address + section.size);
if section.kind == SectionKind::Code {
// For functions, trim any trailing 4-byte zeroes from the end (padding, nops)
while next_address > symbol.address + 4
&& let Some(data) = section.data_range(next_address - 4, 4)
&& data == [0u8; 4]
{
next_address -= 4;
}
}
let new_size = next_address.saturating_sub(symbol.address);
if new_size > 0 {
let symbol = &mut symbols[symbol_idx];
@@ -218,7 +226,7 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
}
// Set symbol kind if unknown and size is non-zero
if symbol.kind == SymbolKind::Unknown {
symbol.kind = match sections[section_idx].kind {
symbol.kind = match section.kind {
SectionKind::Code => SymbolKind::Function,
SectionKind::Data | SectionKind::Bss => SymbolKind::Object,
_ => SymbolKind::Unknown,
@@ -361,7 +369,8 @@ fn map_section_relocations(
None => {
ensure!(
!reloc.has_implicit_addend(),
"Unsupported implicit relocation {:?}",
"Unsupported {:?} implicit relocation {:?}",
obj_file.architecture(),
reloc.flags()
);
}
+9 -6
View File
@@ -29,8 +29,8 @@ cfg-if = "1.0"
const_format = "0.2"
cwdemangle = "1.0"
dirs = "6.0"
egui = "0.31"
egui_extras = "0.31"
egui = "0.32"
egui_extras = "0.32"
filetime = "0.2"
float-ord = "0.3"
font-kit = "0.14"
@@ -43,18 +43,19 @@ pollster = "0.4"
regex = "1.11"
rfd = { version = "0.15" } #, default-features = false, features = ['xdg-portal']
rlwinmdec = "1.1"
ron = "0.8"
ron = "0.10"
serde = { version = "1.0", features = ["derive"] }
time = { version = "0.3", features = ["formatting", "local-offset"] }
typed-path = "0.11"
winit = { version = "0.30", features = ["wayland-csd-adwaita"] }
winit = { version = "0.30", features = ["default"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# Keep version in sync with egui
[dependencies.eframe]
version = "0.31"
version = "0.32"
features = [
"default_fonts",
"glow",
"persistence",
"wayland",
"x11",
@@ -63,10 +64,12 @@ default-features = false
# Keep version in sync with eframe
[dependencies.wgpu]
version = "24.0"
version = "25.0"
features = [
"dx12",
"metal",
"gles",
"vulkan",
"webgpu",
]
optional = true
+12 -12
View File
@@ -461,11 +461,11 @@ impl App {
use eframe::egui_wgpu::wgpu::Backend;
let info = wgpu_render_state.adapter.get_info();
app.view_state.graphics_state.active_backend = match info.backend {
Backend::Empty => "Unknown",
Backend::Noop => "None",
Backend::Vulkan => "Vulkan",
Backend::Metal => "Metal",
Backend::Dx12 => "DirectX 12",
Backend::Gl => "OpenGL",
Backend::Gl => "OpenGL ES",
Backend::BrowserWebGpu => "WebGPU",
}
.to_string();
@@ -474,7 +474,7 @@ impl App {
#[cfg(feature = "glow")]
if let Some(gl) = &cc.gl {
use eframe::glow::HasContext;
app.view_state.graphics_state.active_backend = "OpenGL (Fallback)".to_string();
app.view_state.graphics_state.active_backend = "OpenGL".to_string();
app.view_state.graphics_state.active_device =
unsafe { gl.get_parameter_string(0x1F01) }; // GL_RENDERER
}
@@ -665,7 +665,7 @@ impl eframe::App for App {
let side_panel_available = diff_state.current_view == View::SymbolDiff;
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
egui::menu::bar(ui, |ui| {
egui::MenuBar::new().ui(ui, |ui| {
if ui
.add_enabled(
side_panel_available,
@@ -681,11 +681,11 @@ impl eframe::App for App {
#[cfg(debug_assertions)]
if ui.button("Debug…").clicked() {
*show_debug = !*show_debug;
ui.close_menu();
ui.close();
}
if ui.button("Project…").clicked() {
*show_project_config = !*show_project_config;
ui.close_menu();
ui.close();
}
let recent_projects = if let Ok(guard) = state.read() {
guard.config.recent_projects.clone()
@@ -706,18 +706,18 @@ impl eframe::App for App {
.write()
.unwrap()
.set_project_dir(Utf8PlatformPathBuf::from(path));
ui.close_menu();
ui.close();
}
}
});
}
if ui.button("Appearance…").clicked() {
*show_appearance_config = !*show_appearance_config;
ui.close_menu();
ui.close();
}
if ui.button("Graphics…").clicked() {
*show_graphics = !*show_graphics;
ui.close_menu();
ui.close();
}
if ui.button("Quit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
@@ -726,17 +726,17 @@ impl eframe::App for App {
ui.menu_button("Tools", |ui| {
if ui.button("Demangle…").clicked() {
*show_demangle = !*show_demangle;
ui.close_menu();
ui.close();
}
if ui.button("Rlwinm Decoder…").clicked() {
*show_rlwinm_decode = !*show_rlwinm_decode;
ui.close_menu();
ui.close();
}
});
ui.menu_button("Diff Options", |ui| {
if ui.button("Arch Settings…").clicked() {
*show_arch_config = !*show_arch_config;
ui.close_menu();
ui.close();
}
let mut state = state.write().unwrap();
let response = ui
+2 -1
View File
@@ -95,7 +95,8 @@ fn main() -> ExitCode {
GraphicsBackend::Dx12 => wgpu::Backends::DX12,
GraphicsBackend::Metal => wgpu::Backends::METAL,
GraphicsBackend::Vulkan => wgpu::Backends::VULKAN,
GraphicsBackend::OpenGL => wgpu::Backends::GL,
GraphicsBackend::OpenGLES => wgpu::Backends::GL,
GraphicsBackend::OpenGL => wgpu::Backends::empty(),
};
WgpuSetup::CreateNew(setup)
}
+5 -5
View File
@@ -5,8 +5,8 @@ use std::{mem::take, path::MAIN_SEPARATOR};
#[cfg(all(windows, feature = "wsl"))]
use anyhow::{Context, Result};
use egui::{
CollapsingHeader, FontFamily, FontId, RichText, SelectableLabel, TextFormat, Widget,
output::OpenUrl, text::LayoutJob,
CollapsingHeader, FontFamily, FontId, RichText, TextFormat, Widget, output::OpenUrl,
text::LayoutJob,
};
use globset::Glob;
use objdiff_core::{
@@ -278,7 +278,7 @@ pub fn config_ui(
{
filters_text = filters_text.color(appearance.replace_color);
}
egui::menu::menu_button(ui, filters_text, |ui| {
egui::containers::menu::MenuButton::new(filters_text).ui(ui, |ui| {
ui.checkbox(&mut config_state.filter_diffable, "Diffable")
.on_hover_text_at_pointer("Only show objects with a source file");
ui.checkbox(&mut config_state.filter_incomplete, "Incomplete")
@@ -355,7 +355,7 @@ fn display_unit(
} else {
appearance.text_color
};
let response = SelectableLabel::new(
let response = egui::Button::selectable(
selected,
RichText::new(name)
.font(FontId {
@@ -384,7 +384,7 @@ fn object_context_ui(ui: &mut egui::Ui, object: &ObjectConfig) {
if let Err(e) = open::that_detached(source_path.as_str()) {
log::error!("Failed to open source file: {e}");
}
ui.close_menu();
ui.close();
}
}
}
+2 -2
View File
@@ -873,7 +873,7 @@ pub fn context_menu_items_ui(
}
if ui.button(job).clicked() {
ui.ctx().copy_text(value);
ui.close_menu();
ui.close();
}
}
ContextItem::Navigate { label, symbol_index, kind } => {
@@ -883,7 +883,7 @@ pub fn context_menu_items_ui(
symbol_index,
column,
)));
ui.close_menu();
ui.close();
}
}
ContextItem::Separator => {
+7 -3
View File
@@ -26,7 +26,8 @@ pub enum GraphicsBackend {
Vulkan,
Metal,
Dx12,
OpenGL,
OpenGL, // glow
OpenGLES, // wgpu
}
static ALL_BACKENDS: &[GraphicsBackend] = &[
@@ -35,6 +36,7 @@ static ALL_BACKENDS: &[GraphicsBackend] = &[
GraphicsBackend::Metal,
GraphicsBackend::Dx12,
GraphicsBackend::OpenGL,
GraphicsBackend::OpenGLES,
];
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
@@ -54,7 +56,7 @@ pub fn load_graphics_config(path: &Path) -> Result<Option<GraphicsConfig>> {
pub fn save_graphics_config(path: &Path, config: &GraphicsConfig) -> Result<()> {
let file = BufWriter::new(File::create(path)?);
ron::ser::to_writer(file, config)?;
ron::Options::default().to_io_writer(file, config)?;
Ok(())
}
@@ -67,7 +69,8 @@ impl GraphicsBackend {
}
GraphicsBackend::Metal => cfg!(all(feature = "wgpu", target_os = "macos")),
GraphicsBackend::Dx12 => cfg!(all(feature = "wgpu", target_os = "windows")),
GraphicsBackend::OpenGL => true,
GraphicsBackend::OpenGL => cfg!(feature = "glow"),
GraphicsBackend::OpenGLES => cfg!(all(feature = "wgpu", target_os = "windows")),
}
}
@@ -78,6 +81,7 @@ impl GraphicsBackend {
GraphicsBackend::Metal => "Metal",
GraphicsBackend::Dx12 => "DirectX 12",
GraphicsBackend::OpenGL => "OpenGL",
GraphicsBackend::OpenGLES => "OpenGL ES",
}
}
}
+4 -4
View File
@@ -1,8 +1,8 @@
use std::mem::take;
use egui::{
CollapsingHeader, Color32, Id, OpenUrl, ScrollArea, SelectableLabel, Ui, Widget,
style::ScrollAnimation, text::LayoutJob,
CollapsingHeader, Color32, Id, OpenUrl, ScrollArea, Ui, Widget, style::ScrollAnimation,
text::LayoutJob,
};
use objdiff_core::{
diff::{
@@ -508,7 +508,7 @@ pub fn symbol_context_menu_ui(
} else {
ret = Some(DiffViewAction::SelectingLeft(symbol_ref));
}
ui.close_menu();
ui.close();
}
}
});
@@ -586,7 +586,7 @@ fn symbol_ui(
write_text(") ", appearance.text_color, &mut job, appearance.code_font.clone());
}
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
let response = SelectableLabel::new(selected, job)
let response = egui::Button::selectable(selected, job)
.ui(ui)
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, ctx, symbol_idx, appearance));
response.context_menu(|ui| {
+1 -1
View File
@@ -34,7 +34,7 @@ features = ["arm", "arm64", "mips", "ppc", "superh", "x86", "dwarf"]
talc = { version = "4.4", default-features = false, features = ["lock_api"] }
[target.'cfg(target_os = "wasi")'.dependencies]
wit-bindgen = { version = "0.42", default-features = false, features = ["macros"] }
wit-bindgen = { version = "0.43", default-features = false, features = ["macros"] }
[build-dependencies]
wit-deps = "0.5"
+2 -629
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "objdiff-wasm",
"version": "3.0.0-beta.11",
"version": "3.0.0-beta.12",
"description": "A local diffing tool for decompilation projects.",
"author": {
"name": "Luke Street",