From e254af5acf07dc4935647f3248a3923a913e3760 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 21 May 2024 12:02:00 -0600 Subject: [PATCH] Support bss and text section diffing Display section diff % in symbols view --- objdiff-core/src/diff/data.rs | 53 ++++++++++++++++++++++++++-- objdiff-core/src/diff/mod.rs | 22 +++++++++--- objdiff-gui/src/views/symbol_diff.rs | 27 +++++++++++++- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index e8882d7..ceffa83 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -11,6 +11,27 @@ use crate::{ obj::{ObjInfo, ObjSection, SymbolRef}, }; +/// Compare the addresses and sizes of each symbol in the BSS sections. +pub fn diff_bss_section( + left: &ObjSection, + right: &ObjSection, +) -> Result<(ObjSectionDiff, ObjSectionDiff)> { + let deadline = Instant::now() + Duration::from_secs(5); + let left_sizes = left.symbols.iter().map(|s| (s.section_address, s.size)).collect::>(); + let right_sizes = right.symbols.iter().map(|s| (s.section_address, s.size)).collect::>(); + let ops = capture_diff_slices_deadline( + Algorithm::Patience, + &left_sizes, + &right_sizes, + Some(deadline), + ); + let match_percent = get_diff_ratio(&ops, left_sizes.len(), right_sizes.len()) * 100.0; + Ok(( + ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) }, + ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) }, + )) +} + pub fn diff_bss_symbol( left_obj: &ObjInfo, right_obj: &ObjInfo, @@ -40,14 +61,19 @@ 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( +/// Compare the data sections of two object files. +pub fn diff_data_section( left: &ObjSection, right: &ObjSection, ) -> Result<(ObjSectionDiff, ObjSectionDiff)> { let deadline = Instant::now() + Duration::from_secs(5); + let left_max = left.symbols.iter().map(|s| s.section_address + s.size).max().unwrap_or(0); + let right_max = right.symbols.iter().map(|s| s.section_address + s.size).max().unwrap_or(0); + let left_data = &left.data[..left_max as usize]; + let right_data = &right.data[..right_max as usize]; 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; + 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(); @@ -168,3 +194,24 @@ pub fn diff_data_symbol( }, )) } + +/// Compare the text sections of two object files. +/// This essentially adds up the match percentage of each symbol in the text section. +pub fn diff_text_section( + left: &ObjSection, + _right: &ObjSection, + left_diff: &ObjSectionDiff, + _right_diff: &ObjSectionDiff, +) -> Result<(ObjSectionDiff, ObjSectionDiff)> { + let match_percent = left + .symbols + .iter() + .zip(left_diff.symbols.iter()) + .map(|(s, d)| d.match_percent.unwrap_or(0.0) * s.size as f32) + .sum::() + / left.size as f32; + Ok(( + ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) }, + ObjSectionDiff { symbols: vec![], data_diff: vec![], match_percent: Some(match_percent) }, + )) +} diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index de8d3ea..a194d5f 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -5,7 +5,10 @@ use anyhow::Result; use crate::{ diff::{ code::{diff_code, no_diff_code}, - data::{diff_bss_symbol, diff_data, diff_data_symbol, no_diff_symbol}, + data::{ + diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol, + diff_text_section, no_diff_symbol, + }, }, obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef}, }; @@ -324,15 +327,26 @@ pub fn diff_objs( let right_section = &right_obj.sections[right_section_idx]; match section_kind { ObjSectionKind::Code => { - // TODO? + let left_section_diff = left_out.section_diff(left_section_idx); + let right_section_diff = right_out.section_diff(right_section_idx); + let (left_diff, right_diff) = diff_text_section( + left_section, + right_section, + left_section_diff, + right_section_diff, + )?; + left_out.section_diff_mut(left_section_idx).merge(left_diff); + right_out.section_diff_mut(right_section_idx).merge(right_diff); } ObjSectionKind::Data => { - let (left_diff, right_diff) = diff_data(left_section, right_section)?; + let (left_diff, right_diff) = diff_data_section(left_section, right_section)?; left_out.section_diff_mut(left_section_idx).merge(left_diff); right_out.section_diff_mut(right_section_idx).merge(right_diff); } ObjSectionKind::Bss => { - // TODO + let (left_diff, right_diff) = diff_bss_section(left_section, right_section)?; + left_out.section_diff_mut(left_section_idx).merge(left_diff); + right_out.section_diff_mut(right_section_idx).merge(right_diff); } } } diff --git a/objdiff-gui/src/views/symbol_diff.rs b/objdiff-gui/src/views/symbol_diff.rs index 8dfb41e..7dadf98 100644 --- a/objdiff-gui/src/views/symbol_diff.rs +++ b/objdiff-gui/src/views/symbol_diff.rs @@ -303,7 +303,32 @@ fn symbol_list_ui( } for (section, section_diff) in obj.0.sections.iter().zip(&obj.1.sections) { - CollapsingHeader::new(format!("{} ({:x})", section.name, section.size)) + let mut header = LayoutJob::simple_singleline( + format!("{} ({:x})", section.name, section.size), + appearance.code_font.clone(), + Color32::PLACEHOLDER, + ); + if let Some(match_percent) = section_diff.match_percent { + write_text( + " (", + Color32::PLACEHOLDER, + &mut header, + appearance.code_font.clone(), + ); + write_text( + &format!("{match_percent:.0}%"), + match_color_for_symbol(match_percent, appearance), + &mut header, + appearance.code_font.clone(), + ); + write_text( + ")", + Color32::PLACEHOLDER, + &mut header, + appearance.code_font.clone(), + ); + } + CollapsingHeader::new(header) .id_source(Id::new(section.name.clone()).with(section.orig_index)) .default_open(true) .show(ui, |ui| {