mirror of
https://github.com/encounter/objdiff.git
synced 2025-10-05 09:29:51 +00:00
Refactor data diffing & expose WASM API (#256)
* Refactor data diffing & expose WASM API * Update test snapshots
This commit is contained in:
parent
f7cb494a62
commit
fbdaa89cc0
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -3435,7 +3435,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "3.1.1"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@ -3458,7 +3458,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "3.1.1"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@ -3513,7 +3513,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "3.1.1"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@ -3550,7 +3550,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-wasm"
|
||||
version = "3.1.1"
|
||||
version = "3.2.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objdiff-core",
|
||||
|
@ -14,7 +14,7 @@ default-members = [
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "3.1.1"
|
||||
version = "3.2.0"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
@ -5,7 +5,7 @@ use anyhow::{Result, anyhow};
|
||||
use similar::{Algorithm, capture_diff_slices, get_diff_ratio};
|
||||
|
||||
use super::{
|
||||
DataDiff, DataDiffKind, DataRelocationDiff, ObjectDiff, SectionDiff, SymbolDiff,
|
||||
DataDiff, DataDiffKind, DataDiffRow, DataRelocationDiff, ObjectDiff, SectionDiff, SymbolDiff,
|
||||
code::{address_eq, section_name_eq},
|
||||
};
|
||||
use crate::obj::{Object, Relocation, ResolvedRelocation, Symbol, SymbolFlag, SymbolKind};
|
||||
@ -111,14 +111,12 @@ fn diff_data_range(left_data: &[u8], right_data: &[u8]) -> (f32, Vec<DataDiff>,
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[..len.min(left_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[..len.min(right_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
if kind == DataDiffKind::Replace {
|
||||
match left_len.cmp(&right_len) {
|
||||
@ -127,14 +125,12 @@ fn diff_data_range(left_data: &[u8], right_data: &[u8]) -> (f32, Vec<DataDiff>,
|
||||
left_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[left_len..right_len].to_vec(),
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
}
|
||||
Ordering::Greater => {
|
||||
@ -142,14 +138,12 @@ fn diff_data_range(left_data: &[u8], right_data: &[u8]) -> (f32, Vec<DataDiff>,
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[right_len..left_len].to_vec(),
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
size: len,
|
||||
});
|
||||
}
|
||||
Ordering::Equal => {}
|
||||
@ -219,16 +213,17 @@ fn diff_data_relocs_for_range<'left, 'right>(
|
||||
|
||||
pub fn no_diff_data_section(obj: &Object, section_idx: usize) -> Result<SectionDiff> {
|
||||
let section = &obj.sections[section_idx];
|
||||
let len = section.data.len();
|
||||
let data = §ion.data[0..len];
|
||||
|
||||
let data_diff =
|
||||
vec![DataDiff { data: data.to_vec(), kind: DataDiffKind::None, len, ..Default::default() }];
|
||||
let data_diff = vec![DataDiff {
|
||||
data: section.data.0.clone(),
|
||||
kind: DataDiffKind::None,
|
||||
size: section.data.len(),
|
||||
}];
|
||||
|
||||
let mut reloc_diffs = Vec::new();
|
||||
for reloc in section.relocations.iter() {
|
||||
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
||||
let range = reloc.address as usize..reloc.address as usize + reloc_len;
|
||||
let range = reloc.address..reloc.address + reloc_len as u64;
|
||||
reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: reloc.clone(),
|
||||
kind: DataDiffKind::None,
|
||||
@ -279,8 +274,7 @@ pub fn diff_data_section(
|
||||
) {
|
||||
if let Some(left_reloc) = left_reloc {
|
||||
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
||||
let range = left_reloc.relocation.address as usize
|
||||
..left_reloc.relocation.address as usize + len;
|
||||
let range = left_reloc.relocation.address..left_reloc.relocation.address + len as u64;
|
||||
left_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: left_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
@ -289,8 +283,7 @@ pub fn diff_data_section(
|
||||
}
|
||||
if let Some(right_reloc) = right_reloc {
|
||||
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
||||
let range = right_reloc.relocation.address as usize
|
||||
..right_reloc.relocation.address as usize + len;
|
||||
let range = right_reloc.relocation.address..right_reloc.relocation.address + len as u64;
|
||||
right_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: right_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
@ -345,9 +338,11 @@ pub fn no_diff_data_symbol(obj: &Object, symbol_index: usize) -> Result<SymbolDi
|
||||
let range = start as usize..end as usize;
|
||||
let data = §ion.data[range.clone()];
|
||||
|
||||
let len = symbol.size as usize;
|
||||
let data_diff =
|
||||
vec![DataDiff { data: data.to_vec(), kind: DataDiffKind::None, len, ..Default::default() }];
|
||||
let data_diff = vec![DataDiff {
|
||||
data: data.to_vec(),
|
||||
kind: DataDiffKind::None,
|
||||
size: symbol.size as usize,
|
||||
}];
|
||||
|
||||
let mut reloc_diffs = Vec::new();
|
||||
for reloc in section.relocations.iter() {
|
||||
@ -355,7 +350,7 @@ pub fn no_diff_data_symbol(obj: &Object, symbol_index: usize) -> Result<SymbolDi
|
||||
continue;
|
||||
}
|
||||
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
||||
let range = reloc.address as usize..reloc.address as usize + reloc_len;
|
||||
let range = reloc.address..reloc.address + reloc_len as u64;
|
||||
reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: reloc.clone(),
|
||||
kind: DataDiffKind::None,
|
||||
@ -363,12 +358,12 @@ pub fn no_diff_data_symbol(obj: &Object, symbol_index: usize) -> Result<SymbolDi
|
||||
});
|
||||
}
|
||||
|
||||
let data_rows = build_data_diff_rows(&data_diff, &reloc_diffs, symbol.address);
|
||||
Ok(SymbolDiff {
|
||||
target_symbol: None,
|
||||
match_percent: None,
|
||||
diff_score: None,
|
||||
data_diff,
|
||||
data_reloc_diff: reloc_diffs,
|
||||
data_rows,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
@ -454,8 +449,8 @@ pub fn diff_data_symbol(
|
||||
|
||||
if let Some(left_reloc) = left_reloc {
|
||||
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
||||
let range = left_reloc.relocation.address as usize
|
||||
..left_reloc.relocation.address as usize + len;
|
||||
let range =
|
||||
left_reloc.relocation.address..left_reloc.relocation.address + len as u64;
|
||||
left_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: left_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
@ -464,8 +459,8 @@ pub fn diff_data_symbol(
|
||||
}
|
||||
if let Some(right_reloc) = right_reloc {
|
||||
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
||||
let range = right_reloc.relocation.address as usize
|
||||
..right_reloc.relocation.address as usize + len;
|
||||
let range =
|
||||
right_reloc.relocation.address..right_reloc.relocation.address + len as u64;
|
||||
right_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: right_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
@ -486,23 +481,29 @@ pub fn diff_data_symbol(
|
||||
}
|
||||
}
|
||||
|
||||
left_reloc_diffs
|
||||
.sort_by(|a, b| a.range.start.cmp(&b.range.start).then(a.range.end.cmp(&b.range.end)));
|
||||
right_reloc_diffs
|
||||
.sort_by(|a, b| a.range.start.cmp(&b.range.start).then(a.range.end.cmp(&b.range.end)));
|
||||
|
||||
let match_percent = match_ratio * 100.0;
|
||||
let left_rows = build_data_diff_rows(&left_data_diff, &left_reloc_diffs, left_symbol.address);
|
||||
let right_rows =
|
||||
build_data_diff_rows(&right_data_diff, &right_reloc_diffs, right_symbol.address);
|
||||
|
||||
Ok((
|
||||
SymbolDiff {
|
||||
target_symbol: Some(right_symbol_idx),
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: None,
|
||||
data_diff: left_data_diff,
|
||||
data_reloc_diff: left_reloc_diffs,
|
||||
data_rows: left_rows,
|
||||
..Default::default()
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(left_symbol_idx),
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: None,
|
||||
data_diff: right_data_diff,
|
||||
data_reloc_diff: right_reloc_diffs,
|
||||
data_rows: right_rows,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
@ -593,3 +594,68 @@ fn symbols_matching_section(
|
||||
&& !s.flags.contains(SymbolFlag::Ignored)
|
||||
})
|
||||
}
|
||||
|
||||
pub const BYTES_PER_ROW: usize = 16;
|
||||
|
||||
fn build_data_diff_row(
|
||||
data_diffs: &[DataDiff],
|
||||
reloc_diffs: &[DataRelocationDiff],
|
||||
symbol_address: u64,
|
||||
row_index: usize,
|
||||
) -> DataDiffRow {
|
||||
let row_start = row_index * BYTES_PER_ROW;
|
||||
let row_end = row_start + BYTES_PER_ROW;
|
||||
let mut row_diff = DataDiffRow {
|
||||
address: symbol_address + row_start as u64,
|
||||
segments: Vec::new(),
|
||||
relocations: Vec::new(),
|
||||
};
|
||||
|
||||
// Collect all segments that overlap with this row
|
||||
let mut current_offset = 0;
|
||||
for diff in data_diffs {
|
||||
let diff_end = current_offset + diff.size;
|
||||
if current_offset < row_end && diff_end > row_start {
|
||||
let start_in_diff = row_start.saturating_sub(current_offset);
|
||||
let end_in_diff = row_end.min(diff_end) - current_offset;
|
||||
if start_in_diff < end_in_diff {
|
||||
let data_slice = if diff.data.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
diff.data[start_in_diff..end_in_diff.min(diff.data.len())].to_vec()
|
||||
};
|
||||
row_diff.segments.push(DataDiff {
|
||||
data: data_slice,
|
||||
kind: diff.kind,
|
||||
size: end_in_diff - start_in_diff,
|
||||
});
|
||||
}
|
||||
}
|
||||
current_offset = diff_end;
|
||||
if current_offset >= row_start + BYTES_PER_ROW {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all relocations that overlap with this row
|
||||
let row_end_absolute = row_diff.address + BYTES_PER_ROW as u64;
|
||||
row_diff.relocations = reloc_diffs
|
||||
.iter()
|
||||
.filter(|rd| rd.range.start < row_end_absolute && rd.range.end > row_diff.address)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
row_diff
|
||||
}
|
||||
|
||||
fn build_data_diff_rows(
|
||||
segments: &[DataDiff],
|
||||
relocations: &[DataRelocationDiff],
|
||||
symbol_address: u64,
|
||||
) -> Vec<DataDiffRow> {
|
||||
let total_len = segments.iter().map(|s| s.size as u64).sum::<u64>();
|
||||
let num_rows = total_len.div_ceil(BYTES_PER_ROW as u64) as usize;
|
||||
(0..num_rows)
|
||||
.map(|row_index| build_data_diff_row(segments, relocations, symbol_address, row_index))
|
||||
.collect()
|
||||
}
|
||||
|
@ -12,7 +12,10 @@ use itertools::Itertools;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{
|
||||
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
|
||||
diff::{
|
||||
DataDiffKind, DataDiffRow, DiffObjConfig, InstructionDiffKind, InstructionDiffRow,
|
||||
ObjectDiff, SymbolDiff, data::resolve_relocation,
|
||||
},
|
||||
obj::{
|
||||
FlowAnalysisValue, InstructionArg, InstructionArgValue, Object, ParsedInstruction,
|
||||
ResolvedInstructionRef, ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag,
|
||||
@ -494,6 +497,57 @@ pub fn relocation_context(
|
||||
out
|
||||
}
|
||||
|
||||
pub fn data_row_hover(obj: &Object, diff_row: &DataDiffRow) -> Vec<HoverItem> {
|
||||
let mut out = Vec::new();
|
||||
let mut prev_reloc = None;
|
||||
let mut first = true;
|
||||
for reloc_diff in diff_row.relocations.iter() {
|
||||
let reloc = &reloc_diff.reloc;
|
||||
if prev_reloc == Some(reloc) {
|
||||
// Avoid showing consecutive duplicate relocations.
|
||||
// We do this because a single relocation can span across multiple diffs if the
|
||||
// bytes in the relocation changed (e.g. first byte is added, second is unchanged).
|
||||
continue;
|
||||
}
|
||||
prev_reloc = Some(reloc);
|
||||
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
out.push(HoverItem::Separator);
|
||||
}
|
||||
|
||||
let reloc = resolve_relocation(&obj.symbols, reloc);
|
||||
let color = match reloc_diff.kind {
|
||||
DataDiffKind::None => HoverItemColor::Normal,
|
||||
DataDiffKind::Replace => HoverItemColor::Special,
|
||||
DataDiffKind::Delete => HoverItemColor::Delete,
|
||||
DataDiffKind::Insert => HoverItemColor::Insert,
|
||||
};
|
||||
out.append(&mut relocation_hover(obj, reloc, Some(color)));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn data_row_context(obj: &Object, diff_row: &DataDiffRow) -> Vec<ContextItem> {
|
||||
let mut out = Vec::new();
|
||||
let mut prev_reloc = None;
|
||||
for reloc_diff in diff_row.relocations.iter() {
|
||||
let reloc = &reloc_diff.reloc;
|
||||
if prev_reloc == Some(reloc) {
|
||||
// Avoid showing consecutive duplicate relocations.
|
||||
// We do this because a single relocation can span across multiple diffs if the
|
||||
// bytes in the relocation changed (e.g. first byte is added, second is unchanged).
|
||||
continue;
|
||||
}
|
||||
prev_reloc = Some(reloc);
|
||||
|
||||
let reloc = resolve_relocation(&obj.symbols, reloc);
|
||||
out.append(&mut relocation_context(obj, reloc, None));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn relocation_hover(
|
||||
obj: &Object,
|
||||
reloc: ResolvedRelocation,
|
||||
@ -677,6 +731,7 @@ pub struct SectionDisplay {
|
||||
pub size: u64,
|
||||
pub match_percent: Option<f32>,
|
||||
pub symbols: Vec<SectionDisplaySymbol>,
|
||||
pub kind: SectionKind,
|
||||
}
|
||||
|
||||
pub fn display_sections(
|
||||
@ -755,6 +810,7 @@ pub fn display_sections(
|
||||
size: section.size,
|
||||
match_percent: section_diff.match_percent,
|
||||
symbols,
|
||||
kind: section.kind,
|
||||
});
|
||||
} else {
|
||||
// Don't sort, preserve order of absolute symbols
|
||||
@ -764,6 +820,7 @@ pub fn display_sections(
|
||||
size: 0,
|
||||
match_percent: None,
|
||||
symbols,
|
||||
kind: SectionKind::Common,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -45,8 +45,7 @@ pub struct SymbolDiff {
|
||||
pub match_percent: Option<f32>,
|
||||
pub diff_score: Option<(u64, u64)>,
|
||||
pub instruction_rows: Vec<InstructionDiffRow>,
|
||||
pub data_diff: Vec<DataDiff>,
|
||||
pub data_reloc_diff: Vec<DataRelocationDiff>,
|
||||
pub data_rows: Vec<DataDiffRow>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@ -83,16 +82,15 @@ pub enum InstructionDiffKind {
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct DataDiff {
|
||||
pub data: Vec<u8>,
|
||||
pub size: usize,
|
||||
pub kind: DataDiffKind,
|
||||
pub len: usize,
|
||||
pub symbol: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DataRelocationDiff {
|
||||
pub reloc: Relocation,
|
||||
pub range: Range<u64>,
|
||||
pub kind: DataDiffKind,
|
||||
pub range: Range<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
@ -104,6 +102,13 @@ pub enum DataDiffKind {
|
||||
Insert,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct DataDiffRow {
|
||||
pub address: u64,
|
||||
pub segments: Vec<DataDiff>,
|
||||
pub relocations: Vec<DataRelocationDiff>,
|
||||
}
|
||||
|
||||
/// Index of the argument diff for coloring.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
|
@ -2645,8 +2645,7 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
||||
arg_diff: [],
|
||||
},
|
||||
],
|
||||
data_diff: [],
|
||||
data_reloc_diff: [],
|
||||
data_rows: [],
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(
|
||||
@ -5290,7 +5289,6 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
||||
arg_diff: [],
|
||||
},
|
||||
],
|
||||
data_diff: [],
|
||||
data_reloc_diff: [],
|
||||
data_rows: [],
|
||||
},
|
||||
)
|
||||
|
@ -26,6 +26,7 @@ expression: sections_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Common,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".ctors-0",
|
||||
@ -40,6 +41,7 @@ expression: sections_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Data,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-0",
|
||||
@ -82,5 +84,6 @@ expression: sections_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-1",
|
||||
@ -26,6 +27,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-2",
|
||||
@ -38,6 +40,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-3",
|
||||
@ -50,6 +53,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-4",
|
||||
@ -62,6 +66,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-5",
|
||||
@ -74,6 +79,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-6",
|
||||
@ -86,6 +92,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-7",
|
||||
@ -98,6 +105,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-8",
|
||||
@ -110,6 +118,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-9",
|
||||
@ -122,6 +131,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-10",
|
||||
@ -134,6 +144,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-11",
|
||||
@ -146,6 +157,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-12",
|
||||
@ -158,6 +170,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-13",
|
||||
@ -170,6 +183,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-14",
|
||||
@ -182,6 +196,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-15",
|
||||
@ -194,6 +209,7 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
SectionDisplay {
|
||||
id: ".text-16",
|
||||
@ -206,5 +222,6 @@ expression: section_display
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
kind: Code,
|
||||
},
|
||||
]
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::{cmp::min, default::Default, mem::take};
|
||||
use std::default::Default;
|
||||
|
||||
use egui::{Label, Sense, Widget, text::LayoutJob};
|
||||
use objdiff_core::{
|
||||
diff::{
|
||||
DataDiff, DataDiffKind, DataRelocationDiff,
|
||||
data::resolve_relocation,
|
||||
display::{ContextItem, HoverItem, HoverItemColor, relocation_context, relocation_hover},
|
||||
DataDiffKind, DataDiffRow,
|
||||
data::BYTES_PER_ROW,
|
||||
display::{data_row_context, data_row_hover},
|
||||
},
|
||||
obj::Object,
|
||||
};
|
||||
@ -13,84 +13,30 @@ use objdiff_core::{
|
||||
use super::diff::{context_menu_items_ui, hover_items_ui};
|
||||
use crate::views::{appearance::Appearance, write_text};
|
||||
|
||||
pub(crate) const BYTES_PER_ROW: usize = 16;
|
||||
|
||||
fn data_row_hover(obj: &Object, diffs: &[(DataDiff, Vec<DataRelocationDiff>)]) -> Vec<HoverItem> {
|
||||
let mut out = Vec::new();
|
||||
let reloc_diffs = diffs.iter().flat_map(|(_, reloc_diffs)| reloc_diffs);
|
||||
let mut prev_reloc = None;
|
||||
let mut first = true;
|
||||
for reloc_diff in reloc_diffs {
|
||||
let reloc = &reloc_diff.reloc;
|
||||
if prev_reloc == Some(reloc) {
|
||||
// Avoid showing consecutive duplicate relocations.
|
||||
// We do this because a single relocation can span across multiple diffs if the
|
||||
// bytes in the relocation changed (e.g. first byte is added, second is unchanged).
|
||||
continue;
|
||||
}
|
||||
prev_reloc = Some(reloc);
|
||||
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
out.push(HoverItem::Separator);
|
||||
}
|
||||
|
||||
let color = get_hover_item_color_for_diff_kind(reloc_diff.kind);
|
||||
|
||||
let reloc = resolve_relocation(&obj.symbols, reloc);
|
||||
out.append(&mut relocation_hover(obj, reloc, Some(color)));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn data_row_context(
|
||||
obj: &Object,
|
||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
||||
) -> Vec<ContextItem> {
|
||||
let mut out = Vec::new();
|
||||
let reloc_diffs = diffs.iter().flat_map(|(_, reloc_diffs)| reloc_diffs);
|
||||
let mut prev_reloc = None;
|
||||
for reloc_diff in reloc_diffs {
|
||||
let reloc = &reloc_diff.reloc;
|
||||
if prev_reloc == Some(reloc) {
|
||||
// Avoid showing consecutive duplicate relocations.
|
||||
// We do this because a single relocation can span across multiple diffs if the
|
||||
// bytes in the relocation changed (e.g. first byte is added, second is unchanged).
|
||||
continue;
|
||||
}
|
||||
prev_reloc = Some(reloc);
|
||||
|
||||
let reloc = resolve_relocation(&obj.symbols, reloc);
|
||||
out.append(&mut relocation_context(obj, reloc, None));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn data_row_hover_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: &Object,
|
||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
||||
diff_row: &DataDiffRow,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
hover_items_ui(ui, data_row_hover(obj, diffs), appearance);
|
||||
hover_items_ui(ui, data_row_hover(obj, diff_row), appearance);
|
||||
});
|
||||
}
|
||||
|
||||
fn data_row_context_menu(
|
||||
ui: &mut egui::Ui,
|
||||
obj: &Object,
|
||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
||||
diff_row: &DataDiffRow,
|
||||
column: usize,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
context_menu_items_ui(ui, data_row_context(obj, diffs), column, appearance);
|
||||
context_menu_items_ui(ui, data_row_context(obj, diff_row), column, appearance);
|
||||
});
|
||||
}
|
||||
|
||||
@ -103,27 +49,18 @@ fn get_color_for_diff_kind(diff_kind: DataDiffKind, appearance: &Appearance) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hover_item_color_for_diff_kind(diff_kind: DataDiffKind) -> HoverItemColor {
|
||||
match diff_kind {
|
||||
DataDiffKind::None => HoverItemColor::Normal,
|
||||
DataDiffKind::Replace => HoverItemColor::Special,
|
||||
DataDiffKind::Delete => HoverItemColor::Delete,
|
||||
DataDiffKind::Insert => HoverItemColor::Insert,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn data_row_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: Option<&Object>,
|
||||
base_address: usize,
|
||||
row_address: usize,
|
||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
||||
base_address: u64,
|
||||
row_address: u64,
|
||||
diff_row: &DataDiffRow,
|
||||
appearance: &Appearance,
|
||||
column: usize,
|
||||
) {
|
||||
if diffs.iter().any(|(dd, rds)| {
|
||||
dd.kind != DataDiffKind::None || rds.iter().any(|rd| rd.kind != DataDiffKind::None)
|
||||
}) {
|
||||
if diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
|
||||
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None)
|
||||
{
|
||||
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
||||
}
|
||||
let mut job = LayoutJob::default();
|
||||
@ -137,20 +74,21 @@ pub(crate) fn data_row_ui(
|
||||
let mut cur_addr = 0usize;
|
||||
// The offset into the actual bytes of the section on this side, ignoring differences.
|
||||
let mut cur_addr_actual = base_address + row_address;
|
||||
for (diff, reloc_diffs) in diffs {
|
||||
for diff in diff_row.segments.iter() {
|
||||
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
||||
if diff.data.is_empty() {
|
||||
let mut str = " ".repeat(diff.len);
|
||||
let mut str = " ".repeat(diff.size);
|
||||
let n1 = cur_addr / 8;
|
||||
let n2 = (diff.len + cur_addr) / 8;
|
||||
let n2 = (diff.size + cur_addr) / 8;
|
||||
str.push_str(" ".repeat(n2 - n1).as_str());
|
||||
write_text(str.as_str(), base_color, &mut job, appearance.code_font.clone());
|
||||
cur_addr += diff.len;
|
||||
cur_addr += diff.size;
|
||||
} else {
|
||||
for byte in &diff.data {
|
||||
let mut byte_text = format!("{byte:02x} ");
|
||||
let mut byte_color = base_color;
|
||||
if let Some(reloc_diff) = reloc_diffs
|
||||
if let Some(reloc_diff) = diff_row
|
||||
.relocations
|
||||
.iter()
|
||||
.find(|reloc_diff| reloc_diff.range.contains(&cur_addr_actual))
|
||||
{
|
||||
@ -179,11 +117,11 @@ pub(crate) fn data_row_ui(
|
||||
write_text(str.as_str(), appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
write_text(" ", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
for (diff, _) in diffs {
|
||||
for diff in diff_row.segments.iter() {
|
||||
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
||||
if diff.data.is_empty() {
|
||||
write_text(
|
||||
" ".repeat(diff.len).as_str(),
|
||||
" ".repeat(diff.size).as_str(),
|
||||
base_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
@ -204,70 +142,7 @@ pub(crate) fn data_row_ui(
|
||||
|
||||
let response = Label::new(job).sense(Sense::click()).ui(ui);
|
||||
if let Some(obj) = obj {
|
||||
response.context_menu(|ui| data_row_context_menu(ui, obj, diffs, column, appearance));
|
||||
response.on_hover_ui_at_pointer(|ui| data_row_hover_ui(ui, obj, diffs, appearance));
|
||||
response.context_menu(|ui| data_row_context_menu(ui, obj, diff_row, column, appearance));
|
||||
response.on_hover_ui_at_pointer(|ui| data_row_hover_ui(ui, obj, diff_row, appearance));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn split_diffs(
|
||||
diffs: &[DataDiff],
|
||||
reloc_diffs: &[DataRelocationDiff],
|
||||
symbol_offset_in_section: usize,
|
||||
) -> Vec<Vec<(DataDiff, Vec<DataRelocationDiff>)>> {
|
||||
let mut split_diffs = Vec::<Vec<(DataDiff, Vec<DataRelocationDiff>)>>::new();
|
||||
let mut row_diffs = Vec::<(DataDiff, Vec<DataRelocationDiff>)>::new();
|
||||
// The offset shown on the side of the GUI, shifted by insertions/deletions.
|
||||
let mut cur_addr = 0usize;
|
||||
// The offset into the actual bytes of the section on this side, ignoring differences.
|
||||
let mut cur_addr_actual = symbol_offset_in_section;
|
||||
for diff in diffs {
|
||||
let mut cur_len = 0usize;
|
||||
while cur_len < diff.len {
|
||||
let remaining_len = diff.len - cur_len;
|
||||
let mut remaining_in_row = BYTES_PER_ROW - (cur_addr % BYTES_PER_ROW);
|
||||
let len = min(remaining_len, remaining_in_row);
|
||||
|
||||
let data_diff = DataDiff {
|
||||
data: if diff.data.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
diff.data[cur_len..cur_len + len].to_vec()
|
||||
},
|
||||
kind: diff.kind,
|
||||
len,
|
||||
symbol: String::new(), // TODO
|
||||
};
|
||||
let row_reloc_diffs: Vec<DataRelocationDiff> = if diff.data.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
let diff_range = cur_addr_actual + cur_len..cur_addr_actual + cur_len + len;
|
||||
reloc_diffs
|
||||
.iter()
|
||||
.filter_map(|reloc_diff| {
|
||||
if reloc_diff.range.start < diff_range.end
|
||||
&& diff_range.start < reloc_diff.range.end
|
||||
{
|
||||
Some(reloc_diff.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
let row_diff = (data_diff, row_reloc_diffs);
|
||||
|
||||
row_diffs.push(row_diff);
|
||||
remaining_in_row -= len;
|
||||
cur_len += len;
|
||||
cur_addr += len;
|
||||
if remaining_in_row == 0 {
|
||||
split_diffs.push(take(&mut row_diffs));
|
||||
}
|
||||
}
|
||||
cur_addr_actual += diff.data.len();
|
||||
}
|
||||
if !row_diffs.is_empty() {
|
||||
split_diffs.push(take(&mut row_diffs));
|
||||
}
|
||||
split_diffs
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use objdiff_core::{
|
||||
build::BuildStatus,
|
||||
diff::{
|
||||
DiffObjConfig, ObjectDiff, SymbolDiff,
|
||||
data::BYTES_PER_ROW,
|
||||
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
|
||||
},
|
||||
obj::{Object, Symbol},
|
||||
@ -14,7 +15,7 @@ use crate::{
|
||||
views::{
|
||||
appearance::Appearance,
|
||||
column_layout::{render_header, render_strips, render_table},
|
||||
data_diff::{BYTES_PER_ROW, data_row_ui, split_diffs},
|
||||
data_diff::data_row_ui,
|
||||
extab_diff::extab_ui,
|
||||
function_diff::{FunctionDiffContext, asm_col_ui},
|
||||
symbol_diff::{
|
||||
@ -470,28 +471,14 @@ pub fn diff_view_ui(
|
||||
{
|
||||
// Joint diff view
|
||||
hotkeys::check_scroll_hotkeys(ui, true);
|
||||
let left_total_bytes =
|
||||
left_symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
let right_total_bytes =
|
||||
right_symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
if left_total_bytes != right_total_bytes {
|
||||
ui.label("Data size mismatch");
|
||||
let total_rows = left_symbol_diff.data_rows.len();
|
||||
if total_rows != right_symbol_diff.data_rows.len() {
|
||||
ui.label("Row count mismatch");
|
||||
return;
|
||||
}
|
||||
if left_total_bytes == 0 {
|
||||
if total_rows == 0 {
|
||||
return;
|
||||
}
|
||||
let total_rows = (left_total_bytes - 1) / BYTES_PER_ROW + 1;
|
||||
let left_diffs = split_diffs(
|
||||
&left_symbol_diff.data_diff,
|
||||
&left_symbol_diff.data_reloc_diff,
|
||||
left_symbol.address as usize,
|
||||
);
|
||||
let right_diffs = split_diffs(
|
||||
&right_symbol_diff.data_diff,
|
||||
&right_symbol_diff.data_reloc_diff,
|
||||
right_symbol.address as usize,
|
||||
);
|
||||
render_table(
|
||||
ui,
|
||||
available_width,
|
||||
@ -500,15 +487,15 @@ pub fn diff_view_ui(
|
||||
total_rows,
|
||||
|row, column| {
|
||||
let i = row.index();
|
||||
let row_offset = i * BYTES_PER_ROW;
|
||||
let row_offset = i as u64 * BYTES_PER_ROW as u64;
|
||||
row.col(|ui| {
|
||||
if column == 0 {
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(left_obj),
|
||||
left_symbol.address as usize,
|
||||
left_symbol.address,
|
||||
row_offset,
|
||||
&left_diffs[i],
|
||||
&left_symbol_diff.data_rows[i],
|
||||
appearance,
|
||||
column,
|
||||
);
|
||||
@ -516,9 +503,9 @@ pub fn diff_view_ui(
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(right_obj),
|
||||
right_symbol.address as usize,
|
||||
right_symbol.address,
|
||||
row_offset,
|
||||
&right_diffs[i],
|
||||
&right_symbol_diff.data_rows[i],
|
||||
appearance,
|
||||
column,
|
||||
);
|
||||
@ -618,17 +605,10 @@ fn diff_col_ui(
|
||||
extab_ui(ui, ctx, appearance, column);
|
||||
} else if state.current_view == View::DataDiff {
|
||||
hotkeys::check_scroll_hotkeys(ui, false);
|
||||
let total_bytes =
|
||||
symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
if total_bytes == 0 {
|
||||
let total_rows = symbol_diff.data_rows.len();
|
||||
if total_rows == 0 {
|
||||
return ret;
|
||||
}
|
||||
let total_rows = (total_bytes - 1) / BYTES_PER_ROW + 1;
|
||||
let diffs = split_diffs(
|
||||
&symbol_diff.data_diff,
|
||||
&symbol_diff.data_reloc_diff,
|
||||
symbol.address as usize,
|
||||
);
|
||||
render_table(
|
||||
ui,
|
||||
available_width / 2.0,
|
||||
@ -637,14 +617,14 @@ fn diff_col_ui(
|
||||
total_rows,
|
||||
|row, _column| {
|
||||
let i = row.index();
|
||||
let row_offset = i * BYTES_PER_ROW;
|
||||
let row_offset = i as u64 * BYTES_PER_ROW as u64;
|
||||
row.col(|ui| {
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(obj),
|
||||
symbol.address as usize,
|
||||
symbol.address,
|
||||
row_offset,
|
||||
&diffs[i],
|
||||
&symbol_diff.data_rows[i],
|
||||
appearance,
|
||||
column,
|
||||
);
|
||||
|
4
objdiff-wasm/package-lock.json
generated
4
objdiff-wasm/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.1.1",
|
||||
"version": "3.2.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.1.1",
|
||||
"version": "3.2.0",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.3",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.1.1",
|
||||
"version": "3.2.0",
|
||||
"description": "A local diffing tool for decompilation projects.",
|
||||
"author": {
|
||||
"name": "Luke Street",
|
||||
|
@ -26,13 +26,14 @@ use exports::objdiff::core::{
|
||||
diff::{
|
||||
DiffConfigBorrow, DiffResult, DiffSide, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
||||
GuestObjectDiff, MappingConfig, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
||||
SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
||||
SectionKind, SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
||||
},
|
||||
display::{
|
||||
ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode,
|
||||
DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem,
|
||||
HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay,
|
||||
SymbolDisplay, SymbolFilter, SymbolNavigationKind,
|
||||
ContextItem, ContextItemCopy, ContextItemNavigate, DataDiff, DataDiffKind, DataDiffRow,
|
||||
DataRelocationDiff, DiffText, DiffTextColor, DiffTextOpcode, DiffTextSegment,
|
||||
DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem, HoverItemColor,
|
||||
HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay, SymbolDisplay,
|
||||
SymbolFilter, SymbolNavigationKind,
|
||||
},
|
||||
};
|
||||
|
||||
@ -138,6 +139,7 @@ impl GuestDisplay for Component {
|
||||
size: d.size,
|
||||
match_percent: d.match_percent,
|
||||
symbols: d.symbols.into_iter().map(to_symbol_ref).collect(),
|
||||
kind: d.kind.into(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -162,6 +164,7 @@ impl GuestDisplay for Component {
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||
SymbolDisplay {
|
||||
info: SymbolInfo {
|
||||
id: to_symbol_ref(symbol_display),
|
||||
@ -171,9 +174,8 @@ impl GuestDisplay for Component {
|
||||
size: symbol.size,
|
||||
kind: SymbolKind::from(symbol.kind),
|
||||
section: symbol.section.map(|s| s as u32),
|
||||
section_name: symbol
|
||||
.section
|
||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
||||
section_name: section.map(|sec| sec.name.clone()),
|
||||
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||
flags: SymbolFlags::from(symbol.flags),
|
||||
align: symbol.align.map(|a| a.get()),
|
||||
virtual_address: symbol.virtual_address,
|
||||
@ -181,7 +183,8 @@ impl GuestDisplay for Component {
|
||||
target_symbol: symbol_diff.and_then(|sd| sd.target_symbol.map(|s| s as u32)),
|
||||
match_percent: symbol_diff.and_then(|sd| sd.match_percent),
|
||||
diff_score: symbol_diff.and_then(|sd| sd.diff_score),
|
||||
row_count: symbol_diff.map_or(0, |sd| sd.instruction_rows.len() as u32),
|
||||
row_count: symbol_diff
|
||||
.map_or(0, |sd| sd.instruction_rows.len().max(sd.data_rows.len()) as u32),
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,6 +338,120 @@ impl GuestDisplay for Component {
|
||||
.map(HoverItem::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn display_data_row(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_ref: SymbolRef,
|
||||
row_index: u32,
|
||||
) -> DataDiffRow {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj_diff = &obj_diff.1;
|
||||
let symbol_display = from_symbol_ref(symbol_ref);
|
||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let Some(symbol_diff) = symbol_diff else {
|
||||
return DataDiffRow::default();
|
||||
};
|
||||
symbol_diff.data_rows.get(row_index as usize).map(DataDiffRow::from).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn data_hover(diff: ObjectDiffBorrow, symbol_ref: SymbolRef, row_index: u32) -> Vec<HoverItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = &obj_diff.0;
|
||||
let obj_diff = &obj_diff.1;
|
||||
let symbol_display = from_symbol_ref(symbol_ref);
|
||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let Some(symbol_diff) = symbol_diff else {
|
||||
return vec![];
|
||||
};
|
||||
let Some(diff_row) = symbol_diff.data_rows.get(row_index as usize) else {
|
||||
return vec![];
|
||||
};
|
||||
diff::display::data_row_hover(obj, diff_row).into_iter().map(HoverItem::from).collect()
|
||||
}
|
||||
|
||||
fn data_context(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_ref: SymbolRef,
|
||||
row_index: u32,
|
||||
) -> Vec<ContextItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = &obj_diff.0;
|
||||
let obj_diff = &obj_diff.1;
|
||||
let symbol_display = from_symbol_ref(symbol_ref);
|
||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let Some(symbol_diff) = symbol_diff else {
|
||||
return vec![];
|
||||
};
|
||||
let Some(diff_row) = symbol_diff.data_rows.get(row_index as usize) else {
|
||||
return vec![];
|
||||
};
|
||||
diff::display::data_row_context(obj, diff_row).into_iter().map(ContextItem::from).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diff::DataDiffKind> for DataDiffKind {
|
||||
fn from(kind: diff::DataDiffKind) -> Self {
|
||||
match kind {
|
||||
diff::DataDiffKind::None => DataDiffKind::None,
|
||||
diff::DataDiffKind::Replace => DataDiffKind::Replace,
|
||||
diff::DataDiffKind::Delete => DataDiffKind::Delete,
|
||||
diff::DataDiffKind::Insert => DataDiffKind::Insert,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DataDiffRow {
|
||||
fn default() -> Self { Self { address: 0, segments: Vec::new(), relocations: Vec::new() } }
|
||||
}
|
||||
|
||||
impl From<&diff::DataDiffRow> for DataDiffRow {
|
||||
fn from(row: &diff::DataDiffRow) -> Self {
|
||||
Self {
|
||||
address: row.address,
|
||||
segments: row.segments.iter().map(DataDiff::from).collect(),
|
||||
relocations: row.relocations.iter().map(DataRelocationDiff::from).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&diff::DataDiff> for DataDiff {
|
||||
fn from(diff: &diff::DataDiff) -> Self {
|
||||
Self { data: diff.data.clone(), size: diff.size as u32, kind: diff.kind.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&diff::DataRelocationDiff> for DataRelocationDiff {
|
||||
fn from(diff: &diff::DataRelocationDiff) -> Self {
|
||||
Self {
|
||||
address: diff.reloc.address,
|
||||
size: (diff.range.end - diff.range.start) as u32,
|
||||
kind: diff.kind.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<obj::SymbolKind> for SymbolKind {
|
||||
@ -523,6 +640,7 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
||||
}
|
||||
})?;
|
||||
let symbol = obj.symbols.get(symbol_idx)?;
|
||||
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||
Some(SymbolInfo {
|
||||
id: symbol_idx as SymbolRef,
|
||||
name: symbol.name.clone(),
|
||||
@ -531,9 +649,8 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
||||
size: symbol.size,
|
||||
kind: SymbolKind::from(symbol.kind),
|
||||
section: symbol.section.map(|s| s as u32),
|
||||
section_name: symbol
|
||||
.section
|
||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
||||
section_name: section.map(|sec| sec.name.clone()),
|
||||
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||
flags: SymbolFlags::from(symbol.flags),
|
||||
align: symbol.align.map(|a| a.get()),
|
||||
virtual_address: symbol.virtual_address,
|
||||
@ -544,6 +661,7 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
||||
let obj = self.0.as_ref();
|
||||
let symbol_display = from_symbol_ref(symbol_ref);
|
||||
let symbol = obj.symbols.get(symbol_display.symbol)?;
|
||||
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||
Some(SymbolInfo {
|
||||
id: to_symbol_ref(symbol_display),
|
||||
name: symbol.name.clone(),
|
||||
@ -552,9 +670,8 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
||||
size: symbol.size,
|
||||
kind: SymbolKind::from(symbol.kind),
|
||||
section: symbol.section.map(|s| s as u32),
|
||||
section_name: symbol
|
||||
.section
|
||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
||||
section_name: section.map(|sec| sec.name.clone()),
|
||||
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||
flags: SymbolFlags::from(symbol.flags),
|
||||
align: symbol.align.map(|a| a.get()),
|
||||
virtual_address: symbol.virtual_address,
|
||||
@ -639,6 +756,7 @@ impl Default for SymbolInfo {
|
||||
kind: Default::default(),
|
||||
section: Default::default(),
|
||||
section_name: Default::default(),
|
||||
section_kind: Default::default(),
|
||||
flags: Default::default(),
|
||||
align: Default::default(),
|
||||
virtual_address: Default::default(),
|
||||
@ -684,4 +802,20 @@ fn to_symbol_ref(display_symbol: diff::display::SectionDisplaySymbol) -> SymbolR
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SectionKind {
|
||||
fn default() -> Self { Self::Unknown }
|
||||
}
|
||||
|
||||
impl From<obj::SectionKind> for SectionKind {
|
||||
fn from(kind: obj::SectionKind) -> Self {
|
||||
match kind {
|
||||
obj::SectionKind::Unknown => SectionKind::Unknown,
|
||||
obj::SectionKind::Code => SectionKind::Code,
|
||||
obj::SectionKind::Data => SectionKind::Data,
|
||||
obj::SectionKind::Bss => SectionKind::Bss,
|
||||
obj::SectionKind::Common => SectionKind::Common,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export!(Component);
|
||||
|
@ -54,6 +54,7 @@ interface diff {
|
||||
kind: symbol-kind,
|
||||
section: option<u32>,
|
||||
section-name: option<string>,
|
||||
section-kind: section-kind,
|
||||
%flags: symbol-flags,
|
||||
align: option<u32>,
|
||||
virtual-address: option<u64>,
|
||||
@ -86,6 +87,14 @@ interface diff {
|
||||
target,
|
||||
base,
|
||||
}
|
||||
|
||||
enum section-kind {
|
||||
unknown,
|
||||
code,
|
||||
data,
|
||||
bss,
|
||||
common,
|
||||
}
|
||||
}
|
||||
|
||||
interface display {
|
||||
@ -94,7 +103,8 @@ interface display {
|
||||
object-diff,
|
||||
diff-config,
|
||||
symbol-info,
|
||||
symbol-ref
|
||||
symbol-ref,
|
||||
section-kind
|
||||
};
|
||||
|
||||
record display-config {
|
||||
@ -114,6 +124,7 @@ interface display {
|
||||
size: u64,
|
||||
match-percent: option<f32>,
|
||||
symbols: list<symbol-ref>,
|
||||
kind: section-kind,
|
||||
}
|
||||
|
||||
record symbol-display {
|
||||
@ -238,6 +249,31 @@ interface display {
|
||||
delete,
|
||||
}
|
||||
|
||||
enum data-diff-kind {
|
||||
none,
|
||||
replace,
|
||||
delete,
|
||||
insert,
|
||||
}
|
||||
|
||||
record data-diff {
|
||||
data: list<u8>,
|
||||
size: u32,
|
||||
kind: data-diff-kind,
|
||||
}
|
||||
|
||||
record data-relocation-diff {
|
||||
address: u64,
|
||||
size: u32,
|
||||
kind: data-diff-kind,
|
||||
}
|
||||
|
||||
record data-diff-row {
|
||||
address: u64,
|
||||
segments: list<data-diff>,
|
||||
relocations: list<data-relocation-diff>,
|
||||
}
|
||||
|
||||
display-sections: func(
|
||||
diff: borrow<object-diff>,
|
||||
filter: symbol-filter,
|
||||
@ -279,6 +315,24 @@ interface display {
|
||||
row-index: u32,
|
||||
config: borrow<diff-config>,
|
||||
) -> list<hover-item>;
|
||||
|
||||
display-data-row: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
) -> data-diff-row;
|
||||
|
||||
data-context: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
) -> list<context-item>;
|
||||
|
||||
data-hover: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
) -> list<hover-item>;
|
||||
}
|
||||
|
||||
world api {
|
||||
|
Loading…
x
Reference in New Issue
Block a user