#![doc(html_root_url="https://keystone/doc/here/v1")]
#[macro_use]
extern crate bitflags;
extern crate libc;
pub mod ffi;
pub mod keystone_const;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
pub use keystone_const::*;
#[allow(non_camel_case_types)]
pub type ks_handle = libc::size_t;
impl Error {
pub fn msg(&self) -> String {
error_msg(*self)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg())
}
}
#[derive(Debug, PartialEq)]
pub struct AsmResult {
pub size: u32,
pub stat_count: u32,
pub bytes: Vec<u8>,
}
impl fmt::Display for AsmResult {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for byte in &self.bytes {
try!(f.write_fmt(format_args!("{:02x}", byte)));
}
Ok(())
}
}
pub fn bindings_version() -> (u32, u32) {
(KS_API_MAJOR, KS_API_MINOR)
}
pub fn version() -> (u32, u32) {
let mut major: u32 = 0;
let mut minor: u32 = 0;
unsafe {
ffi::ks_version(&mut major, &mut minor);
}
(major, minor)
}
pub fn arch_supported(arch: Arch) -> bool {
unsafe { ffi::ks_arch_supported(arch.val()) }
}
pub fn error_msg(error: Error) -> String {
unsafe { CStr::from_ptr(ffi::ks_strerror(error.bits())).to_string_lossy().into_owned() }
}
pub struct Keystone {
handle: ks_handle,
}
impl Keystone {
pub fn new(arch: Arch, mode: Mode) -> Result<Keystone, Error> {
if version() != bindings_version() {
return Err(ERR_VERSION);
}
let mut handle: ks_handle = 0;
let err = Error::from_bits_truncate(unsafe {
ffi::ks_open(arch.val(), mode.bits(), &mut handle)
});
if err == ERR_OK {
Ok(Keystone { handle: handle })
} else {
Err(err)
}
}
pub fn error(&self) -> Result<(), Error> {
let err = Error::from_bits_truncate(unsafe { ffi::ks_errno(self.handle) });
if err == ERR_OK {
Ok(())
} else {
Err(err)
}
}
pub fn option(&self, type_: OptionType, value: OptionValue) -> Result<(), Error> {
let err = Error::from_bits_truncate(unsafe {
ffi::ks_option(self.handle, type_.val(), value.bits())
});
if err == ERR_OK {
Ok(())
} else {
Err(err)
}
}
pub fn asm(&self, str: String, address: u64) -> Result<AsmResult, Error> {
let mut size: libc::size_t = 0;
let mut stat_count: libc::size_t = 0;
let s = CString::new(str).unwrap();
let mut ptr: *mut libc::c_uchar = std::ptr::null_mut();
let err = Error::from_bits_truncate(unsafe {
ffi::ks_asm(self.handle,
s.as_ptr(),
address,
&mut ptr,
&mut size,
&mut stat_count)
});
if err == ERR_OK {
let bytes = unsafe { std::slice::from_raw_parts(ptr, size) };
unsafe {
ffi::ks_free(ptr);
};
Ok(AsmResult {
size: size as u32,
stat_count: stat_count as u32,
bytes: From::from(&bytes[..]),
})
} else {
let err = Error::from_bits_truncate(unsafe { ffi::ks_errno(self.handle) });
Err(err)
}
}
}
impl Drop for Keystone {
fn drop(&mut self) {
unsafe { ffi::ks_close(self.handle) };
}
}