qemu_plugin/register/
mod.rs

1//! Register-related functionality for QEMU plugins
2#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
3use crate::{
4    Error, Result,
5    sys::{qemu_plugin_read_register, qemu_plugin_reg_descriptor, qemu_plugin_register},
6};
7#[cfg(all(
8    not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")),
9    feature = "num-traits"
10))]
11use num_traits::{FromBytes, PrimInt};
12#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
13use std::{
14    ffi::CStr,
15    fmt::{Debug, Formatter},
16    marker::PhantomData,
17};
18
19#[cfg(not(any(
20    feature = "plugin-api-v0",
21    feature = "plugin-api-v1",
22    feature = "plugin-api-v2",
23    feature = "plugin-api-v3",
24    feature = "plugin-api-v4"
25)))]
26use crate::sys::{GByteArray, qemu_plugin_write_register};
27
28#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
29#[derive(Clone)]
30/// Wrapper structure for a `qemu_plugin_register_descriptor`
31///
32/// # Safety
33///
34/// This structure is safe to use as long as the pointer is valid. The pointer is
35/// always opaque, and therefore may not be dereferenced.
36pub struct RegisterDescriptor<'a> {
37    /// Opaque handle to the register for retrieving the value with
38    /// qemu_plugin_read_register
39    handle: usize,
40    /// The register name
41    pub name: String,
42    /// Optional feature descriptor
43    pub feature: Option<String>,
44    marker: PhantomData<&'a ()>,
45}
46
47#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
48impl<'a> From<qemu_plugin_reg_descriptor> for RegisterDescriptor<'a> {
49    fn from(descriptor: qemu_plugin_reg_descriptor) -> Self {
50        let name = unsafe { CStr::from_ptr(descriptor.name) }
51            .to_str()
52            .expect("Register name is not valid UTF-8")
53            .to_string();
54
55        let feature = if descriptor.feature.is_null() {
56            None
57        } else {
58            Some(
59                unsafe { CStr::from_ptr(descriptor.feature) }
60                    .to_str()
61                    .expect("Register feature is not valid UTF-8")
62                    .to_string(),
63            )
64        };
65
66        Self {
67            handle: descriptor.handle as usize,
68            name,
69            feature,
70            marker: PhantomData,
71        }
72    }
73}
74
75#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
76impl<'a> Debug for RegisterDescriptor<'a> {
77    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
78        f.debug_struct("RegisterDescriptor")
79            .field("name", &self.name)
80            .field("feature", &self.feature)
81            .finish()
82    }
83}
84
85#[cfg(not(any(feature = "plugin-api-v0", feature = "plugin-api-v1")))]
86impl<'a> RegisterDescriptor<'a> {
87    /// Read a register value
88    ///
89    /// This must only be called in a callback which has been registered with
90    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
91    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`, otherwise it will fail.
92    pub fn read(&self) -> Result<Vec<u8>> {
93        use crate::g_byte_array_free;
94
95        let byte_array = unsafe {
96            use crate::g_byte_array_new;
97            g_byte_array_new()
98        };
99
100        let result = unsafe {
101            qemu_plugin_read_register(self.handle as *mut qemu_plugin_register, byte_array)
102        };
103
104        if result == -1 {
105            return Err(Error::RegisterReadError {
106                name: self.name.clone(),
107            });
108        }
109
110        let mut data = Vec::new();
111        data.extend_from_slice(unsafe {
112            std::slice::from_raw_parts((*byte_array).data, (*byte_array).len as usize)
113        });
114
115        assert_eq!(
116            unsafe { g_byte_array_free(byte_array, true) },
117            std::ptr::null_mut(),
118            "g_byte_array_free must return NULL"
119        );
120
121        Ok(data)
122    }
123
124    #[cfg(not(any(
125        feature = "plugin-api-v0",
126        feature = "plugin-api-v1",
127        feature = "plugin-api-v2",
128        feature = "plugin-api-v3",
129        feature = "plugin-api-v4"
130    )))]
131    /// Read a register value
132    ///
133    /// This must only be called in a callback which has been registered with
134    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`, otherwise it will fail.
135    pub fn write(&self, data: &mut [u8]) -> Result<()> {
136        let mut buf = GByteArray {
137            data: data.as_mut_ptr(),
138            len: data.len() as u32,
139        };
140        if unsafe { qemu_plugin_write_register(self.handle as *mut _, &mut buf as *mut GByteArray) }
141            == 0
142        {
143            Err(Error::RegisterWriteError {
144                name: self.name.clone(),
145            })
146        } else {
147            Ok(())
148        }
149    }
150
151    #[cfg(feature = "num-traits")]
152    /// Read a register value into a numeric type in big-endian byte order
153    ///
154    /// This must only be called in a callback which has been registered with
155    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
156    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`.
157    pub fn read_be<T>(&self) -> Result<T>
158    where
159        T: PrimInt + FromBytes + Sized,
160        T: FromBytes<Bytes = [u8; std::mem::size_of::<T>()]>,
161    {
162        let data = self.read()?;
163        let mut bytes = [0; std::mem::size_of::<T>()];
164        bytes.copy_from_slice(&data);
165        Ok(T::from_be_bytes(&bytes))
166    }
167
168    #[cfg(feature = "num-traits")]
169    /// Read a register value into a numeric type in little-endian byte order
170    ///
171    /// This must only be called in a callback which has been registered with
172    /// `CallbackFlags::QEMU_PLUGIN_CB_R_REGS` or
173    /// `CallbackFlags::QEMU_PLUGIN_CB_RW_REGS`.
174    pub fn read_le<T>(&self) -> Result<T>
175    where
176        T: PrimInt + FromBytes + Sized,
177        T: FromBytes<Bytes = [u8; std::mem::size_of::<T>()]>,
178    {
179        let data = self.read()?;
180        let mut bytes = [0; std::mem::size_of::<T>()];
181        bytes.copy_from_slice(&data);
182        Ok(T::from_le_bytes(&bytes))
183    }
184}