extern crate libc;
use std::ffi::CStr;
use std::ptr;
use std::str;
use std::fmt::{self, Display, Debug, Formatter, Error};
use capstone_sys::*;
#[derive(Debug)]
pub struct Instructions {
ptr: *mut cs_insn,
len: isize,
}
impl Instructions {
pub unsafe fn from_raw_parts(ptr: *mut cs_insn, len: isize) -> Instructions {
Instructions { ptr: ptr, len: len }
}
pub fn len(&self) -> isize {
self.len
}
pub fn iter(&self) -> InstructionIterator {
InstructionIterator {
insns: self,
cur: 0,
}
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl Drop for Instructions {
fn drop(&mut self) {
unsafe {
cs_free(self.ptr, self.len as libc::size_t);
}
}
}
pub struct InstructionIterator<'a> {
insns: &'a Instructions,
cur: isize,
}
impl<'a> Iterator for InstructionIterator<'a> {
type Item = Insn;
fn next(&mut self) -> Option<Insn> {
if self.cur == self.insns.len {
None
} else {
let obj = unsafe { self.insns.ptr.offset(self.cur) };
self.cur += 1;
Some(unsafe { Insn(ptr::read(obj)) })
}
}
}
pub struct Insn(pub(crate) cs_insn);
pub struct Detail<'a>(pub(crate) &'a cs_detail);
impl Insn {
pub fn mnemonic(&self) -> Option<&str> {
let cstr = unsafe { CStr::from_ptr(self.0.mnemonic.as_ptr()) };
str::from_utf8(cstr.to_bytes()).ok()
}
pub fn op_str(&self) -> Option<&str> {
let cstr = unsafe { CStr::from_ptr(self.0.op_str.as_ptr()) };
str::from_utf8(cstr.to_bytes()).ok()
}
pub fn id(&self) -> libc::c_uint {
self.0.id
}
fn len(&self) -> usize {
self.0.size as usize
}
pub fn address(&self) -> u64 {
self.0.address as u64
}
pub fn bytes(&self) -> &[u8] {
&self.0.bytes[..self.len()]
}
pub(crate) unsafe fn detail(&self) -> Detail {
Detail(&*self.0.detail)
}
}
impl Debug for Insn {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
fmt.debug_struct("Insn")
.field("address", &self.address())
.field("len", &self.len())
.field("bytes", &self.bytes())
.field("mnemonic", &self.mnemonic())
.field("op_str", &self.op_str())
.finish()
}
}
impl Display for Insn {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "{:#x}: ", self.address())?;
if let Some(mnemonic) = self.mnemonic() {
write!(fmt, "{} ", mnemonic)?;
if let Some(op_str) = self.op_str() {
write!(fmt, "{}", op_str)?;
}
}
Ok(())
}
}
impl<'a> Detail<'a> {
pub fn regs_read(&self) -> &[libc::uint8_t] {
&(*self.0).regs_read[..self.regs_read_count() as usize]
}
pub fn regs_read_count(&self) -> libc::uint8_t {
(*self.0).regs_read_count
}
pub fn regs_write(&self) -> &[libc::uint8_t] {
&(*self.0).regs_write[..self.regs_write_count() as usize]
}
pub fn regs_write_count(&self) -> libc::uint8_t {
(*self.0).regs_write_count
}
pub fn groups(&'a self) -> &'a [libc::uint8_t] {
&(*self.0).groups[..self.groups_count() as usize]
}
pub fn groups_count(&self) -> libc::uint8_t {
(*self.0).groups_count
}
}
impl<'a> Debug for Detail<'a> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.debug_struct("Detail")
.field("regs_read", &self.regs_read())
.field("regs_read_count", &self.regs_read_count())
.field("regs_write", &self.regs_write())
.field("regs_write_count", &self.regs_write_count())
.field("groups", &self.groups())
.field("groups_count", &self.groups_count())
.finish()
}
}
impl Display for Instructions {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
for instruction in self.iter() {
write!(fmt, "{:x}:\t", instruction.address())?;
for byte in instruction.bytes() {
write!(fmt, " {:02x}", byte)?;
}
let remainder = 16 * 3 - (instruction.bytes().len()) * 3;
for _ in 0..remainder {
write!(fmt, " ")?;
}
if let Some(mnemonic) = instruction.mnemonic() {
write!(fmt, " {}", mnemonic)?;
if let Some(op_str) = instruction.op_str() {
write!(fmt, " {}", op_str)?;
}
}
write!(fmt, "\n")?;
}
Ok(())
}
}