lucet_module/
module_data.rs

1use crate::{
2    functions::{
3        ExportFunction, FunctionIndex, FunctionMetadata, ImportFunction, OwnedFunctionMetadata,
4    },
5    globals::GlobalSpec,
6    linear_memory::{HeapSpec, LinearMemorySpec, SparseData},
7    types::Signature,
8    Error,
9};
10use derivative::Derivative;
11use minisign::SignatureBones;
12use serde::{Deserialize, Serialize};
13use serde_big_array::big_array;
14
15pub const MODULE_DATA_SYM: &str = "lucet_module_data";
16
17big_array! {
18    BigArray;
19    SignatureBones::BYTES,
20}
21
22/// The metadata (and some data) for a Lucet module.
23///
24/// The lifetime parameter exists to support zero-copy deserialization for the `&str` and `&[u8]`
25/// fields at the leaves of the structure. For a variant with owned types at the leaves, see
26/// [`OwnedModuleData`](owned/struct.OwnedModuleData.html).
27///
28/// The goal is for this structure to eventually include everything except the code for the guest
29/// functions themselves.
30#[derive(Derivative, Serialize, Deserialize)]
31#[derivative(Debug)]
32pub struct ModuleData<'a> {
33    #[serde(borrow)]
34    linear_memory: Option<LinearMemorySpec<'a>>,
35    #[serde(borrow)]
36    globals_spec: Vec<GlobalSpec<'a>>,
37    #[serde(borrow)]
38    function_info: Vec<FunctionMetadata<'a>>,
39    #[serde(borrow)]
40    import_functions: Vec<ImportFunction<'a>>,
41    #[serde(borrow)]
42    export_functions: Vec<ExportFunction<'a>>,
43    signatures: Vec<Signature>,
44    #[serde(with = "BigArray")]
45    #[derivative(Debug = "ignore")]
46    module_signature: [u8; SignatureBones::BYTES],
47    features: ModuleFeatures,
48}
49
50#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
51pub struct ModuleFeatures {
52    pub sse3: bool,
53    pub ssse3: bool,
54    pub sse41: bool,
55    pub sse42: bool,
56    pub avx: bool,
57    pub bmi1: bool,
58    pub bmi2: bool,
59    pub lzcnt: bool,
60    pub popcnt: bool,
61    pub instruction_count: bool,
62    _hidden: (),
63}
64
65impl ModuleFeatures {
66    pub fn none() -> Self {
67        Self {
68            sse3: false,
69            ssse3: false,
70            sse41: false,
71            sse42: false,
72            avx: false,
73            bmi1: false,
74            bmi2: false,
75            lzcnt: false,
76            popcnt: false,
77            instruction_count: false,
78            _hidden: (),
79        }
80    }
81}
82
83impl<'a> ModuleData<'a> {
84    pub fn new(
85        linear_memory: Option<LinearMemorySpec<'a>>,
86        globals_spec: Vec<GlobalSpec<'a>>,
87        function_info: Vec<FunctionMetadata<'a>>,
88        import_functions: Vec<ImportFunction<'a>>,
89        export_functions: Vec<ExportFunction<'a>>,
90        signatures: Vec<Signature>,
91        features: ModuleFeatures,
92    ) -> Self {
93        Self {
94            linear_memory,
95            globals_spec,
96            function_info,
97            import_functions,
98            export_functions,
99            signatures,
100            module_signature: [0u8; SignatureBones::BYTES],
101            features,
102        }
103    }
104
105    pub fn heap_spec(&self) -> Option<&HeapSpec> {
106        if let Some(ref linear_memory) = self.linear_memory {
107            Some(&linear_memory.heap)
108        } else {
109            None
110        }
111    }
112
113    pub fn sparse_data(&self) -> Option<&SparseData<'a>> {
114        if let Some(ref linear_memory) = self.linear_memory {
115            Some(&linear_memory.initializer)
116        } else {
117            None
118        }
119    }
120
121    pub fn globals_spec(&self) -> &[GlobalSpec<'a>] {
122        &self.globals_spec
123    }
124
125    pub fn function_info(&self) -> &[FunctionMetadata<'a>] {
126        &self.function_info
127    }
128
129    pub fn import_functions(&self) -> &[ImportFunction<'_>] {
130        &self.import_functions
131    }
132
133    pub fn export_functions(&self) -> &[ExportFunction<'_>] {
134        &self.export_functions
135    }
136
137    // Function index here is a different index space than `get_func_from_idx`, which
138    // uses function index as an index into a table of function elements.
139    //
140    // This is an index of all functions in the module.
141    pub fn get_signature(&self, fn_id: FunctionIndex) -> &Signature {
142        let sig_idx = self.function_info[fn_id.as_u32() as usize].signature;
143        &self.signatures[sig_idx.as_u32() as usize]
144    }
145
146    pub fn get_export_func_id(&self, name: &str) -> Option<FunctionIndex> {
147        self.export_functions
148            .iter()
149            .find(|export| export.names.contains(&name))
150            .map(|export| export.fn_idx)
151    }
152
153    pub fn signatures(&self) -> &[Signature] {
154        &self.signatures
155    }
156
157    pub fn get_module_signature(&self) -> &[u8] {
158        &self.module_signature
159    }
160
161    pub fn features(&self) -> &ModuleFeatures {
162        &self.features
163    }
164
165    pub fn patch_module_signature(
166        module_data_bin: &'a [u8],
167        module_signature: &[u8],
168    ) -> Result<Vec<u8>, Error> {
169        assert_eq!(module_signature.len(), SignatureBones::BYTES);
170        let mut module_data = Self::deserialize(module_data_bin)?;
171        module_data
172            .module_signature
173            .copy_from_slice(module_signature);
174        let patched_module_data_bin = module_data.serialize()?;
175        assert_eq!(patched_module_data_bin.len(), module_data_bin.len());
176        Ok(patched_module_data_bin)
177    }
178
179    pub fn clear_module_signature(module_data_bin: &'a [u8]) -> Result<Vec<u8>, Error> {
180        let module_signature = vec![0u8; SignatureBones::BYTES];
181        Self::patch_module_signature(module_data_bin, &module_signature)
182    }
183
184    /// Serialize to [`bincode`](https://github.com/TyOverby/bincode).
185    pub fn serialize(&self) -> Result<Vec<u8>, Error> {
186        bincode::serialize(self).map_err(Error::SerializationError)
187    }
188
189    /// Deserialize from [`bincode`](https://github.com/TyOverby/bincode).
190    pub fn deserialize(buf: &'a [u8]) -> Result<ModuleData<'a>, Error> {
191        bincode::deserialize(buf).map_err(Error::DeserializationError)
192    }
193}
194
195use crate::{
196    functions::{OwnedExportFunction, OwnedImportFunction},
197    globals::OwnedGlobalSpec,
198    linear_memory::{OwnedLinearMemorySpec, OwnedSparseData},
199};
200
201/// The metadata (and some data) for a Lucet module.
202///
203/// This is a version of [`ModuleData`](../struct.ModuleData.html) with owned types throughout,
204/// rather than references to support zero-copy deserialization. This type is useful when directly
205/// building up a value to be serialized.
206pub struct OwnedModuleData {
207    linear_memory: Option<OwnedLinearMemorySpec>,
208    globals_spec: Vec<OwnedGlobalSpec>,
209    function_info: Vec<OwnedFunctionMetadata>,
210    imports: Vec<OwnedImportFunction>,
211    exports: Vec<OwnedExportFunction>,
212    signatures: Vec<Signature>,
213    features: ModuleFeatures,
214}
215
216impl OwnedModuleData {
217    pub fn new(
218        linear_memory: Option<OwnedLinearMemorySpec>,
219        globals_spec: Vec<OwnedGlobalSpec>,
220        function_info: Vec<OwnedFunctionMetadata>,
221        imports: Vec<OwnedImportFunction>,
222        exports: Vec<OwnedExportFunction>,
223        signatures: Vec<Signature>,
224        features: ModuleFeatures,
225    ) -> Self {
226        Self {
227            linear_memory,
228            globals_spec,
229            function_info,
230            imports,
231            exports,
232            signatures,
233            features,
234        }
235    }
236
237    /// Create a [`ModuleData`](../struct.ModuleData.html) backed by the values in this
238    /// `OwnedModuleData`.
239    pub fn to_ref<'a>(&'a self) -> ModuleData<'a> {
240        ModuleData::new(
241            if let Some(ref owned_linear_memory) = self.linear_memory {
242                Some(owned_linear_memory.to_ref())
243            } else {
244                None
245            },
246            self.globals_spec.iter().map(|gs| gs.to_ref()).collect(),
247            self.function_info
248                .iter()
249                .map(|info| info.to_ref())
250                .collect(),
251            self.imports.iter().map(|imp| imp.to_ref()).collect(),
252            self.exports.iter().map(|exp| exp.to_ref()).collect(),
253            self.signatures.clone(),
254            self.features.clone(),
255        )
256    }
257
258    pub fn empty() -> Self {
259        Self::new(
260            None,
261            vec![],
262            vec![],
263            vec![],
264            vec![],
265            vec![],
266            ModuleFeatures::none(),
267        )
268    }
269
270    pub fn with_heap_spec(mut self, heap_spec: HeapSpec) -> Self {
271        if let Some(ref mut linear_memory) = self.linear_memory {
272            linear_memory.heap = heap_spec;
273        } else {
274            self.linear_memory = Some(OwnedLinearMemorySpec {
275                heap: heap_spec,
276                initializer: OwnedSparseData::new(vec![]).unwrap(),
277            });
278        }
279        self
280    }
281}
282
283impl Default for OwnedModuleData {
284    fn default() -> Self {
285        OwnedModuleData::empty()
286    }
287}