mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7834185223 | |||
| 216dd70d5b | |||
| 976e629f08 | |||
| 67b28b7da1 | |||
| c0b9bfae21 | |||
| f3f4b0482a | |||
| 278683f103 | |||
| 6ad60de32a | |||
| 90c93164ab | |||
| c02eb31dbb | |||
| 86d92866aa | |||
| 51c3af2bbe | |||
| d0b8b449d9 | |||
| 32f5f202f7 | |||
| 481dbc185a | |||
| 26a4cc79cf | |||
| 5c96c2ee51 | |||
| d162fe847e | |||
| 2a24eb5aec | |||
| f7c291bd55 | |||
| 03a578c1bb | |||
| d09ef8e207 | |||
| 63552a58ae | |||
| 827f4a42bd | |||
| b2dcecc5d8 | |||
| 67b237eab6 | |||
| 66da80ff69 | |||
| 0a85f540f2 | |||
| d79b5b1233 | |||
| 8f5519cb6a | |||
| 19ec08be9a | |||
| 2ad0898efa | |||
| 03f2bcb8b1 | |||
| 781071761a |
Generated
+752
-728
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -14,7 +14,7 @@ default-members = [
|
|||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.3.0"
|
version = "3.5.1"
|
||||||
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"
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ ignore = [
|
|||||||
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
||||||
{ id = "RUSTSEC-2024-0436", reason = "Unmaintained paste crate is an indirect dependency" },
|
{ id = "RUSTSEC-2024-0436", reason = "Unmaintained paste crate is an indirect dependency" },
|
||||||
{ id = "RUSTSEC-2025-0052", reason = "Unmaintained async-std crate is an indirect dependency" },
|
{ id = "RUSTSEC-2025-0052", reason = "Unmaintained async-std crate is an indirect dependency" },
|
||||||
|
{ id = "RUSTSEC-2025-0119", reason = "Unmaintained number_prefix crate is an indirect dependency" },
|
||||||
|
{ id = "RUSTSEC-2025-0134", reason = "Unmaintained rustls-pemfile crate is an indirect dependency" },
|
||||||
]
|
]
|
||||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||||
# If this is false, then it uses a built-in git library.
|
# If this is false, then it uses a built-in git library.
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ publish = false
|
|||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
argp = "0.4"
|
argp = "0.4"
|
||||||
crossterm = "0.29"
|
crossterm = "0.29"
|
||||||
enable-ansi-support = "0.2"
|
enable-ansi-support = "0.3"
|
||||||
memmap2 = "0.9"
|
memmap2 = "0.9"
|
||||||
objdiff-core = { path = "../objdiff-core", features = ["all"] }
|
objdiff-core = { path = "../objdiff-core", features = ["all"] }
|
||||||
prost = "0.14"
|
prost = "0.14"
|
||||||
ratatui = "0.29"
|
ratatui = "0.29"
|
||||||
rayon = "1.10"
|
rayon = "1.11"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
supports-color = "3.0"
|
supports-color = "3.0"
|
||||||
time = { version = "0.3", features = ["formatting", "local-offset"] }
|
time = { version = "0.3", features = ["formatting", "local-offset"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
typed-path = "0.11"
|
typed-path = "0.12"
|
||||||
|
|
||||||
[target.'cfg(target_env = "musl")'.dependencies]
|
[target.'cfg(target_env = "musl")'.dependencies]
|
||||||
mimalloc = "0.1"
|
mimalloc = "0.1"
|
||||||
|
|||||||
@@ -66,15 +66,6 @@ pub struct Args {
|
|||||||
#[argp(option, short = 'c')]
|
#[argp(option, short = 'c')]
|
||||||
/// Configuration property (key=value)
|
/// Configuration property (key=value)
|
||||||
config: Vec<String>,
|
config: Vec<String>,
|
||||||
#[argp(option, short = 'm')]
|
|
||||||
/// Symbol mapping (target=base)
|
|
||||||
mapping: Vec<String>,
|
|
||||||
#[argp(option)]
|
|
||||||
/// Left symbol name for selection
|
|
||||||
selecting_left: Option<String>,
|
|
||||||
#[argp(option)]
|
|
||||||
/// Right symbol name for selection
|
|
||||||
selecting_right: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<()> {
|
pub fn run(args: Args) -> Result<()> {
|
||||||
@@ -183,17 +174,7 @@ fn build_config_from_args(
|
|||||||
apply_project_options(&mut diff_config, options)?;
|
apply_project_options(&mut diff_config, options)?;
|
||||||
}
|
}
|
||||||
apply_config_args(&mut diff_config, &args.config)?;
|
apply_config_args(&mut diff_config, &args.config)?;
|
||||||
let mut mapping_config = MappingConfig {
|
Ok((diff_config, MappingConfig::default()))
|
||||||
mappings: Default::default(),
|
|
||||||
selecting_left: args.selecting_left.clone(),
|
|
||||||
selecting_right: args.selecting_right.clone(),
|
|
||||||
};
|
|
||||||
for mapping in &args.mapping {
|
|
||||||
let (target, base) =
|
|
||||||
mapping.split_once('=').context("--mapping expects \"target=base\"")?;
|
|
||||||
mapping_config.mappings.insert(target.to_string(), base.to_string());
|
|
||||||
}
|
|
||||||
Ok((diff_config, mapping_config))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
|||||||
@@ -378,7 +378,6 @@ impl UiView for FunctionDiffUi {
|
|||||||
}
|
}
|
||||||
// Reload
|
// Reload
|
||||||
KeyCode::Char('r') => {
|
KeyCode::Char('r') => {
|
||||||
result.redraw = true;
|
|
||||||
return EventControlFlow::Reload;
|
return EventControlFlow::Reload;
|
||||||
}
|
}
|
||||||
// Scroll right
|
// Scroll right
|
||||||
@@ -400,7 +399,6 @@ impl UiView for FunctionDiffUi {
|
|||||||
FunctionRelocDiffs::DataValue => FunctionRelocDiffs::All,
|
FunctionRelocDiffs::DataValue => FunctionRelocDiffs::All,
|
||||||
FunctionRelocDiffs::All => FunctionRelocDiffs::None,
|
FunctionRelocDiffs::All => FunctionRelocDiffs::None,
|
||||||
};
|
};
|
||||||
result.redraw = true;
|
|
||||||
return EventControlFlow::Reload;
|
return EventControlFlow::Reload;
|
||||||
}
|
}
|
||||||
// Toggle three-way diff
|
// Toggle three-way diff
|
||||||
@@ -541,6 +539,7 @@ impl FunctionDiffUi {
|
|||||||
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
|
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
|
||||||
DiffText::Argument(arg) => arg.to_string(),
|
DiffText::Argument(arg) => arg.to_string(),
|
||||||
DiffText::BranchDest(addr) => format!("{addr:x}"),
|
DiffText::BranchDest(addr) => format!("{addr:x}"),
|
||||||
|
DiffText::BranchArrow(_) => " ~> ".to_string(),
|
||||||
DiffText::Symbol(sym) => {
|
DiffText::Symbol(sym) => {
|
||||||
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone()
|
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,10 +135,10 @@ num-traits = { version = "0.2", default-features = false, optional = true }
|
|||||||
object = { version = "0.37", default-features = false, features = ["read_core", "elf", "coff"] }
|
object = { version = "0.37", default-features = false, features = ["read_core", "elf", "coff"] }
|
||||||
pbjson = { version = "0.8", default-features = false, optional = true }
|
pbjson = { version = "0.8", default-features = false, optional = true }
|
||||||
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
|
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
|
||||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
regex = { version = "1.12", default-features = false, features = [], optional = true }
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
|
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
|
||||||
similar = { git = "https://github.com/encounter/similar.git", branch = "no_std", default-features = false, features = ["hashbrown"], optional = true }
|
similar = { git = "https://github.com/encounter/similar.git", branch = "no_std", default-features = false, features = ["hashbrown"], optional = true }
|
||||||
typed-path = { version = "0.11", default-features = false, optional = true }
|
typed-path = { version = "0.12", default-features = false, optional = true }
|
||||||
|
|
||||||
# config
|
# config
|
||||||
globset = { version = "0.4", default-features = false, optional = true }
|
globset = { version = "0.4", default-features = false, optional = true }
|
||||||
@@ -155,13 +155,13 @@ powerpc = { version = "0.4", optional = true }
|
|||||||
rlwinmdec = { version = "1.1", optional = true }
|
rlwinmdec = { version = "1.1", optional = true }
|
||||||
|
|
||||||
# mips
|
# mips
|
||||||
rabbitizer = { version = "2.0.0-alpha.4", default-features = false, features = ["all_extensions"], optional = true }
|
rabbitizer = { version = "2.0.0-alpha.7", default-features = false, features = ["all_extensions"], optional = true }
|
||||||
|
|
||||||
# x86
|
# x86
|
||||||
iced-x86 = { version = "1.21", default-features = false, features = ["decoder", "intel", "gas", "masm", "nasm", "exhaustive_enums", "no_std"], optional = true }
|
iced-x86 = { version = "1.21", default-features = false, features = ["decoder", "intel", "gas", "masm", "nasm", "exhaustive_enums", "no_std"], optional = true }
|
||||||
|
|
||||||
# arm
|
# arm
|
||||||
unarm = { version = "1.9", optional = true }
|
unarm = { version = "2.1", optional = true }
|
||||||
arm-attr = { version = "0.2", optional = true }
|
arm-attr = { version = "0.2", optional = true }
|
||||||
|
|
||||||
# arm64
|
# arm64
|
||||||
@@ -169,17 +169,17 @@ yaxpeax-arch = { version = "0.3", default-features = false, optional = true }
|
|||||||
yaxpeax-arm = { version = "0.3", default-features = false, optional = true }
|
yaxpeax-arm = { version = "0.3", default-features = false, optional = true }
|
||||||
|
|
||||||
# build
|
# build
|
||||||
notify = { version = "8.1.0", optional = true }
|
notify = { version = "8.2.0", optional = true }
|
||||||
notify-debouncer-full = { version = "0.5.0", optional = true }
|
notify-debouncer-full = { version = "0.6.0", optional = true }
|
||||||
shell-escape = { version = "0.1", optional = true }
|
shell-escape = { version = "0.1", optional = true }
|
||||||
tempfile = { version = "3.20", optional = true }
|
tempfile = { version = "3.23", optional = true }
|
||||||
time = { version = "0.3", optional = true }
|
time = { version = "0.3", optional = true }
|
||||||
encoding_rs = { version = "0.8.35", optional = true }
|
encoding_rs = { version = "0.8.35", optional = true }
|
||||||
|
|
||||||
# demangler
|
# demangler
|
||||||
cpp_demangle = { version = "0.4", optional = true, default-features = false, features = ["alloc"] }
|
cpp_demangle = { version = "0.5", optional = true, default-features = false, features = ["alloc"] }
|
||||||
cwdemangle = { version = "1.0", optional = true }
|
cwdemangle = { version = "1.0", optional = true }
|
||||||
gnuv2_demangle = { version = "0.1.0", optional = true }
|
gnuv2_demangle = { version = "0.4", optional = true }
|
||||||
msvc-demangler = { version = "0.11", optional = true }
|
msvc-demangler = { version = "0.11", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
|||||||
@@ -82,6 +82,27 @@
|
|||||||
"name": "Space between args",
|
"name": "Space between args",
|
||||||
"description": "Adds a space between arguments in the diff output."
|
"description": "Adds a space between arguments in the diff output."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "showSymbolSizes",
|
||||||
|
"type": "choice",
|
||||||
|
"default": "off",
|
||||||
|
"name": "Show symbol sizes",
|
||||||
|
"description": "Shows symbol sizes in the symbol view.",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"value": "off",
|
||||||
|
"name": "Off"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "hex",
|
||||||
|
"name": "Hex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "decimal",
|
||||||
|
"name": "Decimal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "combineDataSections",
|
"id": "combineDataSections",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -107,20 +128,43 @@
|
|||||||
"value": "auto",
|
"value": "auto",
|
||||||
"name": "Auto"
|
"name": "Auto"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "v4",
|
||||||
|
"name": "ARMv4"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "v4t",
|
"value": "v4t",
|
||||||
"name": "ARMv4T (GBA)"
|
"name": "ARMv4T (GBA)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "v5t",
|
||||||
|
"name": "ARMv5T"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "v5te",
|
"value": "v5te",
|
||||||
"name": "ARMv5TE (DS)"
|
"name": "ARMv5TE (DS)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "v5tej",
|
||||||
|
"name": "ARMv5TEJ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "v6",
|
||||||
|
"name": "ARMv6"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "v6k",
|
"value": "v6k",
|
||||||
"name": "ARMv6K (3DS)"
|
"name": "ARMv6K (3DS)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "arm.vfpV2",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"name": "VFPv2 instructions",
|
||||||
|
"description": "Adds floating-point instructions from VFPv2."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "arm.unifiedSyntax",
|
"id": "arm.unifiedSyntax",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -296,6 +340,7 @@
|
|||||||
"properties": [
|
"properties": [
|
||||||
"functionRelocDiffs",
|
"functionRelocDiffs",
|
||||||
"demangler",
|
"demangler",
|
||||||
|
"showSymbolSizes",
|
||||||
"spaceBetweenArgs",
|
"spaceBetweenArgs",
|
||||||
"combineDataSections",
|
"combineDataSections",
|
||||||
"combineTextSections"
|
"combineTextSections"
|
||||||
@@ -306,6 +351,7 @@
|
|||||||
"name": "ARM",
|
"name": "ARM",
|
||||||
"properties": [
|
"properties": [
|
||||||
"arm.archVersion",
|
"arm.archVersion",
|
||||||
|
"arm.vfpV2",
|
||||||
"arm.unifiedSyntax",
|
"arm.unifiedSyntax",
|
||||||
"arm.avRegisters",
|
"arm.avRegisters",
|
||||||
"arm.r9Usage",
|
"arm.r9Usage",
|
||||||
|
|||||||
+258
-346
File diff suppressed because it is too large
Load Diff
@@ -293,6 +293,7 @@ impl Arch for ArchMips {
|
|||||||
}
|
}
|
||||||
elf::R_MIPS_PC16 => 0, // PC-relative relocation
|
elf::R_MIPS_PC16 => 0, // PC-relative relocation
|
||||||
R_MIPS15_S3 => ((code & 0x001FFFC0) >> 3) as i64,
|
R_MIPS15_S3 => ((code & 0x001FFFC0) >> 3) as i64,
|
||||||
|
elf::R_MIPS_GPREL32 => (code as i32 as i64) + self.ri_gp_value as i64,
|
||||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||||
};
|
};
|
||||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||||
@@ -318,6 +319,7 @@ impl Arch for ArchMips {
|
|||||||
elf::R_MIPS_GOT16 => Some("R_MIPS_GOT16"),
|
elf::R_MIPS_GOT16 => Some("R_MIPS_GOT16"),
|
||||||
elf::R_MIPS_PC16 => Some("R_MIPS_PC16"),
|
elf::R_MIPS_PC16 => Some("R_MIPS_PC16"),
|
||||||
elf::R_MIPS_CALL16 => Some("R_MIPS_CALL16"),
|
elf::R_MIPS_CALL16 => Some("R_MIPS_CALL16"),
|
||||||
|
elf::R_MIPS_GPREL32 => Some("R_MIPS_GPREL32"),
|
||||||
R_MIPS15_S3 => Some("R_MIPS15_S3"),
|
R_MIPS15_S3 => Some("R_MIPS15_S3"),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,12 +7,10 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
any::Any,
|
any::Any,
|
||||||
ffi::CStr,
|
|
||||||
fmt::{self, Debug},
|
fmt::{self, Debug},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use encoding_rs::SHIFT_JIS;
|
|
||||||
use object::Endian as _;
|
use object::Endian as _;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -44,6 +42,16 @@ pub mod x86;
|
|||||||
pub const OPCODE_INVALID: u16 = u16::MAX;
|
pub const OPCODE_INVALID: u16 = u16::MAX;
|
||||||
pub const OPCODE_DATA: u16 = u16::MAX - 1;
|
pub const OPCODE_DATA: u16 = u16::MAX - 1;
|
||||||
|
|
||||||
|
const SUPPORTED_ENCODINGS: [(&encoding_rs::Encoding, &str); 7] = [
|
||||||
|
(encoding_rs::UTF_8, "UTF-8"),
|
||||||
|
(encoding_rs::SHIFT_JIS, "Shift JIS"),
|
||||||
|
(encoding_rs::UTF_16BE, "UTF-16BE"),
|
||||||
|
(encoding_rs::UTF_16LE, "UTF-16LE"),
|
||||||
|
(encoding_rs::WINDOWS_1252, "Windows-1252"),
|
||||||
|
(encoding_rs::EUC_JP, "EUC-JP"),
|
||||||
|
(encoding_rs::BIG5, "Big5"),
|
||||||
|
];
|
||||||
|
|
||||||
/// Represents the type of data associated with an instruction
|
/// Represents the type of data associated with an instruction
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum DataType {
|
pub enum DataType {
|
||||||
@@ -75,9 +83,9 @@ impl fmt::Display for DataType {
|
|||||||
impl DataType {
|
impl DataType {
|
||||||
pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> {
|
pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> {
|
||||||
let mut strs = Vec::new();
|
let mut strs = Vec::new();
|
||||||
for (literal, label_override) in self.display_literals(endian, bytes) {
|
for (literal, label_override, _) in self.display_literals(endian, bytes) {
|
||||||
let label = label_override.unwrap_or_else(|| self.to_string());
|
let label = label_override.unwrap_or_else(|| self.to_string());
|
||||||
strs.push(format!("{label}: {literal}"))
|
strs.push(format!("{label}: {literal:?}"))
|
||||||
}
|
}
|
||||||
strs
|
strs
|
||||||
}
|
}
|
||||||
@@ -86,7 +94,7 @@ impl DataType {
|
|||||||
&self,
|
&self,
|
||||||
endian: object::Endianness,
|
endian: object::Endianness,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Vec<(String, Option<String>)> {
|
) -> Vec<(String, Option<String>, Option<String>)> {
|
||||||
let mut strs = Vec::new();
|
let mut strs = Vec::new();
|
||||||
if self.required_len().is_some_and(|l| bytes.len() < l) {
|
if self.required_len().is_some_and(|l| bytes.len() < l) {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -110,34 +118,34 @@ impl DataType {
|
|||||||
match self {
|
match self {
|
||||||
DataType::Int8 => {
|
DataType::Int8 => {
|
||||||
let i = i8::from_ne_bytes(bytes.try_into().unwrap());
|
let i = i8::from_ne_bytes(bytes.try_into().unwrap());
|
||||||
strs.push((format!("{i:#x}"), None));
|
strs.push((format!("{i:#x}"), None, None));
|
||||||
|
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
strs.push((format!("{:#x}", ReallySigned(i)), None, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType::Int16 => {
|
DataType::Int16 => {
|
||||||
let i = endian.read_i16_bytes(bytes.try_into().unwrap());
|
let i = endian.read_i16_bytes(bytes.try_into().unwrap());
|
||||||
strs.push((format!("{i:#x}"), None));
|
strs.push((format!("{i:#x}"), None, None));
|
||||||
|
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
strs.push((format!("{:#x}", ReallySigned(i)), None, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType::Int32 => {
|
DataType::Int32 => {
|
||||||
let i = endian.read_i32_bytes(bytes.try_into().unwrap());
|
let i = endian.read_i32_bytes(bytes.try_into().unwrap());
|
||||||
strs.push((format!("{i:#x}"), None));
|
strs.push((format!("{i:#x}"), None, None));
|
||||||
|
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
strs.push((format!("{:#x}", ReallySigned(i)), None, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType::Int64 => {
|
DataType::Int64 => {
|
||||||
let i = endian.read_i64_bytes(bytes.try_into().unwrap());
|
let i = endian.read_i64_bytes(bytes.try_into().unwrap());
|
||||||
strs.push((format!("{i:#x}"), None));
|
strs.push((format!("{i:#x}"), None, None));
|
||||||
|
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
strs.push((format!("{:#x}", ReallySigned(i)), None, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType::Float => {
|
DataType::Float => {
|
||||||
@@ -148,6 +156,7 @@ impl DataType {
|
|||||||
object::Endianness::Big => f32::from_be_bytes(bytes),
|
object::Endianness::Big => f32::from_be_bytes(bytes),
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
DataType::Double => {
|
DataType::Double => {
|
||||||
@@ -158,22 +167,29 @@ impl DataType {
|
|||||||
object::Endianness::Big => f64::from_be_bytes(bytes),
|
object::Endianness::Big => f64::from_be_bytes(bytes),
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
DataType::Bytes => {
|
DataType::Bytes => {
|
||||||
strs.push((format!("{bytes:#?}"), None));
|
strs.push((format!("{bytes:#?}"), None, None));
|
||||||
}
|
}
|
||||||
DataType::String => {
|
DataType::String => {
|
||||||
if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) {
|
|
||||||
strs.push((format!("{cstr:?}"), None));
|
|
||||||
}
|
|
||||||
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
|
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
|
||||||
let (cow, _, had_errors) = SHIFT_JIS.decode(&bytes[..nul_idx]);
|
let str_bytes = &bytes[..nul_idx];
|
||||||
if !had_errors {
|
// Special case to display (ASCII) as the label for ASCII-only strings.
|
||||||
let str = format!("{cow:?}");
|
let (cow, _, had_errors) = encoding_rs::UTF_8.decode(str_bytes);
|
||||||
// Only add the Shift JIS string if it's different from the ASCII string.
|
if !had_errors && cow.is_ascii() {
|
||||||
if !strs.iter().any(|x| x.0 == str) {
|
let string = format!("{cow}");
|
||||||
strs.push((str, Some("Shift JIS".into())));
|
let copy_string = escape_special_ascii_characters(string.clone());
|
||||||
|
strs.push((string, Some("ASCII".into()), Some(copy_string)));
|
||||||
|
}
|
||||||
|
for (encoding, encoding_name) in SUPPORTED_ENCODINGS {
|
||||||
|
let (cow, _, had_errors) = encoding.decode(str_bytes);
|
||||||
|
// Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible.
|
||||||
|
if !had_errors && (!encoding.is_ascii_compatible() || !cow.is_ascii()) {
|
||||||
|
let string = format!("{cow}");
|
||||||
|
let copy_string = escape_special_ascii_characters(string.clone());
|
||||||
|
strs.push((string, Some(encoding_name.into()), Some(copy_string)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,3 +505,21 @@ pub struct RelocationOverride {
|
|||||||
pub target: RelocationOverrideTarget,
|
pub target: RelocationOverrideTarget,
|
||||||
pub addend: i64,
|
pub addend: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Escape ASCII characters such as \n or \t, but not Unicode characters such as \u{3000}.
|
||||||
|
/// Suitable for copying to clipboard.
|
||||||
|
fn escape_special_ascii_characters(value: String) -> String {
|
||||||
|
let mut escaped = String::new();
|
||||||
|
escaped.push('"');
|
||||||
|
for c in value.chars() {
|
||||||
|
if c.is_ascii() {
|
||||||
|
for e in c.escape_default() {
|
||||||
|
escaped.push(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
escaped.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escaped.push('"');
|
||||||
|
escaped
|
||||||
|
}
|
||||||
|
|||||||
@@ -440,9 +440,13 @@ impl Arch for ArchPpc {
|
|||||||
let simplified = ins.simplified().to_string();
|
let simplified = ins.simplified().to_string();
|
||||||
let show_orig = orig != simplified;
|
let show_orig = orig != simplified;
|
||||||
let mut out = Vec::with_capacity(2);
|
let mut out = Vec::with_capacity(2);
|
||||||
out.push(ContextItem::Copy { value: simplified, label: None });
|
out.push(ContextItem::Copy { value: simplified, label: None, copy_string: None });
|
||||||
if show_orig {
|
if show_orig {
|
||||||
out.push(ContextItem::Copy { value: orig, label: Some("original".to_string()) });
|
out.push(ContextItem::Copy {
|
||||||
|
value: orig,
|
||||||
|
label: Some("original".to_string()),
|
||||||
|
copy_string: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,13 +36,27 @@ pub fn diff_bss_symbol(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool {
|
pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool {
|
||||||
// Match Metrowerks symbol$1234 against symbol$2345
|
if let Some((left_prefix, left_suffix)) = left_name.split_once("@class$")
|
||||||
if let Some((prefix, suffix)) = left_name.split_once('$') {
|
&& let Some((right_prefix, right_suffix)) = right_name.split_once("@class$")
|
||||||
if !suffix.chars().all(char::is_numeric) {
|
{
|
||||||
return false;
|
// Match Metrowerks anonymous class symbol names, ignoring the unique ID.
|
||||||
|
// e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv
|
||||||
|
if left_prefix == right_prefix
|
||||||
|
&& let Some(left_idx) = left_suffix.chars().position(|c| !c.is_numeric())
|
||||||
|
&& let Some(right_idx) = right_suffix.chars().position(|c| !c.is_numeric())
|
||||||
|
{
|
||||||
|
// e.g. d_camera_cppFv (after the unique ID)
|
||||||
|
left_suffix[left_idx..] == right_suffix[right_idx..]
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
} else if let Some((prefix, suffix)) = left_name.split_once(['$', '.'])
|
||||||
|
&& suffix.chars().all(char::is_numeric)
|
||||||
|
{
|
||||||
|
// Match Metrowerks symbol$1234 against symbol$2345
|
||||||
|
// and GCC symbol.1234 against symbol.2345
|
||||||
right_name
|
right_name
|
||||||
.split_once('$')
|
.split_once(['$', '.'])
|
||||||
.is_some_and(|(p, s)| p == prefix && s.chars().all(char::is_numeric))
|
.is_some_and(|(p, s)| p == prefix && s.chars().all(char::is_numeric))
|
||||||
} else {
|
} else {
|
||||||
left_name == right_name
|
left_name == right_name
|
||||||
@@ -587,6 +601,7 @@ fn symbols_matching_section(
|
|||||||
s.section == Some(section_idx)
|
s.section == Some(section_idx)
|
||||||
&& s.kind != SymbolKind::Section
|
&& s.kind != SymbolKind::Section
|
||||||
&& s.size > 0
|
&& s.size > 0
|
||||||
|
&& !s.flags.contains(SymbolFlag::Hidden)
|
||||||
&& !s.flags.contains(SymbolFlag::Ignored)
|
&& !s.flags.contains(SymbolFlag::Ignored)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,12 @@ impl Demangler {
|
|||||||
|
|
||||||
fn demangle_itanium(name: &str) -> Option<String> {
|
fn demangle_itanium(name: &str) -> Option<String> {
|
||||||
let name = name.trim_start_matches('.');
|
let name = name.trim_start_matches('.');
|
||||||
cpp_demangle::Symbol::new(name)
|
cpp_demangle::Symbol::new(name).ok().and_then(|s| s.demangle().ok())
|
||||||
.ok()
|
|
||||||
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle_gnu_legacy(name: &str) -> Option<String> {
|
fn demangle_gnu_legacy(name: &str) -> Option<String> {
|
||||||
let name = name.trim_start_matches('.');
|
let name = name.trim_start_matches('.');
|
||||||
gnuv2_demangle::demangle(name, &gnuv2_demangle::DemangleConfig::new_no_cfilt_mimics()).ok()
|
gnuv2_demangle::demangle(name, &gnuv2_demangle::DemangleConfig::new()).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ pub enum DiffText<'a> {
|
|||||||
Argument(InstructionArgValue<'a>),
|
Argument(InstructionArgValue<'a>),
|
||||||
/// Branch destination
|
/// Branch destination
|
||||||
BranchDest(u64),
|
BranchDest(u64),
|
||||||
|
/// Branch source/destination arrow, scrolls to a specific row when clicked
|
||||||
|
BranchArrow(u32),
|
||||||
/// Symbol name
|
/// Symbol name
|
||||||
Symbol(&'a Symbol),
|
Symbol(&'a Symbol),
|
||||||
/// Relocation addend
|
/// Relocation addend
|
||||||
@@ -185,7 +187,13 @@ pub fn display_row(
|
|||||||
pad_to: 5,
|
pad_to: 5,
|
||||||
})?;
|
})?;
|
||||||
if let Some(branch) = &ins_row.branch_from {
|
if let Some(branch) = &ins_row.branch_from {
|
||||||
cb(DiffTextSegment::basic(" ~> ", DiffTextColor::Rotating(branch.branch_idx as u8)))?;
|
// Pick the first branch source if there are multiple.
|
||||||
|
let ins_idx = branch.ins_idx[0];
|
||||||
|
cb(DiffTextSegment {
|
||||||
|
text: DiffText::BranchArrow(ins_idx),
|
||||||
|
color: DiffTextColor::Rotating(branch.branch_idx as u8),
|
||||||
|
pad_to: 0,
|
||||||
|
})?;
|
||||||
} else {
|
} else {
|
||||||
cb(DiffTextSegment::spacing(4))?;
|
cb(DiffTextSegment::spacing(4))?;
|
||||||
}
|
}
|
||||||
@@ -307,7 +315,11 @@ pub fn display_row(
|
|||||||
cb(DiffTextSegment::basic(">", base_color))?;
|
cb(DiffTextSegment::basic(">", base_color))?;
|
||||||
}
|
}
|
||||||
if let Some(branch) = &ins_row.branch_to {
|
if let Some(branch) = &ins_row.branch_to {
|
||||||
cb(DiffTextSegment::basic(" ~>", DiffTextColor::Rotating(branch.branch_idx as u8)))?;
|
cb(DiffTextSegment {
|
||||||
|
text: DiffText::BranchArrow(branch.ins_idx),
|
||||||
|
color: DiffTextColor::Rotating(branch.branch_idx as u8),
|
||||||
|
pad_to: 0,
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
cb(EOL_SEGMENT)?;
|
cb(EOL_SEGMENT)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -354,7 +366,7 @@ impl From<&DiffText<'_>> for HighlightKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum ContextItem {
|
pub enum ContextItem {
|
||||||
Copy { value: String, label: Option<String> },
|
Copy { value: String, label: Option<String>, copy_string: Option<String> },
|
||||||
Navigate { label: String, symbol_index: usize, kind: SymbolNavigationKind },
|
Navigate { label: String, symbol_index: usize, kind: SymbolNavigationKind },
|
||||||
Separator,
|
Separator,
|
||||||
}
|
}
|
||||||
@@ -386,9 +398,9 @@ pub fn symbol_context(obj: &Object, symbol_index: usize) -> Vec<ContextItem> {
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
out.push(ContextItem::Copy { value: symbol.name.clone(), label: None });
|
out.push(ContextItem::Copy { value: symbol.name.clone(), label: None, copy_string: None });
|
||||||
if let Some(name) = &symbol.demangled_name {
|
if let Some(name) = &symbol.demangled_name {
|
||||||
out.push(ContextItem::Copy { value: name.clone(), label: None });
|
out.push(ContextItem::Copy { value: name.clone(), label: None, copy_string: None });
|
||||||
}
|
}
|
||||||
if symbol.section.is_some()
|
if symbol.section.is_some()
|
||||||
&& let Some(address) = symbol.virtual_address
|
&& let Some(address) = symbol.virtual_address
|
||||||
@@ -396,6 +408,7 @@ pub fn symbol_context(obj: &Object, symbol_index: usize) -> Vec<ContextItem> {
|
|||||||
out.push(ContextItem::Copy {
|
out.push(ContextItem::Copy {
|
||||||
value: format!("{address:x}"),
|
value: format!("{address:x}"),
|
||||||
label: Some("virtual address".to_string()),
|
label: Some("virtual address".to_string()),
|
||||||
|
copy_string: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
out.append(&mut obj.arch.symbol_context(obj, symbol_index));
|
out.append(&mut obj.arch.symbol_context(obj, symbol_index));
|
||||||
@@ -489,8 +502,8 @@ pub fn relocation_context(
|
|||||||
let literals = display_ins_data_literals(obj, ins);
|
let literals = display_ins_data_literals(obj, ins);
|
||||||
if !literals.is_empty() {
|
if !literals.is_empty() {
|
||||||
out.push(ContextItem::Separator);
|
out.push(ContextItem::Separator);
|
||||||
for (literal, label_override) in literals {
|
for (literal, label_override, copy_string) in literals {
|
||||||
out.push(ContextItem::Copy { value: literal, label: label_override });
|
out.push(ContextItem::Copy { value: literal, label: label_override, copy_string });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -586,24 +599,37 @@ pub fn instruction_context(
|
|||||||
for byte in resolved.code {
|
for byte in resolved.code {
|
||||||
hex_string.push_str(&format!("{byte:02x}"));
|
hex_string.push_str(&format!("{byte:02x}"));
|
||||||
}
|
}
|
||||||
out.push(ContextItem::Copy { value: hex_string, label: Some("instruction bytes".to_string()) });
|
out.push(ContextItem::Copy {
|
||||||
|
value: hex_string,
|
||||||
|
label: Some("instruction bytes".to_string()),
|
||||||
|
copy_string: None,
|
||||||
|
});
|
||||||
out.append(&mut obj.arch.instruction_context(obj, resolved));
|
out.append(&mut obj.arch.instruction_context(obj, resolved));
|
||||||
if let Some(virtual_address) = resolved.symbol.virtual_address {
|
if let Some(virtual_address) = resolved.symbol.virtual_address {
|
||||||
let offset = resolved.ins_ref.address - resolved.symbol.address;
|
let offset = resolved.ins_ref.address - resolved.symbol.address;
|
||||||
out.push(ContextItem::Copy {
|
out.push(ContextItem::Copy {
|
||||||
value: format!("{:x}", virtual_address + offset),
|
value: format!("{:x}", virtual_address + offset),
|
||||||
label: Some("virtual address".to_string()),
|
label: Some("virtual address".to_string()),
|
||||||
|
copy_string: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for arg in &ins.args {
|
for arg in &ins.args {
|
||||||
if let InstructionArg::Value(arg) = arg {
|
if let InstructionArg::Value(arg) = arg {
|
||||||
out.push(ContextItem::Copy { value: arg.to_string(), label: None });
|
out.push(ContextItem::Copy { value: arg.to_string(), label: None, copy_string: None });
|
||||||
match arg {
|
match arg {
|
||||||
InstructionArgValue::Signed(v) => {
|
InstructionArgValue::Signed(v) => {
|
||||||
out.push(ContextItem::Copy { value: v.to_string(), label: None });
|
out.push(ContextItem::Copy {
|
||||||
|
value: v.to_string(),
|
||||||
|
label: None,
|
||||||
|
copy_string: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
InstructionArgValue::Unsigned(v) => {
|
InstructionArgValue::Unsigned(v) => {
|
||||||
out.push(ContextItem::Copy { value: v.to_string(), label: None });
|
out.push(ContextItem::Copy {
|
||||||
|
value: v.to_string(),
|
||||||
|
label: None,
|
||||||
|
copy_string: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -665,10 +691,10 @@ pub fn instruction_hover(
|
|||||||
let literals = display_ins_data_literals(obj, resolved);
|
let literals = display_ins_data_literals(obj, resolved);
|
||||||
if !literals.is_empty() {
|
if !literals.is_empty() {
|
||||||
out.push(HoverItem::Separator);
|
out.push(HoverItem::Separator);
|
||||||
for (literal, label_override) in literals {
|
for (literal, label_override, _) in literals {
|
||||||
out.push(HoverItem::Text {
|
out.push(HoverItem::Text {
|
||||||
label: label_override.unwrap_or_else(|| ty.to_string()),
|
label: label_override.unwrap_or_else(|| ty.to_string()),
|
||||||
value: literal,
|
value: format!("{literal:?}"),
|
||||||
color: HoverItemColor::Normal,
|
color: HoverItemColor::Normal,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -859,7 +885,7 @@ pub fn display_ins_data_labels(obj: &Object, resolved: ResolvedInstructionRef) -
|
|||||||
pub fn display_ins_data_literals(
|
pub fn display_ins_data_literals(
|
||||||
obj: &Object,
|
obj: &Object,
|
||||||
resolved: ResolvedInstructionRef,
|
resolved: ResolvedInstructionRef,
|
||||||
) -> Vec<(String, Option<String>)> {
|
) -> Vec<(String, Option<String>, Option<String>)> {
|
||||||
let Some(reloc) = resolved.relocation else {
|
let Some(reloc) = resolved.relocation else {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use alloc::{
|
|||||||
use core::{num::NonZeroU32, ops::Range};
|
use core::{num::NonZeroU32, ops::Range};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diff::{
|
diff::{
|
||||||
@@ -759,18 +760,16 @@ fn find_symbol(
|
|||||||
return closest_match_symbol_idx;
|
return closest_match_symbol_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find an exact name match
|
// Try to find a symbol with a matching name
|
||||||
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
|
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used)
|
||||||
symbol.name == in_symbol.name && symbol_section_kind(obj, symbol) == section_kind
|
.filter(|&(_, symbol)| {
|
||||||
}) {
|
symbol_name_matches(&in_symbol.name, &symbol.name)
|
||||||
return Some(symbol_idx);
|
&& symbol_section_kind(obj, symbol) == section_kind
|
||||||
}
|
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
|
||||||
|
})
|
||||||
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|&(_, symbol)| {
|
.sorted_unstable_by_key(|&(_, symbol)| (symbol.section, symbol.address))
|
||||||
symbol_name_matches(&in_symbol.name, &symbol.name)
|
.next()
|
||||||
&& symbol_section_kind(obj, symbol) == section_kind
|
{
|
||||||
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
|
|
||||||
}) {
|
|
||||||
return Some(symbol_idx);
|
return Some(symbol_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -824,19 +824,16 @@ fn combine_sections(
|
|||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut data_sections = BTreeMap::<String, Vec<usize>>::new();
|
let mut data_sections = BTreeMap::<String, Vec<usize>>::new();
|
||||||
let mut text_sections = Vec::<usize>::new();
|
let mut text_sections = BTreeMap::<String, Vec<usize>>::new();
|
||||||
for (i, section) in sections.iter().enumerate() {
|
for (i, section) in sections.iter().enumerate() {
|
||||||
|
let base_name =
|
||||||
|
if let Some(i) = section.name.rfind('$') { §ion.name[..i] } else { §ion.name };
|
||||||
match section.kind {
|
match section.kind {
|
||||||
SectionKind::Data | SectionKind::Bss => {
|
SectionKind::Data | SectionKind::Bss => {
|
||||||
let base_name = if let Some(i) = section.name.rfind('$') {
|
|
||||||
§ion.name[..i]
|
|
||||||
} else {
|
|
||||||
§ion.name
|
|
||||||
};
|
|
||||||
data_sections.entry(base_name.to_string()).or_default().push(i);
|
data_sections.entry(base_name.to_string()).or_default().push(i);
|
||||||
}
|
}
|
||||||
SectionKind::Code => {
|
SectionKind::Code => {
|
||||||
text_sections.push(i);
|
text_sections.entry(base_name.to_string()).or_default().push(i);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -847,7 +844,9 @@ fn combine_sections(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.combine_text_sections {
|
if config.combine_text_sections {
|
||||||
do_combine_sections(sections, symbols, &mut text_sections, ".text".to_string())?;
|
for (combined_name, mut section_indices) in text_sections {
|
||||||
|
do_combine_sections(sections, symbols, &mut section_indices, combined_name)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
source: objdiff-core/tests/arch_arm.rs
|
source: objdiff-core/tests/arch_arm.rs
|
||||||
expression: output
|
expression: output
|
||||||
---
|
---
|
||||||
[(Line(90), Dim, 5), (Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32799), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(8), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
[(Line(90), Dim, 5), (Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(8), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||||
[(Line(90), Dim, 5), (Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bx", 32779), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
|
[(Line(90), Dim, 5), (Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bx", 32777), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
|
||||||
[(Line(90), Dim, 5), (Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "esEnemyDraw", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
[(Line(90), Dim, 5), (Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "esEnemyDraw", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ expression: diff.instruction_rows
|
|||||||
InstructionRef {
|
InstructionRef {
|
||||||
address: 76,
|
address: 76,
|
||||||
size: 4,
|
size: 4,
|
||||||
opcode: 32799,
|
opcode: 32792,
|
||||||
branch_dest: None,
|
branch_dest: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -22,7 +22,7 @@ expression: diff.instruction_rows
|
|||||||
InstructionRef {
|
InstructionRef {
|
||||||
address: 80,
|
address: 80,
|
||||||
size: 4,
|
size: 4,
|
||||||
opcode: 32779,
|
opcode: 32777,
|
||||||
branch_dest: None,
|
branch_dest: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user