Check relocation addends when diffing functions (#158)

* Check relocation addends when diffing functions

* Also highlight addend when reloc differs
This commit is contained in:
LagoLunatic 2025-02-10 00:26:49 -05:00 committed by GitHub
parent 674c942d7d
commit 3e6efb7736
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 34 deletions

View File

@ -1,3 +1,5 @@
use std::cmp::Ordering;
use anyhow::{bail, Result};
use crossterm::event::{Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind};
use objdiff_core::{
@ -563,6 +565,18 @@ impl FunctionDiffUi {
base_color = Color::White;
}
}
DiffText::Addend(addend, diff) => {
label_text = match addend.cmp(&0i64) {
Ordering::Greater => format!("+{:#x}", addend),
Ordering::Less => format!("-{:#x}", -addend),
_ => "".to_string(),
};
if let Some(diff) = diff {
base_color = COLOR_ROTATION[diff.idx % COLOR_ROTATION.len()]
} else {
base_color = Color::White;
}
}
DiffText::Spacing(n) => {
line.spans.push(Span::raw(" ".repeat(n)));
sx += n as u16;

View File

@ -192,8 +192,18 @@ fn resolve_branches(vec: &mut [ObjInsDiff]) {
}
}
fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
pub fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
if right.target.size == 0 && left.target.size != 0 {
// The base relocation is against a pool but the target relocation isn't.
// This can happen in rare cases where the compiler will generate a pool+addend relocation
// in the base's data, but the one detected in the target is direct with no addend.
// Just check that the final address is the same so these count as a match.
left.target.address as i64 + left.addend == right.target.address as i64 + right.addend
} else {
// But otherwise, if the compiler isn't using a pool, we're more strict and check that the
// target symbol address and relocation addend both match exactly.
left.target.address == right.target.address && left.addend == right.addend
}
}
pub fn section_name_eq(
@ -235,13 +245,14 @@ fn reloc_eq(
return true;
}
let symbol_name_matches = left.target.name == right.target.name;
let symbol_name_addend_matches =
left.target.name == right.target.name && left.addend == right.addend;
match (&left.target.orig_section_index, &right.target.orig_section_index) {
(Some(sl), Some(sr)) => {
// Match if section and name or address match
// Match if section and name+addend or address match
section_name_eq(left_obj, right_obj, *sl, *sr)
&& (config.function_reloc_diffs == FunctionRelocDiffs::DataValue
|| symbol_name_matches
|| symbol_name_addend_matches
|| address_eq(left, right))
&& (config.function_reloc_diffs == FunctionRelocDiffs::NameAddress
|| left.target.kind != ObjSymbolKind::Object
@ -251,9 +262,9 @@ fn reloc_eq(
(Some(_), None) => false,
(None, Some(_)) => {
// Match if possibly stripped weak symbol
symbol_name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
symbol_name_addend_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
}
(None, None) => symbol_name_matches,
(None, None) => symbol_name_addend_matches,
}
}

View File

@ -6,7 +6,7 @@ use std::{
use anyhow::{anyhow, Result};
use similar::{capture_diff_slices_deadline, get_diff_ratio, Algorithm};
use super::code::section_name_eq;
use super::code::{address_eq, section_name_eq};
use crate::{
diff::{ObjDataDiff, ObjDataDiffKind, ObjDataRelocDiff, ObjSectionDiff, ObjSymbolDiff},
obj::{ObjInfo, ObjReloc, ObjSection, ObjSymbolFlags, SymbolRef},
@ -41,39 +41,25 @@ pub fn no_diff_symbol(_obj: &ObjInfo, symbol_ref: SymbolRef) -> ObjSymbolDiff {
ObjSymbolDiff { symbol_ref, target_symbol: None, instructions: vec![], match_percent: None }
}
fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
if right.target.size == 0 && left.target.size != 0 {
// The base relocation is against a pool but the target relocation isn't.
// This can happen in rare cases where the compiler will generate a pool+addend relocation
// in the base, but the one detected in the target is direct with no addend.
// Just check that the final address is the same so these count as a match.
left.target.address as i64 + left.addend == right.target.address as i64 + right.addend
} else {
// But otherwise, if the compiler isn't using a pool, we're more strict and check that the
// target symbol address and relocation addend both match exactly.
left.target.address == right.target.address && left.addend == right.addend
}
}
fn reloc_eq(left_obj: &ObjInfo, right_obj: &ObjInfo, left: &ObjReloc, right: &ObjReloc) -> bool {
if left.flags != right.flags {
return false;
}
let symbol_name_matches = left.target.name == right.target.name;
let symbol_name_addend_matches =
left.target.name == right.target.name && left.addend == right.addend;
match (&left.target.orig_section_index, &right.target.orig_section_index) {
(Some(sl), Some(sr)) => {
// Match if section and name+addend or address match
section_name_eq(left_obj, right_obj, *sl, *sr)
&& ((symbol_name_matches && left.addend == right.addend) || address_eq(left, right))
&& (symbol_name_addend_matches || address_eq(left, right))
}
(Some(_), None) => false,
(None, Some(_)) => {
// Match if possibly stripped weak symbol
(symbol_name_matches && left.addend == right.addend)
&& right.target.flags.0.contains(ObjSymbolFlags::Weak)
symbol_name_addend_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
}
(None, None) => symbol_name_matches,
(None, None) => symbol_name_addend_matches,
}
}

View File

@ -1,5 +1,3 @@
use std::cmp::Ordering;
use crate::{
diff::{ObjInsArgDiff, ObjInsDiff},
obj::{ObjInsArg, ObjInsArgValue, ObjReloc, ObjSymbol},
@ -23,6 +21,8 @@ pub enum DiffText<'a> {
BranchDest(u64, Option<&'a ObjInsArgDiff>),
/// Symbol name
Symbol(&'a ObjSymbol, Option<&'a ObjInsArgDiff>),
/// Relocation addend
Addend(i64, Option<&'a ObjInsArgDiff>),
/// Number of spaces
Spacing(usize),
/// End of line
@ -99,11 +99,7 @@ fn display_reloc_name<E>(
diff: Option<&ObjInsArgDiff>,
) -> Result<(), E> {
cb(DiffText::Symbol(&reloc.target, diff))?;
match reloc.addend.cmp(&0i64) {
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))),
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))),
_ => Ok(()),
}
cb(DiffText::Addend(reloc.addend, diff))
}
impl PartialEq<DiffText<'_>> for HighlightKind {

View File

@ -324,6 +324,18 @@ fn diff_text_ui(
base_color = appearance.emphasized_text_color;
}
}
DiffText::Addend(addend, diff) => {
label_text = match addend.cmp(&0i64) {
Ordering::Greater => format!("+{:#x}", addend),
Ordering::Less => format!("-{:#x}", -addend),
_ => "".to_string(),
};
if let Some(diff) = diff {
base_color = appearance.diff_colors[diff.idx % appearance.diff_colors.len()]
} else {
base_color = appearance.emphasized_text_color;
}
}
DiffText::Spacing(n) => {
ui.add_space(n as f32 * space_width);
return ret;