1use crate::{
4 CallbackFlags, Error, MemRW, MemoryInfo, Result, TranslationBlock, VCPUIndex, g_free,
5 handle_qemu_plugin_register_vcpu_insn_exec_cb, handle_qemu_plugin_register_vcpu_mem_cb,
6 sys::qemu_plugin_insn,
7};
8#[cfg(not(any(
9 feature = "plugin-api-v0",
10 feature = "plugin-api-v1",
11 feature = "plugin-api-v2"
12)))]
13use crate::{PluginCondition, PluginU64};
14use std::{
15 ffi::{CStr, c_void},
16 marker::PhantomData,
17};
18
19#[derive(Debug, Clone)]
20pub struct Instruction<'a> {
53 #[allow(unused)]
54 translation_block: &'a TranslationBlock<'a>,
56 pub(crate) instruction: usize,
57 marker: PhantomData<&'a ()>,
58}
59
60impl<'a> Instruction<'a> {
61 pub(crate) fn new(
62 translation_block: &'a TranslationBlock<'a>,
63 insn: *mut qemu_plugin_insn,
64 ) -> Self {
65 Self {
66 translation_block,
67 instruction: insn as usize,
68 marker: PhantomData,
69 }
70 }
71}
72
73impl<'a> Instruction<'a> {
74 #[cfg(any(
75 feature = "plugin-api-v0",
76 feature = "plugin-api-v1",
77 feature = "plugin-api-v2"
78 ))]
79 pub fn data(&self) -> Vec<u8> {
82 let size = self.size();
83 let mut data = Vec::with_capacity(size);
84
85 let insn_data =
87 unsafe { crate::sys::qemu_plugin_insn_data(self.instruction as *mut qemu_plugin_insn) }
88 as *mut u8;
89
90 unsafe {
91 data.set_len(size);
92 std::ptr::copy_nonoverlapping(insn_data, data.as_mut_ptr(), size);
93 }
94
95 data
96 }
97
98 #[cfg(not(any(
99 feature = "plugin-api-v0",
100 feature = "plugin-api-v1",
101 feature = "plugin-api-v2"
102 )))]
103 pub fn read_data(&self, data: &mut [u8]) -> usize {
106 unsafe {
108 crate::sys::qemu_plugin_insn_data(
109 self.instruction as *mut qemu_plugin_insn,
110 data.as_mut_ptr() as *mut _,
111 data.len(),
112 )
113 }
114 }
115
116 #[cfg(not(any(
117 feature = "plugin-api-v0",
118 feature = "plugin-api-v1",
119 feature = "plugin-api-v2"
120 )))]
121 pub fn data(&self) -> Vec<u8> {
124 let size = self.size();
125 let mut data = vec![0; size];
126
127 let size = self.read_data(&mut data);
128
129 data.truncate(size);
130
131 data
132 }
133
134 pub fn size(&self) -> usize {
136 unsafe { crate::sys::qemu_plugin_insn_size(self.instruction as *mut qemu_plugin_insn) }
137 }
138
139 pub fn vaddr(&self) -> u64 {
141 unsafe { crate::sys::qemu_plugin_insn_vaddr(self.instruction as *mut qemu_plugin_insn) }
142 }
143
144 pub fn haddr(&self) -> u64 {
146 (unsafe { crate::sys::qemu_plugin_insn_haddr(self.instruction as *mut qemu_plugin_insn) })
147 as usize as u64
148 }
149
150 pub fn disas(&self) -> Result<String> {
152 let disas = unsafe {
153 crate::sys::qemu_plugin_insn_disas(self.instruction as *mut qemu_plugin_insn)
154 };
155 if disas.is_null() {
156 Err(Error::NoDisassemblyString)
157 } else {
158 let disas_string = unsafe { CStr::from_ptr(disas) }.to_str()?.to_string();
159
160 unsafe { g_free(disas as *mut _) };
162
163 Ok(disas_string)
164 }
165 }
166
167 #[cfg(not(feature = "plugin-api-v0"))]
168 pub fn symbol(&self) -> Result<Option<String>> {
171 let symbol = unsafe {
172 crate::sys::qemu_plugin_insn_symbol(self.instruction as *mut qemu_plugin_insn)
173 };
174 if symbol.is_null() {
175 Ok(None)
176 } else {
177 let symbol_string = unsafe { CStr::from_ptr(symbol) }.to_str()?.to_string();
178 Ok(Some(symbol_string))
180 }
181 }
182
183 pub fn register_execute_callback<F>(&self, cb: F)
190 where
191 F: FnMut(VCPUIndex) + Send + Sync + 'static,
192 {
193 self.register_execute_callback_flags(cb, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
194 }
195
196 pub fn register_execute_callback_flags<F>(&self, cb: F, flags: CallbackFlags)
205 where
206 F: FnMut(VCPUIndex) + Send + Sync + 'static,
207 {
208 let callback = Box::new(cb);
209 let callback_box = Box::new(callback);
210 let userdata = Box::into_raw(callback_box) as *mut c_void;
211
212 unsafe {
213 crate::sys::qemu_plugin_register_vcpu_insn_exec_cb(
214 self.instruction as *mut qemu_plugin_insn,
215 Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
216 flags,
217 userdata,
218 )
219 };
220 }
221
222 #[cfg(not(any(
232 feature = "plugin-api-v0",
233 feature = "plugin-api-v1",
234 feature = "plugin-api-v2"
235 )))]
236 pub fn register_conditional_execute_callback<F>(
237 &self,
238 cb: F,
239 cond: PluginCondition,
240 entry: PluginU64,
241 immediate: u64,
242 ) where
243 F: FnMut(VCPUIndex) + Send + Sync + 'static,
244 {
245 self.register_conditional_execute_callback_flags(
246 cb,
247 CallbackFlags::QEMU_PLUGIN_CB_NO_REGS,
248 cond,
249 entry,
250 immediate,
251 )
252 }
253
254 #[cfg(not(any(
266 feature = "plugin-api-v0",
267 feature = "plugin-api-v1",
268 feature = "plugin-api-v2"
269 )))]
270 pub fn register_conditional_execute_callback_flags<F>(
271 &self,
272 cb: F,
273 flags: CallbackFlags,
274 cond: PluginCondition,
275 entry: PluginU64,
276 immediate: u64,
277 ) where
278 F: FnMut(VCPUIndex) + Send + Sync + 'static,
279 {
280 let callback = Box::new(cb);
281 let callback_box = Box::new(callback);
282 let userdata = Box::into_raw(callback_box) as *mut c_void;
283
284 unsafe {
285 crate::sys::qemu_plugin_register_vcpu_insn_exec_cond_cb(
286 self.instruction as *mut qemu_plugin_insn,
287 Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
288 flags,
289 cond,
290 entry,
291 immediate,
292 userdata,
293 )
294 };
295 }
296
297 pub fn register_memory_access_callback<F>(&self, cb: F, rw: MemRW)
304 where
305 F: for<'b> FnMut(VCPUIndex, MemoryInfo<'b>, u64) + Send + Sync + 'static,
306 {
307 self.register_memory_access_callback_flags(cb, rw, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
308 }
309
310 pub fn register_memory_access_callback_flags<F>(&self, cb: F, rw: MemRW, flags: CallbackFlags)
317 where
318 F: for<'b> FnMut(VCPUIndex, MemoryInfo<'b>, u64) + Send + Sync + 'static,
319 {
320 let callback = Box::new(cb);
321 let callback_box = Box::new(callback);
322 let userdata = Box::into_raw(callback_box) as *mut c_void;
323
324 unsafe {
325 crate::sys::qemu_plugin_register_vcpu_mem_cb(
326 self.instruction as *mut qemu_plugin_insn,
327 Some(handle_qemu_plugin_register_vcpu_mem_cb::<F>),
328 flags,
329 rw,
330 userdata,
331 )
332 };
333 }
334}