lucet_module_data/
functions.rs

1use crate::traps::{TrapManifest, TrapSite};
2use cranelift_codegen::entity::entity_impl;
3use serde::{Deserialize, Serialize};
4
5use std::slice::from_raw_parts;
6
7/// FunctionIndex is an identifier for a function, imported, exported, or external. The space of
8/// FunctionIndex is shared for all of these, so `FunctionIndex(N)` may identify exported function
9/// #2, `FunctionIndex(N + 1)` may identify an internal function, and `FunctionIndex(N + 2)` may
10/// identify an imported function.
11#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
12pub struct FunctionIndex(u32);
13
14impl FunctionIndex {
15    pub fn from_u32(idx: u32) -> FunctionIndex {
16        FunctionIndex(idx)
17    }
18    pub fn as_u32(&self) -> u32 {
19        self.0
20    }
21}
22
23/// ImportFunction describes an internal function - its internal function index and the name/module
24/// pair that function should be found in.
25#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
26pub struct ImportFunction<'a> {
27    pub fn_idx: FunctionIndex,
28    pub module: &'a str,
29    pub name: &'a str,
30}
31
32/// ExportFunction describes an exported function - its internal function index and a name that
33/// function has been exported under.
34#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
35pub struct ExportFunction<'a> {
36    pub fn_idx: FunctionIndex,
37    #[serde(borrow)]
38    pub names: Vec<&'a str>,
39}
40
41pub struct OwnedExportFunction {
42    pub fn_idx: FunctionIndex,
43    pub names: Vec<String>,
44}
45
46impl OwnedExportFunction {
47    pub fn to_ref<'a>(&'a self) -> ExportFunction<'a> {
48        ExportFunction {
49            fn_idx: self.fn_idx.clone(),
50            names: self.names.iter().map(|x| x.as_str()).collect(),
51        }
52    }
53}
54
55pub struct OwnedImportFunction {
56    pub fn_idx: FunctionIndex,
57    pub module: String,
58    pub name: String,
59}
60
61impl OwnedImportFunction {
62    pub fn to_ref<'a>(&'a self) -> ImportFunction<'a> {
63        ImportFunction {
64            fn_idx: self.fn_idx.clone(),
65            module: self.module.as_str(),
66            name: self.name.as_str(),
67        }
68    }
69}
70
71/// UniqueSignatureIndex names a signature after collapsing duplicate signatures to a single
72/// identifier, whereas SignatureIndex is directly what the original module specifies, and may
73/// specify duplicates of types that are structurally equal.
74#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
75pub struct UniqueSignatureIndex(u32);
76entity_impl!(UniqueSignatureIndex);
77
78/// FunctionPointer serves entirely as a safer way to work with function pointers than as raw u64
79/// or usize values. It also avoids the need to write them as `fn` types, which cannot be freely
80/// cast from one to another with `as`. If you need to call a `FunctionPointer`, use `as_usize()`
81/// and transmute the resulting usize to a `fn` type with appropriate signature.
82#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
83pub struct FunctionPointer(usize);
84
85impl FunctionPointer {
86    pub fn from_usize(ptr: usize) -> FunctionPointer {
87        FunctionPointer(ptr)
88    }
89    pub fn as_usize(&self) -> usize {
90        self.0
91    }
92}
93
94/// Information about the corresponding function.
95///
96/// This is split from but closely related to a [`FunctionSpec`]. The distinction is largely for
97/// serialization/deserialization simplicity, as [`FunctionSpec`] contains fields that need
98/// cooperation from a loader, with manual layout and serialization as a result.
99/// [`FunctionMetadata`] is the remainder of fields that can be automatically
100/// serialized/deserialied and are small enough copying isn't a large concern.
101#[derive(Clone, Debug, Serialize, Deserialize)]
102pub struct FunctionMetadata<'a> {
103    pub signature: UniqueSignatureIndex,
104    /// the "name" field is some human-friendly name, not necessarily the same as used to reach
105    /// this function (through an export, for example), and may not even indicate that a function
106    /// is exported at all.
107    /// TODO: at some point when possible, this field ought to be set from the names section of a
108    /// wasm module. At the moment that information is lost at parse time.
109    #[serde(borrow)]
110    pub name: Option<&'a str>,
111}
112
113#[derive(Clone, Debug, Serialize, Deserialize)]
114pub struct OwnedFunctionMetadata {
115    pub signature: UniqueSignatureIndex,
116    pub name: Option<String>,
117}
118
119impl OwnedFunctionMetadata {
120    pub fn to_ref(&self) -> FunctionMetadata<'_> {
121        FunctionMetadata {
122            signature: self.signature.clone(),
123            name: self.name.as_ref().map(|n| n.as_str()),
124        }
125    }
126}
127
128pub struct FunctionHandle {
129    pub ptr: FunctionPointer,
130    pub id: FunctionIndex,
131}
132
133// The layout of this struct is very tightly coupled to lucetc's `write_function_manifest`!
134//
135// Specifically, `write_function_manifest` sets up relocations on `code_addr` and `traps_addr`.
136// It does not explicitly serialize a correctly formed `FunctionSpec`, because addresses
137// for these fields do not exist until the object is loaded in the future.
138//
139// So `write_function_manifest` has implicit knowledge of the layout of this structure
140// (including padding bytes between `code_len` and `traps_addr`)
141#[repr(C)]
142#[derive(Clone, Debug)]
143pub struct FunctionSpec {
144    code_addr: u64,
145    code_len: u32,
146    traps_addr: u64,
147    traps_len: u64,
148}
149
150impl FunctionSpec {
151    pub fn new(code_addr: u64, code_len: u32, traps_addr: u64, traps_len: u64) -> Self {
152        FunctionSpec {
153            code_addr,
154            code_len,
155            traps_addr,
156            traps_len,
157        }
158    }
159    pub fn ptr(&self) -> FunctionPointer {
160        FunctionPointer::from_usize(self.code_addr as usize)
161    }
162    pub fn code_len(&self) -> u32 {
163        self.code_len
164    }
165    pub fn traps_len(&self) -> u64 {
166        self.traps_len
167    }
168    pub fn contains(&self, addr: u64) -> bool {
169        addr >= self.code_addr && (addr - self.code_addr) < (self.code_len as u64)
170    }
171    pub fn relative_addr(&self, addr: u64) -> Option<u32> {
172        if let Some(offset) = addr.checked_sub(self.code_addr) {
173            if offset < (self.code_len as u64) {
174                // self.code_len is u32, so if the above check succeeded
175                // offset must implicitly be <= u32::MAX - the following
176                // conversion will not truncate bits
177                return Some(offset as u32);
178            }
179        }
180
181        None
182    }
183    pub fn traps(&self) -> Option<TrapManifest<'_>> {
184        let traps_ptr = self.traps_addr as *const TrapSite;
185        if !traps_ptr.is_null() {
186            let traps_slice = unsafe { from_raw_parts(traps_ptr, self.traps_len as usize) };
187            Some(TrapManifest::new(traps_slice))
188        } else {
189            None
190        }
191    }
192}