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