reoxide 0.7.0

Rust-bindings for the ReOxide decompiler extension framework
Documentation
use crate::cpp::StdVector;
pub use crate::manual_bindings::ReOxideInterface;
use crate::manual_bindings::ghidra_throw;
use std::{ffi::c_char, panic::PanicHookInfo};

#[repr(C)]
pub struct Context {
    pub arch: *mut Architecture,
    pub stackspace: *mut AddrSpace,
    pub reoxide: *mut ReOxideInterface,
}

#[repr(C)]
pub struct ExtraArgs {
    pub group_name: *const c_char,
    pub extra_arg: u64,
}

opaque!(OpaquePlugin);
opaque!(OpaqueAction);
opaque!(OpaqueRule);

#[repr(C)]
pub struct ActionDefinition {
    pub name: *const c_char,
    pub constructor: extern "C-unwind" fn(
        *const Context,
        *mut OpaquePlugin,
        *const ExtraArgs,
    ) -> *mut OpaqueAction,
    pub destructor: extern "C-unwind" fn(*mut OpaqueAction),
    pub apply: extern "C-unwind" fn(*mut OpaqueAction, *mut Funcdata) -> i32,
}

#[repr(C)]
pub struct RuleDefinition {
    pub name: *const c_char,
    pub constructor: extern "C-unwind" fn(
        *const Context,
        *mut OpaquePlugin,
        *const ExtraArgs,
    ) -> *mut OpaqueRule,
    pub destructor: extern "C-unwind" fn(*mut OpaqueRule),
    pub oplist: extern "C-unwind" fn(*const OpaqueRule, *mut StdVector<OpCode>),
    pub apply: extern "C-unwind" fn(*mut OpaqueRule, *mut PcodeOp, *mut Funcdata) -> i32,
}

#[repr(C)]
pub struct DefinitionTable<T: ?Sized> {
    pub table: T,
}

unsafe impl<T: ?Sized> Sync for DefinitionTable<T> {}

pub struct CreationContext<'context, 'name, T> {
    pub arch: &'context mut Architecture,
    pub stack_space: &'context mut AddrSpace,
    pub reoxide: &'context mut ReOxideInterface,
    pub plugin: &'context mut T,
    pub group_name: &'name str,
    pub extra_args: u64,
}

#[repr(i32)]
pub enum ApplyResult {
    Applied = 1,
    NotApplied = 0,
}

pub trait Rule<'a> {
    type PluginContext;

    fn new(context: CreationContext<'a, '_, Self::PluginContext>) -> Self;

    fn op_list(&self) -> Vec<OpCode>;

    fn apply(&mut self, op: &mut PcodeOp, data: &mut Funcdata) -> ApplyResult;
}

pub trait Action<'a> {
    type PluginContext;

    fn new(context: CreationContext<'a, '_, Self::PluginContext>) -> Self;

    fn apply(&mut self, data: &mut Funcdata) -> ApplyResult;
}

/// Our drop in panic hook for plugins throws a RustError on the C++
/// side. Because we therefore (kind of) panic while using the
/// panic_hook, we can only do this *once*. On the next panic, Rust
/// will simply abort.
pub fn panic_hook(info: &PanicHookInfo) {
    let mut msg = String::new();

    // Add panic message if there is one
    if let Some(s) = info.payload().downcast_ref::<&str>() {
        msg.push_str(s);
    } else if let Some(s) = info.payload().downcast_ref::<String>() {
        msg.push_str(s);
    }
    msg.push('\n');

    if let Some(l) = info.location() {
        msg.push_str(&format!("In file {}, line {}\n", l.file(), l.line()));
    }

    let bt = std::backtrace::Backtrace::force_capture();
    msg.push_str(&format!("Backtrace:\n\n{}", bt));
    ghidra_throw(&msg);
}

pub use crate::generated::*;
pub use reoxide_proc::{action, plugin, rule};