mirror of
https://github.com/encounter/objdiff.git
synced 2025-10-05 09:29:51 +00:00
Implement diffing individual data symbols (#244)
* Implement diffing individual data symbols * Remove unused code for diffing sections * Data diff view: Make rows show offset within the symbol, not within the section * Remove SelectedSymbol enum as it only has a single variant now * Create fake data section symbols to allow diffing entire sections again * Fix text sections not having their size zeroed out * Update test snapshots * Clean up code for inferring section symbol size * Fix bug where PPC pool references weren't ignoring section symbols * Update comment * Always add unique section symbols for data sections * Update test snapshots * Remove unnecessary clone in format! call * Auto-start mapping for unpaired data symbols
This commit is contained in:
parent
6fb4bb8855
commit
23009bf9a3
@ -9,7 +9,7 @@ use objdiff_core::{
|
||||
},
|
||||
config::path::platform_path,
|
||||
diff,
|
||||
obj::{self, SectionKind, SymbolFlag},
|
||||
obj::{self, SectionKind, SymbolFlag, SymbolKind},
|
||||
};
|
||||
use prost::Message;
|
||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||
@ -247,6 +247,7 @@ fn report_object(
|
||||
|| symbol.size == 0
|
||||
|| symbol.flags.contains(SymbolFlag::Hidden)
|
||||
|| symbol.flags.contains(SymbolFlag::Ignored)
|
||||
|| symbol.kind == SymbolKind::Section
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use crate::{
|
||||
obj::{
|
||||
FlowAnalysisResult, InstructionRef, Object, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedRelocation, Section, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
SymbolKind,
|
||||
},
|
||||
};
|
||||
|
||||
@ -832,6 +833,7 @@ fn make_fake_pool_reloc(
|
||||
&& s.size > 0
|
||||
&& !s.flags.contains(SymbolFlag::Hidden)
|
||||
&& !s.flags.contains(SymbolFlag::Ignored)
|
||||
&& s.kind != SymbolKind::Section
|
||||
&& (s.address..s.address + s.size).contains(&target_address)
|
||||
})?;
|
||||
addend = target_address.checked_sub(symbols[target_symbol].address)? as i64;
|
||||
|
@ -41,7 +41,13 @@ pub fn no_diff_code(
|
||||
instruction_rows.push(InstructionDiffRow { ins_ref: Some(*i), ..Default::default() });
|
||||
}
|
||||
resolve_branches(&ops, &mut instruction_rows);
|
||||
Ok(SymbolDiff { target_symbol: None, match_percent: None, diff_score: None, instruction_rows })
|
||||
Ok(SymbolDiff {
|
||||
target_symbol: None,
|
||||
match_percent: None,
|
||||
diff_score: None,
|
||||
instruction_rows,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
const PENALTY_IMM_DIFF: u64 = 1;
|
||||
@ -147,12 +153,14 @@ pub fn diff_code(
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: Some((diff_score, max_score)),
|
||||
instruction_rows: left_rows,
|
||||
..Default::default()
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(left_symbol_idx),
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: Some((diff_score, max_score)),
|
||||
instruction_rows: right_rows,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ pub fn diff_bss_symbol(
|
||||
target_symbol: Some(right_symbol_ref),
|
||||
match_percent: Some(percent),
|
||||
diff_score: None,
|
||||
instruction_rows: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(left_symbol_ref),
|
||||
match_percent: Some(percent),
|
||||
diff_score: None,
|
||||
instruction_rows: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
}
|
||||
@ -84,7 +84,83 @@ pub fn resolve_relocation<'obj>(
|
||||
ResolvedRelocation { relocation: reloc, symbol }
|
||||
}
|
||||
|
||||
/// Compares relocations contained with a certain data range.
|
||||
/// Compares the bytes within a certain data range.
|
||||
fn diff_data_range(left_data: &[u8], right_data: &[u8]) -> (f32, Vec<DataDiff>, Vec<DataDiff>) {
|
||||
let ops = capture_diff_slices(Algorithm::Patience, left_data, right_data);
|
||||
let bytes_match_ratio = get_diff_ratio(&ops, left_data.len(), right_data.len());
|
||||
|
||||
let mut left_data_diff = Vec::<DataDiff>::new();
|
||||
let mut right_data_diff = Vec::<DataDiff>::new();
|
||||
for op in ops {
|
||||
let (tag, left_range, right_range) = op.as_tag_tuple();
|
||||
let left_len = left_range.len();
|
||||
let right_len = right_range.len();
|
||||
let mut len = left_len.max(right_len);
|
||||
let kind = match tag {
|
||||
similar::DiffTag::Equal => DataDiffKind::None,
|
||||
similar::DiffTag::Delete => DataDiffKind::Delete,
|
||||
similar::DiffTag::Insert => DataDiffKind::Insert,
|
||||
similar::DiffTag::Replace => {
|
||||
// Ensure replacements are equal length
|
||||
len = left_len.min(right_len);
|
||||
DataDiffKind::Replace
|
||||
}
|
||||
};
|
||||
let left_data = &left_data[left_range];
|
||||
let right_data = &right_data[right_range];
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[..len.min(left_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[..len.min(right_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
if kind == DataDiffKind::Replace {
|
||||
match left_len.cmp(&right_len) {
|
||||
Ordering::Less => {
|
||||
let len = right_len - left_len;
|
||||
left_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[left_len..right_len].to_vec(),
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ordering::Greater => {
|
||||
let len = left_len - right_len;
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[right_len..left_len].to_vec(),
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(bytes_match_ratio, left_data_diff, right_data_diff)
|
||||
}
|
||||
|
||||
/// Compares relocations contained within a certain data range.
|
||||
fn diff_data_relocs_for_range<'left, 'right>(
|
||||
left_obj: &'left Object,
|
||||
right_obj: &'right Object,
|
||||
@ -186,76 +262,10 @@ pub fn diff_data_section(
|
||||
.min(right_section.size);
|
||||
let left_data = &left_section.data[..left_max as usize];
|
||||
let right_data = &right_section.data[..right_max as usize];
|
||||
let ops = capture_diff_slices(Algorithm::Patience, left_data, right_data);
|
||||
let match_percent = get_diff_ratio(&ops, left_data.len(), right_data.len()) * 100.0;
|
||||
|
||||
let mut left_data_diff = Vec::<DataDiff>::new();
|
||||
let mut right_data_diff = Vec::<DataDiff>::new();
|
||||
for op in ops {
|
||||
let (tag, left_range, right_range) = op.as_tag_tuple();
|
||||
let left_len = left_range.len();
|
||||
let right_len = right_range.len();
|
||||
let mut len = left_len.max(right_len);
|
||||
let kind = match tag {
|
||||
similar::DiffTag::Equal => DataDiffKind::None,
|
||||
similar::DiffTag::Delete => DataDiffKind::Delete,
|
||||
similar::DiffTag::Insert => DataDiffKind::Insert,
|
||||
similar::DiffTag::Replace => {
|
||||
// Ensure replacements are equal length
|
||||
len = left_len.min(right_len);
|
||||
DataDiffKind::Replace
|
||||
}
|
||||
};
|
||||
let left_data = &left_section.data[left_range];
|
||||
let right_data = &right_section.data[right_range];
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[..len.min(left_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[..len.min(right_data.len())].to_vec(),
|
||||
kind,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
if kind == DataDiffKind::Replace {
|
||||
match left_len.cmp(&right_len) {
|
||||
Ordering::Less => {
|
||||
let len = right_len - left_len;
|
||||
left_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: right_data[left_len..right_len].to_vec(),
|
||||
kind: DataDiffKind::Insert,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ordering::Greater => {
|
||||
let len = left_len - right_len;
|
||||
left_data_diff.push(DataDiff {
|
||||
data: left_data[right_len..left_len].to_vec(),
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
right_data_diff.push(DataDiff {
|
||||
data: vec![],
|
||||
kind: DataDiffKind::Delete,
|
||||
len,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
let (bytes_match_ratio, left_data_diff, right_data_diff) =
|
||||
diff_data_range(left_data, right_data);
|
||||
let match_percent = bytes_match_ratio * 100.0;
|
||||
|
||||
let mut left_reloc_diffs = Vec::new();
|
||||
let mut right_reloc_diffs = Vec::new();
|
||||
@ -314,6 +324,55 @@ pub fn diff_data_section(
|
||||
Ok((left_section_diff, right_section_diff))
|
||||
}
|
||||
|
||||
pub fn no_diff_data_symbol(obj: &Object, symbol_index: usize) -> Result<SymbolDiff> {
|
||||
let symbol = &obj.symbols[symbol_index];
|
||||
let section_idx = symbol.section.ok_or_else(|| anyhow!("Data symbol section not found"))?;
|
||||
let section = &obj.sections[section_idx];
|
||||
|
||||
let start = symbol
|
||||
.address
|
||||
.checked_sub(section.address)
|
||||
.ok_or_else(|| anyhow!("Symbol address out of section bounds"))?;
|
||||
let end = start + symbol.size;
|
||||
if end > section.size {
|
||||
return Err(anyhow!(
|
||||
"Symbol {} size out of section bounds ({} > {})",
|
||||
symbol.name,
|
||||
end,
|
||||
section.size
|
||||
));
|
||||
}
|
||||
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 mut reloc_diffs = Vec::new();
|
||||
for reloc in section.relocations.iter() {
|
||||
if !range.contains(&(reloc.address as usize)) {
|
||||
continue;
|
||||
}
|
||||
let reloc_len = obj.arch.data_reloc_size(reloc.flags);
|
||||
let range = reloc.address as usize..reloc.address as usize + reloc_len;
|
||||
reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: reloc.clone(),
|
||||
kind: DataDiffKind::None,
|
||||
range,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(SymbolDiff {
|
||||
target_symbol: None,
|
||||
match_percent: None,
|
||||
diff_score: None,
|
||||
data_diff,
|
||||
data_reloc_diff: reloc_diffs,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn diff_data_symbol(
|
||||
left_obj: &Object,
|
||||
right_obj: &Object,
|
||||
@ -362,6 +421,9 @@ pub fn diff_data_symbol(
|
||||
let left_data = &left_section.data[left_range.clone()];
|
||||
let right_data = &right_section.data[right_range.clone()];
|
||||
|
||||
let (bytes_match_ratio, left_data_diff, right_data_diff) =
|
||||
diff_data_range(left_data, right_data);
|
||||
|
||||
let reloc_diffs = diff_data_relocs_for_range(
|
||||
left_obj,
|
||||
right_obj,
|
||||
@ -371,10 +433,9 @@ pub fn diff_data_symbol(
|
||||
right_range,
|
||||
);
|
||||
|
||||
let ops = capture_diff_slices(Algorithm::Patience, left_data, right_data);
|
||||
let bytes_match_ratio = get_diff_ratio(&ops, left_data.len(), right_data.len());
|
||||
|
||||
let mut match_ratio = bytes_match_ratio;
|
||||
let mut left_reloc_diffs = Vec::new();
|
||||
let mut right_reloc_diffs = Vec::new();
|
||||
if !reloc_diffs.is_empty() {
|
||||
let mut total_reloc_bytes = 0;
|
||||
let mut matching_reloc_bytes = 0;
|
||||
@ -390,6 +451,27 @@ pub fn diff_data_symbol(
|
||||
if diff_kind == DataDiffKind::None {
|
||||
matching_reloc_bytes += reloc_diff_len;
|
||||
}
|
||||
|
||||
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;
|
||||
left_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: left_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
range,
|
||||
});
|
||||
}
|
||||
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;
|
||||
right_reloc_diffs.push(DataRelocationDiff {
|
||||
reloc: right_reloc.relocation.clone(),
|
||||
kind: diff_kind,
|
||||
range,
|
||||
});
|
||||
}
|
||||
}
|
||||
if total_reloc_bytes > 0 {
|
||||
let relocs_match_ratio = matching_reloc_bytes as f32 / total_reloc_bytes as f32;
|
||||
@ -411,13 +493,17 @@ pub fn diff_data_symbol(
|
||||
target_symbol: Some(right_symbol_idx),
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: None,
|
||||
instruction_rows: vec![],
|
||||
data_diff: left_data_diff,
|
||||
data_reloc_diff: left_reloc_diffs,
|
||||
..Default::default()
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(left_symbol_idx),
|
||||
match_percent: Some(match_percent),
|
||||
diff_score: None,
|
||||
instruction_rows: vec![],
|
||||
data_diff: right_data_diff,
|
||||
data_reloc_diff: right_reloc_diffs,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ use crate::{
|
||||
code::{diff_code, no_diff_code},
|
||||
data::{
|
||||
diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol,
|
||||
diff_generic_section, no_diff_bss_section, no_diff_data_section, symbol_name_matches,
|
||||
diff_generic_section, no_diff_bss_section, no_diff_data_section, no_diff_data_symbol,
|
||||
symbol_name_matches,
|
||||
},
|
||||
},
|
||||
obj::{InstructionRef, Object, Relocation, SectionKind, Symbol, SymbolFlag},
|
||||
@ -44,6 +45,8 @@ 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>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@ -163,7 +166,7 @@ impl ObjectDiff {
|
||||
target_symbol: None,
|
||||
match_percent: None,
|
||||
diff_score: None,
|
||||
instruction_rows: vec![],
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
for _ in obj.sections.iter() {
|
||||
@ -262,7 +265,11 @@ pub fn diff_objs(
|
||||
left_out.symbols[left_symbol_ref] =
|
||||
no_diff_code(left_obj, left_symbol_ref, diff_config)?;
|
||||
}
|
||||
SectionKind::Data | SectionKind::Bss | SectionKind::Common => {
|
||||
SectionKind::Data => {
|
||||
left_out.symbols[left_symbol_ref] =
|
||||
no_diff_data_symbol(left_obj, left_symbol_ref)?;
|
||||
}
|
||||
SectionKind::Bss | SectionKind::Common => {
|
||||
// Nothing needs to be done
|
||||
}
|
||||
SectionKind::Unknown => unreachable!(),
|
||||
@ -275,7 +282,11 @@ pub fn diff_objs(
|
||||
right_out.symbols[right_symbol_ref] =
|
||||
no_diff_code(right_obj, right_symbol_ref, diff_config)?;
|
||||
}
|
||||
SectionKind::Data | SectionKind::Bss | SectionKind::Common => {
|
||||
SectionKind::Data => {
|
||||
right_out.symbols[right_symbol_ref] =
|
||||
no_diff_data_symbol(right_obj, right_symbol_ref)?;
|
||||
}
|
||||
SectionKind::Bss | SectionKind::Common => {
|
||||
// Nothing needs to be done
|
||||
}
|
||||
SectionKind::Unknown => unreachable!(),
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
diff::{DiffObjConfig, DiffSide},
|
||||
obj::{
|
||||
FlowAnalysisResult, Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag,
|
||||
SectionKind, Symbol, SymbolFlag, SymbolKind,
|
||||
SectionKind, Symbol, SymbolFlag, SymbolFlagSet, SymbolKind,
|
||||
split_meta::{SPLITMETA_SECTION, SplitMeta},
|
||||
},
|
||||
util::{align_data_slice_to, align_u64_to, read_u16, read_u32},
|
||||
@ -118,7 +118,7 @@ fn map_symbols(
|
||||
split_meta: Option<&SplitMeta>,
|
||||
) -> Result<(Vec<Symbol>, Vec<usize>)> {
|
||||
let symbol_count = obj_file.symbols().count();
|
||||
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count);
|
||||
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count + obj_file.sections().count());
|
||||
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
|
||||
for obj_symbol in obj_file.symbols() {
|
||||
if symbol_indices.len() <= obj_symbol.index().0 {
|
||||
@ -135,6 +135,52 @@ fn map_symbols(
|
||||
Ok((symbols, symbol_indices))
|
||||
}
|
||||
|
||||
/// Add an extra fake symbol to the start of each data section in order to allow the user to diff
|
||||
/// all of the data in the section at once by clicking on this fake symbol at the top of the list.
|
||||
fn add_section_symbols(sections: &[Section], symbols: &mut Vec<Symbol>) {
|
||||
for (section_idx, section) in sections.iter().enumerate() {
|
||||
if section.kind != SectionKind::Data {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Instead of naming the fake section symbol after `section.name` (e.g. ".data") we use
|
||||
// `section.id` (e.g. ".data-0") so that it is unique when multiple sections with the same
|
||||
// name exist and it also doesn't conflict with any real section symbols from the object.
|
||||
let name = if section.flags.contains(SectionFlag::Combined) {
|
||||
// For combined sections, `section.id` (e.g. ".data-combined") is inconsistent with
|
||||
// uncombined section IDs, so we add the "-0" suffix to the name to enable proper
|
||||
// pairing when one side had multiple sections combined and the other only had one
|
||||
// section to begin with.
|
||||
format!("[{}-0]", section.name)
|
||||
} else {
|
||||
format!("[{}]", section.id)
|
||||
};
|
||||
|
||||
// `section.size` can include extra padding, so instead prefer using the address that the
|
||||
// last symbol ends at when there are any symbols in the section.
|
||||
let size = symbols
|
||||
.iter()
|
||||
.filter(|s| {
|
||||
s.section == Some(section_idx) && s.kind == SymbolKind::Object && s.size > 0
|
||||
})
|
||||
.map(|s| s.address + s.size)
|
||||
.max()
|
||||
.unwrap_or(section.size);
|
||||
|
||||
symbols.push(Symbol {
|
||||
name,
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size,
|
||||
kind: SymbolKind::Section,
|
||||
section: Some(section_idx),
|
||||
flags: SymbolFlagSet::default() | SymbolFlag::Local,
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// When inferring a symbol's size, we ignore symbols that start with specific prefixes. They are
|
||||
/// usually emitted as branch targets and do not represent the start of a function or object.
|
||||
fn is_local_label(symbol: &Symbol) -> bool {
|
||||
@ -216,7 +262,11 @@ fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Secti
|
||||
let section = §ions[section_idx];
|
||||
let next_address =
|
||||
next_symbol.map(|s| s.address).unwrap_or_else(|| section.address + section.size);
|
||||
let new_size = if section.kind == SectionKind::Code {
|
||||
let new_size = if symbol.kind == SymbolKind::Section && section.kind == SectionKind::Data {
|
||||
// Data sections already have always-visible section symbols created by objdiff to allow
|
||||
// diffing them, so no need to unhide these.
|
||||
0
|
||||
} else if section.kind == SectionKind::Code {
|
||||
arch.infer_function_size(symbol, section, next_address)?
|
||||
} else {
|
||||
next_address.saturating_sub(symbol.address)
|
||||
@ -954,6 +1004,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig, diff_side: DiffSide) -> Result
|
||||
if config.combine_data_sections || config.combine_text_sections {
|
||||
combine_sections(&mut sections, &mut symbols, config)?;
|
||||
}
|
||||
add_section_symbols(§ions, &mut symbols);
|
||||
arch.post_init(§ions, &symbols);
|
||||
let mut obj = Object {
|
||||
arch,
|
||||
|
@ -1507,6 +1507,19 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.data-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 76,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
2,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -449,4 +449,17 @@ expression: obj.symbols
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.data-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
2,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
]
|
||||
|
@ -10,10 +10,10 @@ expression: output
|
||||
[(Address(20), Normal, 5), (Spacing(4), Normal, 0), (Opcode("jal", 2), Normal, 10), (Symbol(Symbol { name: "xglSleep", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(24), Normal, 5), (Spacing(4), Normal, 0), (Opcode("nop", 113), Normal, 10), (Eol, Normal, 0)]
|
||||
[(Address(28), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lw", 26), Normal, 10), (Argument(Opaque("$a1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%gp_rel("), Normal, 0), (Symbol(Symbol { name: "WorkEnd", demangled_name: None, address: 64, size: 4, kind: Object, section: Some(8), flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("$gp")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(32), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lui", 20), Normal, 10), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%hi("), Normal, 0), (Symbol(Symbol { name: "[.sdata]", demangled_name: None, address: 0, size: 64, kind: Section, section: Some(8), flags: FlagSet(Local), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(32), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lui", 20), Normal, 10), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%hi("), Normal, 0), (Symbol(Symbol { name: "[.sdata]", demangled_name: None, address: 0, size: 0, kind: Section, section: Some(8), flags: FlagSet(Local), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(36), Normal, 5), (Spacing(4), Normal, 0), (Opcode("daddu", 97), Normal, 10), (Argument(Opaque("$a2")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("$zero")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("$zero")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(40), Normal, 5), (Spacing(4), Normal, 0), (Opcode("jal", 2), Normal, 10), (Symbol(Symbol { name: "xglSoundLoadEffect", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(44), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addiu", 12), Normal, 10), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%lo("), Normal, 0), (Symbol(Symbol { name: "[.sdata]", demangled_name: None, address: 0, size: 64, kind: Section, section: Some(8), flags: FlagSet(Local), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(44), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addiu", 12), Normal, 10), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%lo("), Normal, 0), (Symbol(Symbol { name: "[.sdata]", demangled_name: None, address: 0, size: 0, kind: Section, section: Some(8), flags: FlagSet(Local), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(48), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lui", 20), Normal, 10), (Argument(Opaque("$a0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%hi("), Normal, 0), (Symbol(Symbol { name: "PacketBottomNewVu1DropMicroCode", demangled_name: None, address: 0, size: 12, kind: Object, section: Some(7), flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(52), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lw", 26), Normal, 10), (Argument(Opaque("$a1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("%gp_rel("), Normal, 0), (Symbol(Symbol { name: "WorkEnd", demangled_name: None, address: 64, size: 4, kind: Object, section: Some(8), flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Basic(")"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("$gp")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(56), Normal, 5), (Spacing(4), Normal, 0), (Opcode("jal", 2), Normal, 10), (Symbol(Symbol { name: "xglSoundLoadSwd", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
|
@ -112,7 +112,7 @@ Object {
|
||||
name: "[.sdata]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 64,
|
||||
size: 0,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
8,
|
||||
@ -673,6 +673,45 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.data-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
2,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rodata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
7,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.sdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 76,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
8,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -2645,6 +2645,8 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
||||
arg_diff: [],
|
||||
},
|
||||
],
|
||||
data_diff: [],
|
||||
data_reloc_diff: [],
|
||||
},
|
||||
SymbolDiff {
|
||||
target_symbol: Some(
|
||||
@ -5288,5 +5290,7 @@ expression: "(target_symbol_diff, base_symbol_diff)"
|
||||
arg_diff: [],
|
||||
},
|
||||
],
|
||||
data_diff: [],
|
||||
data_reloc_diff: [],
|
||||
},
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
---
|
||||
source: objdiff-core/tests/arch_ppc.rs
|
||||
assertion_line: 70
|
||||
expression: sections_display
|
||||
---
|
||||
[
|
||||
@ -37,7 +36,7 @@ expression: sections_display
|
||||
),
|
||||
symbols: [
|
||||
SectionDisplaySymbol {
|
||||
symbol: 2,
|
||||
symbol: 16,
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
],
|
||||
|
@ -308,6 +308,32 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[extab-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 40,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
1,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[extabindex-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 36,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
2,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -43,7 +43,7 @@ Object {
|
||||
name: "[.ctors]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 4,
|
||||
size: 0,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
1,
|
||||
@ -157,6 +157,19 @@ Object {
|
||||
0,
|
||||
),
|
||||
},
|
||||
Symbol {
|
||||
name: "[.ctors-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 4,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
1,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -1101,6 +1101,45 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.XBLD$W-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 16,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
2,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 416,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
4,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 40,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
6,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -124,6 +124,19 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.data-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 10,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
1,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -854,6 +854,201 @@ Object {
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.xdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
7,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
8,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.xdata-1]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
9,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-1]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
10,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.xdata-2]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
11,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-2]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
12,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.xdata-3]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
13,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-3]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
14,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rdata-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 256,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
15,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.xdata-4]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 20,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
16,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.pdata-4]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 12,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
17,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rtc$IMZ-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
19,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rtc$TMZ-0]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
20,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rdata-1]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 4,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
21,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
Symbol {
|
||||
name: "[.rdata-2]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 4,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
22,
|
||||
),
|
||||
flags: FlagSet(Local),
|
||||
align: None,
|
||||
virtual_address: None,
|
||||
},
|
||||
],
|
||||
sections: [
|
||||
Section {
|
||||
|
@ -115,7 +115,8 @@ fn get_hover_item_color_for_diff_kind(diff_kind: DataDiffKind) -> HoverItemColor
|
||||
pub(crate) fn data_row_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: Option<&Object>,
|
||||
address: usize,
|
||||
base_address: usize,
|
||||
row_address: usize,
|
||||
diffs: &[(DataDiff, Vec<DataRelocationDiff>)],
|
||||
appearance: &Appearance,
|
||||
column: usize,
|
||||
@ -127,7 +128,7 @@ pub(crate) fn data_row_ui(
|
||||
}
|
||||
let mut job = LayoutJob::default();
|
||||
write_text(
|
||||
format!("{address:08x}: ").as_str(),
|
||||
format!("{row_address:08x}: ").as_str(),
|
||||
appearance.text_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
@ -135,7 +136,7 @@ pub(crate) fn data_row_ui(
|
||||
// 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 = address;
|
||||
let mut cur_addr_actual = base_address + row_address;
|
||||
for (diff, reloc_diffs) in diffs {
|
||||
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
||||
if diff.data.is_empty() {
|
||||
@ -211,13 +212,14 @@ pub(crate) fn data_row_ui(
|
||||
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 = 0usize;
|
||||
let mut cur_addr_actual = symbol_offset_in_section;
|
||||
for diff in diffs {
|
||||
let mut cur_len = 0usize;
|
||||
while cur_len < diff.len {
|
||||
|
@ -2,10 +2,10 @@ use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJ
|
||||
use objdiff_core::{
|
||||
build::BuildStatus,
|
||||
diff::{
|
||||
DiffObjConfig, ObjectDiff, SectionDiff, SymbolDiff,
|
||||
DiffObjConfig, ObjectDiff, SymbolDiff,
|
||||
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
|
||||
},
|
||||
obj::{Object, Section, Symbol},
|
||||
obj::{Object, Symbol},
|
||||
};
|
||||
use time::format_description;
|
||||
|
||||
@ -25,17 +25,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum SelectedSymbol {
|
||||
Symbol(usize),
|
||||
Section(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct DiffColumnContext<'a> {
|
||||
status: &'a BuildStatus,
|
||||
obj: Option<&'a (Object, ObjectDiff)>,
|
||||
section: Option<(&'a Section, &'a SectionDiff, usize)>,
|
||||
symbol: Option<(&'a Symbol, &'a SymbolDiff, usize)>,
|
||||
}
|
||||
|
||||
@ -46,49 +39,28 @@ impl<'a> DiffColumnContext<'a> {
|
||||
obj: Option<&'a (Object, ObjectDiff)>,
|
||||
selected_symbol: Option<&SymbolRefByName>,
|
||||
) -> Self {
|
||||
let selected_symbol = match view {
|
||||
let selected_symbol_idx = match view {
|
||||
View::SymbolDiff => None,
|
||||
View::FunctionDiff | View::ExtabDiff => match (obj, selected_symbol) {
|
||||
(Some(obj), Some(s)) => {
|
||||
obj.0.symbol_by_name(&s.symbol_name).map(SelectedSymbol::Symbol)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
View::DataDiff => match (obj, selected_symbol) {
|
||||
(Some(obj), Some(SymbolRefByName { section_name: Some(section_name), .. })) => {
|
||||
find_section(&obj.0, section_name).map(SelectedSymbol::Section)
|
||||
}
|
||||
View::FunctionDiff | View::DataDiff | View::ExtabDiff => match (obj, selected_symbol) {
|
||||
(Some(obj), Some(s)) => obj.0.symbol_by_name(&s.symbol_name),
|
||||
_ => None,
|
||||
},
|
||||
};
|
||||
let (section, symbol) = match (obj, selected_symbol) {
|
||||
(Some((obj, obj_diff)), Some(SelectedSymbol::Symbol(symbol_ref))) => {
|
||||
let symbol = match (obj, selected_symbol_idx) {
|
||||
(Some((obj, obj_diff)), Some(symbol_ref)) => {
|
||||
let symbol = &obj.symbols[symbol_ref];
|
||||
(
|
||||
symbol.section.map(|section_idx| {
|
||||
(&obj.sections[section_idx], &obj_diff.sections[section_idx], section_idx)
|
||||
}),
|
||||
Some((symbol, &obj_diff.symbols[symbol_ref], symbol_ref)),
|
||||
)
|
||||
Some((symbol, &obj_diff.symbols[symbol_ref], symbol_ref))
|
||||
}
|
||||
(Some((obj, obj_diff)), Some(SelectedSymbol::Section(section_idx))) => (
|
||||
Some((&obj.sections[section_idx], &obj_diff.sections[section_idx], section_idx)),
|
||||
None,
|
||||
),
|
||||
_ => (None, None),
|
||||
_ => None,
|
||||
};
|
||||
Self { status, obj, section, symbol }
|
||||
Self { status, obj, symbol }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_symbol(&self) -> bool { self.section.is_some() || self.symbol.is_some() }
|
||||
pub fn has_symbol(&self) -> bool { self.symbol.is_some() }
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> Option<&str> {
|
||||
self.symbol
|
||||
.map(|(symbol, _, _)| symbol.name.as_str())
|
||||
.or_else(|| self.section.map(|(section, _, _)| section.name.as_str()))
|
||||
}
|
||||
pub fn id(&self) -> Option<&str> { self.symbol.map(|(symbol, _, _)| symbol.name.as_str()) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -133,10 +105,7 @@ pub fn diff_view_ui(
|
||||
{
|
||||
navigation.right_symbol = Some(target_symbol_ref);
|
||||
}
|
||||
} else if navigation.left_symbol.is_some()
|
||||
&& left_ctx.obj.is_some()
|
||||
&& left_ctx.section.is_none()
|
||||
{
|
||||
} else if navigation.left_symbol.is_some() && left_ctx.obj.is_some() {
|
||||
// Clear selection if symbol goes missing
|
||||
navigation.left_symbol = None;
|
||||
}
|
||||
@ -147,10 +116,7 @@ pub fn diff_view_ui(
|
||||
{
|
||||
navigation.left_symbol = Some(target_symbol_ref);
|
||||
}
|
||||
} else if navigation.right_symbol.is_some()
|
||||
&& right_ctx.obj.is_some()
|
||||
&& right_ctx.section.is_none()
|
||||
{
|
||||
} else if navigation.right_symbol.is_some() && right_ctx.obj.is_some() {
|
||||
// Clear selection if symbol goes missing
|
||||
navigation.right_symbol = None;
|
||||
}
|
||||
@ -225,12 +191,6 @@ pub fn diff_view_ui(
|
||||
{
|
||||
ret = Some(action);
|
||||
}
|
||||
} else if let Some((section, _, _)) = left_ctx.section {
|
||||
ui.label(
|
||||
RichText::new(section.name.clone())
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.highlight_color),
|
||||
);
|
||||
} else if right_ctx.has_symbol() {
|
||||
ui.label(
|
||||
RichText::new("Choose target symbol")
|
||||
@ -363,12 +323,6 @@ pub fn diff_view_ui(
|
||||
{
|
||||
ret = Some(action);
|
||||
}
|
||||
} else if let Some((section, _, _)) = right_ctx.section {
|
||||
ui.label(
|
||||
RichText::new(section.name.clone())
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.highlight_color),
|
||||
);
|
||||
} else if left_ctx.has_symbol() {
|
||||
ui.label(
|
||||
RichText::new("Choose base symbol")
|
||||
@ -509,17 +463,17 @@ pub fn diff_view_ui(
|
||||
View::DataDiff,
|
||||
Some((left_obj, _left_diff)),
|
||||
Some((right_obj, _right_diff)),
|
||||
Some((_left_section, left_section_diff, _left_symbol_idx)),
|
||||
Some((_right_section, right_section_diff, _right_symbol_idx)),
|
||||
Some((left_symbol, left_symbol_diff, _left_symbol_idx)),
|
||||
Some((right_symbol, right_symbol_diff, _right_symbol_idx)),
|
||||
) =
|
||||
(state.current_view, left_ctx.obj, right_ctx.obj, left_ctx.section, right_ctx.section)
|
||||
(state.current_view, left_ctx.obj, right_ctx.obj, left_ctx.symbol, right_ctx.symbol)
|
||||
{
|
||||
// Joint diff view
|
||||
hotkeys::check_scroll_hotkeys(ui, true);
|
||||
let left_total_bytes =
|
||||
left_section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
left_symbol_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
let right_total_bytes =
|
||||
right_section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
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;
|
||||
@ -528,10 +482,16 @@ pub fn diff_view_ui(
|
||||
return;
|
||||
}
|
||||
let total_rows = (left_total_bytes - 1) / BYTES_PER_ROW + 1;
|
||||
let left_diffs =
|
||||
split_diffs(&left_section_diff.data_diff, &left_section_diff.reloc_diff);
|
||||
let right_diffs =
|
||||
split_diffs(&right_section_diff.data_diff, &right_section_diff.reloc_diff);
|
||||
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,
|
||||
@ -540,13 +500,14 @@ pub fn diff_view_ui(
|
||||
total_rows,
|
||||
|row, column| {
|
||||
let i = row.index();
|
||||
let address = i * BYTES_PER_ROW;
|
||||
let row_offset = i * BYTES_PER_ROW;
|
||||
row.col(|ui| {
|
||||
if column == 0 {
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(left_obj),
|
||||
address,
|
||||
left_symbol.address as usize,
|
||||
row_offset,
|
||||
&left_diffs[i],
|
||||
appearance,
|
||||
column,
|
||||
@ -555,7 +516,8 @@ pub fn diff_view_ui(
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(right_obj),
|
||||
address,
|
||||
right_symbol.address as usize,
|
||||
row_offset,
|
||||
&right_diffs[i],
|
||||
appearance,
|
||||
column,
|
||||
@ -649,11 +611,46 @@ fn diff_col_ui(
|
||||
if !ctx.status.success {
|
||||
build_log_ui(ui, ctx.status, appearance);
|
||||
} else if let Some((obj, diff)) = ctx.obj {
|
||||
if let Some((_symbol, symbol_diff, symbol_idx)) = ctx.symbol {
|
||||
if let Some((symbol, symbol_diff, symbol_idx)) = ctx.symbol {
|
||||
hotkeys::check_scroll_hotkeys(ui, false);
|
||||
let ctx = FunctionDiffContext { obj, diff, symbol_ref: Some(symbol_idx) };
|
||||
if state.current_view == View::ExtabDiff {
|
||||
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 {
|
||||
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,
|
||||
1,
|
||||
appearance.code_font.size,
|
||||
total_rows,
|
||||
|row, _column| {
|
||||
let i = row.index();
|
||||
let row_offset = i * BYTES_PER_ROW;
|
||||
row.col(|ui| {
|
||||
data_row_ui(
|
||||
ui,
|
||||
Some(obj),
|
||||
symbol.address as usize,
|
||||
row_offset,
|
||||
&diffs[i],
|
||||
appearance,
|
||||
column,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
render_table(
|
||||
ui,
|
||||
@ -678,29 +675,6 @@ fn diff_col_ui(
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if let Some((_section, section_diff, _section_idx)) = ctx.section {
|
||||
hotkeys::check_scroll_hotkeys(ui, false);
|
||||
let total_bytes =
|
||||
section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
if total_bytes == 0 {
|
||||
return ret;
|
||||
}
|
||||
let total_rows = (total_bytes - 1) / BYTES_PER_ROW + 1;
|
||||
let diffs = split_diffs(§ion_diff.data_diff, §ion_diff.reloc_diff);
|
||||
render_table(
|
||||
ui,
|
||||
available_width / 2.0,
|
||||
1,
|
||||
appearance.code_font.size,
|
||||
total_rows,
|
||||
|row, _column| {
|
||||
let i = row.index();
|
||||
let address = i * BYTES_PER_ROW;
|
||||
row.col(|ui| {
|
||||
data_row_ui(ui, Some(obj), address, &diffs[i], appearance, column);
|
||||
});
|
||||
},
|
||||
);
|
||||
} else if let Some((_other_symbol, _other_symbol_diff, other_symbol_idx)) = other_ctx.symbol
|
||||
{
|
||||
if let Some(action) = symbol_list_ui(
|
||||
@ -796,10 +770,6 @@ fn missing_obj_ui(ui: &mut Ui, appearance: &Appearance) {
|
||||
});
|
||||
}
|
||||
|
||||
fn find_section(obj: &Object, section_name: &str) -> Option<usize> {
|
||||
obj.sections.iter().position(|section| section.name == section_name)
|
||||
}
|
||||
|
||||
pub fn hover_items_ui(ui: &mut Ui, items: Vec<HoverItem>, appearance: &Appearance) {
|
||||
for item in items {
|
||||
match item {
|
||||
|
@ -233,7 +233,6 @@ impl DiffViewState {
|
||||
let resolved_nav = resolve_navigation(nav.kind, resolved_left, resolved_right);
|
||||
if (resolved_nav.left_symbol.is_some() && resolved_nav.right_symbol.is_some())
|
||||
|| (resolved_nav.left_symbol.is_none() && resolved_nav.right_symbol.is_none())
|
||||
|| resolved_nav.view != View::FunctionDiff
|
||||
{
|
||||
// Regular navigation
|
||||
if state.is_selecting_symbol() {
|
||||
@ -416,14 +415,8 @@ fn resolve_navigation(
|
||||
},
|
||||
(SectionKind::Data, SectionKind::Data) => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
left_symbol: Some(left.symbol_ref),
|
||||
right_symbol: Some(right.symbol_ref),
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
@ -438,14 +431,8 @@ fn resolve_navigation(
|
||||
},
|
||||
SectionKind::Data => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
left_symbol: Some(left.symbol_ref),
|
||||
right_symbol: None,
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
@ -460,14 +447,8 @@ fn resolve_navigation(
|
||||
},
|
||||
SectionKind::Data => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
left_symbol: None,
|
||||
right_symbol: Some(right.symbol_ref),
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user