use crate::arch::{
arm, arm64, evm, m680x, m68k, mips, mos65xx, ppc, sparc, sysz, tms320c64x, x86, xcore,
InsnGroup, Reg,
};
use crate::{sys, util, Arch};
use core::marker::PhantomData;
const MNEMONIC_SIZE: usize = 32;
#[repr(C)]
pub struct Insn<'a> {
pub(crate) id: libc::c_uint,
address: u64,
size: u16,
bytes: [u8; 24],
mnemonic: [libc::c_char; MNEMONIC_SIZE],
op_str: [libc::c_char; 160],
pub(crate) detail: *mut DetailsInner,
_phan: PhantomData<&'a ()>,
}
impl<'a> Insn<'a> {
#[inline]
pub fn address(&self) -> u64 {
self.address
}
#[inline]
pub fn size(&self) -> usize {
self.size as usize
}
#[inline]
pub fn bytes(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.bytes.as_ptr(), self.size()) }
}
#[inline]
pub fn mnemonic(&self) -> &str {
unsafe { util::cstr(self.mnemonic.as_ptr(), MNEMONIC_SIZE) }
}
#[inline]
pub fn operands(&self) -> &str {
unsafe { util::cstr(self.op_str.as_ptr(), 160) }
}
}
pub struct InsnBuffer<'a> {
inner: *mut Insn<'a>,
count: usize,
_phan: PhantomData<&'a Insn<'a>>,
}
impl<'a> InsnBuffer<'a> {
pub(crate) fn new(insn: *mut Insn<'a>, count: usize) -> InsnBuffer<'a> {
InsnBuffer {
inner: insn,
count,
_phan: PhantomData,
}
}
fn free(&mut self) {
if self.count == 0 || self.inner.is_null() {
return;
}
unsafe { sys::cs_free(self.inner as *mut Insn, self.count as libc::size_t) };
self.inner = core::ptr::null_mut();
self.count = 0;
}
}
impl<'a> core::ops::Deref for InsnBuffer<'a> {
type Target = [Insn<'a>];
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { core::slice::from_raw_parts(self.inner, self.count) }
}
}
impl<'a> Drop for InsnBuffer<'a> {
fn drop(&mut self) {
self.free();
}
}
pub struct InsnIter<'a> {
caps: &'a super::Capstone,
insn: *mut Insn<'a>,
code: *const u8,
size: libc::size_t,
addr: u64,
}
impl<'a> InsnIter<'a> {
pub(crate) fn new(
caps: &'a super::Capstone,
insn: *mut Insn<'a>,
code: *const u8,
size: libc::size_t,
addr: u64,
) -> InsnIter<'a> {
InsnIter {
caps,
insn,
code,
size,
addr,
}
}
fn free(&mut self) {
if self.insn.is_null() {
return;
}
unsafe { sys::cs_free(self.insn as *mut Insn, 1) };
self.insn = core::ptr::null_mut();
}
}
impl<'a> Iterator for InsnIter<'a> {
type Item = Result<&'a Insn<'a>, super::Error>;
fn next(&mut self) -> Option<Self::Item> {
let success = unsafe {
sys::cs_disasm_iter(
self.caps.handle,
&mut self.code,
&mut self.size,
&mut self.addr,
self.insn,
)
};
#[cfg(feature = "std")]
self.caps.resume_panic();
if !success {
match self.caps.errno() {
Ok(_) => return None,
Err(err) => return Some(Err(err)),
}
}
Ok(unsafe { self.insn.as_ref() }).transpose()
}
}
impl<'a> Drop for InsnIter<'a> {
fn drop(&mut self) {
self.free();
}
}
#[derive(Copy, Clone)]
pub struct Details<'i> {
arch: Arch,
inner: &'i DetailsInner,
}
impl<'i> Details<'i> {
pub(crate) fn wrap(arch: Arch, inner: &'i DetailsInner) -> Details<'i> {
Details { arch, inner }
}
pub fn regs_read(self) -> &'i [Reg] {
unsafe {
&*(&self.inner.regs_read[..self.inner.regs_read_count as usize] as *const [u16]
as *const [Reg])
}
}
pub fn regs_write(self) -> &'i [Reg] {
unsafe {
&*(&self.inner.regs_write[..self.inner.regs_write_count as usize] as *const [u16]
as *const [Reg])
}
}
pub fn groups(self) -> &'i [InsnGroup] {
unsafe {
&*(&self.inner.groups[..self.inner.groups_count as usize] as *const [u8]
as *const [InsnGroup])
}
}
pub fn arch(self) -> ArchDetails<'i> {
match self.arch {
Arch::Arm => ArchDetails::Arm(unsafe { &self.inner.arch.arm }),
Arch::Arm64 => ArchDetails::Arm64(unsafe { &self.inner.arch.arm64 }),
Arch::Mips => ArchDetails::Mips(unsafe { &self.inner.arch.mips }),
Arch::X86 => ArchDetails::X86(unsafe { &self.inner.arch.x86 }),
Arch::PowerPc => ArchDetails::PowerPc(unsafe { &self.inner.arch.ppc }),
Arch::Sparc => ArchDetails::Sparc(unsafe { &self.inner.arch.sparc }),
Arch::SystemZ => ArchDetails::SystemZ(unsafe { &self.inner.arch.sysz }),
Arch::XCore => ArchDetails::XCore(unsafe { &self.inner.arch.xcore }),
Arch::M68K => ArchDetails::M68K(unsafe { &self.inner.arch.m68k }),
Arch::Tms320C64X => ArchDetails::Tms320C64X(unsafe { &self.inner.arch.tms320c64x }),
Arch::M680X => ArchDetails::M680X(unsafe { &self.inner.arch.m680x }),
Arch::Evm => ArchDetails::Evm(unsafe { &self.inner.arch.evm }),
Arch::Mos65xx => ArchDetails::Mos65xx(unsafe { &self.inner.arch.mos65xx }),
}
}
pub fn x86(self) -> Option<&'i x86::Details<'i>> {
if self.arch == Arch::X86 {
Some(unsafe { &self.inner.arch.x86 })
} else {
None
}
}
}
#[repr(C)]
pub(crate) struct DetailsInner {
regs_read: [u16; 16],
regs_read_count: u8,
regs_write: [u16; 20],
regs_write_count: u8,
groups: [u8; 8],
groups_count: u8,
pub(crate) arch: ArchDetailsUnion,
}
#[repr(C)]
pub(crate) union ArchDetailsUnion {
pub x86: x86::Details<'static>,
pub arm64: arm64::Details<'static>,
pub arm: arm::Details<'static>,
pub m68k: m68k::Details<'static>,
pub mips: mips::Details<'static>,
pub ppc: ppc::Details<'static>,
pub sparc: sparc::Details<'static>,
pub sysz: sysz::Details<'static>,
pub xcore: xcore::Details<'static>,
pub tms320c64x: tms320c64x::Details<'static>,
pub m680x: m680x::Details<'static>,
pub evm: evm::Details<'static>,
pub mos65xx: mos65xx::Details<'static>,
}
#[derive(Copy, Clone)]
pub enum ArchDetails<'i> {
X86(&'i x86::Details<'i>),
Arm64(&'i arm64::Details<'i>),
Arm(&'i arm::Details<'i>),
M68K(&'i m68k::Details<'i>),
Mips(&'i mips::Details<'i>),
PowerPc(&'i ppc::Details<'i>),
Sparc(&'i sparc::Details<'i>),
SystemZ(&'i sysz::Details<'i>),
XCore(&'i xcore::Details<'i>),
Tms320C64X(&'i tms320c64x::Details<'i>),
M680X(&'i m680x::Details<'i>),
Evm(&'i evm::Details<'i>),
Mos65xx(&'i mos65xx::Details<'i>),
}
#[cfg(test)]
mod test {
use super::*;
use crate::sys;
#[test]
fn detail_size_and_alignment() {
assert_eq!(
core::mem::size_of::<DetailsInner>(),
sys::get_test_val("sizeof(cs_detail)")
);
assert_eq!(
core::mem::align_of::<DetailsInner>(),
sys::get_test_val("alignof(cs_detail)")
);
}
#[test]
fn insn_size_and_alignment() {
assert_eq!(
core::mem::size_of::<Insn>(),
sys::get_test_val("sizeof(cs_insn)")
);
assert_eq!(
core::mem::align_of::<Insn>(),
sys::get_test_val("alignof(cs_insn)")
);
}
}