Reimplement x86 arch, MSVC section group combining

Plus display_row/DiffText refactoring
This commit is contained in:
Luke Street
2025-03-02 16:13:12 -07:00
parent 506c251d68
commit 95868f1d19
29 changed files with 2580 additions and 1044 deletions
-1
View File
@@ -235,7 +235,6 @@ jobs:
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@nightly
with:
targets: wasm32-wasip2
components: rust-src
- name: Cache Rust workspace
uses: Swatinem/rust-cache@v2
+35 -67
View File
@@ -1,10 +1,10 @@
use std::cmp::Ordering;
use core::cmp::Ordering;
use anyhow::{bail, Result};
use crossterm::event::{Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind};
use objdiff_core::{
diff::{
display::{display_row, DiffText, HighlightKind},
display::{display_row, DiffText, DiffTextColor, HighlightKind},
DiffObjConfig, FunctionRelocDiffs, InstructionDiffKind, ObjectDiff, SymbolDiff,
},
obj::Object,
@@ -522,87 +522,55 @@ impl FunctionDiffUi {
let mut sx = rect.x;
let sy = rect.y + y as u16;
let mut line = Line::default();
display_row(obj, symbol_index, ins_row, diff_config, |text, diff_idx| {
let label_text;
let mut base_color = match ins_row.kind {
InstructionDiffKind::None
| InstructionDiffKind::OpMismatch
| InstructionDiffKind::ArgMismatch => Color::Gray,
InstructionDiffKind::Replace => Color::Cyan,
InstructionDiffKind::Delete => Color::Red,
InstructionDiffKind::Insert => Color::Green,
};
if let Some(idx) = diff_idx.get() {
base_color = COLOR_ROTATION[idx as usize % COLOR_ROTATION.len()];
}
let mut pad_to = 0;
match text {
DiffText::Basic(text) => {
label_text = text.to_string();
}
DiffText::Line(num) => {
label_text = format!("{num} ");
base_color = Color::DarkGray;
pad_to = 5;
}
DiffText::Address(addr) => {
label_text = format!("{:x}:", addr);
pad_to = 5;
}
DiffText::Opcode(mnemonic, _op) => {
label_text = mnemonic.to_string();
if ins_row.kind == InstructionDiffKind::OpMismatch {
base_color = Color::Blue;
}
pad_to = 8;
}
DiffText::Argument(arg) => {
label_text = arg.to_string();
}
DiffText::BranchDest(addr) => {
label_text = format!("{addr:x}");
}
display_row(obj, symbol_index, ins_row, diff_config, |segment| {
let highlight_kind = HighlightKind::from(&segment.text);
let label_text = match segment.text {
DiffText::Basic(text) => text.to_string(),
DiffText::Line(num) => format!("{num} "),
DiffText::Address(addr) => format!("{:x}:", addr),
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
DiffText::Argument(arg) => arg.to_string(),
DiffText::BranchDest(addr) => format!("{addr:x}"),
DiffText::Symbol(sym) => {
let name = sym.demangled_name.as_ref().unwrap_or(&sym.name);
label_text = name.clone();
if diff_idx.is_none() {
base_color = Color::White;
}
}
DiffText::Addend(addend) => {
label_text = 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;
}
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),
_ => 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;
}
+1 -1
View File
@@ -26,7 +26,7 @@ all = [
"arm64",
"mips",
"ppc",
# "x86",
"x86",
]
# Implicit, used to check if any arch is enabled
any-arch = [
+51 -89
View File
@@ -16,8 +16,8 @@ use crate::{
arch::Arch,
diff::{display::InstructionPart, ArmArchVersion, ArmR9Usage, DiffObjConfig},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, RelocationFlags, ResolvedRelocation,
ScannedInstruction, SymbolFlag, SymbolFlagSet, SymbolKind,
InstructionRef, RelocationFlags, ResolvedRelocation, ScannedInstruction, SymbolFlag,
SymbolFlagSet, SymbolKind,
},
};
@@ -261,9 +261,9 @@ impl Arch for ArchArm {
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
) -> Result<()> {
let (ins, parsed_ins) = self.parse_ins_ref(ins_ref, code, diff_config)?;
cb(InstructionPart::Opcode(Cow::Borrowed(parsed_ins.mnemonic), ins_ref.opcode))?;
cb(InstructionPart::opcode(parsed_ins.mnemonic, ins_ref.opcode))?;
if ins == unarm::Ins::Data && relocation.is_some() {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::reloc())?;
} else {
push_args(
&parsed_ins,
@@ -396,12 +396,10 @@ fn push_args(
})
| args::Argument::CoOption(_) => {
deref = false;
arg_cb(InstructionPart::Basic("]"))?;
arg_cb(InstructionPart::basic("]"))?;
if writeback {
writeback = false;
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("!".into()),
)))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
_ => {}
@@ -409,130 +407,98 @@ fn push_args(
}
if i > 0 {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
if reloc_arg == Some(i) {
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::reloc())?;
} else {
match arg {
args::Argument::None => {}
args::Argument::Reg(reg) => {
if reg.deref {
deref = true;
arg_cb(InstructionPart::Basic("["))?;
arg_cb(InstructionPart::basic("["))?;
}
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
reg.reg.display(display_options.reg_names).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
reg.reg.display(display_options.reg_names).to_string(),
))?;
if reg.writeback {
if reg.deref {
writeback = true;
} else {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque("!".into()),
)))?;
arg_cb(InstructionPart::opaque("!"))?;
}
}
}
args::Argument::RegList(reg_list) => {
arg_cb(InstructionPart::Basic("{"))?;
arg_cb(InstructionPart::basic("{"))?;
let mut first = true;
for i in 0..16 {
if (reg_list.regs & (1 << i)) != 0 {
if !first {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
args::Register::parse(i)
.display(display_options.reg_names)
.to_string()
.into(),
),
)))?;
arg_cb(InstructionPart::opaque(
args::Register::parse(i)
.display(display_options.reg_names)
.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(())
File diff suppressed because it is too large Load Diff
+37 -41
View File
@@ -159,7 +159,7 @@ impl Arch for ArchMips {
let instruction = self.parse_ins_ref(ins_ref, code, diff_config)?;
let display_flags = self.instruction_display_flags(diff_config);
let opcode = instruction.opcode();
cb(InstructionPart::Opcode(Cow::Borrowed(opcode.name()), opcode as u16))?;
cb(InstructionPart::opcode(opcode.name(), opcode as u16))?;
push_args(&instruction, relocation, function_range, section_index, &display_flags, cb)?;
Ok(())
}
@@ -244,7 +244,7 @@ fn push_args(
let operands = instruction.valued_operands_iter();
for (idx, op) in operands.enumerate() {
if idx > 0 {
arg_cb(InstructionPart::Separator)?;
arg_cb(InstructionPart::separator())?;
}
match op {
@@ -252,10 +252,10 @@ fn push_args(
if let Some(resolved) = relocation {
push_reloc(resolved.relocation, &mut arg_cb)?;
} else {
arg_cb(InstructionPart::Arg(InstructionArg::Value(match imm {
IU16::Integer(s) => InstructionArgValue::Signed(s as i64),
IU16::Unsigned(u) => InstructionArgValue::Unsigned(u as u64),
})))?;
arg_cb(match imm {
IU16::Integer(s) => InstructionPart::signed(s),
IU16::Unsigned(u) => InstructionPart::unsigned(u),
})?;
}
}
ValuedOperand::core_label(..) | ValuedOperand::core_branch_target_label(..) => {
@@ -273,7 +273,7 @@ fn push_args(
{
// TODO move this logic up a level
let target_address = target_address.unwrap();
arg_cb(InstructionPart::Arg(InstructionArg::BranchDest(target_address)))?;
arg_cb(InstructionPart::branch_dest(target_address))?;
} else {
push_reloc(resolved.relocation, &mut arg_cb)?;
}
@@ -281,13 +281,11 @@ fn push_args(
.get_branch_offset_generic()
.map(|o| (instruction.vram() + o).inner() as u64)
{
arg_cb(InstructionPart::Arg(InstructionArg::BranchDest(branch_dest)))?;
arg_cb(InstructionPart::branch_dest(branch_dest))?;
} else {
arg_cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(
op.display(instruction, display_flags, None::<&str>).to_string().into(),
),
)))?;
arg_cb(InstructionPart::opaque(
op.display(instruction, display_flags, None::<&str>).to_string(),
))?;
}
}
ValuedOperand::core_immediate_base(imm, base) => {
@@ -299,28 +297,26 @@ fn push_args(
IU16::Unsigned(u) => InstructionArgValue::Unsigned(u as u64),
})))?;
}
arg_cb(InstructionPart::Basic("("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(
base.either_name(instruction.flags().abi(), display_flags.named_gpr()).into(),
))))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("("))?;
arg_cb(InstructionPart::opaque(
base.either_name(instruction.flags().abi(), display_flags.named_gpr()),
))?;
arg_cb(InstructionPart::basic(")"))?;
}
// ValuedOperand::r5900_immediate15(..) => match relocation {
// Some(resolved)
// if resolved.relocation.flags == RelocationFlags::Elf(R_MIPS15_S3) =>
// {
// push_reloc(&resolved.relocation, &mut arg_cb, &mut plain_cb)?;
// push_reloc(&resolved.relocation, &mut arg_cb)?;
// }
// _ => {
// arg_cb(InstructionArg::Value(InstructionArgValue::Opaque(
// op.disassemble(&instruction, None).into(),
// )))?;
// arg_cb(InstructionPart::opaque(op.disassemble(&instruction, None)))?;
// }
// },
_ => {
arg_cb(InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(
op.display(instruction, display_flags, None::<&str>).to_string().into(),
))))?;
arg_cb(InstructionPart::opaque(
op.display(instruction, display_flags, None::<&str>).to_string(),
))?;
}
}
}
@@ -334,36 +330,36 @@ fn push_reloc(
match reloc.flags {
RelocationFlags::Elf(r_type) => match r_type {
elf::R_MIPS_HI16 => {
arg_cb(InstructionPart::Basic("%hi("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%hi("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_LO16 => {
arg_cb(InstructionPart::Basic("%lo("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%lo("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_GOT16 => {
arg_cb(InstructionPart::Basic("%got("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%got("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_CALL16 => {
arg_cb(InstructionPart::Basic("%call16("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%call16("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_GPREL16 => {
arg_cb(InstructionPart::Basic("%gp_rel("))?;
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::Basic(")"))?;
arg_cb(InstructionPart::basic("%gp_rel("))?;
arg_cb(InstructionPart::reloc())?;
arg_cb(InstructionPart::basic(")"))?;
}
elf::R_MIPS_32
| elf::R_MIPS_26
| elf::R_MIPS_LITERAL
| elf::R_MIPS_PC16
| R_MIPS15_S3 => {
arg_cb(InstructionPart::Arg(InstructionArg::Reloc))?;
arg_cb(InstructionPart::reloc())?;
}
_ => bail!("Unsupported ELF MIPS relocation type {r_type}"),
},
+9 -4
View File
@@ -8,8 +8,8 @@ use object::{File, Relocation, Section};
use crate::{
diff::{display::InstructionPart, DiffObjConfig},
obj::{
InstructionRef, ParsedInstruction, RelocationFlags, ResolvedRelocation, ScannedInstruction,
SymbolFlagSet, SymbolKind,
InstructionArg, InstructionRef, ParsedInstruction, RelocationFlags, ResolvedRelocation,
ScannedInstruction, SymbolFlagSet, SymbolKind,
},
util::ReallySigned,
};
@@ -195,13 +195,18 @@ pub trait Arch: Send + Sync + Debug {
diff_config,
&mut |part| {
match part {
InstructionPart::Opcode(m, _) => mnemonic = Some(m),
InstructionPart::Arg(arg) => args.push(arg),
InstructionPart::Opcode(m, _) => mnemonic = Some(Cow::Owned(m.into_owned())),
InstructionPart::Arg(arg) => args.push(arg.into_static()),
_ => {}
}
Ok(())
},
)?;
// If the instruction has a relocation, but we didn't format it in the display, add it to
// the end of the arguments list.
if relocation.is_some() && !args.contains(&InstructionArg::Reloc) {
args.push(InstructionArg::Reloc);
}
Ok(ParsedInstruction { ins_ref, mnemonic: mnemonic.unwrap_or_default(), args })
}
+28 -45
View File
@@ -18,8 +18,8 @@ use crate::{
arch::{Arch, DataType},
diff::{display::InstructionPart, DiffObjConfig},
obj::{
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
ResolvedRelocation, ScannedInstruction, Symbol, SymbolFlag, SymbolFlagSet,
InstructionRef, Relocation, RelocationFlags, ResolvedRelocation, ScannedInstruction,
Symbol, SymbolFlag, SymbolFlagSet,
},
};
@@ -113,14 +113,14 @@ impl Arch for ArchPpc {
let op = ppc750cl::Opcode::from(ins_ref.opcode as u8);
let ins = ppc750cl::Ins { code, op }.simplified();
cb(InstructionPart::Opcode(Cow::Borrowed(ins.mnemonic), ins_ref.opcode))?;
cb(InstructionPart::opcode(ins.mnemonic, ins_ref.opcode))?;
let reloc_arg = self.find_reloc_arg(&ins, relocation);
let mut writing_offset = false;
for (idx, arg) in ins.args_iter().enumerate() {
if idx > 0 && !writing_offset {
cb(InstructionPart::Separator)?;
cb(InstructionPart::separator())?;
}
if reloc_arg == Some(idx) {
@@ -135,39 +135,22 @@ impl Arch for ArchPpc {
}
} else {
match arg {
ppc750cl::Argument::Simm(simm) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Signed(simm.0 as i64),
)))?;
}
ppc750cl::Argument::Uimm(uimm) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Unsigned(uimm.0 as u64),
)))?;
}
ppc750cl::Argument::Offset(offset) => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Signed(offset.0 as i64),
)))?;
}
ppc750cl::Argument::BranchDest(dest) => {
let dest = (ins_ref.address as u32).wrapping_add_signed(dest.0) as u64;
cb(InstructionPart::Arg(InstructionArg::BranchDest(dest)))?;
}
_ => {
cb(InstructionPart::Arg(InstructionArg::Value(
InstructionArgValue::Opaque(arg.to_string().into()),
)))?;
}
};
ppc750cl::Argument::Simm(simm) => cb(InstructionPart::signed(simm.0)),
ppc750cl::Argument::Uimm(uimm) => cb(InstructionPart::unsigned(uimm.0)),
ppc750cl::Argument::Offset(offset) => cb(InstructionPart::signed(offset.0)),
ppc750cl::Argument::BranchDest(dest) => cb(InstructionPart::branch_dest(
(ins_ref.address as u32).wrapping_add_signed(dest.0),
)),
_ => cb(InstructionPart::opaque(arg.to_string())),
}?;
}
if writing_offset {
cb(InstructionPart::Basic(")"))?;
cb(InstructionPart::basic(")"))?;
writing_offset = false;
}
if is_offset_arg(arg) {
cb(InstructionPart::Basic("("))?;
cb(InstructionPart::basic("("))?;
writing_offset = true;
}
}
@@ -276,33 +259,33 @@ fn display_reloc(
match resolved.relocation.flags {
RelocationFlags::Elf(r_type) => match r_type {
elf::R_PPC_ADDR16_LO => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@l"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@l"))?;
}
elf::R_PPC_ADDR16_HI => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@h"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@h"))?;
}
elf::R_PPC_ADDR16_HA => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@ha"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@ha"))?;
}
elf::R_PPC_EMB_SDA21 => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic("@sda21"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@sda21"))?;
}
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14 => {
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::reloc())?;
}
elf::R_PPC_NONE => {
// Fake pool relocation.
cb(InstructionPart::Basic("<"))?;
cb(InstructionPart::Arg(InstructionArg::Reloc))?;
cb(InstructionPart::Basic(">"))?;
cb(InstructionPart::basic("<"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic(">"))?;
}
_ => cb(InstructionPart::Arg(InstructionArg::Reloc))?,
_ => cb(InstructionPart::reloc())?,
},
_ => cb(InstructionPart::Arg(InstructionArg::Reloc))?,
_ => cb(InstructionPart::reloc())?,
};
Ok(())
}
File diff suppressed because it is too large Load Diff
+9 -9
View File
@@ -107,8 +107,8 @@ pub fn diff_code(
right_obj,
left_symbol_idx,
right_symbol_idx,
left_row.ins_ref.as_ref(),
right_row.ins_ref.as_ref(),
left_row.ins_ref,
right_row.ins_ref,
left_row,
right_row,
diff_config,
@@ -226,7 +226,7 @@ fn resolve_branches(
for ((i, ins_diff), ins) in
rows.iter_mut().enumerate().filter(|(_, row)| row.ins_ref.is_some()).zip(ops)
{
let branch_dest = if let Some(resolved) = section.relocation_at(ins.ins_ref.address, obj) {
let branch_dest = if let Some(resolved) = section.relocation_at(ins.ins_ref, obj) {
if resolved.symbol.section == Some(section_index) {
// If the relocation target is in the same section, use it as the branch destination
resolved.symbol.address.checked_add_signed(resolved.relocation.addend)
@@ -401,8 +401,8 @@ fn diff_instruction(
right_obj: &Object,
left_symbol_idx: usize,
right_symbol_idx: usize,
l: Option<&InstructionRef>,
r: Option<&InstructionRef>,
l: Option<InstructionRef>,
r: Option<InstructionRef>,
left_row: &InstructionDiffRow,
right_row: &InstructionDiffRow,
diff_config: &DiffObjConfig,
@@ -439,8 +439,8 @@ fn diff_instruction(
.ok_or_else(|| anyhow!("Missing section for symbol"))?;
// Resolve relocations
let left_reloc = left_section.relocation_at(l.address, left_obj);
let right_reloc = right_section.relocation_at(r.address, right_obj);
let left_reloc = left_section.relocation_at(l, left_obj);
let right_reloc = right_section.relocation_at(r, right_obj);
// Compare instruction data
let left_data = left_section.data_range(l.address, l.size as usize).ok_or_else(|| {
@@ -460,7 +460,7 @@ fn diff_instruction(
if left_data != right_data {
// If data doesn't match, process instructions and compare args
let left_ins = left_obj.arch.process_instruction(
*l,
l,
left_data,
left_reloc,
left_symbol.address..left_symbol.address + left_symbol.size,
@@ -468,7 +468,7 @@ fn diff_instruction(
diff_config,
)?;
let right_ins = left_obj.arch.process_instruction(
*r,
r,
right_data,
right_reloc,
right_symbol.address..right_symbol.address + right_symbol.size,
+191 -45
View File
@@ -12,14 +12,14 @@ use itertools::Itertools;
use regex::Regex;
use crate::{
diff::{DiffObjConfig, InstructionArgDiffIndex, InstructionDiffRow, ObjectDiff, SymbolDiff},
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
obj::{
InstructionArg, InstructionArgValue, Object, SectionFlag, SectionKind, Symbol, SymbolFlag,
SymbolKind,
},
};
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Clone)]
pub enum DiffText<'a> {
/// Basic text
Basic(&'a str),
@@ -30,7 +30,7 @@ pub enum DiffText<'a> {
/// Instruction mnemonic
Opcode(&'a str, u16),
/// Instruction argument
Argument(&'a InstructionArgValue),
Argument(InstructionArgValue<'a>),
/// Branch destination
BranchDest(u64),
/// Symbol name
@@ -38,63 +38,155 @@ pub enum DiffText<'a> {
/// Relocation addend
Addend(i64),
/// Number of spaces
Spacing(usize),
Spacing(u8),
/// End of line
Eol,
}
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
pub enum DiffTextColor {
#[default]
Normal, // Grey
Dim, // Dark grey
Bright, // White
Replace, // Blue
Delete, // Red
Insert, // Green
Rotating(u8),
}
#[derive(Debug, Clone)]
pub struct DiffTextSegment<'a> {
pub text: DiffText<'a>,
pub color: DiffTextColor,
pub pad_to: u8,
}
impl<'a> DiffTextSegment<'a> {
#[inline(always)]
pub fn basic(text: &'a str, color: DiffTextColor) -> Self {
Self { text: DiffText::Basic(text), color, pad_to: 0 }
}
#[inline(always)]
pub fn spacing(spaces: u8) -> Self {
Self { text: DiffText::Spacing(spaces), color: DiffTextColor::Normal, pad_to: 0 }
}
}
const EOL_SEGMENT: DiffTextSegment<'static> =
DiffTextSegment { text: DiffText::Eol, color: DiffTextColor::Normal, pad_to: 0 };
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub enum HighlightKind {
#[default]
None,
Opcode(u16),
Argument(InstructionArgValue),
Argument(InstructionArgValue<'static>),
Symbol(String),
Address(u64),
}
pub enum InstructionPart {
Basic(&'static str),
Opcode(Cow<'static, str>, u16),
Arg(InstructionArg),
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InstructionPart<'a> {
Basic(Cow<'a, str>),
Opcode(Cow<'a, str>, u16),
Arg(InstructionArg<'a>),
Separator,
}
impl<'a> InstructionPart<'a> {
#[inline(always)]
pub fn basic<T>(s: T) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Basic(s.into())
}
#[inline(always)]
pub fn opcode<T>(s: T, o: u16) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Opcode(s.into(), o)
}
#[inline(always)]
pub fn opaque<T>(s: T) -> Self
where T: Into<Cow<'a, str>> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Opaque(s.into())))
}
#[inline(always)]
pub fn signed<T>(v: T) -> InstructionPart<'static>
where T: Into<i64> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Signed(v.into())))
}
#[inline(always)]
pub fn unsigned<T>(v: T) -> InstructionPart<'static>
where T: Into<u64> {
InstructionPart::Arg(InstructionArg::Value(InstructionArgValue::Unsigned(v.into())))
}
#[inline(always)]
pub fn branch_dest<T>(v: T) -> InstructionPart<'static>
where T: Into<u64> {
InstructionPart::Arg(InstructionArg::BranchDest(v.into()))
}
#[inline(always)]
pub fn reloc() -> InstructionPart<'static> { InstructionPart::Arg(InstructionArg::Reloc) }
#[inline(always)]
pub fn separator() -> InstructionPart<'static> { InstructionPart::Separator }
pub fn into_static(self) -> InstructionPart<'static> {
match self {
InstructionPart::Basic(s) => InstructionPart::Basic(Cow::Owned(s.into_owned())),
InstructionPart::Opcode(s, o) => InstructionPart::Opcode(Cow::Owned(s.into_owned()), o),
InstructionPart::Arg(a) => InstructionPart::Arg(a.into_static()),
InstructionPart::Separator => InstructionPart::Separator,
}
}
}
pub fn display_row(
obj: &Object,
symbol_index: usize,
ins_row: &InstructionDiffRow,
diff_config: &DiffObjConfig,
mut cb: impl FnMut(DiffText, InstructionArgDiffIndex) -> Result<()>,
mut cb: impl FnMut(DiffTextSegment) -> Result<()>,
) -> Result<()> {
let Some(ins_ref) = ins_row.ins_ref else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(EOL_SEGMENT)?;
return Ok(());
};
let symbol = &obj.symbols[symbol_index];
let Some(section_index) = symbol.section else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::basic("<invalid>", DiffTextColor::Delete))?;
cb(EOL_SEGMENT)?;
return Ok(());
};
let section = &obj.sections[section_index];
let Some(data) = section.data_range(ins_ref.address, ins_ref.size as usize) else {
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::basic("<invalid>", DiffTextColor::Delete))?;
cb(EOL_SEGMENT)?;
return Ok(());
};
if let Some(line) = section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b) {
cb(DiffText::Line(line), InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment { text: DiffText::Line(line), color: DiffTextColor::Dim, pad_to: 5 })?;
}
cb(
DiffText::Address(ins_ref.address.saturating_sub(symbol.address)),
InstructionArgDiffIndex::NONE,
)?;
cb(DiffTextSegment {
text: DiffText::Address(ins_ref.address.saturating_sub(symbol.address)),
color: DiffTextColor::Normal,
pad_to: 5,
})?;
if let Some(branch) = &ins_row.branch_from {
cb(DiffText::Basic(" ~> "), InstructionArgDiffIndex::new(branch.branch_idx))?;
cb(DiffTextSegment::basic(" ~> ", DiffTextColor::Rotating(branch.branch_idx as u8)))?;
} else {
cb(DiffText::Spacing(4), InstructionArgDiffIndex::NONE)?;
cb(DiffTextSegment::spacing(4))?;
}
let mut arg_idx = 0;
let relocation = section.relocation_at(ins_ref.address, obj);
let relocation = section.relocation_at(ins_ref, obj);
let mut displayed_relocation = false;
obj.arch.display_instruction(
ins_ref,
data,
@@ -104,47 +196,101 @@ pub fn display_row(
diff_config,
&mut |part| match part {
InstructionPart::Basic(text) => {
cb(DiffText::Basic(text), InstructionArgDiffIndex::NONE)
}
InstructionPart::Opcode(mnemonic, opcode) => {
cb(DiffText::Opcode(mnemonic.as_ref(), opcode), 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(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(DiffTextSegment::basic(">", DiffTextColor::Normal))?;
}
cb(DiffText::Eol, InstructionArgDiffIndex::NONE)?;
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 {
+61 -14
View File
@@ -1,7 +1,14 @@
pub mod read;
pub mod split_meta;
use alloc::{borrow::Cow, boxed::Box, collections::BTreeMap, string::String, vec, vec::Vec};
use alloc::{
borrow::Cow,
boxed::Box,
collections::BTreeMap,
string::{String, ToString},
vec,
vec::Vec,
};
use core::{fmt, num::NonZeroU32};
use flagset::{flags, FlagSet};
@@ -98,11 +105,17 @@ impl Section {
pub fn relocation_at<'obj>(
&'obj self,
address: u64,
ins_ref: InstructionRef,
obj: &'obj Object,
) -> Option<ResolvedRelocation<'obj>> {
self.relocations.binary_search_by_key(&address, |r| r.address).ok().and_then(|i| {
let relocation = self.relocations.get(i)?;
match self.relocations.binary_search_by_key(&ins_ref.address, |r| r.address) {
Ok(i) => self.relocations.get(i),
Err(i) => self
.relocations
.get(i)
.take_if(|r| r.address < ins_ref.address + ins_ref.size as u64),
}
.and_then(|relocation| {
let symbol = obj.symbols.get(relocation.target_symbol)?;
Some(ResolvedRelocation { relocation, symbol })
})
@@ -110,13 +123,13 @@ impl Section {
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InstructionArgValue {
pub enum InstructionArgValue<'a> {
Signed(i64),
Unsigned(u64),
Opaque(Cow<'static, str>),
Opaque(Cow<'a, str>),
}
impl InstructionArgValue {
impl InstructionArgValue<'_> {
pub fn loose_eq(&self, other: &InstructionArgValue) -> bool {
match (self, other) {
(InstructionArgValue::Signed(a), InstructionArgValue::Signed(b)) => a == b,
@@ -127,9 +140,27 @@ impl InstructionArgValue {
_ => false,
}
}
pub fn to_static(&self) -> InstructionArgValue<'static> {
match self {
InstructionArgValue::Signed(v) => InstructionArgValue::Signed(*v),
InstructionArgValue::Unsigned(v) => InstructionArgValue::Unsigned(*v),
InstructionArgValue::Opaque(v) => InstructionArgValue::Opaque(v.to_string().into()),
}
}
pub fn into_static(self) -> InstructionArgValue<'static> {
match self {
InstructionArgValue::Signed(v) => InstructionArgValue::Signed(v),
InstructionArgValue::Unsigned(v) => InstructionArgValue::Unsigned(v),
InstructionArgValue::Opaque(v) => {
InstructionArgValue::Opaque(Cow::Owned(v.into_owned()))
}
}
}
}
impl fmt::Display for InstructionArgValue {
impl fmt::Display for InstructionArgValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InstructionArgValue::Signed(v) => write!(f, "{:#x}", ReallySigned(*v)),
@@ -139,14 +170,14 @@ impl fmt::Display for InstructionArgValue {
}
}
#[derive(Debug, Clone)]
pub enum InstructionArg {
Value(InstructionArgValue),
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InstructionArg<'a> {
Value(InstructionArgValue<'a>),
Reloc,
BranchDest(u64),
}
impl InstructionArg {
impl InstructionArg<'_> {
pub fn loose_eq(&self, other: &InstructionArg) -> bool {
match (self, other) {
(InstructionArg::Value(a), InstructionArg::Value(b)) => a.loose_eq(b),
@@ -155,6 +186,22 @@ impl InstructionArg {
_ => false,
}
}
pub fn to_static(&self) -> InstructionArg<'static> {
match self {
InstructionArg::Value(v) => InstructionArg::Value(v.to_static()),
InstructionArg::Reloc => InstructionArg::Reloc,
InstructionArg::BranchDest(v) => InstructionArg::BranchDest(*v),
}
}
pub fn into_static(self) -> InstructionArg<'static> {
match self {
InstructionArg::Value(v) => InstructionArg::Value(v.into_static()),
InstructionArg::Reloc => InstructionArg::Reloc,
InstructionArg::BranchDest(v) => InstructionArg::BranchDest(v),
}
}
}
#[derive(Copy, Clone, Debug)]
@@ -174,7 +221,7 @@ pub struct ScannedInstruction {
pub struct ParsedInstruction {
pub ins_ref: InstructionRef,
pub mnemonic: Cow<'static, str>,
pub args: Vec<InstructionArg>,
pub args: Vec<InstructionArg<'static>>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
@@ -243,7 +290,7 @@ pub enum RelocationFlags {
Coff(u16),
}
#[derive(Clone, Copy)]
#[derive(Debug, Copy, Clone)]
pub struct ResolvedRelocation<'a> {
pub relocation: &'a Relocation,
pub symbol: &'a Symbol,
+176 -62
View File
@@ -4,6 +4,7 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::cmp::Ordering;
use anyhow::{bail, ensure, Context, Result};
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
@@ -32,16 +33,22 @@ fn map_symbol(
arch: &dyn Arch,
file: &object::File,
symbol: &object::Symbol,
section_indices: &[usize],
split_meta: Option<&SplitMeta>,
) -> Result<Symbol> {
let mut name = symbol.name().context("Failed to process symbol name")?.to_string();
let size = symbol.size();
let mut size = symbol.size();
if let (object::SymbolKind::Section, Some(section)) =
(symbol.kind(), symbol.section_index().and_then(|i| file.section_by_index(i).ok()))
{
let section_name = section.name().context("Failed to process section name")?;
name = format!("[{}]", section_name);
// size = section.size();
// For section symbols, set the size to zero. If the size is non-zero, it will be included
// in the diff. Most of the time, this is duplicative, given that we'll have function or
// object symbols that cover the same range. In the case of an empty section, the size
// inference logic below will set the size back to the section size, thus acting as a
// placeholder symbol.
size = 0;
}
let mut flags = arch.extra_symbol_flags(symbol);
@@ -74,7 +81,7 @@ fn map_symbol(
let virtual_address = split_meta
.and_then(|m| m.virtual_addresses.as_ref())
.and_then(|v| v.get(symbol.index().0).cloned());
let section = symbol.section_index().map(|i| map_section_index(file, i));
let section = symbol.section_index().and_then(|i| section_indices.get(i.0).copied());
Ok(Symbol {
name,
@@ -89,39 +96,123 @@ fn map_symbol(
})
}
fn map_section_index(file: &object::File, idx: object::SectionIndex) -> usize {
match file.format() {
object::BinaryFormat::Elf => idx.0 - 1,
_ => idx.0,
}
}
fn map_symbol_index(file: &object::File, idx: object::SymbolIndex) -> usize {
match file.format() {
object::BinaryFormat::Elf => idx.0 - 1,
_ => idx.0,
}
}
fn map_symbols(
arch: &dyn Arch,
obj_file: &object::File,
sections: &[Section],
section_indices: &[usize],
split_meta: Option<&SplitMeta>,
) -> Result<Vec<Symbol>> {
let mut symbols = Vec::<Symbol>::with_capacity(obj_file.symbols().count());
for symbol in obj_file.symbols() {
symbols.push(map_symbol(arch, obj_file, &symbol, split_meta)?);
) -> Result<(Vec<Symbol>, Vec<usize>)> {
let symbol_count = obj_file.symbols().count();
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count);
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
for obj_symbol in obj_file.symbols() {
if symbol_indices.len() <= obj_symbol.index().0 {
symbol_indices.resize(obj_symbol.index().0 + 1, usize::MAX);
}
let symbol = map_symbol(arch, obj_file, &obj_symbol, section_indices, split_meta)?;
symbol_indices[obj_symbol.index().0] = symbols.len();
symbols.push(symbol);
}
// Infer symbol sizes for 0-size symbols
infer_symbol_sizes(&mut symbols, sections);
Ok((symbols, symbol_indices))
}
fn infer_symbol_sizes(symbols: &mut [Symbol], sections: &[Section]) {
// Create a sorted list of symbol indices by section
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
for (i, symbol) in symbols.iter().enumerate() {
if symbol.section.is_some() {
symbols_with_section.push(i);
}
}
symbols_with_section.sort_by(|a, b| {
let a = &symbols[*a];
let b = &symbols[*b];
a.section
.unwrap_or(usize::MAX)
.cmp(&b.section.unwrap_or(usize::MAX))
.then_with(|| {
// Sort section symbols first
if a.kind == SymbolKind::Section {
Ordering::Less
} else if b.kind == SymbolKind::Section {
Ordering::Greater
} else {
Ordering::Equal
}
})
.then_with(|| a.address.cmp(&b.address))
.then_with(|| a.size.cmp(&b.size))
});
// Set symbol sizes based on the next symbol's address
let mut iter_idx = 0;
while iter_idx < symbols_with_section.len() {
let symbol_idx = symbols_with_section[iter_idx];
let symbol = &symbols[symbol_idx];
iter_idx += 1;
if symbol.size != 0 {
continue;
}
let section_idx = symbol.section.unwrap();
let next_symbol = match symbol.kind {
// For function/object symbols, find the next function/object symbol (in other words:
// skip over labels)
SymbolKind::Function | SymbolKind::Object => loop {
if iter_idx >= symbols_with_section.len() {
break None;
}
let next_symbol = &symbols[symbols_with_section[iter_idx]];
if next_symbol.section != Some(section_idx) {
break None;
}
if let SymbolKind::Function | SymbolKind::Object = next_symbol.kind {
break Some(next_symbol);
}
iter_idx += 1;
},
// For labels (or anything else), simply use the next symbol's address
SymbolKind::Unknown | SymbolKind::Section => symbols_with_section
.get(iter_idx)
.map(|&i| &symbols[i])
.take_if(|s| s.section == Some(section_idx)),
};
let next_address = next_symbol.map(|s| s.address).unwrap_or_else(|| {
let section = &sections[section_idx];
section.address + section.size
});
let new_size = next_address.saturating_sub(symbol.address);
if new_size > 0 {
let symbol = &mut symbols[symbol_idx];
symbol.size = new_size;
if symbol.kind != SymbolKind::Section {
symbol.flags |= SymbolFlag::SizeInferred;
}
// Set symbol kind if unknown and size is non-zero
if symbol.kind == SymbolKind::Unknown {
symbol.kind = match sections[section_idx].kind {
SectionKind::Code => SymbolKind::Function,
SectionKind::Data | SectionKind::Bss => SymbolKind::Object,
_ => SymbolKind::Unknown,
};
}
}
}
Ok(symbols)
}
fn map_sections(
arch: &dyn Arch,
_arch: &dyn Arch,
obj_file: &object::File,
split_meta: Option<&SplitMeta>,
) -> Result<Vec<Section>> {
) -> Result<(Vec<Section>, Vec<usize>)> {
let mut section_names = BTreeMap::<String, usize>::new();
let mut result = Vec::<Section>::with_capacity(obj_file.sections().count());
let section_count = obj_file.sections().count();
let mut result = Vec::<Section>::with_capacity(section_count);
let mut section_indices = Vec::<usize>::with_capacity(section_count + 1);
for section in obj_file.sections() {
let name = section.name().context("Failed to process section name")?;
let kind = map_section_kind(&section);
@@ -142,12 +233,14 @@ fn map_sections(
.and_then(|v| v.get(s.index().0).cloned())
});
let relocations = map_relocations(arch, obj_file, &section)?;
let unique_id = section_names.entry(name.to_string()).or_insert(0);
let id = format!("{}-{}", name, unique_id);
*unique_id += 1;
if section_indices.len() <= section.index().0 {
section_indices.resize(section.index().0 + 1, usize::MAX);
}
section_indices[section.index().0] = result.len();
result.push(Section {
id,
name: name.to_string(),
@@ -156,33 +249,14 @@ fn map_sections(
kind,
data: SectionData(data),
flags: Default::default(),
relocations,
relocations: Default::default(),
virtual_address,
line_info: Default::default(),
});
}
Ok(result)
Ok((result, section_indices))
}
// result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
// let mut iter = result.iter_mut().peekable();
// while let Some(symbol) = iter.next() {
// if symbol.size == 0 {
// if let Some(next_symbol) = iter.peek() {
// symbol.size = next_symbol.address - symbol.address;
// } else {
// symbol.size = (section.address + section.size) - symbol.address;
// }
// // Set symbol kind if we ended up with a non-zero size
// if symbol.kind == ObjSymbolKind::Unknown && symbol.size > 0 {
// symbol.kind = match section.kind {
// ObjSectionKind::Code => ObjSymbolKind::Function,
// ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
// };
// }
// }
// }
const LOW_PRIORITY_SYMBOLS: &[&str] =
&["__gnu_compiled_c", "__gnu_compiled_cplusplus", "gcc2_compiled."];
@@ -230,6 +304,7 @@ fn map_relocations(
arch: &dyn Arch,
obj_file: &object::File,
obj_section: &object::Section,
symbol_indices: &[usize],
) -> Result<Vec<Relocation>> {
let mut relocations = Vec::<Relocation>::with_capacity(obj_section.relocations().count());
let mut ordered_symbols = None;
@@ -269,7 +344,13 @@ fn map_relocations(
} else {
idx
};
map_symbol_index(obj_file, idx)
match symbol_indices.get(idx.0).copied() {
Some(i) => i,
None => {
log::warn!("Invalid symbol index {}", idx.0);
continue;
}
}
}
object::RelocationTarget::Absolute => {
let section_name = obj_section.name()?;
@@ -299,6 +380,7 @@ fn map_relocations(
fn parse_line_info(
obj_file: &object::File,
sections: &mut [Section],
section_indices: &[usize],
obj_data: &[u8],
) -> Result<()> {
// DWARF 1.1
@@ -326,7 +408,6 @@ fn parse_line_info(
}
let address_delta = read_u32(obj_file, &mut section_data)? as u64;
out_section.line_info.insert(base_address + address_delta, line_number);
log::debug!("Line: {:#x} -> {}", base_address + address_delta, line_number);
}
}
}
@@ -376,7 +457,7 @@ fn parse_line_info(
// COFF
if let object::File::Coff(coff) = obj_file {
parse_line_info_coff(coff, sections, obj_data)?;
parse_line_info_coff(coff, sections, section_indices, obj_data)?;
}
Ok(())
@@ -385,6 +466,7 @@ fn parse_line_info(
fn parse_line_info_coff(
coff: &object::coff::CoffFile,
sections: &mut [Section],
section_indices: &[usize],
obj_data: &[u8],
) -> Result<()> {
use object::{
@@ -405,7 +487,9 @@ fn parse_line_info_coff(
// Find this section in our out_section. If it's not in out_section,
// skip it.
let Some(out_section) = sections.get_mut(sect.index().0) else {
let Some(out_section) =
section_indices.get(sect.index().0).and_then(|&i| sections.get_mut(i))
else {
continue;
};
@@ -514,7 +598,12 @@ fn combine_sections(
for (i, section) in sections.iter().enumerate() {
match section.kind {
SectionKind::Data | SectionKind::Bss => {
data_sections.entry(section.name.clone()).or_default().push(i);
let base_name = if let Some(i) = section.name.rfind('$') {
&section.name[..i]
} else {
&section.name
};
data_sections.entry(base_name.to_string()).or_default().push(i);
}
SectionKind::Code => {
text_sections.push(i);
@@ -523,12 +612,12 @@ fn combine_sections(
}
}
if config.combine_data_sections {
for (_, section_indices) in data_sections {
do_combine_sections(sections, symbols, &section_indices)?;
for (combined_name, mut section_indices) in data_sections {
do_combine_sections(sections, symbols, &mut section_indices, combined_name)?;
}
}
if config.combine_text_sections {
do_combine_sections(sections, symbols, &text_sections)?;
do_combine_sections(sections, symbols, &mut text_sections, ".text".to_string())?;
}
Ok(())
}
@@ -536,11 +625,24 @@ fn combine_sections(
fn do_combine_sections(
sections: &mut [Section],
symbols: &mut [Symbol],
section_indices: &[usize],
section_indices: &mut [usize],
combined_name: String,
) -> Result<()> {
if section_indices.len() < 2 {
return Ok(());
}
// Sort sections lexicographically by name (for COFF section groups)
section_indices.sort_by(|&a, &b| {
let a_name = &sections[a].name;
let b_name = &sections[b].name;
// .text$di < .text$mn < .text
if a_name.contains('$') && !b_name.contains('$') {
return Ordering::Less;
} else if !a_name.contains('$') && b_name.contains('$') {
return Ordering::Greater;
}
a_name.cmp(b_name)
});
let first_section_idx = section_indices[0];
// Calculate the new offset for each section
@@ -548,7 +650,7 @@ fn do_combine_sections(
let mut current_offset = 0;
let mut data_size = 0;
let mut num_relocations = 0;
for &i in section_indices {
for i in section_indices.iter().copied() {
let section = &sections[i];
if section.address != 0 {
bail!("Section {} ({}) has non-zero address", i, section.name);
@@ -580,6 +682,8 @@ fn do_combine_sections(
}
{
let first_section = &mut sections[first_section_idx];
first_section.id = format!("{combined_name}-combined");
first_section.name = combined_name;
first_section.size = current_offset;
first_section.data = SectionData(data);
first_section.flags |= SectionFlag::Combined;
@@ -659,9 +763,18 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
let obj_file = object::File::parse(data)?;
let arch = new_arch(&obj_file)?;
let split_meta = parse_split_meta(&obj_file)?;
let mut symbols = map_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let mut sections = map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
parse_line_info(&obj_file, &mut sections, data)?;
let (mut sections, section_indices) =
map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let (mut symbols, symbol_indices) =
map_symbols(arch.as_ref(), &obj_file, &sections, &section_indices, split_meta.as_ref())?;
for obj_section in obj_file.sections() {
let section = &mut sections[section_indices[obj_section.index().0]];
if section.kind != SectionKind::Unknown {
section.relocations =
map_relocations(arch.as_ref(), &obj_file, &obj_section, &symbol_indices)?;
}
}
parse_line_info(&obj_file, &mut sections, &section_indices, data)?;
if config.combine_data_sections || config.combine_text_sections {
combine_sections(&mut sections, &mut symbols, config)?;
}
@@ -803,7 +916,8 @@ mod test {
..Default::default()
},
];
do_combine_sections(&mut sections, &mut symbols, &[1, 2, 3]).unwrap();
do_combine_sections(&mut sections, &mut symbols, &mut [1, 2, 3], ".data".to_string())
.unwrap();
assert_eq!(sections[1].data.0, (1..=12).collect::<Vec<_>>());
insta::assert_debug_snapshot!((sections, symbols));
}
@@ -44,7 +44,7 @@ expression: "(sections, symbols)"
virtual_address: None,
},
Section {
id: ".data-0",
id: ".data-combined",
name: ".data",
address: 0,
size: 12,
+1 -1
View File
@@ -6,7 +6,7 @@ use num_traits::PrimInt;
use object::{Endian, Object};
// https://stackoverflow.com/questions/44711012/how-do-i-format-a-signed-integer-to-a-sign-aware-hexadecimal-representation
pub struct ReallySigned<N: PrimInt>(pub(crate) N);
pub struct ReallySigned<N: PrimInt>(pub N);
impl<N: PrimInt> fmt::LowerHex for ReallySigned<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+28
View File
@@ -0,0 +1,28 @@
use objdiff_core::{diff, obj};
mod common;
#[test]
#[cfg(feature = "x86")]
fn read_x86() {
let diff_config = diff::DiffObjConfig::default();
let obj = obj::read::parse(include_object!("data/x86/staticdebug.obj"), &diff_config).unwrap();
insta::assert_debug_snapshot!(obj);
let symbol_idx = obj.symbols.iter().position(|s| s.name == "?PrintThing@@YAXXZ").unwrap();
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
insta::assert_debug_snapshot!(diff.instruction_rows);
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
insta::assert_snapshot!(output);
}
#[test]
#[cfg(feature = "x86")]
fn read_x86_combine_sections() {
let diff_config = diff::DiffObjConfig {
combine_data_sections: true,
combine_text_sections: true,
..Default::default()
};
let obj = obj::read::parse(include_object!("data/x86/rtest.obj"), &diff_config).unwrap();
insta::assert_debug_snapshot!(obj.sections);
}
+11 -16
View File
@@ -1,5 +1,5 @@
use objdiff_core::{
diff::{DiffObjConfig, SymbolDiff},
diff::{display::DiffTextSegment, DiffObjConfig, SymbolDiff},
obj::Object,
};
@@ -13,21 +13,16 @@ pub fn display_diff(
for row in &diff.instruction_rows {
output.push('[');
let mut separator = false;
objdiff_core::diff::display::display_row(
&obj,
symbol_idx,
row,
&diff_config,
|text, diff_idx| {
if separator {
output.push_str(", ");
} else {
separator = true;
}
output.push_str(&format!("({:?}, {:?})", text, diff_idx.get()));
Ok(())
},
)
objdiff_core::diff::display::display_row(&obj, symbol_idx, row, &diff_config, |segment| {
if separator {
output.push_str(", ");
} else {
separator = true;
}
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,

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