wasmdbg/wasm/
mod.rs

1use std::fmt;
2use std::iter::{self, FromIterator};
3
4use failure::Fail;
5use parity_wasm::elements as pwasm;
6pub use parity_wasm::elements::{
7    CustomSection, ExportEntry, External, GlobalType, ImportEntry, Instruction, Internal,
8    MemoryType, ResizableLimits, TableType, ValueType,
9};
10pub use parity_wasm::SerializationError;
11pub use wasmi_validation::Error as ValidationError;
12
13use crate::value::Value;
14use crate::wasi::WasiFunction;
15
16pub const PAGE_SIZE: u32 = 64 * 1024; // 64 KiB
17
18#[derive(Debug, Fail)]
19pub enum LoadError {
20    #[fail(display = "Error while loading file: {}", _0)]
21    SerializationError(#[fail(cause)] SerializationError),
22    #[fail(display = "Error while validating file: {}", _0)]
23    ValidationError(#[fail(cause)] ValidationError),
24}
25
26#[derive(Clone)]
27pub struct FunctionType {
28    type_ref: u32,
29    params: Vec<ValueType>,
30    return_type: Option<ValueType>,
31}
32
33impl FunctionType {
34    fn new(type_ref: u32, func_type: &pwasm::FunctionType) -> Self {
35        FunctionType {
36            type_ref,
37            params: Vec::from(func_type.params()),
38            return_type: func_type.return_type(),
39        }
40    }
41    pub fn type_ref(&self) -> u32 {
42        self.type_ref
43    }
44    pub fn params(&self) -> &[ValueType] {
45        &self.params
46    }
47    pub fn return_type(&self) -> Option<ValueType> {
48        self.return_type
49    }
50}
51
52impl fmt::Display for FunctionType {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        let params = self
55            .params
56            .iter()
57            .map(|t| t.to_string())
58            .collect::<Vec<String>>()
59            .join(", ");
60        let return_type = match self.return_type {
61            Some(return_type) => return_type.to_string(),
62            None => String::from("()"),
63        };
64        write!(f, "fn ({}) -> {}", params, return_type)
65    }
66}
67
68pub struct Function {
69    name: String,
70    func_type: FunctionType,
71    is_imported: bool,
72    wasi_function: Option<WasiFunction>,
73    locals: Vec<ValueType>,
74    instructions: Vec<Instruction>,
75}
76
77impl Function {
78    fn new(
79        name: String,
80        func_type: FunctionType,
81        locals: Vec<ValueType>,
82        instructions: Vec<Instruction>,
83    ) -> Self {
84        Function {
85            name,
86            func_type,
87            is_imported: false,
88            wasi_function: None,
89            locals,
90            instructions,
91        }
92    }
93
94    fn new_imported(name: String, func_type: FunctionType) -> Self {
95        let wasi_function = if name.starts_with("wasi_unstable.") {
96            // TODO: Check type
97            WasiFunction::from_name(&name["wasi_unstable.".len()..])
98        } else {
99            None
100        };
101        Function {
102            name,
103            func_type,
104            is_imported: true,
105            wasi_function,
106            locals: Vec::with_capacity(0),
107            instructions: Vec::with_capacity(0),
108        }
109    }
110
111    pub fn name(&self) -> &str {
112        &self.name
113    }
114    pub fn func_type(&self) -> &FunctionType {
115        &self.func_type
116    }
117    pub fn is_imported(&self) -> bool {
118        self.is_imported
119    }
120    pub fn wasi_function(&self) -> Option<WasiFunction> {
121        self.wasi_function
122    }
123    pub fn locals(&self) -> &[ValueType] {
124        &self.locals
125    }
126    pub fn instructions(&self) -> &[Instruction] {
127        &self.instructions
128    }
129}
130
131impl fmt::Display for Function {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(f, "fn {}{}", self.name, &self.func_type.to_string()[3..])
134    }
135}
136
137pub enum InitExpr {
138    Const(Value),
139    Global(u32),
140}
141
142impl From<&pwasm::InitExpr> for InitExpr {
143    fn from(init_expr: &pwasm::InitExpr) -> Self {
144        let instrs = init_expr.code();
145        assert!(
146            instrs.len() == 2,
147            "Init expr has invalid length: {}",
148            instrs.len()
149        );
150        assert!(
151            instrs[1] == Instruction::End,
152            "Init expr has multiple instructions"
153        );
154        match &instrs[0] {
155            Instruction::I32Const(val) => InitExpr::Const((*val).into()),
156            Instruction::I64Const(val) => InitExpr::Const((*val).into()),
157            Instruction::F32Const(val) => InitExpr::Const((*val).into()),
158            Instruction::F64Const(val) => InitExpr::Const((*val).into()),
159            Instruction::GetGlobal(index) => InitExpr::Global(*index),
160            other => panic!("Invalid instruction in init expr: {}", other),
161        }
162    }
163}
164
165pub struct Global {
166    name: String,
167    is_imported: bool,
168    is_mutable: bool,
169    value_type: ValueType,
170    init_expr: InitExpr,
171}
172
173impl Global {
174    fn from_parity(name: String, global: &pwasm::GlobalEntry) -> Self {
175        let global_type = global.global_type();
176        Global {
177            name,
178            is_imported: false,
179            is_mutable: global_type.is_mutable(),
180            value_type: global_type.content_type(),
181            init_expr: global.init_expr().into(),
182        }
183    }
184    pub fn name(&self) -> &str {
185        &self.name
186    }
187    pub fn is_imported(&self) -> bool {
188        self.is_imported
189    }
190    pub fn is_mutable(&self) -> bool {
191        self.is_mutable
192    }
193    pub fn value_type(&self) -> ValueType {
194        self.value_type
195    }
196    pub fn init_expr(&self) -> &InitExpr {
197        &self.init_expr
198    }
199}
200
201impl fmt::Display for Global {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        let const_str = if self.is_mutable() { "mut  " } else { "const" };
204        let init_str = match self.init_expr() {
205            InitExpr::Const(val) => format!("{}", val),
206            InitExpr::Global(index) => format!("global {}", index),
207        };
208        write!(f, "{} {:15} = {}", const_str, self.name(), init_str)
209    }
210}
211
212pub struct ElementSegment {
213    index: u32,
214    offset: InitExpr,
215    members: Vec<u32>,
216}
217
218impl ElementSegment {
219    pub fn index(&self) -> u32 {
220        self.index
221    }
222    pub fn offset(&self) -> &InitExpr {
223        &self.offset
224    }
225    pub fn members(&self) -> &[u32] {
226        &self.members
227    }
228}
229
230impl From<&pwasm::ElementSegment> for ElementSegment {
231    fn from(seg: &pwasm::ElementSegment) -> Self {
232        ElementSegment {
233            index: seg.index(),
234            offset: seg.offset().as_ref().unwrap().into(),
235            members: Vec::from(seg.members()),
236        }
237    }
238}
239
240pub struct DataSegment {
241    index: u32,
242    offset: InitExpr,
243    value: Vec<u8>,
244}
245
246impl DataSegment {
247    pub fn index(&self) -> u32 {
248        self.index
249    }
250    pub fn offset(&self) -> &InitExpr {
251        &self.offset
252    }
253    pub fn value(&self) -> &[u8] {
254        &self.value
255    }
256}
257
258impl From<&pwasm::DataSegment> for DataSegment {
259    fn from(seg: &pwasm::DataSegment) -> Self {
260        DataSegment {
261            index: seg.index(),
262            offset: seg.offset().as_ref().unwrap().into(),
263            value: Vec::from(seg.value()),
264        }
265    }
266}
267
268pub struct Module {
269    types: Vec<FunctionType>,
270    imports: Vec<ImportEntry>,
271    exports: Vec<ExportEntry>,
272    functions: Vec<Function>,
273    globals: Vec<Global>,
274    tables: Vec<TableType>,
275    memories: Vec<MemoryType>,
276    element_entries: Vec<ElementSegment>,
277    data_entries: Vec<DataSegment>,
278    start_func: Option<u32>,
279    custom_sections: Vec<CustomSection>,
280}
281
282impl Module {
283    pub fn from_file(file_path: &str) -> Result<Self, LoadError> {
284        match parity_wasm::deserialize_file(file_path) {
285            Ok(module) => {
286                if let Err(error) =
287                    wasmi_validation::validate_module::<wasmi_validation::PlainValidator>(&module)
288                {
289                    return Err(LoadError::ValidationError(error));
290                }
291                Ok(Module::from_parity_module(module))
292            }
293            Err(error) => Err(LoadError::SerializationError(error)),
294        }
295    }
296
297    fn from_parity_module(module: parity_wasm::elements::Module) -> Self {
298        // TODO: What happens when multiple functions have the same name?
299        let module = match module.parse_names() {
300            Ok(module) => module,
301            Err((errors, module)) => {
302                for (_, error) in errors {
303                    println!("Failed to parse name section: {}", error);
304                }
305                module
306            }
307        };
308
309        let mut types = Vec::new();
310        if let Some(type_sec) = module.type_section() {
311            for (i, t) in type_sec.types().iter().enumerate() {
312                let pwasm::Type::Function(func_type) = t;
313                types.push(FunctionType::new(i as u32, func_type));
314            }
315        }
316
317        let mut globals = Vec::new();
318        if let Some(global_sec) = module.global_section() {
319            for (i, global) in global_sec.entries().iter().enumerate() {
320                let name = format!("g{}", i);
321                globals.push(Global::from_parity(name, global));
322            }
323        }
324
325        let mut element_entries = Vec::new();
326        if let Some(element_sec) = module.elements_section() {
327            for entry in element_sec.entries() {
328                element_entries.push(entry.into());
329            }
330        }
331
332        let mut data_entries = Vec::new();
333        if let Some(data_sec) = module.data_section() {
334            for entry in data_sec.entries() {
335                data_entries.push(entry.into());
336            }
337        }
338
339        let func_count = module
340            .function_section()
341            .map(|sec| sec.entries().len())
342            .unwrap_or(0);
343        let mut functions = Vec::with_capacity(func_count);
344
345        if let Some(import_sec) = module.import_section() {
346            for entry in import_sec.entries() {
347                if let pwasm::External::Function(type_ref) = entry.external() {
348                    let name = format!("{}.{}", entry.module(), entry.field());
349                    let func_type = types[*type_ref as usize].clone();
350                    functions.push(Function::new_imported(name, func_type))
351                } else {
352                    println!("Unsupported import: {:?}", entry);
353                }
354            }
355        }
356
357        if let Some(func_sec) = module.function_section() {
358            let func_bodies = module.code_section().map(|sec| sec.bodies()).unwrap_or(&[]);
359            for (type_ref, body) in func_sec.entries().iter().zip(func_bodies.iter()) {
360                let type_ref = type_ref.type_ref();
361                let name = format!("f{}", functions.len());
362                let func_type = types[type_ref as usize].clone();
363                let locals = body
364                    .locals()
365                    .iter()
366                    .flat_map(|locals| {
367                        iter::repeat(locals.value_type()).take(locals.count() as usize)
368                    })
369                    .collect();
370                let instructions = Vec::from(body.code().elements());
371                functions.push(Function::new(name, func_type, locals, instructions));
372            }
373        }
374
375        let imports = Vec::from(
376            module
377                .import_section()
378                .map(|sec| sec.entries())
379                .unwrap_or(&[]),
380        );
381        let exports = Vec::from(
382            module
383                .export_section()
384                .map(|sec| sec.entries())
385                .unwrap_or(&[]),
386        );
387        let tables = Vec::from(
388            module
389                .table_section()
390                .map(|sec| sec.entries())
391                .unwrap_or(&[]),
392        );
393        let memories = Vec::from(
394            module
395                .memory_section()
396                .map(|sec| sec.entries())
397                .unwrap_or(&[]),
398        );
399
400        for export in &exports {
401            match export.internal() {
402                Internal::Function(index) => {
403                    functions[*index as usize].name = export.field().to_string()
404                }
405                Internal::Global(index) => {
406                    globals[*index as usize].name = export.field().to_string()
407                }
408                _ => (),
409            }
410        }
411
412        if let Some(name_sec) = module.names_section() {
413            if let Some(func_names) = name_sec.functions() {
414                for (i, name) in func_names.names() {
415                    functions[i as usize].name = name.clone();
416                }
417            }
418        }
419
420        let start_func = module.start_section().or_else(|| {
421            for export in &exports {
422                if export.field() == "_start" {
423                    if let Internal::Function(index) = export.internal() {
424                        let index = *index;
425                        let func_type = functions[index as usize].func_type();
426                        if func_type.params().is_empty() && func_type.return_type().is_none() {
427                            return Some(index);
428                        }
429                    }
430                }
431            }
432            None
433        });
434
435        Module {
436            types,
437            imports,
438            exports,
439            functions,
440            globals,
441            tables,
442            memories,
443            element_entries,
444            data_entries,
445            start_func,
446            custom_sections: Vec::from_iter(module.custom_sections().cloned()),
447        }
448    }
449
450    pub fn types(&self) -> &[FunctionType] {
451        &self.types
452    }
453
454    pub fn imports(&self) -> &[ImportEntry] {
455        &self.imports
456    }
457
458    pub fn exports(&self) -> &[ExportEntry] {
459        &self.exports
460    }
461
462    pub fn functions(&self) -> &[Function] {
463        &self.functions
464    }
465
466    pub fn get_func(&self, index: u32) -> Option<&Function> {
467        self.functions.get(index as usize)
468    }
469
470    pub fn globals(&self) -> &[Global] {
471        &self.globals
472    }
473
474    pub fn tables(&self) -> &[TableType] {
475        &self.tables
476    }
477
478    pub fn memories(&self) -> &[MemoryType] {
479        &self.memories
480    }
481
482    pub fn element_entries(&self) -> &[ElementSegment] {
483        &self.element_entries
484    }
485
486    pub fn data_entries(&self) -> &[DataSegment] {
487        &self.data_entries
488    }
489
490    pub fn start_func(&self) -> Option<u32> {
491        self.start_func
492    }
493
494    pub fn custom_sections(&self) -> &[CustomSection] {
495        &self.custom_sections
496    }
497}