qemu_plugin/
lib.rs

1//! High level idiomatic Rust bindings to the QEMU plugin API
2//!
3//! `qemu-plugin` makes it easy to write QEMU plugins in Rust.
4//!
5//! # Example
6//!
7//! Below is a minimal plugin example for a plugin which prints the execution trace of the
8//! program running in QEMU. Notice that all we do is register a struct which implements
9//! `Plugin`, and the library takes care of the rest.
10//!
11//! ```rust,ignore
12//! use anyhow::Result;
13//! use ctor::ctor;
14//! use qemu_plugin::{
15//!     plugin::{HasCallbacks, Plugin, Register, PLUGIN},
16//!     PluginId, TranslationBlock,
17//! };
18//! use std::sync::Mutex;
19//!
20//! struct TinyTrace {}
21//!
22//! impl Register for TinyTrace {}
23//!
24//! impl HasCallbacks for TinyTrace {
25//!     fn on_translation_block_translate(
26//!         &mut self,
27//!         _id: PluginId,
28//!         tb: TranslationBlock,
29//!     ) -> Result<()> {
30//!         tb.instructions().enumerate().try_for_each(|(idx, insn)| {
31//!             if idx == 0 {
32//!                 println!("====TB: {:08x}", insn.vaddr());
33//!             }
34//!
35//!             println!("{:08x}: {}", insn.vaddr(), insn.disas()?);
36//!             Ok::<(), anyhow::Error>(())
37//!         })?;
38//!
39//!         Ok(())
40//!     }
41//! }
42//!
43//! impl Plugin for TinyTrace {}
44//!
45//! #[ctor]
46//! fn init() {
47//!     PLUGIN
48//!         .set(Mutex::new(Box::new(TinyTrace {})))
49//!         .map_err(|_| anyhow::anyhow!("Failed to set plugin"))
50//!         .expect("Failed to set plugin");
51//! }
52//! ```
53//!
54//! The above `src/lib.rs` in a Cargo project with the following `Cargo.toml` will compile to
55//! `libtiny.so`, which can be loaded in QEMU by running `qemu-system-ARCH -plugin ./libtiny.so`.
56//!
57//! ```toml
58//! [package]
59//! name = "tiny"
60//! version = "0.1.0"
61//! edition = "2021"
62//!
63//! [lib]
64//! crate-type = ["cdylib"]
65//!
66//! [dependencies]
67//! qemu-plugin = "9.0.0-v0"
68//! anyhow = "1.0.75"
69//! ffi = "0.1.0"
70//! ctor = "0.2.6"
71//! ```
72
73#![deny(missing_docs)]
74#![cfg_attr(all(unix, feature = "unix-weak-link"), feature(linkage))]
75#![cfg_attr(feature = "num-traits", feature(generic_const_exprs))]
76
77#[cfg(all(unix, feature = "unix-weak-link"))]
78mod unix_weak_link;
79
80#[cfg(windows)]
81mod win_link_hook;
82
83use crate::error::{Error, Result};
84#[cfg(feature = "num-traits")]
85use num_traits::{FromBytes, PrimInt};
86#[cfg(feature = "plugin-api-v3")]
87use qemu_plugin_sys::qemu_plugin_cond;
88use qemu_plugin_sys::{
89    qemu_plugin_cb_flags, qemu_plugin_hwaddr, qemu_plugin_id_t, qemu_plugin_insn,
90    qemu_plugin_mem_rw, qemu_plugin_meminfo_t, qemu_plugin_op, qemu_plugin_simple_cb_t,
91    qemu_plugin_tb, qemu_plugin_vcpu_simple_cb_t, qemu_plugin_vcpu_syscall_cb_t,
92    qemu_plugin_vcpu_syscall_ret_cb_t, qemu_plugin_vcpu_tb_trans_cb_t,
93};
94#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
95use qemu_plugin_sys::{
96    qemu_plugin_read_register, qemu_plugin_reg_descriptor, qemu_plugin_register,
97    qemu_plugin_scoreboard, qemu_plugin_u64, GArray, GByteArray,
98};
99use std::{
100    ffi::{c_uint, c_void, CStr, CString},
101    marker::PhantomData,
102    path::PathBuf,
103    sync::{Mutex, OnceLock},
104};
105#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
106use std::{
107    fmt::{Debug, Formatter},
108    mem::MaybeUninit,
109};
110
111pub mod error;
112pub mod install;
113pub mod plugin;
114pub mod sys;
115pub mod version;
116
117#[cfg(not(windows))]
118extern "C" {
119    /// glib g_free is provided by the QEMU program we are being linked into
120    fn g_free(mem: *mut c_void);
121}
122
123#[cfg(all(
124    not(windows),
125    any(feature = "plugin-api-v2", feature = "plugin-api-v3")
126))]
127extern "C" {
128    /// glib g_byte_array_new is provided by the QEMU program we are being linked into
129    fn g_byte_array_new() -> *mut GByteArray;
130    /// glib g_byte_array_free is provided by the QEMU program we are being linked into
131    fn g_byte_array_free(array: *mut GByteArray, free_segment: bool) -> *mut u8;
132    /// glib g_array_free is provided byt he QEMU program we are being linked into
133    fn g_array_free(array: *mut GArray, free_segment: bool) -> *mut u8;
134}
135
136#[cfg(windows)]
137lazy_static::lazy_static! {
138    static ref G_FREE : libloading::os::windows::Symbol<unsafe extern fn(*mut c_void)> = {
139        let lib =
140            libloading::os::windows::Library::open_already_loaded("libglib-2.0-0.dll")
141                .expect("libglib-2.0-0.dll should already be loaded");
142        // SAFETY
143        // "Users of `Library::get` should specify the correct type of the function loaded".
144        // We are specifying the correct type of g_free above (`void g_free(void*)`)
145        unsafe{lib.get(b"g_free").expect("find g_free")}
146    };
147}
148
149#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
150lazy_static::lazy_static! {
151    static ref G_BYTE_ARRAY_NEW: libloading::os::windows::Symbol<unsafe extern fn() -> *mut GByteArray> = {
152        let lib =
153            libloading::os::windows::Library::open_already_loaded("libglib-2.0-0.dll")
154                .expect("libglib-2.0-0.dll should already be loaded");
155        // SAFETY
156        // "Users of `Library::get` should specify the correct type of the function loaded".
157        // We are specifying the correct type of g_free above (`void g_free(void*)`)
158        unsafe{lib.get(b"g_byte_array_new").expect("find g_byte_array_new")}
159    };
160}
161
162#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
163lazy_static::lazy_static! {
164    static ref G_BYTE_ARRAY_FREE: libloading::os::windows::Symbol<unsafe extern fn(*mut c_void, bool) -> *mut u8> = {
165        let lib =
166            libloading::os::windows::Library::open_already_loaded("libglib-2.0-0.dll")
167                .expect("libglib-2.0-0.dll should already be loaded");
168        // SAFETY
169        // "Users of `Library::get` should specify the correct type of the function loaded".
170        // We are specifying the correct type of g_free above (`void g_free(void*)`)
171        unsafe{lib.get(b"g_byte_array_free").expect("find g_byte_array_free")}
172    };
173}
174
175#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
176lazy_static::lazy_static! {
177    static ref G_ARRAY_FREE: libloading::os::windows::Symbol<unsafe extern fn(*mut c_void, bool) -> *mut u8> = {
178        let lib =
179            libloading::os::windows::Library::open_already_loaded("libglib-2.0-0.dll")
180                .expect("libglib-2.0-0.dll should already be loaded");
181        // SAFETY
182        // "Users of `Library::get` should specify the correct type of the function loaded".
183        // We are specifying the correct type of g_free above (`void g_free(void*)`)
184        unsafe{lib.get(b"g_array_free").expect("find g_array_free")}
185    };
186}
187
188#[cfg(windows)]
189/// Define g_free, because on Windows we cannot delay link it
190///
191/// # Safety
192///
193/// `g_free` must *only* be used to deallocate values allocated with `g_malloc`, regardless of
194/// its documented guarantees about wrapping the system allocator. QEMU plugin APIs which return
195/// such values are documented to do so, and it is safe to call `g_free` on these values
196/// provided they are not used afterward.
197unsafe fn g_free(mem: *mut c_void) {
198    unsafe { G_FREE(mem) }
199}
200
201#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
202/// Define g_byte_array_new, because on Windows we cannot delay link it
203///
204/// # Safety
205///
206/// `g_byte_array_new` must be used to allocate a new `GByteArray` which can be used to store
207/// arbitrary data. The returned `GByteArray` must be freed with `g_byte_array_free` when it is
208/// no longer needed.
209unsafe fn g_byte_array_new() -> *mut GByteArray {
210    unsafe { G_BYTE_ARRAY_NEW() }
211}
212
213#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
214/// Define g_byte_array_free, because on Windows we cannot delay link it
215///
216/// # Safety
217///
218/// `g_byte_array_free` must be used to free a `GByteArray` allocated with `g_byte_array_new`.
219/// The `free_segment` argument should be `true` if the data stored in the `GByteArray` should
220/// also be freed. If `false`, the data will not be freed, and the caller is responsible for
221/// freeing it with `g_free`.
222unsafe fn g_byte_array_free(array: *mut GByteArray, free_segment: bool) -> *mut u8 {
223    unsafe { G_BYTE_ARRAY_FREE(array as *mut c_void, free_segment) }
224}
225
226#[cfg(all(windows, any(feature = "plugin-api-v2", feature = "plugin-api-v3")))]
227/// Define g_array_free, because on Windows we cannot delay link it
228///
229/// # Safety
230///
231/// `g_array_free` must be used to free a `GArray` allocated with `g_array_new`. The `free_segment`
232/// argument should be `true` if the data stored in the `GArray` should also be freed. If `false`,
233/// the data will not be freed, and the caller is responsible for freeing it with `g_free`.
234unsafe fn g_array_free(array: *mut GArray, free_segment: bool) -> *mut u8 {
235    unsafe { G_ARRAY_FREE(array as *mut c_void, free_segment) }
236}
237
238/// The index of a vCPU
239pub type VCPUIndex = c_uint;
240#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
241/// u64 member of an entry in a scoreboard, allows access to a specific u64 member in
242/// one given entry, located at a specified offset. Inline operations expect this as an
243/// entry.
244pub type PluginU64 = qemu_plugin_u64;
245/// Flags for callbacks
246pub type CallbackFlags = qemu_plugin_cb_flags;
247/// Memory read/write flags
248pub type MemRW = qemu_plugin_mem_rw;
249#[cfg(any(feature = "plugin-api-v3"))]
250/// A condition for a callback to be run
251pub type PluginCondition = qemu_plugin_cond;
252/// Plugin operations for inline operations
253pub type PluginOp = qemu_plugin_op;
254/// A plugin ID
255pub type PluginId = qemu_plugin_id_t;
256
257/// A callback that can be called many times, each time a vCPU is initialized
258///
259/// # Arguments
260///
261/// - `id`: The plugin ID
262/// - `vcpu_index`: The index of the vCPU that was initialized
263pub type VCPUInitCallback = qemu_plugin_vcpu_simple_cb_t;
264
265/// A callback that can be called many times, each time a vCPU exits
266///
267/// # Arguments
268///
269/// - `id`: The plugin ID
270/// - `vcpu_index`: The index of the vCPU that exited
271pub type VCPUExitCallback = qemu_plugin_vcpu_simple_cb_t;
272
273/// A callback that can be called many times, each time a vCPU idles
274///
275/// # Arguments
276///
277/// - `id`: The plugin ID
278/// - `vcpu_index`: The index of the vCPU that idled
279pub type VCPUIdleCallback = qemu_plugin_vcpu_simple_cb_t;
280
281/// A callback that can be called many times, each time a vCPU is resumed
282///
283/// # Arguments
284///
285/// - `id`: The plugin ID
286/// - `vcpu_index`: The index of the vCPU that resumed
287pub type VCPUResumeCallback = qemu_plugin_vcpu_simple_cb_t;
288
289/// A callback that can be called many times, each time a translation occurs.  The
290/// callback is passed an opaque `qemu_plugin_tb` pointer, which can be queried for
291/// additional information including the list of translated instructions.  The callback
292/// can register further callbacks to be triggered when the block or individual
293/// instructions execute.
294///
295/// # Arguments
296///
297/// - `id`: The plugin ID
298/// - `tb`: The translated block
299pub type VCPUTranslationBlockTranslationCallback = qemu_plugin_vcpu_tb_trans_cb_t;
300
301/// A callback called on flush.
302///
303/// # Arguments
304///
305/// - `id`: The plugin ID
306pub type FlushCallback = qemu_plugin_simple_cb_t;
307
308/// A callback called on Syscall entry
309///
310/// # Arguments
311///
312/// - `id`: The plugin ID
313/// - `vcpu_index`: The index of the vCPU that executed the instruction
314/// - `num`: The syscall number
315/// - `a1`: The first syscall argument
316/// - `a2`: The second syscall argument
317/// - `a3`: The third syscall argument
318/// - `a4`: The fourth syscall argument
319/// - `a5`: The fifth syscall argument
320/// - `a6`: The sixth syscall argument
321/// - `a7`: The seventh syscall argument
322/// - `a8`: The eighth syscall argument
323pub type SyscallCallback = qemu_plugin_vcpu_syscall_cb_t;
324
325/// A callback called on Syscall return
326///
327/// # Arguments
328///
329/// - `id`: The plugin ID
330/// - `vcpu_index`: The index of the vCPU that executed the instruction
331/// - `num`: The syscall number
332/// - `ret`: The syscall return value
333pub type SyscallReturnCallback = qemu_plugin_vcpu_syscall_ret_cb_t;
334
335/// Wrapper structure for a `qemu_plugin_tb *`
336///
337/// # Safety
338///
339/// This structure is safe to use as long as the pointer is valid. The pointer is
340/// always opaque, and therefore may not be dereferenced.
341pub struct TranslationBlock<'a> {
342    translation_block: usize,
343    marker: PhantomData<&'a ()>,
344}
345
346impl<'a> From<*mut qemu_plugin_tb> for TranslationBlock<'a> {
347    fn from(tb: *mut qemu_plugin_tb) -> Self {
348        Self {
349            translation_block: tb as usize,
350            marker: PhantomData,
351        }
352    }
353}
354
355impl<'a> TranslationBlock<'a> {
356    /// Returns the number of instructions in the translation block
357    pub fn size(&self) -> usize {
358        unsafe { crate::sys::qemu_plugin_tb_n_insns(self.translation_block as *mut qemu_plugin_tb) }
359    }
360
361    /// Returns the virtual address for the start of a translation block
362    pub fn vaddr(&self) -> u64 {
363        unsafe { crate::sys::qemu_plugin_tb_vaddr(self.translation_block as *mut qemu_plugin_tb) }
364    }
365
366    /// Returns the instruction in the translation block at `index`. If the index is out of bounds,
367    /// an error is returned.
368    ///
369    /// # Arguments
370    ///
371    /// - `index`: The index of the instruction to return
372    pub fn instruction(&'a self, index: usize) -> Result<Instruction<'a>> {
373        let size = self.size();
374
375        if index >= size {
376            Err(Error::InvalidInstructionIndex { index, size })
377        } else {
378            Ok(Instruction::new(self, unsafe {
379                crate::sys::qemu_plugin_tb_get_insn(
380                    self.translation_block as *mut qemu_plugin_tb,
381                    index,
382                )
383            }))
384        }
385    }
386
387    /// Returns an iterator over the instructions in the translation block
388    pub fn instructions(&'a self) -> TranslationBlockIterator<'a> {
389        TranslationBlockIterator { tb: self, index: 0 }
390    }
391
392    /// Register a callback to be run on execution of this translation block
393    pub fn register_execute_callback<F>(&self, cb: F)
394    where
395        F: FnMut(VCPUIndex) + Send + Sync + 'static,
396    {
397        self.register_execute_callback_flags(cb, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS);
398    }
399
400    /// Register a callback to be run on execution of this translation block
401    pub fn register_execute_callback_flags<F>(&self, cb: F, flags: CallbackFlags)
402    where
403        F: FnMut(VCPUIndex) + Send + Sync + 'static,
404    {
405        let callback = Box::new(cb);
406        let callback_box = Box::new(callback);
407        let userdata = Box::into_raw(callback_box) as *mut c_void;
408
409        unsafe {
410            crate::sys::qemu_plugin_register_vcpu_tb_exec_cb(
411                self.translation_block as *mut qemu_plugin_tb,
412                Some(handle_qemu_plugin_register_vcpu_tb_exec_cb::<F>),
413                flags,
414                userdata,
415            )
416        };
417    }
418
419    #[cfg(feature = "plugin-api-v3")]
420    /// Register a callback to be conditionally run on execution of this translation
421    /// block
422    pub fn register_conditional_execute_callback<F>(
423        &self,
424        cb: F,
425        cond: PluginCondition,
426        entry: PluginU64,
427        immediate: u64,
428    ) where
429        F: FnMut(VCPUIndex) + Send + Sync + 'static,
430    {
431        self.register_conditional_execute_callback_flags(
432            cb,
433            CallbackFlags::QEMU_PLUGIN_CB_NO_REGS,
434            cond,
435            entry,
436            immediate,
437        )
438    }
439
440    #[cfg(feature = "plugin-api-v3")]
441    /// Register a callback to be conditionally run on execution of this translation
442    /// block
443    pub fn register_conditional_execute_callback_flags<F>(
444        &self,
445        cb: F,
446        flags: CallbackFlags,
447        cond: PluginCondition,
448        entry: PluginU64,
449        immediate: u64,
450    ) where
451        F: FnMut(VCPUIndex) + Send + Sync + 'static,
452    {
453        let callback = Box::new(cb);
454        let callback_box = Box::new(callback);
455        let userdata = Box::into_raw(callback_box) as *mut c_void;
456
457        unsafe {
458            crate::sys::qemu_plugin_register_vcpu_tb_exec_cond_cb(
459                self.translation_block as *mut qemu_plugin_tb,
460                Some(handle_qemu_plugin_register_vcpu_tb_exec_cb::<F>),
461                flags,
462                cond,
463                entry,
464                immediate,
465                userdata,
466            )
467        };
468    }
469}
470
471/// An iterator over the instructions of a translation block
472pub struct TranslationBlockIterator<'a> {
473    tb: &'a TranslationBlock<'a>,
474    index: usize,
475}
476
477impl<'a> Iterator for TranslationBlockIterator<'a> {
478    type Item = Instruction<'a>;
479
480    fn next(&mut self) -> Option<Self::Item> {
481        let size = self.tb.size();
482
483        if self.index >= size {
484            None
485        } else {
486            let insn = self.tb.instruction(self.index).ok();
487            self.index += 1;
488            insn
489        }
490    }
491}
492
493/// Wrapper structure for a `qemu_plugin_insn *`
494///
495/// # Safety
496///
497/// This structure is safe to use as long as the pointer is valid. The pointer is
498/// always opaque, and therefore may not be dereferenced.
499pub struct Instruction<'a> {
500    #[allow(unused)]
501    // NOTE: This field may be useful in the future
502    translation_block: &'a TranslationBlock<'a>,
503    instruction: usize,
504    marker: PhantomData<&'a ()>,
505}
506
507impl<'a> Instruction<'a> {
508    fn new(translation_block: &'a TranslationBlock<'a>, insn: *mut qemu_plugin_insn) -> Self {
509        Self {
510            translation_block,
511            instruction: insn as usize,
512            marker: PhantomData,
513        }
514    }
515}
516
517impl<'a> Instruction<'a> {
518    #[cfg(any(feature = "plugin-api-v1", feature = "plugin-api-v2"))]
519    /// Returns the data for this instruction. This method may only be called inside the
520    /// callback in which the instruction is obtained, but the resulting data is owned.
521    pub fn data(&self) -> Vec<u8> {
522        let size = self.size();
523        let mut data = Vec::with_capacity(size);
524
525        // NOTE: The name of this API doesn't change, but its parameters and return value *do*
526        let insn_data =
527            unsafe { crate::sys::qemu_plugin_insn_data(self.instruction as *mut qemu_plugin_insn) }
528                as *mut u8;
529
530        unsafe {
531            data.set_len(size);
532            std::ptr::copy_nonoverlapping(insn_data, data.as_mut_ptr(), size);
533        }
534
535        data
536    }
537
538    #[cfg(feature = "plugin-api-v3")]
539    /// Returns the data for this instruction. This method may only be called inside the
540    /// callback in which the instruction is obtained, but the resulting data is owned.
541    pub fn data(&self) -> Vec<u8> {
542        let size = self.size();
543        let mut data = vec![0; size];
544
545        // NOTE: The name of this API doesn't change, but its parameters and return value *do*
546        let size = unsafe {
547            crate::sys::qemu_plugin_insn_data(
548                self.instruction as *mut qemu_plugin_insn,
549                data.as_mut_ptr() as *mut _,
550                data.len(),
551            )
552        };
553
554        data.truncate(size);
555
556        data
557    }
558
559    /// Returns the size of the data for this instruction
560    pub fn size(&self) -> usize {
561        unsafe { crate::sys::qemu_plugin_insn_size(self.instruction as *mut qemu_plugin_insn) }
562    }
563
564    /// Returns the virtual address of this instruction
565    pub fn vaddr(&self) -> u64 {
566        unsafe { crate::sys::qemu_plugin_insn_vaddr(self.instruction as *mut qemu_plugin_insn) }
567    }
568
569    /// Returns the hardware (physical) address of this instruction
570    pub fn haddr(&self) -> u64 {
571        (unsafe { crate::sys::qemu_plugin_insn_haddr(self.instruction as *mut qemu_plugin_insn) })
572            as usize as u64
573    }
574
575    /// Returns the textual disassembly of this instruction
576    pub fn disas(&self) -> Result<String> {
577        let disas = unsafe {
578            crate::sys::qemu_plugin_insn_disas(self.instruction as *mut qemu_plugin_insn)
579        };
580        if disas.is_null() {
581            Err(Error::NoDisassemblyString)
582        } else {
583            let disas_string = unsafe { CStr::from_ptr(disas) }.to_str()?.to_string();
584
585            // NOTE: The string is allocated, so we free it
586            unsafe { g_free(disas as *mut _) };
587
588            Ok(disas_string)
589        }
590    }
591
592    /// Returns the symbol associated with this instruction, if one exists and the
593    /// binary contains a symbol table
594    pub fn symbol(&self) -> Result<Option<String>> {
595        let symbol = unsafe {
596            crate::sys::qemu_plugin_insn_symbol(self.instruction as *mut qemu_plugin_insn)
597        };
598        if symbol.is_null() {
599            Ok(None)
600        } else {
601            let symbol_string = unsafe { CStr::from_ptr(symbol) }.to_str()?.to_string();
602            // NOTE: The string is static, so we do not free it
603            Ok(Some(symbol_string))
604        }
605    }
606
607    /// Register a callback to be run on execution of this instruction
608    pub fn register_execute_callback<F>(&self, cb: F)
609    where
610        F: FnMut(VCPUIndex) + Send + Sync + 'static,
611    {
612        self.register_execute_callback_flags(cb, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
613    }
614
615    /// Register a callback to be run on execution of this instruction
616    pub fn register_execute_callback_flags<F>(&self, cb: F, flags: CallbackFlags)
617    where
618        F: FnMut(VCPUIndex) + Send + Sync + 'static,
619    {
620        let callback = Box::new(cb);
621        let callback_box = Box::new(callback);
622        let userdata = Box::into_raw(callback_box) as *mut c_void;
623
624        unsafe {
625            crate::sys::qemu_plugin_register_vcpu_insn_exec_cb(
626                self.instruction as *mut qemu_plugin_insn,
627                Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
628                flags,
629                userdata,
630            )
631        };
632    }
633
634    /// Register a callback to be conditionally run on execution of this instruction
635    #[cfg(feature = "plugin-api-v3")]
636    pub fn register_conditional_execute_callback<F>(
637        &self,
638        cb: F,
639        cond: PluginCondition,
640        entry: PluginU64,
641        immediate: u64,
642    ) where
643        F: FnMut(VCPUIndex) + Send + Sync + 'static,
644    {
645        self.register_conditional_execute_callback_flags(
646            cb,
647            CallbackFlags::QEMU_PLUGIN_CB_NO_REGS,
648            cond,
649            entry,
650            immediate,
651        )
652    }
653
654    /// Register a callback to be conditionally run on execution of this instruction
655    #[cfg(feature = "plugin-api-v3")]
656    pub fn register_conditional_execute_callback_flags<F>(
657        &self,
658        cb: F,
659        flags: CallbackFlags,
660        cond: PluginCondition,
661        entry: PluginU64,
662        immediate: u64,
663    ) where
664        F: FnMut(VCPUIndex) + Send + Sync + 'static,
665    {
666        let callback = Box::new(cb);
667        let callback_box = Box::new(callback);
668        let userdata = Box::into_raw(callback_box) as *mut c_void;
669
670        unsafe {
671            crate::sys::qemu_plugin_register_vcpu_insn_exec_cond_cb(
672                self.instruction as *mut qemu_plugin_insn,
673                Some(handle_qemu_plugin_register_vcpu_insn_exec_cb::<F>),
674                flags,
675                cond,
676                entry,
677                immediate,
678                userdata,
679            )
680        };
681    }
682
683    /// Register a callback to be run on memory access of this instruction
684    ///
685    /// # Arguments
686    ///
687    /// - `cb`: The callback to be run
688    /// - `rw`: The type of memory access to trigger the callback on
689    pub fn register_memory_access_callback<F>(&self, cb: F, rw: MemRW)
690    where
691        F: FnMut(VCPUIndex, MemoryInfo, u64) + Send + Sync + 'static,
692    {
693        self.register_memory_access_callback_flags(cb, rw, CallbackFlags::QEMU_PLUGIN_CB_NO_REGS)
694    }
695
696    /// Register a callback to be run on memory access of this instruction
697    ///
698    /// # Arguments
699    ///
700    /// - `cb`: The callback to be run
701    /// - `rw`: The type of memory access to trigger the callback on
702    pub fn register_memory_access_callback_flags<F>(&self, cb: F, rw: MemRW, flags: CallbackFlags)
703    where
704        F: FnMut(VCPUIndex, MemoryInfo, u64) + Send + Sync + 'static,
705    {
706        let callback = Box::new(cb);
707        let callback_box = Box::new(callback);
708        let userdata = Box::into_raw(callback_box) as *mut c_void;
709
710        unsafe {
711            crate::sys::qemu_plugin_register_vcpu_mem_cb(
712                self.instruction as *mut qemu_plugin_insn,
713                Some(handle_qemu_plugin_register_vcpu_mem_cb::<F>),
714                flags,
715                rw,
716                userdata,
717            )
718        };
719    }
720}
721
722/// Wrapper structure for a `qemu_plugin_meminfo_t`
723///
724/// # Safety
725///
726/// This structure is safe to use during the invocation of the callback which receives it as an
727/// argument. The structure is always opaque, and therefore may not be accessed directly.
728pub struct MemoryInfo<'a> {
729    memory_info: qemu_plugin_meminfo_t,
730    marker: PhantomData<&'a ()>,
731}
732
733impl<'a> From<qemu_plugin_meminfo_t> for MemoryInfo<'a> {
734    fn from(info: qemu_plugin_meminfo_t) -> Self {
735        Self {
736            memory_info: info,
737            marker: PhantomData,
738        }
739    }
740}
741
742impl<'a> MemoryInfo<'a> {
743    /// Returns the size of the access in base-2, e.g. 0 for byte, 1 for 16-bit, 2 for
744    /// 32-bit, etc.
745    pub fn size_shift(&self) -> usize {
746        (unsafe { crate::sys::qemu_plugin_mem_size_shift(self.memory_info) }) as usize
747    }
748
749    /// Returns whether the access was sign extended
750    pub fn sign_extended(&self) -> bool {
751        unsafe { crate::sys::qemu_plugin_mem_is_sign_extended(self.memory_info) }
752    }
753
754    /// Returns whether the access was big-endian
755    pub fn big_endian(&self) -> bool {
756        unsafe { crate::sys::qemu_plugin_mem_is_big_endian(self.memory_info) }
757    }
758
759    /// Returns whether the access was a store
760    pub fn is_store(&self) -> bool {
761        unsafe { crate::sys::qemu_plugin_mem_is_store(self.memory_info) }
762    }
763
764    /// Return a handle to query details about the physical address backing the virtual address
765    /// in system emulation. In user-mode, this method always returns `None`.
766    pub fn hwaddr(&self, vaddr: u64) -> Option<HwAddr> {
767        let hwaddr = unsafe { crate::sys::qemu_plugin_get_hwaddr(self.memory_info, vaddr) };
768        if hwaddr.is_null() {
769            None
770        } else {
771            Some(HwAddr::from(hwaddr))
772        }
773    }
774}
775
776#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
777#[derive(Clone)]
778/// Wrapper structure for a `qemu_plugin_register_descriptor`
779///
780/// # Safety
781///
782/// This structure is safe to use as long as the pointer is valid. The pointer is
783/// always opaque, and therefore may not be dereferenced.
784pub struct RegisterDescriptor<'a> {
785    /// Opaque handle to the register for retrieving the value with
786    /// qemu_plugin_read_register
787    handle: usize,
788    /// The register name
789    pub name: String,
790    /// Optional feature descriptor
791    pub feature: Option<String>,
792    marker: PhantomData<&'a ()>,
793}
794
795#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
796impl<'a> From<qemu_plugin_reg_descriptor> for RegisterDescriptor<'a> {
797    fn from(descriptor: qemu_plugin_reg_descriptor) -> Self {
798        let name = unsafe { CStr::from_ptr(descriptor.name) }
799            .to_str()
800            .expect("Register name is not valid UTF-8")
801            .to_string();
802
803        let feature = if descriptor.feature.is_null() {
804            None
805        } else {
806            Some(
807                unsafe { CStr::from_ptr(descriptor.feature) }
808                    .to_str()
809                    .expect("Register feature is not valid UTF-8")
810                    .to_string(),
811            )
812        };
813
814        Self {
815            handle: descriptor.handle as usize,
816            name,
817            feature,
818            marker: PhantomData,
819        }
820    }
821}
822
823#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
824impl<'a> Debug for RegisterDescriptor<'a> {
825    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
826        f.debug_struct("RegisterDescriptor")
827            .field("name", &self.name)
828            .field("feature", &self.feature)
829            .finish()
830    }
831}
832
833#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
834impl<'a> RegisterDescriptor<'a> {
835    /// Read a register value
836    ///
837    /// This must only be called in a callback which has been registered with
838    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
839    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`.
840    pub fn read(&self) -> Result<Vec<u8>> {
841        let byte_array = unsafe { g_byte_array_new() };
842
843        let result = unsafe {
844            qemu_plugin_read_register(self.handle as *mut qemu_plugin_register, byte_array)
845        };
846
847        if result == -1 {
848            return Err(Error::RegisterReadError {
849                name: self.name.clone(),
850            });
851        }
852
853        let mut data = Vec::new();
854        data.extend_from_slice(unsafe {
855            std::slice::from_raw_parts((*byte_array).data, (*byte_array).len as usize)
856        });
857
858        assert_eq!(
859            unsafe { g_byte_array_free(byte_array, true) },
860            std::ptr::null_mut(),
861            "g_byte_array_free must return NULL"
862        );
863
864        Ok(data)
865    }
866
867    #[cfg(feature = "num-traits")]
868    /// Read a register value into a numeric type in big-endian byte order
869    ///
870    /// This must only be called in a callback which has been registered with
871    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
872    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`.
873    pub fn read_be<T>(&self) -> Result<T>
874    where
875        T: PrimInt + FromBytes + Sized,
876        T: FromBytes<Bytes = [u8; std::mem::size_of::<T>()]>,
877    {
878        let data = self.read()?;
879        let mut bytes = [0; std::mem::size_of::<T>()];
880        bytes.copy_from_slice(&data);
881        Ok(T::from_be_bytes(&bytes))
882    }
883
884    #[cfg(feature = "num-traits")]
885    /// Read a register value into a numeric type in little-endian byte order
886    ///
887    /// This must only be called in a callback which has been registered with
888    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
889    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`.
890    pub fn read_le<T>(&self) -> Result<T>
891    where
892        T: PrimInt + FromBytes + Sized,
893        T: FromBytes<Bytes = [u8; std::mem::size_of::<T>()]>,
894    {
895        let data = self.read()?;
896        let mut bytes = [0; std::mem::size_of::<T>()];
897        bytes.copy_from_slice(&data);
898        Ok(T::from_le_bytes(&bytes))
899    }
900}
901
902/// Wrapper structure for a `qemu_plugin_hwaddr *`
903///
904/// # Safety
905///
906/// This structure is safe to use as long as the pointer is valid. The pointer is
907/// always opaque, and therefore may not be dereferenced.
908pub struct HwAddr<'a> {
909    hwaddr: usize,
910    marker: PhantomData<&'a ()>,
911}
912
913impl<'a> From<*mut qemu_plugin_hwaddr> for HwAddr<'a> {
914    fn from(hwaddr: *mut qemu_plugin_hwaddr) -> Self {
915        Self {
916            hwaddr: hwaddr as usize,
917            marker: PhantomData,
918        }
919    }
920}
921
922impl<'a> HwAddr<'a> {
923    /// Returns whether the memory operation is to MMIO. Returns false if the operation is to
924    /// RAM.
925    pub fn is_io(&self) -> bool {
926        unsafe { crate::sys::qemu_plugin_hwaddr_is_io(self.hwaddr as *mut qemu_plugin_hwaddr) }
927    }
928
929    /// Returns the physical address for the memory operation
930    pub fn hwaddr(&self) -> u64 {
931        unsafe { crate::sys::qemu_plugin_hwaddr_phys_addr(self.hwaddr as *mut qemu_plugin_hwaddr) }
932    }
933
934    /// Returns a string representing the device
935    pub fn device_name(&self) -> Result<Option<String>> {
936        let device_name = unsafe {
937            crate::sys::qemu_plugin_hwaddr_device_name(self.hwaddr as *mut qemu_plugin_hwaddr)
938        };
939
940        if device_name.is_null() {
941            Ok(None)
942        } else {
943            let device_name_string = unsafe { CStr::from_ptr(device_name) }.to_str()?.to_string();
944            // NOTE: The string is static, so we do not free it
945            Ok(Some(device_name_string))
946        }
947    }
948}
949
950#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
951/// A wrapper structure for a `qemu_plugin_scoreboard *`. This is a way of having one
952/// entry per VCPU, the count of which is managed automatically by QEMU. Keep in mind
953/// that additional entries *and* existing entries will be allocated and reallocated by
954/// *qemu*, not by the plugin, so every use of a `T` should include a check for whether
955/// it is initialized.
956pub struct Scoreboard<'a, T>
957where
958    T: Sized,
959{
960    handle: usize,
961    marker: PhantomData<&'a T>,
962}
963
964#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
965impl<'a, T> Scoreboard<'a, T> {
966    /// Allocate a new scoreboard object. This must be freed by calling
967    /// `qemu_plugin_scoreboard_free` (or by being dropped).
968    pub fn new() -> Self {
969        let handle =
970            unsafe { crate::sys::qemu_plugin_scoreboard_new(std::mem::size_of::<T>()) as usize };
971
972        Self {
973            handle,
974            marker: PhantomData,
975        }
976    }
977
978    /// Returns a reference to entry of a scoreboard matching a given vcpu index. This address
979    /// is only valid until the next call to `get` or `set`.
980    pub fn find<'b>(&mut self, vcpu_index: VCPUIndex) -> &'b mut MaybeUninit<T> {
981        unsafe {
982            &mut *(crate::sys::qemu_plugin_scoreboard_find(
983                self.handle as *mut qemu_plugin_scoreboard,
984                vcpu_index,
985            ) as *mut MaybeUninit<T>)
986        }
987    }
988}
989
990#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
991impl<'a, T> Default for Scoreboard<'a, T> {
992    fn default() -> Self {
993        Self::new()
994    }
995}
996
997#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
998impl<'a, T> Drop for Scoreboard<'a, T> {
999    fn drop(&mut self) {
1000        unsafe {
1001            crate::sys::qemu_plugin_scoreboard_free(self.handle as *mut qemu_plugin_scoreboard)
1002        }
1003    }
1004}
1005
1006// NOTE: Box<Box< is not strictly necessary here because the pointer is never sent via
1007// FFI which means we never downcast to an 8-byte pointer from fat, but it is best not
1008// to rely on that.
1009
1010#[allow(clippy::type_complexity)]
1011/// A callback which will run once removal and uninstallation of the plugin is finalized. This callback
1012/// can only be set once, by calling the `qemu_plugin_uninstall` function.
1013static UNINSTALL_CALLBACK: OnceLock<
1014    Mutex<Option<Box<Box<dyn FnOnce(qemu_plugin_id_t) + Send + Sync + 'static>>>>,
1015> = OnceLock::new();
1016#[allow(clippy::type_complexity)]
1017/// A callback which will run once the plugin is reset. This callback is set by calling the
1018/// `qemu_plugin_reset` function.
1019static RESET_CALLBACK: OnceLock<
1020    Mutex<Option<Box<Box<dyn FnOnce(qemu_plugin_id_t) + Send + Sync + 'static>>>>,
1021> = OnceLock::new();
1022
1023/// Handle the invocation of the uninstall callback by calling the stored
1024/// callback closure, if one exists.
1025extern "C" fn handle_qemu_plugin_uninstall_callback(id: qemu_plugin_id_t) {
1026    if let Some(callback) = UNINSTALL_CALLBACK.get() {
1027        if let Ok(mut callback) = callback.lock() {
1028            if let Some(callback) = callback.take() {
1029                callback(id);
1030            }
1031        }
1032    }
1033    // NOTE: An error here is ignored, and exceedingly fatal
1034}
1035
1036/// Handle the invocation of the reset callback by calling the stored
1037/// callback closure, if one exists.
1038extern "C" fn handle_qemu_plugin_reset_callback(id: qemu_plugin_id_t) {
1039    if let Some(callback) = UNINSTALL_CALLBACK.get() {
1040        if let Ok(mut callback) = callback.lock() {
1041            if let Some(callback) = callback.take() {
1042                callback(id);
1043            }
1044        }
1045    }
1046    // NOTE: An error here is ignored, and exceedingly fatal
1047}
1048
1049/// Uninstall a plugin.
1050///
1051/// # Arguments
1052///
1053/// - `id`: The plugin ID
1054/// - `cb`: A callback function that will be called when the plugin has been
1055///   uninstalled.
1056///
1057/// # Safety
1058///
1059/// Do NOT assume that the plugin has been uninstalled once this function returns.
1060/// Plugins are uninstalled asynchronously, and therefore the given plugin receives
1061/// callbacks until cb is called. This function must not be called from
1062/// `qemu_plugin_install`.
1063pub fn qemu_plugin_uninstall<F>(id: qemu_plugin_id_t, cb: F) -> Result<()>
1064where
1065    F: FnOnce(qemu_plugin_id_t) + Send + Sync + 'static,
1066{
1067    UNINSTALL_CALLBACK
1068        .set(Mutex::new(Some(Box::new(Box::new(cb)))))
1069        .map_err(|_| Error::ConcurrentPluginUninstallCallbackSet)?;
1070
1071    unsafe { crate::sys::qemu_plugin_uninstall(id, Some(handle_qemu_plugin_uninstall_callback)) };
1072
1073    Ok(())
1074}
1075
1076/// Reset a plugin
1077///
1078/// # Arguments
1079///
1080/// - `id`: The plugin ID
1081/// - `cb`: A callback function that will be called when the plugin has been reset.
1082///
1083/// # Safety
1084///
1085/// Do NOT assume that the plugin has been reset once this function returns. Plugins
1086/// are reset asynchronously, and therefore the given plugin receives callbacks until
1087/// cb is called.
1088pub fn qemu_plugin_reset<F>(id: qemu_plugin_id_t, cb: F) -> Result<()>
1089where
1090    F: FnOnce(qemu_plugin_id_t) + Send + Sync + 'static,
1091{
1092    if let Some(callback) = RESET_CALLBACK.get() {
1093        let Ok(mut callback) = callback.lock() else {
1094            return Err(Error::PluginResetCallbackState);
1095        };
1096        let _ = callback.replace(Box::new(Box::new(cb)));
1097    } else {
1098        RESET_CALLBACK
1099            .set(Mutex::new(Some(Box::new(Box::new(cb)))))
1100            .map_err(|_| Error::ConcurrentPluginResetCallbackSet)?;
1101    }
1102
1103    unsafe { crate::sys::qemu_plugin_reset(id, Some(handle_qemu_plugin_reset_callback)) };
1104
1105    Ok(())
1106}
1107
1108/// Register a callback to be called when a vCPU is initialized. The callback does not receive
1109/// user data, so it is not possible to register it via closure.
1110///
1111/// # Arguments
1112///
1113/// - `id`: The plugin ID
1114/// - `cb`: The callback to be called
1115pub fn qemu_plugin_register_vcpu_init_cb(id: qemu_plugin_id_t, cb: VCPUInitCallback) -> Result<()> {
1116    unsafe { crate::sys::qemu_plugin_register_vcpu_init_cb(id, cb) };
1117    Ok(())
1118}
1119
1120/// Register a callback to be called when a vCPU exits. The callback does not receive
1121/// user data, so it is not possible to register it via closure.
1122///
1123/// # Arguments
1124///
1125/// - `id`: The plugin ID
1126/// - `cb`: The callback to be called
1127pub fn qemu_plugin_register_vcpu_exit_cb(id: qemu_plugin_id_t, cb: VCPUExitCallback) -> Result<()> {
1128    unsafe { crate::sys::qemu_plugin_register_vcpu_exit_cb(id, cb) };
1129    Ok(())
1130}
1131
1132/// Register a callback to be called when a vCPU idles. The callback does not receive
1133/// user data, so it is not possible to register it via closure.
1134///
1135/// # Arguments
1136///
1137/// - `id`: The plugin ID
1138/// - `cb`: The callback to be called
1139pub fn qemu_plugin_register_vcpu_idle_cb(id: qemu_plugin_id_t, cb: VCPUIdleCallback) -> Result<()> {
1140    unsafe { crate::sys::qemu_plugin_register_vcpu_idle_cb(id, cb) };
1141    Ok(())
1142}
1143
1144/// Register a callback to be called when a vCPU resumes. The callback does not receive
1145/// user data, so it is not possible to register it via closure.
1146///
1147/// # Arguments
1148///
1149/// - `id`: The plugin ID
1150/// - `cb`: The callback to be called
1151pub fn qemu_plugin_register_vcpu_resume_cb(
1152    id: qemu_plugin_id_t,
1153    cb: VCPUResumeCallback,
1154) -> Result<()> {
1155    unsafe { crate::sys::qemu_plugin_register_vcpu_resume_cb(id, cb) };
1156    Ok(())
1157}
1158
1159/// Register a callback to be called when a translation block is translated. The callback
1160/// receives a pointer to a `qemu_plugin_tb` structure, which can be queried for additional
1161/// information including the list of translated instructions. The callback can register
1162/// further callbacks to be triggered when the block or individual instructions execute.
1163///
1164/// # Arguments
1165///
1166/// - `id`: The plugin ID
1167/// - `cb`: The callback to be called
1168pub fn qemu_plugin_register_vcpu_tb_trans_cb(
1169    id: qemu_plugin_id_t,
1170    cb: VCPUTranslationBlockTranslationCallback,
1171) -> Result<()> {
1172    unsafe { crate::sys::qemu_plugin_register_vcpu_tb_trans_cb(id, cb) };
1173    Ok(())
1174}
1175
1176extern "C" fn handle_qemu_plugin_register_vcpu_tb_exec_cb<F>(
1177    vcpu_index: VCPUIndex,
1178    userdata: *mut c_void,
1179) where
1180    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1181{
1182    let mut cb: Box<Box<F>> = unsafe { Box::from_raw(userdata as *mut _) };
1183    cb(vcpu_index);
1184    Box::leak(cb);
1185}
1186
1187#[allow(clippy::not_unsafe_ptr_arg_deref)]
1188/// Register a callback to be called when a translation block is executed.
1189///
1190/// # Arguments
1191///
1192/// - `tb`: The translated block to register the execution callback for
1193/// - `cb`: The callback to be called when the block `tb` is executed
1194///
1195/// # Safety
1196///
1197/// This function is safe when the pointer `tb` is a valid pointer to a `qemu_plugin_tb`
1198/// structure, which is always opaque.
1199pub fn qemu_plugin_register_vcpu_tb_exec_cb<F>(tb: TranslationBlock, cb: F, flags: CallbackFlags)
1200where
1201    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1202{
1203    tb.register_execute_callback_flags(cb, flags);
1204}
1205
1206#[cfg(feature = "plugin-api-v3")]
1207/// Register a callback to be conditionally called when a translation block is executed.
1208///
1209/// # Arguments
1210///
1211/// - `tb`: The translated block to register the execution callback for
1212/// - `cb`: The callback to be called when the block `tb` is executed
1213/// - `cond`: The condition to be met for the callback to be called
1214/// - `entry`: The entry to be passed to the callback
1215/// - `immediate`: The immediate value to be passed to the callback
1216///
1217/// # Safety
1218///
1219/// This function is safe when the pointer `tb` is a valid pointer to a `qemu_plugin_tb`
1220/// structure, which is always opaque.
1221pub fn qemu_plugin_register_vcpu_tb_exec_cond_cb<F>(
1222    tb: TranslationBlock,
1223    cb: F,
1224    flags: CallbackFlags,
1225    cond: PluginCondition,
1226    entry: PluginU64,
1227    immediate: u64,
1228) where
1229    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1230{
1231    tb.register_conditional_execute_callback_flags(cb, flags, cond, entry, immediate);
1232}
1233
1234#[cfg(feature = "plugin-api-v1")]
1235#[allow(clippy::not_unsafe_ptr_arg_deref)]
1236/// Register an inline callback to be called when a translation block is executed.
1237///
1238/// # Arguments
1239///
1240/// - `tb`: The translated block to register the execution callback for
1241/// - `op`: The operation to be performed
1242/// - `ptr`: The pointer to the data to be passed to the operation
1243/// - `imm`: The immediate value to be passed to the operation
1244pub fn qemu_plugin_register_vcpu_tb_exec_inline(
1245    tb: TranslationBlock,
1246    op: PluginOp,
1247    ptr: *mut c_void,
1248    imm: u64,
1249) {
1250    unsafe {
1251        crate::sys::qemu_plugin_register_vcpu_tb_exec_inline(
1252            tb.translation_block as *mut qemu_plugin_tb,
1253            op,
1254            ptr,
1255            imm,
1256        );
1257    }
1258}
1259
1260#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1261#[allow(clippy::not_unsafe_ptr_arg_deref)]
1262/// Register an inline callback to be called when a translation block is executed.
1263///
1264/// # Arguments
1265///
1266/// - `tb`: The translated block to register the execution callback for
1267/// - `op`: The operation to be performed
1268/// - `entry`: The entry to be passed to the operation
1269/// - `imm`: The immediate value to be passed to the operation
1270pub fn qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
1271    tb: TranslationBlock,
1272    op: PluginOp,
1273    entry: PluginU64,
1274    imm: u64,
1275) {
1276    unsafe {
1277        crate::sys::qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
1278            tb.translation_block as *mut qemu_plugin_tb,
1279            op,
1280            entry,
1281            imm,
1282        );
1283    }
1284}
1285
1286extern "C" fn handle_qemu_plugin_register_vcpu_insn_exec_cb<F>(
1287    vcpu_index: VCPUIndex,
1288    userdata: *mut c_void,
1289) where
1290    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1291{
1292    let mut cb: Box<Box<F>> = unsafe { Box::from_raw(userdata as *mut _) };
1293    cb(vcpu_index);
1294    // NOTE: This memory will be freed on plugin exit
1295    Box::leak(cb);
1296}
1297
1298#[allow(clippy::not_unsafe_ptr_arg_deref)]
1299/// Register a callback to be called when an instruction is executed.
1300///
1301/// # Arguments
1302///
1303/// - `insn`: The instruction handle to register the callback for
1304/// - `cb`: The callback to be called
1305pub fn qemu_plugin_register_vcpu_insn_exec_cb<F>(insn: Instruction, cb: F, flags: CallbackFlags)
1306where
1307    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1308{
1309    insn.register_execute_callback_flags(cb, flags);
1310}
1311
1312#[cfg(feature = "plugin-api-v3")]
1313#[allow(clippy::not_unsafe_ptr_arg_deref)]
1314/// Register a callback to be conditionally called when an instruction is executed.
1315///
1316/// # Arguments
1317///
1318/// - `insn`: The instruction handle to register the callback for
1319/// - `cb`: The callback to be called
1320/// - `cond`: The condition to be met for the callback to be called
1321/// - `entry`: The entry to be passed to the callback
1322/// - `immediate`: The immediate value to be passed to the callback
1323pub fn qemu_plugin_register_vcpu_insn_exec_cond_cb<F>(
1324    insn: Instruction,
1325    cb: F,
1326    flags: CallbackFlags,
1327    cond: PluginCondition,
1328    entry: PluginU64,
1329    immediate: u64,
1330) where
1331    F: FnMut(VCPUIndex) + Send + Sync + 'static,
1332{
1333    insn.register_conditional_execute_callback_flags(cb, flags, cond, entry, immediate);
1334}
1335
1336#[cfg(feature = "plugin-api-v1")]
1337#[allow(clippy::not_unsafe_ptr_arg_deref)]
1338/// Register an inline callback to be called when an instruction is executed.
1339///
1340/// # Arguments
1341///
1342/// - `insn`: The instruction handle to register the callback for
1343/// - `op`: The operation to be performed
1344/// - `ptr`: The pointer to the data to be passed to the operation
1345/// - `imm`: The immediate value to be passed to the operation
1346pub fn qemu_plugin_register_vcpu_insn_exec_inline(
1347    insn: Instruction,
1348    op: PluginOp,
1349    ptr: *mut c_void,
1350    imm: u64,
1351) {
1352    unsafe {
1353        crate::sys::qemu_plugin_register_vcpu_insn_exec_inline(
1354            insn.instruction as *mut qemu_plugin_insn,
1355            op,
1356            ptr,
1357            imm,
1358        );
1359    }
1360}
1361
1362#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1363#[allow(clippy::not_unsafe_ptr_arg_deref)]
1364/// Register an inline callback to be called when an instruction is executed.
1365///
1366/// # Arguments
1367///
1368/// - `insn`: The instruction handle to register the callback for
1369/// - `op`: The operation to be performed
1370/// - `entry`: The entry to be passed to the operation
1371/// - `imm`: The immediate value to be passed to the operation
1372pub fn qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
1373    insn: Instruction,
1374    op: PluginOp,
1375    entry: PluginU64,
1376    imm: u64,
1377) {
1378    unsafe {
1379        crate::sys::qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
1380            insn.instruction as *mut qemu_plugin_insn,
1381            op,
1382            entry,
1383            imm,
1384        );
1385    }
1386}
1387
1388extern "C" fn handle_qemu_plugin_register_vcpu_mem_cb<F>(
1389    vcpu_index: VCPUIndex,
1390    meminfo: qemu_plugin_meminfo_t,
1391    vaddr: u64,
1392    userdata: *mut c_void,
1393) where
1394    F: FnMut(VCPUIndex, MemoryInfo, u64) + Send + Sync + 'static,
1395{
1396    let mut cb: Box<Box<F>> = unsafe { Box::from_raw(userdata as *mut _) };
1397    let meminfo = MemoryInfo::from(meminfo);
1398    cb(vcpu_index, meminfo, vaddr);
1399    // NOTE: This memory will be freed on plugin exit
1400    Box::leak(cb);
1401}
1402
1403/// Register a callback for every memory transaction of a particular instruction. If the
1404/// instruction is executed multiple times, the callback will be called multiple times.
1405///
1406/// # Arguments
1407///
1408/// - `insn`: The instruction handle to register the callback for
1409/// - `cb`: The callback to be called
1410/// - `rw`: Whether the callback should be called for reads, writes, or both
1411pub fn qemu_plugin_register_vcpu_mem_cb<F>(
1412    insn: Instruction,
1413    cb: F,
1414    flags: CallbackFlags,
1415    rw: MemRW,
1416) where
1417    F: FnMut(VCPUIndex, MemoryInfo, u64) + Send + Sync + 'static,
1418{
1419    insn.register_memory_access_callback_flags(cb, rw, flags);
1420}
1421
1422#[cfg(feature = "plugin-api-v1")]
1423#[allow(clippy::not_unsafe_ptr_arg_deref)]
1424/// Register an inline callback for every memory transaction of a particular instruction.
1425///
1426/// # Arguments
1427///
1428/// - `insn`: The instruction handle to register the callback for
1429/// - `rw`: Whether the callback should be called for reads, writes, or both
1430/// - `op`: The operation to be performed
1431/// - `ptr`: The pointer to the data to be passed to the operation
1432/// - `imm`: The immediate value to be passed to the operation
1433pub fn qemu_plugin_register_vcpu_mem_inline(
1434    insn: Instruction,
1435    rw: MemRW,
1436    op: PluginOp,
1437    ptr: *mut c_void,
1438    imm: u64,
1439) {
1440    unsafe {
1441        crate::sys::qemu_plugin_register_vcpu_mem_inline(
1442            insn.instruction as *mut qemu_plugin_insn,
1443            rw,
1444            op,
1445            ptr,
1446            imm,
1447        );
1448    }
1449}
1450
1451#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1452#[allow(clippy::not_unsafe_ptr_arg_deref)]
1453/// Register an inline callback for every memory transaction of a particular instruction.
1454///
1455/// # Arguments
1456///
1457/// - `insn`: The instruction handle to register the callback for
1458/// - `rw`: Whether the callback should be called for reads, writes, or both
1459/// - `op`: The operation to be performed
1460/// - `entry`: The entry to be passed to the operation
1461/// - `imm`: The immediate value to be passed to the operation
1462pub fn qemu_plugin_register_vcpu_mem_inline_per_vcpu(
1463    insn: Instruction,
1464    rw: MemRW,
1465    op: PluginOp,
1466    entry: PluginU64,
1467    imm: u64,
1468) {
1469    unsafe {
1470        crate::sys::qemu_plugin_register_vcpu_mem_inline_per_vcpu(
1471            insn.instruction as *mut qemu_plugin_insn,
1472            rw,
1473            op,
1474            entry,
1475            imm,
1476        );
1477    }
1478}
1479
1480extern "C" fn handle_qemu_plugin_register_atexit_cb<F>(id: qemu_plugin_id_t, userdata: *mut c_void)
1481where
1482    F: FnOnce(qemu_plugin_id_t) + Send + Sync + 'static,
1483{
1484    let cb: Box<Box<F>> = unsafe { Box::from_raw(userdata as *mut _) };
1485    cb(id);
1486    // NOTE: This memory is not leaked because this is the last callback to be called
1487    // and it can only be called once, so we allow it to drop
1488}
1489
1490/// Register a callback to run once execution is finished. Plugins should be able to free all
1491/// their resources at this point.
1492///
1493/// # Arguments
1494///
1495/// - `id`: The plugin ID
1496/// - `cb`: The callback to be called
1497pub fn qemu_plugin_register_atexit_cb<F>(id: qemu_plugin_id_t, cb: F) -> Result<()>
1498where
1499    F: FnOnce(qemu_plugin_id_t) + Send + Sync + 'static,
1500{
1501    let callback = Box::new(cb);
1502    let callback_box = Box::new(callback);
1503    unsafe {
1504        crate::sys::qemu_plugin_register_atexit_cb(
1505            id,
1506            Some(handle_qemu_plugin_register_atexit_cb::<F>),
1507            Box::into_raw(callback_box) as *mut c_void,
1508        )
1509    };
1510    Ok(())
1511}
1512
1513/// Register a callback to run on flush.
1514///
1515/// # Arguments
1516///
1517/// - `id`: The plugin ID
1518/// - `cb`: The callback to be called
1519pub fn qemu_plugin_register_flush_cb(id: qemu_plugin_id_t, cb: FlushCallback) {
1520    unsafe { crate::sys::qemu_plugin_register_flush_cb(id, cb) };
1521}
1522
1523/// Register a callback to run on Syscall
1524///
1525/// # Arguments
1526///
1527/// - `id`: The plugin ID
1528/// - `cb`: The callback to be called
1529pub fn qemu_plugin_register_vcpu_syscall_cb(id: qemu_plugin_id_t, cb: SyscallCallback) {
1530    unsafe { crate::sys::qemu_plugin_register_vcpu_syscall_cb(id, cb) };
1531}
1532
1533/// Register a callback to run on Syscall return
1534///
1535/// # Arguments
1536///
1537/// - `id`: The plugin ID
1538/// - `cb`: The callback to be called
1539pub fn qemu_plugin_register_vcpu_syscall_ret_cb(id: qemu_plugin_id_t, cb: SyscallReturnCallback) {
1540    unsafe { crate::sys::qemu_plugin_register_vcpu_syscall_ret_cb(id, cb) };
1541}
1542
1543/// Output a string via the QEMU logging mechanism
1544pub fn qemu_plugin_outs<S>(string: S) -> Result<()>
1545where
1546    S: AsRef<str>,
1547{
1548    unsafe {
1549        crate::sys::qemu_plugin_outs(CString::new(string.as_ref())?.as_ptr());
1550    }
1551
1552    Ok(())
1553}
1554
1555/// Parse a boolean argument in the form of `=[on|yes|true|off|no|false]`. returns true
1556/// if the combination @name=@val parses correctly to a boolean argument, and false
1557/// otherwise.
1558///
1559/// # Arguments
1560///
1561/// - `name`: argument name, the part before the equals sign @val: argument value, what’s
1562///   after the equals sign @ret: output return value
1563/// - `val`: Argument value, what’s after the equals sign
1564///
1565pub fn qemu_plugin_bool_parse<S>(name: S, val: S) -> Result<bool>
1566where
1567    S: AsRef<str>,
1568{
1569    let mut value = false;
1570    if unsafe {
1571        crate::sys::qemu_plugin_bool_parse(
1572            CString::new(name.as_ref())?.as_ptr(),
1573            CString::new(val.as_ref())?.as_ptr(),
1574            &mut value,
1575        )
1576    } {
1577        Ok(value)
1578    } else {
1579        Err(Error::InvalidBool {
1580            name: name.as_ref().to_string(),
1581            val: val.as_ref().to_string(),
1582        })
1583    }
1584}
1585
1586/// Return the path to the binary file being executed if running in user mode,
1587/// or None if running in System mode. Return an error if the path cannot be
1588/// converted to a string.
1589pub fn qemu_plugin_path_to_binary() -> Result<Option<PathBuf>> {
1590    let path_str = unsafe { crate::sys::qemu_plugin_path_to_binary() };
1591    if path_str.is_null() {
1592        Ok(None)
1593    } else {
1594        let path = unsafe { PathBuf::from(CStr::from_ptr(path_str).to_str()?) };
1595        unsafe { g_free(path_str as *mut _) };
1596        Ok(Some(path))
1597    }
1598}
1599
1600/// Return the start of the text segment of the binary file being executed if
1601/// running in user mode, or None if running in System mode. If not running in
1602/// system mode, `None` may be interpreted as zero by callers, but the caller
1603/// must take care to ensure the plugin is not running in a system mode context.
1604pub fn qemu_plugin_start_code() -> Option<u64> {
1605    let start = unsafe { crate::sys::qemu_plugin_start_code() };
1606
1607    if start == 0 {
1608        None
1609    } else {
1610        Some(start)
1611    }
1612}
1613
1614/// Return the end of the text segment of the binary file being executed if
1615/// running in user mode, or None if running in System mode. If not running in
1616/// system mode, `None` may be interpreted as zero by callers, but the caller
1617/// must take care to ensure the plugin is not running in a system mode context.
1618pub fn qemu_plugin_end_code() -> Option<u64> {
1619    let end = unsafe { crate::sys::qemu_plugin_end_code() };
1620
1621    if end == 0 {
1622        None
1623    } else {
1624        Some(end)
1625    }
1626}
1627
1628/// Return the start address for the module of the binary file being executed if
1629/// running in user mode, or None if running in System mode. If not running in
1630/// system mode, `None` may be interpreted as zero by callers, but the caller
1631/// must take care to ensure the plugin is not running in a system mode context.
1632pub fn qemu_plugin_entry_code() -> Option<u64> {
1633    let entry = unsafe { crate::sys::qemu_plugin_entry_code() };
1634
1635    if entry == 0 {
1636        None
1637    } else {
1638        Some(entry)
1639    }
1640}
1641
1642#[cfg(feature = "plugin-api-v1")]
1643/// Return the number of vCPUs, if running in system mode
1644pub fn qemu_plugin_n_vcpus() -> Option<i32> {
1645    let vcpus = unsafe { crate::sys::qemu_plugin_n_vcpus() };
1646
1647    if vcpus == -1 {
1648        None
1649    } else {
1650        Some(vcpus)
1651    }
1652}
1653
1654#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1655/// Return the number of vCPUs, if running in system mode
1656pub fn qemu_plugin_num_vcpus() -> Option<i32> {
1657    let vcpus = unsafe { crate::sys::qemu_plugin_num_vcpus() };
1658
1659    if vcpus == -1 {
1660        None
1661    } else {
1662        Some(vcpus)
1663    }
1664}
1665
1666#[cfg(feature = "plugin-api-v1")]
1667/// Return the maximum number of vCPUs, if running in system mode
1668pub fn qemu_plugin_n_max_vcpus() -> Option<i32> {
1669    let max_cpus = unsafe { crate::sys::qemu_plugin_n_max_vcpus() };
1670
1671    if max_cpus == -1 {
1672        None
1673    } else {
1674        Some(max_cpus)
1675    }
1676}
1677
1678#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1679/// Returns a potentially empty list of registers. This should be used from a
1680/// qemu_plugin_register_vcpu_init_cb callback after the vcpu has been initialized.
1681pub fn qemu_plugin_get_registers<'a>() -> Result<Vec<RegisterDescriptor<'a>>> {
1682    use std::slice::from_raw_parts;
1683
1684    let array = unsafe { crate::sys::qemu_plugin_get_registers() };
1685
1686    let registers = unsafe {
1687        from_raw_parts(
1688            (*array).data as *mut qemu_plugin_reg_descriptor,
1689            (*array).len as usize,
1690        )
1691    }
1692    .iter()
1693    .map(|desc| RegisterDescriptor::from(*desc))
1694    .collect::<Vec<_>>();
1695
1696    // Function notes say caller frees the array but not the strings in each entry
1697    assert_eq!(
1698        unsafe { g_array_free(array, true) },
1699        std::ptr::null_mut(),
1700        "g_array_free return value must be NULL"
1701    );
1702
1703    Ok(registers)
1704}
1705
1706#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1707/// Add a value to a `PluginU64` for a given VCPU
1708pub fn qemu_plugin_u64_add(entry: PluginU64, vcpu_index: VCPUIndex, added: u64) -> Result<()> {
1709    unsafe { crate::sys::qemu_plugin_u64_add(entry, vcpu_index, added) };
1710    Ok(())
1711}
1712
1713#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1714/// Get the value of a `PluginU64` for a given VCPU
1715pub fn qemu_plugin_u64_get(entry: PluginU64, vcpu_index: VCPUIndex) -> u64 {
1716    unsafe { crate::sys::qemu_plugin_u64_get(entry, vcpu_index) }
1717}
1718
1719#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1720/// Set the value of a `PluginU64` for a given VCPU
1721pub fn qemu_plugin_u64_set(entry: PluginU64, vcpu_index: VCPUIndex, value: u64) {
1722    unsafe { crate::sys::qemu_plugin_u64_set(entry, vcpu_index, value) }
1723}
1724
1725#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
1726/// Get the sum of all VCPU entries in a scoreboard
1727pub fn qemu_plugin_scoreboard_sum(entry: PluginU64) -> u64 {
1728    unsafe { crate::sys::qemu_plugin_u64_sum(entry) }
1729}