mirror of
https://github.com/encounter/objdiff.git
synced 2025-06-07 15:13:47 +00:00
Reimplement x86 arch, MSVC section group combining
Plus display_row/DiffText refactoring
This commit is contained in:
parent
506c251d68
commit
95868f1d19
1
.github/workflows/build.yaml
vendored
1
.github/workflows/build.yaml
vendored
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ all = [
|
||||
"arm64",
|
||||
"mips",
|
||||
"ppc",
|
||||
# "x86",
|
||||
"x86",
|
||||
]
|
||||
# Implicit, used to check if any arch is enabled
|
||||
any-arch = [
|
||||
|
@ -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(())
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}"),
|
||||
},
|
||||
|
@ -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 })
|
||||
}
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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 = §ions[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(§ion);
|
||||
@ -142,12 +233,14 @@ fn map_sections(
|
||||
.and_then(|v| v.get(s.index().0).cloned())
|
||||
});
|
||||
|
||||
let relocations = map_relocations(arch, obj_file, §ion)?;
|
||||
|
||||
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('$') {
|
||||
§ion.name[..i]
|
||||
} else {
|
||||
§ion.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, §ion_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 = §ions[a].name;
|
||||
let b_name = §ions[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 = §ions[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, §ions, §ion_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, §ion_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));
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ expression: "(sections, symbols)"
|
||||
virtual_address: None,
|
||||
},
|
||||
Section {
|
||||
id: ".data-0",
|
||||
id: ".data-combined",
|
||||
name: ".data",
|
||||
address: 0,
|
||||
size: 12,
|
||||
|
@ -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 {
|
||||
|
28
objdiff-core/tests/arch_x86.rs
Normal file
28
objdiff-core/tests/arch_x86.rs
Normal 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);
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
@ -49,10 +49,6 @@ expression: sections_display
|
||||
59.02353,
|
||||
),
|
||||
symbols: [
|
||||
SectionDisplaySymbol {
|
||||
symbol: 1,
|
||||
is_mapping_symbol: false,
|
||||
},
|
||||
SectionDisplaySymbol {
|
||||
symbol: 3,
|
||||
is_mapping_symbol: false,
|
||||
|
@ -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)]
|
||||
|
@ -39,7 +39,7 @@ Object {
|
||||
name: "[.ctors]",
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
size: 4,
|
||||
kind: Section,
|
||||
section: Some(
|
||||
1,
|
||||
|
97
objdiff-core/tests/snapshots/arch_x86__read_x86-2.snap
Normal file
97
objdiff-core/tests/snapshots/arch_x86__read_x86-2.snap
Normal 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: [],
|
||||
},
|
||||
]
|
11
objdiff-core/tests/snapshots/arch_x86__read_x86-3.snap
Normal file
11
objdiff-core/tests/snapshots/arch_x86__read_x86-3.snap
Normal 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)]
|
200
objdiff-core/tests/snapshots/arch_x86__read_x86.snap
Normal file
200
objdiff-core/tests/snapshots/arch_x86__read_x86.snap
Normal 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,
|
||||
}
|
@ -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,
|
||||
},
|
||||
]
|
@ -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(())
|
||||
|
24
objdiff-wasm/package-lock.json
generated
24
objdiff-wasm/package-lock.json
generated
@ -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)"
|
||||
},
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user