Options for ARM disassembly style (#78)

This commit is contained in:
Aetias 2024-07-15 00:00:57 +02:00 committed by GitHub
parent 233839346a
commit d9fb48853e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 134 additions and 16 deletions

4
Cargo.lock generated
View File

@ -4330,9 +4330,9 @@ dependencies = [
[[package]] [[package]]
name = "unarm" name = "unarm"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6bff109f0171a299559d82a7236e056093fc0dcd2a7da86aa745f82281e2d31" checksum = "379762d9433a2e6e498cde97801fb238318b024a513d0843eeac98b9056b9f3c"
[[package]] [[package]]
name = "unicase" name = "unicase"

View File

@ -817,6 +817,12 @@ impl FunctionDiffUi {
mips_abi: Default::default(), // TODO mips_abi: Default::default(), // TODO
mips_instr_category: Default::default(), // TODO mips_instr_category: Default::default(), // TODO
arm_arch_version: Default::default(), // TODO arm_arch_version: Default::default(), // TODO
arm_unified_syntax: true, // TODO
arm_av_registers: false, // TODO
arm_r9_usage: Default::default(), // TODO
arm_sl_usage: false, // TODO
arm_fp_usage: false, // TODO
arm_ip_usage: false, // TODO
}; };
let target = self let target = self
.target_path .target_path

View File

@ -56,5 +56,5 @@ iced-x86 = { version = "1.21.0", default-features = false, features = ["std", "d
msvc-demangler = { version = "0.10.0", optional = true } msvc-demangler = { version = "0.10.0", optional = true }
# arm # arm
unarm = { version = "1.3.0", optional = true } unarm = { version = "1.4.0", optional = true }
arm-attr = { version = "0.1.1", optional = true } arm-attr = { version = "0.1.1", optional = true }

View File

@ -13,12 +13,12 @@ use object::{
use unarm::{ use unarm::{
args::{Argument, OffsetImm, OffsetReg, Register}, args::{Argument, OffsetImm, OffsetReg, Register},
parse::{ArmVersion, ParseMode, Parser}, parse::{ArmVersion, ParseMode, Parser},
ParsedIns, DisplayOptions, ParseFlags, ParsedIns, RegNames,
}; };
use crate::{ use crate::{
arch::{ObjArch, ProcessCodeResult}, arch::{ObjArch, ProcessCodeResult},
diff::{ArmArchVersion, DiffObjConfig}, diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig},
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection}, obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
}; };
@ -149,7 +149,24 @@ impl ObjArch for ObjArchArm {
object::Endianness::Little => unarm::Endian::Little, object::Endianness::Little => unarm::Endian::Little,
object::Endianness::Big => unarm::Endian::Big, object::Endianness::Big => unarm::Endian::Big,
}; };
let mut parser = Parser::new(version, first_mapping, start_addr, endian, code);
let parse_flags = ParseFlags { ual: config.arm_unified_syntax };
let mut parser = Parser::new(version, first_mapping, start_addr, endian, parse_flags, code);
let display_options = DisplayOptions {
reg_names: RegNames {
av_registers: config.arm_av_registers,
r9_use: match config.arm_r9_usage {
ArmR9Usage::GeneralPurpose => unarm::R9Use::GeneralPurpose,
ArmR9Usage::Sb => unarm::R9Use::Pid,
ArmR9Usage::Tr => unarm::R9Use::Tls,
},
explicit_stack_limit: config.arm_sl_usage,
frame_pointer: config.arm_fp_usage,
ip: config.arm_ip_usage,
},
};
while let Some((address, op, ins)) = parser.next() { while let Some((address, op, ins)) = parser.next() {
if let Some(next) = next_mapping { if let Some(next) = next_mapping {
@ -187,7 +204,7 @@ impl ObjArch for ObjArchArm {
let (args, branch_dest) = if reloc.is_some() && parser.mode == ParseMode::Data { let (args, branch_dest) = if reloc.is_some() && parser.mode == ParseMode::Data {
(vec![ObjInsArg::Reloc], None) (vec![ObjInsArg::Reloc], None)
} else { } else {
push_args(&ins, config, reloc_arg, address)? push_args(&ins, config, reloc_arg, address, display_options)?
}; };
ops.push(op.id()); ops.push(op.id());
@ -200,7 +217,7 @@ impl ObjArch for ObjArchArm {
reloc, reloc,
branch_dest, branch_dest,
line, line,
formatted: ins.to_string(), formatted: ins.display(display_options).to_string(),
orig: None, orig: None,
}); });
} }
@ -281,6 +298,7 @@ fn push_args(
config: &DiffObjConfig, config: &DiffObjConfig,
reloc_arg: Option<usize>, reloc_arg: Option<usize>,
cur_addr: u32, cur_addr: u32,
display_options: DisplayOptions,
) -> Result<(Vec<ObjInsArg>, Option<u64>)> { ) -> Result<(Vec<ObjInsArg>, Option<u64>)> {
let mut args = vec![]; let mut args = vec![];
let mut branch_dest = None; let mut branch_dest = None;
@ -318,7 +336,9 @@ fn push_args(
deref = true; deref = true;
args.push(ObjInsArg::PlainText("[".into())); args.push(ObjInsArg::PlainText("[".into()));
} }
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(reg.reg.to_string().into()))); args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
reg.reg.display(display_options.reg_names).to_string().into(),
)));
if reg.writeback { if reg.writeback {
if reg.deref { if reg.deref {
writeback = true; writeback = true;
@ -336,7 +356,10 @@ fn push_args(
args.push(ObjInsArg::PlainText(config.separator().into())); args.push(ObjInsArg::PlainText(config.separator().into()));
} }
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque( args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
Register::parse(i).to_string().into(), Register::parse(i)
.display(display_options.reg_names)
.to_string()
.into(),
))); )));
first = false; first = false;
} }
@ -376,14 +399,16 @@ fn push_args(
Argument::ShiftReg(shift) => { Argument::ShiftReg(shift) => {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(shift.op.to_string().into()))); args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(shift.op.to_string().into())));
args.push(ObjInsArg::PlainText(" ".into())); args.push(ObjInsArg::PlainText(" ".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(shift.reg.to_string().into()))); args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
shift.reg.display(display_options.reg_names).to_string().into(),
)));
} }
Argument::OffsetReg(offset) => { Argument::OffsetReg(offset) => {
if !offset.add { if !offset.add {
args.push(ObjInsArg::PlainText("-".into())); args.push(ObjInsArg::PlainText("-".into()));
} }
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque( args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
offset.reg.to_string().into(), offset.reg.display(display_options.reg_names).to_string().into(),
))); )));
} }
Argument::CpsrMode(mode) => { Argument::CpsrMode(mode) => {
@ -398,9 +423,9 @@ fn push_args(
| Argument::StatusMask(_) | Argument::StatusMask(_)
| Argument::Shift(_) | Argument::Shift(_)
| Argument::CpsrFlags(_) | Argument::CpsrFlags(_)
| Argument::Endian(_) => { | Argument::Endian(_) => args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(arg.to_string().into()))) arg.display(display_options).to_string().into(),
} ))),
} }
} }
} }

View File

@ -117,6 +117,34 @@ pub enum ArmArchVersion {
V6K, V6K,
} }
#[derive(
Debug,
Copy,
Clone,
Default,
Eq,
PartialEq,
serde::Deserialize,
serde::Serialize,
strum::VariantArray,
strum::EnumMessage,
)]
pub enum ArmR9Usage {
#[default]
#[strum(
message = "R9 or V6 (default)",
detailed_message = "Use R9 as a general-purpose register."
)]
GeneralPurpose,
#[strum(
message = "SB (static base)",
detailed_message = "Used for position-independent data (PID)."
)]
Sb,
#[strum(message = "TR (TLS register)", detailed_message = "Used for thread-local storage.")]
Tr,
}
#[inline] #[inline]
const fn default_true() -> bool { true } const fn default_true() -> bool { true }
@ -134,6 +162,12 @@ pub struct DiffObjConfig {
pub mips_instr_category: MipsInstrCategory, pub mips_instr_category: MipsInstrCategory,
// ARM // ARM
pub arm_arch_version: ArmArchVersion, pub arm_arch_version: ArmArchVersion,
pub arm_unified_syntax: bool,
pub arm_av_registers: bool,
pub arm_r9_usage: ArmR9Usage,
pub arm_sl_usage: bool,
pub arm_fp_usage: bool,
pub arm_ip_usage: bool,
} }
impl Default for DiffObjConfig { impl Default for DiffObjConfig {
@ -146,6 +180,12 @@ impl Default for DiffObjConfig {
mips_abi: Default::default(), mips_abi: Default::default(),
mips_instr_category: Default::default(), mips_instr_category: Default::default(),
arm_arch_version: Default::default(), arm_arch_version: Default::default(),
arm_unified_syntax: true,
arm_av_registers: false,
arm_r9_usage: Default::default(),
arm_sl_usage: false,
arm_fp_usage: false,
arm_ip_usage: false,
} }
} }
} }

View File

@ -16,7 +16,7 @@ use egui::{
use globset::Glob; use globset::Glob;
use objdiff_core::{ use objdiff_core::{
config::{ProjectObject, DEFAULT_WATCH_PATTERNS}, config::{ProjectObject, DEFAULT_WATCH_PATTERNS},
diff::{ArmArchVersion, MipsAbi, MipsInstrCategory, X86Formatter}, diff::{ArmArchVersion, ArmR9Usage, MipsAbi, MipsInstrCategory, X86Formatter},
}; };
use self_update::cargo_crate_version; use self_update::cargo_crate_version;
use strum::{EnumMessage, VariantArray}; use strum::{EnumMessage, VariantArray};
@ -925,4 +925,51 @@ fn arch_config_ui(ui: &mut egui::Ui, config: &mut AppConfig, _appearance: &Appea
} }
} }
}); });
let response = ui
.checkbox(&mut config.diff_obj_config.arm_unified_syntax, "Unified syntax")
.on_hover_text("Disassemble as unified assembly language (UAL).");
if response.changed() {
config.queue_reload = true;
}
let response = ui
.checkbox(&mut config.diff_obj_config.arm_av_registers, "Use A/V registers")
.on_hover_text("Display R0-R3 as A1-A4 and R4-R11 as V1-V8");
if response.changed() {
config.queue_reload = true;
}
egui::ComboBox::new("arm_r9_usage", "Display R9 as")
.selected_text(config.diff_obj_config.arm_r9_usage.get_message().unwrap())
.show_ui(ui, |ui| {
for &usage in ArmR9Usage::VARIANTS {
if ui
.selectable_label(
config.diff_obj_config.arm_r9_usage == usage,
usage.get_message().unwrap(),
)
.on_hover_text(usage.get_detailed_message().unwrap())
.clicked()
{
config.diff_obj_config.arm_r9_usage = usage;
config.queue_reload = true;
}
}
});
let response = ui
.checkbox(&mut config.diff_obj_config.arm_sl_usage, "Display R10 as SL")
.on_hover_text("Used for explicit stack limits.");
if response.changed() {
config.queue_reload = true;
}
let response = ui
.checkbox(&mut config.diff_obj_config.arm_fp_usage, "Display R11 as FP")
.on_hover_text("Used for frame pointers.");
if response.changed() {
config.queue_reload = true;
}
let response = ui
.checkbox(&mut config.diff_obj_config.arm_ip_usage, "Display R12 as IP")
.on_hover_text("Used for interworking and long branches.");
if response.changed() {
config.queue_reload = true;
}
} }