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 interfaces: Vec<ImportInterface<'a>>,
10}
11
12pub 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 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 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 #[allow(dead_code)]
130 fn new(interfaces: Vec<ImportInterface<'a>>) -> Self {
131 RemapImports {
132 interfaces: interfaces,
133 }
134 }
135
136 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 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 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 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 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 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 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}