mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
committed by
Luke Street
co-authored by
Luke Street
parent
bbd8d9714f
commit
6d3c63ccd8
Generated
+57
-128
File diff suppressed because it is too large
Load Diff
@@ -155,7 +155,7 @@ cwextab = { version = "1.0", optional = true, git = "https://github.com/encounte
|
|||||||
ppc750cl = { version = "0.3", optional = true }
|
ppc750cl = { version = "0.3", optional = true }
|
||||||
|
|
||||||
# mips
|
# mips
|
||||||
rabbitizer = { version = "1.12", optional = true }
|
rabbitizer = { git = "https://github.com/Decompollaborate/rabbitizer.git", branch = "🦀", default-features = false, optional = true }
|
||||||
|
|
||||||
# x86
|
# x86
|
||||||
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
use alloc::{borrow::Cow, collections::BTreeMap, format, vec::Vec};
|
use alloc::{borrow::Cow, collections::BTreeMap, format, string::ToString, vec::Vec};
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use object::{
|
use object::{
|
||||||
elf, Endian, Endianness, File, FileFlags, Object, ObjectSection, ObjectSymbol, Relocation,
|
elf, Endian, Endianness, File, FileFlags, Object, ObjectSection, ObjectSymbol, Relocation,
|
||||||
RelocationFlags, RelocationTarget,
|
RelocationFlags, RelocationTarget,
|
||||||
};
|
};
|
||||||
use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
use rabbitizer::{
|
||||||
|
abi::Abi,
|
||||||
|
operands::{ValuedOperand, IU16},
|
||||||
|
registers_meta::Register,
|
||||||
|
Instruction, InstructionDisplayFlags, InstructionFlags, IsaExtension, IsaVersion, Vram,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
@@ -14,18 +18,10 @@ use crate::{
|
|||||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
||||||
};
|
};
|
||||||
|
|
||||||
static RABBITIZER_MUTEX: Mutex<()> = Mutex::new(());
|
|
||||||
|
|
||||||
fn configure_rabbitizer(abi: Abi) {
|
|
||||||
unsafe {
|
|
||||||
config::RabbitizerConfig_Cfg.reg_names.fpr_abi_names = abi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ObjArchMips {
|
pub struct ObjArchMips {
|
||||||
pub endianness: Endianness,
|
pub endianness: Endianness,
|
||||||
pub abi: Abi,
|
pub abi: Abi,
|
||||||
pub instr_category: InstrCategory,
|
pub isa_extension: Option<IsaExtension>,
|
||||||
pub ri_gp_value: i32,
|
pub ri_gp_value: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +35,8 @@ const R_MIPS15_S3: u32 = 119;
|
|||||||
|
|
||||||
impl ObjArchMips {
|
impl ObjArchMips {
|
||||||
pub fn new(object: &File) -> Result<Self> {
|
pub fn new(object: &File) -> Result<Self> {
|
||||||
let mut abi = Abi::NUMERIC;
|
let mut abi = Abi::O32;
|
||||||
let mut instr_category = InstrCategory::CPU;
|
let mut isa_extension = None;
|
||||||
match object.flags() {
|
match object.flags() {
|
||||||
FileFlags::None => {}
|
FileFlags::None => {}
|
||||||
FileFlags::Elf { e_flags, .. } => {
|
FileFlags::Elf { e_flags, .. } => {
|
||||||
@@ -51,14 +47,14 @@ impl ObjArchMips {
|
|||||||
if e_flags & elf::EF_MIPS_ABI2 != 0 {
|
if e_flags & elf::EF_MIPS_ABI2 != 0 {
|
||||||
Abi::N32
|
Abi::N32
|
||||||
} else {
|
} else {
|
||||||
Abi::NUMERIC
|
Abi::O32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
instr_category = match e_flags & EF_MIPS_MACH {
|
isa_extension = match e_flags & EF_MIPS_MACH {
|
||||||
EF_MIPS_MACH_ALLEGREX => InstrCategory::R4000ALLEGREX,
|
EF_MIPS_MACH_ALLEGREX => Some(IsaExtension::R4000ALLEGREX),
|
||||||
EF_MIPS_MACH_5900 => InstrCategory::R5900,
|
EF_MIPS_MACH_5900 => Some(IsaExtension::R5900),
|
||||||
_ => InstrCategory::CPU,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => bail!("Unsupported MIPS file flags"),
|
_ => bail!("Unsupported MIPS file flags"),
|
||||||
@@ -75,7 +71,7 @@ impl ObjArchMips {
|
|||||||
.map(|bytes| object.endianness().read_i32_bytes(bytes))
|
.map(|bytes| object.endianness().read_i32_bytes(bytes))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
Ok(Self { endianness: object.endianness(), abi, instr_category, ri_gp_value })
|
Ok(Self { endianness: object.endianness(), abi, isa_extension, ri_gp_value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,21 +85,25 @@ impl ObjArch for ObjArchMips {
|
|||||||
line_info: &BTreeMap<u64, u32>,
|
line_info: &BTreeMap<u64, u32>,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
) -> Result<ProcessCodeResult> {
|
) -> Result<ProcessCodeResult> {
|
||||||
let _guard = RABBITIZER_MUTEX.lock().map_err(|e| anyhow!("Failed to lock mutex: {e}"))?;
|
let isa_extension = match config.mips_instr_category {
|
||||||
configure_rabbitizer(match config.mips_abi {
|
MipsInstrCategory::Auto => self.isa_extension,
|
||||||
|
MipsInstrCategory::Cpu => None,
|
||||||
|
MipsInstrCategory::Rsp => Some(IsaExtension::RSP),
|
||||||
|
MipsInstrCategory::R3000gte => Some(IsaExtension::R3000GTE),
|
||||||
|
MipsInstrCategory::R4000allegrex => Some(IsaExtension::R4000ALLEGREX),
|
||||||
|
MipsInstrCategory::R5900 => Some(IsaExtension::R5900),
|
||||||
|
};
|
||||||
|
let instruction_flags = match isa_extension {
|
||||||
|
Some(extension) => InstructionFlags::new_extension(extension),
|
||||||
|
None => InstructionFlags::new_isa(IsaVersion::MIPS_III, None),
|
||||||
|
}
|
||||||
|
.with_abi(match config.mips_abi {
|
||||||
MipsAbi::Auto => self.abi,
|
MipsAbi::Auto => self.abi,
|
||||||
MipsAbi::O32 => Abi::O32,
|
MipsAbi::O32 => Abi::O32,
|
||||||
MipsAbi::N32 => Abi::N32,
|
MipsAbi::N32 => Abi::N32,
|
||||||
MipsAbi::N64 => Abi::N64,
|
MipsAbi::N64 => Abi::N64,
|
||||||
});
|
});
|
||||||
let instr_category = match config.mips_instr_category {
|
let display_flags = InstructionDisplayFlags::default().with_unknown_instr_comment(false);
|
||||||
MipsInstrCategory::Auto => self.instr_category,
|
|
||||||
MipsInstrCategory::Cpu => InstrCategory::CPU,
|
|
||||||
MipsInstrCategory::Rsp => InstrCategory::RSP,
|
|
||||||
MipsInstrCategory::R3000gte => InstrCategory::R3000GTE,
|
|
||||||
MipsInstrCategory::R4000allegrex => InstrCategory::R4000ALLEGREX,
|
|
||||||
MipsInstrCategory::R5900 => InstrCategory::R5900,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_address = address;
|
let start_address = address;
|
||||||
let end_address = address + code.len() as u64;
|
let end_address = address + code.len() as u64;
|
||||||
@@ -114,32 +114,35 @@ impl ObjArch for ObjArchMips {
|
|||||||
for chunk in code.chunks_exact(4) {
|
for chunk in code.chunks_exact(4) {
|
||||||
let reloc = relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
let reloc = relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||||
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
||||||
let instruction = Instruction::new(code, cur_addr, instr_category);
|
let instruction = Instruction::new(code, Vram::new(cur_addr), instruction_flags);
|
||||||
|
|
||||||
let formatted = instruction.disassemble(None, 0);
|
let formatted = instruction.display(&display_flags, None::<&str>, 0).to_string();
|
||||||
let op = instruction.unique_id as u16;
|
let op = instruction.opcode() as u16;
|
||||||
ops.push(op);
|
ops.push(op);
|
||||||
|
|
||||||
let mnemonic = instruction.opcode_name();
|
let mnemonic = instruction.opcode().name();
|
||||||
let is_branch = instruction.is_branch();
|
let mut branch_dest = instruction.get_branch_offset_generic().map(|a| a.inner() as u64);
|
||||||
let branch_offset = instruction.branch_offset();
|
|
||||||
let mut branch_dest = if is_branch {
|
|
||||||
cur_addr.checked_add_signed(branch_offset).map(|a| a as u64)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let operands = instruction.get_operands_slice();
|
let operands = instruction.valued_operands_iter();
|
||||||
let mut args = Vec::with_capacity(operands.len() + 1);
|
|
||||||
for (idx, op) in operands.iter().enumerate() {
|
let mut args = Vec::with_capacity(6);
|
||||||
|
for (idx, op) in operands.enumerate() {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
args.push(ObjInsArg::PlainText(config.separator().into()));
|
args.push(ObjInsArg::PlainText(config.separator().into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
OperandType::cpu_immediate
|
ValuedOperand::core_immediate(imm) => {
|
||||||
| OperandType::cpu_label
|
if let Some(reloc) = reloc {
|
||||||
| OperandType::cpu_branch_target_label => {
|
push_reloc(&mut args, reloc)?;
|
||||||
|
} else {
|
||||||
|
args.push(ObjInsArg::Arg(match imm {
|
||||||
|
IU16::Integer(s) => ObjInsArgValue::Signed(s as i64),
|
||||||
|
IU16::Unsigned(u) => ObjInsArgValue::Unsigned(u as u64),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValuedOperand::core_label(..) | ValuedOperand::core_branch_target_label(..) => {
|
||||||
if let Some(reloc) = reloc {
|
if let Some(reloc) = reloc {
|
||||||
// If the relocation target is within the current function, we can
|
// If the relocation target is within the current function, we can
|
||||||
// convert it into a relative branch target. Note that we check
|
// convert it into a relative branch target. Note that we check
|
||||||
@@ -161,25 +164,29 @@ impl ObjArch for ObjArchMips {
|
|||||||
args.push(ObjInsArg::BranchDest(branch_dest));
|
args.push(ObjInsArg::BranchDest(branch_dest));
|
||||||
} else {
|
} else {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
op.disassemble(&instruction, None).into(),
|
op.display(&instruction, &display_flags, None::<&str>)
|
||||||
|
.to_string()
|
||||||
|
.into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperandType::cpu_immediate_base => {
|
ValuedOperand::core_immediate_base(imm, base) => {
|
||||||
if let Some(reloc) = reloc {
|
if let Some(reloc) = reloc {
|
||||||
push_reloc(&mut args, reloc)?;
|
push_reloc(&mut args, reloc)?;
|
||||||
} else {
|
} else {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(match imm {
|
||||||
OperandType::cpu_immediate.disassemble(&instruction, None).into(),
|
IU16::Integer(s) => ObjInsArgValue::Signed(s as i64),
|
||||||
)));
|
IU16::Unsigned(u) => ObjInsArgValue::Unsigned(u as u64),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
args.push(ObjInsArg::PlainText("(".into()));
|
args.push(ObjInsArg::PlainText("(".into()));
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
OperandType::cpu_rs.disassemble(&instruction, None).into(),
|
base.either_name(instruction.flags().abi(), display_flags.named_gpr())
|
||||||
|
.into(),
|
||||||
)));
|
)));
|
||||||
args.push(ObjInsArg::PlainText(")".into()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
// OperandType::r5900_immediate15 => match reloc {
|
// ValuedOperand::r5900_immediate15(..) => match reloc {
|
||||||
// Some(reloc)
|
// Some(reloc)
|
||||||
// if reloc.flags == RelocationFlags::Elf { r_type: R_MIPS15_S3 } =>
|
// if reloc.flags == RelocationFlags::Elf { r_type: R_MIPS15_S3 } =>
|
||||||
// {
|
// {
|
||||||
@@ -193,7 +200,9 @@ impl ObjArch for ObjArchMips {
|
|||||||
// },
|
// },
|
||||||
_ => {
|
_ => {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
op.disassemble(&instruction, None).into(),
|
op.display(&instruction, &display_flags, None::<&str>)
|
||||||
|
.to_string()
|
||||||
|
.into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user