Compare commits

..

14 Commits

Author SHA1 Message Date
Luke Street 1205e8ceb4 Version v3.0.0-beta.12 2025-07-29 21:31:12 -06:00
Luke Street c917cad5f0 Strip zeros from end of inferred function sizes
Resolves #3
2025-07-29 21:20:47 -06:00
Luke Street dd653329f5 Fix reading IMAGE_REL_PPC_REFHI/REFLO without PAIR 2025-07-29 20:58:34 -06:00
Luke Street f5d3d5f10a gui: Split OpenGL into OpenGL (glow), OpenGL ES (wgpu) 2025-07-29 20:49:09 -06:00
Luke Street c327ed3ea8 Update to egui 0.32 (& update all deps) 2025-07-28 17:30:52 -06:00
Ethan Roseman 85fb18a21a Update rabbitizer to v2.0.0-alpha.4 (#226)
* Update rabbitizer to v2.0.0-alpha.4

* Cargo update
2025-07-27 22:13:42 -06:00
Luke Street 00ad0d8094 Support PPC64 ELFs (PS3); refactor relocation processing 2025-07-21 21:01:03 -06:00
Luke Street 8fac63c42c Remove temporary test 2025-07-17 21:23:12 -06:00
Luke Street 0fb7f3901c Add PPC COFF tests; fix IMAGE_REL_PPC_PAIR handling 2025-07-17 21:19:16 -06:00
Mark Langen 3385f58341 Fix data flow analysis for multiple text sections (#220)
* Fix data flow analysis for multiple text sections

* Data flow analysis results were only keyed by the symbol (function)
  address. That doen't work if there are multiple text sections, the
  result from the first function in one section will stomp the result
  from the first function in another because both have address zero.

* Remove the ambiguity by keying off of the section address as well.

* Formatting

* Satisfy wasm build

* Clippy

* Formatting again

* Thought that section was the section address not the section number.

---------

Co-authored-by: Luke Street <luke.street@encounterpc.com>
2025-07-17 16:04:56 -06:00
Luke Street 60b227f45e Support PowerPC COFF (Xenon, Xbox 360)
ppc750cl is superseded by the powerpc crate, which
supports PPC64, AltiVec and VMX128 extensions.
2025-07-17 13:33:12 -06:00
LagoLunatic 127ae5ae44 PPC pooled relocations: Ignore hidden symbols (#221)
* PPC pooled relocations: Ignore hidden symbols

* PPC pooled relocations: Also ignore 'ignored' symbols
2025-07-07 17:29:05 -06:00
Luke Street 5f48e69775 More clippy fixes 2025-07-07 15:29:30 -06:00
Luke Street 8756eee07b clippy fixes & version bump 2025-07-07 14:56:41 -06:00
50 changed files with 6414 additions and 2218 deletions
Generated
+799 -673
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -14,9 +14,9 @@ strip = "debuginfo"
codegen-units = 1
[workspace.package]
version = "3.0.0-beta.10"
version = "3.0.0-beta.12"
authors = ["Luke Street <luke@street.dev>"]
edition = "2024"
license = "MIT OR Apache-2.0"
repository = "https://github.com/encounter/objdiff"
rust-version = "1.85"
rust-version = "1.88"
+1 -1
View File
@@ -19,7 +19,7 @@ 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, x86_64 (PC)
+2 -2
View File
@@ -15,11 +15,11 @@ publish = false
[dependencies]
anyhow = "1.0"
argp = "0.4"
crossterm = "0.28"
crossterm = "0.29"
enable-ansi-support = "0.2"
memmap2 = "0.9"
objdiff-core = { path = "../objdiff-core", features = ["all"] }
prost = "0.13"
prost = "0.14"
ratatui = "0.29"
rayon = "1.10"
serde = { version = "1.0", features = ["derive"] }
+3 -7
View File
@@ -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)?;
+5 -7
View File
@@ -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 =
@@ -433,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}"))
}
+4 -4
View File
@@ -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(
@@ -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(),
},
+14 -14
View File
@@ -92,7 +92,7 @@ ppc = [
"any-arch",
"dep:cwdemangle",
"dep:cwextab",
"dep:ppc750cl",
"dep:powerpc",
"dep:rlwinmdec",
]
x86 = [
@@ -123,14 +123,14 @@ features = ["all"]
[dependencies]
anyhow = { version = "1.0", default-features = false }
filetime = { version = "0.2", optional = true }
flagset = { version = "0.4", default-features = false, optional = true, git = "https://github.com/enarx/flagset.git", rev = "a1fe9369b3741e43fec45da1998e83b9d78966a2" }
flagset = { version = "0.4", default-features = false, optional = true }
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"] }
pbjson = { version = "0.7", default-features = false, optional = true }
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
pbjson = { version = "0.8", default-features = false, optional = true }
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
regex = { version = "1.11", default-features = false, features = [], optional = true }
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
similar = { version = "2.7", default-features = false, features = ["hashbrown"], optional = true, git = "https://github.com/encounter/similar.git", branch = "no_std" }
@@ -142,16 +142,16 @@ semver = { version = "1.0", default-features = false, optional = true }
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
# dwarf
gimli = { version = "0.31", default-features = false, features = ["read"], optional = true }
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
# ppc
cwdemangle = { version = "1.0", optional = true }
cwextab = { version = "1.0", optional = true }
ppc750cl = { version = "0.3", optional = true }
cwextab = { version = "1.1", optional = true }
powerpc = { version = "0.4", optional = true }
rlwinmdec = { version = "1.1", optional = true }
# mips
rabbitizer = { version = "2.0.0-alpha.1", default-features = false, features = ["all_extensions"], optional = true }
rabbitizer = { version = "2.0.0-alpha.4", default-features = false, features = ["all_extensions"], optional = true }
# x86
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
@@ -159,7 +159,7 @@ iced-x86 = { version = "1.21", default-features = false, features = ["decoder",
msvc-demangler = { version = "0.11", optional = true }
# arm
unarm = { version = "1.8", optional = true }
unarm = { version = "1.9", optional = true }
arm-attr = { version = "0.2", optional = true }
# arm64
@@ -167,10 +167,10 @@ yaxpeax-arch = { version = "0.3", default-features = false, optional = true }
yaxpeax-arm = { version = "0.3", default-features = false, optional = true }
# build
notify = { version = "8.0.0", optional = true }
notify = { version = "8.1.0", optional = true }
notify-debouncer-full = { version = "0.5.0", optional = true }
shell-escape = { version = "0.1", optional = true }
tempfile = { version = "3.19", optional = true }
tempfile = { version = "3.20", optional = true }
time = { version = "0.3", optional = true }
encoding_rs = { version = "0.8.35", optional = true }
@@ -189,10 +189,10 @@ self_update = { version = "0.42", optional = true }
[build-dependencies]
heck = { version = "0.5", optional = true }
pbjson-build = { version = "0.7", optional = true }
pbjson-build = { version = "0.8", optional = true }
prettyplease = { version = "0.2", optional = true }
proc-macro2 = { version = "1.0", optional = true }
prost-build = { version = "0.13", optional = true }
prost-build = { version = "0.14", optional = true }
quote = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
+1 -1
View File
@@ -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).
+5 -5
View File
@@ -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),
}
}
}
+48 -38
View File
@@ -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,
@@ -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()))?;
+2 -13
View File
@@ -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(_, _)
+67 -53
View File
@@ -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(
+51 -39
View File
@@ -1,4 +1,10 @@
use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
use alloc::{
borrow::Cow,
boxed::Box,
format,
string::{String, ToString},
vec::Vec,
};
use core::{
ffi::CStr,
fmt::{self, Debug},
@@ -49,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",
})
}
}
@@ -66,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
}
@@ -100,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));
@@ -108,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));
@@ -116,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));
@@ -124,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));
@@ -151,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())));
@@ -351,14 +357,15 @@ pub trait Arch: Send + Sync + Debug {
None
}
fn implcit_addend(
fn relocation_override(
&self,
file: &object::File<'_>,
section: &object::Section,
address: u64,
relocation: &object::Relocation,
flags: RelocationFlags,
) -> Result<i64>;
_file: &object::File<'_>,
_section: &object::Section,
_address: u64,
_relocation: &object::Relocation,
) -> Result<Option<RelocationOverride>> {
Ok(None)
}
fn demangle(&self, _name: &str) -> Option<String> { None }
@@ -405,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")]
@@ -450,16 +459,19 @@ 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 }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelocationOverrideTarget {
Keep,
Skip,
Symbol(object::SymbolIndex),
Section(object::SectionIndex),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RelocationOverride {
pub target: RelocationOverrideTarget,
pub addend: i64,
}
+50 -41
View File
@@ -11,7 +11,7 @@ use core::{
};
use itertools::Itertools;
use ppc750cl::Simm;
use powerpc::{Extensions, Simm};
use crate::{
arch::DataType,
@@ -19,8 +19,8 @@ use crate::{
util::{RawDouble, RawFloat},
};
fn is_store_instruction(op: ppc750cl::Opcode) -> bool {
use ppc750cl::Opcode;
fn is_store_instruction(op: powerpc::Opcode) -> bool {
use powerpc::Opcode;
matches!(
op,
Opcode::Stbux
@@ -52,8 +52,8 @@ fn is_store_instruction(op: ppc750cl::Opcode) -> bool {
)
}
pub fn guess_data_type_from_load_store_inst_op(inst_op: ppc750cl::Opcode) -> Option<DataType> {
use ppc750cl::Opcode;
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),
@@ -92,7 +92,7 @@ impl core::fmt::Display for RegisterContent {
// -i is safe because it's at most a 16 bit constant in the i32
{
if *i >= 0 {
write!(f, "0x{:x}", i)
write!(f, "0x{i:x}")
} else {
write!(f, "-0x{:x}", -i)
}
@@ -118,12 +118,12 @@ impl RegisterState {
// During a function call, these registers must be assumed trashed.
fn clear_volatile(&mut self) {
self[ppc750cl::GPR(0)] = RegisterContent::Unknown;
self[powerpc::GPR(0)] = RegisterContent::Unknown;
for i in 0..=13 {
self[ppc750cl::GPR(i)] = RegisterContent::Unknown;
self[powerpc::GPR(i)] = RegisterContent::Unknown;
}
for i in 0..=13 {
self[ppc750cl::FPR(i)] = RegisterContent::Unknown;
self[powerpc::FPR(i)] = RegisterContent::Unknown;
}
}
@@ -132,10 +132,10 @@ impl RegisterState {
// they get overwritten with another value before getting read.
fn set_potential_inputs(&mut self) {
for g_reg in 3..=13 {
self[ppc750cl::GPR(g_reg)] = RegisterContent::InputRegister(g_reg);
self[powerpc::GPR(g_reg)] = RegisterContent::InputRegister(g_reg);
}
for f_reg in 1..=13 {
self[ppc750cl::FPR(f_reg)] = RegisterContent::InputRegister(f_reg);
self[powerpc::FPR(f_reg)] = RegisterContent::InputRegister(f_reg);
}
}
@@ -172,34 +172,34 @@ impl RegisterState {
}
}
impl Index<ppc750cl::GPR> for RegisterState {
impl Index<powerpc::GPR> for RegisterState {
type Output = RegisterContent;
fn index(&self, gpr: ppc750cl::GPR) -> &Self::Output { &self.gpr[gpr.0 as usize] }
fn index(&self, gpr: powerpc::GPR) -> &Self::Output { &self.gpr[gpr.0 as usize] }
}
impl IndexMut<ppc750cl::GPR> for RegisterState {
fn index_mut(&mut self, gpr: ppc750cl::GPR) -> &mut Self::Output {
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<ppc750cl::FPR> for RegisterState {
impl Index<powerpc::FPR> for RegisterState {
type Output = RegisterContent;
fn index(&self, fpr: ppc750cl::FPR) -> &Self::Output { &self.fpr[fpr.0 as usize] }
fn index(&self, fpr: powerpc::FPR) -> &Self::Output { &self.fpr[fpr.0 as usize] }
}
impl IndexMut<ppc750cl::FPR> for RegisterState {
fn index_mut(&mut self, fpr: ppc750cl::FPR) -> &mut Self::Output {
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: &ppc750cl::Opcode,
args: &ppc750cl::Arguments,
op: &powerpc::Opcode,
args: &powerpc::Arguments,
) {
use ppc750cl::{Argument, GPR, Opcode};
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
@@ -270,11 +270,11 @@ fn execute_instruction(
}
}
fn get_branch_offset(args: &ppc750cl::Arguments) -> i32 {
fn get_branch_offset(args: &powerpc::Arguments) -> i32 {
for arg in args.iter() {
match arg {
ppc750cl::Argument::BranchDest(dest) => return dest.0 / 4,
ppc750cl::Argument::None => break,
powerpc::Argument::BranchDest(dest) => return dest.0 / 4,
powerpc::Argument::None => break,
_ => {}
}
}
@@ -316,7 +316,7 @@ fn clamp_text_length(s: String, max: usize) -> String {
fn get_register_content_from_reloc(
reloc: &Relocation,
obj: &Object,
op: ppc750cl::Opcode,
op: powerpc::Opcode,
) -> RegisterContent {
if let Some(bytes) = obj.symbol_data(reloc.target_symbol) {
match guess_data_type_from_load_store_inst_op(op) {
@@ -354,18 +354,18 @@ fn fill_registers_from_relocation(
reloc: &Relocation,
current_state: &mut RegisterState,
obj: &Object,
op: ppc750cl::Opcode,
args: &ppc750cl::Arguments,
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
(_, ppc750cl::Argument::GPR(gpr)) => {
(_, powerpc::Argument::GPR(gpr)) => {
current_state[gpr] = get_register_content_from_reloc(reloc, obj, op);
}
(_, ppc750cl::Argument::FPR(fpr)) => {
(_, powerpc::Argument::FPR(fpr)) => {
current_state[fpr] = get_register_content_from_reloc(reloc, obj, op);
}
_ => {}
@@ -384,11 +384,12 @@ pub fn ppc_data_flow_analysis(
func_symbol: &Symbol,
code: &[u8],
relocations: &[Relocation],
extensions: Extensions,
) -> Box<dyn FlowAnalysisResult> {
use alloc::collections::VecDeque;
use ppc750cl::InsIter;
let instructions = InsIter::new(code, func_symbol.address as u32)
use powerpc::InsIter;
let instructions = InsIter::new(code, func_symbol.address as u32, extensions)
.map(|(_addr, ins)| (ins.op, ins.basic().args))
.collect_vec();
@@ -449,7 +450,7 @@ pub fn ppc_data_flow_analysis(
// 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 == &ppc750cl::Opcode::Bc {
if op == &powerpc::Opcode::Bc {
let branch_state = (index, current_state.clone());
if !taken_branches.contains(&branch_state) {
let offset = get_branch_offset(args);
@@ -468,7 +469,7 @@ pub fn ppc_data_flow_analysis(
}
// Update index
if op == &ppc750cl::Opcode::B {
if op == &powerpc::Opcode::B {
// Unconditional branch
let offset = get_branch_offset(args);
if offset > 0 {
@@ -502,7 +503,14 @@ pub fn ppc_data_flow_analysis(
}
// Store the relevant data flow values for simplified instructions
generate_flow_analysis_result(obj, func_address, code, register_state_at, relocations)
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> {
@@ -530,14 +538,15 @@ fn generate_flow_analysis_result(
code: &[u8],
register_state_at: Vec<RegisterState>,
relocations: &[Relocation],
extensions: Extensions,
) -> Box<PPCFlowAnalysisResult> {
use ppc750cl::{Argument, InsIter};
use powerpc::{Argument, InsIter};
let mut analysis_result = PPCFlowAnalysisResult::new();
let default_register_state = RegisterState::new();
for (addr, ins) in InsIter::new(code, 0) {
for (addr, ins) in InsIter::new(code, 0, extensions) {
let ins_address = base_address + (addr as u64);
let index = addr / 4;
let ppc750cl::ParsedIns { mnemonic: _, args } = ins.simplified();
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);
@@ -546,7 +555,7 @@ fn generate_flow_analysis_result(
// they are being loaded.
// We need to do this before we break out on showing relocations in the
// subsequent if statement.
if let (ppc750cl::Opcode::Lfs | ppc750cl::Opcode::Lfd, Some(reloc)) = (ins.op, reloc) {
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,
@@ -566,7 +575,7 @@ fn generate_flow_analysis_result(
// 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 (ppc750cl::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
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] {
@@ -625,7 +634,7 @@ fn generate_flow_analysis_result(
Some(FlowAnalysisValue::Text(reg_name))
}
Some(RegisterContent::Unknown) | Some(RegisterContent::Variable) => None,
Some(value) => Some(FlowAnalysisValue::Text(format!("{value}"))),
Some(value) => Some(FlowAnalysisValue::Text(value.to_string())),
None => None,
};
if let Some(analysis_value) = analysis_value {
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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 */"));
}
}
+22 -33
View File
@@ -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());
}
}
+25 -18
View File
@@ -9,7 +9,7 @@ use iced_x86::{
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},
};
@@ -225,40 +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)
| RelocationFlags::Elf(elf::R_386_32 | elf::R_386_PC32) => {
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)
| RelocationFlags::Elf(elf::R_X86_64_32 | elf::R_X86_64_PC32) => {
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)
| RelocationFlags::Elf(elf::R_X86_64_64) => {
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> {
+1 -1
View File
@@ -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")]

Some files were not shown because too many files have changed in this diff Show More