use crate::{
CallbackFlags, Error, MemRW, MemoryInfo, Result, TranslationBlock, VCPUIndex, g_free,
handle_qemu_plugin_register_vcpu_insn_exec_cb, handle_qemu_plugin_register_vcpu_mem_cb,
sys::qemu_plugin_insn,
};
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
use crate::{PluginCondition, PluginU64};
use std::{
ffi::{CStr, c_void},
marker::PhantomData,
};
#[derive(Debug, Clone)]
pub struct Instruction<'a> {
#[allow(unused)]
translation_block: &'a TranslationBlock<'a>,
pub(crate) instruction: usize,
marker: PhantomData<&'a ()>,
}
impl<'a> Instruction<'a> {
pub(crate) fn new(
translation_block: &'a TranslationBlock<'a>,
insn: *mut qemu_plugin_insn,
) -> Self {
Self {
translation_block,
instruction: insn as usize,
marker: PhantomData,
}
}
}
impl<'a> Instruction<'a> {
#[cfg(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
))]
pub fn data(&self) -> Vec<u8> {
let size = self.size();
let mut data = Vec::with_capacity(size);
let insn_data =
unsafe { crate::sys::qemu_plugin_insn_data(self.instruction as *mut qemu_plugin_insn) }
as *mut u8;
unsafe {
data.set_len(size);
std::ptr::copy_nonoverlapping(insn_data, data.as_mut_ptr(), size);
}
data
}
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
pub fn read_data(&self, data: &mut [u8]) -> usize {
unsafe {
crate::sys::qemu_plugin_insn_data(
self.instruction as *mut qemu_plugin_insn,
data.as_mut_ptr() as *mut _,
data.len(),
)
}
}
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
pub fn data(&self) -> Vec<u8> {
let size = self.size();
let mut data = vec![0; size];
let size = self.read_data(&mut data);
data.truncate(size);
data
}
pub fn size(&self) -> usize {
unsafe { crate::sys::qemu_plugin_insn_size(self.instruction as *mut qemu_plugin_insn) }
}
pub fn vaddr(&self) -> u64 {
unsafe { crate::sys::qemu_plugin_insn_vaddr(self.instruction as *mut qemu_plugin_insn) }
}
pub fn haddr(&self) -> u64 {
(unsafe { crate::sys::qemu_plugin_insn_haddr(self.instruction as *mut qemu_plugin_insn) })
as usize as u64
}
pub fn disas(&self) -> Result<String> {
let disas = unsafe {
crate::sys::qemu_plugin_insn_disas(self.instruction as *mut qemu_plugin_insn)
};
if disas.is_null() {
Err(Error::NoDisassemblyString)
} else {
let disas_string = unsafe { CStr::from_ptr(disas) }.to_str()?.to_string();
unsafe { g_free(disas as *mut _) };
Ok(disas_string)
}
}
#[cfg(not(feature = "plugin-api-v0"))]
pub fn symbol(&self) -> Result<Option<String>> {
let symbol = unsafe {
crate::sys::qemu_plugin_insn_symbol(self.instruction as *mut qemu_plugin_insn)
};
if symbol.is_null() {
Ok(None)
} else {
let symbol_string = unsafe { CStr::from_ptr(symbol) }.to_str()?.to_string();
Ok(Some(symbol_string))
}
}
pub fn register_execute_callback<F>(&self, cb: F)
where
F: FnMut(VCPUIndex) + Send + Sync + 'static,
{
self.register_execute_callback_flags(cb, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
}
pub fn register_execute_callback_flags<F>(&self, cb: F, flags: CallbackFlags)
where
F: FnMut(VCPUIndex) + Send + Sync + 'static,
{
let callback = Box::new(cb);
let callback_box = Box::new(callback);
let userdata = Box::into_raw(callback_box) as *mut c_void;
unsafe {
crate::sys::qemu_plugin_register_vcpu_insn_exec_cb(
self.instruction as *mut qemu_plugin_insn,
Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
flags,
userdata,
)
};
}
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
pub fn register_conditional_execute_callback<F>(
&self,
cb: F,
cond: PluginCondition,
entry: PluginU64,
immediate: u64,
) where
F: FnMut(VCPUIndex) + Send + Sync + 'static,
{
self.register_conditional_execute_callback_flags(
cb,
CallbackFlags::QEMU_PLUGIN_CB_NO_REGS,
cond,
entry,
immediate,
)
}
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
pub fn register_conditional_execute_callback_flags<F>(
&self,
cb: F,
flags: CallbackFlags,
cond: PluginCondition,
entry: PluginU64,
immediate: u64,
) where
F: FnMut(VCPUIndex) + Send + Sync + 'static,
{
let callback = Box::new(cb);
let callback_box = Box::new(callback);
let userdata = Box::into_raw(callback_box) as *mut c_void;
unsafe {
crate::sys::qemu_plugin_register_vcpu_insn_exec_cond_cb(
self.instruction as *mut qemu_plugin_insn,
Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
flags,
cond,
entry,
immediate,
userdata,
)
};
}
pub fn register_memory_access_callback<F>(&self, cb: F, rw: MemRW)
where
F: for<'b> FnMut(VCPUIndex, MemoryInfo<'b>, u64) + Send + Sync + 'static,
{
self.register_memory_access_callback_flags(cb, rw, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
}
pub fn register_memory_access_callback_flags<F>(&self, cb: F, rw: MemRW, flags: CallbackFlags)
where
F: for<'b> FnMut(VCPUIndex, MemoryInfo<'b>, u64) + Send + Sync + 'static,
{
let callback = Box::new(cb);
let callback_box = Box::new(callback);
let userdata = Box::into_raw(callback_box) as *mut c_void;
unsafe {
crate::sys::qemu_plugin_register_vcpu_mem_cb(
self.instruction as *mut qemu_plugin_insn,
Some(handle_qemu_plugin_register_vcpu_mem_cb::<F>),
flags,
rw,
userdata,
)
};
}
}