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
135
136
137
138
139
140
mod dl;
mod mock;
mod sparse_page_data;
pub use crate::module::dl::DlModule;
pub use crate::module::mock::{MockExportBuilder, MockModuleBuilder};
pub use lucet_module::{
FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, Global, GlobalSpec, GlobalValue,
HeapSpec, Signature, TableElement, TrapCode, TrapManifest, ValueType,
};
use crate::alloc::Limits;
use crate::error::Error;
use libc::c_void;
#[derive(Clone, Debug)]
pub struct AddrDetails {
pub in_module_code: bool,
pub file_name: Option<String>,
pub sym_name: Option<String>,
}
pub trait Module: ModuleInternal {
fn initial_globals_size(&self) -> usize {
self.globals().len() * std::mem::size_of::<u64>()
}
}
pub trait ModuleInternal: Send + Sync {
fn heap_spec(&self) -> Option<&HeapSpec>;
fn globals(&self) -> &[GlobalSpec<'_>];
fn get_sparse_page_data(&self, page: usize) -> Option<&[u8]>;
fn sparse_page_data_len(&self) -> usize;
fn table_elements(&self) -> Result<&[TableElement], Error>;
fn get_export_func(&self, sym: &str) -> Result<FunctionHandle, Error>;
fn get_func_from_idx(&self, table_id: u32, func_id: u32) -> Result<FunctionHandle, Error>;
fn get_start_func(&self) -> Result<Option<FunctionHandle>, Error>;
fn function_manifest(&self) -> &[FunctionSpec];
fn addr_details(&self, addr: *const c_void) -> Result<Option<AddrDetails>, Error>;
fn get_signature(&self, fn_id: FunctionIndex) -> &Signature;
fn function_handle_from_ptr(&self, ptr: FunctionPointer) -> FunctionHandle {
let id = self
.function_manifest()
.iter()
.enumerate()
.find(|(_, fn_spec)| fn_spec.ptr() == ptr)
.map(|(fn_id, _)| FunctionIndex::from_u32(fn_id as u32))
.expect("valid function pointer");
FunctionHandle { ptr, id }
}
fn lookup_trapcode(&self, rip: *const c_void) -> Option<TrapCode> {
for fn_spec in self.function_manifest() {
if let Some(offset) = fn_spec.relative_addr(rip as u64) {
return fn_spec.traps().and_then(|traps| traps.lookup_addr(offset));
}
}
None
}
fn validate_runtime_spec(&self, limits: &Limits) -> Result<(), Error> {
if let Some(heap) = self.heap_spec() {
if heap.reserved_size > std::u32::MAX as u64 + 1
|| heap.guard_size > std::u32::MAX as u64 + 1
{
return Err(lucet_incorrect_module!(
"heap spec sizes would overflow: {:?}",
heap
));
}
if heap.reserved_size as usize + heap.guard_size as usize
> limits.heap_address_space_size
{
bail_limits_exceeded!("heap spec reserved and guard size: {:?}", heap);
}
if heap.initial_size as usize > limits.heap_memory_size {
bail_limits_exceeded!("heap spec initial size: {:?}", heap);
}
if heap.initial_size > heap.reserved_size {
return Err(lucet_incorrect_module!(
"initial heap size greater than reserved size: {:?}",
heap
));
}
}
if self.globals().len() * std::mem::size_of::<u64>() > limits.globals_size {
bail_limits_exceeded!("globals exceed limits");
}
Ok(())
}
}