use crate::{
CallbackFlags, Error, Instruction, Result, VCPUIndex,
handle_qemu_plugin_register_vcpu_tb_exec_cb, sys::qemu_plugin_tb,
};
#[cfg(not(any(
feature = "plugin-api-v0",
feature = "plugin-api-v1",
feature = "plugin-api-v2"
)))]
use crate::{PluginCondition, PluginU64};
use std::{ffi::c_void, marker::PhantomData};
#[derive(Debug, Clone)]
pub struct TranslationBlock<'a> {
pub(crate) translation_block: usize,
marker: PhantomData<&'a ()>,
}
impl<'a> From<*mut qemu_plugin_tb> for TranslationBlock<'a> {
fn from(tb: *mut qemu_plugin_tb) -> Self {
Self {
translation_block: tb as usize,
marker: PhantomData,
}
}
}
impl<'a> TranslationBlock<'a> {
pub fn size(&self) -> usize {
unsafe { crate::sys::qemu_plugin_tb_n_insns(self.translation_block as *mut qemu_plugin_tb) }
}
pub fn vaddr(&self) -> u64 {
unsafe { crate::sys::qemu_plugin_tb_vaddr(self.translation_block as *mut qemu_plugin_tb) }
}
pub fn instruction(&'a self, index: usize) -> Result<Instruction<'a>> {
let size = self.size();
if index >= size {
Err(Error::InvalidInstructionIndex { index, size })
} else {
Ok(Instruction::new(self, unsafe {
crate::sys::qemu_plugin_tb_get_insn(
self.translation_block as *mut qemu_plugin_tb,
index,
)
}))
}
}
pub fn instructions(&'a self) -> TranslationBlockIterator<'a> {
TranslationBlockIterator { tb: self, index: 0 }
}
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_tb_exec_cb(
self.translation_block as *mut qemu_plugin_tb,
Some(handle_qemu_plugin_register_vcpu_tb_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_tb_exec_cond_cb(
self.translation_block as *mut qemu_plugin_tb,
Some(handle_qemu_plugin_register_vcpu_tb_exec_cb::<F>),
flags,
cond,
entry,
immediate,
userdata,
)
};
}
}
pub struct TranslationBlockIterator<'a> {
tb: &'a TranslationBlock<'a>,
index: usize,
}
impl<'a> Iterator for TranslationBlockIterator<'a> {
type Item = Instruction<'a>;
fn next(&mut self) -> Option<Self::Item> {
let size = self.tb.size();
if self.index >= size {
None
} else {
let insn = self.tb.instruction(self.index).ok();
self.index += 1;
insn
}
}
}