diff --git a/objdiff-cli/src/cmd/report.rs b/objdiff-cli/src/cmd/report.rs index 475cb58..50c7929 100644 --- a/objdiff-cli/src/cmd/report.rs +++ b/objdiff-cli/src/cmd/report.rs @@ -476,7 +476,7 @@ fn read_report(path: &Path) -> Result { fn serialize_hex(x: &Option, s: S) -> Result where S: serde::Serializer { if let Some(x) = x { - s.serialize_str(&format!("{:#X}", x)) + s.serialize_str(&format!("{:#x}", x)) } else { s.serialize_none() } diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index 00146ef..f0355bb 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -52,6 +52,7 @@ impl ObjArch for ObjArchMips { let code = self.endianness.read_u32_bytes(chunk.try_into()?); let instruction = Instruction::new(code, cur_addr, InstrCategory::CPU); + let formatted = instruction.disassemble(None, 0); let op = instruction.unique_id as u16; ops.push(op); @@ -124,6 +125,7 @@ impl ObjArch for ObjArchMips { reloc: reloc.cloned(), branch_dest, line, + formatted, orig: None, }); cur_addr += 4; diff --git a/objdiff-core/src/arch/ppc.rs b/objdiff-core/src/arch/ppc.rs index 3c82f6c..f657787 100644 --- a/objdiff-core/src/arch/ppc.rs +++ b/objdiff-core/src/arch/ppc.rs @@ -62,6 +62,7 @@ impl ObjArch for ObjArchPpc { let orig = ins.basic().to_string(); let simplified = ins.simplified(); + let formatted = simplified.to_string(); let mut reloc_arg = None; if let Some(reloc) = reloc { @@ -145,6 +146,7 @@ impl ObjArch for ObjArchPpc { op: ins.op as u16, branch_dest, line, + formatted, orig: Some(orig), }); } diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index f6a11d8..db961e0 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -60,6 +60,7 @@ impl ObjArch for ObjArchX86 { reloc: None, branch_dest: None, line: None, + formatted: String::new(), orig: None, }, error: None, @@ -84,6 +85,7 @@ impl ObjArch for ObjArchX86 { reloc: reloc.cloned(), branch_dest: None, line: line_info.and_then(|m| m.get(&address).cloned()), + formatted: String::new(), orig: None, }; // Run the formatter, which will populate output.ins @@ -92,7 +94,7 @@ impl ObjArch for ObjArchX86 { return Err(error); } ensure!(output.ins_operands.len() == output.ins.args.len()); - output.ins.orig = Some(output.formatted.clone()); + output.ins.formatted.clone_from(&output.formatted); // Make sure we've put the relocation somewhere in the instruction if reloc.is_some() && !output.ins.args.iter().any(|a| matches!(a, ObjInsArg::Reloc)) { diff --git a/objdiff-core/src/diff/code.rs b/objdiff-core/src/diff/code.rs index 00f064c..f676440 100644 --- a/objdiff-core/src/diff/code.rs +++ b/objdiff-core/src/diff/code.rs @@ -39,7 +39,7 @@ pub fn diff_code( config: &DiffObjConfig, ) -> Result<(ObjSymbolDiff, ObjSymbolDiff)> { let left_out = left_obj.arch.process_code(left_obj, left_symbol_ref, config)?; - let right_out = left_obj.arch.process_code(right_obj, right_symbol_ref, config)?; + let right_out = right_obj.arch.process_code(right_obj, right_symbol_ref, config)?; let mut left_diff = Vec::::new(); let mut right_diff = Vec::::new(); diff --git a/objdiff-core/src/diff/display.rs b/objdiff-core/src/diff/display.rs index ee097e0..95d7a38 100644 --- a/objdiff-core/src/diff/display.rs +++ b/objdiff-core/src/diff/display.rs @@ -5,7 +5,7 @@ use crate::{ obj::{ObjInsArg, ObjInsArgValue, ObjReloc, ObjSymbol}, }; -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub enum DiffText<'a> { /// Basic text Basic(&'a str), @@ -95,8 +95,8 @@ fn display_reloc_name( ) -> Result<(), E> { cb(DiffText::Symbol(&reloc.target))?; match reloc.target.addend.cmp(&0i64) { - Ordering::Greater => cb(DiffText::Basic(&format!("+{:#X}", reloc.target.addend))), - Ordering::Less => cb(DiffText::Basic(&format!("-{:#X}", -reloc.target.addend))), + Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.target.addend))), + Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.target.addend))), _ => Ok(()), } } diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index 0260d24..df93d81 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -106,6 +106,8 @@ pub struct ObjIns { pub branch_dest: Option, /// Line number pub line: Option, + /// Formatted instruction + pub formatted: String, /// Original (unsimplified) instruction pub orig: Option, } diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index 3463d9d..6bc3450 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -257,7 +257,7 @@ fn relocations_by_section( } else { reloc.addend() }; - // println!("Reloc: {reloc:?}, symbol: {symbol:?}, addend: {addend:#X}"); + // println!("Reloc: {reloc:?}, symbol: {symbol:?}, addend: {addend:#x}"); let target = match symbol.kind() { SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => { to_obj_symbol(arch, obj_file, &symbol, addend, split_meta) diff --git a/objdiff-gui/src/views/data_diff.rs b/objdiff-gui/src/views/data_diff.rs index 1ad8505..d30f6dc 100644 --- a/objdiff-gui/src/views/data_diff.rs +++ b/objdiff-gui/src/views/data_diff.rs @@ -26,7 +26,7 @@ fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff], appeara } let mut job = LayoutJob::default(); write_text( - format!("{address:08X}: ").as_str(), + format!("{address:08x}: ").as_str(), appearance.text_color, &mut job, appearance.code_font.clone(), @@ -47,7 +47,7 @@ fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff], appeara } else { let mut text = String::new(); for byte in &diff.data { - text.push_str(format!("{byte:02X} ").as_str()); + text.push_str(format!("{byte:02x} ").as_str()); cur_addr += 1; if cur_addr % 8 == 0 { text.push(' '); diff --git a/objdiff-gui/src/views/function_diff.rs b/objdiff-gui/src/views/function_diff.rs index 4c8bd92..8421782 100644 --- a/objdiff-gui/src/views/function_diff.rs +++ b/objdiff-gui/src/views/function_diff.rs @@ -1,6 +1,6 @@ use std::default::Default; -use egui::{text::LayoutJob, Align, Label, Layout, Sense, Vec2, Widget}; +use egui::{text::LayoutJob, Align, Label, Layout, Response, Sense, Vec2, Widget}; use egui_extras::{Column, TableBuilder, TableRow}; use objdiff_core::{ arch::ObjArch, @@ -27,6 +27,7 @@ fn ins_hover_ui( arch: &dyn ObjArch, section: &ObjSection, ins: &ObjIns, + symbol: &ObjSymbol, appearance: &Appearance, ) { ui.scope(|ui| { @@ -35,10 +36,18 @@ fn ins_hover_ui( let offset = ins.address - section.address; ui.label(format!( - "{:02X?}", + "{:02x?}", §ion.data[offset as usize..(offset + ins.size as u64) as usize] )); + if let Some(virtual_address) = symbol.virtual_address { + let offset = ins.address - symbol.address; + ui.colored_label( + appearance.replace_color, + format!("Virtual address: {:#x}", virtual_address + offset), + ); + } + if let Some(orig) = &ins.orig { ui.label(format!("Original: {}", orig)); } @@ -77,12 +86,33 @@ fn ins_hover_ui( }); } -fn ins_context_menu(ui: &mut egui::Ui, ins: &ObjIns) { +fn ins_context_menu(ui: &mut egui::Ui, section: &ObjSection, ins: &ObjIns, symbol: &ObjSymbol) { ui.scope(|ui| { ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace); ui.style_mut().wrap = Some(false); - // if ui.button("Copy hex").clicked() {} + if ui.button(format!("Copy \"{}\"", ins.formatted)).clicked() { + ui.output_mut(|output| output.copied_text.clone_from(&ins.formatted)); + ui.close_menu(); + } + + let mut hex_string = "0x".to_string(); + for byte in §ion.data[ins.address as usize..(ins.address + ins.size as u64) as usize] { + hex_string.push_str(&format!("{:02x}", byte)); + } + if ui.button(format!("Copy \"{hex_string}\" (instruction bytes)")).clicked() { + ui.output_mut(|output| output.copied_text = hex_string); + ui.close_menu(); + } + + if let Some(virtual_address) = symbol.virtual_address { + let offset = ins.address - symbol.address; + let offset_string = format!("{:#x}", virtual_address + offset); + if ui.button(format!("Copy \"{offset_string}\" (virtual address)")).clicked() { + ui.output_mut(|output| output.copied_text = offset_string); + ui.close_menu(); + } + } for arg in &ins.args { if let ObjInsArg::Arg(arg) = arg { @@ -144,6 +174,7 @@ fn diff_text_ui( appearance: &Appearance, ins_view_state: &mut FunctionViewState, space_width: f32, + response_cb: impl Fn(Response) -> Response, ) { let label_text; let mut base_color = match ins_diff.kind { @@ -204,13 +235,13 @@ fn diff_text_ui( let len = label_text.len(); let highlight = ins_view_state.highlight == text; - let response = Label::new(LayoutJob::single_section( + let mut response = Label::new(LayoutJob::single_section( label_text, appearance.code_text_format(base_color, highlight), )) .sense(Sense::click()) .ui(ui); - response.context_menu(|ui| ins_context_menu(ui, ins_diff.ins.as_ref().unwrap())); + response = response_cb(response); if response.clicked() { if highlight { ins_view_state.highlight = HighlightKind::None; @@ -229,6 +260,7 @@ fn asm_row_ui( symbol: &ObjSymbol, appearance: &Appearance, ins_view_state: &mut FunctionViewState, + response_cb: impl Fn(Response) -> Response, ) { ui.spacing_mut().item_spacing.x = 0.0; if ins_diff.kind != ObjInsDiffKind::None { @@ -236,7 +268,7 @@ fn asm_row_ui( } let space_width = ui.fonts(|f| f.glyph_width(&appearance.code_font, ' ')); display_diff(ins_diff, symbol.address, |text| { - diff_text_ui(ui, text, ins_diff, appearance, ins_view_state, space_width); + diff_text_ui(ui, text, ins_diff, appearance, ins_view_state, space_width, &response_cb); Ok::<_, ()>(()) }) .unwrap(); @@ -251,14 +283,20 @@ fn asm_col_ui( ) { let (section, symbol) = obj.0.section_symbol(symbol_ref); let ins_diff = &obj.1.symbol_diff(symbol_ref).instructions[row.index()]; + let response_cb = |response: Response| { + if let Some(ins) = &ins_diff.ins { + response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol)); + response.on_hover_ui_at_pointer(|ui| { + ins_hover_ui(ui, obj.0.arch.as_ref(), section, ins, symbol, appearance) + }) + } else { + response + } + }; let (_, response) = row.col(|ui| { - asm_row_ui(ui, ins_diff, symbol, appearance, ins_view_state); + asm_row_ui(ui, ins_diff, symbol, appearance, ins_view_state, response_cb); }); - if let Some(ins) = &ins_diff.ins { - response.on_hover_ui_at_pointer(|ui| { - ins_hover_ui(ui, obj.0.arch.as_ref(), section, ins, appearance) - }); - } + response_cb(response); } fn empty_col_ui(row: &mut TableRow<'_, '_>) { diff --git a/objdiff-gui/src/views/symbol_diff.rs b/objdiff-gui/src/views/symbol_diff.rs index b28ecb2..58d0736 100644 --- a/objdiff-gui/src/views/symbol_diff.rs +++ b/objdiff-gui/src/views/symbol_diff.rs @@ -171,10 +171,7 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) { ); } if let Some(address) = symbol.virtual_address { - ui.colored_label( - appearance.highlight_color, - format!("Virtual address: {:#x}", address), - ); + ui.colored_label(appearance.replace_color, format!("Virtual address: {:#x}", address)); } }); }