qemu_plugin/translation_block/
mod.rs

1//! Translation Block-related functionality for QEMU plugins
2
3use crate::{
4    CallbackFlags, Error, Instruction, Result, VCPUIndex,
5    handle_qemu_plugin_register_vcpu_tb_exec_cb, sys::qemu_plugin_tb,
6};
7#[cfg(not(any(
8    feature = "plugin-api-v0",
9    feature = "plugin-api-v1",
10    feature = "plugin-api-v2"
11)))]
12use crate::{PluginCondition, PluginU64};
13use std::{ffi::c_void, marker::PhantomData};
14
15/// Wrapper structure for a `qemu_plugin_tb *`
16///
17/// # Safety
18///
19/// This structure is safe to use as long as the pointer is valid. The pointer is
20/// always opaque, and therefore may not be dereferenced.
21///
22/// # Example
23///
24/// ```
25/// struct MyPlugin;
26///
27/// impl qemu_plugin::plugin::Register for MyPlugin {}
28///
29/// impl qemu_plugin::plugin::HasCallbacks for MyPlugin {
30///     fn on_translation_block_translate(
31///         &mut self,
32///         id: qemu_plugin::PluginId,
33///         tb: qemu_plugin::TranslationBlock,
34///     ) -> Result<()> {
35///         for insn in tb.instructions() {
36///             println!("{:08x}: {}", insn.vaddr(), insn.disas()?);
37///         }   
38///         Ok(())
39///     }
40/// }
41/// ```
42pub struct TranslationBlock<'a> {
43    pub(crate) translation_block: usize,
44    marker: PhantomData<&'a ()>,
45}
46
47impl<'a> From<*mut qemu_plugin_tb> for TranslationBlock<'a> {
48    fn from(tb: *mut qemu_plugin_tb) -> Self {
49        Self {
50            translation_block: tb as usize,
51            marker: PhantomData,
52        }
53    }
54}
55
56impl<'a> TranslationBlock<'a> {
57    /// Returns the number of instructions in the translation block
58    pub fn size(&self) -> usize {
59        unsafe { crate::sys::qemu_plugin_tb_n_insns(self.translation_block as *mut qemu_plugin_tb) }
60    }
61
62    /// Returns the virtual address for the start of a translation block
63    pub fn vaddr(&self) -> u64 {
64        unsafe { crate::sys::qemu_plugin_tb_vaddr(self.translation_block as *mut qemu_plugin_tb) }
65    }
66
67    /// Returns the instruction in the translation block at `index`. If the index is out of bounds,
68    /// an error is returned.
69    ///
70    /// # Arguments
71    ///
72    /// - `index`: The index of the instruction to return
73    pub fn instruction(&'a self, index: usize) -> Result<Instruction<'a>> {
74        let size = self.size();
75
76        if index >= size {
77            Err(Error::InvalidInstructionIndex { index, size })
78        } else {
79            Ok(Instruction::new(self, unsafe {
80                crate::sys::qemu_plugin_tb_get_insn(
81                    self.translation_block as *mut qemu_plugin_tb,
82                    index,
83                )
84            }))
85        }
86    }
87
88    /// Returns an iterator over the instructions in the translation block
89    pub fn instructions(&'a self) -> TranslationBlockIterator<'a> {
90        TranslationBlockIterator { tb: self, index: 0 }
91    }
92
93    /// Register a callback to be run on execution of this translation block
94    ///
95    /// # Arguments
96    ///
97    /// - `cb`: The callback to be run
98    pub fn register_execute_callback<F>(&self, cb: F)
99    where
100        F: FnMut(VCPUIndex) + Send + Sync + 'static,
101    {
102        self.register_execute_callback_flags(cb, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS);
103    }
104
105    /// Register a callback to be run on execution of this translation block
106    ///
107    /// # Arguments
108    ///
109    /// - `cb`: The callback to be run
110    pub fn register_execute_callback_flags<F>(&self, cb: F, flags: CallbackFlags)
111    where
112        F: FnMut(VCPUIndex) + Send + Sync + 'static,
113    {
114        let callback = Box::new(cb);
115        let callback_box = Box::new(callback);
116        let userdata = Box::into_raw(callback_box) as *mut c_void;
117
118        unsafe {
119            crate::sys::qemu_plugin_register_vcpu_tb_exec_cb(
120                self.translation_block as *mut qemu_plugin_tb,
121                Some(handle_qemu_plugin_register_vcpu_tb_exec_cb::<F>),
122                flags,
123                userdata,
124            )
125        };
126    }
127
128    #[cfg(not(any(
129        feature = "plugin-api-v0",
130        feature = "plugin-api-v1",
131        feature = "plugin-api-v2"
132    )))]
133    /// Register a callback to be conditionally run on execution of this translation
134    /// block
135    ///
136    /// # Arguments
137    ///
138    /// - `cb`: The callback to be run
139    /// - `cond`: The condition for the callback to be run
140    /// - `entry` The entry to increment the scoreboard for
141    /// - `immediate`: The immediate value to use for the callback
142    pub fn register_conditional_execute_callback<F>(
143        &self,
144        cb: F,
145        cond: PluginCondition,
146        entry: PluginU64,
147        immediate: u64,
148    ) where
149        F: FnMut(VCPUIndex) + Send + Sync + 'static,
150    {
151        self.register_conditional_execute_callback_flags(
152            cb,
153            CallbackFlags::QEMU_PLUGIN_CB_NO_REGS,
154            cond,
155            entry,
156            immediate,
157        )
158    }
159
160    #[cfg(not(any(
161        feature = "plugin-api-v0",
162        feature = "plugin-api-v1",
163        feature = "plugin-api-v2"
164    )))]
165    /// Register a callback to be conditionally run on execution of this translation
166    /// block
167    ///
168    /// # Arguments
169    ///
170    /// - `cb`: The callback to be run
171    /// - `flags`: The flags for the callback
172    /// - `cond`: The condition for the callback to be run
173    /// - `entry`: The entry to increment the scoreboard for
174    /// - `immediate`: The immediate value to use for the callback
175    pub fn register_conditional_execute_callback_flags<F>(
176        &self,
177        cb: F,
178        flags: CallbackFlags,
179        cond: PluginCondition,
180        entry: PluginU64,
181        immediate: u64,
182    ) where
183        F: FnMut(VCPUIndex) + Send + Sync + 'static,
184    {
185        let callback = Box::new(cb);
186        let callback_box = Box::new(callback);
187        let userdata = Box::into_raw(callback_box) as *mut c_void;
188
189        unsafe {
190            crate::sys::qemu_plugin_register_vcpu_tb_exec_cond_cb(
191                self.translation_block as *mut qemu_plugin_tb,
192                Some(handle_qemu_plugin_register_vcpu_tb_exec_cb::<F>),
193                flags,
194                cond,
195                entry,
196                immediate,
197                userdata,
198            )
199        };
200    }
201}
202
203/// An iterator over the instructions of a translation block
204pub struct TranslationBlockIterator<'a> {
205    tb: &'a TranslationBlock<'a>,
206    index: usize,
207}
208
209impl<'a> Iterator for TranslationBlockIterator<'a> {
210    type Item = Instruction<'a>;
211
212    fn next(&mut self) -> Option<Self::Item> {
213        let size = self.tb.size();
214
215        if self.index >= size {
216            None
217        } else {
218            let insn = self.tb.instruction(self.index).ok();
219            self.index += 1;
220            insn
221        }
222    }
223}