libchisel/
remapimports.rs

1use parity_wasm::elements::{ImportEntry, ImportSection, Module};
2
3use super::{
4    imports::ImportList, ChiselModule, ModuleError, ModuleKind, ModulePreset, ModuleTranslator,
5};
6
7pub struct RemapImports<'a> {
8    /// A list of import sets to remap.
9    interfaces: Vec<ImportInterface<'a>>,
10}
11
12/// A pair containing a list of imports for RemapImports to remap against, and an optional string with which all
13/// imports are expected to be prefixed.
14pub struct ImportInterface<'a>(ImportList<'a>, Option<&'a str>);
15
16impl<'a> ChiselModule<'a> for RemapImports<'a> {
17    type ObjectReference = &'a dyn ModuleTranslator;
18
19    fn id(&'a self) -> String {
20        "remapimports".to_string()
21    }
22
23    fn kind(&'a self) -> ModuleKind {
24        ModuleKind::Translator
25    }
26
27    fn as_abstract(&'a self) -> Self::ObjectReference {
28        self as Self::ObjectReference
29    }
30}
31
32impl<'a> ModulePreset for RemapImports<'a> {
33    fn with_preset(preset: &str) -> Result<Self, ModuleError> {
34        let mut interface_set: Vec<ImportInterface> = Vec::new();
35
36        // Accept a comma-separated list of presets.
37        let presets: String = preset
38            .chars()
39            .filter(|c| *c != '_' && *c != ' ' && *c != '\n' && *c != '\t')
40            .collect();
41        for preset_individual in presets.split(',') {
42            match preset_individual {
43                "ewasm" => interface_set.push(ImportInterface::new(
44                    ImportList::with_preset("ewasm")?,
45                    Some("ethereum_"),
46                )),
47                "eth2" => interface_set.push(ImportInterface::new(
48                    ImportList::with_preset("eth2")?,
49                    Some("eth2_"),
50                )),
51                "debug" => interface_set.push(ImportInterface::new(
52                    ImportList::with_preset("debug")?,
53                    Some("debug_"),
54                )),
55                "bignum" => interface_set.push(ImportInterface::new(
56                    ImportList::with_preset("bignum")?,
57                    Some("bignum_"),
58                )),
59                _ => return Err(ModuleError::NotSupported),
60            }
61        }
62
63        Ok(RemapImports {
64            interfaces: interface_set,
65        })
66    }
67}
68
69impl<'a> ModuleTranslator for RemapImports<'a> {
70    fn translate_inplace(&self, module: &mut Module) -> Result<bool, ModuleError> {
71        let mut was_mutated = false;
72
73        if let Some(section) = module.import_section_mut() {
74            for interface in self.interfaces.iter() {
75                *section = ImportSection::with_entries(
76                    section
77                        .entries()
78                        .iter()
79                        .map(|e| self.remap_from_list(e, &mut was_mutated, interface))
80                        .collect(),
81                );
82            }
83        }
84
85        Ok(was_mutated)
86    }
87
88    fn translate(&self, module: &Module) -> Result<Option<Module>, ModuleError> {
89        let mut new_module = module.clone();
90        let mut was_mutated = false;
91
92        if let Some(section) = new_module.import_section_mut() {
93            // Iterate over entries and remap if needed.
94            for interface in self.interfaces.iter() {
95                *section = ImportSection::with_entries(
96                    section
97                        .entries()
98                        .iter()
99                        .map(|e| self.remap_from_list(e, &mut was_mutated, interface))
100                        .collect(),
101                );
102            }
103        }
104
105        if was_mutated {
106            Ok(Some(new_module))
107        } else {
108            Ok(None)
109        }
110    }
111}
112
113impl<'a> ImportInterface<'a> {
114    pub fn new(imports: ImportList<'a>, prefix: Option<&'a str>) -> Self {
115        ImportInterface(imports, prefix)
116    }
117
118    pub fn prefix(&self) -> Option<&str> {
119        self.1
120    }
121
122    pub fn imports(&self) -> &ImportList<'a> {
123        &self.0
124    }
125}
126
127impl<'a> RemapImports<'a> {
128    // NOTE: 'new()' is currently unused in the library but useful in the future.
129    #[allow(dead_code)]
130    fn new(interfaces: Vec<ImportInterface<'a>>) -> Self {
131        RemapImports {
132            interfaces: interfaces,
133        }
134    }
135
136    /// Takes an import entry and returns either the same entry or a remapped version if it exists.
137    /// Sets the mutation flag if was remapped.
138    fn remap_from_list(
139        &self,
140        entry: &ImportEntry,
141        mutflag: &mut bool,
142        interface: &ImportInterface,
143    ) -> ImportEntry {
144        match interface.prefix() {
145            Some(prefix) => {
146                let prefix_len = prefix.len();
147                if entry.field().len() > prefix_len && prefix == &entry.field()[..prefix_len] {
148                    // Look for a matching remappable import and mutate if found.
149                    if let Some(import) = interface
150                        .imports()
151                        .lookup_by_field(&entry.field()[prefix_len..])
152                    {
153                        *mutflag = true;
154                        return ImportEntry::new(
155                            import.module().into(),
156                            import.field().into(),
157                            entry.external().clone(),
158                        );
159                    }
160                }
161                entry.clone()
162            }
163            None => {
164                if let Some(import) = interface.imports().lookup_by_field(&entry.field()) {
165                    *mutflag = true;
166                    ImportEntry::new(
167                        import.module().into(),
168                        import.field().into(),
169                        entry.external().clone(),
170                    )
171                } else {
172                    entry.clone()
173                }
174            }
175        }
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use rustc_hex::FromHex;
182
183    use super::*;
184    use crate::verifyimports::*;
185    use crate::{ModulePreset, ModuleTranslator, ModuleValidator};
186
187    #[test]
188    fn smoke_test() {
189        let input = FromHex::from_hex(
190            "
191            0061736d0100000001050160017e0002170103656e760f65746865726575
192            6d5f7573654761730000
193        ",
194        )
195        .unwrap();
196        let mut module = Module::from_bytes(&input).unwrap();
197        let did_change = RemapImports::with_preset("ewasm")
198            .unwrap()
199            .translate_inplace(&mut module)
200            .unwrap();
201        let output = module.to_bytes().unwrap();
202        let expected = FromHex::from_hex(
203            "
204            0061736d0100000001050160017e0002130108657468657265756d067573
205            654761730000
206        ",
207        )
208        .unwrap();
209        assert_eq!(output, expected);
210        assert!(did_change);
211    }
212
213    #[test]
214    fn remap_did_mutate() {
215        // wast:
216        // (module
217        //   (import "env" "ethereum_useGas" (func (param i64)))
218        //   (memory 1)
219        //   (export "main" (func $main))
220        //   (export "memory" (memory 0))
221        //
222        //   (func $main)
223        // )
224        let wasm: Vec<u8> = vec![
225            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x01, 0x7e,
226            0x00, 0x60, 0x00, 0x00, 0x02, 0x17, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x0f, 0x65, 0x74,
227            0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x47, 0x61, 0x73, 0x00,
228            0x00, 0x03, 0x02, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07, 0x11, 0x02, 0x04,
229            0x6d, 0x61, 0x69, 0x6e, 0x00, 0x01, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02,
230            0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
231        ];
232
233        let module = Module::from_bytes(&wasm).unwrap();
234
235        let new = RemapImports::with_preset("ewasm")
236            .unwrap()
237            .translate(&module)
238            .expect("Module internal error");
239
240        assert!(new.is_some());
241    }
242
243    #[test]
244    fn remap_did_mutate_verify() {
245        // wast:
246        // (module
247        //   (import "env" "ethereum_useGas" (func (param i64)))
248        //   (memory 1)
249        //   (export "main" (func $main))
250        //   (export "memory" (memory 0))
251        //
252        //   (func $main)
253        // )
254        let wasm: Vec<u8> = vec![
255            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x01, 0x7e,
256            0x00, 0x60, 0x00, 0x00, 0x02, 0x17, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x0f, 0x65, 0x74,
257            0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x47, 0x61, 0x73, 0x00,
258            0x00, 0x03, 0x02, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07, 0x11, 0x02, 0x04,
259            0x6d, 0x61, 0x69, 0x6e, 0x00, 0x01, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02,
260            0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
261        ];
262
263        let module = Module::from_bytes(&wasm).unwrap();
264
265        let new = RemapImports::with_preset("ewasm")
266            .unwrap()
267            .translate(&module)
268            .expect("Module internal error");
269
270        assert!(new.is_some());
271
272        let verified = VerifyImports::with_preset("ewasm")
273            .unwrap()
274            .validate(&new.unwrap())
275            .unwrap();
276
277        assert_eq!(verified, true);
278    }
279
280    #[test]
281    fn remap_did_mutate_verify_explicit_type_section() {
282        // wast:
283        // (module
284        //   (type (;0;) (func (result i64)))
285        //   (import "env" "ethereum_getGasLeft" (func (;0;) (type 0)))
286        //   (memory 1)
287        //   (func $main)
288        //   (export "main" (func $main))
289        //   (export "memory" (memory 0))
290        // )
291
292        let wasm: Vec<u8> = vec![
293            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
294            0x7e, 0x60, 0x00, 0x00, 0x02, 0x1b, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x13, 0x65, 0x74,
295            0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x67, 0x65, 0x74, 0x47, 0x61, 0x73, 0x4c,
296            0x65, 0x66, 0x74, 0x00, 0x00, 0x03, 0x02, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01,
297            0x07, 0x11, 0x02, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x01, 0x06, 0x6d, 0x65, 0x6d,
298            0x6f, 0x72, 0x79, 0x02, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
299        ];
300
301        let module = Module::from_bytes(&wasm).unwrap();
302
303        let new = RemapImports::with_preset("ewasm")
304            .unwrap()
305            .translate(&module)
306            .expect("Module internal error");
307
308        assert!(new.is_some());
309
310        let verified = VerifyImports::with_preset("ewasm")
311            .unwrap()
312            .validate(&new.unwrap())
313            .unwrap();
314
315        assert_eq!(verified, true);
316    }
317
318    #[test]
319    fn remap_mutated_multiple_interfaces() {
320        // wast:
321        // (module
322        //   (type (;0;) (func (result i64)))
323        //   (type (;1;) (func (param i32 i32 i32)))
324        //   (type (;2;) (func (param i32)))
325        //   (import "env" "ethereum_getGasLeft" (func (;0;) (type 0)))
326        //   (import "env" "bignum_mul256" (func (;1;) (type 1)))
327        //   (import "env" "debug_printStorage" (func (;2;) (type 2)))
328        //   (memory 1)
329        //   (func $main)
330        //   (export "main" (func $main))
331        //   (export "memory" (memory 0))
332        // )
333
334        let wasm: Vec<u8> = vec![
335            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x12, 0x04, 0x60, 0x00, 0x01,
336            0x7e, 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x00, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x00, 0x00,
337            0x02, 0x48, 0x03, 0x03, 0x65, 0x6e, 0x76, 0x13, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
338            0x75, 0x6d, 0x5f, 0x67, 0x65, 0x74, 0x47, 0x61, 0x73, 0x4c, 0x65, 0x66, 0x74, 0x00,
339            0x00, 0x03, 0x65, 0x6e, 0x76, 0x0d, 0x62, 0x69, 0x67, 0x6e, 0x75, 0x6d, 0x5f, 0x6d,
340            0x75, 0x6c, 0x32, 0x35, 0x36, 0x00, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x64, 0x65,
341            0x62, 0x75, 0x67, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61,
342            0x67, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x03, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07,
343            0x11, 0x02, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x03, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
344            0x72, 0x79, 0x02, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
345        ];
346
347        let module = Module::from_bytes(&wasm).unwrap();
348
349        let new = RemapImports::with_preset("ewasm, bignum, debug")
350            .unwrap()
351            .translate(&module)
352            .expect("Module internal error")
353            .expect("Module was not mutated");
354
355        let verifier = VerifyImports::with_preset("ewasm, bignum, debug").unwrap();
356
357        assert_eq!(verifier.validate(&new), Ok(true));
358    }
359
360    #[test]
361    fn no_prefix() {
362        // wast:
363        // (module
364        //   (type (;0;) (func (result i64)))
365        //   (type (;1;) (func (param i32 i32 i32)))
366        //   (type (;2;) (func (param i32)))
367        //   (import "env" "getGasLeft" (func (;0;) (type 0)))
368        //   (import "env" "mul256" (func (;1;) (type 1)))
369        //   (import "env" "printStorage" (func (;2;) (type 2)))
370        //   (memory 1)
371        //   (func $main)
372        //   (export "main" (func $main))
373        //   (export "memory" (memory 0))
374        // )
375
376        let wasm: Vec<u8> = vec![
377            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x12, 0x04, 0x60, 0x00, 0x01,
378            0x7e, 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x00, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x00, 0x00,
379            0x02, 0x32, 0x03, 0x03, 0x65, 0x6e, 0x76, 0x0a, 0x67, 0x65, 0x74, 0x47, 0x61, 0x73,
380            0x4c, 0x65, 0x66, 0x74, 0x00, 0x00, 0x03, 0x65, 0x6e, 0x76, 0x06, 0x6d, 0x75, 0x6c,
381            0x32, 0x35, 0x36, 0x00, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x0c, 0x70, 0x72, 0x69, 0x6e,
382            0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x03,
383            0x05, 0x03, 0x01, 0x00, 0x01, 0x07, 0x11, 0x02, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x00,
384            0x03, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x0a, 0x04, 0x01, 0x02,
385            0x00, 0x0b,
386        ];
387
388        let module = Module::from_bytes(&wasm).unwrap();
389
390        let interfaces_noprefix = vec![
391            ImportInterface::new(ImportList::with_preset("ewasm").unwrap(), None),
392            ImportInterface::new(ImportList::with_preset("bignum").unwrap(), None),
393            ImportInterface::new(ImportList::with_preset("debug").unwrap(), None),
394        ];
395
396        let new = RemapImports::new(interfaces_noprefix)
397            .translate(&module)
398            .expect("Module internal error")
399            .expect("Module was not mutated");
400
401        let verifier = VerifyImports::with_preset("ewasm, bignum, debug").unwrap();
402
403        assert_eq!(verifier.validate(&new), Ok(true));
404    }
405}