panda/plugins/cosi/
osi_statics.rs

1use std::ops::Deref;
2
3use crate::guest_ptr::GuestReadFail;
4use crate::prelude::*;
5use crate::GuestType;
6
7use super::{find_per_cpu_address, symbol_addr_from_name};
8
9/// A trait representing that a type is readable using OSI 2.
10///
11/// See the [`OsiType`](macro@panda::plugins::cosi::OsiType) derive macro for more details.
12pub trait OsiType: Sized {
13    type MethodDispatcher;
14
15    /// Read the given type out of memory starting at `base_ptr`
16    fn osi_read(cpu: &mut CPUState, base_ptr: target_ptr_t) -> Result<Self, GuestReadFail>;
17}
18
19#[doc(hidden)]
20pub struct EmptyMethodDelegator(&'static str, bool);
21
22impl EmptyMethodDelegator {
23    pub const fn new(_: &'static str, _: bool) -> Self {
24        Self("", false)
25    }
26}
27
28/// Types with a fixed layout (primarily primitives) implement OsiType automatically,
29/// allowing them to be used with [`osi_static`](super::osi_static) seamlessly.
30impl<T: GuestType> OsiType for T {
31    type MethodDispatcher = EmptyMethodDelegator;
32
33    fn osi_read(cpu: &mut CPUState, base_ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
34        T::read_from_guest(cpu, base_ptr)
35    }
36}
37
38/// A type used internally by [`osi_static`](panda::plugins::cosi::osi_static) in order
39/// to provide a value that can be read wholesale or one field at a time.
40#[doc(hidden)]
41pub struct PerCpu<T: OsiType>(pub &'static str, pub T::MethodDispatcher);
42
43impl<T: OsiType> PerCpu<T> {
44    pub fn read(&self, cpu: &mut CPUState) -> Result<T, GuestReadFail> {
45        let ptr = find_per_cpu_address(cpu, self.0)?;
46
47        T::osi_read(cpu, ptr)
48    }
49}
50
51impl<T: OsiType> Deref for PerCpu<T> {
52    type Target = T::MethodDispatcher;
53
54    fn deref(&self) -> &Self::Target {
55        &self.1
56    }
57}
58
59/// A type used internally by [`osi_static`](panda::plugins::cosi::osi_static) in order
60/// to provide a value that can be read wholesale or one field at a time.
61#[doc(hidden)]
62pub struct OsiGlobal<T: OsiType>(pub &'static str, pub T::MethodDispatcher);
63
64impl<T: OsiType> OsiGlobal<T> {
65    pub fn read(&self, cpu: &mut CPUState) -> Result<T, GuestReadFail> {
66        let ptr = symbol_addr_from_name(self.0);
67
68        T::osi_read(cpu, ptr)
69    }
70}
71
72impl<T: OsiType> Deref for OsiGlobal<T> {
73    type Target = T::MethodDispatcher;
74
75    fn deref(&self) -> &Self::Target {
76        &self.1
77    }
78}