1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::path::Path;
use std::ffi::CString;
use libloading::Symbol;
use crate::sys::panda_require;

pub mod glib;
pub mod osi;
pub mod hooks2;
pub mod syscalls2;

#[macro_export]
macro_rules! plugin_import {
    {
        static $static:ident : $ty:ident = extern $name:literal {
        $(
            $(
                #[$meta:meta]
             )*
            fn $fn_name:ident(
                $(
                    $arg_name:ident : $arg_ty:ty
                 ),*
                $(,)?
            ) $(-> $fn_ret:ty)?;
         )*
        $(
            callbacks {
                $(
                    fn $cb_fn_name:ident(
                        $(
                            $cb_arg_name:ident : $cb_arg_ty:ty
                         ),*
                        $(,)?
                    ) $(-> $cb_fn_ret:ty)?;
                )*
            }
        )?
        };
    } => {
        pub struct $ty {
            plugin: $crate::plugins::Plugin
        }

        impl $ty {
            /// Create a new handle to this plugin
            pub fn new() -> Self {
                Self {
                    plugin: $crate::plugins::Plugin::new($name)
                }
            }

            /// Load the plugin and initialize it if it hasn't been loaded already.
            pub fn ensure_init(&self) {}

            $(
                $(
                    #[$meta]
                 )*
                pub fn $fn_name(&self $(, $arg_name : $arg_ty )*) $(-> $fn_ret)? {
                    unsafe {
                        self.plugin.get::<unsafe extern "C" fn($($arg_ty),*) $(-> $fn_ret)?>(
                            stringify!($fn_name)
                        )(
                            $(
                                $arg_name
                            ),*
                        )
                    }
                }
             )*

            $($(
                ::paste::paste!{
                    pub fn [<add_callback_ $cb_fn_name>](
                        &self,
                        callback: extern "C" fn(
                            $($cb_arg_name: $cb_arg_ty),*
                        )
                    )
                    {
                        let add_cb = self.plugin.get::<
                            extern "C" fn(
                                extern "C" fn(
                                    $($cb_arg_ty),*
                                ) $(-> $cb_fn_ret)?
                            )
                        >(
                            concat!("ppp_add_cb_", stringify!($cb_fn_name))
                        );

                        add_cb(callback);
                    }
                }
            )*)?
        }

        lazy_static::lazy_static!{
            pub static ref $static: $ty = $ty::new();
        }
    }
}

struct Plugin {
    lib: libloading::Library,
}

// TODO: make this work for other archs
const PLUGIN_DIR: &str = "x86_64-softmmu/panda/plugins";

impl Plugin {
    pub fn new(name: &str) -> Self {
        std::env::set_var("PANDA_DIR", std::env::var("PANDA_PATH").expect("Missing PANDA_PATH"));
        let c_name = CString::new(name).unwrap();
        unsafe {
            panda_require(c_name.as_ptr());
        }
        let path = 
            Path::new(&std::env::var("PANDA_PATH").unwrap())
                .join(PLUGIN_DIR)
                .join(&format!("panda_{}.so", name));
        Self {
            lib: libloading::Library::new(
                path
            ).expect("Failed to load plugin")
        }
    }

    pub fn get<T>(&self, sym: &str) -> Symbol<T> {
        let symbol: Vec<_> = sym.bytes().chain(std::iter::once(0)).collect();
        unsafe {
            self.lib.get(&symbol).expect("Could not find symbol")
        }
    }
}