Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regs access #149

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions capstone-rs/src/capstone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use crate::instruction::{Insn, InsnDetail, InsnGroupId, InsnId, Instructions, Re

use {crate::ffi::str_from_cstr_ptr, alloc::string::ToString, libc::c_uint};

/// This is taken from the [python bindings](https://github.com/capstone-engine/capstone/blob/5fb8a423d4455cade99b12912142fd3a0c10d957/bindings/python/capstone/__init__.py#L929)
const MAX_NUM_REGISTERS: usize = 64;

/// An instance of the capstone disassembler
///
/// Create with an instance with [`.new()`](Self::new) and disassemble bytes with [`.disasm_all()`](Self::disasm_all).
Expand Down Expand Up @@ -100,6 +103,11 @@ impl Iterator for EmptyExtraModeIter {
}
}

pub struct RegAccess {
pub read: Vec<RegId>,
pub write: Vec<RegId>,
}

impl Capstone {
/// Create a new instance of the decompiler using the builder pattern interface.
/// This is the recommended interface to `Capstone`.
Expand Down Expand Up @@ -365,6 +373,65 @@ impl Capstone {
}
}

/// Get the registers are which are read to and written to
pub fn regs_access_buf(&self, insn: &Insn) -> CsResult<RegAccess> {
let mut read = Vec::new();
let mut write = Vec::new();

self.regs_access(insn, &mut read, &mut write)?;

Ok(RegAccess { read, write })
}

/// Get the registers are which are read to and written to\
/// the registers are pushed to the back of the provided buffers
pub fn regs_access(
&self,
insn: &Insn,
read: &mut Vec<RegId>,
write: &mut Vec<RegId>,
) -> CsResult<()> {
if cfg!(feature = "full") {
let mut regs_read_count: u8 = 0;
let mut regs_write_count: u8 = 0;

let mut regs_write = [0u16; MAX_NUM_REGISTERS];
let mut regs_read = [0u16; MAX_NUM_REGISTERS];

let err = unsafe {
cs_regs_access(
self.csh(),
&insn.insn as *const cs_insn,
&mut regs_read as *mut _,
&mut regs_read_count as *mut _,
&mut regs_write as *mut _,
&mut regs_write_count as *mut _,
)
};

if err != cs_err::CS_ERR_OK {
return Err(err.into());
}

read.extend(
regs_read
.iter()
.take(regs_read_count as usize)
.map(|x| RegId(*x)),
);
write.extend(
regs_write
.iter()
.take(regs_write_count as usize)
.map(|x| RegId(*x)),
);

Ok(())
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use an early return in the case of an error to reduce the indentation of the "happy" case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you referring to the entire outer if cfg!(...) {? I agree it's cleaner, however the entire file is written this way currently :)

Err(Error::DetailOff)
}
}

/// Converts a group id `group_id` to a `String` containing the group name.
/// Unavailable in Diet mode
pub fn group_name(&self, group_id: InsnGroupId) -> Option<String> {
Expand Down