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]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@ -3458,7 +3458,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
@ -3513,7 +3513,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@ -3550,7 +3550,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-wasm"
|
name = "objdiff-wasm"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
|
@ -14,7 +14,7 @@ default-members = [
|
|||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -5,7 +5,7 @@ use anyhow::{Result, anyhow};
|
|||||||
use similar::{Algorithm, capture_diff_slices, get_diff_ratio};
|
use similar::{Algorithm, capture_diff_slices, get_diff_ratio};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
DataDiff, DataDiffKind, DataRelocationDiff, ObjectDiff, SectionDiff, SymbolDiff,
|
DataDiff, DataDiffKind, DataDiffRow, DataRelocationDiff, ObjectDiff, SectionDiff, SymbolDiff,
|
||||||
code::{address_eq, section_name_eq},
|
code::{address_eq, section_name_eq},
|
||||||
};
|
};
|
||||||
use crate::obj::{Object, Relocation, ResolvedRelocation, Symbol, SymbolFlag, SymbolKind};
|
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 {
|
left_data_diff.push(DataDiff {
|
||||||
data: left_data[..len.min(left_data.len())].to_vec(),
|
data: left_data[..len.min(left_data.len())].to_vec(),
|
||||||
kind,
|
kind,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
right_data_diff.push(DataDiff {
|
right_data_diff.push(DataDiff {
|
||||||
data: right_data[..len.min(right_data.len())].to_vec(),
|
data: right_data[..len.min(right_data.len())].to_vec(),
|
||||||
kind,
|
kind,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
if kind == DataDiffKind::Replace {
|
if kind == DataDiffKind::Replace {
|
||||||
match left_len.cmp(&right_len) {
|
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 {
|
left_data_diff.push(DataDiff {
|
||||||
data: vec![],
|
data: vec![],
|
||||||
kind: DataDiffKind::Insert,
|
kind: DataDiffKind::Insert,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
right_data_diff.push(DataDiff {
|
right_data_diff.push(DataDiff {
|
||||||
data: right_data[left_len..right_len].to_vec(),
|
data: right_data[left_len..right_len].to_vec(),
|
||||||
kind: DataDiffKind::Insert,
|
kind: DataDiffKind::Insert,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
@ -142,14 +138,12 @@ fn diff_data_range(left_data: &[u8], right_data: &[u8]) -> (f32, Vec<DataDiff>,
|
|||||||
left_data_diff.push(DataDiff {
|
left_data_diff.push(DataDiff {
|
||||||
data: left_data[right_len..left_len].to_vec(),
|
data: left_data[right_len..left_len].to_vec(),
|
||||||
kind: DataDiffKind::Delete,
|
kind: DataDiffKind::Delete,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
right_data_diff.push(DataDiff {
|
right_data_diff.push(DataDiff {
|
||||||
data: vec![],
|
data: vec![],
|
||||||
kind: DataDiffKind::Delete,
|
kind: DataDiffKind::Delete,
|
||||||
len,
|
size: len,
|
||||||
..Default::default()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ordering::Equal => {}
|
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> {
|
pub fn no_diff_data_section(obj: &Object, section_idx: usize) -> Result<SectionDiff> {
|
||||||
let section = &obj.sections[section_idx];
|
let section = &obj.sections[section_idx];
|
||||||
let len = section.data.len();
|
|
||||||
let data = §ion.data[0..len];
|
|
||||||
|
|
||||||
let data_diff =
|
let data_diff = vec![DataDiff {
|
||||||
vec![DataDiff { data: data.to_vec(), kind: DataDiffKind::None, len, ..Default::default() }];
|
data: section.data.0.clone(),
|
||||||
|
kind: DataDiffKind::None,
|
||||||
|
size: section.data.len(),
|
||||||
|
}];
|
||||||
|
|
||||||
let mut reloc_diffs = Vec::new();
|
let mut reloc_diffs = Vec::new();
|
||||||
for reloc in section.relocations.iter() {
|
for reloc in section.relocations.iter() {
|
||||||
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
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_diffs.push(DataRelocationDiff {
|
||||||
reloc: reloc.clone(),
|
reloc: reloc.clone(),
|
||||||
kind: DataDiffKind::None,
|
kind: DataDiffKind::None,
|
||||||
@ -279,8 +274,7 @@ pub fn diff_data_section(
|
|||||||
) {
|
) {
|
||||||
if let Some(left_reloc) = left_reloc {
|
if let Some(left_reloc) = left_reloc {
|
||||||
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
||||||
let range = left_reloc.relocation.address as usize
|
let range = left_reloc.relocation.address..left_reloc.relocation.address + len as u64;
|
||||||
..left_reloc.relocation.address as usize + len;
|
|
||||||
left_reloc_diffs.push(DataRelocationDiff {
|
left_reloc_diffs.push(DataRelocationDiff {
|
||||||
reloc: left_reloc.relocation.clone(),
|
reloc: left_reloc.relocation.clone(),
|
||||||
kind: diff_kind,
|
kind: diff_kind,
|
||||||
@ -289,8 +283,7 @@ pub fn diff_data_section(
|
|||||||
}
|
}
|
||||||
if let Some(right_reloc) = right_reloc {
|
if let Some(right_reloc) = right_reloc {
|
||||||
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
||||||
let range = right_reloc.relocation.address as usize
|
let range = right_reloc.relocation.address..right_reloc.relocation.address + len as u64;
|
||||||
..right_reloc.relocation.address as usize + len;
|
|
||||||
right_reloc_diffs.push(DataRelocationDiff {
|
right_reloc_diffs.push(DataRelocationDiff {
|
||||||
reloc: right_reloc.relocation.clone(),
|
reloc: right_reloc.relocation.clone(),
|
||||||
kind: diff_kind,
|
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 range = start as usize..end as usize;
|
||||||
let data = §ion.data[range.clone()];
|
let data = §ion.data[range.clone()];
|
||||||
|
|
||||||
let len = symbol.size as usize;
|
let data_diff = vec![DataDiff {
|
||||||
let data_diff =
|
data: data.to_vec(),
|
||||||
vec![DataDiff { data: data.to_vec(), kind: DataDiffKind::None, len, ..Default::default() }];
|
kind: DataDiffKind::None,
|
||||||
|
size: symbol.size as usize,
|
||||||
|
}];
|
||||||
|
|
||||||
let mut reloc_diffs = Vec::new();
|
let mut reloc_diffs = Vec::new();
|
||||||
for reloc in section.relocations.iter() {
|
for reloc in section.relocations.iter() {
|
||||||
@ -355,7 +350,7 @@ pub fn no_diff_data_symbol(obj: &Object, symbol_index: usize) -> Result<SymbolDi
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
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_diffs.push(DataRelocationDiff {
|
||||||
reloc: reloc.clone(),
|
reloc: reloc.clone(),
|
||||||
kind: DataDiffKind::None,
|
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 {
|
Ok(SymbolDiff {
|
||||||
target_symbol: None,
|
target_symbol: None,
|
||||||
match_percent: None,
|
match_percent: None,
|
||||||
diff_score: None,
|
diff_score: None,
|
||||||
data_diff,
|
data_rows,
|
||||||
data_reloc_diff: reloc_diffs,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -454,8 +449,8 @@ pub fn diff_data_symbol(
|
|||||||
|
|
||||||
if let Some(left_reloc) = left_reloc {
|
if let Some(left_reloc) = left_reloc {
|
||||||
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
let len = left_obj.arch.data_reloc_size(left_reloc.relocation.flags);
|
||||||
let range = left_reloc.relocation.address as usize
|
let range =
|
||||||
..left_reloc.relocation.address as usize + len;
|
left_reloc.relocation.address..left_reloc.relocation.address + len as u64;
|
||||||
left_reloc_diffs.push(DataRelocationDiff {
|
left_reloc_diffs.push(DataRelocationDiff {
|
||||||
reloc: left_reloc.relocation.clone(),
|
reloc: left_reloc.relocation.clone(),
|
||||||
kind: diff_kind,
|
kind: diff_kind,
|
||||||
@ -464,8 +459,8 @@ pub fn diff_data_symbol(
|
|||||||
}
|
}
|
||||||
if let Some(right_reloc) = right_reloc {
|
if let Some(right_reloc) = right_reloc {
|
||||||
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
let len = right_obj.arch.data_reloc_size(right_reloc.relocation.flags);
|
||||||
let range = right_reloc.relocation.address as usize
|
let range =
|
||||||
..right_reloc.relocation.address as usize + len;
|
right_reloc.relocation.address..right_reloc.relocation.address + len as u64;
|
||||||
right_reloc_diffs.push(DataRelocationDiff {
|
right_reloc_diffs.push(DataRelocationDiff {
|
||||||
reloc: right_reloc.relocation.clone(),
|
reloc: right_reloc.relocation.clone(),
|
||||||
kind: diff_kind,
|
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 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((
|
Ok((
|
||||||
SymbolDiff {
|
SymbolDiff {
|
||||||
target_symbol: Some(right_symbol_idx),
|
target_symbol: Some(right_symbol_idx),
|
||||||
match_percent: Some(match_percent),
|
match_percent: Some(match_percent),
|
||||||
diff_score: None,
|
diff_score: None,
|
||||||
data_diff: left_data_diff,
|
data_rows: left_rows,
|
||||||
data_reloc_diff: left_reloc_diffs,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
SymbolDiff {
|
SymbolDiff {
|
||||||
target_symbol: Some(left_symbol_idx),
|
target_symbol: Some(left_symbol_idx),
|
||||||
match_percent: Some(match_percent),
|
match_percent: Some(match_percent),
|
||||||
diff_score: None,
|
diff_score: None,
|
||||||
data_diff: right_data_diff,
|
data_rows: right_rows,
|
||||||
data_reloc_diff: right_reloc_diffs,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
@ -593,3 +594,68 @@ fn symbols_matching_section(
|
|||||||
&& !s.flags.contains(SymbolFlag::Ignored)
|
&& !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 regex::Regex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
|
diff::{
|
||||||
|
DataDiffKind, DataDiffRow, DiffObjConfig, InstructionDiffKind, InstructionDiffRow,
|
||||||
|
ObjectDiff, SymbolDiff, data::resolve_relocation,
|
||||||
|
},
|
||||||
obj::{
|
obj::{
|
||||||
FlowAnalysisValue, InstructionArg, InstructionArgValue, Object, ParsedInstruction,
|
FlowAnalysisValue, InstructionArg, InstructionArgValue, Object, ParsedInstruction,
|
||||||
ResolvedInstructionRef, ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag,
|
ResolvedInstructionRef, ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag,
|
||||||
@ -494,6 +497,57 @@ pub fn relocation_context(
|
|||||||
out
|
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(
|
pub fn relocation_hover(
|
||||||
obj: &Object,
|
obj: &Object,
|
||||||
reloc: ResolvedRelocation,
|
reloc: ResolvedRelocation,
|
||||||
@ -677,6 +731,7 @@ pub struct SectionDisplay {
|
|||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub match_percent: Option<f32>,
|
pub match_percent: Option<f32>,
|
||||||
pub symbols: Vec<SectionDisplaySymbol>,
|
pub symbols: Vec<SectionDisplaySymbol>,
|
||||||
|
pub kind: SectionKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_sections(
|
pub fn display_sections(
|
||||||
@ -755,6 +810,7 @@ pub fn display_sections(
|
|||||||
size: section.size,
|
size: section.size,
|
||||||
match_percent: section_diff.match_percent,
|
match_percent: section_diff.match_percent,
|
||||||
symbols,
|
symbols,
|
||||||
|
kind: section.kind,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Don't sort, preserve order of absolute symbols
|
// Don't sort, preserve order of absolute symbols
|
||||||
@ -764,6 +820,7 @@ pub fn display_sections(
|
|||||||
size: 0,
|
size: 0,
|
||||||
match_percent: None,
|
match_percent: None,
|
||||||
symbols,
|
symbols,
|
||||||
|
kind: SectionKind::Common,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,7 @@ pub struct SymbolDiff {
|
|||||||
pub match_percent: Option<f32>,
|
pub match_percent: Option<f32>,
|
||||||
pub diff_score: Option<(u64, u64)>,
|
pub diff_score: Option<(u64, u64)>,
|
||||||
pub instruction_rows: Vec<InstructionDiffRow>,
|
pub instruction_rows: Vec<InstructionDiffRow>,
|
||||||
pub data_diff: Vec<DataDiff>,
|
pub data_rows: Vec<DataDiffRow>,
|
||||||
pub data_reloc_diff: Vec<DataRelocationDiff>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
@ -83,16 +82,15 @@ pub enum InstructionDiffKind {
|
|||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct DataDiff {
|
pub struct DataDiff {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
|
pub size: usize,
|
||||||
pub kind: DataDiffKind,
|
pub kind: DataDiffKind,
|
||||||
pub len: usize,
|
|
||||||
pub symbol: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DataRelocationDiff {
|
pub struct DataRelocationDiff {
|
||||||
pub reloc: Relocation,
|
pub reloc: Relocation,
|
||||||
|
pub range: Range<u64>,
|
||||||
pub kind: DataDiffKind,
|
pub kind: DataDiffKind,
|
||||||
pub range: Range<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
@ -104,6 +102,13 @@ pub enum DataDiffKind {
|
|||||||
Insert,
|
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.
|
/// Index of the argument diff for coloring.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Debug, Copy, Clone, Default)]
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
|
@ -2645,8 +2645,7 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
|||||||
arg_diff: [],
|
arg_diff: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
data_diff: [],
|
data_rows: [],
|
||||||
data_reloc_diff: [],
|
|
||||||
},
|
},
|
||||||
SymbolDiff {
|
SymbolDiff {
|
||||||
target_symbol: Some(
|
target_symbol: Some(
|
||||||
@ -5290,7 +5289,6 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
|||||||
arg_diff: [],
|
arg_diff: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
data_diff: [],
|
data_rows: [],
|
||||||
data_reloc_diff: [],
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -26,6 +26,7 @@ expression: sections_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Common,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".ctors-0",
|
id: ".ctors-0",
|
||||||
@ -40,6 +41,7 @@ expression: sections_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Data,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-0",
|
id: ".text-0",
|
||||||
@ -82,5 +84,6 @@ expression: sections_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -14,6 +14,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-1",
|
id: ".text-1",
|
||||||
@ -26,6 +27,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-2",
|
id: ".text-2",
|
||||||
@ -38,6 +40,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-3",
|
id: ".text-3",
|
||||||
@ -50,6 +53,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-4",
|
id: ".text-4",
|
||||||
@ -62,6 +66,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-5",
|
id: ".text-5",
|
||||||
@ -74,6 +79,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-6",
|
id: ".text-6",
|
||||||
@ -86,6 +92,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-7",
|
id: ".text-7",
|
||||||
@ -98,6 +105,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-8",
|
id: ".text-8",
|
||||||
@ -110,6 +118,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-9",
|
id: ".text-9",
|
||||||
@ -122,6 +131,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-10",
|
id: ".text-10",
|
||||||
@ -134,6 +144,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-11",
|
id: ".text-11",
|
||||||
@ -146,6 +157,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-12",
|
id: ".text-12",
|
||||||
@ -158,6 +170,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-13",
|
id: ".text-13",
|
||||||
@ -170,6 +183,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-14",
|
id: ".text-14",
|
||||||
@ -182,6 +196,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-15",
|
id: ".text-15",
|
||||||
@ -194,6 +209,7 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
is_mapping_symbol: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
kind: Code,
|
||||||
},
|
},
|
||||||
SectionDisplay {
|
SectionDisplay {
|
||||||
id: ".text-16",
|
id: ".text-16",
|
||||||
@ -206,5 +222,6 @@ expression: section_display
|
|||||||
is_mapping_symbol: false,
|
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 egui::{Label, Sense, Widget, text::LayoutJob};
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
diff::{
|
diff::{
|
||||||
DataDiff, DataDiffKind, DataRelocationDiff,
|
DataDiffKind, DataDiffRow,
|
||||||
data::resolve_relocation,
|
data::BYTES_PER_ROW,
|
||||||
display::{ContextItem, HoverItem, HoverItemColor, relocation_context, relocation_hover},
|
display::{data_row_context, data_row_hover},
|
||||||
},
|
},
|
||||||
obj::Object,
|
obj::Object,
|
||||||
};
|
};
|
||||||
@ -13,84 +13,30 @@ use objdiff_core::{
|
|||||||
use super::diff::{context_menu_items_ui, hover_items_ui};
|
use super::diff::{context_menu_items_ui, hover_items_ui};
|
||||||
use crate::views::{appearance::Appearance, write_text};
|
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(
|
fn data_row_hover_ui(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
obj: &Object,
|
obj: &Object,
|
||||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
diff_row: &DataDiffRow,
|
||||||
appearance: &Appearance,
|
appearance: &Appearance,
|
||||||
) {
|
) {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
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(
|
fn data_row_context_menu(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
obj: &Object,
|
obj: &Object,
|
||||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
diff_row: &DataDiffRow,
|
||||||
column: usize,
|
column: usize,
|
||||||
appearance: &Appearance,
|
appearance: &Appearance,
|
||||||
) {
|
) {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
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(
|
pub(crate) fn data_row_ui(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
obj: Option<&Object>,
|
obj: Option<&Object>,
|
||||||
base_address: usize,
|
base_address: u64,
|
||||||
row_address: usize,
|
row_address: u64,
|
||||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
diff_row: &DataDiffRow,
|
||||||
appearance: &Appearance,
|
appearance: &Appearance,
|
||||||
column: usize,
|
column: usize,
|
||||||
) {
|
) {
|
||||||
if diffs.iter().any(|(dd, rds)| {
|
if diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
|
||||||
dd.kind != DataDiffKind::None || rds.iter().any(|rd| rd.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);
|
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
||||||
}
|
}
|
||||||
let mut job = LayoutJob::default();
|
let mut job = LayoutJob::default();
|
||||||
@ -137,20 +74,21 @@ pub(crate) fn data_row_ui(
|
|||||||
let mut cur_addr = 0usize;
|
let mut cur_addr = 0usize;
|
||||||
// The offset into the actual bytes of the section on this side, ignoring differences.
|
// The offset into the actual bytes of the section on this side, ignoring differences.
|
||||||
let mut cur_addr_actual = base_address + row_address;
|
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);
|
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
||||||
if diff.data.is_empty() {
|
if diff.data.is_empty() {
|
||||||
let mut str = " ".repeat(diff.len);
|
let mut str = " ".repeat(diff.size);
|
||||||
let n1 = cur_addr / 8;
|
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());
|
str.push_str(" ".repeat(n2 - n1).as_str());
|
||||||
write_text(str.as_str(), base_color, &mut job, appearance.code_font.clone());
|
write_text(str.as_str(), base_color, &mut job, appearance.code_font.clone());
|
||||||
cur_addr += diff.len;
|
cur_addr += diff.size;
|
||||||
} else {
|
} else {
|
||||||
for byte in &diff.data {
|
for byte in &diff.data {
|
||||||
let mut byte_text = format!("{byte:02x} ");
|
let mut byte_text = format!("{byte:02x} ");
|
||||||
let mut byte_color = base_color;
|
let mut byte_color = base_color;
|
||||||
if let Some(reloc_diff) = reloc_diffs
|
if let Some(reloc_diff) = diff_row
|
||||||
|
.relocations
|
||||||
.iter()
|
.iter()
|
||||||
.find(|reloc_diff| reloc_diff.range.contains(&cur_addr_actual))
|
.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(str.as_str(), appearance.text_color, &mut job, appearance.code_font.clone());
|
||||||
}
|
}
|
||||||
write_text(" ", 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);
|
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
||||||
if diff.data.is_empty() {
|
if diff.data.is_empty() {
|
||||||
write_text(
|
write_text(
|
||||||
" ".repeat(diff.len).as_str(),
|
" ".repeat(diff.size).as_str(),
|
||||||
base_color,
|
base_color,
|
||||||
&mut job,
|
&mut job,
|
||||||
appearance.code_font.clone(),
|
appearance.code_font.clone(),
|
||||||
@ -204,70 +142,7 @@ pub(crate) fn data_row_ui(
|
|||||||
|
|
||||||
let response = Label::new(job).sense(Sense::click()).ui(ui);
|
let response = Label::new(job).sense(Sense::click()).ui(ui);
|
||||||
if let Some(obj) = obj {
|
if let Some(obj) = obj {
|
||||||
response.context_menu(|ui| data_row_context_menu(ui, obj, diffs, column, 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, diffs, 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,
|
build::BuildStatus,
|
||||||
diff::{
|
diff::{
|
||||||
DiffObjConfig, ObjectDiff, SymbolDiff,
|
DiffObjConfig, ObjectDiff, SymbolDiff,
|
||||||
|
data::BYTES_PER_ROW,
|
||||||
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
|
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
|
||||||
},
|
},
|
||||||
obj::{Object, Symbol},
|
obj::{Object, Symbol},
|
||||||
@ -14,7 +15,7 @@ use crate::{
|
|||||||
views::{
|
views::{
|
||||||
appearance::Appearance,
|
appearance::Appearance,
|
||||||
column_layout::{render_header, render_strips, render_table},
|
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,
|
extab_diff::extab_ui,
|
||||||
function_diff::{FunctionDiffContext, asm_col_ui},
|
function_diff::{FunctionDiffContext, asm_col_ui},
|
||||||
symbol_diff::{
|
symbol_diff::{
|
||||||
@ -470,28 +471,14 @@ pub fn diff_view_ui(
|
|||||||
{
|
{
|
||||||
// Joint diff view
|
// Joint diff view
|
||||||
hotkeys::check_scroll_hotkeys(ui, true);
|
hotkeys::check_scroll_hotkeys(ui, true);
|
||||||
let left_total_bytes =
|
let total_rows = left_symbol_diff.data_rows.len();
|
||||||
left_symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
if total_rows != right_symbol_diff.data_rows.len() {
|
||||||
let right_total_bytes =
|
ui.label("Row count mismatch");
|
||||||
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");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if left_total_bytes == 0 {
|
if total_rows == 0 {
|
||||||
return;
|
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(
|
render_table(
|
||||||
ui,
|
ui,
|
||||||
available_width,
|
available_width,
|
||||||
@ -500,15 +487,15 @@ pub fn diff_view_ui(
|
|||||||
total_rows,
|
total_rows,
|
||||||
|row, column| {
|
|row, column| {
|
||||||
let i = row.index();
|
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| {
|
row.col(|ui| {
|
||||||
if column == 0 {
|
if column == 0 {
|
||||||
data_row_ui(
|
data_row_ui(
|
||||||
ui,
|
ui,
|
||||||
Some(left_obj),
|
Some(left_obj),
|
||||||
left_symbol.address as usize,
|
left_symbol.address,
|
||||||
row_offset,
|
row_offset,
|
||||||
&left_diffs[i],
|
&left_symbol_diff.data_rows[i],
|
||||||
appearance,
|
appearance,
|
||||||
column,
|
column,
|
||||||
);
|
);
|
||||||
@ -516,9 +503,9 @@ pub fn diff_view_ui(
|
|||||||
data_row_ui(
|
data_row_ui(
|
||||||
ui,
|
ui,
|
||||||
Some(right_obj),
|
Some(right_obj),
|
||||||
right_symbol.address as usize,
|
right_symbol.address,
|
||||||
row_offset,
|
row_offset,
|
||||||
&right_diffs[i],
|
&right_symbol_diff.data_rows[i],
|
||||||
appearance,
|
appearance,
|
||||||
column,
|
column,
|
||||||
);
|
);
|
||||||
@ -618,17 +605,10 @@ fn diff_col_ui(
|
|||||||
extab_ui(ui, ctx, appearance, column);
|
extab_ui(ui, ctx, appearance, column);
|
||||||
} else if state.current_view == View::DataDiff {
|
} else if state.current_view == View::DataDiff {
|
||||||
hotkeys::check_scroll_hotkeys(ui, false);
|
hotkeys::check_scroll_hotkeys(ui, false);
|
||||||
let total_bytes =
|
let total_rows = symbol_diff.data_rows.len();
|
||||||
symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
if total_rows == 0 {
|
||||||
if total_bytes == 0 {
|
|
||||||
return ret;
|
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(
|
render_table(
|
||||||
ui,
|
ui,
|
||||||
available_width / 2.0,
|
available_width / 2.0,
|
||||||
@ -637,14 +617,14 @@ fn diff_col_ui(
|
|||||||
total_rows,
|
total_rows,
|
||||||
|row, _column| {
|
|row, _column| {
|
||||||
let i = row.index();
|
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| {
|
row.col(|ui| {
|
||||||
data_row_ui(
|
data_row_ui(
|
||||||
ui,
|
ui,
|
||||||
Some(obj),
|
Some(obj),
|
||||||
symbol.address as usize,
|
symbol.address,
|
||||||
row_offset,
|
row_offset,
|
||||||
&diffs[i],
|
&symbol_diff.data_rows[i],
|
||||||
appearance,
|
appearance,
|
||||||
column,
|
column,
|
||||||
);
|
);
|
||||||
|
4
objdiff-wasm/package-lock.json
generated
4
objdiff-wasm/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.1.1",
|
"version": "3.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.1.1",
|
"version": "3.2.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.3",
|
"@biomejs/biome": "^1.9.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.1.1",
|
"version": "3.2.0",
|
||||||
"description": "A local diffing tool for decompilation projects.",
|
"description": "A local diffing tool for decompilation projects.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Luke Street",
|
"name": "Luke Street",
|
||||||
|
@ -26,13 +26,14 @@ use exports::objdiff::core::{
|
|||||||
diff::{
|
diff::{
|
||||||
DiffConfigBorrow, DiffResult, DiffSide, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
DiffConfigBorrow, DiffResult, DiffSide, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
||||||
GuestObjectDiff, MappingConfig, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
GuestObjectDiff, MappingConfig, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
||||||
SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
SectionKind, SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
||||||
},
|
},
|
||||||
display::{
|
display::{
|
||||||
ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode,
|
ContextItem, ContextItemCopy, ContextItemNavigate, DataDiff, DataDiffKind, DataDiffRow,
|
||||||
DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem,
|
DataRelocationDiff, DiffText, DiffTextColor, DiffTextOpcode, DiffTextSegment,
|
||||||
HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay,
|
DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem, HoverItemColor,
|
||||||
SymbolDisplay, SymbolFilter, SymbolNavigationKind,
|
HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay, SymbolDisplay,
|
||||||
|
SymbolFilter, SymbolNavigationKind,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -138,6 +139,7 @@ impl GuestDisplay for Component {
|
|||||||
size: d.size,
|
size: d.size,
|
||||||
match_percent: d.match_percent,
|
match_percent: d.match_percent,
|
||||||
symbols: d.symbols.into_iter().map(to_symbol_ref).collect(),
|
symbols: d.symbols.into_iter().map(to_symbol_ref).collect(),
|
||||||
|
kind: d.kind.into(),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -162,6 +164,7 @@ impl GuestDisplay for Component {
|
|||||||
} else {
|
} else {
|
||||||
obj_diff.symbols.get(symbol_display.symbol)
|
obj_diff.symbols.get(symbol_display.symbol)
|
||||||
};
|
};
|
||||||
|
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||||
SymbolDisplay {
|
SymbolDisplay {
|
||||||
info: SymbolInfo {
|
info: SymbolInfo {
|
||||||
id: to_symbol_ref(symbol_display),
|
id: to_symbol_ref(symbol_display),
|
||||||
@ -171,9 +174,8 @@ impl GuestDisplay for Component {
|
|||||||
size: symbol.size,
|
size: symbol.size,
|
||||||
kind: SymbolKind::from(symbol.kind),
|
kind: SymbolKind::from(symbol.kind),
|
||||||
section: symbol.section.map(|s| s as u32),
|
section: symbol.section.map(|s| s as u32),
|
||||||
section_name: symbol
|
section_name: section.map(|sec| sec.name.clone()),
|
||||||
.section
|
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
|
||||||
flags: SymbolFlags::from(symbol.flags),
|
flags: SymbolFlags::from(symbol.flags),
|
||||||
align: symbol.align.map(|a| a.get()),
|
align: symbol.align.map(|a| a.get()),
|
||||||
virtual_address: symbol.virtual_address,
|
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)),
|
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),
|
match_percent: symbol_diff.and_then(|sd| sd.match_percent),
|
||||||
diff_score: symbol_diff.and_then(|sd| sd.diff_score),
|
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)
|
.map(HoverItem::from)
|
||||||
.collect()
|
.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 {
|
impl From<obj::SymbolKind> for SymbolKind {
|
||||||
@ -523,6 +640,7 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
let symbol = obj.symbols.get(symbol_idx)?;
|
let symbol = obj.symbols.get(symbol_idx)?;
|
||||||
|
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||||
Some(SymbolInfo {
|
Some(SymbolInfo {
|
||||||
id: symbol_idx as SymbolRef,
|
id: symbol_idx as SymbolRef,
|
||||||
name: symbol.name.clone(),
|
name: symbol.name.clone(),
|
||||||
@ -531,9 +649,8 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
|||||||
size: symbol.size,
|
size: symbol.size,
|
||||||
kind: SymbolKind::from(symbol.kind),
|
kind: SymbolKind::from(symbol.kind),
|
||||||
section: symbol.section.map(|s| s as u32),
|
section: symbol.section.map(|s| s as u32),
|
||||||
section_name: symbol
|
section_name: section.map(|sec| sec.name.clone()),
|
||||||
.section
|
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
|
||||||
flags: SymbolFlags::from(symbol.flags),
|
flags: SymbolFlags::from(symbol.flags),
|
||||||
align: symbol.align.map(|a| a.get()),
|
align: symbol.align.map(|a| a.get()),
|
||||||
virtual_address: symbol.virtual_address,
|
virtual_address: symbol.virtual_address,
|
||||||
@ -544,6 +661,7 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
|||||||
let obj = self.0.as_ref();
|
let obj = self.0.as_ref();
|
||||||
let symbol_display = from_symbol_ref(symbol_ref);
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
let symbol = obj.symbols.get(symbol_display.symbol)?;
|
let symbol = obj.symbols.get(symbol_display.symbol)?;
|
||||||
|
let section = symbol.section.and_then(|s| obj.sections.get(s));
|
||||||
Some(SymbolInfo {
|
Some(SymbolInfo {
|
||||||
id: to_symbol_ref(symbol_display),
|
id: to_symbol_ref(symbol_display),
|
||||||
name: symbol.name.clone(),
|
name: symbol.name.clone(),
|
||||||
@ -552,9 +670,8 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
|||||||
size: symbol.size,
|
size: symbol.size,
|
||||||
kind: SymbolKind::from(symbol.kind),
|
kind: SymbolKind::from(symbol.kind),
|
||||||
section: symbol.section.map(|s| s as u32),
|
section: symbol.section.map(|s| s as u32),
|
||||||
section_name: symbol
|
section_name: section.map(|sec| sec.name.clone()),
|
||||||
.section
|
section_kind: section.map_or(SectionKind::Unknown, |sec| sec.kind.into()),
|
||||||
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
|
||||||
flags: SymbolFlags::from(symbol.flags),
|
flags: SymbolFlags::from(symbol.flags),
|
||||||
align: symbol.align.map(|a| a.get()),
|
align: symbol.align.map(|a| a.get()),
|
||||||
virtual_address: symbol.virtual_address,
|
virtual_address: symbol.virtual_address,
|
||||||
@ -639,6 +756,7 @@ impl Default for SymbolInfo {
|
|||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
section: Default::default(),
|
section: Default::default(),
|
||||||
section_name: Default::default(),
|
section_name: Default::default(),
|
||||||
|
section_kind: Default::default(),
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
align: Default::default(),
|
align: Default::default(),
|
||||||
virtual_address: 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);
|
export!(Component);
|
||||||
|
@ -54,6 +54,7 @@ interface diff {
|
|||||||
kind: symbol-kind,
|
kind: symbol-kind,
|
||||||
section: option<u32>,
|
section: option<u32>,
|
||||||
section-name: option<string>,
|
section-name: option<string>,
|
||||||
|
section-kind: section-kind,
|
||||||
%flags: symbol-flags,
|
%flags: symbol-flags,
|
||||||
align: option<u32>,
|
align: option<u32>,
|
||||||
virtual-address: option<u64>,
|
virtual-address: option<u64>,
|
||||||
@ -86,6 +87,14 @@ interface diff {
|
|||||||
target,
|
target,
|
||||||
base,
|
base,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum section-kind {
|
||||||
|
unknown,
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
bss,
|
||||||
|
common,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface display {
|
interface display {
|
||||||
@ -94,7 +103,8 @@ interface display {
|
|||||||
object-diff,
|
object-diff,
|
||||||
diff-config,
|
diff-config,
|
||||||
symbol-info,
|
symbol-info,
|
||||||
symbol-ref
|
symbol-ref,
|
||||||
|
section-kind
|
||||||
};
|
};
|
||||||
|
|
||||||
record display-config {
|
record display-config {
|
||||||
@ -114,6 +124,7 @@ interface display {
|
|||||||
size: u64,
|
size: u64,
|
||||||
match-percent: option<f32>,
|
match-percent: option<f32>,
|
||||||
symbols: list<symbol-ref>,
|
symbols: list<symbol-ref>,
|
||||||
|
kind: section-kind,
|
||||||
}
|
}
|
||||||
|
|
||||||
record symbol-display {
|
record symbol-display {
|
||||||
@ -238,6 +249,31 @@ interface display {
|
|||||||
delete,
|
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(
|
display-sections: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
filter: symbol-filter,
|
filter: symbol-filter,
|
||||||
@ -279,6 +315,24 @@ interface display {
|
|||||||
row-index: u32,
|
row-index: u32,
|
||||||
config: borrow<diff-config>,
|
config: borrow<diff-config>,
|
||||||
) -> list<hover-item>;
|
) -> 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 {
|
world api {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user