use cxx::CxxString;
use cxx::CxxVector;
use cxx::UniquePtr;
use std::os::raw::c_char;
use num_derive::FromPrimitive;
#[derive(Debug, FromPrimitive)]
pub enum SpaceType {
Constant = 0,
Processor = 1,
SpaceBase = 2,
Internal = 3,
Fspec = 4,
Iop = 5,
Join = 6,
}
impl SpaceType {
pub fn from_u32(val: u32) -> Option<Self> {
num::FromPrimitive::from_u32(val)
}
}
#[derive(Debug, FromPrimitive)]
pub enum Opcode {
Copy = 1,
Load = 2,
Store = 3,
Branch = 4,
CBranch = 5,
BranchInd = 6,
Call = 7,
CallInd = 8,
CallOther = 9,
Return = 10,
IntEqual = 11,
IntNotEqual = 12,
IntSLess = 13,
IntSLessEqual = 14,
IntLess = 15,
IntLessEqual = 16,
IntZExt = 17,
IntSExt = 18,
IntAdd = 19,
IntSub = 20,
IntCarry = 21,
IntSCarry = 22,
IntSBorrow = 23,
Int2Comp = 24,
IntNegate = 25,
IntXor = 26,
IntAnd = 27,
IntOr = 28,
IntLeft = 29,
IntRight = 30,
IntSRight = 31,
IntMult = 32,
IntDiv = 33,
IntSDiv = 34,
IntRem = 35,
IntSRem = 36,
BoolNegate = 37,
BoolXor = 38,
BoolAnd = 39,
BoolOr = 40,
FloatEqual = 41,
FloatNotEqual = 42,
FloatLess = 43,
FloatLessEqual = 44,
FloatNan = 46,
FloatAdd = 47,
FloatDiv = 48,
FloatMult = 49,
FloatSub = 50,
FloatNeg = 51,
FloatAbs = 52,
FloatSqrt = 53,
FloatInt2Float = 54,
FloatFloat2Float = 55,
FloatTrunc = 56,
FloatCeil = 57,
FloatFloor = 58,
FloatRound = 59,
MultiEqual = 60,
Indirect = 61,
Piece = 62,
SubPiece = 63,
Cast = 64,
PtrAdd = 65,
PtrSub = 66,
SegmentOp = 67,
CPoolRef = 68,
New = 69,
Insert = 70,
Extract = 71,
PopCount = 72,
Max = 73,
}
impl Opcode {
pub fn from_u32(val: u32) -> Option<Self> {
num::FromPrimitive::from_u32(val)
}
}
pub trait AssemblyEmit {
fn dump(&mut self, addr: &ffi::Address, mnem: &str, body: &str);
}
pub struct RustAssemblyEmit<'a> {
internal: &'a mut dyn AssemblyEmit,
}
impl<'a> RustAssemblyEmit<'a> {
pub fn from_internal(internal: &'a mut dyn AssemblyEmit) -> Self {
Self { internal }
}
pub fn dump(&mut self, address: &ffi::Address, mnem: &CxxString, body: &CxxString) {
let mnem = mnem.to_str().unwrap();
let body = body.to_str().unwrap();
self.internal.dump(address, mnem, body);
}
}
pub trait PCodeEmit {
fn dump(
&mut self,
address: &ffi::Address,
opcode: Opcode,
outvar: Option<&ffi::VarnodeData>,
vars: &[ffi::VarnodeData],
);
}
pub struct RustPCodeEmit<'a> {
pub internal: &'a mut dyn PCodeEmit,
}
pub trait LoadImage {
fn load_fill(&mut self, ptr: &mut [u8], addr: &ffi::Address);
fn adjust_vma(&mut self, _adjust: isize) {}
}
pub struct RustLoadImage<'a> {
internal: &'a mut dyn LoadImage,
}
impl<'a> RustLoadImage<'a> {
pub fn from_internal(internal: &'a mut dyn LoadImage) -> Self {
Self { internal }
}
unsafe fn load_fill(&mut self, ptr: *mut u8, size: u32, addr: &ffi::Address) {
let slice = std::slice::from_raw_parts_mut(ptr, size as usize);
self.internal.load_fill(slice, addr);
}
fn adjust_vma(&mut self, adjust: isize) {
self.internal.adjust_vma(adjust)
}
}
impl<'a> RustPCodeEmit<'a> {
pub fn from_internal(internal: &'a mut dyn PCodeEmit) -> Self {
Self { internal }
}
unsafe fn dump(
&mut self,
address: &ffi::Address,
opcode: u32,
outvar: *const ffi::VarnodeData,
vars: *const ffi::VarnodeData,
size: i32,
) {
let outvar = if outvar.is_null() {
None
} else {
Some(&*outvar)
};
let vars = std::slice::from_raw_parts(vars, size as usize);
let opcode = num::FromPrimitive::from_u32(opcode).unwrap();
self.internal.dump(address, opcode, outvar, vars);
}
}
#[cxx::bridge]
pub mod ffi {
extern "Rust" {
type RustAssemblyEmit<'a>;
fn dump(self: &mut RustAssemblyEmit, address: &Address, mnem: &CxxString, body: &CxxString);
type RustPCodeEmit<'a>;
unsafe fn dump(
self: &mut RustPCodeEmit,
address: &Address,
opcode: u32,
outvar: *const VarnodeData,
vars: *const VarnodeData,
size: i32,
);
type RustLoadImage<'a>;
unsafe fn load_fill(self: &mut RustLoadImage, ptr: *mut u8, size: u32, addr: &Address);
fn adjust_vma(self: &mut RustLoadImage, adjust: isize);
}
unsafe extern "C++" {
include!("bridge.hh");
type Address;
fn isInvalid(self: &Address) -> bool;
fn getAddrSize(self: &Address) -> i32;
fn isBigEndian(self: &Address) -> bool;
fn getSpace(self: &Address) -> *mut AddrSpace;
fn getOffset(self: &Address) -> u64;
fn toPhysical(self: Pin<&mut Address>);
fn getShortcut(self: &Address) -> c_char;
fn containedBy(self: &Address, sz: i32, op2: &Address, sz2: i32) -> bool;
fn justifiedContain(
self: &Address,
sz: i32,
op2: &Address,
sz2: i32,
forceleft: bool,
) -> i32;
fn overlap(self: &Address, skip: i32, op: &Address, size: i32) -> i32;
fn isContiguous(self: &Address, sz: i32, loaddr: &Address, losz: i32) -> bool;
fn isConstant(self: &Address) -> bool;
fn renormalize(self: Pin<&mut Address>, size: i32);
fn isJoin(self: &Address) -> bool;
type VarnodeData;
fn getVarnodeDataAddress(data: &VarnodeData) -> UniquePtr<Address>;
fn getVarnodeSize(data: &VarnodeData) -> u32;
type spacetype;
type AddrSpace;
fn getName(self: &AddrSpace) -> &CxxString;
fn getDelay(self: &AddrSpace) -> i32;
fn getDeadcodeDelay(self: &AddrSpace) -> i32;
fn getIndex(self: &AddrSpace) -> i32;
fn getWordSize(self: &AddrSpace) -> u32;
fn getAddrSize(self: &AddrSpace) -> u32;
fn getHighest(self: &AddrSpace) -> u64;
fn getPointerLowerBound(self: &AddrSpace) -> u64;
fn getPointerUpperBound(self: &AddrSpace) -> u64;
fn getMinimumPtrSize(self: &AddrSpace) -> i32;
fn wrapOffset(self: &AddrSpace, off: u64) -> u64;
fn getShortcut(self: &AddrSpace) -> c_char;
fn isHeritaged(self: &AddrSpace) -> bool;
fn doesDeadcode(self: &AddrSpace) -> bool;
fn hasPhysical(self: &AddrSpace) -> bool;
fn isBigEndian(self: &AddrSpace) -> bool;
fn isReverseJustified(self: &AddrSpace) -> bool;
fn isOverlay(self: &AddrSpace) -> bool;
fn isOverlayBase(self: &AddrSpace) -> bool;
fn isOtherSpace(self: &AddrSpace) -> bool;
fn isTruncated(self: &AddrSpace) -> bool;
fn hasNearPointers(self: &AddrSpace) -> bool;
fn numSpacebase(self: &AddrSpace) -> i32;
fn getSpacebase(self: &AddrSpace, i: i32) -> &VarnodeData;
fn getSpacebaseFull(self: &AddrSpace, i: i32) -> &VarnodeData;
fn stackGrowsNegative(self: &AddrSpace) -> bool;
fn getContain(self: &AddrSpace) -> *mut AddrSpace;
type OpCode;
type DocumentStorage;
type ContextInternal;
type ContextDatabase;
fn setVariableDefault(self: Pin<&mut ContextDatabase>, nm: &CxxString, val: u32);
fn getDefaultValue(self: &ContextDatabase, nm: &CxxString) -> u32;
fn setVariable(self: Pin<&mut ContextDatabase>, nm: &CxxString, addr: &Address, val: u32);
fn getVariable(self: &ContextDatabase, nm: &CxxString, addr: &Address) -> u32;
fn newAddress() -> UniquePtr<Address>;
fn newContext() -> UniquePtr<ContextDatabase>;
fn newDocumentStorage(s: &CxxString) -> UniquePtr<DocumentStorage>;
fn getAddrSpaceType(addr: &AddrSpace) -> u32;
type Decompiler;
unsafe fn translate(self: &Decompiler, emit: *mut RustPCodeEmit, addr: u64) -> i32;
unsafe fn disassemble(self: &Decompiler, emit: *mut RustAssemblyEmit, addr: u64) -> i32;
unsafe fn getContext(self: Pin<&mut Decompiler>) -> *mut ContextDatabase;
unsafe fn newDecompiler(
loadImage: *mut RustLoadImage,
spec: UniquePtr<DocumentStorage>,
) -> UniquePtr<Decompiler>;
}
}
#[cfg(test)]
mod tests {
use super::ffi;
#[test]
fn test_new() {
let _a = ffi::newAddress();
let _a = ffi::newContext();
}
}