1 //! Cranelift instructions modify the state of the machine; the [State] trait describes these 2 //! ways this can happen. 3 use crate::address::{Address, AddressSize}; 4 use crate::frame::Frame; 5 use crate::interpreter::LibCallHandler; 6 use cranelift_codegen::data_value::DataValue; 7 use cranelift_codegen::ir::{ 8 ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot, Type, 9 Value, types, 10 }; 11 use cranelift_codegen::isa::CallConv; 12 use smallvec::SmallVec; 13 use thiserror::Error; 14 15 /// This trait manages the state necessary to interpret a single Cranelift instruction--it describes 16 /// all of the ways a Cranelift interpreter can interact with its virtual state. This makes it 17 /// possible to use the [Interpreter](crate::interpreter::Interpreter) in a range of situations: 18 /// - when interpretation needs to happen in a way isolated from the host a state which keeps a 19 /// stack and bound checks memory accesses can be used, like 20 /// [InterpreterState](crate::interpreter::InterpreterState). 21 /// - when interpretation needs to have access to the host a state which allows direct access to the 22 /// host memory and native functions can be used. 23 pub trait State<'a> { 24 /// Retrieve a reference to a [Function]. 25 fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function>; 26 /// Retrieve a reference to the currently executing [Function]. 27 fn get_current_function(&self) -> &'a Function; 28 /// Retrieve the handler callback for a [LibCall] 29 fn get_libcall_handler(&self) -> LibCallHandler; 30 31 /// Record that an interpreter has called into a new [Function]. 32 fn push_frame(&mut self, function: &'a Function); 33 /// Record that an interpreter has returned from a called [Function]. 34 fn pop_frame(&mut self); 35 36 fn current_frame_mut(&mut self) -> &mut Frame<'a>; 37 fn current_frame(&self) -> &Frame<'a>; 38 39 /// Collect a list of values `V` by their [value references](cranelift_codegen::ir::Value). 40 fn collect_values(&self, names: &[Value]) -> SmallVec<[DataValue; 1]> { 41 let frame = self.current_frame(); 42 names.into_iter().map(|n| frame.get(*n).clone()).collect() 43 } 44 45 /// Computes the stack address for this stack slot, including an offset. 46 fn stack_address( 47 &self, 48 size: AddressSize, 49 slot: StackSlot, 50 offset: u64, 51 ) -> Result<Address, MemoryError>; 52 /// Retrieve a value `V` from memory at the given `address`, checking if it belongs either to the 53 /// stack or to one of the heaps; the number of bytes loaded corresponds to the specified [Type]. 54 fn checked_load( 55 &self, 56 address: Address, 57 ty: Type, 58 mem_flags: MemFlags, 59 ) -> Result<DataValue, MemoryError>; 60 /// Store a value `V` into memory at the given `address`, checking if it belongs either to the 61 /// stack or to one of the heaps; the number of bytes stored corresponds to the specified [Type]. 62 fn checked_store( 63 &mut self, 64 address: Address, 65 v: DataValue, 66 mem_flags: MemFlags, 67 ) -> Result<(), MemoryError>; 68 69 /// Compute the address of a function given its name. 70 fn function_address( 71 &self, 72 size: AddressSize, 73 name: &ExternalName, 74 ) -> Result<Address, MemoryError>; 75 76 /// Retrieve a reference to a [Function] given its address. 77 fn get_function_from_address(&self, address: Address) -> Option<InterpreterFunctionRef<'a>>; 78 79 /// Given a global value, compute the final value for that global value, applying all operations 80 /// in intermediate global values. 81 fn resolve_global_value(&self, gv: GlobalValue) -> Result<DataValue, MemoryError>; 82 83 /// Retrieves the current pinned reg value 84 fn get_pinned_reg(&self) -> DataValue; 85 /// Sets a value for the pinned reg 86 fn set_pinned_reg(&mut self, v: DataValue); 87 } 88 89 pub enum InterpreterFunctionRef<'a> { 90 Function(&'a Function), 91 LibCall(LibCall), 92 } 93 94 impl<'a> InterpreterFunctionRef<'a> { 95 pub fn signature(&self) -> Signature { 96 match self { 97 InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(), 98 // CallConv here is sort of irrelevant, since we don't use it for anything 99 // FIXME handle non-64bit systems 100 InterpreterFunctionRef::LibCall(lc) => lc.signature(CallConv::SystemV, types::I64), 101 } 102 } 103 } 104 105 impl<'a> From<&'a Function> for InterpreterFunctionRef<'a> { 106 fn from(f: &'a Function) -> Self { 107 InterpreterFunctionRef::Function(f) 108 } 109 } 110 111 impl From<LibCall> for InterpreterFunctionRef<'_> { 112 fn from(lc: LibCall) -> Self { 113 InterpreterFunctionRef::LibCall(lc) 114 } 115 } 116 117 #[derive(Error, Debug)] 118 pub enum MemoryError { 119 #[error("Invalid DataValue passed as an address: {0}")] 120 InvalidAddress(DataValue), 121 #[error("Invalid type for address: {0}")] 122 InvalidAddressType(Type), 123 #[error("Requested an the entry {entry} but only {max} entries are allowed")] 124 InvalidEntry { entry: u64, max: u64 }, 125 #[error("Requested an offset of {offset} but max was {max}")] 126 InvalidOffset { offset: u64, max: u64 }, 127 #[error("Load of {load_size} bytes is larger than available size at address {addr:?}")] 128 OutOfBoundsLoad { 129 addr: Address, 130 load_size: usize, 131 mem_flags: MemFlags, 132 }, 133 #[error("Store of {store_size} bytes is larger than available size at address {addr:?}")] 134 OutOfBoundsStore { 135 addr: Address, 136 store_size: usize, 137 mem_flags: MemFlags, 138 }, 139 #[error("Load of {load_size} bytes is misaligned at address {addr:?}")] 140 MisalignedLoad { addr: Address, load_size: usize }, 141 #[error("Store of {store_size} bytes is misaligned at address {addr:?}")] 142 MisalignedStore { addr: Address, store_size: usize }, 143 } 144