mirror of https://github.com/encounter/objdiff.git
Implement diffing relocations within data sections (#154)
* Data view: Show data bytes with differing relocations as a diff * Data view: Show differing relocations on hover * Symbol list view: Adjust symbol/section match %s when relocations differ * Improve data reloc diffing logic * Don't make reloc diffs cause bytes to show as red or green * Properly detect byte size of each relocation * Data view: Add context menu for copying relocation target symbols * Also show already-matching relocations on hover/right click * Change font color for nonmatching relocs on hover
This commit is contained in:
parent
2876be37a3
commit
a4fdb61f04
|
@ -276,6 +276,19 @@ impl ObjArch for ObjArchArm {
|
|||
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str> {
|
||||
Cow::Owned(format!("<{flags:?}>"))
|
||||
}
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
|
||||
match flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_ARM_ABS32 => 4,
|
||||
elf::R_ARM_REL32 => 4,
|
||||
elf::R_ARM_ABS16 => 2,
|
||||
elf::R_ARM_ABS8 => 1,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
|
|
@ -173,6 +173,21 @@ impl ObjArch for ObjArchArm64 {
|
|||
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
|
||||
match flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_AARCH64_ABS64 => 8,
|
||||
elf::R_AARCH64_ABS32 => 4,
|
||||
elf::R_AARCH64_ABS16 => 2,
|
||||
elf::R_AARCH64_PREL64 => 8,
|
||||
elf::R_AARCH64_PREL32 => 4,
|
||||
elf::R_AARCH64_PREL16 => 2,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DisplayCtx<'a> {
|
||||
|
|
|
@ -271,6 +271,17 @@ impl ObjArch for ObjArchMips {
|
|||
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
|
||||
match flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_MIPS_16 => 2,
|
||||
elf::R_MIPS_32 => 4,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||
|
|
|
@ -148,6 +148,8 @@ pub trait ObjArch: Send + Sync {
|
|||
|
||||
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str>;
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize;
|
||||
|
||||
fn symbol_address(&self, symbol: &Symbol) -> u64 { symbol.address() }
|
||||
|
||||
fn guess_data_type(&self, _instruction: &ObjIns) -> Option<DataType> { None }
|
||||
|
|
|
@ -202,6 +202,17 @@ impl ObjArch for ObjArchPpc {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
|
||||
match flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_PPC_ADDR32 => 4,
|
||||
elf::R_PPC_UADDR32 => 4,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn guess_data_type(&self, instruction: &ObjIns) -> Option<super::DataType> {
|
||||
if instruction.reloc.as_ref().is_some_and(|r| r.target.name.starts_with("@stringBase")) {
|
||||
return Some(DataType::String);
|
||||
|
|
|
@ -162,6 +162,19 @@ impl ObjArch for ObjArchX86 {
|
|||
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
|
||||
match flags {
|
||||
RelocationFlags::Coff { typ } => match typ {
|
||||
pe::IMAGE_REL_I386_DIR16 => 2,
|
||||
pe::IMAGE_REL_I386_REL16 => 2,
|
||||
pe::IMAGE_REL_I386_DIR32 => 4,
|
||||
pe::IMAGE_REL_I386_REL32 => 4,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_arg(
|
||||
|
|
|
@ -196,7 +196,7 @@ fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
|
|||
left.target.address as i64 + left.addend == right.target.address as i64 + right.addend
|
||||
}
|
||||
|
||||
fn section_name_eq(
|
||||
pub fn section_name_eq(
|
||||
left_obj: &ObjInfo,
|
||||
right_obj: &ObjInfo,
|
||||
left_orig_section_index: usize,
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
use std::cmp::{max, min, Ordering};
|
||||
use std::{
|
||||
cmp::{max, min, Ordering},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use similar::{capture_diff_slices_deadline, get_diff_ratio, Algorithm};
|
||||
|
||||
use super::code::section_name_eq;
|
||||
use crate::{
|
||||
diff::{ObjDataDiff, ObjDataDiffKind, ObjSectionDiff, ObjSymbolDiff},
|
||||
obj::{ObjInfo, ObjSection, SymbolRef},
|
||||
obj::{ObjInfo, ObjReloc, ObjSection, ObjSymbolFlags, SymbolRef},
|
||||
};
|
||||
|
||||
pub fn diff_bss_symbol(
|
||||
|
@ -37,8 +41,110 @@ 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;
|
||||
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))
|
||||
}
|
||||
(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)
|
||||
}
|
||||
(None, None) => symbol_name_matches,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares relocations contained with a certain data range.
|
||||
/// The ObjDataDiffKind for each diff will either be `None`` (if the relocation matches),
|
||||
/// or `Replace` (if a relocation was changed, added, or removed).
|
||||
/// `Insert` and `Delete` are not used when a relocation is added or removed to avoid confusing diffs
|
||||
/// where it looks like the bytes themselves were changed but actually only the relocations changed.
|
||||
fn diff_data_relocs_for_range(
|
||||
left_obj: &ObjInfo,
|
||||
right_obj: &ObjInfo,
|
||||
left: &ObjSection,
|
||||
right: &ObjSection,
|
||||
left_range: Range<usize>,
|
||||
right_range: Range<usize>,
|
||||
) -> Vec<(ObjDataDiffKind, Option<ObjReloc>, Option<ObjReloc>)> {
|
||||
let mut diffs = Vec::new();
|
||||
for left_reloc in left.relocations.iter() {
|
||||
if !left_range.contains(&(left_reloc.address as usize)) {
|
||||
continue;
|
||||
}
|
||||
let left_offset = left_reloc.address as usize - left_range.start;
|
||||
let Some(right_reloc) = right.relocations.iter().find(|r| {
|
||||
if !right_range.contains(&(r.address as usize)) {
|
||||
return false;
|
||||
}
|
||||
let right_offset = r.address as usize - right_range.start;
|
||||
right_offset == left_offset
|
||||
}) else {
|
||||
diffs.push((ObjDataDiffKind::Replace, Some(left_reloc.clone()), None));
|
||||
continue;
|
||||
};
|
||||
if reloc_eq(left_obj, right_obj, left_reloc, right_reloc) {
|
||||
diffs.push((
|
||||
ObjDataDiffKind::None,
|
||||
Some(left_reloc.clone()),
|
||||
Some(right_reloc.clone()),
|
||||
));
|
||||
} else {
|
||||
diffs.push((
|
||||
ObjDataDiffKind::Replace,
|
||||
Some(left_reloc.clone()),
|
||||
Some(right_reloc.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
for right_reloc in right.relocations.iter() {
|
||||
if !right_range.contains(&(right_reloc.address as usize)) {
|
||||
continue;
|
||||
}
|
||||
let right_offset = right_reloc.address as usize - right_range.start;
|
||||
let Some(_) = left.relocations.iter().find(|r| {
|
||||
if !left_range.contains(&(r.address as usize)) {
|
||||
return false;
|
||||
}
|
||||
let left_offset = r.address as usize - left_range.start;
|
||||
left_offset == right_offset
|
||||
}) else {
|
||||
diffs.push((ObjDataDiffKind::Replace, None, Some(right_reloc.clone())));
|
||||
continue;
|
||||
};
|
||||
// No need to check the cases for relocations being deleted or matching again.
|
||||
// They were already handled in the loop over the left relocs.
|
||||
}
|
||||
diffs
|
||||
}
|
||||
|
||||
/// Compare the data sections of two object files.
|
||||
pub fn diff_data_section(
|
||||
left_obj: &ObjInfo,
|
||||
right_obj: &ObjInfo,
|
||||
left: &ObjSection,
|
||||
right: &ObjSection,
|
||||
left_section_diff: &ObjSectionDiff,
|
||||
|
@ -70,6 +176,94 @@ pub fn diff_data_section(
|
|||
ObjDataDiffKind::Replace
|
||||
}
|
||||
};
|
||||
if kind == ObjDataDiffKind::None {
|
||||
let mut found_any_relocs = false;
|
||||
let mut left_curr_addr = left_range.start;
|
||||
let mut right_curr_addr = right_range.start;
|
||||
for (diff_kind, left_reloc, right_reloc) in diff_data_relocs_for_range(
|
||||
left_obj,
|
||||
right_obj,
|
||||
left,
|
||||
right,
|
||||
left_range.clone(),
|
||||
right_range.clone(),
|
||||
) {
|
||||
found_any_relocs = true;
|
||||
|
||||
if let Some(left_reloc) = left_reloc {
|
||||
let left_reloc_addr = left_reloc.address as usize;
|
||||
if left_reloc_addr > left_curr_addr {
|
||||
let len = left_reloc_addr - left_curr_addr;
|
||||
let left_data = &left.data[left_curr_addr..left_reloc_addr];
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data[..min(len, left_data.len())].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
let reloc_diff_len = left_obj.arch.get_reloc_byte_size(left_reloc.flags);
|
||||
let left_data = &left.data[left_reloc_addr..left_reloc_addr + reloc_diff_len];
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data[..min(reloc_diff_len, left_data.len())].to_vec(),
|
||||
kind: diff_kind,
|
||||
len: reloc_diff_len,
|
||||
reloc: Some(left_reloc.clone()),
|
||||
..Default::default()
|
||||
});
|
||||
left_curr_addr = left_reloc_addr + reloc_diff_len;
|
||||
}
|
||||
|
||||
if let Some(right_reloc) = right_reloc {
|
||||
let right_reloc_addr = right_reloc.address as usize;
|
||||
if right_reloc_addr > right_curr_addr {
|
||||
let len = right_reloc_addr - right_curr_addr;
|
||||
let right_data = &right.data[right_curr_addr..right_reloc_addr];
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data[..min(len, right_data.len())].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
let reloc_diff_len = right_obj.arch.get_reloc_byte_size(right_reloc.flags);
|
||||
let right_data =
|
||||
&right.data[right_reloc_addr..right_reloc_addr + reloc_diff_len];
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data[..min(reloc_diff_len, right_data.len())].to_vec(),
|
||||
kind: diff_kind,
|
||||
len: reloc_diff_len,
|
||||
reloc: Some(right_reloc.clone()),
|
||||
..Default::default()
|
||||
});
|
||||
right_curr_addr = right_reloc_addr + reloc_diff_len;
|
||||
}
|
||||
}
|
||||
|
||||
if found_any_relocs {
|
||||
if left_curr_addr < left_range.end - 1 {
|
||||
let len = left_range.end - left_curr_addr;
|
||||
let left_data = &left.data[left_curr_addr..left_range.end];
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data[..min(len, left_data.len())].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
if right_curr_addr < right_range.end - 1 {
|
||||
let len = right_range.end - right_curr_addr;
|
||||
let right_data = &right.data[right_curr_addr..right_range.end];
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data[..min(len, right_data.len())].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let left_data = &left.data[left_range];
|
||||
let right_data = &right.data[right_range];
|
||||
left_diff.push(ObjDataDiff {
|
||||
|
@ -123,14 +317,19 @@ pub fn diff_data_section(
|
|||
|
||||
let (mut left_section_diff, mut right_section_diff) =
|
||||
diff_generic_section(left, right, left_section_diff, right_section_diff)?;
|
||||
let all_left_relocs_match =
|
||||
left_diff.iter().all(|d| d.kind == ObjDataDiffKind::None || d.reloc.is_none());
|
||||
left_section_diff.data_diff = left_diff;
|
||||
right_section_diff.data_diff = right_diff;
|
||||
// Use the highest match percent between two options:
|
||||
// - Left symbols matching right symbols by name
|
||||
// - Diff of the data itself
|
||||
if left_section_diff.match_percent.unwrap_or(-1.0) < match_percent {
|
||||
left_section_diff.match_percent = Some(match_percent);
|
||||
right_section_diff.match_percent = Some(match_percent);
|
||||
if all_left_relocs_match {
|
||||
// Use the highest match percent between two options:
|
||||
// - Left symbols matching right symbols by name
|
||||
// - Diff of the data itself
|
||||
// We only do this when all relocations on the left side match.
|
||||
if left_section_diff.match_percent.unwrap_or(-1.0) < match_percent {
|
||||
left_section_diff.match_percent = Some(match_percent);
|
||||
right_section_diff.match_percent = Some(match_percent);
|
||||
}
|
||||
}
|
||||
Ok((left_section_diff, right_section_diff))
|
||||
}
|
||||
|
@ -147,13 +346,54 @@ pub fn diff_data_symbol(
|
|||
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 left_range = left_symbol.section_address as usize
|
||||
..(left_symbol.section_address + left_symbol.size) as usize;
|
||||
let right_range = right_symbol.section_address as usize
|
||||
..(right_symbol.section_address + right_symbol.size) as usize;
|
||||
let left_data = &left_section.data[left_range.clone()];
|
||||
let right_data = &right_section.data[right_range.clone()];
|
||||
|
||||
let reloc_diffs = diff_data_relocs_for_range(
|
||||
left_obj,
|
||||
right_obj,
|
||||
left_section,
|
||||
right_section,
|
||||
left_range,
|
||||
right_range,
|
||||
);
|
||||
|
||||
let ops = capture_diff_slices_deadline(Algorithm::Patience, left_data, right_data, None);
|
||||
let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0;
|
||||
let bytes_match_ratio = get_diff_ratio(&ops, left_data.len(), right_data.len());
|
||||
|
||||
let mut match_ratio = bytes_match_ratio;
|
||||
if !reloc_diffs.is_empty() {
|
||||
let mut total_reloc_bytes = 0;
|
||||
let mut matching_reloc_bytes = 0;
|
||||
for (diff_kind, left_reloc, right_reloc) in reloc_diffs {
|
||||
let reloc_diff_len = match (left_reloc, right_reloc) {
|
||||
(None, None) => unreachable!(),
|
||||
(None, Some(right_reloc)) => right_obj.arch.get_reloc_byte_size(right_reloc.flags),
|
||||
(Some(left_reloc), _) => left_obj.arch.get_reloc_byte_size(left_reloc.flags),
|
||||
};
|
||||
total_reloc_bytes += reloc_diff_len;
|
||||
if diff_kind == ObjDataDiffKind::None {
|
||||
matching_reloc_bytes += reloc_diff_len;
|
||||
}
|
||||
}
|
||||
if total_reloc_bytes > 0 {
|
||||
let relocs_match_ratio = matching_reloc_bytes as f32 / total_reloc_bytes as f32;
|
||||
// Adjust the overall match ratio to include relocation differences.
|
||||
// We calculate it so that bytes that contain a relocation are counted twice: once for the
|
||||
// byte's raw value, and once for its relocation.
|
||||
// e.g. An 8 byte symbol that has 8 matching raw bytes and a single 4 byte relocation that
|
||||
// doesn't match would show as 66% (weighted average of 100% and 0%).
|
||||
match_ratio = ((bytes_match_ratio * (left_data.len() as f32))
|
||||
+ (relocs_match_ratio * total_reloc_bytes as f32))
|
||||
/ (left_data.len() + total_reloc_bytes) as f32;
|
||||
}
|
||||
}
|
||||
|
||||
let match_percent = match_ratio * 100.0;
|
||||
|
||||
Ok((
|
||||
ObjSymbolDiff {
|
||||
|
|
|
@ -11,7 +11,9 @@ use crate::{
|
|||
diff_generic_section, no_diff_symbol,
|
||||
},
|
||||
},
|
||||
obj::{ObjInfo, ObjIns, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef, SECTION_COMMON},
|
||||
obj::{
|
||||
ObjInfo, ObjIns, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, SymbolRef, SECTION_COMMON,
|
||||
},
|
||||
};
|
||||
|
||||
pub mod code;
|
||||
|
@ -85,6 +87,7 @@ pub struct ObjDataDiff {
|
|||
pub kind: ObjDataDiffKind,
|
||||
pub len: usize,
|
||||
pub symbol: String,
|
||||
pub reloc: Option<ObjReloc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
|
@ -153,6 +156,7 @@ impl ObjDiff {
|
|||
kind: ObjDataDiffKind::None,
|
||||
len: section.data.len(),
|
||||
symbol: section.name.clone(),
|
||||
..Default::default()
|
||||
}],
|
||||
match_percent: None,
|
||||
});
|
||||
|
@ -345,6 +349,8 @@ pub fn diff_objs(
|
|||
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_data_section(
|
||||
left_obj,
|
||||
right_obj,
|
||||
left_section,
|
||||
right_section,
|
||||
left_section_diff,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::{cmp::min, default::Default, mem::take};
|
||||
use std::{
|
||||
cmp::{min, Ordering},
|
||||
default::Default,
|
||||
mem::take,
|
||||
};
|
||||
|
||||
use egui::{text::LayoutJob, Id, Label, RichText, Sense, Widget};
|
||||
use objdiff_core::{
|
||||
|
@ -23,7 +27,88 @@ fn find_section(obj: &ObjInfo, section_name: &str) -> Option<usize> {
|
|||
obj.sections.iter().position(|section| section.name == section_name)
|
||||
}
|
||||
|
||||
fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff], appearance: &Appearance) {
|
||||
fn data_row_hover_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: &ObjInfo,
|
||||
diffs: &[ObjDataDiff],
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
for diff in diffs {
|
||||
let Some(reloc) = &diff.reloc else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Use a slightly different font color for nonmatching relocations so they stand out.
|
||||
let color = match diff.kind {
|
||||
ObjDataDiffKind::None => appearance.highlight_color,
|
||||
_ => appearance.replace_color,
|
||||
};
|
||||
|
||||
// TODO: Most of this code is copy-pasted from ins_hover_ui.
|
||||
// Try to separate this out into a shared function.
|
||||
ui.label(format!("Relocation type: {}", obj.arch.display_reloc(reloc.flags)));
|
||||
let addend_str = match reloc.addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:x}", reloc.addend),
|
||||
Ordering::Less => format!("-{:x}", -reloc.addend),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
ui.colored_label(color, format!("Name: {}{}", reloc.target.name, addend_str));
|
||||
if let Some(orig_section_index) = reloc.target.orig_section_index {
|
||||
if let Some(section) =
|
||||
obj.sections.iter().find(|s| s.orig_index == orig_section_index)
|
||||
{
|
||||
ui.colored_label(color, format!("Section: {}", section.name));
|
||||
}
|
||||
ui.colored_label(
|
||||
color,
|
||||
format!("Address: {:x}{}", reloc.target.address, addend_str),
|
||||
);
|
||||
ui.colored_label(color, format!("Size: {:x}", reloc.target.size));
|
||||
if reloc.addend >= 0 && reloc.target.bytes.len() > reloc.addend as usize {}
|
||||
} else {
|
||||
ui.colored_label(color, "Extern".to_string());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn data_row_context_menu(ui: &mut egui::Ui, diffs: &[ObjDataDiff]) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
for diff in diffs {
|
||||
let Some(reloc) = &diff.reloc else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// TODO: This code is copy-pasted from ins_context_menu.
|
||||
// Try to separate this out into a shared function.
|
||||
if let Some(name) = &reloc.target.demangled_name {
|
||||
if ui.button(format!("Copy \"{name}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text.clone_from(name));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
if ui.button(format!("Copy \"{}\"", reloc.target.name)).clicked() {
|
||||
ui.output_mut(|output| output.copied_text.clone_from(&reloc.target.name));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn data_row_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: Option<&ObjInfo>,
|
||||
address: usize,
|
||||
diffs: &[ObjDataDiff],
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
if diffs.iter().any(|d| d.kind != ObjDataDiffKind::None) {
|
||||
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
||||
}
|
||||
|
@ -94,9 +179,13 @@ fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff], appeara
|
|||
write_text(text.as_str(), base_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
}
|
||||
Label::new(job).sense(Sense::click()).ui(ui);
|
||||
// .on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, ins))
|
||||
// .context_menu(|ui| ins_context_menu(ui, ins));
|
||||
|
||||
let response = Label::new(job).sense(Sense::click()).ui(ui);
|
||||
if let Some(obj) = obj {
|
||||
response
|
||||
.on_hover_ui_at_pointer(|ui| data_row_hover_ui(ui, obj, diffs, appearance))
|
||||
.context_menu(|ui| data_row_context_menu(ui, diffs));
|
||||
}
|
||||
}
|
||||
|
||||
fn split_diffs(diffs: &[ObjDataDiff]) -> Vec<Vec<ObjDataDiff>> {
|
||||
|
@ -117,8 +206,8 @@ fn split_diffs(diffs: &[ObjDataDiff]) -> Vec<Vec<ObjDataDiff>> {
|
|||
},
|
||||
kind: diff.kind,
|
||||
len,
|
||||
// TODO
|
||||
symbol: String::new(),
|
||||
symbol: String::new(), // TODO
|
||||
reloc: diff.reloc.clone(),
|
||||
});
|
||||
remaining_in_row -= len;
|
||||
cur_len += len;
|
||||
|
@ -161,6 +250,8 @@ fn data_table_ui(
|
|||
right_ctx: Option<SectionDiffContext<'_>>,
|
||||
config: &Appearance,
|
||||
) -> Option<()> {
|
||||
let left_obj = left_ctx.map(|ctx| ctx.obj);
|
||||
let right_obj = right_ctx.map(|ctx| ctx.obj);
|
||||
let left_section = left_ctx
|
||||
.and_then(|ctx| ctx.section_index.map(|i| (&ctx.obj.sections[i], &ctx.diff.sections[i])));
|
||||
let right_section = right_ctx
|
||||
|
@ -187,11 +278,11 @@ fn data_table_ui(
|
|||
row.col(|ui| {
|
||||
if column == 0 {
|
||||
if let Some(left_diffs) = &left_diffs {
|
||||
data_row_ui(ui, address, &left_diffs[i], config);
|
||||
data_row_ui(ui, left_obj, address, &left_diffs[i], config);
|
||||
}
|
||||
} else if column == 1 {
|
||||
if let Some(right_diffs) = &right_diffs {
|
||||
data_row_ui(ui, address, &right_diffs[i], config);
|
||||
data_row_ui(ui, right_obj, address, &right_diffs[i], config);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue