mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-15 16:16:15 +00:00
Compare commits
26 Commits
v3.0.0-bet
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85fb18a21a | ||
| 00ad0d8094 | |||
| 8fac63c42c | |||
| 0fb7f3901c | |||
|
|
3385f58341 | ||
| 60b227f45e | |||
|
|
127ae5ae44 | ||
| 5f48e69775 | |||
| 8756eee07b | |||
| bd3ed0d5ad | |||
|
|
e638d0b17a | ||
|
|
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]
|
||||
linker = "rust-lld"
|
||||
|
||||
[target.aarch64-pc-windows-msvc]
|
||||
linker = "rust-lld"
|
||||
# statically link the C runtime so the executable does not depend on
|
||||
# that shared/dynamic library.
|
||||
[target.'cfg(all(target_env = "msvc", target_os = "windows"))']
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
1179
Cargo.lock
generated
1179
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ strip = "debuginfo"
|
||||
codegen-units = 1
|
||||
|
||||
[workspace.package]
|
||||
version = "3.0.0-beta.7"
|
||||
version = "3.0.0-beta.11"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -19,9 +19,9 @@ Supports:
|
||||
- ARM (GBA, DS, 3DS)
|
||||
- ARM64 (Switch)
|
||||
- MIPS (N64, PS1, PS2, PSP)
|
||||
- PowerPC (GameCube, Wii)
|
||||
- PowerPC (GameCube, Wii, PS3, Xbox 360)
|
||||
- SuperH (Saturn, Dreamcast)
|
||||
- x86 (COFF only)
|
||||
- x86, x86_64 (PC)
|
||||
|
||||
See [Usage](#usage) for more information.
|
||||
|
||||
|
||||
@@ -175,6 +175,10 @@
|
||||
"type": "boolean",
|
||||
"description": "If true, objdiff will run the build command with the context file as an argument to generate it.",
|
||||
"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": [
|
||||
|
||||
@@ -203,14 +203,10 @@ fn run_oneshot(
|
||||
let output_format = OutputFormat::from_option(args.format.as_deref())?;
|
||||
let (diff_config, mapping_config) = build_config_from_args(args)?;
|
||||
let target = target_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
|
||||
})
|
||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
||||
.transpose()?;
|
||||
let base = base_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
|
||||
})
|
||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
||||
.transpose()?;
|
||||
let result =
|
||||
diff::diff_objs(target.as_ref(), base.as_ref(), None, &diff_config, &mapping_config)?;
|
||||
@@ -399,7 +395,7 @@ fn run_interactive(
|
||||
stdout(),
|
||||
EnterAlternateScreen,
|
||||
EnableMouseCapture,
|
||||
SetTitle(format!("{} - objdiff", symbol_name)),
|
||||
SetTitle(format!("{symbol_name} - objdiff")),
|
||||
)?;
|
||||
let backend = CrosstermBackend::new(stdout());
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
@@ -177,16 +177,14 @@ fn report_object(
|
||||
.target_path
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), diff_config)
|
||||
.with_context(|| format!("Failed to open {}", p))
|
||||
obj::read::read(p.as_ref(), diff_config).with_context(|| format!("Failed to open {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let base = object
|
||||
.base_path
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), diff_config)
|
||||
.with_context(|| format!("Failed to open {}", p))
|
||||
obj::read::read(p.as_ref(), diff_config).with_context(|| format!("Failed to open {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let result =
|
||||
@@ -245,12 +243,14 @@ fn report_object(
|
||||
for (symbol, symbol_diff) in obj.symbols.iter().zip(&obj_diff.symbols) {
|
||||
if symbol.section != Some(section_idx)
|
||||
|| symbol.size == 0
|
||||
|| symbol.flags.contains(SymbolFlag::Hidden | SymbolFlag::Ignored)
|
||||
|| symbol.flags.contains(SymbolFlag::Hidden)
|
||||
|| symbol.flags.contains(SymbolFlag::Ignored)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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())
|
||||
{
|
||||
continue;
|
||||
@@ -431,8 +431,8 @@ fn read_report(path: &Utf8PlatformPath) -> Result<Report> {
|
||||
std::io::stdin().read_to_end(&mut data)?;
|
||||
return Report::parse(&data).with_context(|| "Failed to load report from stdin");
|
||||
}
|
||||
let file = File::open(path).with_context(|| format!("Failed to open {}", path))?;
|
||||
let file = File::open(path).with_context(|| format!("Failed to open {path}"))?;
|
||||
let mmap =
|
||||
unsafe { memmap2::Mmap::map(&file) }.with_context(|| format!("Failed to map {}", path))?;
|
||||
Report::parse(mmap.as_ref()).with_context(|| format!("Failed to load report {}", path))
|
||||
unsafe { memmap2::Mmap::map(&file) }.with_context(|| format!("Failed to map {path}"))?;
|
||||
Report::parse(mmap.as_ref()).with_context(|| format!("Failed to load report {path}"))
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl UiView for FunctionDiffUi {
|
||||
.and_then(|(_, _, d)| d.match_percent)
|
||||
{
|
||||
line_r.spans.push(Span::styled(
|
||||
format!("{:.2}% ", percent),
|
||||
format!("{percent:.2}% "),
|
||||
Style::new().fg(match_percent_color(percent)),
|
||||
));
|
||||
}
|
||||
@@ -97,7 +97,7 @@ impl UiView for FunctionDiffUi {
|
||||
.and_then(|t| t.format(&state.time_format).ok())
|
||||
.unwrap_or_else(|| "N/A".to_string());
|
||||
line_r.spans.push(Span::styled(
|
||||
format!("Last reload: {}", reload_time),
|
||||
format!("Last reload: {reload_time}"),
|
||||
Style::new().fg(Color::White),
|
||||
));
|
||||
line_r.spans.push(Span::styled(
|
||||
@@ -450,11 +450,11 @@ impl UiView for FunctionDiffUi {
|
||||
|
||||
fn reload(&mut self, state: &AppState) -> Result<()> {
|
||||
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 =
|
||||
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 =
|
||||
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 (
|
||||
get_symbol(state.left_obj.as_ref(), left_sym),
|
||||
get_symbol(state.right_obj.as_ref(), right_sym),
|
||||
@@ -538,7 +538,7 @@ impl FunctionDiffUi {
|
||||
let label_text = match segment.text {
|
||||
DiffText::Basic(text) => text.to_string(),
|
||||
DiffText::Line(num) => format!("{num} "),
|
||||
DiffText::Address(addr) => format!("{:x}:", addr),
|
||||
DiffText::Address(addr) => format!("{addr:x}:"),
|
||||
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
|
||||
DiffText::Argument(arg) => arg.to_string(),
|
||||
DiffText::BranchDest(addr) => format!("{addr:x}"),
|
||||
@@ -546,7 +546,7 @@ impl FunctionDiffUi {
|
||||
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone()
|
||||
}
|
||||
DiffText::Addend(addend) => match addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:#x}", addend),
|
||||
Ordering::Greater => format!("+{addend:#x}"),
|
||||
Ordering::Less => format!("-{:#x}", -addend),
|
||||
_ => String::new(),
|
||||
},
|
||||
@@ -570,6 +570,7 @@ impl FunctionDiffUi {
|
||||
DiffTextColor::Normal => Color::Gray,
|
||||
DiffTextColor::Dim => Color::DarkGray,
|
||||
DiffTextColor::Bright => Color::White,
|
||||
DiffTextColor::DataFlow => Color::LightCyan,
|
||||
DiffTextColor::Replace => Color::Cyan,
|
||||
DiffTextColor::Delete => Color::Red,
|
||||
DiffTextColor::Insert => Color::Green,
|
||||
@@ -650,12 +651,3 @@ fn get_symbol(
|
||||
let sym = 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:similar",
|
||||
"dep:syn",
|
||||
"dep:encoding_rs"
|
||||
]
|
||||
bindings = [
|
||||
"dep:prost",
|
||||
@@ -91,7 +92,7 @@ ppc = [
|
||||
"any-arch",
|
||||
"dep:cwdemangle",
|
||||
"dep:cwextab",
|
||||
"dep:ppc750cl",
|
||||
"dep:powerpc",
|
||||
"dep:rlwinmdec",
|
||||
]
|
||||
x86 = [
|
||||
@@ -127,7 +128,7 @@ itertools = { version = "0.14", default-features = false, features = ["use_alloc
|
||||
log = { version = "0.4", default-features = false, optional = true }
|
||||
memmap2 = { version = "0.9", optional = true }
|
||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||
object = { git = "https://github.com/gimli-rs/object", rev = "a74579249e21ab8fcd3a86be588de336f18297cb", default-features = false, features = ["read_core", "elf", "pe"] }
|
||||
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
|
||||
pbjson = { version = "0.7", default-features = false, optional = true }
|
||||
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
||||
@@ -146,7 +147,7 @@ gimli = { version = "0.31", default-features = false, features = ["read"], optio
|
||||
# ppc
|
||||
cwdemangle = { version = "1.0", optional = true }
|
||||
cwextab = { version = "1.0", optional = true }
|
||||
ppc750cl = { version = "0.3", optional = true }
|
||||
powerpc = { version = "0.4", optional = true }
|
||||
rlwinmdec = { version = "1.1", optional = true }
|
||||
|
||||
# mips
|
||||
@@ -171,10 +172,10 @@ notify-debouncer-full = { version = "0.5.0", optional = true }
|
||||
shell-escape = { version = "0.1", optional = true }
|
||||
tempfile = { version = "3.19", 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]
|
||||
winapi = { version = "0.3", optional = true }
|
||||
winapi = { version = "0.3", optional = true, features = ["winbase"] }
|
||||
|
||||
# For Linux static binaries, use rustls
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
|
||||
@@ -11,6 +11,6 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
|
||||
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
|
||||
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
|
||||
- **`mips`**: Enables the MIPS backend powered by [rabbitizer](https://github.com/Decompollaborate/rabbitizer).
|
||||
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
|
||||
- **`ppc`**: Enables the PowerPC backend powered by [powerpc](https://github.com/encounter/powerpc-rs).
|
||||
- **`superh`**: Enables the SuperH backend powered by an included disassembler.
|
||||
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "analyzeDataFlow",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"name": "(Experimental) Perform data flow analysis",
|
||||
"description": "Use data flow analysis to display known information about register contents where possible"
|
||||
},
|
||||
{
|
||||
"id": "showDataFlow",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"name": "Show data flow",
|
||||
"description": "Show data flow analysis results in place of register name where present"
|
||||
},
|
||||
{
|
||||
"id": "spaceBetweenArgs",
|
||||
"type": "boolean",
|
||||
@@ -264,7 +278,8 @@
|
||||
"id": "ppc",
|
||||
"name": "PowerPC",
|
||||
"properties": [
|
||||
"ppc.calculatePoolRelocations"
|
||||
"ppc.calculatePoolRelocations",
|
||||
"analyzeDataFlow"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -60,10 +60,10 @@ pub struct ConfigGroup {
|
||||
}
|
||||
|
||||
fn build_doc(name: &str, description: Option<&str>) -> TokenStream {
|
||||
let mut doc = format!(" {}", name);
|
||||
let mut doc = format!(" {name}");
|
||||
let mut out = quote! { #[doc = #doc] };
|
||||
if let Some(description) = description {
|
||||
doc = format!(" {}", description);
|
||||
doc = format!(" {description}");
|
||||
out.extend(quote! { #[doc = ""] });
|
||||
out.extend(quote! { #[doc = #doc] });
|
||||
}
|
||||
@@ -443,9 +443,9 @@ pub fn generate_diff_config() {
|
||||
}
|
||||
impl core::fmt::Display for ConfigPropertyValue {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
ConfigPropertyValue::Boolean(value) => write!(f, "{}", value),
|
||||
ConfigPropertyValue::Choice(value) => write!(f, "{}", value),
|
||||
match *self {
|
||||
ConfigPropertyValue::Boolean(value) => write!(f, "{value}"),
|
||||
ConfigPropertyValue::Choice(value) => f.write_str(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, el
|
||||
use unarm::{args, arm, thumb};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart},
|
||||
obj::{
|
||||
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
|
||||
@@ -225,7 +225,7 @@ impl Arch for ArchArm {
|
||||
|
||||
let mut address = start_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
|
||||
mode = next.mapping;
|
||||
next_mapping = mappings_iter.next();
|
||||
@@ -356,47 +356,57 @@ impl Arch for ArchArm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn relocation_override(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
let section_data = section.data()?;
|
||||
let address = address as usize;
|
||||
Ok(match flags {
|
||||
// ARM calls
|
||||
RelocationFlags::Elf(elf::R_ARM_PC24)
|
||||
| RelocationFlags::Elf(elf::R_ARM_XPC25)
|
||||
| RelocationFlags::Elf(elf::R_ARM_CALL) => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
let addend = self.endianness.read_i32_bytes(data);
|
||||
let imm24 = addend & 0xffffff;
|
||||
(imm24 << 2) << 8 >> 8
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
match relocation.flags() {
|
||||
// Handle ELF implicit relocations
|
||||
object::RelocationFlags::Elf { r_type } => {
|
||||
if relocation.has_implicit_addend() {
|
||||
let section_data = section.data()?;
|
||||
let address = address as usize;
|
||||
let addend = match r_type {
|
||||
// ARM calls
|
||||
elf::R_ARM_PC24 | elf::R_ARM_XPC25 | elf::R_ARM_CALL => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
let addend = self.endianness.read_i32_bytes(data);
|
||||
let imm24 = addend & 0xffffff;
|
||||
(imm24 << 2) << 8 >> 8
|
||||
}
|
||||
|
||||
// Thumb calls
|
||||
elf::R_ARM_THM_PC22 | elf::R_ARM_THM_XPC22 => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let high = self.endianness.read_i16_bytes(data) as i32;
|
||||
let data = section_data[address + 2..address + 4].try_into()?;
|
||||
let low = self.endianness.read_i16_bytes(data) as i32;
|
||||
|
||||
let imm22 = ((high & 0x7ff) << 11) | (low & 0x7ff);
|
||||
(imm22 << 1) << 9 >> 9
|
||||
}
|
||||
|
||||
// Data
|
||||
elf::R_ARM_ABS32 => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
self.endianness.read_i32_bytes(data)
|
||||
}
|
||||
|
||||
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
||||
};
|
||||
Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Keep,
|
||||
addend: addend as i64,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Thumb calls
|
||||
RelocationFlags::Elf(elf::R_ARM_THM_PC22)
|
||||
| RelocationFlags::Elf(elf::R_ARM_THM_XPC22) => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let high = self.endianness.read_i16_bytes(data) as i32;
|
||||
let data = section_data[address + 2..address + 4].try_into()?;
|
||||
let low = self.endianness.read_i16_bytes(data) as i32;
|
||||
|
||||
let imm22 = ((high & 0x7ff) << 11) | (low & 0x7ff);
|
||||
(imm22 << 1) << 9 >> 9
|
||||
}
|
||||
|
||||
// Data
|
||||
RelocationFlags::Elf(elf::R_ARM_ABS32) => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
self.endianness.read_i32_bytes(data)
|
||||
}
|
||||
|
||||
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
||||
} as i64)
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
@@ -575,7 +585,7 @@ fn push_args(
|
||||
arg_cb(InstructionPart::basic("}"))?;
|
||||
}
|
||||
args::Argument::CoprocNum(value) => {
|
||||
arg_cb(InstructionPart::opaque(format!("p{}", value)))?;
|
||||
arg_cb(InstructionPart::opaque(format!("p{value}")))?;
|
||||
}
|
||||
args::Argument::ShiftImm(shift) => {
|
||||
arg_cb(InstructionPart::opaque(shift.op.to_string()))?;
|
||||
|
||||
@@ -5,7 +5,7 @@ use alloc::{
|
||||
};
|
||||
use core::cmp::Ordering;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use anyhow::Result;
|
||||
use object::elf;
|
||||
use yaxpeax_arch::{Arch as YaxpeaxArch, Decoder, Reader, U8Reader};
|
||||
use yaxpeax_arm::armv8::a64::{
|
||||
@@ -108,17 +108,6 @@ impl Arch for ArchArm64 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
bail!("Unsupported ARM64 implicit relocation {:#x}:{:?}", address, flags)
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
cpp_demangle::Symbol::new(name)
|
||||
.ok()
|
||||
@@ -2268,7 +2257,7 @@ where Cb: FnMut(InstructionPart<'static>) {
|
||||
push_plain(args, "]");
|
||||
push_separator(args);
|
||||
// TODO does 31 have to be handled separate?
|
||||
args(InstructionPart::opaque(format!("x{}", offset_reg)));
|
||||
args(InstructionPart::opaque(format!("x{offset_reg}")));
|
||||
}
|
||||
// Fall back to original logic
|
||||
Operand::SIMDRegister(_, _)
|
||||
|
||||
@@ -7,14 +7,11 @@ use alloc::{
|
||||
use anyhow::{Result, bail};
|
||||
use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, elf};
|
||||
use rabbitizer::{
|
||||
IsaExtension, IsaVersion, Vram,
|
||||
abi::Abi,
|
||||
operands::{IU16, ValuedOperand},
|
||||
registers_meta::Register,
|
||||
IsaExtension, IsaVersion, Vram, abi::Abi, operands::ValuedOperand, registers_meta::Register,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
||||
obj::{
|
||||
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
||||
@@ -225,53 +222,67 @@ impl Arch for ArchMips {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn relocation_override(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
reloc: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||
if let RelocationFlags::Elf(elf::R_MIPS_HI16 | elf::R_MIPS_LO16) = flags {
|
||||
if let Some(addend) = self
|
||||
.paired_relocations
|
||||
.get(section.index().0)
|
||||
.and_then(|m| m.get(&address).copied())
|
||||
{
|
||||
return Ok(addend);
|
||||
}
|
||||
}
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
match relocation.flags() {
|
||||
// Handle ELF implicit relocations
|
||||
object::RelocationFlags::Elf { r_type } => {
|
||||
if relocation.has_implicit_addend() {
|
||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||
if let elf::R_MIPS_HI16 | elf::R_MIPS_LO16 = r_type {
|
||||
if let Some(addend) = self
|
||||
.paired_relocations
|
||||
.get(section.index().0)
|
||||
.and_then(|m| m.get(&address).copied())
|
||||
{
|
||||
return Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Keep,
|
||||
addend,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
let data = section.data()?;
|
||||
let code = data[address as usize..address as usize + 4].try_into()?;
|
||||
let addend = self.endianness.read_u32_bytes(code);
|
||||
Ok(match flags {
|
||||
RelocationFlags::Elf(elf::R_MIPS_32) => addend as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_26) => ((addend & 0x03FFFFFF) << 2) as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_HI16) => ((addend & 0x0000FFFF) << 16) as i32 as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16) => {
|
||||
(addend & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL) => {
|
||||
let object::RelocationTarget::Symbol(idx) = reloc.target() else {
|
||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||
};
|
||||
let sym = file.symbol_by_index(idx)?;
|
||||
let data = section.data()?;
|
||||
let code = self
|
||||
.endianness
|
||||
.read_u32_bytes(data[address as usize..address as usize + 4].try_into()?);
|
||||
let addend = match r_type {
|
||||
elf::R_MIPS_32 => code as i64,
|
||||
elf::R_MIPS_26 => ((code & 0x03FFFFFF) << 2) as i64,
|
||||
elf::R_MIPS_HI16 => ((code & 0x0000FFFF) << 16) as i32 as i64,
|
||||
elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16 => {
|
||||
(code & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL => {
|
||||
let object::RelocationTarget::Symbol(idx) = relocation.target() else {
|
||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||
};
|
||||
let sym = file.symbol_by_index(idx)?;
|
||||
|
||||
// if the symbol we are relocating against is in a local section we need to add
|
||||
// the ri_gp_value from .reginfo to the addend.
|
||||
if sym.section().index().is_some() {
|
||||
((addend & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||
// if the symbol we are relocating against is in a local section we need to add
|
||||
// the ri_gp_value from .reginfo to the addend.
|
||||
if sym.section().index().is_some() {
|
||||
((code & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||
} else {
|
||||
(code & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
}
|
||||
elf::R_MIPS_PC16 => 0, // PC-relative relocation
|
||||
R_MIPS15_S3 => ((code & 0x001FFFC0) >> 3) as i64,
|
||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||
};
|
||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||
} else {
|
||||
(addend & 0x0000FFFF) as i16 as i64
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_MIPS_PC16) => 0, // PC-relative relocation
|
||||
RelocationFlags::Elf(R_MIPS15_S3) => ((addend & 0x001FFFC0) >> 3) as i64,
|
||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||
})
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
@@ -335,14 +346,18 @@ fn push_args(
|
||||
}
|
||||
|
||||
match op {
|
||||
ValuedOperand::core_immediate(imm) => {
|
||||
ValuedOperand::core_imm_i16(imm) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(match imm {
|
||||
IU16::Integer(s) => InstructionPart::signed(s),
|
||||
IU16::Unsigned(u) => InstructionPart::unsigned(u),
|
||||
})?;
|
||||
arg_cb(InstructionPart::signed(imm))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_imm_u16(imm) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(InstructionPart::unsigned(imm))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_label(..) | ValuedOperand::core_branch_target_label(..) => {
|
||||
@@ -359,14 +374,13 @@ fn push_args(
|
||||
))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_immediate_base(imm, base) => {
|
||||
ValuedOperand::core_imm_rs(imm, base) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(InstructionPart::Arg(InstructionArg::Value(match imm {
|
||||
IU16::Integer(s) => InstructionArgValue::Signed(s as i64),
|
||||
IU16::Unsigned(u) => InstructionArgValue::Unsigned(u as u64),
|
||||
})))?;
|
||||
arg_cb(InstructionPart::Arg(InstructionArg::Value(
|
||||
InstructionArgValue::Signed(imm as i64),
|
||||
)))?;
|
||||
}
|
||||
arg_cb(InstructionPart::basic("("))?;
|
||||
arg_cb(InstructionPart::opaque(base.either_name(
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
|
||||
use core::{ffi::CStr, fmt, fmt::Debug};
|
||||
use alloc::{
|
||||
borrow::Cow,
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{
|
||||
ffi::CStr,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use encoding_rs::SHIFT_JIS;
|
||||
@@ -11,8 +20,9 @@ use crate::{
|
||||
display::{ContextItem, HoverItem, InstructionPart},
|
||||
},
|
||||
obj::{
|
||||
InstructionArg, InstructionRef, Object, ParsedInstruction, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedSymbol, Section, Symbol, SymbolFlagSet, SymbolKind,
|
||||
FlowAnalysisResult, InstructionArg, InstructionRef, Object, ParsedInstruction, Relocation,
|
||||
RelocationFlags, ResolvedInstructionRef, ResolvedSymbol, Section, Symbol, SymbolFlagSet,
|
||||
SymbolKind,
|
||||
},
|
||||
util::ReallySigned,
|
||||
};
|
||||
@@ -31,6 +41,7 @@ pub mod superh;
|
||||
pub mod x86;
|
||||
|
||||
/// Represents the type of data associated with an instruction
|
||||
#[derive(PartialEq)]
|
||||
pub enum DataType {
|
||||
Int8,
|
||||
Int16,
|
||||
@@ -44,16 +55,16 @@ pub enum DataType {
|
||||
|
||||
impl fmt::Display for DataType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DataType::Int8 => write!(f, "Int8"),
|
||||
DataType::Int16 => write!(f, "Int16"),
|
||||
DataType::Int32 => write!(f, "Int32"),
|
||||
DataType::Int64 => write!(f, "Int64"),
|
||||
DataType::Float => write!(f, "Float"),
|
||||
DataType::Double => write!(f, "Double"),
|
||||
DataType::Bytes => write!(f, "Bytes"),
|
||||
DataType::String => write!(f, "String"),
|
||||
}
|
||||
f.write_str(match self {
|
||||
DataType::Int8 => "Int8",
|
||||
DataType::Int16 => "Int16",
|
||||
DataType::Int32 => "Int32",
|
||||
DataType::Int64 => "Int64",
|
||||
DataType::Float => "Float",
|
||||
DataType::Double => "Double",
|
||||
DataType::Bytes => "Bytes",
|
||||
DataType::String => "String",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +72,8 @@ impl DataType {
|
||||
pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> {
|
||||
let mut strs = Vec::new();
|
||||
for (literal, label_override) in self.display_literals(endian, bytes) {
|
||||
let label = label_override.unwrap_or_else(|| format!("{}", self));
|
||||
strs.push(format!("{}: {}", label, literal))
|
||||
let label = label_override.unwrap_or_else(|| self.to_string());
|
||||
strs.push(format!("{label}: {literal}"))
|
||||
}
|
||||
strs
|
||||
}
|
||||
@@ -95,7 +106,7 @@ impl DataType {
|
||||
match self {
|
||||
DataType::Int8 => {
|
||||
let i = i8::from_ne_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -103,7 +114,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int16 => {
|
||||
let i = endian.read_i16_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -111,7 +122,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int32 => {
|
||||
let i = endian.read_i32_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -119,7 +130,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let i = endian.read_i64_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -146,16 +157,16 @@ impl DataType {
|
||||
));
|
||||
}
|
||||
DataType::Bytes => {
|
||||
strs.push((format!("{:#?}", bytes), None));
|
||||
strs.push((format!("{bytes:#?}"), None));
|
||||
}
|
||||
DataType::String => {
|
||||
if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) {
|
||||
strs.push((format!("{:?}", cstr), None));
|
||||
strs.push((format!("{cstr:?}"), None));
|
||||
}
|
||||
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
|
||||
let (cow, _, had_errors) = SHIFT_JIS.decode(&bytes[..nul_idx]);
|
||||
if !had_errors {
|
||||
let str = format!("{:?}", cow);
|
||||
let str = format!("{cow:?}");
|
||||
// Only add the Shift JIS string if it's different from the ASCII string.
|
||||
if !strs.iter().any(|x| x.0 == str) {
|
||||
strs.push((str, Some("Shift JIS".into())));
|
||||
@@ -335,14 +346,26 @@ pub trait Arch: Send + Sync + Debug {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
// Perform detailed data flow analysis
|
||||
fn data_flow_analysis(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64>;
|
||||
_obj: &Object,
|
||||
_symbol: &Symbol,
|
||||
_code: &[u8],
|
||||
_relocations: &[Relocation],
|
||||
) -> Option<Box<dyn FlowAnalysisResult>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn relocation_override(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
_address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn demangle(&self, _name: &str) -> Option<String> { None }
|
||||
|
||||
@@ -389,7 +412,9 @@ pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
||||
use object::Object as _;
|
||||
Ok(match object.architecture() {
|
||||
#[cfg(feature = "ppc")]
|
||||
object::Architecture::PowerPc => Box::new(ppc::ArchPpc::new(object)?),
|
||||
object::Architecture::PowerPc | object::Architecture::PowerPc64 => {
|
||||
Box::new(ppc::ArchPpc::new(object)?)
|
||||
}
|
||||
#[cfg(feature = "mips")]
|
||||
object::Architecture::Mips => Box::new(mips::ArchMips::new(object)?),
|
||||
#[cfg(feature = "x86")]
|
||||
@@ -434,16 +459,17 @@ impl Arch for ArchDummy {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
_address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
_flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn data_reloc_size(&self, _flags: RelocationFlags) -> usize { 0 }
|
||||
}
|
||||
|
||||
pub enum RelocationOverrideTarget {
|
||||
Keep,
|
||||
Skip,
|
||||
Symbol(object::SymbolIndex),
|
||||
Section(object::SectionIndex),
|
||||
}
|
||||
|
||||
pub struct RelocationOverride {
|
||||
pub target: RelocationOverrideTarget,
|
||||
pub addend: i64,
|
||||
}
|
||||
|
||||
651
objdiff-core/src/arch/ppc/flow_analysis.rs
Normal file
651
objdiff-core/src/arch/ppc/flow_analysis.rs
Normal file
@@ -0,0 +1,651 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{
|
||||
ffi::CStr,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
use powerpc::{Extensions, Simm};
|
||||
|
||||
use crate::{
|
||||
arch::DataType,
|
||||
obj::{FlowAnalysisResult, FlowAnalysisValue, Object, Relocation, Symbol},
|
||||
util::{RawDouble, RawFloat},
|
||||
};
|
||||
|
||||
fn is_store_instruction(op: powerpc::Opcode) -> bool {
|
||||
use powerpc::Opcode;
|
||||
matches!(
|
||||
op,
|
||||
Opcode::Stbux
|
||||
| Opcode::Stbx
|
||||
| Opcode::Stfdux
|
||||
| Opcode::Stfdx
|
||||
| Opcode::Stfiwx
|
||||
| Opcode::Stfsux
|
||||
| Opcode::Stfsx
|
||||
| Opcode::Sthbrx
|
||||
| Opcode::Sthux
|
||||
| Opcode::Sthx
|
||||
| Opcode::Stswi
|
||||
| Opcode::Stswx
|
||||
| Opcode::Stwbrx
|
||||
| Opcode::Stwcx_
|
||||
| Opcode::Stwux
|
||||
| Opcode::Stwx
|
||||
| Opcode::Stwu
|
||||
| Opcode::Stb
|
||||
| Opcode::Stbu
|
||||
| Opcode::Sth
|
||||
| Opcode::Sthu
|
||||
| Opcode::Stmw
|
||||
| Opcode::Stfs
|
||||
| Opcode::Stfsu
|
||||
| Opcode::Stfd
|
||||
| Opcode::Stfdu
|
||||
)
|
||||
}
|
||||
|
||||
pub fn guess_data_type_from_load_store_inst_op(inst_op: powerpc::Opcode) -> Option<DataType> {
|
||||
use powerpc::Opcode;
|
||||
match inst_op {
|
||||
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
|
||||
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
|
||||
Opcode::Lha | Opcode::Lhau | Opcode::Lhaux | Opcode::Lhax => Some(DataType::Int16),
|
||||
Opcode::Lwz | Opcode::Lwzu | Opcode::Lwzux | Opcode::Lwzx => Some(DataType::Int32),
|
||||
Opcode::Lfs | Opcode::Lfsu | Opcode::Lfsux | Opcode::Lfsx => Some(DataType::Float),
|
||||
Opcode::Lfd | Opcode::Lfdu | Opcode::Lfdux | Opcode::Lfdx => Some(DataType::Double),
|
||||
|
||||
Opcode::Stb | Opcode::Stbu | Opcode::Stbux | Opcode::Stbx => Some(DataType::Int8),
|
||||
Opcode::Sth | Opcode::Sthu | Opcode::Sthux | Opcode::Sthx => Some(DataType::Int16),
|
||||
Opcode::Stw | Opcode::Stwu | Opcode::Stwux | Opcode::Stwx => Some(DataType::Int32),
|
||||
Opcode::Stfs | Opcode::Stfsu | Opcode::Stfsux | Opcode::Stfsx => Some(DataType::Float),
|
||||
Opcode::Stfd | Opcode::Stfdu | Opcode::Stfdux | Opcode::Stfdx => Some(DataType::Double),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord)]
|
||||
enum RegisterContent {
|
||||
#[default]
|
||||
Unknown,
|
||||
Variable, // Multiple potential values
|
||||
FloatConstant(RawFloat),
|
||||
DoubleConstant(RawDouble),
|
||||
IntConstant(i32),
|
||||
InputRegister(u8),
|
||||
Symbol(usize),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for RegisterContent {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
RegisterContent::Unknown => write!(f, "unknown"),
|
||||
RegisterContent::Variable => write!(f, "variable"),
|
||||
RegisterContent::IntConstant(i) =>
|
||||
// -i is safe because it's at most a 16 bit constant in the i32
|
||||
{
|
||||
if *i >= 0 {
|
||||
write!(f, "0x{i:x}")
|
||||
} else {
|
||||
write!(f, "-0x{:x}", -i)
|
||||
}
|
||||
}
|
||||
RegisterContent::FloatConstant(RawFloat(fp)) => write!(f, "{fp:?}f"),
|
||||
RegisterContent::DoubleConstant(RawDouble(fp)) => write!(f, "{fp:?}d"),
|
||||
RegisterContent::InputRegister(p) => write!(f, "input{p}"),
|
||||
RegisterContent::Symbol(_u) => write!(f, "relocation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||
struct RegisterState {
|
||||
gpr: [RegisterContent; 32],
|
||||
fpr: [RegisterContent; 32],
|
||||
}
|
||||
|
||||
impl RegisterState {
|
||||
fn new() -> Self {
|
||||
RegisterState { gpr: [RegisterContent::Unknown; 32], fpr: [RegisterContent::Unknown; 32] }
|
||||
}
|
||||
|
||||
// During a function call, these registers must be assumed trashed.
|
||||
fn clear_volatile(&mut self) {
|
||||
self[powerpc::GPR(0)] = RegisterContent::Unknown;
|
||||
for i in 0..=13 {
|
||||
self[powerpc::GPR(i)] = RegisterContent::Unknown;
|
||||
}
|
||||
for i in 0..=13 {
|
||||
self[powerpc::FPR(i)] = RegisterContent::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark potential input values.
|
||||
// Subsequent flow analysis will "realize" that they are not actually inputs if
|
||||
// they get overwritten with another value before getting read.
|
||||
fn set_potential_inputs(&mut self) {
|
||||
for g_reg in 3..=13 {
|
||||
self[powerpc::GPR(g_reg)] = RegisterContent::InputRegister(g_reg);
|
||||
}
|
||||
for f_reg in 1..=13 {
|
||||
self[powerpc::FPR(f_reg)] = RegisterContent::InputRegister(f_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// If the there is no value, we can take the new known value.
|
||||
// If there's a known value different than the new value, the content
|
||||
// must is variable.
|
||||
// Returns whether the current value was updated.
|
||||
fn unify_values(current: &mut RegisterContent, new: &RegisterContent) -> bool {
|
||||
if *current == *new {
|
||||
false
|
||||
} else if *current == RegisterContent::Unknown {
|
||||
*current = *new;
|
||||
true
|
||||
} else if *current == RegisterContent::Variable {
|
||||
// Already variable
|
||||
false
|
||||
} else {
|
||||
*current = RegisterContent::Variable;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// Unify currently known register contents in a give situation with new
|
||||
// information about the register contents in that situation.
|
||||
// Currently unknown register contents can be filled, but if there are
|
||||
// conflicting contents, we go back to unknown.
|
||||
fn unify(&mut self, other: &RegisterState) -> bool {
|
||||
let mut updated = false;
|
||||
for i in 0..32 {
|
||||
updated |= Self::unify_values(&mut self.gpr[i], &other.gpr[i]);
|
||||
updated |= Self::unify_values(&mut self.fpr[i], &other.fpr[i]);
|
||||
}
|
||||
updated
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<powerpc::GPR> for RegisterState {
|
||||
type Output = RegisterContent;
|
||||
|
||||
fn index(&self, gpr: powerpc::GPR) -> &Self::Output { &self.gpr[gpr.0 as usize] }
|
||||
}
|
||||
impl IndexMut<powerpc::GPR> for RegisterState {
|
||||
fn index_mut(&mut self, gpr: powerpc::GPR) -> &mut Self::Output {
|
||||
&mut self.gpr[gpr.0 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<powerpc::FPR> for RegisterState {
|
||||
type Output = RegisterContent;
|
||||
|
||||
fn index(&self, fpr: powerpc::FPR) -> &Self::Output { &self.fpr[fpr.0 as usize] }
|
||||
}
|
||||
impl IndexMut<powerpc::FPR> for RegisterState {
|
||||
fn index_mut(&mut self, fpr: powerpc::FPR) -> &mut Self::Output {
|
||||
&mut self.fpr[fpr.0 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_instruction(
|
||||
registers: &mut RegisterState,
|
||||
op: &powerpc::Opcode,
|
||||
args: &powerpc::Arguments,
|
||||
) {
|
||||
use powerpc::{Argument, GPR, Opcode};
|
||||
match (op, args[0], args[1], args[2]) {
|
||||
(Opcode::Or, Argument::GPR(a), Argument::GPR(b), Argument::GPR(c)) => {
|
||||
// Move is implemented as or with self for ints
|
||||
if b == c {
|
||||
registers[a] = registers[b];
|
||||
} else {
|
||||
registers[a] = RegisterContent::Unknown;
|
||||
}
|
||||
}
|
||||
(Opcode::Fmr, Argument::FPR(a), Argument::FPR(b), _) => {
|
||||
registers[a] = registers[b];
|
||||
}
|
||||
(Opcode::Addi, Argument::GPR(a), Argument::GPR(GPR(0)), Argument::Simm(c)) => {
|
||||
// Load immidiate implemented as addi with addend = r0
|
||||
// Let Addi with other addends fall through to the case which
|
||||
// overwrites the destination
|
||||
registers[a] = RegisterContent::IntConstant(c.0 as i32);
|
||||
}
|
||||
(Opcode::Bcctr, _, _, _) => {
|
||||
// Called a function pointer, may have erased volatile registers
|
||||
registers.clear_volatile();
|
||||
}
|
||||
(Opcode::B, _, _, _) => {
|
||||
if get_branch_offset(args) == 0 {
|
||||
// Call to another function
|
||||
registers.clear_volatile();
|
||||
}
|
||||
}
|
||||
(
|
||||
Opcode::Stbu | Opcode::Sthu | Opcode::Stwu | Opcode::Stfsu | Opcode::Stfdu,
|
||||
_,
|
||||
_,
|
||||
Argument::GPR(rel),
|
||||
) => {
|
||||
// Storing with update, clear updated register (third arg)
|
||||
registers[rel] = RegisterContent::Unknown;
|
||||
}
|
||||
(
|
||||
Opcode::Stbux | Opcode::Sthux | Opcode::Stwux | Opcode::Stfsux | Opcode::Stfdux,
|
||||
_,
|
||||
Argument::GPR(rel),
|
||||
_,
|
||||
) => {
|
||||
// Storing indexed with update, clear updated register (second arg)
|
||||
registers[rel] = RegisterContent::Unknown;
|
||||
}
|
||||
(Opcode::Lmw, Argument::GPR(target), _, _) => {
|
||||
// `lmw` overwrites all registers from rd to r31.
|
||||
for reg in target.0..31 {
|
||||
registers[GPR(reg)] = RegisterContent::Unknown;
|
||||
}
|
||||
}
|
||||
(_, Argument::GPR(a), _, _) => {
|
||||
// Store instructions don't modify the GPR
|
||||
if !is_store_instruction(*op) {
|
||||
// Other operations which write to GPR a
|
||||
registers[a] = RegisterContent::Unknown;
|
||||
}
|
||||
}
|
||||
(_, Argument::FPR(a), _, _) => {
|
||||
// Store instructions don't modify the FPR
|
||||
if !is_store_instruction(*op) {
|
||||
// Other operations which write to FPR a
|
||||
registers[a] = RegisterContent::Unknown;
|
||||
}
|
||||
}
|
||||
(_, _, _, _) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_branch_offset(args: &powerpc::Arguments) -> i32 {
|
||||
for arg in args.iter() {
|
||||
match arg {
|
||||
powerpc::Argument::BranchDest(dest) => return dest.0 / 4,
|
||||
powerpc::Argument::None => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct PPCFlowAnalysisResult {
|
||||
argument_contents: BTreeMap<(u64, u8), FlowAnalysisValue>,
|
||||
}
|
||||
|
||||
impl PPCFlowAnalysisResult {
|
||||
fn set_argument_value_at_address(
|
||||
&mut self,
|
||||
address: u64,
|
||||
argument: u8,
|
||||
value: FlowAnalysisValue,
|
||||
) {
|
||||
self.argument_contents.insert((address, argument), value);
|
||||
}
|
||||
|
||||
fn new() -> Self { PPCFlowAnalysisResult { argument_contents: Default::default() } }
|
||||
}
|
||||
|
||||
impl FlowAnalysisResult for PPCFlowAnalysisResult {
|
||||
fn get_argument_value_at_address(
|
||||
&self,
|
||||
address: u64,
|
||||
argument: u8,
|
||||
) -> Option<&FlowAnalysisValue> {
|
||||
self.argument_contents.get(&(address, argument))
|
||||
}
|
||||
}
|
||||
|
||||
fn clamp_text_length(s: String, max: usize) -> String {
|
||||
if s.len() <= max { s } else { format!("{}…", s.chars().take(max - 3).collect::<String>()) }
|
||||
}
|
||||
|
||||
fn get_register_content_from_reloc(
|
||||
reloc: &Relocation,
|
||||
obj: &Object,
|
||||
op: powerpc::Opcode,
|
||||
) -> RegisterContent {
|
||||
if let Some(bytes) = obj.symbol_data(reloc.target_symbol) {
|
||||
match guess_data_type_from_load_store_inst_op(op) {
|
||||
Some(DataType::Float) => {
|
||||
RegisterContent::FloatConstant(RawFloat(match obj.endianness {
|
||||
object::Endianness::Little => {
|
||||
f32::from_le_bytes(bytes.try_into().unwrap_or([0; 4]))
|
||||
}
|
||||
object::Endianness::Big => {
|
||||
f32::from_be_bytes(bytes.try_into().unwrap_or([0; 4]))
|
||||
}
|
||||
}))
|
||||
}
|
||||
Some(DataType::Double) => {
|
||||
RegisterContent::DoubleConstant(RawDouble(match obj.endianness {
|
||||
object::Endianness::Little => {
|
||||
f64::from_le_bytes(bytes.try_into().unwrap_or([0; 8]))
|
||||
}
|
||||
object::Endianness::Big => {
|
||||
f64::from_be_bytes(bytes.try_into().unwrap_or([0; 8]))
|
||||
}
|
||||
}))
|
||||
}
|
||||
_ => RegisterContent::Symbol(reloc.target_symbol),
|
||||
}
|
||||
} else {
|
||||
RegisterContent::Symbol(reloc.target_symbol)
|
||||
}
|
||||
}
|
||||
|
||||
// Executing op with args at cur_address, update current_state with symbols that
|
||||
// come from relocations. That is, references to globals, floating point
|
||||
// constants, string constants, etc.
|
||||
fn fill_registers_from_relocation(
|
||||
reloc: &Relocation,
|
||||
current_state: &mut RegisterState,
|
||||
obj: &Object,
|
||||
op: powerpc::Opcode,
|
||||
args: &powerpc::Arguments,
|
||||
) {
|
||||
// Only update the register state for loads. We may store to a reloc
|
||||
// address but that doesn't update register contents.
|
||||
if !is_store_instruction(op) {
|
||||
match (op, args[0]) {
|
||||
// Everything else is a load of some sort
|
||||
(_, powerpc::Argument::GPR(gpr)) => {
|
||||
current_state[gpr] = get_register_content_from_reloc(reloc, obj, op);
|
||||
}
|
||||
(_, powerpc::Argument::FPR(fpr)) => {
|
||||
current_state[fpr] = get_register_content_from_reloc(reloc, obj, op);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special helper fragments generated by MWCC.
|
||||
// See: https://github.com/encounter/decomp-toolkit/blob/main/src/analysis/pass.rs
|
||||
const SLEDS: [&str; 6] = ["_savefpr_", "_restfpr_", "_savegpr_", "_restgpr_", "_savev", "_restv"];
|
||||
|
||||
fn is_sled_function(name: &str) -> bool { SLEDS.iter().any(|sled| name.starts_with(sled)) }
|
||||
|
||||
pub fn ppc_data_flow_analysis(
|
||||
obj: &Object,
|
||||
func_symbol: &Symbol,
|
||||
code: &[u8],
|
||||
relocations: &[Relocation],
|
||||
extensions: Extensions,
|
||||
) -> Box<dyn FlowAnalysisResult> {
|
||||
use alloc::collections::VecDeque;
|
||||
|
||||
use powerpc::InsIter;
|
||||
let instructions = InsIter::new(code, func_symbol.address as u32, extensions)
|
||||
.map(|(_addr, ins)| (ins.op, ins.basic().args))
|
||||
.collect_vec();
|
||||
|
||||
let func_address = func_symbol.address;
|
||||
|
||||
// Get initial register values from function parameters
|
||||
let mut initial_register_state = RegisterState::new();
|
||||
initial_register_state.set_potential_inputs();
|
||||
|
||||
let mut execution_queue = VecDeque::<(usize, RegisterState)>::new();
|
||||
execution_queue.push_back((0, initial_register_state));
|
||||
|
||||
// Execute the instructions against abstract data
|
||||
let mut failsafe_counter = 0;
|
||||
let mut taken_branches = BTreeSet::<(usize, RegisterState)>::new();
|
||||
let mut register_state_at = Vec::<RegisterState>::new();
|
||||
let mut completed_first_pass = false;
|
||||
register_state_at.resize_with(instructions.len(), RegisterState::new);
|
||||
while let Some((mut index, mut current_state)) = execution_queue.pop_front() {
|
||||
while let Some((op, args)) = instructions.get(index) {
|
||||
// Record the state at this index
|
||||
// If recording does not result in any changes to the known values
|
||||
// we're done, because the subsequent values are a function of the
|
||||
// current values so we'll get the same result as the last time
|
||||
// we went down this path.
|
||||
// Don't break out if we haven't even completed the first pass
|
||||
// through the function though.
|
||||
if !register_state_at[index].unify(¤t_state) && completed_first_pass {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get symbol used in this instruction
|
||||
let cur_addr = (func_address as u32) + ((index * 4) as u32);
|
||||
let reloc = relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||
|
||||
// Is this a branch to a compiler generated helper? These helpers
|
||||
// do not trash registers like normal function calls, so we don't
|
||||
// want to treat this as normal execution.
|
||||
let symbol = reloc.and_then(|r| obj.symbols.get(r.target_symbol));
|
||||
let is_sled_invocation = symbol.is_some_and(|x| is_sled_function(&x.name));
|
||||
|
||||
// Execute the instruction to update the state
|
||||
// Since sled invocations are only used to save / restore registers
|
||||
// as part of prelude / cleanup in a function call we don't have to
|
||||
// do any execution for them.
|
||||
if !is_sled_invocation {
|
||||
execute_instruction(&mut current_state, op, args);
|
||||
}
|
||||
|
||||
// Fill in register state coming from relocations at this line. This
|
||||
// handles references to global variables, floating point constants,
|
||||
// etc.
|
||||
if let Some(reloc) = reloc {
|
||||
fill_registers_from_relocation(reloc, &mut current_state, obj, *op, args);
|
||||
}
|
||||
|
||||
// Add conditional branches to execution queue
|
||||
// Only take a given (address, register state) combination once. If
|
||||
// the known register state is different we have to take the branch
|
||||
// again to stabilize the known values for backwards branches.
|
||||
if op == &powerpc::Opcode::Bc {
|
||||
let branch_state = (index, current_state.clone());
|
||||
if !taken_branches.contains(&branch_state) {
|
||||
let offset = get_branch_offset(args);
|
||||
let target_index = ((index as i32) + offset) as usize;
|
||||
execution_queue.push_back((target_index, current_state.clone()));
|
||||
taken_branches.insert(branch_state);
|
||||
|
||||
// We should never hit this case, but avoid getting stuck in
|
||||
// an infinite loop if we hit some kind of bad behavior.
|
||||
failsafe_counter += 1;
|
||||
if failsafe_counter > 256 {
|
||||
//println!("Analysis of {} failed to stabilize", func_symbol.name);
|
||||
return Box::new(PPCFlowAnalysisResult::new());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update index
|
||||
if op == &powerpc::Opcode::B {
|
||||
// Unconditional branch
|
||||
let offset = get_branch_offset(args);
|
||||
if offset > 0 {
|
||||
// Jump table or branch to over else clause.
|
||||
index += offset as usize;
|
||||
} else if offset == 0 {
|
||||
// Function call with relocation. We'll return to
|
||||
// the next instruction.
|
||||
index += 1;
|
||||
} else {
|
||||
// Unconditional branch (E.g.: loop { ... })
|
||||
// Also some compilations of loops put the conditional at
|
||||
// the end and B to it for the check of the first iteration.
|
||||
let branch_state = (index, current_state.clone());
|
||||
if taken_branches.contains(&branch_state) {
|
||||
break;
|
||||
}
|
||||
taken_branches.insert(branch_state);
|
||||
index = ((index as i32) + offset) as usize;
|
||||
}
|
||||
} else {
|
||||
// Normal execution of next instruction
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark that we've completed at least one pass over the function, at
|
||||
// this point we can break out if the code we're running doesn't change
|
||||
// any register outcomes.
|
||||
completed_first_pass = true;
|
||||
}
|
||||
|
||||
// Store the relevant data flow values for simplified instructions
|
||||
generate_flow_analysis_result(
|
||||
obj,
|
||||
func_address,
|
||||
code,
|
||||
register_state_at,
|
||||
relocations,
|
||||
extensions,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_string_data(obj: &Object, symbol_index: usize, offset: Simm) -> Option<&str> {
|
||||
if let Some(sym) = obj.symbols.get(symbol_index) {
|
||||
if sym.name.starts_with("@stringBase") && offset.0 != 0 {
|
||||
if let Some(data) = obj.symbol_data(symbol_index) {
|
||||
let bytes = &data[offset.0 as usize..];
|
||||
if let Ok(Ok(str)) = CStr::from_bytes_until_nul(bytes).map(|x| x.to_str()) {
|
||||
return Some(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// Write the relevant part of the flow analysis out into the FlowAnalysisResult
|
||||
// the rest of the application will use to query results of the flow analysis.
|
||||
// Flow analysis will compute the known contents of every register at every
|
||||
// line, but we only need to record the values of registers that are actually
|
||||
// referenced at each line.
|
||||
fn generate_flow_analysis_result(
|
||||
obj: &Object,
|
||||
base_address: u64,
|
||||
code: &[u8],
|
||||
register_state_at: Vec<RegisterState>,
|
||||
relocations: &[Relocation],
|
||||
extensions: Extensions,
|
||||
) -> Box<PPCFlowAnalysisResult> {
|
||||
use powerpc::{Argument, InsIter};
|
||||
let mut analysis_result = PPCFlowAnalysisResult::new();
|
||||
let default_register_state = RegisterState::new();
|
||||
for (addr, ins) in InsIter::new(code, 0, extensions) {
|
||||
let ins_address = base_address + (addr as u64);
|
||||
let index = addr / 4;
|
||||
let powerpc::ParsedIns { mnemonic: _, args } = ins.simplified();
|
||||
|
||||
// If we're already showing relocations on a line don't also show data flow
|
||||
let reloc = relocations.iter().find(|r| (r.address & !3) == ins_address);
|
||||
|
||||
// Special case to show float and double constants on the line where
|
||||
// they are being loaded.
|
||||
// We need to do this before we break out on showing relocations in the
|
||||
// subsequent if statement.
|
||||
if let (powerpc::Opcode::Lfs | powerpc::Opcode::Lfd, Some(reloc)) = (ins.op, reloc) {
|
||||
let content = get_register_content_from_reloc(reloc, obj, ins.op);
|
||||
if matches!(
|
||||
content,
|
||||
RegisterContent::FloatConstant(_) | RegisterContent::DoubleConstant(_)
|
||||
) {
|
||||
analysis_result.set_argument_value_at_address(
|
||||
ins_address,
|
||||
1,
|
||||
FlowAnalysisValue::Text(content.to_string()),
|
||||
);
|
||||
|
||||
// Don't need to show any other data flow if we're showing that
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Special case to show string constants on the line where they are
|
||||
// being indexed to. This will typically be "addi t, stringbase, offset"
|
||||
let registers = register_state_at.get(index as usize).unwrap_or(&default_register_state);
|
||||
if let (powerpc::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
|
||||
(ins.op, args[1], args[2])
|
||||
{
|
||||
if let RegisterContent::Symbol(sym_index) = registers[rel] {
|
||||
if let Some(str) = get_string_data(obj, sym_index, offset) {
|
||||
// Show the string constant in the analysis result
|
||||
let formatted = format!("\"{str}\"");
|
||||
analysis_result.set_argument_value_at_address(
|
||||
ins_address,
|
||||
2,
|
||||
FlowAnalysisValue::Text(clamp_text_length(formatted, 20)),
|
||||
);
|
||||
// Don't continue, we want to show the stringbase value as well
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let is_store = is_store_instruction(ins.op);
|
||||
for (arg_index, arg) in args.into_iter().enumerate() {
|
||||
// Hacky shorthand for determining which arguments are sources,
|
||||
// We only want to show data flow for source registers, not target
|
||||
// registers. Technically there are some non-"st_" operations which
|
||||
// read from their first argument but they're rare.
|
||||
if (arg_index == 0) && !is_store {
|
||||
continue;
|
||||
}
|
||||
|
||||
let content = match arg {
|
||||
Argument::GPR(gpr) => Some(registers[gpr]),
|
||||
Argument::FPR(fpr) => Some(registers[fpr]),
|
||||
_ => None,
|
||||
};
|
||||
let analysis_value = match content {
|
||||
Some(RegisterContent::Symbol(s)) => {
|
||||
if reloc.is_none() {
|
||||
// Only symbols if there isn't already a relocation, because
|
||||
// code other than the data flow analysis will be showing
|
||||
// the symbol for a relocation on the line it is for. If we
|
||||
// also showed it as data flow analysis value we would be
|
||||
// showing redundant information.
|
||||
obj.symbols.get(s).map(|sym| {
|
||||
FlowAnalysisValue::Text(clamp_text_length(
|
||||
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone(),
|
||||
20,
|
||||
))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(RegisterContent::InputRegister(reg)) => {
|
||||
let reg_name = match arg {
|
||||
Argument::GPR(_) => format!("in_r{reg}"),
|
||||
Argument::FPR(_) => format!("in_f{reg}"),
|
||||
_ => panic!("Register content should only be in a register"),
|
||||
};
|
||||
Some(FlowAnalysisValue::Text(reg_name))
|
||||
}
|
||||
Some(RegisterContent::Unknown) | Some(RegisterContent::Variable) => None,
|
||||
Some(value) => Some(FlowAnalysisValue::Text(value.to_string())),
|
||||
None => None,
|
||||
};
|
||||
if let Some(analysis_value) = analysis_value {
|
||||
analysis_result.set_argument_value_at_address(
|
||||
ins_address,
|
||||
arg_index as u8,
|
||||
analysis_value,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(analysis_result)
|
||||
}
|
||||
@@ -1,81 +1,106 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use anyhow::{Result, bail, ensure};
|
||||
use anyhow::{Result, anyhow, bail, ensure};
|
||||
use cwextab::{ExceptionTableData, decode_extab};
|
||||
use flagset::Flags;
|
||||
use object::{Object as _, ObjectSection as _, ObjectSymbol as _, elf};
|
||||
use object::{Object as _, ObjectSection as _, ObjectSymbol as _, elf, pe};
|
||||
|
||||
use crate::{
|
||||
arch::{Arch, DataType},
|
||||
arch::{Arch, DataType, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{
|
||||
DiffObjConfig,
|
||||
data::resolve_relocation,
|
||||
display::{ContextItem, HoverItem, HoverItemColor, InstructionPart, SymbolNavigationKind},
|
||||
},
|
||||
obj::{
|
||||
InstructionRef, Object, Relocation, RelocationFlags, ResolvedInstructionRef,
|
||||
ResolvedRelocation, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
FlowAnalysisResult, InstructionRef, Object, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedRelocation, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
},
|
||||
};
|
||||
|
||||
mod flow_analysis;
|
||||
|
||||
// Relative relocation, can be Simm, Offset or BranchDest
|
||||
fn is_relative_arg(arg: &ppc750cl::Argument) -> bool {
|
||||
fn is_relative_arg(arg: &powerpc::Argument) -> bool {
|
||||
matches!(
|
||||
arg,
|
||||
ppc750cl::Argument::Simm(_)
|
||||
| ppc750cl::Argument::Offset(_)
|
||||
| ppc750cl::Argument::BranchDest(_)
|
||||
powerpc::Argument::Simm(_)
|
||||
| powerpc::Argument::Offset(_)
|
||||
| powerpc::Argument::BranchDest(_)
|
||||
)
|
||||
}
|
||||
|
||||
// Relative or absolute relocation, can be Uimm, Simm or Offset
|
||||
fn is_rel_abs_arg(arg: &ppc750cl::Argument) -> bool {
|
||||
fn is_rel_abs_arg(arg: &powerpc::Argument) -> bool {
|
||||
matches!(
|
||||
arg,
|
||||
ppc750cl::Argument::Uimm(_) | ppc750cl::Argument::Simm(_) | ppc750cl::Argument::Offset(_)
|
||||
powerpc::Argument::Uimm(_) | powerpc::Argument::Simm(_) | powerpc::Argument::Offset(_)
|
||||
)
|
||||
}
|
||||
|
||||
fn is_offset_arg(arg: &ppc750cl::Argument) -> bool { matches!(arg, ppc750cl::Argument::Offset(_)) }
|
||||
fn is_offset_arg(arg: &powerpc::Argument) -> bool { matches!(arg, powerpc::Argument::Offset(_)) }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArchPpc {
|
||||
pub extensions: powerpc::Extensions,
|
||||
/// Exception info
|
||||
pub extab: Option<BTreeMap<usize, ExceptionInfo>>,
|
||||
}
|
||||
|
||||
impl ArchPpc {
|
||||
pub fn new(file: &object::File) -> Result<Self> {
|
||||
Ok(Self { extab: decode_exception_info(file)? })
|
||||
let extensions = match file.flags() {
|
||||
object::FileFlags::Coff { .. } => powerpc::Extensions::xenon(),
|
||||
object::FileFlags::Elf { e_flags, .. }
|
||||
if (e_flags & elf::EF_PPC_EMB) == elf::EF_PPC_EMB =>
|
||||
{
|
||||
powerpc::Extensions::gekko_broadway()
|
||||
}
|
||||
_ => {
|
||||
if file.is_64() {
|
||||
powerpc::Extension::Ppc64 | powerpc::Extension::AltiVec
|
||||
} else {
|
||||
powerpc::Extension::AltiVec.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
let extab = decode_exception_info(file)?;
|
||||
Ok(Self { extensions, extab })
|
||||
}
|
||||
|
||||
fn parse_ins_ref(&self, resolved: ResolvedInstructionRef) -> Result<ppc750cl::Ins> {
|
||||
fn parse_ins_ref(&self, resolved: ResolvedInstructionRef) -> Result<powerpc::Ins> {
|
||||
let mut code = u32::from_be_bytes(resolved.code.try_into()?);
|
||||
if let Some(reloc) = resolved.relocation {
|
||||
code = zero_reloc(code, reloc.relocation);
|
||||
}
|
||||
let op = ppc750cl::Opcode::from(resolved.ins_ref.opcode as u8);
|
||||
Ok(ppc750cl::Ins { code, op })
|
||||
let op = powerpc::Opcode::from(resolved.ins_ref.opcode);
|
||||
Ok(powerpc::Ins { code, op })
|
||||
}
|
||||
|
||||
fn find_reloc_arg(
|
||||
&self,
|
||||
ins: &ppc750cl::ParsedIns,
|
||||
ins: &powerpc::ParsedIns,
|
||||
resolved: Option<ResolvedRelocation>,
|
||||
) -> Option<usize> {
|
||||
match resolved?.relocation.flags {
|
||||
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => Some(1),
|
||||
RelocationFlags::Elf(elf::R_PPC_REL24 | elf::R_PPC_REL14) => {
|
||||
RelocationFlags::Elf(elf::R_PPC_REL24 | elf::R_PPC_REL14)
|
||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL24 | pe::IMAGE_REL_PPC_REL14) => {
|
||||
ins.args.iter().rposition(is_relative_arg)
|
||||
}
|
||||
RelocationFlags::Elf(
|
||||
elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
|
||||
) => ins.args.iter().rposition(is_rel_abs_arg),
|
||||
)
|
||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
|
||||
ins.args.iter().rposition(is_rel_abs_arg)
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC64_TOC16) => ins.args.iter().rposition(is_offset_arg),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -93,11 +118,11 @@ impl Arch for ArchPpc {
|
||||
ensure!(code.len() & 3 == 0, "Code length must be a multiple of 4");
|
||||
let ins_count = code.len() / 4;
|
||||
let mut insts = Vec::<InstructionRef>::with_capacity(ins_count);
|
||||
for (cur_addr, ins) in ppc750cl::InsIter::new(code, address as u32) {
|
||||
for (cur_addr, ins) in powerpc::InsIter::new(code, address as u32, self.extensions) {
|
||||
insts.push(InstructionRef {
|
||||
address: cur_addr as u64,
|
||||
size: 4,
|
||||
opcode: u8::from(ins.op) as u16,
|
||||
opcode: u16::from(ins.op),
|
||||
branch_dest: ins.branch_dest(cur_addr).map(u64::from),
|
||||
});
|
||||
}
|
||||
@@ -128,16 +153,16 @@ impl Arch for ArchPpc {
|
||||
// For @sda21, we can omit the register argument
|
||||
if matches!(reloc.relocation.flags, RelocationFlags::Elf(elf::R_PPC_EMB_SDA21))
|
||||
// Sanity check: the next argument should be r0
|
||||
&& matches!(ins.args.get(idx + 1), Some(ppc750cl::Argument::GPR(ppc750cl::GPR(0))))
|
||||
&& matches!(ins.args.get(idx + 1), Some(powerpc::Argument::GPR(powerpc::GPR(0))))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
match arg {
|
||||
ppc750cl::Argument::Simm(simm) => cb(InstructionPart::signed(simm.0)),
|
||||
ppc750cl::Argument::Uimm(uimm) => cb(InstructionPart::unsigned(uimm.0)),
|
||||
ppc750cl::Argument::Offset(offset) => cb(InstructionPart::signed(offset.0)),
|
||||
ppc750cl::Argument::BranchDest(dest) => cb(InstructionPart::branch_dest(
|
||||
powerpc::Argument::Simm(simm) => cb(InstructionPart::signed(simm.0)),
|
||||
powerpc::Argument::Uimm(uimm) => cb(InstructionPart::unsigned(uimm.0)),
|
||||
powerpc::Argument::Offset(offset) => cb(InstructionPart::signed(offset.0)),
|
||||
powerpc::Argument::BranchDest(dest) => cb(InstructionPart::branch_dest(
|
||||
(resolved.ins_ref.address as u32).wrapping_add_signed(dest.0),
|
||||
)),
|
||||
_ => cb(InstructionPart::opaque(arg.to_string())),
|
||||
@@ -157,6 +182,7 @@ impl Arch for ArchPpc {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Could be replaced by data_flow_analysis once that feature stabilizes
|
||||
fn generate_pooled_relocations(
|
||||
&self,
|
||||
address: u64,
|
||||
@@ -164,22 +190,125 @@ impl Arch for ArchPpc {
|
||||
relocations: &[Relocation],
|
||||
symbols: &[Symbol],
|
||||
) -> Vec<Relocation> {
|
||||
generate_fake_pool_relocations_for_function(address, code, relocations, symbols)
|
||||
generate_fake_pool_relocations_for_function(
|
||||
address,
|
||||
code,
|
||||
relocations,
|
||||
symbols,
|
||||
self.extensions,
|
||||
)
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn data_flow_analysis(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
bail!("Unsupported PPC implicit relocation {:#x}:{:?}", address, flags)
|
||||
obj: &Object,
|
||||
symbol: &Symbol,
|
||||
code: &[u8],
|
||||
relocations: &[Relocation],
|
||||
) -> Option<Box<dyn FlowAnalysisResult>> {
|
||||
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations, self.extensions))
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
cwdemangle::demangle(name, &cwdemangle::DemangleOptions::default())
|
||||
fn relocation_override(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
match relocation.flags() {
|
||||
// IMAGE_REL_PPC_PAIR contains the REF{HI,LO} displacement instead of a symbol index
|
||||
object::RelocationFlags::Coff {
|
||||
typ: pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO,
|
||||
} => section
|
||||
.relocations()
|
||||
.skip_while(|&(a, _)| a < address)
|
||||
.take_while(|&(a, _)| a == address)
|
||||
.find(|(_, reloc)| {
|
||||
matches!(reloc.flags(), object::RelocationFlags::Coff {
|
||||
typ: pe::IMAGE_REL_PPC_PAIR
|
||||
})
|
||||
})
|
||||
.map_or(Ok(None), |(_, reloc)| match reloc.target() {
|
||||
object::RelocationTarget::Symbol(index) => Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Keep,
|
||||
addend: index.0 as u16 as i16 as i64,
|
||||
})),
|
||||
target => Err(anyhow!("Unsupported IMAGE_REL_PPC_PAIR target {target:?}")),
|
||||
}),
|
||||
// Skip PAIR relocations as they are handled by the previous case
|
||||
object::RelocationFlags::Coff { typ: pe::IMAGE_REL_PPC_PAIR } => {
|
||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Skip, addend: 0 }))
|
||||
}
|
||||
// Any other COFF relocation has an addend of 0
|
||||
object::RelocationFlags::Coff { .. } => {
|
||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend: 0 }))
|
||||
}
|
||||
// Handle ELF implicit relocations
|
||||
flags @ object::RelocationFlags::Elf { r_type } => {
|
||||
ensure!(
|
||||
!relocation.has_implicit_addend(),
|
||||
"Unsupported implicit relocation {:?}",
|
||||
flags
|
||||
);
|
||||
match r_type {
|
||||
elf::R_PPC64_TOC16 => {
|
||||
let offset = u64::try_from(relocation.addend())
|
||||
.map_err(|_| anyhow!("Negative addend for R_PPC64_TOC16 relocation"))?;
|
||||
let Some(toc_section) = file.section_by_name(".toc") else {
|
||||
bail!("Missing .toc section for R_PPC64_TOC16 relocation");
|
||||
};
|
||||
// If TOC target is a relocation, replace it with the target symbol
|
||||
let Some((_, toc_relocation)) =
|
||||
toc_section.relocations().find(|&(a, _)| a == offset)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
if toc_relocation.has_implicit_addend() {
|
||||
log::warn!(
|
||||
"Unsupported implicit addend for R_PPC64_TOC16 relocation: {toc_relocation:?}"
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
let addend = toc_relocation.addend();
|
||||
match toc_relocation.target() {
|
||||
object::RelocationTarget::Symbol(symbol_index) => {
|
||||
Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Symbol(symbol_index),
|
||||
addend,
|
||||
}))
|
||||
}
|
||||
object::RelocationTarget::Section(section_index) => {
|
||||
Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Section(section_index),
|
||||
addend,
|
||||
}))
|
||||
}
|
||||
target => {
|
||||
log::warn!(
|
||||
"Unsupported R_PPC64_TOC16 relocation target {target:?}"
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn demangle(&self, mut name: &str) -> Option<String> {
|
||||
if name.starts_with('?') {
|
||||
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
|
||||
} else {
|
||||
name = name.trim_start_matches('.');
|
||||
cpp_demangle::Symbol::new(name)
|
||||
.ok()
|
||||
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
||||
.or_else(|| cwdemangle::demangle(name, &cwdemangle::DemangleOptions::default()))
|
||||
}
|
||||
}
|
||||
|
||||
fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> {
|
||||
@@ -194,9 +323,18 @@ impl Arch for ArchPpc {
|
||||
elf::R_PPC_UADDR32 => Some("R_PPC_UADDR32"),
|
||||
elf::R_PPC_REL24 => Some("R_PPC_REL24"),
|
||||
elf::R_PPC_REL14 => Some("R_PPC_REL14"),
|
||||
elf::R_PPC64_TOC16 => Some("R_PPC64_TOC16"),
|
||||
_ => None,
|
||||
},
|
||||
RelocationFlags::Coff(r_type) => match r_type {
|
||||
pe::IMAGE_REL_PPC_ADDR32 => Some("IMAGE_REL_PPC_ADDR32"),
|
||||
pe::IMAGE_REL_PPC_REFHI => Some("IMAGE_REL_PPC_REFHI"),
|
||||
pe::IMAGE_REL_PPC_REFLO => Some("IMAGE_REL_PPC_REFLO"),
|
||||
pe::IMAGE_REL_PPC_REL24 => Some("IMAGE_REL_PPC_REL24"),
|
||||
pe::IMAGE_REL_PPC_REL14 => Some("IMAGE_REL_PPC_REL14"),
|
||||
pe::IMAGE_REL_PPC_PAIR => Some("IMAGE_REL_PPC_PAIR"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,8 +362,8 @@ impl Arch for ArchPpc {
|
||||
// Pooled string.
|
||||
return Some(DataType::String);
|
||||
}
|
||||
let opcode = ppc750cl::Opcode::from(resolved.ins_ref.opcode as u8);
|
||||
if let Some(ty) = guess_data_type_from_load_store_inst_op(opcode) {
|
||||
let opcode = powerpc::Opcode::from(resolved.ins_ref.opcode);
|
||||
if let Some(ty) = flow_analysis::guess_data_type_from_load_store_inst_op(opcode) {
|
||||
// Numeric type.
|
||||
return Some(ty);
|
||||
}
|
||||
@@ -322,11 +460,18 @@ impl ArchPpc {
|
||||
fn zero_reloc(code: u32, reloc: &Relocation) -> u32 {
|
||||
match reloc.flags {
|
||||
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => code & !0x1FFFFF,
|
||||
RelocationFlags::Elf(elf::R_PPC_REL24) => code & !0x3FFFFFC,
|
||||
RelocationFlags::Elf(elf::R_PPC_REL14) => code & !0xFFFC,
|
||||
RelocationFlags::Elf(elf::R_PPC_REL24) | RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL24) => {
|
||||
code & !0x3FFFFFC
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC_REL14) | RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL14) => {
|
||||
code & !0xFFFC
|
||||
}
|
||||
RelocationFlags::Elf(
|
||||
elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
|
||||
) => code & !0xFFFF,
|
||||
)
|
||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
|
||||
code & !0xFFFF
|
||||
}
|
||||
_ => code,
|
||||
}
|
||||
}
|
||||
@@ -336,34 +481,38 @@ fn display_reloc(
|
||||
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
match resolved.relocation.flags {
|
||||
RelocationFlags::Elf(r_type) => match r_type {
|
||||
elf::R_PPC_ADDR16_LO => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@l"))?;
|
||||
}
|
||||
elf::R_PPC_ADDR16_HI => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@h"))?;
|
||||
}
|
||||
elf::R_PPC_ADDR16_HA => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@ha"))?;
|
||||
}
|
||||
elf::R_PPC_EMB_SDA21 => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@sda21"))?;
|
||||
}
|
||||
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14 => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
}
|
||||
elf::R_PPC_NONE => {
|
||||
// Fake pool relocation.
|
||||
cb(InstructionPart::basic("<"))?;
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic(">"))?;
|
||||
}
|
||||
_ => cb(InstructionPart::reloc())?,
|
||||
},
|
||||
RelocationFlags::Elf(elf::R_PPC_ADDR16_LO)
|
||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFLO) => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@l"))?;
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC_ADDR16_HI)
|
||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI) => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@h"))?;
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC_ADDR16_HA) => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@ha"))?;
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic("@sda21"))?;
|
||||
}
|
||||
RelocationFlags::Elf(
|
||||
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14,
|
||||
)
|
||||
| RelocationFlags::Coff(
|
||||
pe::IMAGE_REL_PPC_ADDR32 | pe::IMAGE_REL_PPC_REL24 | pe::IMAGE_REL_PPC_REL14,
|
||||
) => {
|
||||
cb(InstructionPart::reloc())?;
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_PPC_NONE) => {
|
||||
// Fake pool relocation.
|
||||
cb(InstructionPart::basic("<"))?;
|
||||
cb(InstructionPart::reloc())?;
|
||||
cb(InstructionPart::basic(">"))?;
|
||||
}
|
||||
_ => cb(InstructionPart::reloc())?,
|
||||
};
|
||||
Ok(())
|
||||
@@ -447,16 +596,14 @@ fn decode_exception_info(
|
||||
|
||||
// Decode the extab data
|
||||
let Some(extab_data) = extab_section.data_range(extab_start_addr, extab.size())? else {
|
||||
log::warn!("Failed to get extab data for function {}", extab_func_name);
|
||||
log::warn!("Failed to get extab data for function {extab_func_name}");
|
||||
continue;
|
||||
};
|
||||
let data = match decode_extab(extab_data) {
|
||||
Ok(decoded_data) => decoded_data,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
"Exception table decoding failed for function {}, reason: {}",
|
||||
extab_func_name,
|
||||
e
|
||||
"Exception table decoding failed for function {extab_func_name}, reason: {e}"
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -501,42 +648,23 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
|
||||
Ok(ExtabSymbolRef { original_index: symbol.index().0 - 1, name, demangled_name })
|
||||
}
|
||||
|
||||
fn guess_data_type_from_load_store_inst_op(inst_op: ppc750cl::Opcode) -> Option<DataType> {
|
||||
use ppc750cl::Opcode;
|
||||
match inst_op {
|
||||
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
|
||||
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
|
||||
Opcode::Lha | Opcode::Lhau | Opcode::Lhaux | Opcode::Lhax => Some(DataType::Int16),
|
||||
Opcode::Lwz | Opcode::Lwzu | Opcode::Lwzux | Opcode::Lwzx => Some(DataType::Int32),
|
||||
Opcode::Lfs | Opcode::Lfsu | Opcode::Lfsux | Opcode::Lfsx => Some(DataType::Float),
|
||||
Opcode::Lfd | Opcode::Lfdu | Opcode::Lfdux | Opcode::Lfdx => Some(DataType::Double),
|
||||
|
||||
Opcode::Stb | Opcode::Stbu | Opcode::Stbux | Opcode::Stbx => Some(DataType::Int8),
|
||||
Opcode::Sth | Opcode::Sthu | Opcode::Sthux | Opcode::Sthx => Some(DataType::Int16),
|
||||
Opcode::Stw | Opcode::Stwu | Opcode::Stwux | Opcode::Stwx => Some(DataType::Int32),
|
||||
Opcode::Stfs | Opcode::Stfsu | Opcode::Stfsux | Opcode::Stfsx => Some(DataType::Float),
|
||||
Opcode::Stfd | Opcode::Stfdu | Opcode::Stfdux | Opcode::Stfdx => Some(DataType::Double),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PoolReference {
|
||||
addr_src_gpr: ppc750cl::GPR,
|
||||
addr_src_gpr: powerpc::GPR,
|
||||
addr_offset: i16,
|
||||
addr_dst_gpr: Option<ppc750cl::GPR>,
|
||||
addr_dst_gpr: Option<powerpc::GPR>,
|
||||
}
|
||||
|
||||
// Given an instruction, check if it could be accessing pooled data at the address in a register.
|
||||
// If so, return information pertaining to where the instruction is getting that address from and
|
||||
// what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
|
||||
fn get_pool_reference_for_inst(
|
||||
opcode: ppc750cl::Opcode,
|
||||
simplified: &ppc750cl::ParsedIns,
|
||||
opcode: powerpc::Opcode,
|
||||
simplified: &powerpc::ParsedIns,
|
||||
) -> Option<PoolReference> {
|
||||
use ppc750cl::{Argument, Opcode};
|
||||
use powerpc::{Argument, Opcode};
|
||||
let args = &simplified.args;
|
||||
if guess_data_type_from_load_store_inst_op(opcode).is_some() {
|
||||
if flow_analysis::guess_data_type_from_load_store_inst_op(opcode).is_some() {
|
||||
match (args[1], args[2]) {
|
||||
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
|
||||
// e.g. lwz. Immediate offset.
|
||||
@@ -599,15 +727,15 @@ fn get_pool_reference_for_inst(
|
||||
|
||||
// Remove the relocation we're keeping track of in a particular register when an instruction reuses
|
||||
// that register to hold some other value, unrelated to pool relocation addresses.
|
||||
fn clear_overwritten_gprs(ins: ppc750cl::Ins, gpr_pool_relocs: &mut BTreeMap<u8, Relocation>) {
|
||||
use ppc750cl::{Argument, Arguments, Opcode};
|
||||
fn clear_overwritten_gprs(ins: powerpc::Ins, gpr_pool_relocs: &mut BTreeMap<u8, Relocation>) {
|
||||
use powerpc::{Argument, Arguments, Opcode};
|
||||
let mut def_args = Arguments::default();
|
||||
ins.parse_defs(&mut def_args);
|
||||
for arg in def_args {
|
||||
if let Argument::GPR(gpr) = arg {
|
||||
if ins.op == Opcode::Lmw {
|
||||
// `lmw` overwrites all registers from rd to r31.
|
||||
// ppc750cl only returns rd itself, so we manually clear the rest of them.
|
||||
// powerpc only returns rd itself, so we manually clear the rest of them.
|
||||
for reg in gpr.0..31 {
|
||||
gpr_pool_relocs.remove(®);
|
||||
}
|
||||
@@ -640,6 +768,8 @@ fn make_fake_pool_reloc(
|
||||
target_symbol = symbols.iter().position(|s| {
|
||||
s.section == Some(section_index)
|
||||
&& s.size > 0
|
||||
&& !s.flags.contains(SymbolFlag::Hidden)
|
||||
&& !s.flags.contains(SymbolFlag::Ignored)
|
||||
&& (s.address..s.address + s.size).contains(&target_address)
|
||||
})?;
|
||||
addend = target_address.checked_sub(symbols[target_symbol].address)? as i64;
|
||||
@@ -668,7 +798,7 @@ fn make_fake_pool_reloc(
|
||||
// and returns a Vec of "fake pool relocations" that simulate what a relocation for that instruction
|
||||
// would look like if data hadn't been pooled.
|
||||
// This method tries to follow the function's proper control flow. It keeps track of a queue of
|
||||
// states it hasn't traversed yet, where each state holds an instruction address and a HashMap of
|
||||
// states it hasn't traversed yet, where each state holds an instruction address and a map of
|
||||
// which registers hold which pool relocations at that point.
|
||||
// When a conditional or unconditional branch is encountered, the destination of the branch is added
|
||||
// to the queue. Conditional branches will traverse both the path where the branch is taken and the
|
||||
@@ -687,12 +817,13 @@ fn generate_fake_pool_relocations_for_function(
|
||||
code: &[u8],
|
||||
relocations: &[Relocation],
|
||||
symbols: &[Symbol],
|
||||
extensions: powerpc::Extensions,
|
||||
) -> Vec<Relocation> {
|
||||
use ppc750cl::{Argument, InsIter, Opcode};
|
||||
use powerpc::{Argument, InsIter, Opcode};
|
||||
let mut visited_ins_addrs = BTreeSet::new();
|
||||
let mut pool_reloc_for_addr = BTreeMap::new();
|
||||
let mut ins_iters_with_gpr_state =
|
||||
vec![(InsIter::new(code, func_address as u32), BTreeMap::new())];
|
||||
vec![(InsIter::new(code, func_address as u32, extensions), BTreeMap::new())];
|
||||
let mut gpr_state_at_bctr = BTreeMap::new();
|
||||
while let Some((ins_iter, mut gpr_pool_relocs)) = ins_iters_with_gpr_state.pop() {
|
||||
for (cur_addr, ins) in ins_iter {
|
||||
@@ -724,7 +855,7 @@ fn generate_fake_pool_relocations_for_function(
|
||||
// Conditional branch.
|
||||
// Add the branch destination to the queue to do later.
|
||||
ins_iters_with_gpr_state.push((
|
||||
InsIter::new(dest_code_slice, branch_dest),
|
||||
InsIter::new(dest_code_slice, branch_dest, extensions),
|
||||
gpr_pool_relocs.clone(),
|
||||
));
|
||||
// Then continue on with the current iterator.
|
||||
@@ -734,7 +865,7 @@ fn generate_fake_pool_relocations_for_function(
|
||||
// Unconditional branch.
|
||||
// Add the branch destination to the queue.
|
||||
ins_iters_with_gpr_state.push((
|
||||
InsIter::new(dest_code_slice, branch_dest),
|
||||
InsIter::new(dest_code_slice, branch_dest, extensions),
|
||||
gpr_pool_relocs.clone(),
|
||||
));
|
||||
// Break out of the current iterator so we can do the newly added one.
|
||||
@@ -842,7 +973,7 @@ fn generate_fake_pool_relocations_for_function(
|
||||
let dest_offset_into_func = unseen_addr - func_address as u32;
|
||||
let dest_code_slice = &code[dest_offset_into_func as usize..];
|
||||
ins_iters_with_gpr_state.push((
|
||||
InsIter::new(dest_code_slice, unseen_addr),
|
||||
InsIter::new(dest_code_slice, unseen_addr, extensions),
|
||||
gpr_pool_relocs.clone(),
|
||||
));
|
||||
break;
|
||||
@@ -197,7 +197,7 @@ fn match_ni_f(
|
||||
}
|
||||
_ => {
|
||||
parts.push(InstructionPart::basic(".word 0x"));
|
||||
parts.push(InstructionPart::basic(format!("{:04X}", op)));
|
||||
parts.push(InstructionPart::basic(format!("{op:04X}")));
|
||||
parts.push(InstructionPart::basic(" /* unknown instruction */"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloc::{collections::BTreeMap, format, string::String, vec, vec::Vec};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use anyhow::Result;
|
||||
use object::elf;
|
||||
|
||||
use crate::{
|
||||
@@ -109,7 +109,7 @@ impl Arch for ArchSuperH {
|
||||
);
|
||||
parts.push(InstructionPart::basic(" /* "));
|
||||
parts.push(InstructionPart::basic("0x"));
|
||||
parts.push(InstructionPart::basic(format!("{:04X}", data)));
|
||||
parts.push(InstructionPart::basic(format!("{data:04X}")));
|
||||
parts.push(InstructionPart::basic(" */"));
|
||||
} else if value.size == 4 && value.address as usize + 3 < symbol_data.len() {
|
||||
let data = u32::from_be_bytes(
|
||||
@@ -119,7 +119,7 @@ impl Arch for ArchSuperH {
|
||||
);
|
||||
parts.push(InstructionPart::basic(" /* "));
|
||||
parts.push(InstructionPart::basic("0x"));
|
||||
parts.push(InstructionPart::basic(format!("{:08X}", data)));
|
||||
parts.push(InstructionPart::basic(format!("{data:08X}")));
|
||||
parts.push(InstructionPart::basic(" */"));
|
||||
}
|
||||
}
|
||||
@@ -132,17 +132,6 @@ impl Arch for ArchSuperH {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
bail!("Unsupported SuperH implicit relocation {:#x}:{:?}", address, flags)
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
cpp_demangle::Symbol::new(name)
|
||||
.ok()
|
||||
@@ -214,10 +203,10 @@ mod test {
|
||||
impl Display for InstructionPart<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InstructionPart::Basic(s) => write!(f, "{}", s),
|
||||
InstructionPart::Opcode(s, _o) => write!(f, "{} ", s),
|
||||
InstructionPart::Arg(arg) => write!(f, "{}", arg),
|
||||
InstructionPart::Separator => write!(f, ", "),
|
||||
InstructionPart::Basic(s) => f.write_str(s),
|
||||
InstructionPart::Opcode(s, _o) => write!(f, "{s} "),
|
||||
InstructionPart::Arg(arg) => write!(f, "{arg}"),
|
||||
InstructionPart::Separator => f.write_str(", "),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,9 +214,9 @@ mod test {
|
||||
impl Display for InstructionArg<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InstructionArg::Value(v) => write!(f, "{}", v),
|
||||
InstructionArg::BranchDest(v) => write!(f, "{}", v),
|
||||
InstructionArg::Reloc => write!(f, "reloc"),
|
||||
InstructionArg::Value(v) => write!(f, "{v}"),
|
||||
InstructionArg::BranchDest(v) => write!(f, "{v}"),
|
||||
InstructionArg::Reloc => f.write_str("reloc"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +253,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -342,7 +331,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -425,7 +414,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -462,7 +451,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -516,7 +505,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -557,7 +546,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -601,7 +590,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -645,7 +634,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -682,7 +671,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -716,7 +705,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -764,7 +753,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
@@ -814,7 +803,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||
let joined_str: String = parts.iter().map(<_>::to_string).collect();
|
||||
assert_eq!(joined_str, expected_str.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ use iced_x86::{
|
||||
Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter,
|
||||
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::{
|
||||
arch::Arch,
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{DiffObjConfig, X86Formatter, display::InstructionPart},
|
||||
obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef},
|
||||
};
|
||||
@@ -67,7 +67,11 @@ impl ArchX86 {
|
||||
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,
|
||||
},
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
@@ -75,7 +79,11 @@ impl ArchX86 {
|
||||
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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -217,37 +225,47 @@ impl Arch for ArchX86 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn relocation_override(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
match self.arch {
|
||||
Architecture::X86 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
if !relocation.has_implicit_addend() {
|
||||
return Ok(None);
|
||||
}
|
||||
let addend = match self.arch {
|
||||
Architecture::X86 => match relocation.flags() {
|
||||
object::RelocationFlags::Coff {
|
||||
typ: pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32,
|
||||
}
|
||||
| object::RelocationFlags::Elf { r_type: elf::R_386_32 | elf::R_386_PC32 } => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
self.endianness.read_i32_bytes(data) as i64
|
||||
}
|
||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32) => {
|
||||
Architecture::X86_64 => match relocation.flags() {
|
||||
object::RelocationFlags::Coff {
|
||||
typ: pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32,
|
||||
}
|
||||
| object::RelocationFlags::Elf { r_type: elf::R_X86_64_32 | elf::R_X86_64_PC32 } => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
self.endianness.read_i32_bytes(data) as i64
|
||||
}
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64) => {
|
||||
object::RelocationFlags::Coff { typ: pe::IMAGE_REL_AMD64_ADDR64 }
|
||||
| object::RelocationFlags::Elf { r_type: elf::R_X86_64_64 } => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 8].try_into()?;
|
||||
Ok(self.endianness.read_i64_bytes(data))
|
||||
self.endianness.read_i64_bytes(data)
|
||||
}
|
||||
flags => bail!("Unsupported x86-64 implicit relocation {flags:?}"),
|
||||
},
|
||||
}
|
||||
};
|
||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
|
||||
@@ -442,7 +442,7 @@ impl From<LegacyReportItem> for ReportItem {
|
||||
#[cfg(feature = "serde")]
|
||||
fn serialize_hex<S>(x: &Option<u64>, s: S) -> Result<S::Ok, S::Error>
|
||||
where S: serde::Serializer {
|
||||
if let Some(x) = x { s.serialize_str(&format!("{:#x}", x)) } else { s.serialize_none() }
|
||||
if let Some(x) = x { s.serialize_str(&format!("{x:#x}")) } else { s.serialize_none() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
||||
@@ -325,12 +325,11 @@ fn reloc_eq(
|
||||
|| display_ins_data_literals(left_obj, left_ins)
|
||||
== display_ins_data_literals(right_obj, right_ins))
|
||||
}
|
||||
(Some(_), None) => false,
|
||||
(None, Some(_)) => {
|
||||
// Match if possibly stripped weak symbol
|
||||
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)
|
||||
&& (symbol_name_addend_matches || address_eq(left, right))
|
||||
}
|
||||
(Some(_), None) => false,
|
||||
(None, Some(_)) => {
|
||||
// Match if possibly stripped weak symbol
|
||||
symbol_name_addend_matches && right.symbol.flags.contains(SymbolFlag::Weak)
|
||||
}
|
||||
(None, None) => symbol_name_addend_matches,
|
||||
(Some(_), None) | (None, None) => symbol_name_addend_matches,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ use regex::Regex;
|
||||
use crate::{
|
||||
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
|
||||
obj::{
|
||||
InstructionArg, InstructionArgValue, Object, ParsedInstruction, ResolvedInstructionRef,
|
||||
ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag, SymbolKind,
|
||||
FlowAnalysisValue, InstructionArg, InstructionArgValue, Object, ParsedInstruction,
|
||||
ResolvedInstructionRef, ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag,
|
||||
SymbolKind,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -47,11 +48,12 @@ pub enum DiffText<'a> {
|
||||
pub enum DiffTextColor {
|
||||
#[default]
|
||||
Normal, // Grey
|
||||
Dim, // Dark grey
|
||||
Bright, // White
|
||||
Replace, // Blue
|
||||
Delete, // Red
|
||||
Insert, // Green
|
||||
Dim, // Dark grey
|
||||
Bright, // White
|
||||
DataFlow, // Light blue
|
||||
Replace, // Blue
|
||||
Delete, // Red
|
||||
Insert, // Green
|
||||
Rotating(u8),
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ impl<'a> DiffTextSegment<'a> {
|
||||
const EOL_SEGMENT: DiffTextSegment<'static> =
|
||||
DiffTextSegment { text: DiffText::Eol, color: DiffTextColor::Normal, pad_to: 0 };
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub enum HighlightKind {
|
||||
#[default]
|
||||
None,
|
||||
@@ -186,6 +188,11 @@ pub fn display_row(
|
||||
}
|
||||
let mut arg_idx = 0;
|
||||
let mut displayed_relocation = false;
|
||||
let analysis_result = if diff_config.show_data_flow {
|
||||
obj.get_flow_analysis_result(resolved.symbol)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
obj.arch.display_instruction(resolved, diff_config, &mut |part| match part {
|
||||
InstructionPart::Basic(text) => {
|
||||
if text.chars().all(|c| c == ' ') {
|
||||
@@ -208,15 +215,30 @@ pub fn display_row(
|
||||
if arg == InstructionArg::Reloc {
|
||||
displayed_relocation = true;
|
||||
}
|
||||
match (arg, resolved.ins_ref.branch_dest) {
|
||||
(InstructionArg::Value(value), _) => cb(DiffTextSegment {
|
||||
text: DiffText::Argument(value),
|
||||
color: diff_index
|
||||
let data_flow_value =
|
||||
analysis_result.and_then(|result|
|
||||
result.get_argument_value_at_address(
|
||||
ins_ref.address, (arg_idx - 1) as u8));
|
||||
match (arg, data_flow_value, resolved.ins_ref.branch_dest) {
|
||||
// If we have a flow analysis result, always use that over anything else.
|
||||
(InstructionArg::Value(_) | InstructionArg::Reloc, Some(FlowAnalysisValue::Text(text)), _) => {
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::Argument(InstructionArgValue::Opaque(Cow::Borrowed(text))),
|
||||
color: DiffTextColor::DataFlow,
|
||||
pad_to: 0,
|
||||
})
|
||||
},
|
||||
(InstructionArg::Value(value), None, _) => {
|
||||
let color = diff_index
|
||||
.get()
|
||||
.map_or(base_color, |i| DiffTextColor::Rotating(i as u8)),
|
||||
pad_to: 0,
|
||||
}),
|
||||
(InstructionArg::Reloc, None) => {
|
||||
.map_or(base_color, |i| DiffTextColor::Rotating(i as u8));
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::Argument(value),
|
||||
color,
|
||||
pad_to: 0,
|
||||
})
|
||||
},
|
||||
(InstructionArg::Reloc, _, None) => {
|
||||
let resolved = resolved.relocation.unwrap();
|
||||
let color = diff_index
|
||||
.get()
|
||||
@@ -235,9 +257,9 @@ pub fn display_row(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(InstructionArg::BranchDest(dest), _) |
|
||||
(InstructionArg::BranchDest(dest), _, _) |
|
||||
// If the relocation was resolved to a branch destination, emit that instead.
|
||||
(InstructionArg::Reloc, Some(dest)) => {
|
||||
(InstructionArg::Reloc, _, Some(dest)) => {
|
||||
if let Some(addr) = dest.checked_sub(resolved.symbol.address) {
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::BranchDest(addr),
|
||||
@@ -288,6 +310,18 @@ pub fn display_row(
|
||||
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 {
|
||||
fn eq(&self, other: &DiffText) -> bool {
|
||||
match (self, other) {
|
||||
@@ -354,7 +388,7 @@ pub fn symbol_context(obj: &Object, symbol_index: usize) -> Vec<ContextItem> {
|
||||
if symbol.section.is_some() {
|
||||
if let Some(address) = symbol.virtual_address {
|
||||
out.push(ContextItem::Copy {
|
||||
value: format!("{:x}", address),
|
||||
value: format!("{address:x}"),
|
||||
label: Some("virtual address".to_string()),
|
||||
});
|
||||
}
|
||||
@@ -371,7 +405,7 @@ pub fn symbol_hover(
|
||||
) -> Vec<HoverItem> {
|
||||
let symbol = &obj.symbols[symbol_index];
|
||||
let addend_str = match addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:x}", addend),
|
||||
Ordering::Greater => format!("+{addend:x}"),
|
||||
Ordering::Less => format!("-{:x}", -addend),
|
||||
_ => String::new(),
|
||||
};
|
||||
@@ -422,7 +456,7 @@ pub fn symbol_hover(
|
||||
if let Some(address) = symbol.virtual_address {
|
||||
out.push(HoverItem::Text {
|
||||
label: "Virtual address".into(),
|
||||
value: format!("{:x}", address),
|
||||
value: format!("{address:x}"),
|
||||
color: override_color.clone().unwrap_or(HoverItemColor::Special),
|
||||
});
|
||||
}
|
||||
@@ -492,7 +526,7 @@ pub fn instruction_context(
|
||||
let mut out = Vec::new();
|
||||
let mut hex_string = String::new();
|
||||
for byte in resolved.code {
|
||||
hex_string.push_str(&format!("{:02x}", byte));
|
||||
hex_string.push_str(&format!("{byte:02x}"));
|
||||
}
|
||||
out.push(ContextItem::Copy { value: hex_string, label: Some("instruction bytes".to_string()) });
|
||||
out.append(&mut obj.arch.instruction_context(obj, resolved));
|
||||
@@ -575,7 +609,7 @@ pub fn instruction_hover(
|
||||
out.push(HoverItem::Separator);
|
||||
for (literal, label_override) in literals {
|
||||
out.push(HoverItem::Text {
|
||||
label: label_override.unwrap_or_else(|| format!("{}", ty)),
|
||||
label: label_override.unwrap_or_else(|| ty.to_string()),
|
||||
value: literal,
|
||||
color: HoverItemColor::Normal,
|
||||
});
|
||||
@@ -604,7 +638,9 @@ fn symbol_matches_filter(
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -341,11 +341,25 @@ pub fn diff_objs(
|
||||
if let (Some((right_obj, right_out)), Some((left_obj, left_out))) =
|
||||
(right.as_mut(), left.as_mut())
|
||||
{
|
||||
if let Some(right_name) = &mapping_config.selecting_left {
|
||||
generate_mapping_symbols(right_obj, right_name, left_obj, left_out, diff_config)?;
|
||||
if let Some(right_name) = mapping_config.selecting_left.as_deref() {
|
||||
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 {
|
||||
generate_mapping_symbols(left_obj, left_name, right_obj, right_out, diff_config)?;
|
||||
if let Some(left_name) = mapping_config.selecting_right.as_deref() {
|
||||
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
|
||||
/// 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.
|
||||
fn generate_mapping_symbols(
|
||||
base_obj: &Object,
|
||||
base_name: &str,
|
||||
target_obj: &Object,
|
||||
target_out: &mut ObjectDiff,
|
||||
left_obj: &Object,
|
||||
left_out: &mut ObjectDiff,
|
||||
right_obj: &Object,
|
||||
right_out: &mut ObjectDiff,
|
||||
mapping_symbol: MappingSymbol,
|
||||
config: &DiffObjConfig,
|
||||
) -> 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(());
|
||||
};
|
||||
let base_section_kind = symbol_section_kind(base_obj, &base_obj.symbols[base_symbol_ref]);
|
||||
@@ -377,32 +402,30 @@ fn generate_mapping_symbols(
|
||||
{
|
||||
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 => {
|
||||
let (left_diff, _right_diff) =
|
||||
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,
|
||||
});
|
||||
diff_code(left_obj, right_obj, left_symbol_idx, right_symbol_idx, config)
|
||||
}
|
||||
SectionKind::Data => {
|
||||
let (left_diff, _right_diff) =
|
||||
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,
|
||||
});
|
||||
diff_data_symbol(left_obj, right_obj, left_symbol_idx, right_symbol_idx)
|
||||
}
|
||||
SectionKind::Bss | SectionKind::Common => {
|
||||
let (left_diff, _right_diff) =
|
||||
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,
|
||||
});
|
||||
diff_bss_symbol(left_obj, right_obj, left_symbol_idx, right_symbol_idx)
|
||||
}
|
||||
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(())
|
||||
@@ -434,10 +457,6 @@ pub struct MappingConfig {
|
||||
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(
|
||||
left: &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
|
||||
// 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_symbol) = symbol_ref_by_name(left, left_name) {
|
||||
if let Some(left_symbol) = left.symbol_by_name(left_name) {
|
||||
left_used.insert(left_symbol);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply manual symbol 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;
|
||||
};
|
||||
if left_used.contains(&left_symbol_index) {
|
||||
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;
|
||||
};
|
||||
if right_used.contains(&right_symbol_index) {
|
||||
@@ -487,11 +506,7 @@ fn apply_symbol_mappings(
|
||||
.map_or(SectionKind::Unknown, |s| s.kind);
|
||||
if left_section_kind != right_section_kind {
|
||||
log::warn!(
|
||||
"Symbol section kind mismatch: {} ({:?}) vs {} ({:?})",
|
||||
left_name,
|
||||
left_section_kind,
|
||||
right_name,
|
||||
right_section_kind
|
||||
"Symbol section kind mismatch: {left_name} ({left_section_kind:?}) vs {right_name} ({right_section_kind:?})"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ fn run_build(
|
||||
Some(target_path_rel) if config.build_target => {
|
||||
update_status(
|
||||
context,
|
||||
format!("Building target {}", target_path_rel),
|
||||
format!("Building target {target_path_rel}"),
|
||||
step_idx,
|
||||
total,
|
||||
&cancel,
|
||||
@@ -94,7 +94,7 @@ fn run_build(
|
||||
Some(base_path_rel) if config.build_base => {
|
||||
update_status(
|
||||
context,
|
||||
format!("Building base {}", base_path_rel),
|
||||
format!("Building base {base_path_rel}"),
|
||||
step_idx,
|
||||
total,
|
||||
&cancel,
|
||||
@@ -111,7 +111,7 @@ fn run_build(
|
||||
Some(target_path) if first_status.success => {
|
||||
update_status(
|
||||
context,
|
||||
format!("Loading target {}", target_path),
|
||||
format!("Loading target {target_path}"),
|
||||
step_idx,
|
||||
total,
|
||||
&cancel,
|
||||
@@ -122,8 +122,8 @@ fn run_build(
|
||||
Err(e) => {
|
||||
first_status = BuildStatus {
|
||||
success: false,
|
||||
stdout: format!("Loading object '{}'", target_path),
|
||||
stderr: format!("{:#}", e),
|
||||
stdout: format!("Loading object '{target_path}'"),
|
||||
stderr: format!("{e:#}"),
|
||||
..Default::default()
|
||||
};
|
||||
None
|
||||
@@ -139,21 +139,15 @@ fn run_build(
|
||||
|
||||
let second_obj = match &config.base_path {
|
||||
Some(base_path) if second_status.success => {
|
||||
update_status(
|
||||
context,
|
||||
format!("Loading base {}", base_path),
|
||||
step_idx,
|
||||
total,
|
||||
&cancel,
|
||||
)?;
|
||||
update_status(context, format!("Loading base {base_path}"), step_idx, total, &cancel)?;
|
||||
step_idx += 1;
|
||||
match read::read(base_path.as_ref(), &config.diff_obj_config) {
|
||||
Ok(obj) => Some(obj),
|
||||
Err(e) => {
|
||||
second_status = BuildStatus {
|
||||
success: false,
|
||||
stdout: format!("Loading object '{}'", base_path),
|
||||
stderr: format!("{:#}", e),
|
||||
stdout: format!("Loading object '{base_path}'"),
|
||||
stderr: format!("{e:#}"),
|
||||
..Default::default()
|
||||
};
|
||||
None
|
||||
|
||||
@@ -114,11 +114,21 @@ impl Section {
|
||||
ins_ref: InstructionRef,
|
||||
) -> Option<ResolvedRelocation<'obj>> {
|
||||
match self.relocations.binary_search_by_key(&ins_ref.address, |r| r.address) {
|
||||
Ok(i) => self.relocations.get(i),
|
||||
Ok(mut i) => {
|
||||
// Find the first relocation at the address
|
||||
while i
|
||||
.checked_sub(1)
|
||||
.and_then(|n| self.relocations.get(n))
|
||||
.is_some_and(|r| r.address == ins_ref.address)
|
||||
{
|
||||
i -= 1;
|
||||
}
|
||||
self.relocations.get(i)
|
||||
}
|
||||
Err(i) => self
|
||||
.relocations
|
||||
.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| {
|
||||
let symbol = obj.symbols.get(relocation.target_symbol)?;
|
||||
@@ -169,8 +179,8 @@ impl fmt::Display for InstructionArgValue<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
InstructionArgValue::Signed(v) => write!(f, "{:#x}", ReallySigned(*v)),
|
||||
InstructionArgValue::Unsigned(v) => write!(f, "{:#x}", v),
|
||||
InstructionArgValue::Opaque(v) => write!(f, "{}", v),
|
||||
InstructionArgValue::Unsigned(v) => write!(f, "{v:#x}"),
|
||||
InstructionArgValue::Opaque(v) => write!(f, "{v}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,6 +243,19 @@ pub enum SymbolKind {
|
||||
Section,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FlowAnalysisValue {
|
||||
Text(String),
|
||||
}
|
||||
|
||||
pub trait FlowAnalysisResult: core::fmt::Debug + Send {
|
||||
fn get_argument_value_at_address(
|
||||
&self,
|
||||
address: u64,
|
||||
argument: u8,
|
||||
) -> Option<&FlowAnalysisValue>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
@@ -260,6 +283,7 @@ pub struct Object {
|
||||
pub path: Option<std::path::PathBuf>,
|
||||
#[cfg(feature = "std")]
|
||||
pub timestamp: Option<filetime::FileTime>,
|
||||
pub flow_analysis_results: BTreeMap<u64, Box<dyn FlowAnalysisResult>>,
|
||||
}
|
||||
|
||||
impl Default for Object {
|
||||
@@ -274,6 +298,7 @@ impl Default for Object {
|
||||
path: None,
|
||||
#[cfg(feature = "std")]
|
||||
timestamp: None,
|
||||
flow_analysis_results: BTreeMap::<u64, Box<dyn FlowAnalysisResult>>::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,7 +308,7 @@ impl Object {
|
||||
&self,
|
||||
symbol_index: usize,
|
||||
ins_ref: InstructionRef,
|
||||
) -> Option<ResolvedInstructionRef> {
|
||||
) -> Option<ResolvedInstructionRef<'_>> {
|
||||
let symbol = self.symbols.get(symbol_index)?;
|
||||
let section_index = symbol.section?;
|
||||
let section = self.sections.get(section_index)?;
|
||||
@@ -308,6 +333,26 @@ impl Object {
|
||||
let offset = symbol.address.checked_sub(section.address)?;
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn get_flow_analysis_result(&self, symbol: &Symbol) -> Option<&dyn FlowAnalysisResult> {
|
||||
let key = symbol.section.unwrap_or_default() as u64 * 1024 * 1024 * 1024 + symbol.address;
|
||||
self.flow_analysis_results.get(&key).map(|result| result.as_ref())
|
||||
}
|
||||
|
||||
pub fn add_flow_analysis_result(
|
||||
&mut self,
|
||||
symbol: &Symbol,
|
||||
result: Box<dyn FlowAnalysisResult>,
|
||||
) {
|
||||
let key = symbol.section.unwrap_or_default() as u64 * 1024 * 1024 * 1024 + symbol.address;
|
||||
self.flow_analysis_results.insert(key, result);
|
||||
}
|
||||
|
||||
pub fn has_flow_analysis_result(&self) -> bool { !self.flow_analysis_results.is_empty() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::BTreeMap,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
@@ -10,11 +11,11 @@ use anyhow::{Context, Result, anyhow, bail, ensure};
|
||||
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
|
||||
|
||||
use crate::{
|
||||
arch::{Arch, new_arch},
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget, new_arch},
|
||||
diff::DiffObjConfig,
|
||||
obj::{
|
||||
Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag, SectionKind,
|
||||
Symbol, SymbolFlag, SymbolKind,
|
||||
FlowAnalysisResult, Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag,
|
||||
SectionKind, Symbol, SymbolFlag, SymbolKind,
|
||||
split_meta::{SPLITMETA_SECTION, SplitMeta},
|
||||
},
|
||||
util::{align_data_slice_to, align_u64_to, read_u16, read_u32},
|
||||
@@ -23,8 +24,13 @@ use crate::{
|
||||
fn map_section_kind(section: &object::Section) -> SectionKind {
|
||||
match section.kind() {
|
||||
object::SectionKind::Text => SectionKind::Code,
|
||||
object::SectionKind::Data | object::SectionKind::ReadOnlyData => SectionKind::Data,
|
||||
object::SectionKind::UninitializedData => SectionKind::Bss,
|
||||
object::SectionKind::Data
|
||||
| object::SectionKind::ReadOnlyData
|
||||
| object::SectionKind::ReadOnlyString
|
||||
| object::SectionKind::Tls => SectionKind::Data,
|
||||
object::SectionKind::UninitializedData
|
||||
| object::SectionKind::UninitializedTls
|
||||
| object::SectionKind::Common => SectionKind::Bss,
|
||||
_ => SectionKind::Unknown,
|
||||
}
|
||||
}
|
||||
@@ -42,7 +48,7 @@ fn map_symbol(
|
||||
(symbol.kind(), symbol.section_index().and_then(|i| file.section_by_index(i).ok()))
|
||||
{
|
||||
let section_name = section.name().context("Failed to process section name")?;
|
||||
name = format!("[{}]", section_name);
|
||||
name = format!("[{section_name}]");
|
||||
// For section symbols, set the size to zero. If the size is non-zero, it will be included
|
||||
// in the diff. Most of the time, this is duplicative, given that we'll have function or
|
||||
// object symbols that cover the same range. In the case of an empty section, the size
|
||||
@@ -121,6 +127,15 @@ fn map_symbols(
|
||||
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]) {
|
||||
// Create a sorted list of symbol indices by section
|
||||
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
||||
@@ -167,27 +182,28 @@ fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
|
||||
if last_end.0 == section_idx && last_end.1 > symbol.address {
|
||||
continue;
|
||||
}
|
||||
let next_symbol = match symbol.kind {
|
||||
// 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() {
|
||||
break None;
|
||||
let next_symbol = loop {
|
||||
if iter_idx >= symbols_with_section.len() {
|
||||
break None;
|
||||
}
|
||||
let next_symbol = &symbols[symbols_with_section[iter_idx]];
|
||||
if next_symbol.section != Some(section_idx) {
|
||||
break None;
|
||||
}
|
||||
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)
|
||||
}
|
||||
let next_symbol = &symbols[symbols_with_section[iter_idx]];
|
||||
if next_symbol.section != Some(section_idx) {
|
||||
break None;
|
||||
SymbolKind::Unknown | SymbolKind::Section => {
|
||||
// For labels (or anything else), stop at any symbol
|
||||
true
|
||||
}
|
||||
if let SymbolKind::Function | SymbolKind::Object = next_symbol.kind {
|
||||
break Some(next_symbol);
|
||||
}
|
||||
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)),
|
||||
} && !is_local_label(next_symbol)
|
||||
{
|
||||
break Some(next_symbol);
|
||||
}
|
||||
iter_idx += 1;
|
||||
};
|
||||
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
|
||||
let section = §ions[section_idx];
|
||||
@@ -242,7 +258,7 @@ fn map_sections(
|
||||
});
|
||||
|
||||
let unique_id = section_names.entry(name.to_string()).or_insert(0);
|
||||
let id = format!("{}-{}", name, unique_id);
|
||||
let id = format!("{name}-{unique_id}");
|
||||
*unique_id += 1;
|
||||
|
||||
if section_indices.len() <= section.index().0 {
|
||||
@@ -318,60 +334,125 @@ fn map_section_relocations(
|
||||
) -> Result<Vec<Relocation>> {
|
||||
let mut relocations = Vec::<Relocation>::with_capacity(obj_section.relocations().count());
|
||||
for (address, reloc) in obj_section.relocations() {
|
||||
let flags = match reloc.flags() {
|
||||
object::RelocationFlags::Elf { r_type } => RelocationFlags::Elf(r_type),
|
||||
object::RelocationFlags::Coff { typ } => RelocationFlags::Coff(typ),
|
||||
flags => {
|
||||
bail!("Unhandled relocation flags: {:?}", flags);
|
||||
let mut target_reloc = RelocationOverride {
|
||||
target: match reloc.target() {
|
||||
object::RelocationTarget::Symbol(symbol) => {
|
||||
RelocationOverrideTarget::Symbol(symbol)
|
||||
}
|
||||
object::RelocationTarget::Section(section) => {
|
||||
RelocationOverrideTarget::Section(section)
|
||||
}
|
||||
_ => RelocationOverrideTarget::Skip,
|
||||
},
|
||||
addend: reloc.addend(),
|
||||
};
|
||||
|
||||
// Allow the architecture to override the relocation target and addend
|
||||
match arch.relocation_override(obj_file, obj_section, address, &reloc)? {
|
||||
Some(reloc_override) => {
|
||||
match reloc_override.target {
|
||||
RelocationOverrideTarget::Keep => {}
|
||||
target => {
|
||||
target_reloc.target = target;
|
||||
}
|
||||
}
|
||||
target_reloc.addend = reloc_override.addend;
|
||||
}
|
||||
};
|
||||
// TODO validate reloc here?
|
||||
let mut addend = if reloc.has_implicit_addend() {
|
||||
arch.implcit_addend(obj_file, obj_section, address, &reloc, flags)?
|
||||
} else {
|
||||
reloc.addend()
|
||||
};
|
||||
let target_symbol = match reloc.target() {
|
||||
object::RelocationTarget::Symbol(idx) => {
|
||||
if idx.0 == u32::MAX as usize {
|
||||
// ???
|
||||
None => {
|
||||
ensure!(
|
||||
!reloc.has_implicit_addend(),
|
||||
"Unsupported implicit relocation {:?}",
|
||||
reloc.flags()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the relocation target symbol
|
||||
let (symbol_index, addend) = match target_reloc.target {
|
||||
RelocationOverrideTarget::Keep => unreachable!(),
|
||||
RelocationOverrideTarget::Skip => continue,
|
||||
RelocationOverrideTarget::Symbol(symbol_index) => {
|
||||
// Sometimes used to indicate "absolute"
|
||||
if symbol_index.0 == u32::MAX as usize {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the target is a section symbol, try to resolve a better symbol as the target
|
||||
let idx = if let Some(section_symbol) = obj_file
|
||||
.symbol_by_index(idx)
|
||||
if let Some(section_symbol) = obj_file
|
||||
.symbol_by_index(symbol_index)
|
||||
.ok()
|
||||
.take_if(|s| s.kind() == object::SymbolKind::Section)
|
||||
.filter(|s| s.kind() == object::SymbolKind::Section)
|
||||
{
|
||||
let section_index =
|
||||
section_symbol.section_index().context("Section symbol without section")?;
|
||||
let target_address = section_symbol.address().wrapping_add_signed(addend);
|
||||
let target_address =
|
||||
section_symbol.address().wrapping_add_signed(target_reloc.addend);
|
||||
if let Some((new_idx, addr)) = ordered_symbols
|
||||
.get(section_index.0)
|
||||
.and_then(|symbols| best_symbol(symbols, target_address))
|
||||
{
|
||||
addend = target_address.wrapping_sub(addr) as i64;
|
||||
new_idx
|
||||
(new_idx, target_address.wrapping_sub(addr) as i64)
|
||||
} else {
|
||||
idx
|
||||
(symbol_index, target_reloc.addend)
|
||||
}
|
||||
} else {
|
||||
idx
|
||||
};
|
||||
match symbol_indices.get(idx.0).copied() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
log::warn!("Invalid symbol index {}", idx.0);
|
||||
continue;
|
||||
}
|
||||
(symbol_index, target_reloc.addend)
|
||||
}
|
||||
}
|
||||
object::RelocationTarget::Absolute => {
|
||||
let section_name = obj_section.name()?;
|
||||
log::warn!("Ignoring absolute relocation @ {}:{:#x}", section_name, address);
|
||||
RelocationOverrideTarget::Section(section_index) => {
|
||||
let section = match obj_file.section_by_index(section_index) {
|
||||
Ok(section) => section,
|
||||
Err(e) => {
|
||||
log::warn!("Invalid relocation section: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let Ok(target_address) = u64::try_from(target_reloc.addend) else {
|
||||
log::warn!(
|
||||
"Negative section relocation addend: {}{}",
|
||||
section.name()?,
|
||||
target_reloc.addend
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Some(symbols) = ordered_symbols.get(section_index.0) else {
|
||||
log::warn!(
|
||||
"Couldn't resolve relocation target symbol for section {} (no symbols)",
|
||||
section.name()?
|
||||
);
|
||||
continue;
|
||||
};
|
||||
// Attempt to resolve a target symbol for the relocation
|
||||
if let Some((new_idx, addr)) = best_symbol(symbols, target_address) {
|
||||
(new_idx, target_address.wrapping_sub(addr) as i64)
|
||||
} else if let Some(section_symbol) =
|
||||
symbols.iter().find(|s| s.kind() == object::SymbolKind::Section)
|
||||
{
|
||||
(
|
||||
section_symbol.index(),
|
||||
target_address.wrapping_sub(section_symbol.address()) as i64,
|
||||
)
|
||||
} else {
|
||||
log::warn!(
|
||||
"Couldn't resolve relocation target symbol for section {}",
|
||||
section.name()?
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let flags = match reloc.flags() {
|
||||
object::RelocationFlags::Elf { r_type } => RelocationFlags::Elf(r_type),
|
||||
object::RelocationFlags::Coff { typ } => RelocationFlags::Coff(typ),
|
||||
flags => bail!("Unhandled relocation flags: {:?}", flags),
|
||||
};
|
||||
let target_symbol = match symbol_indices.get(symbol_index.0).copied() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
log::warn!("Invalid symbol index {}", symbol_index.0);
|
||||
continue;
|
||||
}
|
||||
_ => bail!("Unhandled relocation target: {:?}", reloc.target()),
|
||||
};
|
||||
relocations.push(Relocation { address, flags, target_symbol, addend });
|
||||
}
|
||||
@@ -422,17 +503,19 @@ fn map_relocations(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_pooled_relocations(
|
||||
arch: &dyn Arch,
|
||||
sections: &mut [Section],
|
||||
symbols: &[Symbol],
|
||||
) -> Result<()> {
|
||||
for (section_index, section) in sections.iter_mut().enumerate() {
|
||||
fn perform_data_flow_analysis(obj: &mut Object, config: &DiffObjConfig) -> Result<()> {
|
||||
// If neither of these settings are on, no flow analysis to perform
|
||||
if !config.analyze_data_flow && !config.ppc_calculate_pool_relocations {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut generated_relocations = Vec::<(usize, Vec<Relocation>)>::new();
|
||||
let mut generated_flow_results = Vec::<(Symbol, Box<dyn FlowAnalysisResult>)>::new();
|
||||
for (section_index, section) in obj.sections.iter().enumerate() {
|
||||
if section.kind != SectionKind::Code {
|
||||
continue;
|
||||
}
|
||||
let mut fake_pool_relocs = Vec::new();
|
||||
for symbol in symbols {
|
||||
for symbol in obj.symbols.iter() {
|
||||
if symbol.section != Some(section_index) {
|
||||
continue;
|
||||
}
|
||||
@@ -447,14 +530,37 @@ fn calculate_pooled_relocations(
|
||||
symbol.address + symbol.size
|
||||
)
|
||||
})?;
|
||||
fake_pool_relocs.append(&mut arch.generate_pooled_relocations(
|
||||
symbol.address,
|
||||
code,
|
||||
§ion.relocations,
|
||||
symbols,
|
||||
));
|
||||
|
||||
// Optional pooled relocation computation
|
||||
// Long view: This could be replaced by the full data flow analysis
|
||||
// once that feature has stabilized.
|
||||
if config.ppc_calculate_pool_relocations {
|
||||
let relocations = obj.arch.generate_pooled_relocations(
|
||||
symbol.address,
|
||||
code,
|
||||
§ion.relocations,
|
||||
&obj.symbols,
|
||||
);
|
||||
generated_relocations.push((section_index, relocations));
|
||||
}
|
||||
|
||||
// Optional full data flow analysis
|
||||
if config.analyze_data_flow {
|
||||
if let Some(flow_result) =
|
||||
obj.arch.data_flow_analysis(obj, symbol, code, §ion.relocations)
|
||||
{
|
||||
generated_flow_results.push((symbol.clone(), flow_result));
|
||||
}
|
||||
}
|
||||
}
|
||||
section.relocations.append(&mut fake_pool_relocs);
|
||||
}
|
||||
for (symbol, flow_result) in generated_flow_results {
|
||||
obj.add_flow_analysis_result(&symbol, flow_result);
|
||||
}
|
||||
for (section_index, mut relocations) in generated_relocations {
|
||||
obj.sections[section_index].relocations.append(&mut relocations);
|
||||
}
|
||||
for section in obj.sections.iter_mut() {
|
||||
section.relocations.sort_by_key(|r| r.address);
|
||||
}
|
||||
Ok(())
|
||||
@@ -487,7 +593,7 @@ fn parse_line_info(
|
||||
let line_number = read_u32(obj_file, &mut section_data)?;
|
||||
let statement_pos = read_u16(obj_file, &mut section_data)?;
|
||||
if statement_pos != 0xFFFF {
|
||||
log::warn!("Unhandled statement pos {}", statement_pos);
|
||||
log::warn!("Unhandled statement pos {statement_pos}");
|
||||
}
|
||||
let address_delta = read_u32(obj_file, &mut section_data)? as u64;
|
||||
out_section.line_info.insert(base_address + address_delta, line_number);
|
||||
@@ -855,15 +961,12 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
|
||||
let (mut symbols, symbol_indices) =
|
||||
map_symbols(arch.as_ref(), &obj_file, §ions, §ion_indices, split_meta.as_ref())?;
|
||||
map_relocations(arch.as_ref(), &obj_file, &mut sections, §ion_indices, &symbol_indices)?;
|
||||
if config.ppc_calculate_pool_relocations {
|
||||
calculate_pooled_relocations(arch.as_ref(), &mut sections, &symbols)?;
|
||||
}
|
||||
parse_line_info(&obj_file, &mut sections, §ion_indices, data)?;
|
||||
if config.combine_data_sections || config.combine_text_sections {
|
||||
combine_sections(&mut sections, &mut symbols, config)?;
|
||||
}
|
||||
arch.post_init(§ions, &symbols);
|
||||
Ok(Object {
|
||||
let mut obj = Object {
|
||||
arch,
|
||||
endianness: obj_file.endianness(),
|
||||
symbols,
|
||||
@@ -873,7 +976,14 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
|
||||
path: None,
|
||||
#[cfg(feature = "std")]
|
||||
timestamp: None,
|
||||
})
|
||||
flow_analysis_results: Default::default(),
|
||||
};
|
||||
|
||||
// Need to construct the obj first so that we have a convinient package to
|
||||
// pass to flow analysis. Then the flow analysis will mutate obj adding
|
||||
// additional data to it.
|
||||
perform_data_flow_analysis(&mut obj, config)?;
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -59,3 +59,33 @@ pub fn align_u64_to(len: u64, align: u64) -> u64 { len + ((align - (len % align)
|
||||
pub fn align_data_slice_to(data: &mut Vec<u8>, align: u64) {
|
||||
data.resize(align_u64_to(data.len() as u64, align) as usize, 0);
|
||||
}
|
||||
|
||||
// Float where we specifically care about comparing the raw bits rather than
|
||||
// caring about IEEE semantics.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RawFloat(pub f32);
|
||||
impl PartialEq for RawFloat {
|
||||
fn eq(&self, other: &Self) -> bool { self.0.to_bits() == other.0.to_bits() }
|
||||
}
|
||||
impl Eq for RawFloat {}
|
||||
impl Ord for RawFloat {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.to_bits().cmp(&other.0.to_bits()) }
|
||||
}
|
||||
impl PartialOrd for RawFloat {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
// Double where we specifically care about comparing the raw bits rather than
|
||||
// caring about IEEE semantics.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RawDouble(pub f64);
|
||||
impl PartialEq for RawDouble {
|
||||
fn eq(&self, other: &Self) -> bool { self.0.to_bits() == other.0.to_bits() }
|
||||
}
|
||||
impl Eq for RawDouble {}
|
||||
impl Ord for RawDouble {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.to_bits().cmp(&other.0.to_bits()) }
|
||||
}
|
||||
impl PartialOrd for RawDouble {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
@@ -85,3 +85,17 @@ fn diff_ppc() {
|
||||
assert_eq!(base_symbol_diff.target_symbol, Some(target_symbol_idx));
|
||||
insta::assert_debug_snapshot!((target_symbol_diff, base_symbol_diff));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "ppc")]
|
||||
fn read_vmx128_coff() {
|
||||
let diff_config = diff::DiffObjConfig { combine_data_sections: true, ..Default::default() };
|
||||
let obj = obj::read::parse(include_object!("data/ppc/vmx128.obj"), &diff_config).unwrap();
|
||||
insta::assert_debug_snapshot!(obj);
|
||||
let symbol_idx =
|
||||
obj.symbols.iter().position(|s| s.name == "?FloatingPointExample@@YAXXZ").unwrap();
|
||||
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
|
||||
insta::assert_debug_snapshot!(diff.instruction_rows);
|
||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
@@ -68,3 +68,12 @@ fn read_x86_jumptable() {
|
||||
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn display_diff(
|
||||
separator = true;
|
||||
}
|
||||
let DiffTextSegment { text, color, pad_to } = segment;
|
||||
output.push_str(&format!("({:?}, {:?}, {:?})", text, color, pad_to));
|
||||
output.push_str(&format!("({text:?}, {color:?}, {pad_to:?})"));
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
BIN
objdiff-core/tests/data/ppc/vmx128.obj
Normal file
BIN
objdiff-core/tests/data/ppc/vmx128.obj
Normal file
Binary file not shown.
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.
@@ -1954,4 +1954,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -3826,4 +3826,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -1490,4 +1490,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@ expression: obj
|
||||
---
|
||||
Object {
|
||||
arch: ArchPpc {
|
||||
extensions: Extensions(
|
||||
2,
|
||||
),
|
||||
extab: Some(
|
||||
{
|
||||
10: ExceptionInfo {
|
||||
@@ -548,4 +551,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 0,
|
||||
size: 4,
|
||||
opcode: 60,
|
||||
opcode: 283,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -22,7 +22,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 4,
|
||||
size: 4,
|
||||
opcode: 38,
|
||||
opcode: 260,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -36,7 +36,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 8,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
20,
|
||||
),
|
||||
@@ -57,7 +57,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 12,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -71,7 +71,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 16,
|
||||
size: 4,
|
||||
opcode: 45,
|
||||
opcode: 267,
|
||||
branch_dest: Some(
|
||||
32,
|
||||
),
|
||||
@@ -92,7 +92,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 20,
|
||||
size: 4,
|
||||
opcode: 42,
|
||||
opcode: 264,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -113,7 +113,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 24,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -127,7 +127,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 28,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -141,7 +141,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 32,
|
||||
size: 4,
|
||||
opcode: 60,
|
||||
opcode: 283,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -162,7 +162,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 36,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -176,7 +176,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 40,
|
||||
size: 4,
|
||||
opcode: 38,
|
||||
opcode: 260,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -190,7 +190,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 44,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
56,
|
||||
),
|
||||
@@ -211,7 +211,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 48,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -225,7 +225,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 52,
|
||||
size: 4,
|
||||
opcode: 45,
|
||||
opcode: 267,
|
||||
branch_dest: Some(
|
||||
68,
|
||||
),
|
||||
@@ -246,7 +246,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 56,
|
||||
size: 4,
|
||||
opcode: 42,
|
||||
opcode: 264,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -267,7 +267,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 60,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -281,7 +281,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 64,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -295,7 +295,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 68,
|
||||
size: 4,
|
||||
opcode: 60,
|
||||
opcode: 283,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -316,7 +316,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 72,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -330,7 +330,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 76,
|
||||
size: 4,
|
||||
opcode: 38,
|
||||
opcode: 260,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -344,7 +344,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 80,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -358,7 +358,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 84,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
96,
|
||||
),
|
||||
@@ -379,7 +379,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 88,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -393,7 +393,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 92,
|
||||
size: 4,
|
||||
opcode: 45,
|
||||
opcode: 267,
|
||||
branch_dest: Some(
|
||||
108,
|
||||
),
|
||||
@@ -414,7 +414,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 96,
|
||||
size: 4,
|
||||
opcode: 42,
|
||||
opcode: 264,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -435,7 +435,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 100,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -449,7 +449,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 104,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -463,7 +463,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 108,
|
||||
size: 4,
|
||||
opcode: 60,
|
||||
opcode: 283,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -484,7 +484,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 112,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -498,7 +498,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 116,
|
||||
size: 4,
|
||||
opcode: 38,
|
||||
opcode: 260,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -512,7 +512,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 120,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -526,7 +526,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 124,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
136,
|
||||
),
|
||||
@@ -547,7 +547,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 128,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -561,7 +561,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 132,
|
||||
size: 4,
|
||||
opcode: 45,
|
||||
opcode: 267,
|
||||
branch_dest: Some(
|
||||
148,
|
||||
),
|
||||
@@ -582,7 +582,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 136,
|
||||
size: 4,
|
||||
opcode: 42,
|
||||
opcode: 264,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -603,7 +603,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 140,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -617,7 +617,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 144,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -631,7 +631,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 148,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -652,7 +652,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 152,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -666,7 +666,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 156,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -680,7 +680,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 160,
|
||||
size: 4,
|
||||
opcode: 42,
|
||||
opcode: 264,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -694,7 +694,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 164,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -708,7 +708,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 168,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -722,7 +722,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 172,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -736,7 +736,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 176,
|
||||
size: 4,
|
||||
opcode: 162,
|
||||
opcode: 441,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -750,7 +750,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 180,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -764,7 +764,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 184,
|
||||
size: 4,
|
||||
opcode: 66,
|
||||
opcode: 289,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -778,7 +778,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 188,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
196,
|
||||
),
|
||||
@@ -799,7 +799,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 192,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -813,7 +813,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 196,
|
||||
size: 4,
|
||||
opcode: 163,
|
||||
opcode: 442,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -834,7 +834,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 200,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -848,7 +848,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 204,
|
||||
size: 4,
|
||||
opcode: 66,
|
||||
opcode: 289,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -862,7 +862,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 208,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
216,
|
||||
),
|
||||
@@ -883,7 +883,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 212,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -897,7 +897,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 216,
|
||||
size: 4,
|
||||
opcode: 163,
|
||||
opcode: 442,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -918,7 +918,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 220,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -932,7 +932,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 224,
|
||||
size: 4,
|
||||
opcode: 66,
|
||||
opcode: 289,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -946,7 +946,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 228,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
236,
|
||||
),
|
||||
@@ -967,7 +967,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 232,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -981,7 +981,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 236,
|
||||
size: 4,
|
||||
opcode: 163,
|
||||
opcode: 442,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -1002,7 +1002,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 240,
|
||||
size: 4,
|
||||
opcode: 94,
|
||||
opcode: 323,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -1016,7 +1016,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 244,
|
||||
size: 4,
|
||||
opcode: 66,
|
||||
opcode: 289,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -1030,7 +1030,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 248,
|
||||
size: 4,
|
||||
opcode: 43,
|
||||
opcode: 265,
|
||||
branch_dest: Some(
|
||||
256,
|
||||
),
|
||||
@@ -1051,7 +1051,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 252,
|
||||
size: 4,
|
||||
opcode: 166,
|
||||
opcode: 445,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -1065,7 +1065,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 256,
|
||||
size: 4,
|
||||
opcode: 41,
|
||||
opcode: 263,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
@@ -1086,7 +1086,7 @@ expression: diff.instruction_rows
|
||||
InstructionRef {
|
||||
address: 260,
|
||||
size: 4,
|
||||
opcode: 47,
|
||||
opcode: 269,
|
||||
branch_dest: None,
|
||||
},
|
||||
),
|
||||
|
||||
@@ -1,71 +1,70 @@
|
||||
---
|
||||
source: objdiff-core/tests/arch_ppc.rs
|
||||
assertion_line: 20
|
||||
expression: output
|
||||
---
|
||||
[(Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("srwi", 60), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("24")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(4), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 38), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(8), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(20), Normal, 0), (Basic(" ~>"), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(12), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(16), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 45), Normal, 10), (BranchDest(32), Normal, 0), (Basic(" ~>"), Rotating(1), 0), (Eol, Normal, 0)]
|
||||
[(Address(20), Normal, 5), (Basic(" ~> "), Rotating(0), 0), (Opcode("lis", 42), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(24), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 41), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(28), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(32), Normal, 5), (Basic(" ~> "), Rotating(1), 0), (Opcode("extrwi", 60), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(36), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(40), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 38), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(44), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(56), Normal, 0), (Basic(" ~>"), Rotating(2), 0), (Eol, Normal, 0)]
|
||||
[(Address(48), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(52), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 45), Normal, 10), (BranchDest(68), Normal, 0), (Basic(" ~>"), Rotating(3), 0), (Eol, Normal, 0)]
|
||||
[(Address(56), Normal, 5), (Basic(" ~> "), Rotating(2), 0), (Opcode("lis", 42), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(60), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 41), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(64), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(68), Normal, 5), (Basic(" ~> "), Rotating(3), 0), (Opcode("extrwi", 60), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("16")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(72), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(76), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 38), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(80), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(84), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(96), Normal, 0), (Basic(" ~>"), Rotating(4), 0), (Eol, Normal, 0)]
|
||||
[(Address(88), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(92), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 45), Normal, 10), (BranchDest(108), Normal, 0), (Basic(" ~>"), Rotating(5), 0), (Eol, Normal, 0)]
|
||||
[(Address(96), Normal, 5), (Basic(" ~> "), Rotating(4), 0), (Opcode("lis", 42), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(100), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 41), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(104), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(108), Normal, 5), (Basic(" ~> "), Rotating(5), 0), (Opcode("clrlwi", 60), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("24")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(112), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(116), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 38), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(120), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(2)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(124), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(136), Normal, 0), (Basic(" ~>"), Rotating(6), 0), (Eol, Normal, 0)]
|
||||
[(Address(128), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(132), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 45), Normal, 10), (BranchDest(148), Normal, 0), (Basic(" ~>"), Rotating(7), 0), (Eol, Normal, 0)]
|
||||
[(Address(136), Normal, 5), (Basic(" ~> "), Rotating(6), 0), (Opcode("lis", 42), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(140), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 41), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(144), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(148), Normal, 5), (Basic(" ~> "), Rotating(7), 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(152), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(156), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(3)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(160), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 42), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(164), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 41), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(168), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(4)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(172), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(45)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(176), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbz", 162), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(180), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(184), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 66), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(188), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(196), Normal, 0), (Basic(" ~>"), Rotating(8), 0), (Eol, Normal, 0)]
|
||||
[(Address(192), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(196), Normal, 5), (Basic(" ~> "), Rotating(8), 0), (Opcode("lbzu", 163), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(200), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(204), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 66), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(208), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(216), Normal, 0), (Basic(" ~>"), Rotating(9), 0), (Eol, Normal, 0)]
|
||||
[(Address(212), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(216), Normal, 5), (Basic(" ~> "), Rotating(9), 0), (Opcode("lbzu", 163), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(220), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(224), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 66), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(228), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(236), Normal, 0), (Basic(" ~>"), Rotating(10), 0), (Eol, Normal, 0)]
|
||||
[(Address(232), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(236), Normal, 5), (Basic(" ~> "), Rotating(10), 0), (Opcode("lbzu", 163), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(240), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 94), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(244), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 66), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(248), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 43), Normal, 10), (BranchDest(256), Normal, 0), (Basic(" ~>"), Rotating(11), 0), (Eol, Normal, 0)]
|
||||
[(Address(252), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 166), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(256), Normal, 5), (Basic(" ~> "), Rotating(11), 0), (Opcode("li", 41), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(260), Normal, 5), (Spacing(4), Normal, 0), (Opcode("blr", 47), Normal, 10), (Eol, Normal, 0)]
|
||||
[(Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("srwi", 283), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("24")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(4), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 260), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(8), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(20), Normal, 0), (Basic(" ~>"), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(12), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(16), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 267), Normal, 10), (BranchDest(32), Normal, 0), (Basic(" ~>"), Rotating(1), 0), (Eol, Normal, 0)]
|
||||
[(Address(20), Normal, 5), (Basic(" ~> "), Rotating(0), 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(24), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(28), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(32), Normal, 5), (Basic(" ~> "), Rotating(1), 0), (Opcode("extrwi", 283), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(36), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(40), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 260), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(44), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(56), Normal, 0), (Basic(" ~>"), Rotating(2), 0), (Eol, Normal, 0)]
|
||||
[(Address(48), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(52), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 267), Normal, 10), (BranchDest(68), Normal, 0), (Basic(" ~>"), Rotating(3), 0), (Eol, Normal, 0)]
|
||||
[(Address(56), Normal, 5), (Basic(" ~> "), Rotating(2), 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(60), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(64), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(68), Normal, 5), (Basic(" ~> "), Rotating(3), 0), (Opcode("extrwi", 283), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("16")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(72), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(76), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 260), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(80), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(84), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(96), Normal, 0), (Basic(" ~>"), Rotating(4), 0), (Eol, Normal, 0)]
|
||||
[(Address(88), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(92), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 267), Normal, 10), (BranchDest(108), Normal, 0), (Basic(" ~>"), Rotating(5), 0), (Eol, Normal, 0)]
|
||||
[(Address(96), Normal, 5), (Basic(" ~> "), Rotating(4), 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(100), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(104), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(108), Normal, 5), (Basic(" ~> "), Rotating(5), 0), (Opcode("clrlwi", 283), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("24")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(112), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(116), Normal, 5), (Spacing(4), Normal, 0), (Opcode("cmpwi", 260), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(120), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(2)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(124), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(136), Normal, 0), (Basic(" ~>"), Rotating(6), 0), (Eol, Normal, 0)]
|
||||
[(Address(128), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(132), Normal, 5), (Spacing(4), Normal, 0), (Opcode("b", 267), Normal, 10), (BranchDest(148), Normal, 0), (Basic(" ~>"), Rotating(7), 0), (Eol, Normal, 0)]
|
||||
[(Address(136), Normal, 5), (Basic(" ~> "), Rotating(6), 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(140), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(144), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__upper_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(148), Normal, 5), (Basic(" ~> "), Rotating(7), 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(152), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(156), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(3)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(160), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@ha"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(164), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(168), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(4)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(172), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(45)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(176), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbz", 441), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(180), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(184), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 289), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(188), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(196), Normal, 0), (Basic(" ~>"), Rotating(8), 0), (Eol, Normal, 0)]
|
||||
[(Address(192), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(196), Normal, 5), (Basic(" ~> "), Rotating(8), 0), (Opcode("lbzu", 442), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(200), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(204), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 289), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(208), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(216), Normal, 0), (Basic(" ~>"), Rotating(9), 0), (Eol, Normal, 0)]
|
||||
[(Address(212), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(216), Normal, 5), (Basic(" ~> "), Rotating(9), 0), (Opcode("lbzu", 442), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(220), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(224), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 289), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(228), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(236), Normal, 0), (Basic(" ~>"), Rotating(10), 0), (Eol, Normal, 0)]
|
||||
[(Address(232), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(236), Normal, 5), (Basic(" ~> "), Rotating(10), 0), (Opcode("lbzu", 442), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(1)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(240), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lbzx", 323), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(" <"), Normal, 0), (Symbol(Symbol { name: "__ctype_map", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: Some(0) }), Bright, 0), (Basic(">"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(244), Normal, 5), (Spacing(4), Normal, 0), (Opcode("andi.", 289), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Unsigned(220)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(248), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bne", 265), Normal, 10), (BranchDest(256), Normal, 0), (Basic(" ~>"), Rotating(11), 0), (Eol, Normal, 0)]
|
||||
[(Address(252), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stb", 445), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(256), Normal, 5), (Basic(" ~> "), Rotating(11), 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "text$52", demangled_name: None, address: 8, size: 5, kind: Object, section: Some(2), flags: FlagSet(Local), align: None, virtual_address: Some(2153420056) }), Bright, 0), (Basic("@sda21"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(260), Normal, 5), (Spacing(4), Normal, 0), (Opcode("blr", 269), Normal, 10), (Eol, Normal, 0)]
|
||||
|
||||
@@ -4,6 +4,9 @@ expression: obj
|
||||
---
|
||||
Object {
|
||||
arch: ArchPpc {
|
||||
extensions: Extensions(
|
||||
2,
|
||||
),
|
||||
extab: None,
|
||||
},
|
||||
endianness: Big,
|
||||
@@ -581,4 +584,5 @@ Object {
|
||||
),
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
1826
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff-2.snap
Normal file
1826
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff-2.snap
Normal file
File diff suppressed because it is too large
Load Diff
134
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff-3.snap
Normal file
134
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff-3.snap
Normal file
@@ -0,0 +1,134 @@
|
||||
---
|
||||
source: objdiff-core/tests/arch_ppc.rs
|
||||
expression: output
|
||||
---
|
||||
[(Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mflr", 342), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(4), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stw", 443), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-8)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(8), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stwu", 444), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-336)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(12), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f800000", demangled_name: None, address: 388, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(16), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f800000", demangled_name: None, address: 388, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r11")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(20), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(272)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(24), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r10")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40000000", demangled_name: None, address: 384, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(28), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f13")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40000000", demangled_name: None, address: 384, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r10")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(32), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f13")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(276)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(36), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40400000", demangled_name: None, address: 380, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(40), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f12")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40400000", demangled_name: None, address: 380, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r9")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(44), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f12")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(280)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(48), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40800000", demangled_name: None, address: 376, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(52), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f11")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40800000", demangled_name: None, address: 376, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(56), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f11")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(284)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(60), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40a00000", demangled_name: None, address: 372, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(64), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f10")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40a00000", demangled_name: None, address: 372, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(68), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(256)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(72), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40c00000", demangled_name: None, address: 368, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(76), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f9")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40c00000", demangled_name: None, address: 368, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(80), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f9")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(260)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(84), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40e00000", demangled_name: None, address: 364, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(88), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f8")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@40e00000", demangled_name: None, address: 364, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(92), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(264)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(96), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@41000000", demangled_name: None, address: 360, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(100), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f7")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@41000000", demangled_name: None, address: 360, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(104), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(268)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(108), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(112), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f6")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(116), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(224)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(120), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(124), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r11")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(128), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(228)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(132), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r10")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(136), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r10")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(140), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(232)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(144), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(148), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lfs", 455), Normal, 10), (Argument(Opaque("f3")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "__real@3f000000", demangled_name: None, address: 356, size: 4, kind: Object, section: Some(4), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r9")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(152), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stfs", 459), Normal, 10), (Argument(Opaque("f3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(236)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(156), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(160), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(272)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(164), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "__lvx", demangled_name: None, address: 640, size: 24, kind: Function, section: Some(5), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(168), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(80)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(172), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(176), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(80)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(180), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(184), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(240)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(188), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(192), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(196), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(256)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(200), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "__lvx", demangled_name: None, address: 640, size: 24, kind: Function, section: Some(5), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(204), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(96)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(208), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(212), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(96)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(216), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v13")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(220), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(208)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(224), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v13")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(228), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(232), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(224)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(236), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "__lvx", demangled_name: None, address: 640, size: 24, kind: Function, section: Some(5), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(240), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(112)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(244), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r11")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(248), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(112)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(252), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v12")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r10")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(256), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(304)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(260), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v12")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r9")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(264), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(304)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(268), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v11")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(272), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(208)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(276), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(280), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(240)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(284), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v9")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(288), Normal, 5), (Spacing(4), Normal, 0), (Opcode("vmaddfp", 76), Normal, 10), (Argument(Opaque("v8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("v9")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("v10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("v11")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(292), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(128)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(296), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(300), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(128)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(304), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(308), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(192)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(312), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(316), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(208)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(320), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r11")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(324), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(240)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(328), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r10")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(332), Normal, 5), (Spacing(4), Normal, 0), (Opcode("vmsum4fp128", 203), Normal, 10), (Argument(Opaque("v4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("v5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("v6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(336), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(144)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(340), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r9")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(344), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(144)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(348), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(352), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(176)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(356), Normal, 5), (Spacing(4), Normal, 0), (Opcode("stvx128", 194), Normal, 10), (Argument(Opaque("v3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(360), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(364), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(288)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(368), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(192)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(372), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(376), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "__stvx", demangled_name: None, address: 664, size: 40, kind: Function, section: Some(5), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(380), Normal, 5), (Spacing(4), Normal, 0), (Opcode("li", 263), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(384), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(160)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(388), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(176)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(392), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(396), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "__stvx", demangled_name: None, address: 664, size: 40, kind: Function, section: Some(5), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(400), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4433", demangled_name: None, address: 32, size: 32, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(404), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4433", demangled_name: None, address: 32, size: 32, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(408), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "printf", demangled_name: None, address: 0, size: 0, kind: Function, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(412), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(240)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(416), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r3")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(420), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4434", demangled_name: None, address: 64, size: 8, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(424), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r11")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4434", demangled_name: None, address: 64, size: 8, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(428), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "?PrintVector@@YAXPBDU__vector4@@@Z", demangled_name: Some("void __cdecl PrintVector(char const *, struct __vector4)"), address: 0, size: 120, kind: Function, section: Some(5), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(432), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r10")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(208)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(436), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r10")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(440), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4435", demangled_name: None, address: 72, size: 8, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(444), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r9")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4435", demangled_name: None, address: 72, size: 8, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(448), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "?PrintVector@@YAXPBDU__vector4@@@Z", demangled_name: Some("void __cdecl PrintVector(char const *, struct __vector4)"), address: 0, size: 120, kind: Function, section: Some(5), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(452), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(192)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(456), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(460), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4436", demangled_name: None, address: 80, size: 12, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(464), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4436", demangled_name: None, address: 80, size: 12, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(468), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "?PrintVector@@YAXPBDU__vector4@@@Z", demangled_name: Some("void __cdecl PrintVector(char const *, struct __vector4)"), address: 0, size: 120, kind: Function, section: Some(5), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(472), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(176)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(476), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lvx128", 187), Normal, 10), (Argument(Opaque("v1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(480), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4437", demangled_name: None, address: 92, size: 12, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(484), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4437", demangled_name: None, address: 92, size: 12, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(488), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "?PrintVector@@YAXPBDU__vector4@@@Z", demangled_name: Some("void __cdecl PrintVector(char const *, struct __vector4)"), address: 0, size: 120, kind: Function, section: Some(5), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(492), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lis", 264), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4438", demangled_name: None, address: 104, size: 4, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@h"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(496), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "$SG4438", demangled_name: None, address: 104, size: 4, kind: Object, section: Some(4), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Basic("@l"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(500), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bl", 267), Normal, 10), (Symbol(Symbol { name: "printf", demangled_name: None, address: 0, size: 0, kind: Function, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(504), Normal, 5), (Spacing(4), Normal, 0), (Opcode("addi", 263), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(336)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(508), Normal, 5), (Spacing(4), Normal, 0), (Opcode("lwz", 439), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Signed(-8)), Normal, 0), (Basic("("), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(512), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mtlr", 348), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(516), Normal, 5), (Spacing(4), Normal, 0), (Opcode("blr", 269), Normal, 10), (Eol, Normal, 0)]
|
||||
2442
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff.snap
Normal file
2442
objdiff-core/tests/snapshots/arch_ppc__read_vmx128_coff.snap
Normal file
File diff suppressed because it is too large
Load Diff
@@ -207,4 +207,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -1574,4 +1574,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -311,4 +311,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
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,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
@@ -542,7 +542,7 @@ impl App {
|
||||
Ok(()) => state.config_error = None,
|
||||
Err(e) => {
|
||||
log::error!("Failed to load project config: {e}");
|
||||
state.config_error = Some(format!("{e}"));
|
||||
state.config_error = Some(e.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn load_font_family(
|
||||
) -> Option<LoadedFontFamily> {
|
||||
let family_handle = source.select_family_by_name(name).ok()?;
|
||||
if family_handle.fonts().is_empty() {
|
||||
log::warn!("No fonts found for family '{}'", name);
|
||||
log::warn!("No fonts found for family '{name}'");
|
||||
return None;
|
||||
}
|
||||
let handles = family_handle.fonts().to_vec();
|
||||
@@ -34,7 +34,7 @@ pub fn load_font_family(
|
||||
match font_kit::loaders::default::Font::from_handle(handle) {
|
||||
Ok(font) => loaded.push(font),
|
||||
Err(err) => {
|
||||
log::warn!("Failed to load font '{}': {}", name, err);
|
||||
log::warn!("Failed to load font '{name}': {err}");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ pub fn load_font_if_needed(
|
||||
egui::FontFamily::Name(v) => v,
|
||||
};
|
||||
let family = load_font_family(source, family_name)
|
||||
.with_context(|| format!("Failed to load font family '{}'", family_name))?;
|
||||
.with_context(|| format!("Failed to load font family '{family_name}'"))?;
|
||||
let default_fonts = fonts.families.get(&base_family).cloned().unwrap_or_default();
|
||||
// FIXME clean up
|
||||
let default_font_ref = family.fonts.get(family.default_index).unwrap();
|
||||
|
||||
@@ -23,6 +23,8 @@ pub struct Appearance {
|
||||
#[serde(skip)]
|
||||
pub highlight_color: Color32, // WHITE
|
||||
#[serde(skip)]
|
||||
pub dataflow_color: Color32, //
|
||||
#[serde(skip)]
|
||||
pub replace_color: Color32, // LIGHT_BLUE
|
||||
#[serde(skip)]
|
||||
pub insert_color: Color32, // GREEN
|
||||
@@ -61,6 +63,7 @@ impl Default for Appearance {
|
||||
emphasized_text_color: Color32::LIGHT_GRAY,
|
||||
deemphasized_text_color: Color32::DARK_GRAY,
|
||||
highlight_color: Color32::WHITE,
|
||||
dataflow_color: Color32::from_rgb(0, 128, 128),
|
||||
replace_color: Color32::LIGHT_BLUE,
|
||||
insert_color: Color32::GREEN,
|
||||
delete_color: Color32::from_rgb(200, 40, 41),
|
||||
@@ -104,6 +107,7 @@ impl Appearance {
|
||||
self.emphasized_text_color = Color32::LIGHT_GRAY;
|
||||
self.deemphasized_text_color = Color32::DARK_GRAY;
|
||||
self.highlight_color = Color32::WHITE;
|
||||
self.dataflow_color = Color32::from_rgb(0, 128, 128);
|
||||
self.replace_color = Color32::LIGHT_BLUE;
|
||||
self.insert_color = Color32::GREEN;
|
||||
self.delete_color = Color32::from_rgb(200, 40, 41);
|
||||
@@ -114,6 +118,7 @@ impl Appearance {
|
||||
self.emphasized_text_color = Color32::DARK_GRAY;
|
||||
self.deemphasized_text_color = Color32::LIGHT_GRAY;
|
||||
self.highlight_color = Color32::BLACK;
|
||||
self.dataflow_color = Color32::from_rgb(0, 128, 128);
|
||||
self.replace_color = Color32::DARK_BLUE;
|
||||
self.insert_color = Color32::DARK_GREEN;
|
||||
self.delete_color = Color32::from_rgb(200, 40, 41);
|
||||
@@ -136,7 +141,7 @@ impl Appearance {
|
||||
) {
|
||||
Ok(()) => self.ui_font = next_ui_font,
|
||||
Err(e) => {
|
||||
log::error!("Failed to load font: {}", e)
|
||||
log::error!("Failed to load font: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +155,7 @@ impl Appearance {
|
||||
) {
|
||||
Ok(()) => self.code_font = next_code_font,
|
||||
Err(e) => {
|
||||
log::error!("Failed to load font: {}", e)
|
||||
log::error!("Failed to load font: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +172,7 @@ impl Appearance {
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("Failed to load font: {}", e);
|
||||
log::error!("Failed to load font: {e}");
|
||||
// Revert to default
|
||||
self.ui_font = DEFAULT_UI_FONT;
|
||||
}
|
||||
@@ -181,7 +186,7 @@ impl Appearance {
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("Failed to load font: {}", e);
|
||||
log::error!("Failed to load font: {e}");
|
||||
// Revert to default
|
||||
self.code_font = DEFAULT_CODE_FONT;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ fn object_context_ui(ui: &mut egui::Ui, object: &ObjectConfig) {
|
||||
.on_hover_text("Open the source file in the default editor")
|
||||
.clicked()
|
||||
{
|
||||
log::info!("Opening file {}", source_path);
|
||||
log::info!("Opening file {source_path}");
|
||||
if let Err(e) = open::that_detached(source_path.as_str()) {
|
||||
log::error!("Failed to open source file: {e}");
|
||||
}
|
||||
@@ -509,7 +509,7 @@ fn format_path(path: &Option<Utf8PlatformPathBuf>, appearance: &Appearance) -> R
|
||||
.and_then(|home| check_path_buf(home).ok())
|
||||
.and_then(|home| dir.strip_prefix(&home).ok())
|
||||
{
|
||||
format!("~{}{}", MAIN_SEPARATOR, rel)
|
||||
format!("~{MAIN_SEPARATOR}{rel}")
|
||||
} else {
|
||||
dir.to_string()
|
||||
}
|
||||
@@ -808,7 +808,7 @@ fn split_obj_config_ui(
|
||||
for (idx, glob) in state.config.watch_patterns.iter().enumerate() {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(
|
||||
RichText::new(format!("{}", glob))
|
||||
RichText::new(glob.to_string())
|
||||
.color(appearance.text_color)
|
||||
.family(FontFamily::Monospace),
|
||||
);
|
||||
|
||||
@@ -147,14 +147,20 @@ pub(crate) fn data_row_ui(
|
||||
cur_addr += diff.len;
|
||||
} else {
|
||||
for byte in &diff.data {
|
||||
let mut byte_text = format!("{byte:02x} ");
|
||||
let mut byte_color = base_color;
|
||||
if let Some(reloc_diff) = reloc_diffs.iter().find(|reloc_diff| {
|
||||
reloc_diff.kind != DataDiffKind::None
|
||||
&& reloc_diff.range.contains(&cur_addr_actual)
|
||||
}) {
|
||||
byte_color = get_color_for_diff_kind(reloc_diff.kind, appearance);
|
||||
if let Some(reloc_diff) = reloc_diffs
|
||||
.iter()
|
||||
.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);
|
||||
}
|
||||
}
|
||||
let byte_text = format!("{byte:02x} ");
|
||||
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
||||
cur_addr += 1;
|
||||
cur_addr_actual += 1;
|
||||
|
||||
@@ -49,7 +49,9 @@ impl<'a> DiffColumnContext<'a> {
|
||||
let selected_symbol = match view {
|
||||
View::SymbolDiff => None,
|
||||
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,
|
||||
},
|
||||
View::DataDiff => match (obj, selected_symbol) {
|
||||
@@ -279,6 +281,24 @@ pub fn diff_view_ui(
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Only need to check the first Object. Technically the first could not have a flow analysis
|
||||
// result while the second does but we don't want to waste space on two separate checkboxes.
|
||||
if state.current_view == View::FunctionDiff
|
||||
&& result
|
||||
.first_obj
|
||||
.as_ref()
|
||||
.is_some_and(|(first, _)| first.has_flow_analysis_result())
|
||||
{
|
||||
let mut value = diff_config.show_data_flow;
|
||||
if ui
|
||||
.checkbox(&mut value, "Show data flow")
|
||||
.on_hover_text("Show data flow analysis results in place of register names")
|
||||
.clicked()
|
||||
{
|
||||
ret = Some(DiffViewAction::SetShowDataFlow(value));
|
||||
}
|
||||
}
|
||||
} else if column == 1 {
|
||||
// Right column
|
||||
|
||||
@@ -370,14 +390,14 @@ pub fn diff_view_ui(
|
||||
let mut needs_separator = false;
|
||||
if let Some(match_percent) = symbol_diff.match_percent {
|
||||
let response = ui.label(
|
||||
RichText::new(format!("{:.2}%", match_percent))
|
||||
RichText::new(format!("{match_percent:.2}%"))
|
||||
.font(appearance.code_font.clone())
|
||||
.color(match_color_for_symbol(match_percent, appearance)),
|
||||
);
|
||||
if let Some((diff_score, max_score)) = symbol_diff.diff_score {
|
||||
response.on_hover_ui_at_pointer(|ui| {
|
||||
ui.label(
|
||||
RichText::new(format!("Score: {}/{}", diff_score, max_score))
|
||||
RichText::new(format!("Score: {diff_score}/{max_score}"))
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.text_color),
|
||||
);
|
||||
@@ -497,6 +517,7 @@ pub fn diff_view_ui(
|
||||
(state.current_view, left_ctx.obj, right_ctx.obj, left_ctx.section, right_ctx.section)
|
||||
{
|
||||
// Joint diff view
|
||||
hotkeys::check_scroll_hotkeys(ui, true);
|
||||
let left_total_bytes =
|
||||
left_section_diff.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
let right_total_bytes =
|
||||
@@ -779,10 +800,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> {
|
||||
obj.sections.iter().position(|section| section.name == section_name)
|
||||
}
|
||||
|
||||
@@ -146,17 +146,17 @@ fn diff_text_ui(
|
||||
let label_text = match segment.text {
|
||||
DiffText::Basic(text) => text.to_string(),
|
||||
DiffText::Line(num) => format!("{num} "),
|
||||
DiffText::Address(addr) => format!("{:x}:", addr),
|
||||
DiffText::Address(addr) => format!("{addr:x}:"),
|
||||
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
|
||||
DiffText::Argument(arg) => match arg {
|
||||
InstructionArgValue::Signed(v) => format!("{:#x}", ReallySigned(v)),
|
||||
InstructionArgValue::Unsigned(v) => format!("{:#x}", v),
|
||||
InstructionArgValue::Unsigned(v) => format!("{v:#x}"),
|
||||
InstructionArgValue::Opaque(v) => v.into_owned(),
|
||||
},
|
||||
DiffText::BranchDest(addr) => format!("{addr:x}"),
|
||||
DiffText::Symbol(sym) => sym.demangled_name.as_ref().unwrap_or(&sym.name).clone(),
|
||||
DiffText::Addend(addend) => match addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:#x}", addend),
|
||||
Ordering::Greater => format!("+{addend:#x}"),
|
||||
Ordering::Less => format!("-{:#x}", -addend),
|
||||
_ => String::new(),
|
||||
},
|
||||
@@ -174,6 +174,7 @@ fn diff_text_ui(
|
||||
DiffTextColor::Normal => appearance.text_color,
|
||||
DiffTextColor::Dim => appearance.deemphasized_text_color,
|
||||
DiffTextColor::Bright => appearance.emphasized_text_color,
|
||||
DiffTextColor::DataFlow => appearance.dataflow_color,
|
||||
DiffTextColor::Replace => appearance.replace_color,
|
||||
DiffTextColor::Delete => appearance.delete_color,
|
||||
DiffTextColor::Insert => appearance.insert_color,
|
||||
|
||||
@@ -157,7 +157,7 @@ pub fn graphics_window(
|
||||
state.should_relaunch = true;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to save graphics config: {:?}", e);
|
||||
log::error!("Failed to save graphics config: {e:?}");
|
||||
state.graphics_config.desired_backend = prev_backend;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub fn jobs_ui(ui: &mut egui::Ui, jobs: &mut JobQueue, appearance: &Appearance)
|
||||
bar.ui(ui);
|
||||
const STATUS_LENGTH: usize = 80;
|
||||
if let Some(err) = &status.error {
|
||||
let err_string = format!("{:#}", err);
|
||||
let err_string = format!("{err:#}");
|
||||
ui.colored_label(
|
||||
appearance.delete_color,
|
||||
if err_string.len() > STATUS_LENGTH - 10 {
|
||||
@@ -119,7 +119,7 @@ pub fn jobs_menu_ui(ui: &mut egui::Ui, jobs: &mut JobQueue, appearance: &Appeara
|
||||
}
|
||||
Ordering::Greater => {
|
||||
spinner.ui(ui);
|
||||
clicked |= ui.link(format!("{} running", running_jobs)).clicked();
|
||||
clicked |= ui.link(format!("{running_jobs} running")).clicked();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -135,9 +135,7 @@ pub fn jobs_menu_ui(ui: &mut egui::Ui, jobs: &mut JobQueue, appearance: &Appeara
|
||||
}
|
||||
Ordering::Greater => {
|
||||
clicked |= ui
|
||||
.link(
|
||||
RichText::new(format!("{} errors", error_jobs)).color(appearance.delete_color),
|
||||
)
|
||||
.link(RichText::new(format!("{error_jobs} errors")).color(appearance.delete_color))
|
||||
.clicked();
|
||||
}
|
||||
_ => (),
|
||||
|
||||
@@ -79,6 +79,8 @@ pub enum DiffViewAction {
|
||||
SetMapping(usize, usize),
|
||||
/// Set the show_mapped_symbols flag
|
||||
SetShowMappedSymbols(bool),
|
||||
/// Set the show_data_flow flag
|
||||
SetShowDataFlow(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
@@ -279,7 +281,7 @@ impl DiffViewState {
|
||||
if let Some(source_path) =
|
||||
state.config.selected_obj.as_ref().and_then(|obj| obj.source_path.as_ref())
|
||||
{
|
||||
log::info!("Opening file {}", source_path);
|
||||
log::info!("Opening file {source_path}");
|
||||
open::that_detached(source_path.as_str()).unwrap_or_else(|err| {
|
||||
log::error!("Failed to open source file: {err}");
|
||||
});
|
||||
@@ -350,10 +352,20 @@ impl DiffViewState {
|
||||
DiffViewAction::SetShowMappedSymbols(value) => {
|
||||
self.symbol_state.show_mapped_symbols = value;
|
||||
}
|
||||
DiffViewAction::SetShowDataFlow(value) => {
|
||||
let Ok(mut state) = state.write() else {
|
||||
return;
|
||||
};
|
||||
state.config.diff_obj_config.show_data_flow = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_symbol(&self, symbol_idx: Option<usize>, column: usize) -> Option<ResolvedSymbol> {
|
||||
fn resolve_symbol(
|
||||
&self,
|
||||
symbol_idx: Option<usize>,
|
||||
column: usize,
|
||||
) -> Option<ResolvedSymbol<'_>> {
|
||||
let symbol_idx = symbol_idx?;
|
||||
let result = self.build.as_deref()?;
|
||||
let (obj, diff) = match column {
|
||||
|
||||
4
objdiff-wasm/package-lock.json
generated
4
objdiff-wasm/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.0.0-beta.7",
|
||||
"version": "3.0.0-beta.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.0.0-beta.7",
|
||||
"version": "3.0.0-beta.11",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "objdiff-wasm",
|
||||
"version": "3.0.0-beta.7",
|
||||
"version": "3.0.0-beta.11",
|
||||
"description": "A local diffing tool for decompilation projects.",
|
||||
"author": {
|
||||
"name": "Luke Street",
|
||||
|
||||
@@ -24,14 +24,14 @@ wit_bindgen::generate!({
|
||||
use exports::objdiff::core::{
|
||||
diff::{
|
||||
DiffConfigBorrow, DiffResult, Guest as GuestDiff, GuestDiffConfig, GuestObject,
|
||||
GuestObjectDiff, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
||||
GuestObjectDiff, MappingConfig, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
|
||||
SymbolFlags, SymbolInfo, SymbolKind, SymbolRef,
|
||||
},
|
||||
display::{
|
||||
ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode,
|
||||
DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem,
|
||||
HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay,
|
||||
SectionDisplaySymbol, SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind,
|
||||
SymbolNavigationKind, SymbolRef,
|
||||
SymbolDisplay, SymbolFilter, SymbolNavigationKind,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -59,15 +59,17 @@ impl GuestDiff for Component {
|
||||
left: Option<ObjectBorrow>,
|
||||
right: Option<ObjectBorrow>,
|
||||
diff_config: DiffConfigBorrow,
|
||||
mapping_config: MappingConfig,
|
||||
) -> Result<DiffResult, String> {
|
||||
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);
|
||||
let result = diff::diff_objs(
|
||||
left.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
||||
right.as_ref().map(|o| o.get::<ResourceObject>().0.as_ref()),
|
||||
None,
|
||||
&diff_config,
|
||||
&diff::MappingConfig::default(),
|
||||
&mapping_config,
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(DiffResult {
|
||||
@@ -134,48 +136,47 @@ impl GuestDisplay for Component {
|
||||
name: d.name,
|
||||
size: d.size,
|
||||
match_percent: d.match_percent,
|
||||
symbols: d
|
||||
.symbols
|
||||
.into_iter()
|
||||
.map(|s| SectionDisplaySymbol {
|
||||
symbol: s.symbol as SymbolRef,
|
||||
is_mapping_symbol: s.is_mapping_symbol,
|
||||
})
|
||||
.collect(),
|
||||
symbols: d.symbols.into_iter().map(to_symbol_ref).collect(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn display_symbol(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
) -> SymbolDisplay {
|
||||
fn display_symbol(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> SymbolDisplay {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = obj_diff.0.as_ref();
|
||||
let obj_diff = &obj_diff.1;
|
||||
let symbol_idx = symbol_display.symbol as usize;
|
||||
let Some(symbol) = obj.symbols.get(symbol_idx) else {
|
||||
return SymbolDisplay { name: "<unknown>".to_string(), ..Default::default() };
|
||||
let symbol_display = from_symbol_ref(symbol_ref);
|
||||
let Some(symbol) = obj.symbols.get(symbol_display.symbol) else {
|
||||
return SymbolDisplay {
|
||||
info: SymbolInfo { name: "<unknown>".to_string(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
};
|
||||
let symbol_diff = if symbol_display.is_mapping_symbol {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_idx)
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_idx)
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
SymbolDisplay {
|
||||
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),
|
||||
flags: SymbolFlags::from(symbol.flags),
|
||||
align: symbol.align.map(|a| a.get()),
|
||||
virtual_address: symbol.virtual_address,
|
||||
info: 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,
|
||||
},
|
||||
target_symbol: symbol_diff.and_then(|sd| sd.target_symbol.map(|s| s as u32)),
|
||||
match_percent: symbol_diff.and_then(|sd| sd.match_percent),
|
||||
diff_score: symbol_diff.and_then(|sd| sd.diff_score),
|
||||
@@ -185,22 +186,22 @@ impl GuestDisplay for Component {
|
||||
|
||||
fn display_instruction_row(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
symbol_ref: SymbolRef,
|
||||
row_index: u32,
|
||||
diff_config: DiffConfigBorrow,
|
||||
) -> InstructionDiffRow {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = obj_diff.0.as_ref();
|
||||
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 {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_idx)
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} 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))
|
||||
else {
|
||||
@@ -208,7 +209,7 @@ impl GuestDisplay for Component {
|
||||
};
|
||||
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
|
||||
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));
|
||||
Ok(())
|
||||
})
|
||||
@@ -216,26 +217,22 @@ impl GuestDisplay for Component {
|
||||
InstructionDiffRow { segments, diff_kind: InstructionDiffKind::from(row.kind) }
|
||||
}
|
||||
|
||||
fn symbol_context(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
) -> Vec<ContextItem> {
|
||||
fn symbol_context(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> Vec<ContextItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
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)
|
||||
.into_iter()
|
||||
.map(|item| ContextItem::from(item))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn symbol_hover(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
) -> Vec<HoverItem> {
|
||||
fn symbol_hover(diff: ObjectDiffBorrow, symbol_ref: SymbolRef) -> Vec<HoverItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = obj_diff.0.as_ref();
|
||||
let addend = 0; // TODO
|
||||
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)
|
||||
.into_iter()
|
||||
.map(|item| HoverItem::from(item))
|
||||
@@ -244,22 +241,22 @@ impl GuestDisplay for Component {
|
||||
|
||||
fn instruction_context(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
symbol_ref: SymbolRef,
|
||||
row_index: u32,
|
||||
diff_config: DiffConfigBorrow,
|
||||
) -> Vec<ContextItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = obj_diff.0.as_ref();
|
||||
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 {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_idx)
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_idx)
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let Some(ins_ref) = symbol_diff
|
||||
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
||||
@@ -268,7 +265,7 @@ impl GuestDisplay for Component {
|
||||
return Vec::new();
|
||||
};
|
||||
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 {
|
||||
value: "Failed to resolve instruction".to_string(),
|
||||
label: Some("error".to_string()),
|
||||
@@ -291,22 +288,22 @@ impl GuestDisplay for Component {
|
||||
|
||||
fn instruction_hover(
|
||||
diff: ObjectDiffBorrow,
|
||||
symbol_display: SectionDisplaySymbol,
|
||||
symbol_ref: SymbolRef,
|
||||
row_index: u32,
|
||||
diff_config: DiffConfigBorrow,
|
||||
) -> Vec<HoverItem> {
|
||||
let obj_diff = diff.get::<ResourceObjectDiff>();
|
||||
let obj = obj_diff.0.as_ref();
|
||||
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 {
|
||||
obj_diff
|
||||
.mapping_symbols
|
||||
.iter()
|
||||
.find(|s| s.symbol_index == symbol_idx)
|
||||
.find(|s| s.symbol_index == symbol_display.symbol)
|
||||
.map(|s| &s.symbol_diff)
|
||||
} else {
|
||||
obj_diff.symbols.get(symbol_idx)
|
||||
obj_diff.symbols.get(symbol_display.symbol)
|
||||
};
|
||||
let Some(ins_ref) = symbol_diff
|
||||
.and_then(|sd| sd.instruction_rows.get(row_index as usize))
|
||||
@@ -315,7 +312,7 @@ impl GuestDisplay for Component {
|
||||
return Vec::new();
|
||||
};
|
||||
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 {
|
||||
label: "Error".to_string(),
|
||||
value: "Failed to resolve instruction".to_string(),
|
||||
@@ -404,6 +401,7 @@ impl From<diff::display::DiffTextColor> for DiffTextColor {
|
||||
diff::display::DiffTextColor::Replace => DiffTextColor::Replace,
|
||||
diff::display::DiffTextColor::Delete => DiffTextColor::Delete,
|
||||
diff::display::DiffTextColor::Insert => DiffTextColor::Insert,
|
||||
diff::display::DiffTextColor::DataFlow => DiffTextColor::DataFlow,
|
||||
diff::display::DiffTextColor::Rotating(v) => DiffTextColor::Rotating(v),
|
||||
}
|
||||
}
|
||||
@@ -497,20 +495,56 @@ impl GuestObject for ResourceObject {
|
||||
}
|
||||
|
||||
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();
|
||||
obj.symbols
|
||||
.iter()
|
||||
.position(|s| {
|
||||
s.name == name
|
||||
&& match section_name.as_deref() {
|
||||
Some(section_name) => {
|
||||
s.section.is_some_and(|n| obj.sections[n].name == section_name)
|
||||
}
|
||||
None => true,
|
||||
let symbol_idx = obj.symbols.iter().position(|s| {
|
||||
s.name == name
|
||||
&& match section_name.as_deref() {
|
||||
Some(section_name) => {
|
||||
s.section.is_some_and(|n| obj.sections[n].name == section_name)
|
||||
}
|
||||
})
|
||||
.map(|i| i as SymbolRef)
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,18 +614,28 @@ impl Default for SymbolFlags {
|
||||
fn default() -> Self { Self::empty() }
|
||||
}
|
||||
|
||||
impl Default for SymbolDisplay {
|
||||
impl Default for SymbolInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: u32::MAX,
|
||||
name: Default::default(),
|
||||
demangled_name: Default::default(),
|
||||
address: Default::default(),
|
||||
size: Default::default(),
|
||||
kind: Default::default(),
|
||||
section: Default::default(),
|
||||
section_name: Default::default(),
|
||||
flags: Default::default(),
|
||||
align: Default::default(),
|
||||
virtual_address: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SymbolDisplay {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
info: Default::default(),
|
||||
target_symbol: Default::default(),
|
||||
match_percent: Default::default(),
|
||||
diff_score: Default::default(),
|
||||
@@ -600,4 +644,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);
|
||||
|
||||
@@ -24,58 +24,8 @@ interface diff {
|
||||
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;
|
||||
|
||||
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 {
|
||||
unknown,
|
||||
function,
|
||||
@@ -94,17 +44,74 @@ interface display {
|
||||
ignored,
|
||||
}
|
||||
|
||||
record symbol-display {
|
||||
record symbol-info {
|
||||
id: symbol-ref,
|
||||
name: string,
|
||||
demangled-name: option<string>,
|
||||
address: u64,
|
||||
size: u64,
|
||||
kind: symbol-kind,
|
||||
section: option<u32>,
|
||||
section-name: option<string>,
|
||||
%flags: symbol-flags,
|
||||
align: option<u32>,
|
||||
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>,
|
||||
match-percent: option<f32>,
|
||||
diff-score: option<tuple<u64, u64>>,
|
||||
@@ -194,6 +201,7 @@ interface display {
|
||||
dim,
|
||||
bright,
|
||||
replace,
|
||||
data-flow,
|
||||
delete,
|
||||
insert,
|
||||
rotating(u8),
|
||||
@@ -232,36 +240,36 @@ interface display {
|
||||
|
||||
display-symbol: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
) -> symbol-display;
|
||||
|
||||
display-instruction-row: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
config: borrow<diff-config>,
|
||||
) -> instruction-diff-row;
|
||||
|
||||
symbol-context: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
) -> list<context-item>;
|
||||
|
||||
symbol-hover: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
) -> list<hover-item>;
|
||||
|
||||
instruction-context: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
config: borrow<diff-config>,
|
||||
) -> list<context-item>;
|
||||
|
||||
instruction-hover: func(
|
||||
diff: borrow<object-diff>,
|
||||
symbol: section-display-symbol,
|
||||
symbol: symbol-ref,
|
||||
row-index: u32,
|
||||
config: borrow<diff-config>,
|
||||
) -> list<hover-item>;
|
||||
|
||||
Reference in New Issue
Block a user