1 use crate::info::ModuleContext; 2 use anyhow::{Context, bail}; 3 use wasmparser::{Encoding, Parser}; 4 5 /// Parse the given Wasm bytes into a `ModuleInfo` tree. 6 pub(crate) fn parse<'a>(full_wasm: &'a [u8]) -> anyhow::Result<ModuleContext<'a>> { 7 parse_with(full_wasm, &mut Parser::new(0).parse_all(full_wasm)) 8 } 9 10 pub(crate) fn parse_with<'a>( 11 full_wasm: &'a [u8], 12 payloads: &mut impl Iterator<Item = wasmparser::Result<wasmparser::Payload<'a>>>, 13 ) -> anyhow::Result<ModuleContext<'a>> { 14 log::debug!("Parsing the input Wasm"); 15 16 let mut module = ModuleContext::default(); 17 18 while let Some(payload) = payloads.next() { 19 use wasmparser::Payload::*; 20 21 let payload = payload.context("failed to parse Wasm")?; 22 23 if let Some((id, range)) = payload.as_section() { 24 module.add_raw_section(id, range, full_wasm); 25 } 26 27 match payload { 28 Version { 29 encoding: Encoding::Component, 30 .. 31 } => { 32 bail!("expected a core module, found a component"); 33 } 34 ImportSection(imports) => import_section(&mut module, imports)?, 35 FunctionSection(funcs) => function_section(&mut module, funcs)?, 36 TableSection(tables) => table_section(&mut module, tables)?, 37 MemorySection(mems) => memory_section(&mut module, mems)?, 38 GlobalSection(globals) => global_section(&mut module, globals)?, 39 ExportSection(exports) => export_section(&mut module, exports)?, 40 End { .. } => break, 41 _ => {} 42 } 43 } 44 45 Ok(module) 46 } 47 48 fn import_section<'a>( 49 module: &mut ModuleContext<'a>, 50 imports: wasmparser::ImportSectionReader<'a>, 51 ) -> anyhow::Result<()> { 52 // Check that we can properly handle all imports. 53 for imp in imports { 54 let imp = imp?; 55 56 if imp.module.starts_with("__wizer_") || imp.name.starts_with("__wizer_") { 57 anyhow::bail!( 58 "input Wasm module already imports entities named with the `__wizer_*` prefix" 59 ); 60 } 61 62 module.push_import(imp); 63 } 64 Ok(()) 65 } 66 67 fn function_section<'a>( 68 module: &mut ModuleContext<'a>, 69 funcs: wasmparser::FunctionSectionReader<'a>, 70 ) -> anyhow::Result<()> { 71 for ty_idx in funcs { 72 module.push_function(ty_idx?); 73 } 74 Ok(()) 75 } 76 77 fn table_section<'a>( 78 module: &mut ModuleContext<'a>, 79 tables: wasmparser::TableSectionReader<'a>, 80 ) -> anyhow::Result<()> { 81 for table in tables { 82 module.push_table(table?.ty); 83 } 84 Ok(()) 85 } 86 87 fn memory_section<'a>( 88 module: &mut ModuleContext<'a>, 89 mems: wasmparser::MemorySectionReader<'a>, 90 ) -> anyhow::Result<()> { 91 for m in mems { 92 module.push_defined_memory(m?); 93 } 94 Ok(()) 95 } 96 97 fn global_section<'a>( 98 module: &mut ModuleContext<'a>, 99 globals: wasmparser::GlobalSectionReader<'a>, 100 ) -> anyhow::Result<()> { 101 for g in globals { 102 module.push_defined_global(g?.ty); 103 } 104 Ok(()) 105 } 106 107 fn export_section<'a>( 108 module: &mut ModuleContext<'a>, 109 exports: wasmparser::ExportSectionReader<'a>, 110 ) -> anyhow::Result<()> { 111 for export in exports { 112 let export = export?; 113 114 if export.name.starts_with("__wizer_") { 115 anyhow::bail!( 116 "input Wasm module already exports entities named with the `__wizer_*` prefix" 117 ); 118 } 119 120 match export.kind { 121 wasmparser::ExternalKind::Tag 122 | wasmparser::ExternalKind::Func 123 | wasmparser::ExternalKind::FuncExact 124 | wasmparser::ExternalKind::Table 125 | wasmparser::ExternalKind::Memory 126 | wasmparser::ExternalKind::Global => { 127 module.push_export(export); 128 } 129 } 130 } 131 Ok(()) 132 } 133