mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Initial x86 support
Includes a bit of work to make adding new architectures easier in the future
This commit is contained in:
+30
-6
@@ -12,8 +12,11 @@ use std::{
|
||||
use filetime::FileTime;
|
||||
use globset::{Glob, GlobSet};
|
||||
use notify::{RecursiveMode, Watcher};
|
||||
use objdiff_core::config::{
|
||||
build_globset, ProjectConfigInfo, ProjectObject, ScratchConfig, DEFAULT_WATCH_PATTERNS,
|
||||
use objdiff_core::{
|
||||
config::{
|
||||
build_globset, ProjectConfigInfo, ProjectObject, ScratchConfig, DEFAULT_WATCH_PATTERNS,
|
||||
},
|
||||
diff::DiffObjConfig,
|
||||
};
|
||||
use time::UtcOffset;
|
||||
|
||||
@@ -26,7 +29,9 @@ use crate::{
|
||||
},
|
||||
views::{
|
||||
appearance::{appearance_window, Appearance},
|
||||
config::{config_ui, project_window, ConfigViewState, CONFIG_DISABLED_TEXT},
|
||||
config::{
|
||||
config_ui, diff_config_window, project_window, ConfigViewState, CONFIG_DISABLED_TEXT,
|
||||
},
|
||||
data_diff::data_diff_ui,
|
||||
debug::debug_window,
|
||||
demangle::{demangle_window, DemangleViewState},
|
||||
@@ -47,6 +52,7 @@ pub struct ViewState {
|
||||
pub show_appearance_config: bool,
|
||||
pub show_demangle: bool,
|
||||
pub show_project_config: bool,
|
||||
pub show_diff_config: bool,
|
||||
pub show_debug: bool,
|
||||
}
|
||||
|
||||
@@ -100,7 +106,7 @@ pub struct AppConfig {
|
||||
#[serde(default)]
|
||||
pub recent_projects: Vec<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub relax_reloc_diffs: bool,
|
||||
pub diff_obj_config: DiffObjConfig,
|
||||
|
||||
#[serde(skip)]
|
||||
pub objects: Vec<ProjectObject>,
|
||||
@@ -138,7 +144,7 @@ impl Default for AppConfig {
|
||||
auto_update_check: true,
|
||||
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
|
||||
recent_projects: vec![],
|
||||
relax_reloc_diffs: false,
|
||||
diff_obj_config: Default::default(),
|
||||
objects: vec![],
|
||||
object_nodes: vec![],
|
||||
watcher_change: false,
|
||||
@@ -408,6 +414,7 @@ impl eframe::App for App {
|
||||
show_appearance_config,
|
||||
show_demangle,
|
||||
show_project_config,
|
||||
show_diff_config,
|
||||
show_debug,
|
||||
} = view_state;
|
||||
|
||||
@@ -461,6 +468,10 @@ impl eframe::App for App {
|
||||
}
|
||||
});
|
||||
ui.menu_button("Diff Options", |ui| {
|
||||
if ui.button("More…").clicked() {
|
||||
*show_diff_config = !*show_diff_config;
|
||||
ui.close_menu();
|
||||
}
|
||||
let mut config = config.write().unwrap();
|
||||
let response = ui
|
||||
.checkbox(&mut config.rebuild_on_changes, "Rebuild on changes")
|
||||
@@ -481,7 +492,10 @@ impl eframe::App for App {
|
||||
"Show hidden symbols",
|
||||
);
|
||||
if ui
|
||||
.checkbox(&mut config.relax_reloc_diffs, "Relax relocation diffs")
|
||||
.checkbox(
|
||||
&mut config.diff_obj_config.relax_reloc_diffs,
|
||||
"Relax relocation diffs",
|
||||
)
|
||||
.on_hover_text(
|
||||
"Ignores differences in relocation targets. (Address, name, etc)",
|
||||
)
|
||||
@@ -489,6 +503,15 @@ impl eframe::App for App {
|
||||
{
|
||||
config.queue_reload = true;
|
||||
}
|
||||
if ui
|
||||
.checkbox(
|
||||
&mut config.diff_obj_config.space_between_args,
|
||||
"Space between args",
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
config.queue_reload = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -518,6 +541,7 @@ impl eframe::App for App {
|
||||
project_window(ctx, config, show_project_config, config_state, appearance);
|
||||
appearance_window(ctx, show_appearance_config, appearance);
|
||||
demangle_window(ctx, show_demangle, demangle_state, appearance);
|
||||
diff_config_window(ctx, config, show_diff_config, appearance);
|
||||
debug_window(ctx, show_debug, frame_history, appearance);
|
||||
|
||||
self.post_update(ctx);
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{
|
||||
use anyhow::{anyhow, Context, Error, Result};
|
||||
use objdiff_core::{
|
||||
diff::{diff_objs, DiffObjConfig},
|
||||
obj::{elf, ObjInfo},
|
||||
obj::{read, ObjInfo},
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -57,7 +57,7 @@ pub struct ObjDiffConfig {
|
||||
pub build_base: bool,
|
||||
pub build_target: bool,
|
||||
pub selected_obj: Option<ObjectConfig>,
|
||||
pub relax_reloc_diffs: bool,
|
||||
pub diff_obj_config: DiffObjConfig,
|
||||
}
|
||||
|
||||
impl ObjDiffConfig {
|
||||
@@ -67,7 +67,7 @@ impl ObjDiffConfig {
|
||||
build_base: config.build_base,
|
||||
build_target: config.build_target,
|
||||
selected_obj: config.selected_obj.clone(),
|
||||
relax_reloc_diffs: config.relax_reloc_diffs,
|
||||
diff_obj_config: config.diff_obj_config.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ fn run_build(
|
||||
total,
|
||||
&cancel,
|
||||
)?;
|
||||
Some(elf::read(target_path).with_context(|| {
|
||||
Some(read::read(target_path).with_context(|| {
|
||||
format!("Failed to read object '{}'", target_path.display())
|
||||
})?)
|
||||
}
|
||||
@@ -241,7 +241,7 @@ fn run_build(
|
||||
&cancel,
|
||||
)?;
|
||||
Some(
|
||||
elf::read(base_path)
|
||||
read::read(base_path)
|
||||
.with_context(|| format!("Failed to read object '{}'", base_path.display()))?,
|
||||
)
|
||||
}
|
||||
@@ -249,8 +249,7 @@ fn run_build(
|
||||
};
|
||||
|
||||
update_status(context, "Performing diff".to_string(), 4, total, &cancel)?;
|
||||
let diff_config = DiffObjConfig { relax_reloc_diffs: config.relax_reloc_diffs };
|
||||
diff_objs(&diff_config, first_obj.as_mut(), second_obj.as_mut())?;
|
||||
diff_objs(&config.diff_obj_config, first_obj.as_mut(), second_obj.as_mut())?;
|
||||
|
||||
update_status(context, "Complete".to_string(), total, total, &cancel)?;
|
||||
Ok(Box::new(ObjDiffResult { first_status, second_status, first_obj, second_obj, time }))
|
||||
|
||||
@@ -14,7 +14,10 @@ use egui::{
|
||||
SelectableLabel, TextFormat, Widget,
|
||||
};
|
||||
use globset::Glob;
|
||||
use objdiff_core::config::{ProjectObject, DEFAULT_WATCH_PATTERNS};
|
||||
use objdiff_core::{
|
||||
config::{ProjectObject, DEFAULT_WATCH_PATTERNS},
|
||||
obj::x86::X86Formatter,
|
||||
};
|
||||
use self_update::cargo_crate_version;
|
||||
|
||||
use crate::{
|
||||
@@ -838,3 +841,36 @@ fn split_obj_config_ui(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn diff_config_window(
|
||||
ctx: &egui::Context,
|
||||
config: &AppConfigRef,
|
||||
show: &mut bool,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
let mut config_guard = config.write().unwrap();
|
||||
egui::Window::new("Diff Config").open(show).show(ctx, |ui| {
|
||||
diff_config_ui(ui, &mut config_guard, appearance);
|
||||
});
|
||||
}
|
||||
|
||||
fn diff_config_ui(ui: &mut egui::Ui, config: &mut AppConfig, _appearance: &Appearance) {
|
||||
egui::ComboBox::new("x86_formatter", "X86 Format")
|
||||
.selected_text(format!("{:?}", config.diff_obj_config.x86_formatter))
|
||||
.show_ui(ui, |ui| {
|
||||
for &formatter in
|
||||
&[X86Formatter::Intel, X86Formatter::Gas, X86Formatter::Nasm, X86Formatter::Masm]
|
||||
{
|
||||
if ui
|
||||
.selectable_label(
|
||||
config.diff_obj_config.x86_formatter == formatter,
|
||||
format!("{:?}", formatter),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
config.diff_obj_config.x86_formatter = formatter;
|
||||
config.queue_reload = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ use egui::{text::LayoutJob, Align, Label, Layout, Sense, Vec2, Widget};
|
||||
use egui_extras::{Column, TableBuilder, TableRow};
|
||||
use objdiff_core::{
|
||||
diff::display::{display_diff, DiffText, HighlightKind},
|
||||
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjInsDiff, ObjInsDiffKind, ObjSymbol},
|
||||
obj::{
|
||||
ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjInsDiff, ObjInsDiffKind, ObjSection,
|
||||
ObjSymbol,
|
||||
},
|
||||
};
|
||||
use time::format_description;
|
||||
|
||||
@@ -18,19 +21,23 @@ pub struct FunctionViewState {
|
||||
pub highlight: HighlightKind,
|
||||
}
|
||||
|
||||
fn ins_hover_ui(ui: &mut egui::Ui, ins: &ObjIns, appearance: &Appearance) {
|
||||
fn ins_hover_ui(ui: &mut egui::Ui, section: &ObjSection, ins: &ObjIns, appearance: &Appearance) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
|
||||
ui.label(format!("{:02X?}", ins.code.to_be_bytes()));
|
||||
let offset = ins.address - section.address;
|
||||
ui.label(format!(
|
||||
"{:02X?}",
|
||||
§ion.data[offset as usize..(offset + ins.size as u64) as usize]
|
||||
));
|
||||
|
||||
if let Some(orig) = &ins.orig {
|
||||
ui.label(format!("Original: {}", orig));
|
||||
}
|
||||
|
||||
for arg in &ins.args {
|
||||
if let ObjInsArg::Arg(arg) | ObjInsArg::ArgWithBase(arg) = arg {
|
||||
if let ObjInsArg::Arg(arg) = arg {
|
||||
match arg {
|
||||
ObjInsArgValue::Signed(v) => {
|
||||
ui.label(format!("{arg} == {v}"));
|
||||
@@ -71,7 +78,7 @@ fn ins_context_menu(ui: &mut egui::Ui, ins: &ObjIns) {
|
||||
// if ui.button("Copy hex").clicked() {}
|
||||
|
||||
for arg in &ins.args {
|
||||
if let ObjInsArg::Arg(arg) | ObjInsArg::ArgWithBase(arg) = arg {
|
||||
if let ObjInsArg::Arg(arg) = arg {
|
||||
match arg {
|
||||
ObjInsArgValue::Signed(v) => {
|
||||
if ui.button(format!("Copy \"{arg}\"")).clicked() {
|
||||
@@ -112,9 +119,14 @@ fn ins_context_menu(ui: &mut egui::Ui, ins: &ObjIns) {
|
||||
});
|
||||
}
|
||||
|
||||
fn find_symbol<'a>(obj: &'a ObjInfo, selected_symbol: &SymbolReference) -> Option<&'a ObjSymbol> {
|
||||
fn find_symbol<'a>(
|
||||
obj: &'a ObjInfo,
|
||||
selected_symbol: &SymbolReference,
|
||||
) -> Option<(&'a ObjSection, &'a ObjSymbol)> {
|
||||
obj.sections.iter().find_map(|section| {
|
||||
section.symbols.iter().find(|symbol| symbol.name == selected_symbol.symbol_name)
|
||||
section.symbols.iter().find_map(|symbol| {
|
||||
(symbol.name == selected_symbol.symbol_name).then_some((section, symbol))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -166,7 +178,7 @@ fn diff_text_ui(
|
||||
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
|
||||
}
|
||||
}
|
||||
DiffText::BranchTarget(addr) => {
|
||||
DiffText::BranchDest(addr) => {
|
||||
label_text = format!("{addr:x}");
|
||||
}
|
||||
DiffText::Symbol(sym) => {
|
||||
@@ -216,7 +228,7 @@ fn asm_row_ui(
|
||||
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
||||
}
|
||||
let space_width = ui.fonts(|f| f.glyph_width(&appearance.code_font, ' '));
|
||||
display_diff(ins_diff, symbol.address as u32, |text| {
|
||||
display_diff(ins_diff, symbol.address, |text| {
|
||||
diff_text_ui(ui, text, ins_diff, appearance, ins_view_state, space_width);
|
||||
Ok::<_, ()>(())
|
||||
})
|
||||
@@ -226,6 +238,7 @@ fn asm_row_ui(
|
||||
fn asm_col_ui(
|
||||
row: &mut TableRow<'_, '_>,
|
||||
ins_diff: &ObjInsDiff,
|
||||
section: &ObjSection,
|
||||
symbol: &ObjSymbol,
|
||||
appearance: &Appearance,
|
||||
ins_view_state: &mut FunctionViewState,
|
||||
@@ -234,7 +247,7 @@ fn asm_col_ui(
|
||||
asm_row_ui(ui, ins_diff, symbol, appearance, ins_view_state);
|
||||
});
|
||||
if let Some(ins) = &ins_diff.ins {
|
||||
response.on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, ins, appearance));
|
||||
response.on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, section, ins, appearance));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,14 +267,15 @@ fn asm_table_ui(
|
||||
) -> Option<()> {
|
||||
let left_symbol = left_obj.and_then(|obj| find_symbol(obj, selected_symbol));
|
||||
let right_symbol = right_obj.and_then(|obj| find_symbol(obj, selected_symbol));
|
||||
let instructions_len = left_symbol.or(right_symbol).map(|s| s.instructions.len())?;
|
||||
let instructions_len = left_symbol.or(right_symbol).map(|(_, s)| s.instructions.len())?;
|
||||
table.body(|body| {
|
||||
body.rows(appearance.code_font.size, instructions_len, |mut row| {
|
||||
let row_index = row.index();
|
||||
if let Some(symbol) = left_symbol {
|
||||
if let Some((section, symbol)) = left_symbol {
|
||||
asm_col_ui(
|
||||
&mut row,
|
||||
&symbol.instructions[row_index],
|
||||
section,
|
||||
symbol,
|
||||
appearance,
|
||||
ins_view_state,
|
||||
@@ -269,10 +283,11 @@ fn asm_table_ui(
|
||||
} else {
|
||||
empty_col_ui(&mut row);
|
||||
}
|
||||
if let Some(symbol) = right_symbol {
|
||||
if let Some((section, symbol)) = right_symbol {
|
||||
asm_col_ui(
|
||||
&mut row,
|
||||
&symbol.instructions[row_index],
|
||||
section,
|
||||
symbol,
|
||||
appearance,
|
||||
ins_view_state,
|
||||
@@ -384,7 +399,7 @@ pub fn function_diff_ui(ui: &mut egui::Ui, state: &mut DiffViewState, appearance
|
||||
.second_obj
|
||||
.as_ref()
|
||||
.and_then(|obj| find_symbol(obj, selected_symbol))
|
||||
.and_then(|symbol| symbol.match_percent)
|
||||
.and_then(|(_, symbol)| symbol.match_percent)
|
||||
{
|
||||
ui.colored_label(
|
||||
match_color_for_symbol(match_percent, appearance),
|
||||
|
||||
Reference in New Issue
Block a user