diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index ba4ca80..f21738b 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags}; use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType}; @@ -35,6 +35,7 @@ impl ObjArch for ObjArchMips { config: &DiffObjConfig, ) -> Result { let (section, symbol) = obj.section_symbol(symbol_ref); + let section = section.ok_or_else(|| anyhow!("Code symbol section not found"))?; let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; diff --git a/objdiff-core/src/arch/ppc.rs b/objdiff-core/src/arch/ppc.rs index 485ef6b..c27fbe2 100644 --- a/objdiff-core/src/arch/ppc.rs +++ b/objdiff-core/src/arch/ppc.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; use object::{elf, File, Relocation, RelocationFlags}; use ppc750cl::{Argument, InsIter, GPR}; @@ -36,6 +36,7 @@ impl ObjArch for ObjArchPpc { config: &DiffObjConfig, ) -> Result { let (section, symbol) = obj.section_symbol(symbol_ref); + let section = section.ok_or_else(|| anyhow!("Code symbol section not found"))?; let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index 89e0345..8bbecd7 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -33,6 +33,7 @@ impl ObjArch for ObjArchX86 { config: &DiffObjConfig, ) -> Result { let (section, symbol) = obj.section_symbol(symbol_ref); + let section = section.ok_or_else(|| anyhow!("Code symbol section not found"))?; let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; diff --git a/objdiff-core/src/diff/code.rs b/objdiff-core/src/diff/code.rs index f676440..bbd300d 100644 --- a/objdiff-core/src/diff/code.rs +++ b/objdiff-core/src/diff/code.rs @@ -28,7 +28,7 @@ pub fn no_diff_code( diff.push(ObjInsDiff { ins: Some(i), kind: ObjInsDiffKind::None, ..Default::default() }); } resolve_branches(&mut diff); - Ok(ObjSymbolDiff { diff_symbol: None, instructions: diff, match_percent: None }) + Ok(ObjSymbolDiff { symbol_ref, diff_symbol: None, instructions: diff, match_percent: None }) } pub fn diff_code( @@ -66,11 +66,13 @@ pub fn diff_code( Ok(( ObjSymbolDiff { + symbol_ref: left_symbol_ref, diff_symbol: Some(right_symbol_ref), instructions: left_diff, match_percent: Some(percent), }, ObjSymbolDiff { + symbol_ref: right_symbol_ref, diff_symbol: Some(left_symbol_ref), instructions: right_diff, match_percent: Some(percent), diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index d0a4c6e..e8882d7 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -3,8 +3,8 @@ use std::{ time::{Duration, Instant}, }; -use anyhow::Result; -use similar::{capture_diff_slices_deadline, Algorithm}; +use anyhow::{anyhow, Result}; +use similar::{capture_diff_slices_deadline, get_diff_ratio, Algorithm}; use crate::{ diff::{ObjDataDiff, ObjDataDiffKind, ObjSectionDiff, ObjSymbolDiff}, @@ -22,11 +22,13 @@ pub fn diff_bss_symbol( let percent = if left_symbol.size == right_symbol.size { 100.0 } else { 50.0 }; Ok(( ObjSymbolDiff { + symbol_ref: left_symbol_ref, diff_symbol: Some(right_symbol_ref), instructions: vec![], match_percent: Some(percent), }, ObjSymbolDiff { + symbol_ref: right_symbol_ref, diff_symbol: Some(left_symbol_ref), instructions: vec![], match_percent: Some(percent), @@ -34,8 +36,8 @@ pub fn diff_bss_symbol( )) } -pub fn no_diff_bss_symbol(_obj: &ObjInfo, _symbol_ref: SymbolRef) -> ObjSymbolDiff { - ObjSymbolDiff { diff_symbol: None, instructions: vec![], match_percent: Some(0.0) } +pub fn no_diff_symbol(_obj: &ObjInfo, symbol_ref: SymbolRef) -> ObjSymbolDiff { + ObjSymbolDiff { symbol_ref, diff_symbol: None, instructions: vec![], match_percent: None } } pub fn diff_data( @@ -45,6 +47,7 @@ pub fn diff_data( let deadline = Instant::now() + Duration::from_secs(5); let ops = capture_diff_slices_deadline(Algorithm::Patience, &left.data, &right.data, Some(deadline)); + let match_percent = get_diff_ratio(&ops, left.data.len(), right.data.len()) * 100.0; let mut left_diff = Vec::::new(); let mut right_diff = Vec::::new(); @@ -118,14 +121,50 @@ pub fn diff_data( ObjSectionDiff { symbols: vec![], data_diff: left_diff, - // TODO - match_percent: None, + match_percent: Some(match_percent), }, ObjSectionDiff { symbols: vec![], data_diff: right_diff, - // TODO - match_percent: None, + match_percent: Some(match_percent), + }, + )) +} + +pub fn diff_data_symbol( + left_obj: &ObjInfo, + right_obj: &ObjInfo, + left_symbol_ref: SymbolRef, + right_symbol_ref: SymbolRef, +) -> Result<(ObjSymbolDiff, ObjSymbolDiff)> { + let (left_section, left_symbol) = left_obj.section_symbol(left_symbol_ref); + let (right_section, right_symbol) = right_obj.section_symbol(right_symbol_ref); + + let left_section = left_section.ok_or_else(|| anyhow!("Data symbol section not found"))?; + let right_section = right_section.ok_or_else(|| anyhow!("Data symbol section not found"))?; + + let left_data = &left_section.data[left_symbol.section_address as usize + ..(left_symbol.section_address + left_symbol.size) as usize]; + let right_data = &right_section.data[right_symbol.section_address as usize + ..(right_symbol.section_address + right_symbol.size) as usize]; + + let deadline = Instant::now() + Duration::from_secs(5); + let ops = + capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, Some(deadline)); + let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0; + + Ok(( + ObjSymbolDiff { + symbol_ref: left_symbol_ref, + diff_symbol: Some(right_symbol_ref), + instructions: vec![], + match_percent: Some(match_percent), + }, + ObjSymbolDiff { + symbol_ref: right_symbol_ref, + diff_symbol: Some(left_symbol_ref), + instructions: vec![], + match_percent: Some(match_percent), }, )) } diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index 399a6d7..de8d3ea 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -1,7 +1,3 @@ -mod code; -mod data; -pub mod display; - use std::collections::HashSet; use anyhow::Result; @@ -9,11 +5,15 @@ use anyhow::Result; use crate::{ diff::{ code::{diff_code, no_diff_code}, - data::{diff_bss_symbol, diff_data, no_diff_bss_symbol}, + data::{diff_bss_symbol, diff_data, diff_data_symbol, no_diff_symbol}, }, - obj::{ObjInfo, ObjIns, ObjSectionKind, SymbolRef}, + obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef}, }; +mod code; +mod data; +pub mod display; + #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub enum X86Formatter { #[default] @@ -62,6 +62,7 @@ impl ObjSectionDiff { #[derive(Debug, Clone, Default)] pub struct ObjSymbolDiff { + pub symbol_ref: SymbolRef, pub diff_symbol: Option, pub instructions: Vec, pub match_percent: Option, @@ -142,10 +143,11 @@ impl ObjDiff { sections: Vec::with_capacity(obj.sections.len()), common: Vec::with_capacity(obj.common.len()), }; - for section in &obj.sections { + for (section_idx, section) in obj.sections.iter().enumerate() { let mut symbols = Vec::with_capacity(section.symbols.len()); - for _ in §ion.symbols { + for (symbol_idx, _) in section.symbols.iter().enumerate() { symbols.push(ObjSymbolDiff { + symbol_ref: SymbolRef { section_idx, symbol_idx }, diff_symbol: None, instructions: vec![], match_percent: None, @@ -162,8 +164,9 @@ impl ObjDiff { match_percent: None, }); } - for _ in &obj.common { + for (symbol_idx, _) in obj.common.iter().enumerate() { result.common.push(ObjSymbolDiff { + symbol_ref: SymbolRef { section_idx: obj.sections.len(), symbol_idx }, diff_symbol: None, instructions: vec![], match_percent: None, @@ -184,12 +187,20 @@ impl ObjDiff { #[inline] pub fn symbol_diff(&self, symbol_ref: SymbolRef) -> &ObjSymbolDiff { - &self.section_diff(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx] + if symbol_ref.section_idx == self.sections.len() { + &self.common[symbol_ref.symbol_idx] + } else { + &self.section_diff(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx] + } } #[inline] pub fn symbol_diff_mut(&mut self, symbol_ref: SymbolRef) -> &mut ObjSymbolDiff { - &mut self.section_diff_mut(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx] + if symbol_ref.section_idx == self.sections.len() { + &mut self.common[symbol_ref.symbol_idx] + } else { + &mut self.section_diff_mut(symbol_ref.section_idx).symbols[symbol_ref.symbol_idx] + } } } @@ -247,7 +258,14 @@ pub fn diff_objs( } } ObjSectionKind::Data => { - // TODO diff data symbol + let (left_diff, right_diff) = diff_data_symbol( + left_obj, + right_obj, + left_symbol_ref, + right_symbol_ref, + )?; + *left_out.symbol_diff_mut(left_symbol_ref) = left_diff; + *right_out.symbol_diff_mut(right_symbol_ref) = right_diff; } ObjSectionKind::Bss => { let (left_diff, right_diff) = diff_bss_symbol( @@ -268,10 +286,9 @@ pub fn diff_objs( *left_out.symbol_diff_mut(left_symbol_ref) = no_diff_code(left_obj, left_symbol_ref, config)?; } - ObjSectionKind::Data => {} - ObjSectionKind::Bss => { + ObjSectionKind::Data | ObjSectionKind::Bss => { *left_out.symbol_diff_mut(left_symbol_ref) = - no_diff_bss_symbol(left_obj, left_symbol_ref); + no_diff_symbol(left_obj, left_symbol_ref); } } } @@ -282,10 +299,9 @@ pub fn diff_objs( *right_out.symbol_diff_mut(right_symbol_ref) = no_diff_code(right_obj, right_symbol_ref, config)?; } - ObjSectionKind::Data => {} - ObjSectionKind::Bss => { + ObjSectionKind::Data | ObjSectionKind::Bss => { *right_out.symbol_diff_mut(right_symbol_ref) = - no_diff_bss_symbol(right_obj, right_symbol_ref); + no_diff_symbol(right_obj, right_symbol_ref); } } } @@ -357,8 +373,8 @@ fn matching_symbols( for (symbol_idx, symbol) in section.symbols.iter().enumerate() { let symbol_match = SymbolMatch { left: Some(SymbolRef { section_idx, symbol_idx }), - right: find_symbol(right, &symbol.name, section.kind), - prev: find_symbol(prev, &symbol.name, section.kind), + right: find_symbol(right, symbol, section), + prev: find_symbol(prev, symbol, section), section_kind: section.kind, }; matches.push(symbol_match); @@ -367,6 +383,18 @@ fn matching_symbols( } } } + for (symbol_idx, symbol) in left.common.iter().enumerate() { + let symbol_match = SymbolMatch { + left: Some(SymbolRef { section_idx: left.sections.len(), symbol_idx }), + right: find_common_symbol(right, symbol), + prev: find_common_symbol(prev, symbol), + section_kind: ObjSectionKind::Bss, + }; + matches.push(symbol_match); + if let Some(right) = symbol_match.right { + right_used.insert(right); + } + } } if let Some(right) = right { for (section_idx, section) in right.sections.iter().enumerate() { @@ -378,29 +406,68 @@ fn matching_symbols( matches.push(SymbolMatch { left: None, right: Some(symbol_ref), - prev: find_symbol(prev, &symbol.name, section.kind), + prev: find_symbol(prev, symbol, section), section_kind: section.kind, }); } } + for (symbol_idx, symbol) in right.common.iter().enumerate() { + let symbol_ref = SymbolRef { section_idx: right.sections.len(), symbol_idx }; + if right_used.contains(&symbol_ref) { + continue; + } + matches.push(SymbolMatch { + left: None, + right: Some(symbol_ref), + prev: find_common_symbol(prev, symbol), + section_kind: ObjSectionKind::Bss, + }); + } } Ok(matches) } fn find_symbol( obj: Option<&ObjInfo>, - name: &str, - section_kind: ObjSectionKind, + in_symbol: &ObjSymbol, + in_section: &ObjSection, ) -> Option { - for (section_idx, section) in obj?.sections.iter().enumerate() { - if section.kind != section_kind { + let obj = obj?; + // Try to find an exact name match + for (section_idx, section) in obj.sections.iter().enumerate() { + if section.kind != in_section.kind { continue; } - let symbol_idx = match section.symbols.iter().position(|symbol| symbol.name == name) { - Some(symbol_idx) => symbol_idx, - None => continue, - }; - return Some(SymbolRef { section_idx, symbol_idx }); + if let Some(symbol_idx) = + section.symbols.iter().position(|symbol| symbol.name == in_symbol.name) + { + return Some(SymbolRef { section_idx, symbol_idx }); + } + } + // Match compiler-generated symbols against each other (e.g. @251 -> @60) + // If they are at the same address in the same section + if in_symbol.name.starts_with('@') + && matches!(in_section.kind, ObjSectionKind::Data | ObjSectionKind::Bss) + { + if let Some((section_idx, section)) = + obj.sections.iter().enumerate().find(|(_, s)| s.name == in_section.name) + { + if let Some(symbol_idx) = section.symbols.iter().position(|symbol| { + symbol.address == in_symbol.address && symbol.name.starts_with('@') + }) { + return Some(SymbolRef { section_idx, symbol_idx }); + } + } + } + None +} + +fn find_common_symbol(obj: Option<&ObjInfo>, in_symbol: &ObjSymbol) -> Option { + let obj = obj?; + for (symbol_idx, symbol) in obj.common.iter().enumerate() { + if symbol.name == in_symbol.name { + return Some(SymbolRef { section_idx: obj.sections.len(), symbol_idx }); + } } None } diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index 02f69b7..f1586c9 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -142,16 +142,20 @@ pub struct ObjReloc { pub target_section: Option, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct SymbolRef { pub section_idx: usize, pub symbol_idx: usize, } impl ObjInfo { - pub fn section_symbol(&self, symbol_ref: SymbolRef) -> (&ObjSection, &ObjSymbol) { + pub fn section_symbol(&self, symbol_ref: SymbolRef) -> (Option<&ObjSection>, &ObjSymbol) { + if symbol_ref.section_idx == self.sections.len() { + let symbol = &self.common[symbol_ref.symbol_idx]; + return (None, symbol); + } let section = &self.sections[symbol_ref.section_idx]; let symbol = §ion.symbols[symbol_ref.symbol_idx]; - (section, symbol) + (Some(section), symbol) } } diff --git a/objdiff-gui/src/views/function_diff.rs b/objdiff-gui/src/views/function_diff.rs index 8421782..b1d3b88 100644 --- a/objdiff-gui/src/views/function_diff.rs +++ b/objdiff-gui/src/views/function_diff.rs @@ -282,6 +282,7 @@ fn asm_col_ui( ins_view_state: &mut FunctionViewState, ) { let (section, symbol) = obj.0.section_symbol(symbol_ref); + let section = section.unwrap(); let ins_diff = &obj.1.symbol_diff(symbol_ref).instructions[row.index()]; let response_cb = |response: Response| { if let Some(ins) = &ins_diff.ins { diff --git a/objdiff-gui/src/views/symbol_diff.rs b/objdiff-gui/src/views/symbol_diff.rs index 58d0736..8dfb41e 100644 --- a/objdiff-gui/src/views/symbol_diff.rs +++ b/objdiff-gui/src/views/symbol_diff.rs @@ -7,7 +7,7 @@ use egui::{ use egui_extras::{Size, StripBuilder}; use objdiff_core::{ diff::{ObjDiff, ObjSymbolDiff}, - obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags}, + obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef}, }; use crate::{ @@ -52,7 +52,7 @@ pub struct DiffViewState { #[derive(Default)] pub struct SymbolViewState { - pub highlighted_symbol: Option, + pub highlighted_symbol: (Option, Option), pub selected_symbol: Option, pub reverse_fn_order: bool, pub disable_reverse_fn_order: bool, @@ -184,6 +184,7 @@ fn symbol_ui( section: Option<&ObjSection>, state: &mut SymbolViewState, appearance: &Appearance, + left: bool, ) -> Option { if symbol.flags.0.contains(ObjSymbolFlags::Hidden) && !state.show_hidden_symbols { return None; @@ -193,8 +194,10 @@ fn symbol_ui( let name: &str = if let Some(demangled) = &symbol.demangled_name { demangled } else { &symbol.name }; let mut selected = false; - if let Some(sym) = &state.highlighted_symbol { - selected = sym == &symbol.name; + if let Some(sym_ref) = + if left { state.highlighted_symbol.0 } else { state.highlighted_symbol.1 } + { + selected = symbol_diff.symbol_ref == sym_ref; } write_text("[", appearance.text_color, &mut job, appearance.code_font.clone()); if symbol.flags.0.contains(ObjSymbolFlags::Common) { @@ -245,7 +248,15 @@ fn symbol_ui( } } } else if response.hovered() { - state.highlighted_symbol = Some(symbol.name.clone()); + state.highlighted_symbol = if let Some(diff_symbol) = symbol_diff.diff_symbol { + if left { + (Some(symbol_diff.symbol_ref), Some(diff_symbol)) + } else { + (Some(diff_symbol), Some(symbol_diff.symbol_ref)) + } + } else { + (None, None) + }; } ret } @@ -267,6 +278,7 @@ fn symbol_list_ui( state: &mut SymbolViewState, lower_search: &str, appearance: &Appearance, + left: bool, ) -> Option { let mut ret = None; ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| { @@ -277,7 +289,15 @@ fn symbol_list_ui( if !obj.0.common.is_empty() { CollapsingHeader::new(".comm").default_open(true).show(ui, |ui| { for (symbol, symbol_diff) in obj.0.common.iter().zip(&obj.1.common) { - ret = ret.or(symbol_ui(ui, symbol, symbol_diff, None, state, appearance)); + ret = ret.or(symbol_ui( + ui, + symbol, + symbol_diff, + None, + state, + appearance, + left, + )); } }); } @@ -301,6 +321,7 @@ fn symbol_list_ui( Some(section), state, appearance, + left, )); } } else { @@ -317,6 +338,7 @@ fn symbol_list_ui( Some(section), state, appearance, + left, )); } } @@ -447,6 +469,7 @@ pub fn symbol_diff_ui(ui: &mut Ui, state: &mut DiffViewState, appearance: &Appea symbol_state, &lower_search, appearance, + true, )); } else { missing_obj_ui(ui, appearance); @@ -466,6 +489,7 @@ pub fn symbol_diff_ui(ui: &mut Ui, state: &mut DiffViewState, appearance: &Appea symbol_state, &lower_search, appearance, + false, )); } else { missing_obj_ui(ui, appearance);