use crate::address::{Address, AddressSize};
use crate::frame::Frame;
use crate::interpreter::LibCallHandler;
use cranelift_codegen::data_value::DataValue;
use cranelift_codegen::ir::{
types, ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot,
Type, Value,
};
use cranelift_codegen::isa::CallConv;
use smallvec::SmallVec;
use thiserror::Error;
pub trait State<'a> {
fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function>;
fn get_current_function(&self) -> &'a Function;
fn get_libcall_handler(&self) -> LibCallHandler;
fn push_frame(&mut self, function: &'a Function);
fn pop_frame(&mut self);
fn current_frame_mut(&mut self) -> &mut Frame<'a>;
fn current_frame(&self) -> &Frame<'a>;
fn collect_values(&self, names: &[Value]) -> SmallVec<[DataValue; 1]> {
let frame = self.current_frame();
names.into_iter().map(|n| frame.get(*n).clone()).collect()
}
fn stack_address(
&self,
size: AddressSize,
slot: StackSlot,
offset: u64,
) -> Result<Address, MemoryError>;
fn checked_load(
&self,
address: Address,
ty: Type,
mem_flags: MemFlags,
) -> Result<DataValue, MemoryError>;
fn checked_store(
&mut self,
address: Address,
v: DataValue,
mem_flags: MemFlags,
) -> Result<(), MemoryError>;
fn function_address(
&self,
size: AddressSize,
name: &ExternalName,
) -> Result<Address, MemoryError>;
fn get_function_from_address(&self, address: Address) -> Option<InterpreterFunctionRef<'a>>;
fn resolve_global_value(&self, gv: GlobalValue) -> Result<DataValue, MemoryError>;
fn get_pinned_reg(&self) -> DataValue;
fn set_pinned_reg(&mut self, v: DataValue);
}
pub enum InterpreterFunctionRef<'a> {
Function(&'a Function),
LibCall(LibCall),
}
impl<'a> InterpreterFunctionRef<'a> {
pub fn signature(&self) -> Signature {
match self {
InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(),
InterpreterFunctionRef::LibCall(lc) => lc.signature(CallConv::SystemV, types::I64),
}
}
}
impl<'a> From<&'a Function> for InterpreterFunctionRef<'a> {
fn from(f: &'a Function) -> Self {
InterpreterFunctionRef::Function(f)
}
}
impl From<LibCall> for InterpreterFunctionRef<'_> {
fn from(lc: LibCall) -> Self {
InterpreterFunctionRef::LibCall(lc)
}
}
#[derive(Error, Debug)]
pub enum MemoryError {
#[error("Invalid DataValue passed as an address: {0}")]
InvalidAddress(DataValue),
#[error("Invalid type for address: {0}")]
InvalidAddressType(Type),
#[error("Requested an the entry {entry} but only {max} entries are allowed")]
InvalidEntry { entry: u64, max: u64 },
#[error("Requested an offset of {offset} but max was {max}")]
InvalidOffset { offset: u64, max: u64 },
#[error("Load of {load_size} bytes is larger than available size at address {addr:?}")]
OutOfBoundsLoad {
addr: Address,
load_size: usize,
mem_flags: MemFlags,
},
#[error("Store of {store_size} bytes is larger than available size at address {addr:?}")]
OutOfBoundsStore {
addr: Address,
store_size: usize,
mem_flags: MemFlags,
},
#[error("Load of {load_size} bytes is misaligned at address {addr:?}")]
MisalignedLoad { addr: Address, load_size: usize },
#[error("Store of {store_size} bytes is misaligned at address {addr:?}")]
MisalignedStore { addr: Address, store_size: usize },
}