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