Reimplement x86 arch, MSVC section group combining

Plus display_row/DiffText refactoring
This commit is contained in:
Luke Street 2025-02-28 00:17:32 -07:00
parent 506c251d68
commit 95868f1d19
29 changed files with 2580 additions and 1044 deletions

View File

@ -235,7 +235,6 @@ jobs:
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@nightly
with:
targets: wasm32-wasip2
components: rust-src
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2

View File

@ -1,10 +1,10 @@
use std::cmp::Ordering;
use core::cmp::Ordering;
use anyhow::{bail, Result};
use crossterm::event::{Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind};
use objdiff_core::{
diff::{
display::{display_row, DiffText, HighlightKind},
display::{display_row, DiffText, DiffTextColor, HighlightKind},
DiffObjConfig, FunctionRelocDiffs, InstructionDiffKind, ObjectDiff, SymbolDiff,
},
obj::Object,
@ -522,87 +522,55 @@ impl FunctionDiffUi {
let mut sx = rect.x;
let sy = rect.y + y as u16;
let mut line = Line::default();
display_row(obj, symbol_index, ins_row, diff_config, |text, diff_idx| {
let label_text;
let mut base_color = match ins_row.kind {
InstructionDiffKind::None
| InstructionDiffKind::OpMismatch
| InstructionDiffKind::ArgMismatch => Color::Gray,
InstructionDiffKind::Replace => Color::Cyan,
InstructionDiffKind::Delete => Color::Red,
InstructionDiffKind::Insert => Color::Green,
};
if let Some(idx) = diff_idx.get() {
base_color = COLOR_ROTATION[idx as usize % COLOR_ROTATION.len()];
}
let mut pad_to = 0;
match text {
DiffText::Basic(text) => {
label_text = text.to_string();
}
DiffText::Line(num) => {
label_text = format!("{num} ");
base_color = Color::DarkGray;
pad_to = 5;
}
DiffText::Address(addr) => {
label_text = format!("{:x}:", addr);
pad_to = 5;
}
DiffText::Opcode(mnemonic, _op) => {
label_text = mnemonic.to_string();
if ins_row.kind == InstructionDiffKind::OpMismatch {
base_color = Color::Blue;
}
pad_to = 8;
}
DiffText::Argument(arg) => {
label_text = arg.to_string();
}
DiffText::BranchDest(addr) => {
label_text = format!("{addr:x}");
}
display_row(obj, symbol_index, ins_row, diff_config, |segment| {
let highlight_kind = HighlightKind::from(&segment.text);
let label_text = match segment.text {
DiffText::Basic(text) => text.to_string(),
DiffText::Line(num) => format!("{num} "),
DiffText::Address(addr) => format!("{:x}:", addr),
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
DiffText::Argument(arg) => arg.to_string(),
DiffText::BranchDest(addr) => format!("{addr:x}"),
DiffText::Symbol(sym) => {
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
label_text = name.clone();
if diff_idx.is_none() {
base_color = Color::White;
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone()
}
}
DiffText::Addend(addend) => {
label_text = match addend.cmp(&0i64) {
DiffText::Addend(addend) => match addend.cmp(&0i64) {
Ordering::Greater => format!("+{:#x}", addend),
Ordering::Less => format!("-{:#x}", -addend),
_ => "".to_string(),
};
if diff_idx.is_none() {
base_color = Color::White;
}
}
_ => String::new(),
},
DiffText::Spacing(n) => {
line.spans.push(Span::raw(" ".repeat(n)));
line.spans.push(Span::raw(" ".repeat(n as usize)));
sx += n as u16;
return Ok(());
}
DiffText::Eol => {
return Ok(());
}
}
DiffText::Eol => return Ok(()),
};
let len = label_text.len();
let highlighted = *highlight == text;
let highlighted =
highlight_kind != HighlightKind::None && *highlight == highlight_kind;
if let Some((cx, cy)) = result.click_xy {
if cx >= sx && cx < sx + len as u16 && cy == sy {
new_highlight = Some(text.into());
new_highlight = Some(highlight_kind);
}
}
let mut style = Style::new().fg(base_color);
let mut style = Style::new().fg(match segment.color {
DiffTextColor::Normal => Color::Gray,
DiffTextColor::Dim => Color::DarkGray,
DiffTextColor::Bright => Color::White,
DiffTextColor::Replace => Color::Cyan,
DiffTextColor::Delete => Color::Red,
DiffTextColor::Insert => Color::Green,
DiffTextColor::Rotating(i) => COLOR_ROTATION[i as usize % COLOR_ROTATION.len()],
});
if highlighted {
style = style.bg(Color::DarkGray);
}
line.spans.push(Span::styled(label_text, style));
sx += len as u16;
if pad_to > len {
let pad = (pad_to - len) as u16;
if segment.pad_to as usize > len {
let pad = (segment.pad_to as usize - len) as u16;
line.spans.push(Span::raw(" ".repeat(pad as usize)));
sx += pad;
}

View File

@ -26,7 +26,7 @@ all = [
"arm64",
"mips",
"ppc",
# "x86",
"x86",
]
# Implicit, used to check if any arch is enabled
any-arch = [

View File

@ -16,8 +16,8 @@ use crate::{
arch::Arch,
diff::{display::InstructionPart, ArmArchVersion, ArmR9Usage, DiffObjConfig},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, RelocationFlags, ResolvedRelocation,
ScannedInstruction, SymbolFlag, SymbolFlagSet, SymbolKind,
InstructionRef, RelocationFlags, ResolvedRelocation, ScannedInstruction, SymbolFlag,
SymbolFlagSet, SymbolKind,
},
};
@ -261,9 +261,9 @@ impl Arch for ArchArm {
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
) -> Result<()> {
let (ins, parsed_ins) = self.parse_ins_ref(ins_ref, code, diff_config)?;
cb(InstructionPart::Opcode(Cow::Borrowed(parsed_ins.mnemonic), ins_ref.opcode))?;
cb(InstructionPart::opcode(parsed_ins.mnemonic, ins_ref.opcode))?;
if ins == unarm::Ins::Data && relocation.is_some() {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::reloc())?;
} else {
push_args(
&parsed_ins,
@ -396,12 +396,10 @@ fn push_args(
})
| args::Argument::CoOption(_) => {
deref = false;
arg_cb(InstructionPart::Basic("]"))?;
arg_cb(InstructionPart::basic("]"))?;
if writeback {
writeback = false;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("!".into()),
)))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
_ => {}
@ -409,130 +407,98 @@ fn push_args(
}
if i > 0 {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
if reloc_arg == Some(i) {
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::reloc())?;
} else {
match arg {
args::Argument::None => {}
args::Argument::Reg(reg) => {
if reg.deref {
deref = true;
arg_cb(InstructionPart::Basic("["))?;
arg_cb(InstructionPart::basic("["))?;
}
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
reg.reg.display(display_options.reg_names).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
reg.reg.display(display_options.reg_names).to_string(),
))?;
if reg.writeback {
if reg.deref {
writeback = true;
} else {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("!".into()),
)))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
}
args::Argument::RegList(reg_list) => {
arg_cb(InstructionPart::Basic("{"))?;
arg_cb(InstructionPart::basic("{"))?;
let mut first = true;
for i in 0..16 {
if (reg_list.regs & (1 << i)) != 0 {
if !first {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
arg_cb(InstructionPart::opaque(
args::Register::parse(i)
.display(display_options.reg_names)
.to_string()
.into(),
),
)))?;
.to_string(),
))?;
first = false;
}
}
arg_cb(InstructionPart::Basic("}"))?;
arg_cb(InstructionPart::basic("}"))?;
if reg_list.user_mode {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("^".into()),
)))?;
arg_cb(InstructionPart::opaque("^"))?;
}
}
args::Argument::UImm(value)
| args::Argument::CoOpcode(value)
| args::Argument::SatImm(value) => {
arg_cb(InstructionPart::Basic("#"))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(*value as u64),
)))?;
arg_cb(InstructionPart::basic("#"))?;
arg_cb(InstructionPart::unsigned(*value))?;
}
args::Argument::SImm(value)
| args::Argument::OffsetImm(args::OffsetImm { post_indexed: _, value }) => {
arg_cb(InstructionPart::Basic("#"))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Signed(*value as i64),
)))?;
arg_cb(InstructionPart::basic("#"))?;
arg_cb(InstructionPart::signed(*value))?;
}
args::Argument::BranchDest(value) => {
let dest = cur_addr.wrapping_add_signed(*value) as u64;
arg_cb(InstructionPart::Arg(InstructionArg::BranchDest(dest)))?;
arg_cb(InstructionPart::branch_dest(cur_addr.wrapping_add_signed(*value)))?;
}
args::Argument::CoOption(value) => {
arg_cb(InstructionPart::Basic("{"))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(*value as u64),
)))?;
arg_cb(InstructionPart::Basic("}"))?;
arg_cb(InstructionPart::basic("{"))?;
arg_cb(InstructionPart::unsigned(*value))?;
arg_cb(InstructionPart::basic("}"))?;
}
args::Argument::CoprocNum(value) => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(format!("p{}", value).into()),
)))?;
arg_cb(InstructionPart::opaque(format!("p{}", value)))?;
}
args::Argument::ShiftImm(shift) => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(shift.op.to_string().into()),
)))?;
arg_cb(InstructionPart::Basic(" #"))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(shift.imm as u64),
)))?;
arg_cb(InstructionPart::opaque(shift.op.to_string()))?;
arg_cb(InstructionPart::basic(" #"))?;
arg_cb(InstructionPart::unsigned(shift.imm))?;
}
args::Argument::ShiftReg(shift) => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(shift.op.to_string().into()),
)))?;
arg_cb(InstructionPart::Basic(" "))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
shift.reg.display(display_options.reg_names).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(shift.op.to_string()))?;
arg_cb(InstructionPart::basic(" "))?;
arg_cb(InstructionPart::opaque(
shift.reg.display(display_options.reg_names).to_string(),
))?;
}
args::Argument::OffsetReg(offset) => {
if !offset.add {
arg_cb(InstructionPart::Basic("-"))?;
arg_cb(InstructionPart::basic("-"))?;
}
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
offset.reg.display(display_options.reg_names).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
offset.reg.display(display_options.reg_names).to_string(),
))?;
}
args::Argument::CpsrMode(mode) => {
arg_cb(InstructionPart::Basic("#"))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(mode.mode as u64),
)))?;
arg_cb(InstructionPart::basic("#"))?;
arg_cb(InstructionPart::unsigned(mode.mode))?;
if mode.writeback {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("!".into()),
)))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
args::Argument::CoReg(_)
@ -541,21 +507,17 @@ fn push_args(
| args::Argument::Shift(_)
| args::Argument::CpsrFlags(_)
| args::Argument::Endian(_) => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
arg.display(display_options, None).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
arg.display(display_options, None).to_string(),
))?;
}
}
}
}
if deref {
arg_cb(InstructionPart::Basic("]"))?;
arg_cb(InstructionPart::basic("]"))?;
if writeback {
arg_cb(InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(
"!".into(),
))))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
Ok(())

View File

@ -17,10 +17,7 @@ use yaxpeax_arm::armv8::a64::{
use crate::{
arch::Arch,
diff::{display::InstructionPart, DiffObjConfig},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, RelocationFlags, ResolvedRelocation,
ScannedInstruction,
},
obj::{InstructionRef, RelocationFlags, ResolvedRelocation, ScannedInstruction},
};
#[derive(Debug)]
@ -83,14 +80,14 @@ impl Arch for ArchArm64 {
relocation: Option<ResolvedRelocation>,
function_range: Range<u64>,
_section_index: usize,
diff_config: &DiffObjConfig,
_diff_config: &DiffObjConfig,
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
) -> Result<()> {
let mut reader = U8Reader::new(code);
let decoder = InstDecoder::default();
let mut ins = Instruction::default();
if decoder.decode_into(&mut ins, &mut reader).is_err() {
cb(InstructionPart::Opcode(Cow::Borrowed("<invalid>"), u16::MAX))?;
cb(InstructionPart::opcode("<invalid>", u16::MAX))?;
return Ok(());
}
@ -100,12 +97,11 @@ impl Arch for ArchArm64 {
start_address: function_range.start,
end_address: function_range.end,
reloc: relocation,
config: diff_config,
};
let mut display_args = Vec::with_capacity(16);
let mnemonic = display_instruction(&mut |ret| display_args.push(ret), &ins, &mut ctx);
cb(InstructionPart::Opcode(Cow::Borrowed(mnemonic), ins_ref.opcode))?;
cb(InstructionPart::opcode(mnemonic, ins_ref.opcode))?;
for arg in display_args {
cb(arg)?;
}
@ -317,7 +313,6 @@ struct DisplayCtx<'a> {
start_address: u64,
end_address: u64,
reloc: Option<ResolvedRelocation<'a>>,
config: &'a DiffObjConfig,
}
// Source: https://github.com/iximeow/yaxpeax-arm/blob/716a6e3fc621f5fe3300f3309e56943b8e1e65ad/src/armv8/a64.rs#L317
@ -325,7 +320,7 @@ struct DisplayCtx<'a> {
// Reworked for more structured output. The library only gives us a Display impl, and no way to
// capture any of this information, so it needs to be reimplemented here.
fn display_instruction<Cb>(args: &mut Cb, ins: &Instruction, ctx: &mut DisplayCtx) -> &'static str
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
let mnemonic = match ins.opcode {
Opcode::Invalid => return "<invalid>",
Opcode::UDF => "udf",
@ -345,7 +340,7 @@ where Cb: FnMut(InstructionPart) {
unreachable!("movn operand 0 is always Register");
};
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, imm);
return "mov";
}
@ -366,7 +361,7 @@ where Cb: FnMut(InstructionPart) {
unreachable!("movz operand 0 is always Register");
};
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, imm);
return "mov";
}
@ -375,7 +370,7 @@ where Cb: FnMut(InstructionPart) {
Opcode::SBC => {
if let Operand::Register(_, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "ngc";
} else {
@ -385,7 +380,7 @@ where Cb: FnMut(InstructionPart) {
Opcode::SBCS => {
if let Operand::Register(_, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "ngcs";
} else {
@ -397,25 +392,25 @@ where Cb: FnMut(InstructionPart) {
if let Operand::Register(_, 31) = ins.operands[1] {
if let Operand::Immediate(0) = ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "mov";
} else if let Operand::RegShift(style, amt, size, r) = ins.operands[2] {
if style == ShiftStyle::LSL && amt == 0 {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, r, false);
return "mov";
}
} else {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "mov";
}
} else if ins.operands[1] == ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "mov";
}
@ -424,7 +419,7 @@ where Cb: FnMut(InstructionPart) {
Opcode::ORN => {
if let Operand::Register(_, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "mvn";
}
@ -437,7 +432,7 @@ where Cb: FnMut(InstructionPart) {
Opcode::ANDS => {
if let Operand::Register(_, 31) = ins.operands[0] {
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "tst";
}
@ -446,14 +441,14 @@ where Cb: FnMut(InstructionPart) {
Opcode::ADDS => {
if let Operand::Register(_, 31) = ins.operands[0] {
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "cmn";
} else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, reg, false);
return "adds";
}
@ -463,20 +458,20 @@ where Cb: FnMut(InstructionPart) {
if let Operand::Immediate(0) = ins.operands[2] {
if let Operand::RegisterOrSP(size, 31) = ins.operands[0] {
push_register(args, size, 31, true);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "mov";
} else if let Operand::RegisterOrSP(size, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, 31, true);
return "mov";
}
} else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, reg, false);
return "add";
}
@ -485,19 +480,19 @@ where Cb: FnMut(InstructionPart) {
Opcode::SUBS => {
if let Operand::Register(_, 31) = ins.operands[0] {
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "cmp";
} else if let Operand::Register(_, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "negs";
} else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, reg, false);
return "subs";
}
@ -506,14 +501,14 @@ where Cb: FnMut(InstructionPart) {
Opcode::SUB => {
if let Operand::Register(_, 31) = ins.operands[1] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "neg";
} else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, size, reg, false);
return "sub";
}
@ -533,18 +528,18 @@ where Cb: FnMut(InstructionPart) {
};
return if rn == 31 {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, lsb as u64);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, width as u64);
"bfc"
} else {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, lsb as u64);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, width as u64);
"bfi"
};
@ -554,11 +549,11 @@ where Cb: FnMut(InstructionPart) {
let lsb = immr;
let width = imms + 1 - lsb;
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, lsb as u64);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, width as u64);
return "bfxil";
}
@ -575,12 +570,12 @@ where Cb: FnMut(InstructionPart) {
{
if let Operand::Immediate(7) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "uxtb";
} else if let Operand::Immediate(15) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "uxth";
}
@ -594,9 +589,9 @@ where Cb: FnMut(InstructionPart) {
match (imms, size) {
(63, SizeCode::X) | (31, SizeCode::W) => {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "lsr";
}
@ -609,19 +604,19 @@ where Cb: FnMut(InstructionPart) {
};
if imms + 1 == immr {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, (size - imms - 1) as u64);
return "lsl";
}
if imms < immr {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, (size - immr) as u64);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, (imms + 1) as u64);
return "ubfiz";
}
@ -637,11 +632,11 @@ where Cb: FnMut(InstructionPart) {
unreachable!("last two operands of ubfm are always immediates");
};
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &width, ctx);
return "ubfx";
}
@ -649,9 +644,9 @@ where Cb: FnMut(InstructionPart) {
if let Operand::Immediate(63) = ins.operands[3] {
if let Operand::Register(SizeCode::X, _) = ins.operands[0] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "asr";
}
@ -659,9 +654,9 @@ where Cb: FnMut(InstructionPart) {
if let Operand::Immediate(31) = ins.operands[3] {
if let Operand::Register(SizeCode::W, _) = ins.operands[0] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "asr";
}
@ -674,17 +669,17 @@ where Cb: FnMut(InstructionPart) {
};
if let Operand::Immediate(7) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &newsrc, ctx);
return "sxtb";
} else if let Operand::Immediate(15) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &newsrc, ctx);
return "sxth";
} else if let Operand::Immediate(31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &newsrc, ctx);
return "sxtw";
}
@ -703,11 +698,11 @@ where Cb: FnMut(InstructionPart) {
unreachable!("operand 0 is always a register");
};
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, (size - imms) as u64);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, (immr + 1) as u64);
return "sbfiz";
}
@ -721,11 +716,11 @@ where Cb: FnMut(InstructionPart) {
unreachable!("last two operands of sbfm are always immediates");
};
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &width, ctx);
return "sbfx";
}
@ -737,9 +732,9 @@ where Cb: FnMut(InstructionPart) {
{
if rn == rm {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[3], ctx);
return "ror";
}
@ -853,25 +848,25 @@ where Cb: FnMut(InstructionPart) {
Opcode::MRS => "mrs",
Opcode::SYS(ops) => {
push_unsigned(args, ops.op1() as u64);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, ops.op2() as u64);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[0], ctx);
return "sys";
}
Opcode::SYSL(ops) => {
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, ops.op1() as u64);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_unsigned(args, ops.op2() as u64);
return "sysl";
}
@ -933,9 +928,9 @@ where Cb: FnMut(InstructionPart) {
{
if cond < 0b1110 && rn == rm {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_condition_code(args, cond ^ 0x01);
return "cneg";
}
@ -954,14 +949,14 @@ where Cb: FnMut(InstructionPart) {
if n == m && cond < 0b1110 {
return if n == 31 {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_condition_code(args, cond ^ 0x01);
"cset"
} else {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_condition_code(args, cond ^ 0x01);
"cinc"
};
@ -978,14 +973,14 @@ where Cb: FnMut(InstructionPart) {
{
if n == m && n != 31 && cond < 0b1110 {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_condition_code(args, cond ^ 0x01);
return "cinv";
} else if n == m && n == 31 && cond < 0b1110 {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_condition_code(args, cond ^ 0x01);
return "csetm";
}
@ -1003,9 +998,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::MADD => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "mul";
}
@ -1014,9 +1009,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::MSUB => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "mneg";
}
@ -1025,9 +1020,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::SMADDL => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "smull";
}
@ -1036,9 +1031,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::SMSUBL => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "smnegl";
}
@ -1048,9 +1043,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::UMADDL => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "umull";
}
@ -1059,9 +1054,9 @@ where Cb: FnMut(InstructionPart) {
Opcode::UMSUBL => {
if let Operand::Register(_, 31) = ins.operands[3] {
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return "umnegl";
}
@ -1346,7 +1341,7 @@ where Cb: FnMut(InstructionPart) {
|| (reg_sz == SizeCode::X && elem_sz == SIMDSizeCode::D)
{
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[1], ctx);
return "mov";
}
@ -1453,7 +1448,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "staddb" } else { "staddlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1473,7 +1468,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stclrb" } else { "stclrlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1493,7 +1488,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "steorb" } else { "steorlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1513,7 +1508,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsetb" } else { "stsetlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1533,7 +1528,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsmaxb" } else { "stsmaxlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1553,7 +1548,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsminb" } else { "stsminlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1573,7 +1568,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stumaxb" } else { "stumaxlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1593,7 +1588,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stuminb" } else { "stuminlb" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1614,7 +1609,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "staddh" } else { "staddlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1634,7 +1629,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stclrh" } else { "stclrlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1654,7 +1649,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "steorh" } else { "steorlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1674,7 +1669,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stseth" } else { "stsetlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1694,7 +1689,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsmaxh" } else { "stsmaxlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1714,7 +1709,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsminh" } else { "stsminlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1734,7 +1729,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stumaxh" } else { "stumaxlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1754,7 +1749,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stuminh" } else { "stuminlh" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1774,7 +1769,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stadd" } else { "staddl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1794,7 +1789,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stclr" } else { "stclrl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1814,7 +1809,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "steor" } else { "steorl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1834,7 +1829,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stset" } else { "stsetl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1854,7 +1849,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsmax" } else { "stsmaxl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1874,7 +1869,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stsmin" } else { "stsminl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1894,7 +1889,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stumax" } else { "stumaxl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -1914,7 +1909,7 @@ where Cb: FnMut(InstructionPart) {
if rt == 31 && ar & 0b10 == 0b00 {
let inst = if ar & 0b01 == 0b00 { "stumin" } else { "stuminl" };
push_operand(args, &ins.operands[0], ctx);
push_separator(args, ctx.config);
push_separator(args);
push_operand(args, &ins.operands[2], ctx);
return inst;
}
@ -2052,7 +2047,7 @@ where Cb: FnMut(InstructionPart) {
break;
}
if i > 0 {
push_separator(args, ctx.config);
push_separator(args);
}
push_operand(args, o, ctx);
}
@ -2135,13 +2130,13 @@ fn condition_code(cond: u8) -> &'static str {
#[inline]
fn push_register<Cb>(args: &mut Cb, size: SizeCode, reg: u16, sp: bool)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
push_opaque(args, reg_name(size, reg, sp));
}
#[inline]
fn push_shift<Cb>(args: &mut Cb, style: ShiftStyle, amount: u8)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
push_opaque(args, shift_style(style));
if amount != 0 {
push_plain(args, " ");
@ -2151,12 +2146,12 @@ where Cb: FnMut(InstructionPart) {
#[inline]
fn push_condition_code<Cb>(args: &mut Cb, cond: u8)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
push_opaque(args, condition_code(cond));
}
fn push_barrier<Cb>(args: &mut Cb, option: u8)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
match option {
0b0001 => push_opaque(args, "oshld"),
0b0010 => push_opaque(args, "oshst"),
@ -2175,41 +2170,35 @@ where Cb: FnMut(InstructionPart) {
}
#[inline]
fn push_opaque<Cb>(args: &mut Cb, text: &'static str)
where Cb: FnMut(InstructionPart) {
push_arg(args, InstructionArg::Value(InstructionArgValue::Opaque(Cow::Borrowed(text))));
fn push_opaque<'a, Cb>(args: &mut Cb, text: &'a str)
where Cb: FnMut(InstructionPart<'a>) {
args(InstructionPart::opaque(text));
}
#[inline]
fn push_plain<Cb>(args: &mut Cb, text: &'static str)
where Cb: FnMut(InstructionPart) {
args(InstructionPart::Basic(text));
where Cb: FnMut(InstructionPart<'static>) {
args(InstructionPart::basic(text));
}
#[inline]
fn push_separator<Cb>(args: &mut Cb, _config: &DiffObjConfig)
where Cb: FnMut(InstructionPart) {
args(InstructionPart::Separator);
fn push_separator<Cb>(args: &mut Cb)
where Cb: FnMut(InstructionPart<'static>) {
args(InstructionPart::separator());
}
#[inline]
fn push_unsigned<Cb>(args: &mut Cb, v: u64)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
push_plain(args, "#");
push_arg(args, InstructionArg::Value(InstructionArgValue::Unsigned(v)));
args(InstructionPart::unsigned(v));
}
#[inline]
fn push_signed<Cb>(args: &mut Cb, v: i64)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
push_plain(args, "#");
push_arg(args, InstructionArg::Value(InstructionArgValue::Signed(v)));
}
#[inline]
fn push_arg<Cb>(args: &mut Cb, arg: InstructionArg)
where Cb: FnMut(InstructionPart) {
args(InstructionPart::Arg(arg));
args(InstructionPart::signed(v));
}
/// Relocations that appear in Operand::PCOffset.
@ -2248,7 +2237,7 @@ fn is_reg_index_reloc(resolved: Option<ResolvedRelocation>) -> bool {
}
fn push_operand<Cb>(args: &mut Cb, o: &Operand, ctx: &mut DisplayCtx)
where Cb: FnMut(InstructionPart) {
where Cb: FnMut(InstructionPart<'static>) {
match o {
Operand::Nothing => unreachable!(),
Operand::PCOffset(off) => {
@ -2260,19 +2249,19 @@ where Cb: FnMut(InstructionPart) {
{
let dest = target_address.unwrap();
push_plain(args, "$");
push_arg(args, InstructionArg::BranchDest(dest));
args(InstructionPart::branch_dest(dest));
} else {
push_arg(args, InstructionArg::Reloc);
args(InstructionPart::reloc());
}
} else {
let dest = ctx.address.saturating_add_signed(*off);
push_plain(args, "$");
push_arg(args, InstructionArg::BranchDest(dest));
args(InstructionPart::branch_dest(dest));
}
}
Operand::Immediate(imm) => {
if is_imm_reloc(ctx.reloc) {
push_arg(args, InstructionArg::Reloc);
args(InstructionPart::reloc());
} else {
push_unsigned(args, *imm as u64);
}
@ -2288,7 +2277,7 @@ where Cb: FnMut(InstructionPart) {
}
Operand::RegisterPair(size, reg) => {
push_register(args, *size, *reg, false);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, *size, *reg + 1, false);
}
Operand::RegisterOrSP(size, reg) => {
@ -2316,7 +2305,7 @@ where Cb: FnMut(InstructionPart) {
Operand::ImmShift(i, shift) => {
push_unsigned(args, *i as u64);
if *shift > 0 {
push_separator(args, ctx.config);
push_separator(args);
push_opaque(args, "lsl");
push_plain(args, " ");
push_unsigned(args, *shift as u64);
@ -2325,7 +2314,7 @@ where Cb: FnMut(InstructionPart) {
Operand::ImmShiftMSL(i, shift) => {
push_unsigned(args, *i as u64);
if *shift > 0 {
push_separator(args, ctx.config);
push_separator(args);
push_opaque(args, "msl");
push_plain(args, " ");
push_unsigned(args, *shift as u64);
@ -2339,7 +2328,7 @@ where Cb: FnMut(InstructionPart) {
{
// pass
} else {
push_separator(args, ctx.config);
push_separator(args);
push_shift(args, *shift_type, *amount);
}
}
@ -2348,7 +2337,7 @@ where Cb: FnMut(InstructionPart) {
if *shift_type == ShiftStyle::LSL && *amount == 0 {
// pass
} else {
push_separator(args, ctx.config);
push_separator(args);
push_shift(args, *shift_type, *amount);
}
}
@ -2356,7 +2345,7 @@ where Cb: FnMut(InstructionPart) {
Operand::RegRegOffset(reg, index_reg, index_size, extend, amount) => {
push_plain(args, "[");
push_register(args, SizeCode::X, *reg, true);
push_separator(args, ctx.config);
push_separator(args);
push_register(args, *index_size, *index_reg, false);
if extend == &ShiftStyle::LSL && *amount == 0 {
// pass
@ -2364,10 +2353,10 @@ where Cb: FnMut(InstructionPart) {
|| (extend == &ShiftStyle::UXTX && index_size == &SizeCode::X))
&& *amount == 0
{
push_separator(args, ctx.config);
push_separator(args);
push_shift(args, *extend, 0);
} else {
push_separator(args, ctx.config);
push_separator(args);
push_shift(args, *extend, *amount);
}
push_plain(args, "]");
@ -2376,10 +2365,10 @@ where Cb: FnMut(InstructionPart) {
push_plain(args, "[");
push_register(args, SizeCode::X, *reg, true);
if is_reg_index_reloc(ctx.reloc) {
push_separator(args, ctx.config);
push_arg(args, InstructionArg::Reloc);
push_separator(args);
args(InstructionPart::reloc());
} else if *offset != 0 || *wback_bit {
push_separator(args, ctx.config);
push_separator(args);
push_signed(args, *offset as i64);
}
push_plain(args, "]");
@ -2391,9 +2380,9 @@ where Cb: FnMut(InstructionPart) {
push_plain(args, "[");
push_register(args, SizeCode::X, *reg, true);
push_plain(args, "]");
push_separator(args, ctx.config);
push_separator(args);
if is_reg_index_reloc(ctx.reloc) {
push_arg(args, InstructionArg::Reloc);
args(InstructionPart::reloc());
} else {
push_signed(args, *offset as i64);
}
@ -2402,15 +2391,9 @@ where Cb: FnMut(InstructionPart) {
push_plain(args, "[");
push_register(args, SizeCode::X, *reg, true);
push_plain(args, "]");
push_separator(args, ctx.config);
push_separator(args);
// TODO does 31 have to be handled separate?
push_arg(
args,
InstructionArg::Value(InstructionArgValue::Opaque(Cow::Owned(format!(
"x{}",
offset_reg
)))),
);
args(InstructionPart::opaque(format!("x{}", offset_reg)));
}
// Fall back to original logic
Operand::SIMDRegister(_, _)
@ -2424,10 +2407,7 @@ where Cb: FnMut(InstructionPart) {
| Operand::SystemReg(_)
| Operand::ControlReg(_)
| Operand::PstateField(_) => {
push_arg(
args,
InstructionArg::Value(InstructionArgValue::Opaque(Cow::Owned(o.to_string()))),
);
args(InstructionPart::opaque(o.to_string()));
}
}
}

View File

@ -159,7 +159,7 @@ impl Arch for ArchMips {
let instruction = self.parse_ins_ref(ins_ref, code, diff_config)?;
let display_flags = self.instruction_display_flags(diff_config);
let opcode = instruction.opcode();
cb(InstructionPart::Opcode(Cow::Borrowed(opcode.name()), opcode as u16))?;
cb(InstructionPart::opcode(opcode.name(), opcode as u16))?;
push_args(&instruction, relocation, function_range, section_index, &display_flags, cb)?;
Ok(())
}
@ -244,7 +244,7 @@ fn push_args(
let operands = instruction.valued_operands_iter();
for (idx, op) in operands.enumerate() {
if idx > 0 {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
match op {
@ -252,10 +252,10 @@ fn push_args(
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(match imm {
IU16::Integer(s) => InstructionPart::signed(s),
IU16::Unsigned(u) => InstructionPart::unsigned(u),
})?;
}
}
ValuedOperand::core_label(..) | ValuedOperand::core_branch_target_label(..) => {
@ -273,7 +273,7 @@ fn push_args(
{
// TODO move this logic up a level
let target_address = target_address.unwrap();
arg_cb(InstructionPart::Arg(InstructionArg::BranchDest(target_address)))?;
arg_cb(InstructionPart::branch_dest(target_address))?;
} else {
push_reloc(resolved.relocation, &mut arg_cb)?;
}
@ -281,13 +281,11 @@ fn push_args(
.get_branch_offset_generic()
.map(|o| (instruction.vram() + o).inner() as u64)
{
arg_cb(InstructionPart::Arg(InstructionArg::BranchDest(branch_dest)))?;
arg_cb(InstructionPart::branch_dest(branch_dest))?;
} else {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
op.display(instruction, display_flags, None::<&str>).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
op.display(instruction, display_flags, None::<&str>).to_string(),
))?;
}
}
ValuedOperand::core_immediate_base(imm, base) => {
@ -299,28 +297,26 @@ fn push_args(
IU16::Unsigned(u) => InstructionArgValue::Unsigned(u as u64),
})))?;
}
arg_cb(InstructionPart::Basic("("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(
base.either_name(instruction.flags().abi(), display_flags.named_gpr()).into(),
))))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("("))?;
arg_cb(InstructionPart::opaque(
base.either_name(instruction.flags().abi(), display_flags.named_gpr()),
))?;
arg_cb(InstructionPart::basic(")"))?;
}
// ValuedOperand::r5900_immediate15(..) => match relocation {
// Some(resolved)
// if resolved.relocation.flags == RelocationFlags::Elf(R_MIPS15_S3) =>
// {
// push_reloc(&resolved.relocation, &mut arg_cb, &mut plain_cb)?;
// push_reloc(&resolved.relocation, &mut arg_cb)?;
// }
// _ => {
// arg_cb(InstructionArg::Value(InstructionArgValue::Opaque(
// op.disassemble(&instruction, None).into(),
// )))?;
// arg_cb(InstructionPart::opaque(op.disassemble(&instruction, None)))?;
// }
// },
_ => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(
op.display(instruction, display_flags, None::<&str>).to_string().into(),
))))?;
arg_cb(InstructionPart::opaque(
op.display(instruction, display_flags, None::<&str>).to_string(),
))?;
}
}
}
@ -334,36 +330,36 @@ fn push_reloc(
match reloc.flags {
RelocationFlags::Elf(r_type) => match r_type {
elf::R_MIPS_HI16 => {
arg_cb(InstructionPart::Basic("%hi("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%hi("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_LO16 => {
arg_cb(InstructionPart::Basic("%lo("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%lo("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_GOT16 => {
arg_cb(InstructionPart::Basic("%got("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%got("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_CALL16 => {
arg_cb(InstructionPart::Basic("%call16("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%call16("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_GPREL16 => {
arg_cb(InstructionPart::Basic("%gp_rel("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%gp_rel("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_32
| elf::R_MIPS_26
| elf::R_MIPS_LITERAL
| elf::R_MIPS_PC16
| R_MIPS15_S3 => {
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::reloc())?;
}
_ => bail!("Unsupported ELF MIPS relocation type {r_type}"),
},

View File

@ -8,8 +8,8 @@ use object::{File, Relocation, Section};
use crate::{
diff::{display::InstructionPart, DiffObjConfig},
obj::{
InstructionRef, ParsedInstruction, RelocationFlags, ResolvedRelocation, ScannedInstruction,
SymbolFlagSet, SymbolKind,
InstructionArg, InstructionRef, ParsedInstruction, RelocationFlags, ResolvedRelocation,
ScannedInstruction, SymbolFlagSet, SymbolKind,
},
util::ReallySigned,
};
@ -195,13 +195,18 @@ pub trait Arch: Send + Sync + Debug {
diff_config,
&mut |part| {
match part {
InstructionPart::Opcode(m, _) => mnemonic = Some(m),
InstructionPart::Arg(arg) => args.push(arg),
InstructionPart::Opcode(m, _) => mnemonic = Some(Cow::Owned(m.into_owned())),
InstructionPart::Arg(arg) => args.push(arg.into_static()),
_ => {}
}
Ok(())
},
)?;
// If the instruction has a relocation, but we didn't format it in the display, add it to
// the end of the arguments list.
if relocation.is_some() && !args.contains(&InstructionArg::Reloc) {
args.push(InstructionArg::Reloc);
}
Ok(ParsedInstruction { ins_ref, mnemonic: mnemonic.unwrap_or_default(), args })
}

View File

@ -18,8 +18,8 @@ use crate::{
arch::{Arch, DataType},
diff::{display::InstructionPart, DiffObjConfig},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
ResolvedRelocation, ScannedInstruction, Symbol, SymbolFlag, SymbolFlagSet,
InstructionRef, Relocation, RelocationFlags, ResolvedRelocation, ScannedInstruction,
Symbol, SymbolFlag, SymbolFlagSet,
},
};
@ -113,14 +113,14 @@ impl Arch for ArchPpc {
let op = ppc750cl::Opcode::from(ins_ref.opcode as u8);
let ins = ppc750cl::Ins { code, op }.simplified();
cb(InstructionPart::Opcode(Cow::Borrowed(ins.mnemonic), ins_ref.opcode))?;
cb(InstructionPart::opcode(ins.mnemonic, ins_ref.opcode))?;
let reloc_arg = self.find_reloc_arg(&ins, relocation);
let mut writing_offset = false;
for (idx, arg) in ins.args_iter().enumerate() {
if idx > 0 && !writing_offset {
cb(InstructionPart::Separator)?;
cb(InstructionPart::separator())?;
}
if reloc_arg == Some(idx) {
@ -135,39 +135,22 @@ impl Arch for ArchPpc {
}
} else {
match arg {
ppc750cl::Argument::Simm(simm) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Signed(simm.0 as i64),
)))?;
}
ppc750cl::Argument::Uimm(uimm) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(uimm.0 as u64),
)))?;
}
ppc750cl::Argument::Offset(offset) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Signed(offset.0 as i64),
)))?;
}
ppc750cl::Argument::BranchDest(dest) => {
let dest = (ins_ref.address as u32).wrapping_add_signed(dest.0) as u64;
cb(InstructionPart::Arg(InstructionArg::BranchDest(dest)))?;
}
_ => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(arg.to_string().into()),
)))?;
}
};
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(
(ins_ref.address as u32).wrapping_add_signed(dest.0),
)),
_ => cb(InstructionPart::opaque(arg.to_string())),
}?;
}
if writing_offset {
cb(InstructionPart::Basic(")"))?;
cb(InstructionPart::basic(")"))?;
writing_offset = false;
}
if is_offset_arg(arg) {
cb(InstructionPart::Basic("("))?;
cb(InstructionPart::basic("("))?;
writing_offset = true;
}
}
@ -276,33 +259,33 @@ fn display_reloc(
match resolved.relocation.flags {
RelocationFlags::Elf(r_type) => match r_type {
elf::R_PPC_ADDR16_LO => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@l"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@l"))?;
}
elf::R_PPC_ADDR16_HI => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@h"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@h"))?;
}
elf::R_PPC_ADDR16_HA => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@ha"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@ha"))?;
}
elf::R_PPC_EMB_SDA21 => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@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::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::reloc())?;
}
elf::R_PPC_NONE => {
// Fake pool relocation.
cb(InstructionPart::Basic("<"))?;
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic(">"))?;
cb(InstructionPart::basic("<"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic(">"))?;
}
_ => cb(InstructionPart::Arg(InstructionArg::Reloc))?,
_ => cb(InstructionPart::reloc())?,
},
_ => cb(InstructionPart::Arg(InstructionArg::Reloc))?,
_ => cb(InstructionPart::reloc())?,
};
Ok(())
}

View File

@ -1,29 +1,17 @@
use alloc::{
borrow::Cow,
boxed::Box,
collections::BTreeMap,
format,
string::{String, ToString},
vec,
vec::Vec,
};
use std::ops::Range;
use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
use core::ops::Range;
use anyhow::{anyhow, bail, ensure, Result};
use anyhow::{anyhow, bail, Result};
use iced_x86::{
Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter,
Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, PrefixKind,
Register,
Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, Register,
};
use object::{pe, Endian as _, Object as _, ObjectSection as _};
use crate::{
arch::Arch,
diff::{display::InstructionPart, DiffObjConfig, X86Formatter},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, ParsedInstruction, RelocationFlags,
ResolvedRelocation, ScannedInstruction,
},
obj::{InstructionRef, RelocationFlags, ResolvedRelocation, ScannedInstruction},
};
#[derive(Debug)]
@ -37,6 +25,10 @@ impl ArchX86 {
Ok(Self { bits: if object.is_64() { 64 } else { 32 }, endianness: object.endianness() })
}
fn decoder<'a>(&self, code: &'a [u8], address: u64) -> Decoder<'a> {
Decoder::with_ip(self.bits, code, address, DecoderOptions::NONE)
}
fn formatter(&self, diff_config: &DiffObjConfig) -> Box<dyn iced_x86::Formatter> {
let mut formatter: Box<dyn iced_x86::Formatter> = match diff_config.x86_formatter {
X86Formatter::Intel => Box::new(IntelFormatter::new()),
@ -58,11 +50,10 @@ impl Arch for ArchX86 {
_diff_config: &DiffObjConfig,
) -> Result<Vec<ScannedInstruction>> {
let mut out = Vec::with_capacity(code.len() / 2);
let mut decoder = Decoder::with_ip(self.bits, code, address, DecoderOptions::NONE);
let mut decoder = self.decoder(code, address);
let mut instruction = Instruction::default();
while decoder.can_decode() {
decoder.decode_out(&mut instruction);
// TODO is this right?
let branch_dest = match instruction.op0_kind() {
OpKind::NearBranch16 => Some(instruction.near_branch16() as u64),
OpKind::NearBranch32 => Some(instruction.near_branch32() as u64),
@ -86,110 +77,72 @@ impl Arch for ArchX86 {
ins_ref: InstructionRef,
code: &[u8],
relocation: Option<ResolvedRelocation>,
function_range: Range<u64>,
section_index: usize,
_function_range: Range<u64>,
_section_index: usize,
diff_config: &DiffObjConfig,
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
) -> Result<()> {
todo!()
}
fn process_code(
&self,
address: u64,
code: &[u8],
_section_index: usize,
relocations: &[ObjReloc],
line_info: &BTreeMap<u64, u32>,
config: &DiffObjConfig,
) -> Result<ProcessCodeResult> {
let mut result = ProcessCodeResult { ops: Vec::new(), insts: Vec::new() };
let mut decoder = Decoder::with_ip(self.bits, code, address, DecoderOptions::NONE);
let mut formatter = self.formatter(config);
let mut output = InstructionFormatterOutput {
formatted: String::new(),
ins: ObjIns {
address: 0,
size: 0,
op: 0,
mnemonic: Cow::Borrowed("<invalid>"),
args: vec![],
reloc: None,
branch_dest: None,
line: None,
formatted: String::new(),
orig: None,
},
error: None,
ins_operands: vec![],
};
let mut decoder = self.decoder(code, ins_ref.address);
let mut formatter = self.formatter(diff_config);
let mut instruction = Instruction::default();
while decoder.can_decode() {
decoder.decode_out(&mut instruction);
let address = instruction.ip();
let op = instruction.mnemonic() as u16;
let reloc = relocations
.iter()
.find(|r| r.address >= address && r.address < address + instruction.len() as u64);
let line = line_info.range(..=address).last().map(|(_, &b)| b);
output.ins = ObjIns {
address,
size: instruction.len() as u8,
op,
mnemonic: Cow::Borrowed("<invalid>"),
args: vec![],
reloc: reloc.cloned(),
branch_dest: None,
line,
formatted: String::new(),
orig: None,
// Determine where to insert relocation in instruction output.
// We replace the immediate or displacement with a placeholder value since the formatter
// doesn't provide enough information to know which number is the displacement inside a
// memory operand.
let mut reloc_replace = None;
if let Some(resolved) = relocation {
const PLACEHOLDER: u64 = 0x7BDEBE7D; // chosen by fair dice roll.
// guaranteed to be random.
let reloc_offset = resolved.relocation.address - ins_ref.address;
let reloc_size = reloc_size(resolved.relocation.flags).unwrap_or(usize::MAX);
let offsets = decoder.get_constant_offsets(&instruction);
if reloc_offset == offsets.displacement_offset() as u64
&& reloc_size == offsets.displacement_size()
{
instruction.set_memory_displacement64(PLACEHOLDER);
// Formatter always writes the displacement as Int32
reloc_replace = Some((OpKind::Memory, NumberKind::Int32, PLACEHOLDER));
} else if reloc_offset == offsets.immediate_offset() as u64
&& reloc_size == offsets.immediate_size()
{
let is_branch = matches!(
instruction.op0_kind(),
OpKind::NearBranch16 | OpKind::NearBranch32 | OpKind::NearBranch64
);
let op_kind = if is_branch {
instruction.op0_kind()
} else {
match reloc_size {
2 => OpKind::Immediate16,
4 => OpKind::Immediate32,
8 => OpKind::Immediate64,
_ => OpKind::default(),
}
};
// Run the formatter, which will populate output.ins
let number_kind = match reloc_size {
2 => NumberKind::UInt16,
4 => NumberKind::UInt32,
8 => NumberKind::UInt64,
_ => NumberKind::default(),
};
if is_branch {
instruction.set_near_branch64(PLACEHOLDER);
} else {
instruction.set_immediate32(PLACEHOLDER as u32);
}
reloc_replace = Some((op_kind, number_kind, PLACEHOLDER));
}
}
let mut output =
InstructionFormatterOutput { cb, reloc_replace, error: None, skip_next: false };
formatter.format(&instruction, &mut output);
if let Some(error) = output.error.take() {
return Err(error);
}
ensure!(output.ins_operands.len() == output.ins.args.len());
output.ins.formatted.clone_from(&output.formatted);
// Make sure we've put the relocation somewhere in the instruction
if reloc.is_some()
&& !output.ins.args.iter().any(|a| matches!(a, InstructionArg::Reloc))
{
let mut found = replace_arg(
OpKind::Memory,
InstructionArg::Reloc,
&mut output.ins.args,
&instruction,
&output.ins_operands,
)?;
if !found {
found = replace_arg(
OpKind::Immediate32,
InstructionArg::Reloc,
&mut output.ins.args,
&instruction,
&output.ins_operands,
)?;
}
ensure!(found, "x86: Failed to find operand for Absolute relocation");
}
if reloc.is_some()
&& !output.ins.args.iter().any(|a| matches!(a, InstructionArg::Reloc))
{
bail!("Failed to find relocation in instruction");
}
result.ops.push(op);
result.insts.push(output.ins.clone());
// Clear for next iteration
output.formatted.clear();
output.ins_operands.clear();
}
Ok(result)
Ok(())
}
fn implcit_addend(
@ -202,7 +155,7 @@ impl Arch for ArchX86 {
) -> Result<i64> {
match flags {
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
let data = section.data()[address as usize..address as usize + 4].try_into()?;
let data = section.data()?[address as usize..address as usize + 4].try_into()?;
Ok(self.endianness.read_i32_bytes(data) as i64)
}
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
@ -231,171 +184,128 @@ impl Arch for ArchX86 {
}
fn get_reloc_byte_size(&self, flags: RelocationFlags) -> usize {
reloc_size(flags).unwrap_or(1)
}
}
fn reloc_size(flags: RelocationFlags) -> Option<usize> {
match flags {
RelocationFlags::Coff(typ) => match typ {
pe::IMAGE_REL_I386_DIR16 => 2,
pe::IMAGE_REL_I386_REL16 => 2,
pe::IMAGE_REL_I386_DIR32 => 4,
pe::IMAGE_REL_I386_REL32 => 4,
_ => 1,
pe::IMAGE_REL_I386_DIR16 | pe::IMAGE_REL_I386_REL16 => Some(2),
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
_ => None,
},
_ => 1,
}
_ => None,
}
}
fn replace_arg(
from: OpKind,
to: InstructionArg,
args: &mut [InstructionArg],
instruction: &Instruction,
ins_operands: &[Option<u32>],
) -> Result<bool> {
let mut replace = None;
for i in 0..instruction.op_count() {
let op_kind = instruction.op_kind(i);
if op_kind == from {
replace = Some(i);
break;
}
}
if let Some(i) = replace {
for (j, arg) in args.iter_mut().enumerate() {
if ins_operands[j] == Some(i) {
*arg = to;
return Ok(true);
}
}
}
Ok(false)
}
struct InstructionFormatterOutput {
formatted: String,
ins: ParsedInstruction,
struct InstructionFormatterOutput<'a> {
cb: &'a mut dyn FnMut(InstructionPart<'_>) -> Result<()>,
reloc_replace: Option<(OpKind, NumberKind, u64)>,
error: Option<anyhow::Error>,
ins_operands: Vec<Option<u32>>,
skip_next: bool,
}
impl InstructionFormatterOutput {
fn push_signed(&mut self, value: i64) {
// The formatter writes the '-' operator and then gives us a negative value,
// so convert it to a positive value to avoid double negatives
if value < 0
&& matches!(self.ins.args.last(), Some(InstructionArg::Value(InstructionArgValue::Opaque(v))) if v == "-")
{
self.ins
.args
.push(InstructionArg::Value(InstructionArgValue::Signed(value.wrapping_abs())));
} else {
self.ins.args.push(InstructionArg::Value(InstructionArgValue::Signed(value)));
}
}
}
impl FormatterOutput for InstructionFormatterOutput {
fn write(&mut self, text: &str, kind: FormatterTextKind) {
self.formatted.push_str(text);
// Skip whitespace after the mnemonic
if self.ins.args.is_empty() && kind == FormatterTextKind::Text {
impl InstructionFormatterOutput<'_> {
fn push_signed(&mut self, mut value: i64) {
if self.error.is_some() {
return;
}
self.ins_operands.push(None);
// The formatter writes the '-' operator and then gives us a negative value,
// so convert it to a positive value to avoid double negatives
if value < 0 {
value = value.wrapping_abs();
}
if let Err(e) = (self.cb)(InstructionPart::signed(value)) {
self.error = Some(e);
}
}
}
impl FormatterOutput for InstructionFormatterOutput<'_> {
fn write(&mut self, text: &str, kind: FormatterTextKind) {
if self.error.is_some() {
return;
}
// Skip whitespace after the mnemonic
if self.skip_next {
self.skip_next = false;
if kind == FormatterTextKind::Text && text == " " {
return;
}
}
match kind {
FormatterTextKind::Text | FormatterTextKind::Punctuation => {
self.ins.args.push(InstructionArg::PlainText(text.to_string().into()));
}
FormatterTextKind::Keyword | FormatterTextKind::Operator => {
self.ins.args.push(InstructionArg::Value(InstructionArgValue::Opaque(
text.to_string().into(),
)));
}
_ => {
if self.error.is_none() {
self.error = Some(anyhow!("x86: Unsupported FormatterTextKind {:?}", kind));
if let Err(e) = (self.cb)(InstructionPart::basic(text)) {
self.error = Some(e);
}
}
FormatterTextKind::Prefix
| FormatterTextKind::Keyword
| FormatterTextKind::Operator => {
if let Err(e) = (self.cb)(InstructionPart::opaque(text)) {
self.error = Some(e);
}
}
_ => self.error = Some(anyhow!("x86: Unsupported FormatterTextKind {:?}", kind)),
}
}
fn write_prefix(&mut self, _instruction: &Instruction, text: &str, _prefix: PrefixKind) {
self.formatted.push_str(text);
self.ins_operands.push(None);
self.ins
.args
.push(InstructionArg::Value(InstructionArgValue::Opaque(text.to_string().into())));
fn write_mnemonic(&mut self, instruction: &Instruction, text: &str) {
if self.error.is_some() {
return;
}
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
self.formatted.push_str(text);
self.ins.mnemonic = Cow::Owned(text.to_string());
if let Err(e) = (self.cb)(InstructionPart::opcode(text, instruction.mnemonic() as u16)) {
self.error = Some(e);
}
// Skip whitespace after the mnemonic
self.skip_next = true;
}
fn write_number(
&mut self,
_instruction: &Instruction,
instruction: &Instruction,
_operand: u32,
instruction_operand: Option<u32>,
text: &str,
_text: &str,
value: u64,
number_kind: NumberKind,
kind: FormatterTextKind,
) {
self.formatted.push_str(text);
self.ins_operands.push(instruction_operand);
if self.error.is_some() {
return;
}
// Handle relocations
match kind {
FormatterTextKind::LabelAddress => {
if let Some(reloc) = self.ins.reloc.as_ref() {
if matches!(
reloc.flags,
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32)
) {
self.ins.args.push(InstructionArg::Reloc);
return;
} else if self.error.is_none() {
self.error = Some(anyhow!(
"x86: Unsupported LabelAddress relocation flags {:?}",
reloc.flags
));
if let (Some(operand), Some((target_op_kind, target_number_kind, target_value))) =
(instruction_operand, self.reloc_replace)
{
if instruction.op_kind(operand) == target_op_kind
&& number_kind == target_number_kind
&& value == target_value
{
if let Err(e) = (self.cb)(InstructionPart::reloc()) {
self.error = Some(e);
}
}
self.ins.args.push(InstructionArg::BranchDest(value));
self.ins.branch_dest = Some(value);
return;
}
FormatterTextKind::FunctionAddress => {
if let Some(reloc) = self.ins.reloc.as_ref() {
if matches!(reloc.flags, RelocationFlags::Coff(pe::IMAGE_REL_I386_REL32)) {
self.ins.args.push(InstructionArg::Reloc);
}
if let FormatterTextKind::LabelAddress | FormatterTextKind::FunctionAddress = kind {
if let Err(e) = (self.cb)(InstructionPart::branch_dest(value)) {
self.error = Some(e);
}
return;
} else if self.error.is_none() {
self.error = Some(anyhow!(
"x86: Unsupported FunctionAddress relocation flags {:?}",
reloc.flags
));
}
}
}
_ => {}
}
match number_kind {
NumberKind::Int8 => {
self.push_signed(value as i8 as i64);
}
NumberKind::Int16 => {
self.push_signed(value as i16 as i64);
}
NumberKind::Int32 => {
self.push_signed(value as i32 as i64);
}
NumberKind::Int64 => {
self.push_signed(value as i64);
}
NumberKind::Int8 => self.push_signed(value as i8 as i64),
NumberKind::Int16 => self.push_signed(value as i16 as i64),
NumberKind::Int32 => self.push_signed(value as i32 as i64),
NumberKind::Int64 => self.push_signed(value as i64),
NumberKind::UInt8 | NumberKind::UInt16 | NumberKind::UInt32 | NumberKind::UInt64 => {
self.ins.args.push(InstructionArg::Value(InstructionArgValue::Unsigned(value)));
if let Err(e) = (self.cb)(InstructionPart::unsigned(value)) {
self.error = Some(e);
}
}
}
}
@ -404,27 +314,208 @@ impl FormatterOutput for InstructionFormatterOutput {
&mut self,
_instruction: &Instruction,
_operand: u32,
instruction_operand: Option<u32>,
_instruction_operand: Option<u32>,
text: &str,
_decorator: DecoratorKind,
) {
self.formatted.push_str(text);
self.ins_operands.push(instruction_operand);
self.ins.args.push(InstructionArg::PlainText(text.to_string().into()));
if self.error.is_some() {
return;
}
if let Err(e) = (self.cb)(InstructionPart::basic(text)) {
self.error = Some(e);
}
}
fn write_register(
&mut self,
_instruction: &Instruction,
_operand: u32,
instruction_operand: Option<u32>,
_instruction_operand: Option<u32>,
text: &str,
_register: Register,
) {
self.formatted.push_str(text);
self.ins_operands.push(instruction_operand);
self.ins
.args
.push(InstructionArg::Value(InstructionArgValue::Opaque(text.to_string().into())));
if self.error.is_some() {
return;
}
if let Err(e) = (self.cb)(InstructionPart::opaque(text)) {
self.error = Some(e);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::obj::Relocation;
#[test]
fn test_scan_instructions() {
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
let code = [
0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x04, 0x85, 0x00,
0x00, 0x00, 0x00,
];
let scanned = arch.scan_instructions(0, &code, 0, &DiffObjConfig::default()).unwrap();
assert_eq!(scanned.len(), 2);
assert_eq!(scanned[0].ins_ref.address, 0);
assert_eq!(scanned[0].ins_ref.size, 10);
assert_eq!(scanned[0].ins_ref.opcode, iced_x86::Mnemonic::Mov as u16);
assert_eq!(scanned[0].branch_dest, None);
assert_eq!(scanned[1].ins_ref.address, 10);
assert_eq!(scanned[1].ins_ref.size, 7);
assert_eq!(scanned[1].ins_ref.opcode, iced_x86::Mnemonic::Mov as u16);
assert_eq!(scanned[1].branch_dest, None);
}
#[test]
fn test_process_instruction() {
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
let code = [0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00];
let opcode = iced_x86::Mnemonic::Mov as u16;
let mut parts = Vec::new();
arch.display_instruction(
InstructionRef { address: 0x1234, size: 10, opcode },
&code,
None,
0x1234..0x2000,
0,
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
assert_eq!(parts, &[
InstructionPart::opcode("mov", opcode),
InstructionPart::opaque("dword"),
InstructionPart::basic(" "),
InstructionPart::opaque("ptr"),
InstructionPart::basic(" "),
InstructionPart::basic("["),
InstructionPart::opaque("ebp"),
InstructionPart::opaque("-"),
InstructionPart::signed(152i64),
InstructionPart::basic("]"),
InstructionPart::basic(","),
InstructionPart::basic(" "),
InstructionPart::unsigned(0u64),
]);
}
#[test]
fn test_process_instruction_with_reloc_1() {
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
let code = [0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00];
let opcode = iced_x86::Mnemonic::Mov as u16;
let mut parts = Vec::new();
arch.display_instruction(
InstructionRef { address: 0x1234, size: 10, opcode },
&code,
Some(ResolvedRelocation {
relocation: &Relocation {
flags: RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32),
address: 0x1234 + 6,
target_symbol: 0,
addend: 0,
},
symbol: &Default::default(),
}),
0x1234..0x2000,
0,
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
assert_eq!(parts, &[
InstructionPart::opcode("mov", opcode),
InstructionPart::opaque("dword"),
InstructionPart::basic(" "),
InstructionPart::opaque("ptr"),
InstructionPart::basic(" "),
InstructionPart::basic("["),
InstructionPart::opaque("ebp"),
InstructionPart::opaque("-"),
InstructionPart::signed(152i64),
InstructionPart::basic("]"),
InstructionPart::basic(","),
InstructionPart::basic(" "),
InstructionPart::reloc(),
]);
}
#[test]
fn test_process_instruction_with_reloc_2() {
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
let code = [0x8b, 0x04, 0x85, 0x00, 0x00, 0x00, 0x00];
let opcode = iced_x86::Mnemonic::Mov as u16;
let mut parts = Vec::new();
arch.display_instruction(
InstructionRef { address: 0x1234, size: 7, opcode },
&code,
Some(ResolvedRelocation {
relocation: &Relocation {
flags: RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32),
address: 0x1234 + 3,
target_symbol: 0,
addend: 0,
},
symbol: &Default::default(),
}),
0x1234..0x2000,
0,
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
assert_eq!(parts, &[
InstructionPart::opcode("mov", opcode),
InstructionPart::opaque("eax"),
InstructionPart::basic(","),
InstructionPart::basic(" "),
InstructionPart::basic("["),
InstructionPart::opaque("eax"),
InstructionPart::opaque("*"),
InstructionPart::signed(4),
InstructionPart::opaque("+"),
InstructionPart::reloc(),
InstructionPart::basic("]"),
]);
}
#[test]
fn test_process_instruction_with_reloc_3() {
let arch = ArchX86 { bits: 32, endianness: object::Endianness::Little };
let code = [0xe8, 0x00, 0x00, 0x00, 0x00];
let opcode = iced_x86::Mnemonic::Call as u16;
let mut parts = Vec::new();
arch.display_instruction(
InstructionRef { address: 0x1234, size: 5, opcode },
&code,
Some(ResolvedRelocation {
relocation: &Relocation {
flags: RelocationFlags::Coff(pe::IMAGE_REL_I386_REL32),
address: 0x1234 + 1,
target_symbol: 0,
addend: 0,
},
symbol: &Default::default(),
}),
0x1234..0x2000,
0,
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
assert_eq!(parts, &[InstructionPart::opcode("call", opcode), InstructionPart::reloc()]);
}
}

View File

@ -107,8 +107,8 @@ pub fn diff_code(
right_obj,
left_symbol_idx,
right_symbol_idx,
left_row.ins_ref.as_ref(),
right_row.ins_ref.as_ref(),
left_row.ins_ref,
right_row.ins_ref,
left_row,
right_row,
diff_config,
@ -226,7 +226,7 @@ fn resolve_branches(
for ((i, ins_diff), ins) in
rows.iter_mut().enumerate().filter(|(_, row)| row.ins_ref.is_some()).zip(ops)
{
let branch_dest = if let Some(resolved) = section.relocation_at(ins.ins_ref.address, obj) {
let branch_dest = if let Some(resolved) = section.relocation_at(ins.ins_ref, obj) {
if resolved.symbol.section == Some(section_index) {
// If the relocation target is in the same section, use it as the branch destination
resolved.symbol.address.checked_add_signed(resolved.relocation.addend)
@ -401,8 +401,8 @@ fn diff_instruction(
right_obj: &Object,
left_symbol_idx: usize,
right_symbol_idx: usize,
l: Option<&InstructionRef>,
r: Option<&InstructionRef>,
l: Option<InstructionRef>,
r: Option<InstructionRef>,
left_row: &InstructionDiffRow,
right_row: &InstructionDiffRow,
diff_config: &DiffObjConfig,
@ -439,8 +439,8 @@ fn diff_instruction(
.ok_or_else(|| anyhow!("Missing section for symbol"))?;
// Resolve relocations
let left_reloc = left_section.relocation_at(l.address, left_obj);
let right_reloc = right_section.relocation_at(r.address, right_obj);
let left_reloc = left_section.relocation_at(l, left_obj);
let right_reloc = right_section.relocation_at(r, right_obj);
// Compare instruction data
let left_data = left_section.data_range(l.address, l.size as usize).ok_or_else(|| {
@ -460,7 +460,7 @@ fn diff_instruction(
if left_data != right_data {
// If data doesn't match, process instructions and compare args
let left_ins = left_obj.arch.process_instruction(
*l,
l,
left_data,
left_reloc,
left_symbol.address..left_symbol.address + left_symbol.size,
@ -468,7 +468,7 @@ fn diff_instruction(
diff_config,
)?;
let right_ins = left_obj.arch.process_instruction(
*r,
r,
right_data,
right_reloc,
right_symbol.address..right_symbol.address + right_symbol.size,

View File

@ -12,14 +12,14 @@ use itertools::Itertools;
use regex::Regex;
use crate::{
diff::{DiffObjConfig, InstructionArgDiffIndex, InstructionDiffRow, ObjectDiff, SymbolDiff},
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
obj::{
InstructionArg, InstructionArgValue, Object, SectionFlag, SectionKind, Symbol, SymbolFlag,
SymbolKind,
},
};
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Clone)]
pub enum DiffText<'a> {
/// Basic text
Basic(&'a str),
@ -30,7 +30,7 @@ pub enum DiffText<'a> {
/// Instruction mnemonic
Opcode(&'a str, u16),
/// Instruction argument
Argument(&'a InstructionArgValue),
Argument(InstructionArgValue<'a>),
/// Branch destination
BranchDest(u64),
/// Symbol name
@ -38,63 +38,155 @@ pub enum DiffText<'a> {
/// Relocation addend
Addend(i64),
/// Number of spaces
Spacing(usize),
Spacing(u8),
/// End of line
Eol,
}
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
pub enum DiffTextColor {
#[default]
Normal, // Grey
Dim, // Dark grey
Bright, // White
Replace, // Blue
Delete, // Red
Insert, // Green
Rotating(u8),
}
#[derive(Debug, Clone)]
pub struct DiffTextSegment<'a> {
pub text: DiffText<'a>,
pub color: DiffTextColor,
pub pad_to: u8,
}
impl<'a> DiffTextSegment<'a> {
#[inline(always)]
pub fn basic(text: &'a str, color: DiffTextColor) -> Self {
Self { text: DiffText::Basic(text), color, pad_to: 0 }
}
#[inline(always)]
pub fn spacing(spaces: u8) -> Self {
Self { text: DiffText::Spacing(spaces), color: DiffTextColor::Normal, pad_to: 0 }
}
}
const EOL_SEGMENT: DiffTextSegment<'static> =
DiffTextSegment { text: DiffText::Eol, color: DiffTextColor::Normal, pad_to: 0 };
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub enum HighlightKind {
#[default]
None,
Opcode(u16),
Argument(InstructionArgValue),
Argument(InstructionArgValue<'static>),
Symbol(String),
Address(u64),
}
pub enum InstructionPart {
Basic(&'static str),
Opcode(Cow<'static, str>, u16),
Arg(InstructionArg),
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InstructionPart<'a> {
Basic(Cow<'a, str>),
Opcode(Cow<'a, str>, u16),
Arg(InstructionArg<'a>),
Separator,
}
impl<'a> InstructionPart<'a> {
#[inline(always)]
pub fn basic<T>(s: T) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Basic(s.into())
}
#[inline(always)]
pub fn opcode<T>(s: T, o: u16) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Opcode(s.into(), o)
}
#[inline(always)]
pub fn opaque<T>(s: T) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(s.into())))
}
#[inline(always)]
pub fn signed<T>(v: T) -> InstructionPart<'static>
where T: Into<i64> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Signed(v.into())))
}
#[inline(always)]
pub fn unsigned<T>(v: T) -> InstructionPart<'static>
where T: Into<u64> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Unsigned(v.into())))
}
#[inline(always)]
pub fn branch_dest<T>(v: T) -> InstructionPart<'static>
where T: Into<u64> {
InstructionPart::Arg(InstructionArg::BranchDest(v.into()))
}
#[inline(always)]
pub fn reloc() -> InstructionPart<'static> { InstructionPart::Arg(InstructionArg::Reloc) }
#[inline(always)]
pub fn separator() -> InstructionPart<'static> { InstructionPart::Separator }
pub fn into_static(self) -> InstructionPart<'static> {
match self {
InstructionPart::Basic(s) => InstructionPart::Basic(Cow::Owned(s.into_owned())),
InstructionPart::Opcode(s, o) => InstructionPart::Opcode(Cow::Owned(s.into_owned()), o),
InstructionPart::Arg(a) => InstructionPart::Arg(a.into_static()),
InstructionPart::Separator => InstructionPart::Separator,
}
}
}
pub fn display_row(
obj: &Object,
symbol_index: usize,
ins_row: &InstructionDiffRow,
diff_config: &DiffObjConfig,
mut cb: impl FnMut(DiffText, InstructionArgDiffIndex) -> Result<()>,
mut cb: impl FnMut(DiffTextSegment) -> Result<()>,
) -> Result<()> {
let Some(ins_ref) = ins_row.ins_ref else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(EOL_SEGMENT)?;
return Ok(());
};
let symbol = &obj.symbols[symbol_index];
let Some(section_index) = symbol.section else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::basic("<invalid>", DiffTextColor::Delete))?;
cb(EOL_SEGMENT)?;
return Ok(());
};
let section = &obj.sections[section_index];
let Some(data) = section.data_range(ins_ref.address, ins_ref.size as usize) else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::basic("<invalid>", DiffTextColor::Delete))?;
cb(EOL_SEGMENT)?;
return Ok(());
};
if let Some(line) = section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b) {
cb(DiffText::Line(line), InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment { text: DiffText::Line(line), color: DiffTextColor::Dim, pad_to: 5 })?;
}
cb(
DiffText::Address(ins_ref.address.saturating_sub(symbol.address)),
InstructionArgDiffIndex::NONE,
)?;
cb(DiffTextSegment {
text: DiffText::Address(ins_ref.address.saturating_sub(symbol.address)),
color: DiffTextColor::Normal,
pad_to: 5,
})?;
if let Some(branch) = &ins_row.branch_from {
cb(DiffText::Basic(" ~> "), InstructionArgDiffIndex::new(branch.branch_idx))?;
cb(DiffTextSegment::basic(" ~> ", DiffTextColor::Rotating(branch.branch_idx as u8)))?;
} else {
cb(DiffText::Spacing(4), InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::spacing(4))?;
}
let mut arg_idx = 0;
let relocation = section.relocation_at(ins_ref.address, obj);
let relocation = section.relocation_at(ins_ref, obj);
let mut displayed_relocation = false;
obj.arch.display_instruction(
ins_ref,
data,
@ -104,47 +196,101 @@ pub fn display_row(
diff_config,
&mut |part| match part {
InstructionPart::Basic(text) => {
cb(DiffText::Basic(text), InstructionArgDiffIndex::NONE)
if text.chars().all(|c| c == ' ') {
cb(DiffTextSegment::spacing(text.len() as u8))
} else {
cb(DiffTextSegment::basic(&text, DiffTextColor::Normal))
}
InstructionPart::Opcode(mnemonic, opcode) => {
cb(DiffText::Opcode(mnemonic.as_ref(), opcode), InstructionArgDiffIndex::NONE)
}
InstructionPart::Opcode(mnemonic, opcode) => cb(DiffTextSegment {
text: DiffText::Opcode(mnemonic.as_ref(), opcode),
color: if ins_row.kind == InstructionDiffKind::OpMismatch {
DiffTextColor::Replace
} else {
DiffTextColor::Normal
},
pad_to: 10,
}),
InstructionPart::Arg(arg) => {
let diff_index = ins_row.arg_diff.get(arg_idx).copied().unwrap_or_default();
arg_idx += 1;
match arg {
InstructionArg::Value(ref value) => cb(DiffText::Argument(value), diff_index),
InstructionArg::Value(value) => cb(DiffTextSegment {
text: DiffText::Argument(value),
color: diff_index
.get()
.map_or(DiffTextColor::Normal, |i| DiffTextColor::Rotating(i as u8)),
pad_to: 0,
}),
InstructionArg::Reloc => {
displayed_relocation = true;
let resolved = relocation.unwrap();
cb(DiffText::Symbol(resolved.symbol), diff_index)?;
let color = diff_index
.get()
.map_or(DiffTextColor::Bright, |i| DiffTextColor::Rotating(i as u8));
cb(DiffTextSegment {
text: DiffText::Symbol(resolved.symbol),
color,
pad_to: 0,
})?;
if resolved.relocation.addend != 0 {
cb(DiffText::Addend(resolved.relocation.addend), diff_index)?;
cb(DiffTextSegment {
text: DiffText::Addend(resolved.relocation.addend),
color,
pad_to: 0,
})?;
}
Ok(())
}
InstructionArg::BranchDest(dest) => {
if let Some(addr) = dest.checked_sub(symbol.address) {
cb(DiffText::BranchDest(addr), diff_index)
cb(DiffTextSegment {
text: DiffText::BranchDest(addr),
color: diff_index.get().map_or(DiffTextColor::Normal, |i| {
DiffTextColor::Rotating(i as u8)
}),
pad_to: 0,
})
} else {
cb(
DiffText::Argument(&InstructionArgValue::Opaque(Cow::Borrowed(
"<invalid>",
))),
diff_index,
)
cb(DiffTextSegment {
text: DiffText::Argument(InstructionArgValue::Opaque(
Cow::Borrowed("<invalid>"),
)),
color: diff_index.get().map_or(DiffTextColor::Normal, |i| {
DiffTextColor::Rotating(i as u8)
}),
pad_to: 0,
})
}
}
}
}
InstructionPart::Separator => {
cb(DiffText::Basic(diff_config.separator()), InstructionArgDiffIndex::NONE)
cb(DiffTextSegment::basic(diff_config.separator(), DiffTextColor::Normal))
}
},
)?;
if let Some(branch) = &ins_row.branch_to {
cb(DiffText::Basic(" ~>"), InstructionArgDiffIndex::new(branch.branch_idx))?;
// Fallback for relocation that wasn't displayed
if relocation.is_some() && !displayed_relocation {
cb(DiffTextSegment::basic(" <", DiffTextColor::Normal))?;
let resolved = relocation.unwrap();
let diff_index = ins_row.arg_diff.get(arg_idx).copied().unwrap_or_default();
let color =
diff_index.get().map_or(DiffTextColor::Bright, |i| DiffTextColor::Rotating(i as u8));
cb(DiffTextSegment { text: DiffText::Symbol(resolved.symbol), color, pad_to: 0 })?;
if resolved.relocation.addend != 0 {
cb(DiffTextSegment {
text: DiffText::Addend(resolved.relocation.addend),
color,
pad_to: 0,
})?;
}
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::basic(">", DiffTextColor::Normal))?;
}
if let Some(branch) = &ins_row.branch_to {
cb(DiffTextSegment::basic(" ~>", DiffTextColor::Rotating(branch.branch_idx as u8)))?;
}
cb(EOL_SEGMENT)?;
Ok(())
}
@ -164,13 +310,13 @@ impl PartialEq<HighlightKind> for DiffText<'_> {
fn eq(&self, other: &HighlightKind) -> bool { other.eq(self) }
}
impl From<DiffText<'_>> for HighlightKind {
fn from(value: DiffText<'_>) -> Self {
impl From<&DiffText<'_>> for HighlightKind {
fn from(value: &DiffText<'_>) -> Self {
match value {
DiffText::Opcode(_, op) => HighlightKind::Opcode(op),
DiffText::Argument(arg) => HighlightKind::Argument(arg.clone()),
DiffText::Opcode(_, op) => HighlightKind::Opcode(*op),
DiffText::Argument(arg) => HighlightKind::Argument(arg.to_static()),
DiffText::Symbol(sym) => HighlightKind::Symbol(sym.name.to_string()),
DiffText::Address(addr) | DiffText::BranchDest(addr) => HighlightKind::Address(addr),
DiffText::Address(addr) | DiffText::BranchDest(addr) => HighlightKind::Address(*addr),
_ => HighlightKind::None,
}
}
@ -267,7 +413,7 @@ fn symbol_matches_filter(
if symbol.section.is_none() && !symbol.flags.contains(SymbolFlag::Common) {
return false;
}
if !show_hidden_symbols && symbol.flags.contains(SymbolFlag::Hidden) {
if !show_hidden_symbols && (symbol.size == 0 || symbol.flags.contains(SymbolFlag::Hidden)) {
return false;
}
match filter {

View File

@ -1,7 +1,14 @@
pub mod read;
pub mod split_meta;
use alloc::{borrow::Cow, boxed::Box, collections::BTreeMap, string::String, vec, vec::Vec};
use alloc::{
borrow::Cow,
boxed::Box,
collections::BTreeMap,
string::{String, ToString},
vec,
vec::Vec,
};
use core::{fmt, num::NonZeroU32};
use flagset::{flags, FlagSet};
@ -98,11 +105,17 @@ impl Section {
pub fn relocation_at<'obj>(
&'obj self,
address: u64,
ins_ref: InstructionRef,
obj: &'obj Object,
) -> Option<ResolvedRelocation<'obj>> {
self.relocations.binary_search_by_key(&address, |r| r.address).ok().and_then(|i| {
let relocation = self.relocations.get(i)?;
match self.relocations.binary_search_by_key(&ins_ref.address, |r| r.address) {
Ok(i) => self.relocations.get(i),
Err(i) => self
.relocations
.get(i)
.take_if(|r| r.address < ins_ref.address + ins_ref.size as u64),
}
.and_then(|relocation| {
let symbol = obj.symbols.get(relocation.target_symbol)?;
Some(ResolvedRelocation { relocation, symbol })
})
@ -110,13 +123,13 @@ impl Section {
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InstructionArgValue {
pub enum InstructionArgValue<'a> {
Signed(i64),
Unsigned(u64),
Opaque(Cow<'static, str>),
Opaque(Cow<'a, str>),
}
impl InstructionArgValue {
impl InstructionArgValue<'_> {
pub fn loose_eq(&self, other: &InstructionArgValue) -> bool {
match (self, other) {
(InstructionArgValue::Signed(a), InstructionArgValue::Signed(b)) => a == b,
@ -127,9 +140,27 @@ impl InstructionArgValue {
_ => false,
}
}
pub fn to_static(&self) -> InstructionArgValue<'static> {
match self {
InstructionArgValue::Signed(v) => InstructionArgValue::Signed(*v),
InstructionArgValue::Unsigned(v) => InstructionArgValue::Unsigned(*v),
InstructionArgValue::Opaque(v) => InstructionArgValue::Opaque(v.to_string().into()),
}
}
pub fn into_static(self) -> InstructionArgValue<'static> {
match self {
InstructionArgValue::Signed(v) => InstructionArgValue::Signed(v),
InstructionArgValue::Unsigned(v) => InstructionArgValue::Unsigned(v),
InstructionArgValue::Opaque(v) => {
InstructionArgValue::Opaque(Cow::Owned(v.into_owned()))
}
}
}
}
impl fmt::Display for InstructionArgValue {
impl fmt::Display for InstructionArgValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InstructionArgValue::Signed(v) => write!(f, "{:#x}", ReallySigned(*v)),
@ -139,14 +170,14 @@ impl fmt::Display for InstructionArgValue {
}
}
#[derive(Debug, Clone)]
pub enum InstructionArg {
Value(InstructionArgValue),
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InstructionArg<'a> {
Value(InstructionArgValue<'a>),
Reloc,
BranchDest(u64),
}
impl InstructionArg {
impl InstructionArg<'_> {
pub fn loose_eq(&self, other: &InstructionArg) -> bool {
match (self, other) {
(InstructionArg::Value(a), InstructionArg::Value(b)) => a.loose_eq(b),
@ -155,6 +186,22 @@ impl InstructionArg {
_ => false,
}
}
pub fn to_static(&self) -> InstructionArg<'static> {
match self {
InstructionArg::Value(v) => InstructionArg::Value(v.to_static()),
InstructionArg::Reloc => InstructionArg::Reloc,
InstructionArg::BranchDest(v) => InstructionArg::BranchDest(*v),
}
}
pub fn into_static(self) -> InstructionArg<'static> {
match self {
InstructionArg::Value(v) => InstructionArg::Value(v.into_static()),
InstructionArg::Reloc => InstructionArg::Reloc,
InstructionArg::BranchDest(v) => InstructionArg::BranchDest(v),
}
}
}
#[derive(Copy, Clone, Debug)]
@ -174,7 +221,7 @@ pub struct ScannedInstruction {
pub struct ParsedInstruction {
pub ins_ref: InstructionRef,
pub mnemonic: Cow<'static, str>,
pub args: Vec<InstructionArg>,
pub args: Vec<InstructionArg<'static>>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
@ -243,7 +290,7 @@ pub enum RelocationFlags {
Coff(u16),
}
#[derive(Clone, Copy)]
#[derive(Debug, Copy, Clone)]
pub struct ResolvedRelocation<'a> {
pub relocation: &'a Relocation,
pub symbol: &'a Symbol,

View File

@ -4,6 +4,7 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::cmp::Ordering;
use anyhow::{bail, ensure, Context, Result};
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
@ -32,16 +33,22 @@ fn map_symbol(
arch: &dyn Arch,
file: &object::File,
symbol: &object::Symbol,
section_indices: &[usize],
split_meta: Option<&SplitMeta>,
) -> Result<Symbol> {
let mut name = symbol.name().context("Failed to process symbol name")?.to_string();
let size = symbol.size();
let mut size = symbol.size();
if let (object::SymbolKind::Section, Some(section)) =
(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);
// size = section.size();
// 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
// inference logic below will set the size back to the section size, thus acting as a
// placeholder symbol.
size = 0;
}
let mut flags = arch.extra_symbol_flags(symbol);
@ -74,7 +81,7 @@ fn map_symbol(
let virtual_address = split_meta
.and_then(|m| m.virtual_addresses.as_ref())
.and_then(|v| v.get(symbol.index().0).cloned());
let section = symbol.section_index().map(|i| map_section_index(file, i));
let section = symbol.section_index().and_then(|i| section_indices.get(i.0).copied());
Ok(Symbol {
name,
@ -89,39 +96,123 @@ fn map_symbol(
})
}
fn map_section_index(file: &object::File, idx: object::SectionIndex) -> usize {
match file.format() {
object::BinaryFormat::Elf => idx.0 - 1,
_ => idx.0,
}
}
fn map_symbol_index(file: &object::File, idx: object::SymbolIndex) -> usize {
match file.format() {
object::BinaryFormat::Elf => idx.0 - 1,
_ => idx.0,
}
}
fn map_symbols(
arch: &dyn Arch,
obj_file: &object::File,
sections: &[Section],
section_indices: &[usize],
split_meta: Option<&SplitMeta>,
) -> Result<Vec<Symbol>> {
let mut symbols = Vec::<Symbol>::with_capacity(obj_file.symbols().count());
for symbol in obj_file.symbols() {
symbols.push(map_symbol(arch, obj_file, &symbol, split_meta)?);
) -> Result<(Vec<Symbol>, Vec<usize>)> {
let symbol_count = obj_file.symbols().count();
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count);
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
for obj_symbol in obj_file.symbols() {
if symbol_indices.len() <= obj_symbol.index().0 {
symbol_indices.resize(obj_symbol.index().0 + 1, usize::MAX);
}
let symbol = map_symbol(arch, obj_file, &obj_symbol, section_indices, split_meta)?;
symbol_indices[obj_symbol.index().0] = symbols.len();
symbols.push(symbol);
}
// Infer symbol sizes for 0-size symbols
infer_symbol_sizes(&mut symbols, sections);
Ok((symbols, symbol_indices))
}
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());
for (i, symbol) in symbols.iter().enumerate() {
if symbol.section.is_some() {
symbols_with_section.push(i);
}
}
symbols_with_section.sort_by(|a, b| {
let a = &symbols[*a];
let b = &symbols[*b];
a.section
.unwrap_or(usize::MAX)
.cmp(&b.section.unwrap_or(usize::MAX))
.then_with(|| {
// Sort section symbols first
if a.kind == SymbolKind::Section {
Ordering::Less
} else if b.kind == SymbolKind::Section {
Ordering::Greater
} else {
Ordering::Equal
}
})
.then_with(|| a.address.cmp(&b.address))
.then_with(|| a.size.cmp(&b.size))
});
// Set symbol sizes based on the next symbol's address
let mut iter_idx = 0;
while iter_idx < symbols_with_section.len() {
let symbol_idx = symbols_with_section[iter_idx];
let symbol = &symbols[symbol_idx];
iter_idx += 1;
if symbol.size != 0 {
continue;
}
let section_idx = symbol.section.unwrap();
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 = &symbols[symbols_with_section[iter_idx]];
if next_symbol.section != Some(section_idx) {
break None;
}
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)),
};
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
let section = &sections[section_idx];
section.address + section.size
});
let new_size = next_address.saturating_sub(symbol.address);
if new_size > 0 {
let symbol = &mut symbols[symbol_idx];
symbol.size = new_size;
if symbol.kind != SymbolKind::Section {
symbol.flags |= SymbolFlag::SizeInferred;
}
// Set symbol kind if unknown and size is non-zero
if symbol.kind == SymbolKind::Unknown {
symbol.kind = match sections[section_idx].kind {
SectionKind::Code => SymbolKind::Function,
SectionKind::Data | SectionKind::Bss => SymbolKind::Object,
_ => SymbolKind::Unknown,
};
}
}
}
Ok(symbols)
}
fn map_sections(
arch: &dyn Arch,
_arch: &dyn Arch,
obj_file: &object::File,
split_meta: Option<&SplitMeta>,
) -> Result<Vec<Section>> {
) -> Result<(Vec<Section>, Vec<usize>)> {
let mut section_names = BTreeMap::<String, usize>::new();
let mut result = Vec::<Section>::with_capacity(obj_file.sections().count());
let section_count = obj_file.sections().count();
let mut result = Vec::<Section>::with_capacity(section_count);
let mut section_indices = Vec::<usize>::with_capacity(section_count + 1);
for section in obj_file.sections() {
let name = section.name().context("Failed to process section name")?;
let kind = map_section_kind(&section);
@ -142,12 +233,14 @@ fn map_sections(
.and_then(|v| v.get(s.index().0).cloned())
});
let relocations = map_relocations(arch, obj_file, &section)?;
let unique_id = section_names.entry(name.to_string()).or_insert(0);
let id = format!("{}-{}", name, unique_id);
*unique_id += 1;
if section_indices.len() <= section.index().0 {
section_indices.resize(section.index().0 + 1, usize::MAX);
}
section_indices[section.index().0] = result.len();
result.push(Section {
id,
name: name.to_string(),
@ -156,33 +249,14 @@ fn map_sections(
kind,
data: SectionData(data),
flags: Default::default(),
relocations,
relocations: Default::default(),
virtual_address,
line_info: Default::default(),
});
}
Ok(result)
Ok((result, section_indices))
}
// result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
// let mut iter = result.iter_mut().peekable();
// while let Some(symbol) = iter.next() {
// if symbol.size == 0 {
// if let Some(next_symbol) = iter.peek() {
// symbol.size = next_symbol.address - symbol.address;
// } else {
// symbol.size = (section.address + section.size) - symbol.address;
// }
// // Set symbol kind if we ended up with a non-zero size
// if symbol.kind == ObjSymbolKind::Unknown && symbol.size > 0 {
// symbol.kind = match section.kind {
// ObjSectionKind::Code => ObjSymbolKind::Function,
// ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
// };
// }
// }
// }
const LOW_PRIORITY_SYMBOLS: &[&str] =
&["__gnu_compiled_c", "__gnu_compiled_cplusplus", "gcc2_compiled."];
@ -230,6 +304,7 @@ fn map_relocations(
arch: &dyn Arch,
obj_file: &object::File,
obj_section: &object::Section,
symbol_indices: &[usize],
) -> Result<Vec<Relocation>> {
let mut relocations = Vec::<Relocation>::with_capacity(obj_section.relocations().count());
let mut ordered_symbols = None;
@ -269,7 +344,13 @@ fn map_relocations(
} else {
idx
};
map_symbol_index(obj_file, idx)
match symbol_indices.get(idx.0).copied() {
Some(i) => i,
None => {
log::warn!("Invalid symbol index {}", idx.0);
continue;
}
}
}
object::RelocationTarget::Absolute => {
let section_name = obj_section.name()?;
@ -299,6 +380,7 @@ fn map_relocations(
fn parse_line_info(
obj_file: &object::File,
sections: &mut [Section],
section_indices: &[usize],
obj_data: &[u8],
) -> Result<()> {
// DWARF 1.1
@ -326,7 +408,6 @@ fn parse_line_info(
}
let address_delta = read_u32(obj_file, &mut section_data)? as u64;
out_section.line_info.insert(base_address + address_delta, line_number);
log::debug!("Line: {:#x} -> {}", base_address + address_delta, line_number);
}
}
}
@ -376,7 +457,7 @@ fn parse_line_info(
// COFF
if let object::File::Coff(coff) = obj_file {
parse_line_info_coff(coff, sections, obj_data)?;
parse_line_info_coff(coff, sections, section_indices, obj_data)?;
}
Ok(())
@ -385,6 +466,7 @@ fn parse_line_info(
fn parse_line_info_coff(
coff: &object::coff::CoffFile,
sections: &mut [Section],
section_indices: &[usize],
obj_data: &[u8],
) -> Result<()> {
use object::{
@ -405,7 +487,9 @@ fn parse_line_info_coff(
// Find this section in our out_section. If it's not in out_section,
// skip it.
let Some(out_section) = sections.get_mut(sect.index().0) else {
let Some(out_section) =
section_indices.get(sect.index().0).and_then(|&i| sections.get_mut(i))
else {
continue;
};
@ -514,7 +598,12 @@ fn combine_sections(
for (i, section) in sections.iter().enumerate() {
match section.kind {
SectionKind::Data | SectionKind::Bss => {
data_sections.entry(section.name.clone()).or_default().push(i);
let base_name = if let Some(i) = section.name.rfind('$') {
&section.name[..i]
} else {
&section.name
};
data_sections.entry(base_name.to_string()).or_default().push(i);
}
SectionKind::Code => {
text_sections.push(i);
@ -523,12 +612,12 @@ fn combine_sections(
}
}
if config.combine_data_sections {
for (_, section_indices) in data_sections {
do_combine_sections(sections, symbols, &section_indices)?;
for (combined_name, mut section_indices) in data_sections {
do_combine_sections(sections, symbols, &mut section_indices, combined_name)?;
}
}
if config.combine_text_sections {
do_combine_sections(sections, symbols, &text_sections)?;
do_combine_sections(sections, symbols, &mut text_sections, ".text".to_string())?;
}
Ok(())
}
@ -536,11 +625,24 @@ fn combine_sections(
fn do_combine_sections(
sections: &mut [Section],
symbols: &mut [Symbol],
section_indices: &[usize],
section_indices: &mut [usize],
combined_name: String,
) -> Result<()> {
if section_indices.len() < 2 {
return Ok(());
}
// Sort sections lexicographically by name (for COFF section groups)
section_indices.sort_by(|&a, &b| {
let a_name = &sections[a].name;
let b_name = &sections[b].name;
// .text$di < .text$mn < .text
if a_name.contains('$') && !b_name.contains('$') {
return Ordering::Less;
} else if !a_name.contains('$') && b_name.contains('$') {
return Ordering::Greater;
}
a_name.cmp(b_name)
});
let first_section_idx = section_indices[0];
// Calculate the new offset for each section
@ -548,7 +650,7 @@ fn do_combine_sections(
let mut current_offset = 0;
let mut data_size = 0;
let mut num_relocations = 0;
for &i in section_indices {
for i in section_indices.iter().copied() {
let section = &sections[i];
if section.address != 0 {
bail!("Section {} ({}) has non-zero address", i, section.name);
@ -580,6 +682,8 @@ fn do_combine_sections(
}
{
let first_section = &mut sections[first_section_idx];
first_section.id = format!("{combined_name}-combined");
first_section.name = combined_name;
first_section.size = current_offset;
first_section.data = SectionData(data);
first_section.flags |= SectionFlag::Combined;
@ -659,9 +763,18 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
let obj_file = object::File::parse(data)?;
let arch = new_arch(&obj_file)?;
let split_meta = parse_split_meta(&obj_file)?;
let mut symbols = map_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let mut sections = map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
parse_line_info(&obj_file, &mut sections, data)?;
let (mut sections, section_indices) =
map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let (mut symbols, symbol_indices) =
map_symbols(arch.as_ref(), &obj_file, &sections, &section_indices, split_meta.as_ref())?;
for obj_section in obj_file.sections() {
let section = &mut sections[section_indices[obj_section.index().0]];
if section.kind != SectionKind::Unknown {
section.relocations =
map_relocations(arch.as_ref(), &obj_file, &obj_section, &symbol_indices)?;
}
}
parse_line_info(&obj_file, &mut sections, &section_indices, data)?;
if config.combine_data_sections || config.combine_text_sections {
combine_sections(&mut sections, &mut symbols, config)?;
}
@ -803,7 +916,8 @@ mod test {
..Default::default()
},
];
do_combine_sections(&mut sections, &mut symbols, &[1, 2, 3]).unwrap();
do_combine_sections(&mut sections, &mut symbols, &mut [1, 2, 3], ".data".to_string())
.unwrap();
assert_eq!(sections[1].data.0, (1..=12).collect::<Vec<_>>());
insta::assert_debug_snapshot!((sections, symbols));
}

View File

@ -44,7 +44,7 @@ expression: "(sections, symbols)"
virtual_address: None,
},
Section {
id: ".data-0",
id: ".data-combined",
name: ".data",
address: 0,
size: 12,

View File

@ -6,7 +6,7 @@ use num_traits::PrimInt;
use object::{Endian, Object};
// https://stackoverflow.com/questions/44711012/how-do-i-format-a-signed-integer-to-a-sign-aware-hexadecimal-representation
pub struct ReallySigned<N: PrimInt>(pub(crate) N);
pub struct ReallySigned<N: PrimInt>(pub N);
impl<N: PrimInt> fmt::LowerHex for ReallySigned<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View File

@ -0,0 +1,28 @@
use objdiff_core::{diff, obj};
mod common;
#[test]
#[cfg(feature = "x86")]
fn read_x86() {
let diff_config = diff::DiffObjConfig::default();
let obj = obj::read::parse(include_object!("data/x86/staticdebug.obj"), &diff_config).unwrap();
insta::assert_debug_snapshot!(obj);
let symbol_idx = obj.symbols.iter().position(|s| s.name == "?PrintThing@@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);
}
#[test]
#[cfg(feature = "x86")]
fn read_x86_combine_sections() {
let diff_config = diff::DiffObjConfig {
combine_data_sections: true,
combine_text_sections: true,
..Default::default()
};
let obj = obj::read::parse(include_object!("data/x86/rtest.obj"), &diff_config).unwrap();
insta::assert_debug_snapshot!(obj.sections);
}

View File

@ -1,5 +1,5 @@
use objdiff_core::{
diff::{DiffObjConfig, SymbolDiff},
diff::{display::DiffTextSegment, DiffObjConfig, SymbolDiff},
obj::Object,
};
@ -13,21 +13,16 @@ pub fn display_diff(
for row in &diff.instruction_rows {
output.push('[');
let mut separator = false;
objdiff_core::diff::display::display_row(
&obj,
symbol_idx,
row,
&diff_config,
|text, diff_idx| {
objdiff_core::diff::display::display_row(&obj, symbol_idx, row, &diff_config, |segment| {
if separator {
output.push_str(", ");
} else {
separator = true;
}
output.push_str(&format!("({:?}, {:?})", text, diff_idx.get()));
let DiffTextSegment { text, color, pad_to } = segment;
output.push_str(&format!("({:?}, {:?}, {:?})", text, color, pad_to));
Ok(())
},
)
})
.unwrap();
output.push_str("]\n");
}

View File

@ -49,10 +49,6 @@ expression: sections_display
59.02353,
),
symbols: [
SectionDisplaySymbol {
symbol: 1,
is_mapping_symbol: false,
},
SectionDisplaySymbol {
symbol: 3,
is_mapping_symbol: false,

View File

@ -2,69 +2,69 @@
source: objdiff-core/tests/arch_ppc.rs
expression: output
---
[(Address(0), None), (Spacing(4), None), (Opcode("srwi", 60), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("24")), None), (Eol, None)]
[(Address(4), None), (Spacing(4), None), (Opcode("cmpwi", 38), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(8), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(20), None), (Basic(" ~>"), Some(0)), (Eol, None)]
[(Address(12), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(16), None), (Spacing(4), None), (Opcode("b", 45), None), (BranchDest(32), None), (Basic(" ~>"), Some(1)), (Eol, None)]
[(Address(20), None), (Basic(" ~> "), Some(0)), (Opcode("lis", 42), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Unsigned(0)), None), (Eol, None)]
[(Address(24), None), (Spacing(4), None), (Opcode("addi", 41), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(28), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r0")), None), (Eol, None)]
[(Address(32), None), (Basic(" ~> "), Some(1)), (Opcode("extrwi", 60), None), (Argument(Opaque("r5")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("8")), None), (Basic(", "), None), (Argument(Opaque("8")), None), (Eol, None)]
[(Address(36), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(40), None), (Spacing(4), None), (Opcode("cmpwi", 38), None), (Argument(Opaque("r5")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(44), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(56), None), (Basic(" ~>"), Some(2)), (Eol, None)]
[(Address(48), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(52), None), (Spacing(4), None), (Opcode("b", 45), None), (BranchDest(68), None), (Basic(" ~>"), Some(3)), (Eol, None)]
[(Address(56), None), (Basic(" ~> "), Some(2)), (Opcode("lis", 42), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Unsigned(0)), None), (Eol, None)]
[(Address(60), None), (Spacing(4), None), (Opcode("addi", 41), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(64), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r5")), None), (Eol, None)]
[(Address(68), None), (Basic(" ~> "), Some(3)), (Opcode("extrwi", 60), None), (Argument(Opaque("r5")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("8")), None), (Basic(", "), None), (Argument(Opaque("16")), None), (Eol, None)]
[(Address(72), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(76), None), (Spacing(4), None), (Opcode("cmpwi", 38), None), (Argument(Opaque("r5")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(80), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(1)), None), (Basic("("), None), (Argument(Opaque("r4")), None), (Basic(")"), None), (Eol, None)]
[(Address(84), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(96), None), (Basic(" ~>"), Some(4)), (Eol, None)]
[(Address(88), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(92), None), (Spacing(4), None), (Opcode("b", 45), None), (BranchDest(108), None), (Basic(" ~>"), Some(5)), (Eol, None)]
[(Address(96), None), (Basic(" ~> "), Some(4)), (Opcode("lis", 42), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Unsigned(0)), None), (Eol, None)]
[(Address(100), None), (Spacing(4), None), (Opcode("addi", 41), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(104), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r5")), None), (Eol, None)]
[(Address(108), None), (Basic(" ~> "), Some(5)), (Opcode("clrlwi", 60), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("24")), None), (Eol, None)]
[(Address(112), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(116), None), (Spacing(4), None), (Opcode("cmpwi", 38), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(120), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(2)), None), (Basic("("), None), (Argument(Opaque("r3")), None), (Basic(")"), None), (Eol, None)]
[(Address(124), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(136), None), (Basic(" ~>"), Some(6)), (Eol, None)]
[(Address(128), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(-1)), None), (Eol, None)]
[(Address(132), None), (Spacing(4), None), (Opcode("b", 45), None), (BranchDest(148), None), (Basic(" ~>"), Some(7)), (Eol, None)]
[(Address(136), None), (Basic(" ~> "), Some(6)), (Opcode("lis", 42), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(0)), None), (Eol, None)]
[(Address(140), None), (Spacing(4), None), (Opcode("addi", 41), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(144), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Eol, None)]
[(Address(148), None), (Basic(" ~> "), Some(7)), (Opcode("li", 41), None), (Argument(Opaque("r5")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(152), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(156), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(3)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(160), None), (Spacing(4), None), (Opcode("lis", 42), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(0)), None), (Eol, None)]
[(Address(164), None), (Spacing(4), None), (Opcode("addi", 41), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Eol, None)]
[(Address(168), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(4)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(172), None), (Spacing(4), None), (Opcode("li", 41), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(45)), None), (Eol, None)]
[(Address(176), None), (Spacing(4), None), (Opcode("lbz", 162), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(180), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Eol, None)]
[(Address(184), None), (Spacing(4), None), (Opcode("andi.", 66), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(220)), None), (Eol, None)]
[(Address(188), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(196), None), (Basic(" ~>"), Some(8)), (Eol, None)]
[(Address(192), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(196), None), (Basic(" ~> "), Some(8)), (Opcode("lbzu", 163), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(1)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(200), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Eol, None)]
[(Address(204), None), (Spacing(4), None), (Opcode("andi.", 66), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(220)), None), (Eol, None)]
[(Address(208), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(216), None), (Basic(" ~>"), Some(9)), (Eol, None)]
[(Address(212), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(216), None), (Basic(" ~> "), Some(9)), (Opcode("lbzu", 163), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(1)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(220), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Eol, None)]
[(Address(224), None), (Spacing(4), None), (Opcode("andi.", 66), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(220)), None), (Eol, None)]
[(Address(228), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(236), None), (Basic(" ~>"), Some(10)), (Eol, None)]
[(Address(232), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(236), None), (Basic(" ~> "), Some(10)), (Opcode("lbzu", 163), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Signed(1)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(240), None), (Spacing(4), None), (Opcode("lbzx", 94), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r4")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Eol, None)]
[(Address(244), None), (Spacing(4), None), (Opcode("andi.", 66), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (Argument(Unsigned(220)), None), (Eol, None)]
[(Address(248), None), (Spacing(4), None), (Opcode("bne", 43), None), (BranchDest(256), None), (Basic(" ~>"), Some(11)), (Eol, None)]
[(Address(252), None), (Spacing(4), None), (Opcode("stb", 166), None), (Argument(Opaque("r0")), None), (Basic(", "), None), (Argument(Signed(0)), None), (Basic("("), None), (Argument(Opaque("r5")), None), (Basic(")"), None), (Eol, None)]
[(Address(256), None), (Basic(" ~> "), Some(11)), (Opcode("li", 41), None), (Argument(Opaque("r3")), None), (Basic(", "), None), (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) }), None), (Basic("@sda21"), None), (Eol, None)]
[(Address(260), None), (Spacing(4), None), (Opcode("blr", 47), None), (Eol, None)]
[(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), (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), (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), (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), (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), (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), (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), (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), (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)]

View File

@ -39,7 +39,7 @@ Object {
name: "[.ctors]",
demangled_name: None,
address: 0,
size: 0,
size: 4,
kind: Section,
section: Some(
1,

View File

@ -0,0 +1,97 @@
---
source: objdiff-core/tests/arch_x86.rs
expression: diff.instruction_rows
---
[
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 0,
size: 1,
opcode: 640,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 1,
size: 2,
opcode: 414,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 3,
size: 5,
opcode: 640,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 8,
size: 5,
opcode: 59,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 13,
size: 3,
opcode: 7,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 16,
size: 1,
opcode: 590,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
InstructionDiffRow {
ins_ref: Some(
InstructionRef {
address: 17,
size: 1,
opcode: 662,
},
),
kind: None,
branch_from: None,
branch_to: None,
arg_diff: [],
},
]

View File

@ -0,0 +1,11 @@
---
source: objdiff-core/tests/arch_x86.rs
expression: output
---
[(Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Eol, Normal, 0)]
[(Address(1), Normal, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("esp")), Normal, 0), (Eol, Normal, 0)]
[(Address(3), Normal, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Symbol(Symbol { name: "$SG526", demangled_name: None, address: 4, size: 6, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
[(Address(8), Normal, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), 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(13), Normal, 5), (Spacing(4), Normal, 0), (Opcode("add", 7), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(4)), Normal, 0), (Eol, Normal, 0)]
[(Address(16), Normal, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Eol, Normal, 0)]
[(Address(17), Normal, 5), (Spacing(4), Normal, 0), (Opcode("ret", 662), Normal, 10), (Eol, Normal, 0)]

View File

@ -0,0 +1,200 @@
---
source: objdiff-core/tests/arch_x86.rs
expression: obj
---
Object {
arch: ArchX86 {
bits: 32,
endianness: Little,
},
symbols: [
Symbol {
name: "objdiffstaticdebug.cpp",
demangled_name: None,
address: 0,
size: 0,
kind: Unknown,
section: None,
flags: FlagSet(Local),
align: None,
virtual_address: None,
},
Symbol {
name: "@comp.id",
demangled_name: None,
address: 0,
size: 0,
kind: Object,
section: None,
flags: FlagSet(Local),
align: None,
virtual_address: None,
},
Symbol {
name: "[.drectve]",
demangled_name: None,
address: 0,
size: 38,
kind: Section,
section: Some(
0,
),
flags: FlagSet(Local),
align: None,
virtual_address: None,
},
Symbol {
name: "[.data]",
demangled_name: None,
address: 0,
size: 0,
kind: Section,
section: Some(
1,
),
flags: FlagSet(Local),
align: None,
virtual_address: None,
},
Symbol {
name: "?a@@3PAXA",
demangled_name: Some(
"void *a",
),
address: 0,
size: 4,
kind: Object,
section: Some(
1,
),
flags: FlagSet(Global | SizeInferred),
align: None,
virtual_address: None,
},
Symbol {
name: "[.text]",
demangled_name: None,
address: 0,
size: 0,
kind: Section,
section: Some(
2,
),
flags: FlagSet(Local),
align: None,
virtual_address: None,
},
Symbol {
name: "?PrintThing@@YAXXZ",
demangled_name: Some(
"void __cdecl PrintThing(void)",
),
address: 0,
size: 18,
kind: Function,
section: Some(
2,
),
flags: FlagSet(Local | SizeInferred),
align: None,
virtual_address: None,
},
Symbol {
name: "_printf",
demangled_name: None,
address: 0,
size: 0,
kind: Function,
section: None,
flags: FlagSet(Global),
align: None,
virtual_address: None,
},
Symbol {
name: "$SG526",
demangled_name: None,
address: 4,
size: 6,
kind: Object,
section: Some(
1,
),
flags: FlagSet(Local | SizeInferred),
align: None,
virtual_address: None,
},
],
sections: [
Section {
id: ".drectve-0",
name: ".drectve",
address: 0,
size: 38,
kind: Unknown,
data: SectionData(
0,
),
flags: FlagSet(),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".data-0",
name: ".data",
address: 0,
size: 10,
kind: Data,
data: SectionData(
10,
),
flags: FlagSet(),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 0,
target_symbol: 6,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
Section {
id: ".text-0",
name: ".text",
address: 0,
size: 18,
kind: Code,
data: SectionData(
18,
),
flags: FlagSet(),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 4,
target_symbol: 8,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 9,
target_symbol: 7,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
],
split_meta: None,
path: None,
timestamp: None,
}

View File

@ -0,0 +1,940 @@
---
source: objdiff-core/tests/arch_x86.rs
expression: obj.sections
---
[
Section {
id: ".drectve-0",
name: ".drectve",
address: 0,
size: 47,
kind: Unknown,
data: SectionData(
0,
),
flags: FlagSet(),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".debug$S-0",
name: ".debug$S",
address: 0,
size: 100,
kind: Unknown,
data: SectionData(
0,
),
flags: FlagSet(),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata-0",
name: ".rdata",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata-1",
name: ".rdata",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-0",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".data-combined",
name: ".data",
address: 0,
size: 56,
kind: Data,
data: SectionData(
56,
),
flags: FlagSet(Combined),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 0,
target_symbol: 44,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 16,
target_symbol: 44,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 32,
target_symbol: 44,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 48,
target_symbol: 6,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 52,
target_symbol: 8,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata-combined",
name: ".rdata",
address: 0,
size: 295,
kind: Data,
data: SectionData(
295,
),
flags: FlagSet(Combined),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 12,
target_symbol: 17,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 16,
target_symbol: 19,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 21,
target_symbol: 13,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 45,
target_symbol: 15,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 61,
target_symbol: 25,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 65,
target_symbol: 27,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 70,
target_symbol: 21,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 94,
target_symbol: 23,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 110,
target_symbol: 31,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 114,
target_symbol: 33,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 130,
target_symbol: 35,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 134,
target_symbol: 37,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 138,
target_symbol: 19,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 142,
target_symbol: 39,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 147,
target_symbol: 31,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 171,
target_symbol: 33,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 175,
target_symbol: 21,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 199,
target_symbol: 23,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 215,
target_symbol: 31,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 219,
target_symbol: 33,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 235,
target_symbol: 13,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 239,
target_symbol: 15,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 255,
target_symbol: 21,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 259,
target_symbol: 23,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 263,
target_symbol: 29,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 267,
target_symbol: 11,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 271,
target_symbol: 43,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 275,
target_symbol: 41,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 279,
target_symbol: 70,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 283,
target_symbol: 56,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 287,
target_symbol: 72,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 291,
target_symbol: 59,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-1",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-2",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".data$rs-1",
name: ".data$rs",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-3",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-4",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-5",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-6",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".data$rs-2",
name: ".data$rs",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-7",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-8",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-9",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-10",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-1",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-11",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-2",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-3",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-4",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-5",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$mn-6",
name: ".text$mn",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".text-combined",
name: ".text",
address: 0,
size: 268,
kind: Code,
data: SectionData(
268,
),
flags: FlagSet(Combined),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 4,
target_symbol: 62,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 9,
target_symbol: 53,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 29,
target_symbol: 60,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 48,
target_symbol: 52,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 68,
target_symbol: 11,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 84,
target_symbol: 64,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 104,
target_symbol: 66,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 124,
target_symbol: 6,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 134,
target_symbol: 8,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 145,
target_symbol: 57,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 153,
target_symbol: 54,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 172,
target_symbol: 54,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 191,
target_symbol: 52,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 218,
target_symbol: 57,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 237,
target_symbol: 52,
addend: 0,
},
Relocation {
flags: Coff(
6,
),
address: 257,
target_symbol: 68,
addend: 0,
},
Relocation {
flags: Coff(
20,
),
address: 262,
target_symbol: 60,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
Section {
id: ".text$yd-0",
name: ".text$yd",
address: 0,
size: 0,
kind: Code,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata-2",
name: ".rdata",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata-3",
name: ".rdata",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".data-0",
name: ".data",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-12",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".rdata$r-13",
name: ".rdata$r",
address: 0,
size: 0,
kind: Data,
data: SectionData(
0,
),
flags: FlagSet(Hidden),
relocations: [],
line_info: {},
virtual_address: None,
},
Section {
id: ".CRT$XCU-0",
name: ".CRT$XCU",
address: 0,
size: 4,
kind: Data,
data: SectionData(
4,
),
flags: FlagSet(),
relocations: [
Relocation {
flags: Coff(
6,
),
address: 0,
target_symbol: 61,
addend: 0,
},
],
line_info: {},
virtual_address: None,
},
Section {
id: ".chks64-0",
name: ".chks64",
address: 0,
size: 280,
kind: Unknown,
data: SectionData(
0,
),
flags: FlagSet(),
relocations: [],
line_info: {},
virtual_address: None,
},
]

View File

@ -4,14 +4,14 @@ use egui::{text::LayoutJob, Label, Response, Sense, Widget};
use egui_extras::TableRow;
use objdiff_core::{
diff::{
display::{display_row, DiffText, HighlightKind},
DiffObjConfig, InstructionArgDiffIndex, InstructionDiffKind, InstructionDiffRow,
ObjectDiff,
display::{display_row, DiffText, DiffTextColor, DiffTextSegment, HighlightKind},
DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff,
},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, Object, ParsedInstruction,
ResolvedRelocation, Section, Symbol,
},
util::ReallySigned,
};
use crate::views::{appearance::Appearance, symbol_diff::DiffViewAction};
@ -87,7 +87,7 @@ fn resolve_instruction_ref(
let section = &obj.sections[section_idx];
let offset = ins_ref.address.checked_sub(section.address)?;
let data = section.data.get(offset as usize..offset as usize + ins_ref.size as usize)?;
let relocation = section.relocation_at(ins_ref.address, obj);
let relocation = section.relocation_at(ins_ref, obj);
Some(ResolvedInstructionRef { symbol, section, section_idx, data, relocation })
}
@ -301,91 +301,65 @@ fn ins_context_menu(
#[must_use]
fn diff_text_ui(
ui: &mut egui::Ui,
text: DiffText<'_>,
diff: InstructionArgDiffIndex,
ins_diff: &InstructionDiffRow,
segment: DiffTextSegment,
appearance: &Appearance,
ins_view_state: &FunctionViewState,
column: usize,
space_width: f32,
response_cb: impl Fn(Response) -> Response,
) -> Option<DiffViewAction> {
let mut ret = None;
let label_text;
let mut base_color = match ins_diff.kind {
InstructionDiffKind::None
| InstructionDiffKind::OpMismatch
| InstructionDiffKind::ArgMismatch => appearance.text_color,
InstructionDiffKind::Replace => appearance.replace_color,
InstructionDiffKind::Delete => appearance.delete_color,
InstructionDiffKind::Insert => appearance.insert_color,
};
let mut pad_to = 0;
match text {
DiffText::Basic(text) => {
label_text = text.to_string();
}
DiffText::Line(num) => {
label_text = num.to_string();
base_color = appearance.deemphasized_text_color;
pad_to = 5;
}
DiffText::Address(addr) => {
label_text = format!("{:x}:", addr);
pad_to = 5;
}
DiffText::Opcode(mnemonic, _op) => {
label_text = mnemonic.to_string();
if ins_diff.kind == InstructionDiffKind::OpMismatch {
base_color = appearance.replace_color;
}
pad_to = 8;
}
DiffText::Argument(arg) => {
label_text = arg.to_string();
}
DiffText::BranchDest(addr) => {
label_text = format!("{addr:x}");
}
DiffText::Symbol(sym) => {
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
label_text = name.clone();
base_color = appearance.emphasized_text_color;
}
DiffText::Addend(addend) => {
label_text = match addend.cmp(&0i64) {
let highlight_kind = HighlightKind::from(&segment.text);
let label_text = match segment.text {
DiffText::Basic(text) => text.to_string(),
DiffText::Line(num) => format!("{num} "),
DiffText::Address(addr) => format!("{:x}:", addr),
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::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::Less => format!("-{:#x}", -addend),
_ => "".to_string(),
};
base_color = appearance.emphasized_text_color;
}
_ => String::new(),
},
DiffText::Spacing(n) => {
ui.add_space(n as f32 * space_width);
return ret;
}
DiffText::Eol => {
label_text = "\n".to_string();
}
}
if let Some(diff_idx) = diff.get() {
base_color = appearance.diff_colors[diff_idx as usize % appearance.diff_colors.len()];
return None;
}
DiffText::Eol => "\n".to_string(),
};
let len = label_text.len();
let highlight = *ins_view_state.highlight(column) == text;
let highlight = highlight_kind != HighlightKind::None
&& *ins_view_state.highlight(column) == highlight_kind;
let color = match segment.color {
DiffTextColor::Normal => appearance.text_color,
DiffTextColor::Dim => appearance.deemphasized_text_color,
DiffTextColor::Bright => appearance.emphasized_text_color,
DiffTextColor::Replace => appearance.replace_color,
DiffTextColor::Delete => appearance.delete_color,
DiffTextColor::Insert => appearance.insert_color,
DiffTextColor::Rotating(i) => {
appearance.diff_colors[i as usize % appearance.diff_colors.len()]
}
};
let mut response = Label::new(LayoutJob::single_section(
label_text,
appearance.code_text_format(base_color, highlight),
appearance.code_text_format(color, highlight),
))
.sense(Sense::click())
.ui(ui);
response = response_cb(response);
let mut ret = None;
if response.clicked() {
ret = Some(DiffViewAction::SetDiffHighlight(column, text.into()));
ret = Some(DiffViewAction::SetDiffHighlight(column, highlight_kind));
}
if len < pad_to {
ui.add_space((pad_to - len) as f32 * space_width);
if len < segment.pad_to as usize {
ui.add_space((segment.pad_to as usize - len) as f32 * space_width);
}
ret
}
@ -409,18 +383,10 @@ fn asm_row_ui(
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
}
let space_width = ui.fonts(|f| f.glyph_width(&appearance.code_font, ' '));
display_row(obj, symbol_idx, ins_diff, diff_config, |text, diff| {
if let Some(action) = diff_text_ui(
ui,
text,
diff,
ins_diff,
appearance,
ins_view_state,
column,
space_width,
&response_cb,
) {
display_row(obj, symbol_idx, ins_diff, diff_config, |segment| {
if let Some(action) =
diff_text_ui(ui, segment, appearance, ins_view_state, column, space_width, &response_cb)
{
ret = Some(action);
}
Ok(())

View File

@ -10,8 +10,7 @@
"license": "MIT OR Apache-2.0",
"devDependencies": {
"@biomejs/biome": "^1.9.3",
"@bytecodealliance/jco": "^1.10.1",
"@bytecodealliance/preview2-shim": "^0.17.1",
"@bytecodealliance/jco": "^1.10.2",
"@rslib/core": "^0.4.1",
"typescript": "^5.7.2"
}
@ -196,9 +195,9 @@
}
},
"node_modules/@bytecodealliance/jco": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.10.1.tgz",
"integrity": "sha512-1HfO7HT+Rrvviv/l0CBm5O9/qtx3463W7ulZ+P7AV6icpHM97VeszQ1qbiegUxflT2GRXp4lVSaOaNGxoATQoQ==",
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.10.2.tgz",
"integrity": "sha512-ShBb9Jul4CYo4asmfDdjmYE2+4TgJLSHhsRMyVDvROA5j6s+cAKMmlsUjOrS6QM5TL8GJb48G9jsxif6na6qYg==",
"dev": true,
"license": "(Apache-2.0 WITH LLVM-exception)",
"workspaces": [
@ -206,7 +205,7 @@
],
"dependencies": {
"@bytecodealliance/componentize-js": "^0.17.0",
"@bytecodealliance/preview2-shim": "file:packages/preview2-shim",
"@bytecodealliance/preview2-shim": "^0.17.2",
"binaryen": "^122.0.0",
"chalk-template": "^1",
"commander": "^12",
@ -218,17 +217,10 @@
"jco": "src/jco.js"
}
},
"node_modules/@bytecodealliance/jco/node_modules/@bytecodealliance/preview2-shim": {
"resolved": "node_modules/@bytecodealliance/jco/packages/preview2-shim",
"link": true
},
"node_modules/@bytecodealliance/jco/packages/preview2-shim": {
"dev": true
},
"node_modules/@bytecodealliance/preview2-shim": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.1.tgz",
"integrity": "sha512-h1qLL0TN5KXk/zagY2BtbZuDX6xYjz4Br9RZXEa0ID4UpiPc0agUMhTdz9r89G4vX5SU/tqBg1A6UNv2+DJ5pg==",
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.2.tgz",
"integrity": "sha512-mNm/lblgES8UkVle8rGImXOz4TtL3eU3inHay/7TVchkKrb/lgcVvTK0+VAw8p5zQ0rgQsXm1j5dOlAAd+MeoA==",
"dev": true,
"license": "(Apache-2.0 WITH LLVM-exception)"
},

View File

@ -23,8 +23,7 @@
},
"devDependencies": {
"@biomejs/biome": "^1.9.3",
"@bytecodealliance/jco": "^1.10.1",
"@bytecodealliance/preview2-shim": "^0.17.1",
"@bytecodealliance/jco": "^1.10.2",
"@rslib/core": "^0.4.1",
"typescript": "^5.7.2"
}

View File

@ -20,15 +20,15 @@ wit_bindgen::generate!({
});
use exports::objdiff::core::{
diff::Guest as GuestDiff,
diff_types::{
DiffConfigBorrow, DiffResult, Guest as GuestDiffTypes, GuestDiffConfig, GuestObject,
diff::{
DiffConfigBorrow, DiffResult, Guest as GuestDiff, GuestDiffConfig, GuestObject,
GuestObjectDiff, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow,
},
display_types::{
ContextMenuItem, DiffText, DiffTextOpcode, DiffTextSegment, DiffTextSymbol, DisplayConfig,
HoverItem, InstructionDiffKind, InstructionDiffRow, SectionDisplay, SectionDisplaySymbol,
SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind, SymbolRef,
display::{
ContextMenuItem, DiffText, DiffTextColor, DiffTextOpcode, DiffTextSegment, DiffTextSymbol,
DisplayConfig, Guest as GuestDisplay, HoverItem, InstructionDiffKind, InstructionDiffRow,
SectionDisplay, SectionDisplaySymbol, SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind,
SymbolRef,
},
};
@ -48,13 +48,11 @@ struct ResourceObjectDiff(Rc<obj::Object>, diff::ObjectDiff);
#[repr(transparent)]
struct ResourceDiffConfig(RefCell<diff::DiffObjConfig>);
impl GuestDiffTypes for Component {
impl GuestDiff for Component {
type DiffConfig = ResourceDiffConfig;
type Object = ResourceObject;
type ObjectDiff = ResourceObjectDiff;
}
impl GuestDiff for Component {
fn run_diff(
left: Option<ObjectBorrow>,
right: Option<ObjectBorrow>,
@ -85,7 +83,9 @@ impl GuestDiff for Component {
}),
})
}
}
impl GuestDisplay for Component {
fn symbol_context(_obj: ObjectBorrow, _symbol: SymbolRef) -> Vec<ContextMenuItem> { todo!() }
fn symbol_hover(_obj: ObjectBorrow, _symbol: SymbolRef) -> Vec<HoverItem> { todo!() }
@ -195,8 +195,8 @@ impl GuestDiff for Component {
};
let row = &symbol_diff.instruction_rows[row_index as usize];
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
diff::display::display_row(obj, symbol_idx, row, &diff_config, |text, idx| {
segments.push(DiffTextSegment { text: DiffText::from(text), diff_index: idx.get() });
diff::display::display_row(obj, symbol_idx, row, &diff_config, |segment| {
segments.push(DiffTextSegment::from(segment));
Ok(())
})
.unwrap();
@ -243,9 +243,9 @@ impl From<diff::display::DiffText<'_>> for DiffText {
DiffText::Opcode(DiffTextOpcode { mnemonic: n.to_string(), opcode: op })
}
diff::display::DiffText::Argument(s) => match s {
obj::InstructionArgValue::Signed(v) => DiffText::Signed(*v),
obj::InstructionArgValue::Unsigned(v) => DiffText::Unsigned(*v),
obj::InstructionArgValue::Opaque(v) => DiffText::Opaque(v.to_string()),
obj::InstructionArgValue::Signed(v) => DiffText::Signed(v),
obj::InstructionArgValue::Unsigned(v) => DiffText::Unsigned(v),
obj::InstructionArgValue::Opaque(v) => DiffText::Opaque(v.into_owned()),
},
diff::display::DiffText::BranchDest(v) => DiffText::BranchDest(v),
diff::display::DiffText::Symbol(s) => DiffText::Symbol(DiffTextSymbol {
@ -253,12 +253,36 @@ impl From<diff::display::DiffText<'_>> for DiffText {
demangled_name: s.demangled_name.clone(),
}),
diff::display::DiffText::Addend(v) => DiffText::Addend(v),
diff::display::DiffText::Spacing(v) => DiffText::Spacing(v as u32),
diff::display::DiffText::Spacing(v) => DiffText::Spacing(v),
diff::display::DiffText::Eol => DiffText::Eol,
}
}
}
impl From<diff::display::DiffTextColor> for DiffTextColor {
fn from(value: diff::display::DiffTextColor) -> Self {
match value {
diff::display::DiffTextColor::Normal => DiffTextColor::Normal,
diff::display::DiffTextColor::Dim => DiffTextColor::Dim,
diff::display::DiffTextColor::Bright => DiffTextColor::Bright,
diff::display::DiffTextColor::Replace => DiffTextColor::Replace,
diff::display::DiffTextColor::Delete => DiffTextColor::Delete,
diff::display::DiffTextColor::Insert => DiffTextColor::Insert,
diff::display::DiffTextColor::Rotating(v) => DiffTextColor::Rotating(v),
}
}
}
impl From<diff::display::DiffTextSegment<'_>> for DiffTextSegment {
fn from(segment: diff::display::DiffTextSegment) -> Self {
DiffTextSegment {
text: DiffText::from(segment.text),
color: DiffTextColor::from(segment.color),
pad_to: segment.pad_to,
}
}
}
impl From<diff::InstructionDiffKind> for InstructionDiffKind {
fn from(kind: diff::InstructionDiffKind) -> Self {
match kind {

View File

@ -2,7 +2,7 @@ package objdiff:core;
use wasi:logging/logging@0.1.0-draft;
interface diff-types {
interface diff {
resource diff-config {
constructor();
set-property: func(id: string, value: string) -> result<_, string>;
@ -33,9 +33,21 @@ interface diff-types {
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-types {
interface display {
use diff.{
object,
object-diff,
diff-config
};
type symbol-ref = u32;
record display-config {
@ -153,16 +165,28 @@ interface display-types {
// Relocation addend
addend(s64),
// Number of spaces
spacing(u32),
spacing(u8),
// End of line
eol,
}
variant diff-text-color {
normal,
dim,
bright,
replace,
delete,
insert,
rotating(u8),
}
record diff-text-segment {
// Text to display
text: diff-text,
// Index for colorization
diff-index: option<u32>,
// Text color
color: diff-text-color,
// Number of spaces to pad to
pad-to: u8,
}
record instruction-diff-row {
@ -180,32 +204,6 @@ interface display-types {
insert,
delete,
}
}
interface diff {
use diff-types.{
object,
object-diff,
diff-config,
diff-result
};
use display-types.{
section-display-symbol,
section-display,
symbol-ref,
symbol-filter,
symbol-display,
context-menu-item,
hover-item,
display-config,
instruction-diff-row
};
run-diff: func(
left: option<borrow<object>>,
right: option<borrow<object>>,
config: borrow<diff-config>,
) -> result<diff-result, string>;
display-sections: func(
diff: borrow<object-diff>,
@ -241,8 +239,7 @@ world api {
use logging.{level};
export diff;
export diff-types;
export display-types;
export display;
export init: func(level: level);
export version: func() -> string;