mirror of
https://github.com/encounter/objdiff.git
synced 2025-06-08 15:43:27 +00:00
Compare commits
15 Commits
v3.0.0-bet
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
f58616b6dd | ||
|
e9762e24c2 | ||
dab79d96a1 | |||
a57e5db983 | |||
|
d0afd3b83e | ||
|
a367af612b | ||
|
22052ea10b | ||
f7c3501eae | |||
07ef93f16a | |||
8e8ab6bef8 | |||
e865f3d598 | |||
2b13e9886a | |||
1750af736a | |||
|
731b604c24 | ||
2d643eb071 |
@ -1,5 +1,4 @@
|
|||||||
[target.x86_64-pc-windows-msvc]
|
# statically link the C runtime so the executable does not depend on
|
||||||
linker = "rust-lld"
|
# that shared/dynamic library.
|
||||||
|
[target.'cfg(all(target_env = "msvc", target_os = "windows"))']
|
||||||
[target.aarch64-pc-windows-msvc]
|
rustflags = ["-C", "target-feature=+crt-static"]
|
||||||
linker = "rust-lld"
|
|
||||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -3373,7 +3373,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "3.0.0-beta.7"
|
version = "3.0.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@ -3396,7 +3396,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "3.0.0-beta.7"
|
version = "3.0.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
@ -3450,7 +3450,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "3.0.0-beta.7"
|
version = "3.0.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -3486,7 +3486,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-wasm"
|
name = "objdiff-wasm"
|
||||||
version = "3.0.0-beta.7"
|
version = "3.0.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
|
@ -14,7 +14,7 @@ strip = "debuginfo"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.0.0-beta.7"
|
version = "3.0.0-beta.9"
|
||||||
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"
|
||||||
|
@ -175,6 +175,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "If true, objdiff will run the build command with the context file as an argument to generate it.",
|
"description": "If true, objdiff will run the build command with the context file as an argument to generate it.",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"preset_id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "The decomp.me preset ID to use for the scratch.\nCompiler and flags in the config will take precedence over the preset, but the preset is useful for organizational purposes."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -245,12 +245,14 @@ fn report_object(
|
|||||||
for (symbol, symbol_diff) in obj.symbols.iter().zip(&obj_diff.symbols) {
|
for (symbol, symbol_diff) in obj.symbols.iter().zip(&obj_diff.symbols) {
|
||||||
if symbol.section != Some(section_idx)
|
if symbol.section != Some(section_idx)
|
||||||
|| symbol.size == 0
|
|| symbol.size == 0
|
||||||
|| symbol.flags.contains(SymbolFlag::Hidden | SymbolFlag::Ignored)
|
|| symbol.flags.contains(SymbolFlag::Hidden)
|
||||||
|
|| symbol.flags.contains(SymbolFlag::Ignored)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(existing_functions) = &mut existing_functions {
|
if let Some(existing_functions) = &mut existing_functions {
|
||||||
if symbol.flags.contains(SymbolFlag::Global | SymbolFlag::Weak)
|
if (symbol.flags.contains(SymbolFlag::Global)
|
||||||
|
|| symbol.flags.contains(SymbolFlag::Weak))
|
||||||
&& !existing_functions.insert(symbol.name.clone())
|
&& !existing_functions.insert(symbol.name.clone())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -450,11 +450,11 @@ impl UiView for FunctionDiffUi {
|
|||||||
|
|
||||||
fn reload(&mut self, state: &AppState) -> Result<()> {
|
fn reload(&mut self, state: &AppState) -> Result<()> {
|
||||||
let left_sym =
|
let left_sym =
|
||||||
state.left_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
state.left_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||||
let right_sym =
|
let right_sym =
|
||||||
state.right_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
state.right_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||||
let prev_sym =
|
let prev_sym =
|
||||||
state.prev_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
state.prev_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||||
self.num_rows = match (
|
self.num_rows = match (
|
||||||
get_symbol(state.left_obj.as_ref(), left_sym),
|
get_symbol(state.left_obj.as_ref(), left_sym),
|
||||||
get_symbol(state.right_obj.as_ref(), right_sym),
|
get_symbol(state.right_obj.as_ref(), right_sym),
|
||||||
@ -650,12 +650,3 @@ fn get_symbol(
|
|||||||
let sym = sym?;
|
let sym = sym?;
|
||||||
Some((obj, sym, &diff.symbols[sym]))
|
Some((obj, sym, &diff.symbols[sym]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_function(obj: &Object, name: &str) -> Option<usize> {
|
|
||||||
for (symbol_idx, symbol) in obj.symbols.iter().enumerate() {
|
|
||||||
if symbol.name == name {
|
|
||||||
return Some(symbol_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
@ -41,6 +41,7 @@ any-arch = [
|
|||||||
"dep:regex",
|
"dep:regex",
|
||||||
"dep:similar",
|
"dep:similar",
|
||||||
"dep:syn",
|
"dep:syn",
|
||||||
|
"dep:encoding_rs"
|
||||||
]
|
]
|
||||||
bindings = [
|
bindings = [
|
||||||
"dep:prost",
|
"dep:prost",
|
||||||
@ -171,7 +172,7 @@ notify-debouncer-full = { version = "0.5.0", optional = true }
|
|||||||
shell-escape = { version = "0.1", optional = true }
|
shell-escape = { version = "0.1", optional = true }
|
||||||
tempfile = { version = "3.19", optional = true }
|
tempfile = { version = "3.19", optional = true }
|
||||||
time = { version = "0.3", optional = true }
|
time = { version = "0.3", optional = true }
|
||||||
encoding_rs = "0.8.35"
|
encoding_rs = { version = "0.8.35", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", optional = true }
|
winapi = { version = "0.3", optional = true }
|
||||||
|
@ -225,7 +225,7 @@ impl Arch for ArchArm {
|
|||||||
|
|
||||||
let mut address = start_addr;
|
let mut address = start_addr;
|
||||||
while address < end_addr {
|
while address < end_addr {
|
||||||
while let Some(next) = next_mapping.take_if(|x| address >= x.address) {
|
while let Some(next) = next_mapping.filter(|x| address >= x.address) {
|
||||||
// Change mapping
|
// Change mapping
|
||||||
mode = next.mapping;
|
mode = next.mapping;
|
||||||
next_mapping = mappings_iter.next();
|
next_mapping = mappings_iter.next();
|
||||||
|
@ -6,7 +6,7 @@ use iced_x86::{
|
|||||||
Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter,
|
Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter,
|
||||||
Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, Register,
|
Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, Register,
|
||||||
};
|
};
|
||||||
use object::{Endian as _, Object as _, ObjectSection as _, pe};
|
use object::{Endian as _, Object as _, ObjectSection as _, elf, pe};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::Arch,
|
arch::Arch,
|
||||||
@ -67,16 +67,24 @@ impl ArchX86 {
|
|||||||
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
|
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
RelocationFlags::Elf(typ) => match typ {
|
||||||
|
elf::R_386_32 | elf::R_386_PC32 => Some(4),
|
||||||
|
elf::R_386_16 => Some(2),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Architecture::X86_64 => match flags {
|
Architecture::X86_64 => match flags {
|
||||||
RelocationFlags::Coff(typ) => match typ {
|
RelocationFlags::Coff(typ) => match typ {
|
||||||
pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32 => Some(4),
|
pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32 => Some(4),
|
||||||
pe::IMAGE_REL_AMD64_ADDR64 => Some(8),
|
pe::IMAGE_REL_AMD64_ADDR64 => Some(8),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
RelocationFlags::Elf(typ) => match typ {
|
||||||
|
elf::R_X86_64_PC32 => Some(4),
|
||||||
|
elf::R_X86_64_64 => Some(8),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,7 +235,8 @@ impl Arch for ArchX86 {
|
|||||||
) -> Result<i64> {
|
) -> Result<i64> {
|
||||||
match self.arch {
|
match self.arch {
|
||||||
Architecture::X86 => match flags {
|
Architecture::X86 => match flags {
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
|
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32)
|
||||||
|
| RelocationFlags::Elf(elf::R_386_32 | elf::R_386_PC32) => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||||
@ -235,12 +244,14 @@ impl Arch for ArchX86 {
|
|||||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||||
},
|
},
|
||||||
Architecture::X86_64 => match flags {
|
Architecture::X86_64 => match flags {
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32) => {
|
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32)
|
||||||
|
| RelocationFlags::Elf(elf::R_X86_64_32 | elf::R_X86_64_PC32) => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||||
}
|
}
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64) => {
|
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64)
|
||||||
|
| RelocationFlags::Elf(elf::R_X86_64_64) => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 8].try_into()?;
|
section.data()?[address as usize..address as usize + 8].try_into()?;
|
||||||
Ok(self.endianness.read_i64_bytes(data))
|
Ok(self.endianness.read_i64_bytes(data))
|
||||||
|
@ -325,12 +325,11 @@ fn reloc_eq(
|
|||||||
|| display_ins_data_literals(left_obj, left_ins)
|
|| display_ins_data_literals(left_obj, left_ins)
|
||||||
== display_ins_data_literals(right_obj, right_ins))
|
== display_ins_data_literals(right_obj, right_ins))
|
||||||
}
|
}
|
||||||
(Some(_), None) => false,
|
|
||||||
(None, Some(_)) => {
|
(None, Some(_)) => {
|
||||||
// Match if possibly stripped weak symbol
|
// Match if possibly stripped weak symbol
|
||||||
symbol_name_addend_matches && right_reloc.symbol.flags.contains(SymbolFlag::Weak)
|
symbol_name_addend_matches && right_reloc.symbol.flags.contains(SymbolFlag::Weak)
|
||||||
}
|
}
|
||||||
(None, None) => symbol_name_addend_matches,
|
(Some(_), None) | (None, None) => symbol_name_addend_matches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,12 +53,11 @@ fn reloc_eq(
|
|||||||
section_name_eq(left_obj, right_obj, sl, sr)
|
section_name_eq(left_obj, right_obj, sl, sr)
|
||||||
&& (symbol_name_addend_matches || address_eq(left, right))
|
&& (symbol_name_addend_matches || address_eq(left, right))
|
||||||
}
|
}
|
||||||
(Some(_), None) => false,
|
|
||||||
(None, Some(_)) => {
|
(None, Some(_)) => {
|
||||||
// Match if possibly stripped weak symbol
|
// Match if possibly stripped weak symbol
|
||||||
symbol_name_addend_matches && right.symbol.flags.contains(SymbolFlag::Weak)
|
symbol_name_addend_matches && right.symbol.flags.contains(SymbolFlag::Weak)
|
||||||
}
|
}
|
||||||
(None, None) => symbol_name_addend_matches,
|
(Some(_), None) | (None, None) => symbol_name_addend_matches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ impl<'a> DiffTextSegment<'a> {
|
|||||||
const EOL_SEGMENT: DiffTextSegment<'static> =
|
const EOL_SEGMENT: DiffTextSegment<'static> =
|
||||||
DiffTextSegment { text: DiffText::Eol, color: DiffTextColor::Normal, pad_to: 0 };
|
DiffTextSegment { text: DiffText::Eol, color: DiffTextColor::Normal, pad_to: 0 };
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub enum HighlightKind {
|
pub enum HighlightKind {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
@ -288,6 +288,18 @@ pub fn display_row(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq<HighlightKind> for HighlightKind {
|
||||||
|
fn eq(&self, other: &HighlightKind) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(HighlightKind::Opcode(a), HighlightKind::Opcode(b)) => a == b,
|
||||||
|
(HighlightKind::Argument(a), HighlightKind::Argument(b)) => a.loose_eq(b),
|
||||||
|
(HighlightKind::Symbol(a), HighlightKind::Symbol(b)) => a == b,
|
||||||
|
(HighlightKind::Address(a), HighlightKind::Address(b)) => a == b,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq<DiffText<'_>> for HighlightKind {
|
impl PartialEq<DiffText<'_>> for HighlightKind {
|
||||||
fn eq(&self, other: &DiffText) -> bool {
|
fn eq(&self, other: &DiffText) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
@ -604,7 +616,9 @@ fn symbol_matches_filter(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if !show_hidden_symbols
|
if !show_hidden_symbols
|
||||||
&& (symbol.size == 0 || symbol.flags.contains(SymbolFlag::Hidden | SymbolFlag::Ignored))
|
&& (symbol.size == 0
|
||||||
|
|| symbol.flags.contains(SymbolFlag::Hidden)
|
||||||
|
|| symbol.flags.contains(SymbolFlag::Ignored))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -341,11 +341,25 @@ pub fn diff_objs(
|
|||||||
if let (Some((right_obj, right_out)), Some((left_obj, left_out))) =
|
if let (Some((right_obj, right_out)), Some((left_obj, left_out))) =
|
||||||
(right.as_mut(), left.as_mut())
|
(right.as_mut(), left.as_mut())
|
||||||
{
|
{
|
||||||
if let Some(right_name) = &mapping_config.selecting_left {
|
if let Some(right_name) = mapping_config.selecting_left.as_deref() {
|
||||||
generate_mapping_symbols(right_obj, right_name, left_obj, left_out, diff_config)?;
|
generate_mapping_symbols(
|
||||||
|
left_obj,
|
||||||
|
left_out,
|
||||||
|
right_obj,
|
||||||
|
right_out,
|
||||||
|
MappingSymbol::Right(right_name),
|
||||||
|
diff_config,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
if let Some(left_name) = &mapping_config.selecting_right {
|
if let Some(left_name) = mapping_config.selecting_right.as_deref() {
|
||||||
generate_mapping_symbols(left_obj, left_name, right_obj, right_out, diff_config)?;
|
generate_mapping_symbols(
|
||||||
|
left_obj,
|
||||||
|
left_out,
|
||||||
|
right_obj,
|
||||||
|
right_out,
|
||||||
|
MappingSymbol::Left(left_name),
|
||||||
|
diff_config,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,17 +370,28 @@ pub fn diff_objs(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum MappingSymbol<'a> {
|
||||||
|
Left(&'a str),
|
||||||
|
Right(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
/// When we're selecting a symbol to use as a comparison, we'll create comparisons for all
|
/// When we're selecting a symbol to use as a comparison, we'll create comparisons for all
|
||||||
/// symbols in the other object that match the selected symbol's section and kind. This allows
|
/// symbols in the other object that match the selected symbol's section and kind. This allows
|
||||||
/// us to display match percentages for all symbols in the other object that could be selected.
|
/// us to display match percentages for all symbols in the other object that could be selected.
|
||||||
fn generate_mapping_symbols(
|
fn generate_mapping_symbols(
|
||||||
base_obj: &Object,
|
left_obj: &Object,
|
||||||
base_name: &str,
|
left_out: &mut ObjectDiff,
|
||||||
target_obj: &Object,
|
right_obj: &Object,
|
||||||
target_out: &mut ObjectDiff,
|
right_out: &mut ObjectDiff,
|
||||||
|
mapping_symbol: MappingSymbol,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let Some(base_symbol_ref) = symbol_ref_by_name(base_obj, base_name) else {
|
let (base_obj, base_name, target_obj) = match mapping_symbol {
|
||||||
|
MappingSymbol::Left(name) => (left_obj, name, right_obj),
|
||||||
|
MappingSymbol::Right(name) => (right_obj, name, left_obj),
|
||||||
|
};
|
||||||
|
let Some(base_symbol_ref) = base_obj.symbol_by_name(base_name) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let base_section_kind = symbol_section_kind(base_obj, &base_obj.symbols[base_symbol_ref]);
|
let base_section_kind = symbol_section_kind(base_obj, &base_obj.symbols[base_symbol_ref]);
|
||||||
@ -377,32 +402,30 @@ fn generate_mapping_symbols(
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match base_section_kind {
|
let (left_symbol_idx, right_symbol_idx) = match mapping_symbol {
|
||||||
|
MappingSymbol::Left(_) => (base_symbol_ref, target_symbol_index),
|
||||||
|
MappingSymbol::Right(_) => (target_symbol_index, base_symbol_ref),
|
||||||
|
};
|
||||||
|
let (left_diff, right_diff) = match base_section_kind {
|
||||||
SectionKind::Code => {
|
SectionKind::Code => {
|
||||||
let (left_diff, _right_diff) =
|
diff_code(left_obj, right_obj, left_symbol_idx, right_symbol_idx, config)
|
||||||
diff_code(target_obj, base_obj, target_symbol_index, base_symbol_ref, config)?;
|
|
||||||
target_out.mapping_symbols.push(MappingSymbolDiff {
|
|
||||||
symbol_index: target_symbol_index,
|
|
||||||
symbol_diff: left_diff,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
SectionKind::Data => {
|
SectionKind::Data => {
|
||||||
let (left_diff, _right_diff) =
|
diff_data_symbol(left_obj, right_obj, left_symbol_idx, right_symbol_idx)
|
||||||
diff_data_symbol(target_obj, base_obj, target_symbol_index, base_symbol_ref)?;
|
|
||||||
target_out.mapping_symbols.push(MappingSymbolDiff {
|
|
||||||
symbol_index: target_symbol_index,
|
|
||||||
symbol_diff: left_diff,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
SectionKind::Bss | SectionKind::Common => {
|
SectionKind::Bss | SectionKind::Common => {
|
||||||
let (left_diff, _right_diff) =
|
diff_bss_symbol(left_obj, right_obj, left_symbol_idx, right_symbol_idx)
|
||||||
diff_bss_symbol(target_obj, base_obj, target_symbol_index, base_symbol_ref)?;
|
|
||||||
target_out.mapping_symbols.push(MappingSymbolDiff {
|
|
||||||
symbol_index: target_symbol_index,
|
|
||||||
symbol_diff: left_diff,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
SectionKind::Unknown => {}
|
SectionKind::Unknown => continue,
|
||||||
|
}?;
|
||||||
|
match mapping_symbol {
|
||||||
|
MappingSymbol::Left(_) => right_out.mapping_symbols.push(MappingSymbolDiff {
|
||||||
|
symbol_index: right_symbol_idx,
|
||||||
|
symbol_diff: right_diff,
|
||||||
|
}),
|
||||||
|
MappingSymbol::Right(_) => left_out
|
||||||
|
.mapping_symbols
|
||||||
|
.push(MappingSymbolDiff { symbol_index: left_symbol_idx, symbol_diff: left_diff }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -434,10 +457,6 @@ pub struct MappingConfig {
|
|||||||
pub selecting_right: Option<String>,
|
pub selecting_right: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_ref_by_name(obj: &Object, name: &str) -> Option<usize> {
|
|
||||||
obj.symbols.iter().position(|s| s.name == name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_symbol_mappings(
|
fn apply_symbol_mappings(
|
||||||
left: &Object,
|
left: &Object,
|
||||||
right: &Object,
|
right: &Object,
|
||||||
@ -449,25 +468,25 @@ fn apply_symbol_mappings(
|
|||||||
// If we're selecting a symbol to use as a comparison, mark it as used
|
// If we're selecting a symbol to use as a comparison, mark it as used
|
||||||
// This ensures that we don't match it to another symbol at any point
|
// This ensures that we don't match it to another symbol at any point
|
||||||
if let Some(left_name) = &mapping_config.selecting_left {
|
if let Some(left_name) = &mapping_config.selecting_left {
|
||||||
if let Some(left_symbol) = symbol_ref_by_name(left, left_name) {
|
if let Some(left_symbol) = left.symbol_by_name(left_name) {
|
||||||
left_used.insert(left_symbol);
|
left_used.insert(left_symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(right_name) = &mapping_config.selecting_right {
|
if let Some(right_name) = &mapping_config.selecting_right {
|
||||||
if let Some(right_symbol) = symbol_ref_by_name(right, right_name) {
|
if let Some(right_symbol) = right.symbol_by_name(right_name) {
|
||||||
right_used.insert(right_symbol);
|
right_used.insert(right_symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply manual symbol mappings
|
// Apply manual symbol mappings
|
||||||
for (left_name, right_name) in &mapping_config.mappings {
|
for (left_name, right_name) in &mapping_config.mappings {
|
||||||
let Some(left_symbol_index) = symbol_ref_by_name(left, left_name) else {
|
let Some(left_symbol_index) = left.symbol_by_name(left_name) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if left_used.contains(&left_symbol_index) {
|
if left_used.contains(&left_symbol_index) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let Some(right_symbol_index) = symbol_ref_by_name(right, right_name) else {
|
let Some(right_symbol_index) = right.symbol_by_name(right_name) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if right_used.contains(&right_symbol_index) {
|
if right_used.contains(&right_symbol_index) {
|
||||||
|
@ -118,7 +118,7 @@ impl Section {
|
|||||||
Err(i) => self
|
Err(i) => self
|
||||||
.relocations
|
.relocations
|
||||||
.get(i)
|
.get(i)
|
||||||
.take_if(|r| r.address < ins_ref.address + ins_ref.size as u64),
|
.filter(|r| r.address < ins_ref.address + ins_ref.size as u64),
|
||||||
}
|
}
|
||||||
.and_then(|relocation| {
|
.and_then(|relocation| {
|
||||||
let symbol = obj.symbols.get(relocation.target_symbol)?;
|
let symbol = obj.symbols.get(relocation.target_symbol)?;
|
||||||
@ -308,6 +308,10 @@ impl Object {
|
|||||||
let offset = symbol.address.checked_sub(section.address)?;
|
let offset = symbol.address.checked_sub(section.address)?;
|
||||||
section.data.get(offset as usize..offset as usize + symbol.size as usize)
|
section.data.get(offset as usize..offset as usize + symbol.size as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn symbol_by_name(&self, name: &str) -> Option<usize> {
|
||||||
|
self.symbols.iter().position(|symbol| symbol.section.is_some() && symbol.name == name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
@ -121,6 +121,15 @@ fn map_symbols(
|
|||||||
Ok((symbols, symbol_indices))
|
Ok((symbols, symbol_indices))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
const LABEL_PREFIXES: &[&str] = &[".L", "LAB_"];
|
||||||
|
symbol.size == 0
|
||||||
|
&& symbol.flags.contains(SymbolFlag::Local)
|
||||||
|
&& LABEL_PREFIXES.iter().any(|p| symbol.name.starts_with(p))
|
||||||
|
}
|
||||||
|
|
||||||
fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
||||||
// Create a sorted list of symbol indices by section
|
// Create a sorted list of symbol indices by section
|
||||||
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
||||||
@ -167,10 +176,7 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
|||||||
if last_end.0 == section_idx && last_end.1 > symbol.address {
|
if last_end.0 == section_idx && last_end.1 > symbol.address {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let next_symbol = match symbol.kind {
|
let next_symbol = loop {
|
||||||
// For function/object symbols, find the next function/object symbol (in other words:
|
|
||||||
// skip over labels)
|
|
||||||
SymbolKind::Function | SymbolKind::Object => loop {
|
|
||||||
if iter_idx >= symbols_with_section.len() {
|
if iter_idx >= symbols_with_section.len() {
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
@ -178,16 +184,20 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
|||||||
if next_symbol.section != Some(section_idx) {
|
if next_symbol.section != Some(section_idx) {
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
if let SymbolKind::Function | SymbolKind::Object = next_symbol.kind {
|
if match symbol.kind {
|
||||||
|
SymbolKind::Function | SymbolKind::Object => {
|
||||||
|
// For function/object symbols, find the next function/object
|
||||||
|
matches!(next_symbol.kind, SymbolKind::Function | SymbolKind::Object)
|
||||||
|
}
|
||||||
|
SymbolKind::Unknown | SymbolKind::Section => {
|
||||||
|
// For labels (or anything else), stop at any symbol
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} && !is_local_label(next_symbol)
|
||||||
|
{
|
||||||
break Some(next_symbol);
|
break Some(next_symbol);
|
||||||
}
|
}
|
||||||
iter_idx += 1;
|
iter_idx += 1;
|
||||||
},
|
|
||||||
// For labels (or anything else), simply use the next symbol's address
|
|
||||||
SymbolKind::Unknown | SymbolKind::Section => symbols_with_section
|
|
||||||
.get(iter_idx)
|
|
||||||
.map(|&i| &symbols[i])
|
|
||||||
.take_if(|s| s.section == Some(section_idx)),
|
|
||||||
};
|
};
|
||||||
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
|
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
|
||||||
let section = §ions[section_idx];
|
let section = §ions[section_idx];
|
||||||
@ -341,7 +351,7 @@ fn map_section_relocations(
|
|||||||
let idx = if let Some(section_symbol) = obj_file
|
let idx = if let Some(section_symbol) = obj_file
|
||||||
.symbol_by_index(idx)
|
.symbol_by_index(idx)
|
||||||
.ok()
|
.ok()
|
||||||
.take_if(|s| s.kind() == object::SymbolKind::Section)
|
.filter(|s| s.kind() == object::SymbolKind::Section)
|
||||||
{
|
{
|
||||||
let section_index =
|
let section_index =
|
||||||
section_symbol.section_index().context("Section symbol without section")?;
|
section_symbol.section_index().context("Section symbol without section")?;
|
||||||
|
@ -68,3 +68,12 @@ fn read_x86_jumptable() {
|
|||||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||||
insta::assert_snapshot!(output);
|
insta::assert_snapshot!(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inferred size of functions should ignore symbols with specific prefixes
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "x86")]
|
||||||
|
fn read_x86_local_labels() {
|
||||||
|
let diff_config = diff::DiffObjConfig::default();
|
||||||
|
let obj = obj::read::parse(include_object!("data/x86/local_labels.obj"), &diff_config).unwrap();
|
||||||
|
insta::assert_debug_snapshot!(obj);
|
||||||
|
}
|
||||||
|
BIN
objdiff-core/tests/data/x86/local_labels.obj
Normal file
BIN
objdiff-core/tests/data/x86/local_labels.obj
Normal file
Binary file not shown.
@ -0,0 +1,163 @@
|
|||||||
|
---
|
||||||
|
source: objdiff-core/tests/arch_x86.rs
|
||||||
|
expression: obj
|
||||||
|
---
|
||||||
|
Object {
|
||||||
|
arch: ArchX86 {
|
||||||
|
arch: X86,
|
||||||
|
endianness: Little,
|
||||||
|
},
|
||||||
|
endianness: Little,
|
||||||
|
symbols: [
|
||||||
|
Symbol {
|
||||||
|
name: "42b830_convertToUppercaseShiftJIS.obj",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 0,
|
||||||
|
size: 0,
|
||||||
|
kind: Unknown,
|
||||||
|
section: None,
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "[.text]",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 0,
|
||||||
|
size: 0,
|
||||||
|
kind: Section,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b850",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 32,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b883",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 83,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b87c",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 76,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b884",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 84,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b889",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 89,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b845",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 21,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "LAB_0042b869",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 57,
|
||||||
|
size: 0,
|
||||||
|
kind: Object,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Local),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
Symbol {
|
||||||
|
name: "ConvertToUppercaseShiftJIS",
|
||||||
|
demangled_name: None,
|
||||||
|
address: 0,
|
||||||
|
size: 92,
|
||||||
|
kind: Function,
|
||||||
|
section: Some(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
flags: FlagSet(Global | SizeInferred),
|
||||||
|
align: None,
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sections: [
|
||||||
|
Section {
|
||||||
|
id: ".text-0",
|
||||||
|
name: ".text",
|
||||||
|
address: 0,
|
||||||
|
size: 92,
|
||||||
|
kind: Code,
|
||||||
|
data: SectionData(
|
||||||
|
92,
|
||||||
|
),
|
||||||
|
flags: FlagSet(),
|
||||||
|
align: Some(
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
relocations: [],
|
||||||
|
line_info: {},
|
||||||
|
virtual_address: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_meta: None,
|
||||||
|
path: None,
|
||||||
|
timestamp: None,
|
||||||
|
}
|
@ -147,14 +147,20 @@ pub(crate) fn data_row_ui(
|
|||||||
cur_addr += diff.len;
|
cur_addr += diff.len;
|
||||||
} else {
|
} else {
|
||||||
for byte in &diff.data {
|
for byte in &diff.data {
|
||||||
|
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.iter().find(|reloc_diff| {
|
if let Some(reloc_diff) = reloc_diffs
|
||||||
reloc_diff.kind != DataDiffKind::None
|
.iter()
|
||||||
&& reloc_diff.range.contains(&cur_addr_actual)
|
.find(|reloc_diff| reloc_diff.range.contains(&cur_addr_actual))
|
||||||
}) {
|
{
|
||||||
|
if *byte == 0 {
|
||||||
|
// Display 00 data bytes with a relocation as ?? instead.
|
||||||
|
byte_text = "?? ".to_string();
|
||||||
|
}
|
||||||
|
if reloc_diff.kind != DataDiffKind::None {
|
||||||
byte_color = get_color_for_diff_kind(reloc_diff.kind, appearance);
|
byte_color = get_color_for_diff_kind(reloc_diff.kind, appearance);
|
||||||
}
|
}
|
||||||
let byte_text = format!("{byte:02x} ");
|
}
|
||||||
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
||||||
cur_addr += 1;
|
cur_addr += 1;
|
||||||
cur_addr_actual += 1;
|
cur_addr_actual += 1;
|
||||||
|
@ -49,7 +49,9 @@ impl<'a> DiffColumnContext<'a> {
|
|||||||
let selected_symbol = match view {
|
let selected_symbol = match view {
|
||||||
View::SymbolDiff => None,
|
View::SymbolDiff => None,
|
||||||
View::FunctionDiff | View::ExtabDiff => match (obj, selected_symbol) {
|
View::FunctionDiff | View::ExtabDiff => match (obj, selected_symbol) {
|
||||||
(Some(obj), Some(s)) => find_symbol(&obj.0, s).map(SelectedSymbol::Symbol),
|
(Some(obj), Some(s)) => {
|
||||||
|
obj.0.symbol_by_name(&s.symbol_name).map(SelectedSymbol::Symbol)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
View::DataDiff => match (obj, selected_symbol) {
|
View::DataDiff => match (obj, selected_symbol) {
|
||||||
@ -497,6 +499,7 @@ pub fn diff_view_ui(
|
|||||||
(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.section, right_ctx.section)
|
||||||
{
|
{
|
||||||
// Joint diff view
|
// Joint diff view
|
||||||
|
hotkeys::check_scroll_hotkeys(ui, true);
|
||||||
let left_total_bytes =
|
let left_total_bytes =
|
||||||
left_section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
left_section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||||
let right_total_bytes =
|
let right_total_bytes =
|
||||||
@ -779,10 +782,6 @@ fn missing_obj_ui(ui: &mut Ui, appearance: &Appearance) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_symbol(obj: &Object, selected_symbol: &SymbolRefByName) -> Option<usize> {
|
|
||||||
obj.symbols.iter().position(|symbol| symbol.name == selected_symbol.symbol_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_section(obj: &Object, section_name: &str) -> Option<usize> {
|
fn find_section(obj: &Object, section_name: &str) -> Option<usize> {
|
||||||
obj.sections.iter().position(|section| section.name == section_name)
|
obj.sections.iter().position(|section| section.name == section_name)
|
||||||
}
|
}
|
||||||
|
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.0.0-beta.7",
|
"version": "3.0.0-beta.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.7",
|
"version": "3.0.0-beta.9",
|
||||||
"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.0.0-beta.7",
|
"version": "3.0.0-beta.9",
|
||||||
"description": "A local diffing tool for decompilation projects.",
|
"description": "A local diffing tool for decompilation projects.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Luke Street",
|
"name": "Luke Street",
|
||||||
|
@ -24,14 +24,14 @@ wit_bindgen::generate!({
|
|||||||
use exports::objdiff::core::{
|
use exports::objdiff::core::{
|
||||||
diff::{
|
diff::{
|
||||||
DiffConfigBorrow, DiffResult, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
DiffConfigBorrow, DiffResult, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
||||||
GuestObjectDiff, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
GuestObjectDiff, MappingConfig, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
||||||
|
SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
||||||
},
|
},
|
||||||
display::{
|
display::{
|
||||||
ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode,
|
ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode,
|
||||||
DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem,
|
DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem,
|
||||||
HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay,
|
HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay,
|
||||||
SectionDisplaySymbol, SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind,
|
SymbolDisplay, SymbolFilter, SymbolNavigationKind,
|
||||||
SymbolNavigationKind, SymbolRef,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,15 +59,17 @@ impl GuestDiff for Component {
|
|||||||
left: Option<ObjectBorrow>,
|
left: Option<ObjectBorrow>,
|
||||||
right: Option<ObjectBorrow>,
|
right: Option<ObjectBorrow>,
|
||||||
diff_config: DiffConfigBorrow,
|
diff_config: DiffConfigBorrow,
|
||||||
|
mapping_config: MappingConfig,
|
||||||
) -> Result<DiffResult, String> {
|
) -> Result<DiffResult, String> {
|
||||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||||
|
let mapping_config = diff::MappingConfig::from(mapping_config);
|
||||||
log::debug!("Running diff with config: {:?}", diff_config);
|
log::debug!("Running diff with config: {:?}", diff_config);
|
||||||
let result = diff::diff_objs(
|
let result = diff::diff_objs(
|
||||||
left.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
left.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
||||||
right.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
right.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
||||||
None,
|
None,
|
||||||
&diff_config,
|
&diff_config,
|
||||||
&diff::MappingConfig::default(),
|
&mapping_config,
|
||||||
)
|
)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(DiffResult {
|
Ok(DiffResult {
|
||||||
@ -134,48 +136,47 @@ impl GuestDisplay for Component {
|
|||||||
name: d.name,
|
name: d.name,
|
||||||
size: d.size,
|
size: d.size,
|
||||||
match_percent: d.match_percent,
|
match_percent: d.match_percent,
|
||||||
symbols: d
|
symbols: d.symbols.into_iter().map(to_symbol_ref).collect(),
|
||||||
.symbols
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| SectionDisplaySymbol {
|
|
||||||
symbol: s.symbol as SymbolRef,
|
|
||||||
is_mapping_symbol: s.is_mapping_symbol,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_symbol(
|
fn display_symbol(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> SymbolDisplay {
|
||||||
diff: ObjectDiffBorrow,
|
|
||||||
symbol_display: SectionDisplaySymbol,
|
|
||||||
) -> SymbolDisplay {
|
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
let obj_diff = &obj_diff.1;
|
let obj_diff = &obj_diff.1;
|
||||||
let symbol_idx = symbol_display.symbol as usize;
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
let Some(symbol) = obj.symbols.get(symbol_idx) else {
|
let Some(symbol) = obj.symbols.get(symbol_display.symbol) else {
|
||||||
return SymbolDisplay { name: "<unknown>".to_string(), ..Default::default() };
|
return SymbolDisplay {
|
||||||
|
info: SymbolInfo { name: "<unknown>".to_string(), ..Default::default() },
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
};
|
};
|
||||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||||
obj_diff
|
obj_diff
|
||||||
.mapping_symbols
|
.mapping_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.symbol_index == symbol_idx)
|
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||||
.map(|s| &s.symbol_diff)
|
.map(|s| &s.symbol_diff)
|
||||||
} else {
|
} else {
|
||||||
obj_diff.symbols.get(symbol_idx)
|
obj_diff.symbols.get(symbol_display.symbol)
|
||||||
};
|
};
|
||||||
SymbolDisplay {
|
SymbolDisplay {
|
||||||
|
info: SymbolInfo {
|
||||||
|
id: to_symbol_ref(symbol_display),
|
||||||
name: symbol.name.clone(),
|
name: symbol.name.clone(),
|
||||||
demangled_name: symbol.demangled_name.clone(),
|
demangled_name: symbol.demangled_name.clone(),
|
||||||
address: symbol.address,
|
address: symbol.address,
|
||||||
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
|
||||||
|
.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,
|
||||||
|
},
|
||||||
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),
|
||||||
@ -185,22 +186,22 @@ impl GuestDisplay for Component {
|
|||||||
|
|
||||||
fn display_instruction_row(
|
fn display_instruction_row(
|
||||||
diff: ObjectDiffBorrow,
|
diff: ObjectDiffBorrow,
|
||||||
symbol_display: SectionDisplaySymbol,
|
symbol_ref: SymbolRef,
|
||||||
row_index: u32,
|
row_index: u32,
|
||||||
diff_config: DiffConfigBorrow,
|
diff_config: DiffConfigBorrow,
|
||||||
) -> InstructionDiffRow {
|
) -> InstructionDiffRow {
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
let obj_diff = &obj_diff.1;
|
let obj_diff = &obj_diff.1;
|
||||||
let symbol_idx = symbol_display.symbol as usize;
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||||
obj_diff
|
obj_diff
|
||||||
.mapping_symbols
|
.mapping_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.symbol_index == symbol_idx)
|
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||||
.map(|s| &s.symbol_diff)
|
.map(|s| &s.symbol_diff)
|
||||||
} else {
|
} else {
|
||||||
obj_diff.symbols.get(symbol_idx)
|
obj_diff.symbols.get(symbol_display.symbol)
|
||||||
};
|
};
|
||||||
let Some(row) = symbol_diff.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
let Some(row) = symbol_diff.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
||||||
else {
|
else {
|
||||||
@ -208,7 +209,7 @@ impl GuestDisplay for Component {
|
|||||||
};
|
};
|
||||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||||
let mut segments = Vec::with_capacity(16);
|
let mut segments = Vec::with_capacity(16);
|
||||||
diff::display::display_row(obj, symbol_idx, row, &diff_config, |segment| {
|
diff::display::display_row(obj, symbol_display.symbol, row, &diff_config, |segment| {
|
||||||
segments.push(DiffTextSegment::from(segment));
|
segments.push(DiffTextSegment::from(segment));
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@ -216,26 +217,22 @@ impl GuestDisplay for Component {
|
|||||||
InstructionDiffRow { segments, diff_kind: InstructionDiffKind::from(row.kind) }
|
InstructionDiffRow { segments, diff_kind: InstructionDiffKind::from(row.kind) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_context(
|
fn symbol_context(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> Vec<ContextItem> {
|
||||||
diff: ObjectDiffBorrow,
|
|
||||||
symbol_display: SectionDisplaySymbol,
|
|
||||||
) -> Vec<ContextItem> {
|
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
diff::display::symbol_context(obj, symbol_display.symbol as usize)
|
diff::display::symbol_context(obj, symbol_display.symbol as usize)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|item| ContextItem::from(item))
|
.map(|item| ContextItem::from(item))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_hover(
|
fn symbol_hover(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> Vec<HoverItem> {
|
||||||
diff: ObjectDiffBorrow,
|
|
||||||
symbol_display: SectionDisplaySymbol,
|
|
||||||
) -> Vec<HoverItem> {
|
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
let addend = 0; // TODO
|
let addend = 0; // TODO
|
||||||
let override_color = None; // TODO: colorize replaced/deleted/inserted relocations
|
let override_color = None; // TODO: colorize replaced/deleted/inserted relocations
|
||||||
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
diff::display::symbol_hover(obj, symbol_display.symbol as usize, addend, override_color)
|
diff::display::symbol_hover(obj, symbol_display.symbol as usize, addend, override_color)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|item| HoverItem::from(item))
|
.map(|item| HoverItem::from(item))
|
||||||
@ -244,22 +241,22 @@ impl GuestDisplay for Component {
|
|||||||
|
|
||||||
fn instruction_context(
|
fn instruction_context(
|
||||||
diff: ObjectDiffBorrow,
|
diff: ObjectDiffBorrow,
|
||||||
symbol_display: SectionDisplaySymbol,
|
symbol_ref: SymbolRef,
|
||||||
row_index: u32,
|
row_index: u32,
|
||||||
diff_config: DiffConfigBorrow,
|
diff_config: DiffConfigBorrow,
|
||||||
) -> Vec<ContextItem> {
|
) -> Vec<ContextItem> {
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
let obj_diff = &obj_diff.1;
|
let obj_diff = &obj_diff.1;
|
||||||
let symbol_idx = symbol_display.symbol as usize;
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||||
obj_diff
|
obj_diff
|
||||||
.mapping_symbols
|
.mapping_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.symbol_index == symbol_idx)
|
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||||
.map(|s| &s.symbol_diff)
|
.map(|s| &s.symbol_diff)
|
||||||
} else {
|
} else {
|
||||||
obj_diff.symbols.get(symbol_idx)
|
obj_diff.symbols.get(symbol_display.symbol)
|
||||||
};
|
};
|
||||||
let Some(ins_ref) = symbol_diff
|
let Some(ins_ref) = symbol_diff
|
||||||
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
||||||
@ -268,7 +265,7 @@ impl GuestDisplay for Component {
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||||
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
|
let Some(resolved) = obj.resolve_instruction_ref(symbol_display.symbol, ins_ref) else {
|
||||||
return vec![ContextItem::Copy(ContextItemCopy {
|
return vec![ContextItem::Copy(ContextItemCopy {
|
||||||
value: "Failed to resolve instruction".to_string(),
|
value: "Failed to resolve instruction".to_string(),
|
||||||
label: Some("error".to_string()),
|
label: Some("error".to_string()),
|
||||||
@ -291,22 +288,22 @@ impl GuestDisplay for Component {
|
|||||||
|
|
||||||
fn instruction_hover(
|
fn instruction_hover(
|
||||||
diff: ObjectDiffBorrow,
|
diff: ObjectDiffBorrow,
|
||||||
symbol_display: SectionDisplaySymbol,
|
symbol_ref: SymbolRef,
|
||||||
row_index: u32,
|
row_index: u32,
|
||||||
diff_config: DiffConfigBorrow,
|
diff_config: DiffConfigBorrow,
|
||||||
) -> Vec<HoverItem> {
|
) -> Vec<HoverItem> {
|
||||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||||
let obj = obj_diff.0.as_ref();
|
let obj = obj_diff.0.as_ref();
|
||||||
let obj_diff = &obj_diff.1;
|
let obj_diff = &obj_diff.1;
|
||||||
let symbol_idx = symbol_display.symbol as usize;
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||||
obj_diff
|
obj_diff
|
||||||
.mapping_symbols
|
.mapping_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.symbol_index == symbol_idx)
|
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||||
.map(|s| &s.symbol_diff)
|
.map(|s| &s.symbol_diff)
|
||||||
} else {
|
} else {
|
||||||
obj_diff.symbols.get(symbol_idx)
|
obj_diff.symbols.get(symbol_display.symbol)
|
||||||
};
|
};
|
||||||
let Some(ins_ref) = symbol_diff
|
let Some(ins_ref) = symbol_diff
|
||||||
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
||||||
@ -315,7 +312,7 @@ impl GuestDisplay for Component {
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||||
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
|
let Some(resolved) = obj.resolve_instruction_ref(symbol_display.symbol, ins_ref) else {
|
||||||
return vec![HoverItem::Text(HoverItemText {
|
return vec![HoverItem::Text(HoverItemText {
|
||||||
label: "Error".to_string(),
|
label: "Error".to_string(),
|
||||||
value: "Failed to resolve instruction".to_string(),
|
value: "Failed to resolve instruction".to_string(),
|
||||||
@ -497,11 +494,9 @@ impl GuestObject for ResourceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GuestObjectDiff for ResourceObjectDiff {
|
impl GuestObjectDiff for ResourceObjectDiff {
|
||||||
fn find_symbol(&self, name: String, section_name: Option<String>) -> Option<SymbolRef> {
|
fn find_symbol(&self, name: String, section_name: Option<String>) -> Option<SymbolInfo> {
|
||||||
let obj = self.0.as_ref();
|
let obj = self.0.as_ref();
|
||||||
obj.symbols
|
let symbol_idx = obj.symbols.iter().position(|s| {
|
||||||
.iter()
|
|
||||||
.position(|s| {
|
|
||||||
s.name == name
|
s.name == name
|
||||||
&& match section_name.as_deref() {
|
&& match section_name.as_deref() {
|
||||||
Some(section_name) => {
|
Some(section_name) => {
|
||||||
@ -509,8 +504,46 @@ impl GuestObjectDiff for ResourceObjectDiff {
|
|||||||
}
|
}
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
|
})?;
|
||||||
|
let symbol = obj.symbols.get(symbol_idx)?;
|
||||||
|
Some(SymbolInfo {
|
||||||
|
id: symbol_idx as SymbolRef,
|
||||||
|
name: symbol.name.clone(),
|
||||||
|
demangled_name: symbol.demangled_name.clone(),
|
||||||
|
address: symbol.address,
|
||||||
|
size: symbol.size,
|
||||||
|
kind: SymbolKind::from(symbol.kind),
|
||||||
|
section: symbol.section.map(|s| s as u32),
|
||||||
|
section_name: symbol
|
||||||
|
.section
|
||||||
|
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
||||||
|
flags: SymbolFlags::from(symbol.flags),
|
||||||
|
align: symbol.align.map(|a| a.get()),
|
||||||
|
virtual_address: symbol.virtual_address,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_symbol(&self, symbol_ref: SymbolRef) -> Option<SymbolInfo> {
|
||||||
|
let obj = self.0.as_ref();
|
||||||
|
let symbol_display = from_symbol_ref(symbol_ref);
|
||||||
|
let Some(symbol) = obj.symbols.get(symbol_display.symbol) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(SymbolInfo {
|
||||||
|
id: to_symbol_ref(symbol_display),
|
||||||
|
name: symbol.name.clone(),
|
||||||
|
demangled_name: symbol.demangled_name.clone(),
|
||||||
|
address: symbol.address,
|
||||||
|
size: symbol.size,
|
||||||
|
kind: SymbolKind::from(symbol.kind),
|
||||||
|
section: symbol.section.map(|s| s as u32),
|
||||||
|
section_name: symbol
|
||||||
|
.section
|
||||||
|
.and_then(|s| obj.sections.get(s).map(|sec| sec.name.clone())),
|
||||||
|
flags: SymbolFlags::from(symbol.flags),
|
||||||
|
align: symbol.align.map(|a| a.get()),
|
||||||
|
virtual_address: symbol.virtual_address,
|
||||||
})
|
})
|
||||||
.map(|i| i as SymbolRef)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,18 +613,28 @@ impl Default for SymbolFlags {
|
|||||||
fn default() -> Self { Self::empty() }
|
fn default() -> Self { Self::empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SymbolDisplay {
|
impl Default for SymbolInfo {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
id: u32::MAX,
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
demangled_name: Default::default(),
|
demangled_name: Default::default(),
|
||||||
address: Default::default(),
|
address: Default::default(),
|
||||||
size: Default::default(),
|
size: Default::default(),
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
section: Default::default(),
|
section: Default::default(),
|
||||||
|
section_name: Default::default(),
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
align: Default::default(),
|
align: Default::default(),
|
||||||
virtual_address: Default::default(),
|
virtual_address: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SymbolDisplay {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
info: Default::default(),
|
||||||
target_symbol: Default::default(),
|
target_symbol: Default::default(),
|
||||||
match_percent: Default::default(),
|
match_percent: Default::default(),
|
||||||
diff_score: Default::default(),
|
diff_score: Default::default(),
|
||||||
@ -600,4 +643,30 @@ impl Default for SymbolDisplay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<MappingConfig> for diff::MappingConfig {
|
||||||
|
fn from(config: MappingConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
mappings: config.mappings.into_iter().collect(),
|
||||||
|
selecting_left: config.selecting_left,
|
||||||
|
selecting_right: config.selecting_right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_symbol_ref(symbol_ref: SymbolRef) -> diff::display::SectionDisplaySymbol {
|
||||||
|
diff::display::SectionDisplaySymbol {
|
||||||
|
symbol: (symbol_ref & !(1 << 31)) as usize,
|
||||||
|
is_mapping_symbol: (symbol_ref & (1 << 31)) != 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_symbol_ref(display_symbol: diff::display::SectionDisplaySymbol) -> SymbolRef {
|
||||||
|
if display_symbol.is_mapping_symbol {
|
||||||
|
// Use the highest bit to indicate a mapping symbol
|
||||||
|
display_symbol.symbol as u32 | (1 << 31)
|
||||||
|
} else {
|
||||||
|
display_symbol.symbol as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export!(Component);
|
export!(Component);
|
||||||
|
@ -24,58 +24,8 @@ interface diff {
|
|||||||
hash: func() -> u64;
|
hash: func() -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
resource object-diff {
|
|
||||||
find-symbol: func(
|
|
||||||
name: string,
|
|
||||||
section-name: option<string>
|
|
||||||
) -> option<u32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
record diff-result {
|
|
||||||
left: option<object-diff>,
|
|
||||||
right: option<object-diff>,
|
|
||||||
}
|
|
||||||
|
|
||||||
run-diff: func(
|
|
||||||
left: option<borrow<object>>,
|
|
||||||
right: option<borrow<object>>,
|
|
||||||
config: borrow<diff-config>,
|
|
||||||
) -> result<diff-result, string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface display {
|
|
||||||
use diff.{
|
|
||||||
object,
|
|
||||||
object-diff,
|
|
||||||
diff-config
|
|
||||||
};
|
|
||||||
|
|
||||||
type symbol-ref = u32;
|
type symbol-ref = u32;
|
||||||
|
|
||||||
record display-config {
|
|
||||||
show-hidden-symbols: bool,
|
|
||||||
show-mapped-symbols: bool,
|
|
||||||
reverse-fn-order: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
record symbol-filter {
|
|
||||||
regex: option<string>,
|
|
||||||
mapping: option<symbol-ref>,
|
|
||||||
}
|
|
||||||
|
|
||||||
record section-display-symbol {
|
|
||||||
symbol: symbol-ref,
|
|
||||||
is-mapping-symbol: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
record section-display {
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
size: u64,
|
|
||||||
match-percent: option<f32>,
|
|
||||||
symbols: list<section-display-symbol>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum symbol-kind {
|
enum symbol-kind {
|
||||||
unknown,
|
unknown,
|
||||||
function,
|
function,
|
||||||
@ -94,17 +44,74 @@ interface display {
|
|||||||
ignored,
|
ignored,
|
||||||
}
|
}
|
||||||
|
|
||||||
record symbol-display {
|
record symbol-info {
|
||||||
|
id: symbol-ref,
|
||||||
name: string,
|
name: string,
|
||||||
demangled-name: option<string>,
|
demangled-name: option<string>,
|
||||||
address: u64,
|
address: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
kind: symbol-kind,
|
kind: symbol-kind,
|
||||||
section: option<u32>,
|
section: option<u32>,
|
||||||
|
section-name: option<string>,
|
||||||
%flags: symbol-flags,
|
%flags: symbol-flags,
|
||||||
align: option<u32>,
|
align: option<u32>,
|
||||||
virtual-address: option<u64>,
|
virtual-address: option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource object-diff {
|
||||||
|
find-symbol: func(
|
||||||
|
name: string,
|
||||||
|
section-name: option<string>
|
||||||
|
) -> option<symbol-info>;
|
||||||
|
|
||||||
|
get-symbol: func(
|
||||||
|
id: u32
|
||||||
|
) -> option<symbol-info>;
|
||||||
|
}
|
||||||
|
|
||||||
|
record diff-result {
|
||||||
|
left: option<object-diff>,
|
||||||
|
right: option<object-diff>,
|
||||||
|
}
|
||||||
|
|
||||||
|
run-diff: func(
|
||||||
|
left: option<borrow<object>>,
|
||||||
|
right: option<borrow<object>>,
|
||||||
|
config: borrow<diff-config>,
|
||||||
|
mapping: mapping-config,
|
||||||
|
) -> result<diff-result, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface display {
|
||||||
|
use diff.{
|
||||||
|
object,
|
||||||
|
object-diff,
|
||||||
|
diff-config,
|
||||||
|
symbol-info,
|
||||||
|
symbol-ref
|
||||||
|
};
|
||||||
|
|
||||||
|
record display-config {
|
||||||
|
show-hidden-symbols: bool,
|
||||||
|
show-mapped-symbols: bool,
|
||||||
|
reverse-fn-order: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
record symbol-filter {
|
||||||
|
regex: option<string>,
|
||||||
|
mapping: option<symbol-ref>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record section-display {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
size: u64,
|
||||||
|
match-percent: option<f32>,
|
||||||
|
symbols: list<symbol-ref>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record symbol-display {
|
||||||
|
info: symbol-info,
|
||||||
target-symbol: option<symbol-ref>,
|
target-symbol: option<symbol-ref>,
|
||||||
match-percent: option<f32>,
|
match-percent: option<f32>,
|
||||||
diff-score: option<tuple<u64, u64>>,
|
diff-score: option<tuple<u64, u64>>,
|
||||||
@ -232,36 +239,36 @@ interface display {
|
|||||||
|
|
||||||
display-symbol: func(
|
display-symbol: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
) -> symbol-display;
|
) -> symbol-display;
|
||||||
|
|
||||||
display-instruction-row: func(
|
display-instruction-row: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
row-index: u32,
|
row-index: u32,
|
||||||
config: borrow<diff-config>,
|
config: borrow<diff-config>,
|
||||||
) -> instruction-diff-row;
|
) -> instruction-diff-row;
|
||||||
|
|
||||||
symbol-context: func(
|
symbol-context: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
) -> list<context-item>;
|
) -> list<context-item>;
|
||||||
|
|
||||||
symbol-hover: func(
|
symbol-hover: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
) -> list<hover-item>;
|
) -> list<hover-item>;
|
||||||
|
|
||||||
instruction-context: func(
|
instruction-context: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
row-index: u32,
|
row-index: u32,
|
||||||
config: borrow<diff-config>,
|
config: borrow<diff-config>,
|
||||||
) -> list<context-item>;
|
) -> list<context-item>;
|
||||||
|
|
||||||
instruction-hover: func(
|
instruction-hover: func(
|
||||||
diff: borrow<object-diff>,
|
diff: borrow<object-diff>,
|
||||||
symbol: section-display-symbol,
|
symbol: symbol-ref,
|
||||||
row-index: u32,
|
row-index: u32,
|
||||||
config: borrow<diff-config>,
|
config: borrow<diff-config>,
|
||||||
) -> list<hover-item>;
|
) -> list<hover-item>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user