mirror of
https://github.com/encounter/objdiff.git
synced 2025-06-07 07:03:39 +00:00
Preliminary SuperH support (#186)
* Preliminary SuperH support * fixes * clippy * clippy
This commit is contained in:
parent
b40fae5140
commit
644d4762f0
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -475,7 +475,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"object",
|
"object 0.36.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
@ -3353,7 +3353,7 @@ dependencies = [
|
|||||||
"notify-debouncer-full",
|
"notify-debouncer-full",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
"object",
|
"object 0.36.7 (git+https://github.com/gimli-rs/object?rev=a74579249e21ab8fcd3a86be588de336f18297cb)",
|
||||||
"pbjson",
|
"pbjson",
|
||||||
"pbjson-build",
|
"pbjson-build",
|
||||||
"ppc750cl",
|
"ppc750cl",
|
||||||
@ -3440,6 +3440,14 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "git+https://github.com/gimli-rs/object?rev=a74579249e21ab8fcd3a86be588de336f18297cb#a74579249e21ab8fcd3a86be588de336f18297cb"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
@ -27,6 +27,7 @@ all = [
|
|||||||
"mips",
|
"mips",
|
||||||
"ppc",
|
"ppc",
|
||||||
"x86",
|
"x86",
|
||||||
|
"superh"
|
||||||
]
|
]
|
||||||
# Implicit, used to check if any arch is enabled
|
# Implicit, used to check if any arch is enabled
|
||||||
any-arch = [
|
any-arch = [
|
||||||
@ -111,6 +112,9 @@ arm64 = [
|
|||||||
"dep:yaxpeax-arch",
|
"dep:yaxpeax-arch",
|
||||||
"dep:yaxpeax-arm",
|
"dep:yaxpeax-arm",
|
||||||
]
|
]
|
||||||
|
superh = [
|
||||||
|
"any-arch",
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["all"]
|
features = ["all"]
|
||||||
@ -123,7 +127,7 @@ itertools = { version = "0.14", default-features = false, features = ["use_alloc
|
|||||||
log = { version = "0.4", default-features = false, optional = true }
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
memmap2 = { version = "0.9", optional = true }
|
memmap2 = { version = "0.9", optional = true }
|
||||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||||
object = { version = "0.36", default-features = false, features = ["read_core", "elf", "pe"] }
|
object = { git = "https://github.com/gimli-rs/object", rev = "a74579249e21ab8fcd3a86be588de336f18297cb", default-features = false, features = ["read_core", "elf", "pe"] }
|
||||||
pbjson = { version = "0.7", default-features = false, optional = true }
|
pbjson = { version = "0.7", default-features = false, optional = true }
|
||||||
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
||||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
||||||
|
@ -25,6 +25,8 @@ pub mod arm64;
|
|||||||
pub mod mips;
|
pub mod mips;
|
||||||
#[cfg(feature = "ppc")]
|
#[cfg(feature = "ppc")]
|
||||||
pub mod ppc;
|
pub mod ppc;
|
||||||
|
#[cfg(feature = "superh")]
|
||||||
|
pub mod superh;
|
||||||
#[cfg(feature = "x86")]
|
#[cfg(feature = "x86")]
|
||||||
pub mod x86;
|
pub mod x86;
|
||||||
|
|
||||||
@ -313,6 +315,8 @@ pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
|||||||
object::Architecture::Arm => Box::new(arm::ArchArm::new(object)?),
|
object::Architecture::Arm => Box::new(arm::ArchArm::new(object)?),
|
||||||
#[cfg(feature = "arm64")]
|
#[cfg(feature = "arm64")]
|
||||||
object::Architecture::Aarch64 => Box::new(arm64::ArchArm64::new(object)?),
|
object::Architecture::Aarch64 => Box::new(arm64::ArchArm64::new(object)?),
|
||||||
|
#[cfg(feature = "superh")]
|
||||||
|
object::Architecture::SuperH => Box::new(superh::ArchSuperH::new(object)?),
|
||||||
arch => bail!("Unsupported architecture: {arch:?}"),
|
arch => bail!("Unsupported architecture: {arch:?}"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
1370
objdiff-core/src/arch/superh/disasm.rs
Normal file
1370
objdiff-core/src/arch/superh/disasm.rs
Normal file
File diff suppressed because it is too large
Load Diff
637
objdiff-core/src/arch/superh/mod.rs
Normal file
637
objdiff-core/src/arch/superh/mod.rs
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
|
||||||
|
use anyhow::{Result, bail};
|
||||||
|
use object::elf;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::{Arch, superh::disasm::sh2_disasm},
|
||||||
|
diff::{DiffObjConfig, display::InstructionPart},
|
||||||
|
obj::{
|
||||||
|
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ScannedInstruction,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod disasm;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ArchSuperH {}
|
||||||
|
|
||||||
|
impl ArchSuperH {
|
||||||
|
pub fn new(_file: &object::File) -> Result<Self> { Ok(Self {}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arch for ArchSuperH {
|
||||||
|
fn scan_instructions(
|
||||||
|
&self,
|
||||||
|
address: u64,
|
||||||
|
code: &[u8],
|
||||||
|
_section_index: usize,
|
||||||
|
_relocations: &[Relocation],
|
||||||
|
_diff_config: &DiffObjConfig,
|
||||||
|
) -> Result<Vec<ScannedInstruction>> {
|
||||||
|
let mut ops = Vec::<ScannedInstruction>::with_capacity(code.len() / 2);
|
||||||
|
let mut offset = address;
|
||||||
|
for chunk in code.chunks_exact(2) {
|
||||||
|
let opcode = u16::from_be_bytes(chunk.try_into().unwrap());
|
||||||
|
let mut parts: Vec<InstructionPart> = vec![];
|
||||||
|
let resolved: ResolvedInstructionRef = Default::default();
|
||||||
|
let mut branch_dest: Option<u64> = None;
|
||||||
|
sh2_disasm(
|
||||||
|
offset.try_into().unwrap(),
|
||||||
|
opcode,
|
||||||
|
true,
|
||||||
|
&mut parts,
|
||||||
|
&resolved,
|
||||||
|
&mut branch_dest,
|
||||||
|
);
|
||||||
|
|
||||||
|
let opcode_enum: u16 = match parts.first() {
|
||||||
|
Some(InstructionPart::Opcode(_, val)) => *val,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
let ins_ref: InstructionRef =
|
||||||
|
InstructionRef { address: offset, size: 2, opcode: opcode_enum };
|
||||||
|
ops.push(ScannedInstruction { ins_ref, branch_dest });
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ops)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_instruction(
|
||||||
|
&self,
|
||||||
|
resolved: ResolvedInstructionRef,
|
||||||
|
_diff_config: &DiffObjConfig,
|
||||||
|
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let opcode = u16::from_be_bytes(resolved.code.try_into().unwrap());
|
||||||
|
let mut parts: Vec<InstructionPart> = vec![];
|
||||||
|
let mut branch_dest: Option<u64> = None;
|
||||||
|
sh2_disasm(0, opcode, true, &mut parts, &resolved, &mut branch_dest);
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
cb(part)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn implcit_addend(
|
||||||
|
&self,
|
||||||
|
_file: &object::File<'_>,
|
||||||
|
_section: &object::Section,
|
||||||
|
address: u64,
|
||||||
|
_relocation: &object::Relocation,
|
||||||
|
flags: RelocationFlags,
|
||||||
|
) -> Result<i64> {
|
||||||
|
bail!("Unsupported SuperH implicit relocation {:#x}:{:?}", address, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
|
cpp_demangle::Symbol::new(name)
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> {
|
||||||
|
match flags {
|
||||||
|
RelocationFlags::Elf(r_type) => match r_type {
|
||||||
|
elf::R_SH_NONE => Some("R_SH_NONE"),
|
||||||
|
elf::R_SH_DIR32 => Some("R_SH_DIR32"),
|
||||||
|
elf::R_SH_REL32 => Some("R_SH_REL32"),
|
||||||
|
elf::R_SH_DIR8WPN => Some("R_SH_DIR8WPN"),
|
||||||
|
elf::R_SH_IND12W => Some("R_SH_IND12W"),
|
||||||
|
elf::R_SH_DIR8WPL => Some("R_SH_DIR8WPL"),
|
||||||
|
elf::R_SH_DIR8WPZ => Some("R_SH_DIR8WPZ"),
|
||||||
|
elf::R_SH_DIR8BP => Some("R_SH_DIR8BP"),
|
||||||
|
elf::R_SH_DIR8W => Some("R_SH_DIR8W"),
|
||||||
|
elf::R_SH_DIR8L => Some("R_SH_DIR8L"),
|
||||||
|
elf::R_SH_SWITCH16 => Some("R_SH_SWITCH16"),
|
||||||
|
elf::R_SH_SWITCH32 => Some("R_SH_SWITCH32"),
|
||||||
|
elf::R_SH_USES => Some("R_SH_USES"),
|
||||||
|
elf::R_SH_COUNT => Some("R_SH_COUNT"),
|
||||||
|
elf::R_SH_ALIGN => Some("R_SH_ALIGN"),
|
||||||
|
elf::R_SH_CODE => Some("R_SH_CODE"),
|
||||||
|
elf::R_SH_DATA => Some("R_SH_DATA"),
|
||||||
|
elf::R_SH_LABEL => Some("R_SH_LABEL"),
|
||||||
|
elf::R_SH_SWITCH8 => Some("R_SH_SWITCH8"),
|
||||||
|
elf::R_SH_GNU_VTINHERIT => Some("R_SH_GNU_VTINHERIT"),
|
||||||
|
elf::R_SH_GNU_VTENTRY => Some("R_SH_GNU_VTENTRY"),
|
||||||
|
elf::R_SH_TLS_GD_32 => Some("R_SH_TLS_GD_32"),
|
||||||
|
elf::R_SH_TLS_LD_32 => Some("R_SH_TLS_LD_32"),
|
||||||
|
elf::R_SH_TLS_LDO_32 => Some("R_SH_TLS_LDO_32"),
|
||||||
|
elf::R_SH_TLS_IE_32 => Some("R_SH_TLS_IE_32"),
|
||||||
|
elf::R_SH_TLS_LE_32 => Some("R_SH_TLS_LE_32"),
|
||||||
|
elf::R_SH_TLS_DTPMOD32 => Some("R_SH_TLS_DTPMOD32"),
|
||||||
|
elf::R_SH_TLS_DTPOFF32 => Some("R_SH_TLS_DTPOFF32"),
|
||||||
|
elf::R_SH_TLS_TPOFF32 => Some("R_SH_TLS_TPOFF32"),
|
||||||
|
elf::R_SH_GOT32 => Some("R_SH_GOT32"),
|
||||||
|
elf::R_SH_PLT32 => Some("R_SH_PLT32"),
|
||||||
|
elf::R_SH_COPY => Some("R_SH_COPY"),
|
||||||
|
elf::R_SH_GLOB_DAT => Some("R_SH_GLOB_DAT"),
|
||||||
|
elf::R_SH_JMP_SLOT => Some("R_SH_JMP_SLOT"),
|
||||||
|
elf::R_SH_RELATIVE => Some("R_SH_RELATIVE"),
|
||||||
|
elf::R_SH_GOTOFF => Some("R_SH_GOTOFF"),
|
||||||
|
elf::R_SH_GOTPC => Some("R_SH_GOTPC"),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data_reloc_size(&self, flags: RelocationFlags) -> usize {
|
||||||
|
match flags {
|
||||||
|
RelocationFlags::Elf(elf::R_SH_DIR32) => 4,
|
||||||
|
RelocationFlags::Elf(_) => 1,
|
||||||
|
_ => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::obj::InstructionArg;
|
||||||
|
|
||||||
|
impl Display for InstructionPart<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InstructionPart::Basic(s) => write!(f, "{}", s),
|
||||||
|
InstructionPart::Opcode(s, _o) => write!(f, "{} ", s),
|
||||||
|
InstructionPart::Arg(arg) => write!(f, "{}", arg),
|
||||||
|
InstructionPart::Separator => write!(f, ", "),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for InstructionArg<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InstructionArg::Value(v) => write!(f, "{}", v),
|
||||||
|
InstructionArg::BranchDest(v) => write!(f, "{}", v),
|
||||||
|
InstructionArg::Reloc => write!(f, "reloc"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_basic_ops() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: [(u16, &str); 8] = [
|
||||||
|
(0x0008, "clrt "),
|
||||||
|
(0x0028, "clrmac "),
|
||||||
|
(0x0019, "div0u "),
|
||||||
|
(0x0009, "nop "),
|
||||||
|
(0x002b, "rte "),
|
||||||
|
(0x000b, "rts "),
|
||||||
|
(0x0018, "sett "),
|
||||||
|
(0x001b, "sleep "),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (opcode, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: 0x1000, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_f0ff_ops() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: [(u16, &str); 49] = [
|
||||||
|
(0x4015, "cmp/pl r0"),
|
||||||
|
(0x4115, "cmp/pl r1"),
|
||||||
|
(0x4215, "cmp/pl r2"),
|
||||||
|
(0x4315, "cmp/pl r3"),
|
||||||
|
(0x4011, "cmp/pz r0"),
|
||||||
|
(0x4010, "dt r0"),
|
||||||
|
(0x0029, "movt r0"),
|
||||||
|
(0x4004, "rotl r0"),
|
||||||
|
(0x4005, "rotr r0"),
|
||||||
|
(0x4024, "rotcl r0"),
|
||||||
|
(0x4025, "rotcr r0"),
|
||||||
|
(0x4020, "shal r0"),
|
||||||
|
(0x4021, "shar r0"),
|
||||||
|
(0x4000, "shll r0"),
|
||||||
|
(0x4001, "shlr r0"),
|
||||||
|
(0x4008, "shll2 r0"),
|
||||||
|
(0x4009, "shlr2 r0"),
|
||||||
|
(0x4018, "shll8 r0"),
|
||||||
|
(0x4019, "shlr8 r0"),
|
||||||
|
(0x4028, "shll16 r0"),
|
||||||
|
(0x4029, "shlr16 r0"),
|
||||||
|
(0x0002, "stc sr, r0"),
|
||||||
|
(0x0012, "stc gbr, r0"),
|
||||||
|
(0x0022, "stc vbr, r0"),
|
||||||
|
(0x000a, "sts mach, r0"),
|
||||||
|
(0x001a, "sts macl, r0"),
|
||||||
|
(0x402a, "lds r0, pr"),
|
||||||
|
(0x401b, "tas.b r0"),
|
||||||
|
(0x4003, "stc.l sr, @-r0"),
|
||||||
|
(0x4013, "stc.l gbr, @-r0"),
|
||||||
|
(0x4023, "stc.l vbr, @-r0"),
|
||||||
|
(0x4002, "sts.l mach, @-r0"),
|
||||||
|
(0x4012, "sts.l macl, @-r0"),
|
||||||
|
(0x4022, "sts.l pr, @-r0"),
|
||||||
|
(0x400e, "ldc r0, sr"),
|
||||||
|
(0x401e, "ldc r0, gbr"),
|
||||||
|
(0x402e, "ldc r0, vbr"),
|
||||||
|
(0x400a, "lds r0, mach"),
|
||||||
|
(0x401a, "lds r0, macl"),
|
||||||
|
(0x402b, "jmp @r0"),
|
||||||
|
(0x400b, "jsr @r0"),
|
||||||
|
(0x4007, "ldc.l @r0+, sr"),
|
||||||
|
(0x4017, "ldc.l @r0+, gbr"),
|
||||||
|
(0x4027, "ldc.l @r0+, vbr"),
|
||||||
|
(0x4006, "lds.l @r0+, mach"),
|
||||||
|
(0x4016, "lds.l @r0+, macl"),
|
||||||
|
(0x4026, "lds.l @r0+, pr"),
|
||||||
|
(0x0023, "braf r0"),
|
||||||
|
(0x0003, "bsrf r0"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (opcode, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: 0x1000, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instructions_f00f() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: [(u16, &str); 54] = [
|
||||||
|
(0x300c, "add r0, r0"),
|
||||||
|
(0x300e, "addc r0, r0"),
|
||||||
|
(0x300f, "addv r0, r0"),
|
||||||
|
(0x2009, "and r0, r0"),
|
||||||
|
(0x3000, "cmp/eq r0, r0"),
|
||||||
|
(0x3002, "cmp/hs r0, r0"),
|
||||||
|
(0x3003, "cmp/ge r0, r0"),
|
||||||
|
(0x3006, "cmp/hi r0, r0"),
|
||||||
|
(0x3007, "cmp/gt r0, r0"),
|
||||||
|
(0x200c, "cmp/str r0, r0"),
|
||||||
|
(0x3004, "div1 r0, r0"),
|
||||||
|
(0x2007, "div0s r0, r0"),
|
||||||
|
(0x300d, "dmuls.l r0, r0"),
|
||||||
|
(0x3005, "dmulu.l r0, r0"),
|
||||||
|
(0x600e, "exts.b r0, r0"),
|
||||||
|
(0x600f, "exts.w r0, r0"),
|
||||||
|
(0x600c, "extu.b r0, r0"),
|
||||||
|
(0x600d, "extu.w r0, r0"),
|
||||||
|
(0x6003, "mov r0, r0"),
|
||||||
|
(0x0007, "mul.l r0, r0"),
|
||||||
|
(0x200f, "muls r0, r0"),
|
||||||
|
(0x200e, "mulu r0, r0"),
|
||||||
|
(0x600b, "neg r0, r0"),
|
||||||
|
(0x600a, "negc r0, r0"),
|
||||||
|
(0x6007, "not r0, r0"),
|
||||||
|
(0x200b, "or r0, r0"),
|
||||||
|
(0x3008, "sub r0, r0"),
|
||||||
|
(0x300a, "subc r0, r0"),
|
||||||
|
(0x300b, "subv r0, r0"),
|
||||||
|
(0x6008, "swap.b r0, r0"),
|
||||||
|
(0x6009, "swap.w r0, r0"),
|
||||||
|
(0x2008, "tst r0, r0"),
|
||||||
|
(0x200a, "xor r0, r0"),
|
||||||
|
(0x200d, "xtrct r0, r0"),
|
||||||
|
(0x2000, "mov.b r0, @r0"),
|
||||||
|
(0x2001, "mov.w r0, @r0"),
|
||||||
|
(0x2002, "mov.l r0, @r0"),
|
||||||
|
(0x6000, "mov.b @r0, r0"),
|
||||||
|
(0x6001, "mov.w @r0, r0"),
|
||||||
|
(0x6002, "mov.l @r0, r0"),
|
||||||
|
(0x000f, "mac.l @r0+, @r0+"),
|
||||||
|
(0x400f, "mac.w @r0+, @r0+"),
|
||||||
|
(0x6004, "mov.b @r0+, r0"),
|
||||||
|
(0x6005, "mov.w @r0+, r0"),
|
||||||
|
(0x6006, "mov.l @r0+, r0"),
|
||||||
|
(0x2004, "mov.b r0, @-r0"),
|
||||||
|
(0x2005, "mov.w r0, @-r0"),
|
||||||
|
(0x2006, "mov.l r0, @-r0"),
|
||||||
|
(0x0004, "mov.b r0, @(r0, r0)"),
|
||||||
|
(0x0005, "mov.w r0, @(r0, r0)"),
|
||||||
|
(0x0006, "mov.l r0, @(r0, r0)"),
|
||||||
|
(0x000c, "mov.b @(r0, r0), r0"),
|
||||||
|
(0x000d, "mov.w @(r0, r0), r0"),
|
||||||
|
(0x000e, "mov.l @(r0, r0), r0"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (opcode, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: 0x1000, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_mov_immediate_offset() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: [(u16, &str); 8] = [
|
||||||
|
(0x8000, "mov.b r0, @(0x0, r0)"),
|
||||||
|
(0x8011, "mov.b r0, @(0x1, r1)"),
|
||||||
|
(0x8102, "mov.w r0, @(0x4, r0)"),
|
||||||
|
(0x8113, "mov.w r0, @(0x6, r1)"),
|
||||||
|
(0x8404, "mov.b @(0x4, r0), r0"),
|
||||||
|
(0x8415, "mov.b @(0x5, r1), r0"),
|
||||||
|
(0x8506, "mov.w @(0xc, r0), r0"),
|
||||||
|
(0x8517, "mov.w @(0xe, r1), r0"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (opcode, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: 0x1000, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_gbr_and_branches() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] = &[
|
||||||
|
(0xc000, 0x0000, "mov.b r0, @(0x0, gbr)"),
|
||||||
|
(0xc07f, 0x0000, "mov.b r0, @(0x7f, gbr)"),
|
||||||
|
(0xc100, 0x0000, "mov.w r0, @(0x0, gbr)"),
|
||||||
|
(0xc17f, 0x0000, "mov.w r0, @(0xfe, gbr)"),
|
||||||
|
(0xc200, 0x0000, "mov.l r0, @(0x0, gbr)"),
|
||||||
|
(0xc27f, 0x0000, "mov.l r0, @(0x1fc, gbr)"),
|
||||||
|
(0xc400, 0x0000, "mov.b @(0x0, gbr), r0"),
|
||||||
|
(0xc47f, 0x0000, "mov.b @(0x7f, gbr), r0"),
|
||||||
|
(0xc500, 0x0000, "mov.w @(0x0, gbr), r0"),
|
||||||
|
(0xc57f, 0x0000, "mov.w @(0xfe, gbr), r0"),
|
||||||
|
(0xc600, 0x0000, "mov.l @(0x0, gbr), r0"),
|
||||||
|
(0xc67f, 0x0000, "mov.l @(0x1fc, gbr), r0"),
|
||||||
|
(0x8b20, 0x1000, "bf 0x44"),
|
||||||
|
(0x8b80, 0x1000, "bf 0xffffff04"),
|
||||||
|
(0x8f10, 0x2000, "bf.s 0x24"),
|
||||||
|
(0x8f90, 0x2000, "bf.s 0xffffff24"),
|
||||||
|
(0x8904, 0x3000, "bt 0xc"),
|
||||||
|
(0x8980, 0x3000, "bt 0xffffff04"),
|
||||||
|
(0x8d04, 0x4000, "bt.s 0xc"),
|
||||||
|
(0x8d80, 0x4000, "bt.s 0xffffff04"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_mov_l() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] = &[
|
||||||
|
// mov.l rX, @(0xXXX, rY)
|
||||||
|
(0x1000, 0x0000, "mov.l r0, @(0x0, r0)"),
|
||||||
|
(0x1001, 0x0000, "mov.l r0, @(0x4, r0)"),
|
||||||
|
(0x100f, 0x0000, "mov.l r0, @(0x3c, r0)"),
|
||||||
|
(0x101f, 0x0000, "mov.l r1, @(0x3c, r0)"),
|
||||||
|
// mov.l @(0xXXX, rY), rX
|
||||||
|
(0x5000, 0x0000, "mov.l @(0x0, r0), r0"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_bra_bsr() {
|
||||||
|
let arch: ArchSuperH = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] = &[
|
||||||
|
// bra
|
||||||
|
(0xa000, 0x0000, "bra 0x4"),
|
||||||
|
(0xa001, 0x0000, "bra 0x6"),
|
||||||
|
(0xa800, 0x0000, "bra 0xfffff004"),
|
||||||
|
(0xa801, 0x0000, "bra 0xfffff006"),
|
||||||
|
// bsr
|
||||||
|
(0xb000, 0x0000, "bsr 0x4"),
|
||||||
|
(0xb001, 0x0000, "bsr 0x6"),
|
||||||
|
(0xb800, 0x0000, "bsr 0xfffff004"),
|
||||||
|
(0xb801, 0x0000, "bsr 0xfffff006"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_display_instruction_operations() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] = &[
|
||||||
|
(0xcdff, 0x0000, "and.b #0xff, @(r0, gbr)"),
|
||||||
|
(0xcfff, 0x0000, "or.b #0xff, @(r0, gbr)"),
|
||||||
|
(0xccff, 0x0000, "tst.b #0xff, @(r0, gbr)"),
|
||||||
|
(0xceff, 0x0000, "xor.b #0xff, @(r0, gbr)"),
|
||||||
|
(0xc9ff, 0x0000, "and #0xff, r0"),
|
||||||
|
(0x88ff, 0x0000, "cmp/eq #0xff, r0"),
|
||||||
|
(0xcbff, 0x0000, "or #0xff, r0"),
|
||||||
|
(0xc8ff, 0x0000, "tst #0xff, r0"),
|
||||||
|
(0xcaff, 0x0000, "xor #0xff, r0"),
|
||||||
|
(0xc3ff, 0x0000, "trapa #0xff"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_add_mov_unknown_instructions() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] = &[
|
||||||
|
(0x70FF, 0x0000, "add #0xff, r0"),
|
||||||
|
(0xE0FF, 0x0000, "mov #0xff, r0"),
|
||||||
|
(0x0000, 0x0000, ".word 0x0000 /* unknown instruction */"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sh2_mov_instructions_with_labels() {
|
||||||
|
let arch = ArchSuperH {};
|
||||||
|
let ops: &[(u16, u32, &str)] =
|
||||||
|
&[(0x9000, 0x0000, "mov.w @(0x4, pc), r0"), (0xd000, 0x0000, "mov.l @(0x4, pc), r0")];
|
||||||
|
|
||||||
|
for &(opcode, addr, expected_str) in ops {
|
||||||
|
let code = opcode.to_be_bytes();
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
arch.display_instruction(
|
||||||
|
ResolvedInstructionRef {
|
||||||
|
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
|
||||||
|
code: &code,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&DiffObjConfig::default(),
|
||||||
|
&mut |part| {
|
||||||
|
parts.push(part.into_static());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
|
||||||
|
assert_eq!(joined_str, expected_str.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user