1 use crate::info::{ 2 types_interner::{EntityType, TypeId}, 3 Module, ModuleContext, 4 }; 5 use crate::stack_ext::StackExt; 6 use anyhow::{Context, Result}; 7 use std::convert::TryFrom; 8 use wasm_encoder::SectionId; 9 10 struct StackEntry { 11 parser: wasmparser::Parser, 12 module: Module, 13 } 14 15 /// Parse the given Wasm bytes into a `ModuleInfo` tree. 16 pub(crate) fn parse<'a>(full_wasm: &'a [u8]) -> anyhow::Result<ModuleContext<'a>> { 17 log::debug!("Parsing the input Wasm"); 18 19 let mut cx = ModuleContext::new(); 20 21 // The wasm we are currently parsing. This is advanced as the parser 22 // consumes input. 23 let mut wasm = full_wasm; 24 25 let mut stack = vec![StackEntry { 26 parser: wasmparser::Parser::new(0), 27 module: cx.root(), 28 }]; 29 30 loop { 31 let (payload, consumed) = match stack 32 .top_mut() 33 .parser 34 .parse(wasm, true) 35 .context("failed to parse Wasm")? 36 { 37 wasmparser::Chunk::NeedMoreData(_) => unreachable!(), 38 wasmparser::Chunk::Parsed { payload, consumed } => (payload, consumed), 39 }; 40 wasm = &wasm[consumed..]; 41 42 use wasmparser::Payload::*; 43 match payload { 44 Version { .. } => {} 45 TypeSection(types) => type_section(&mut cx, &mut stack, full_wasm, types)?, 46 ImportSection(imports) => import_section(&mut cx, &mut stack, full_wasm, imports)?, 47 FunctionSection(funcs) => function_section(&mut cx, &mut stack, full_wasm, funcs)?, 48 TableSection(tables) => table_section(&mut cx, &mut stack, full_wasm, tables)?, 49 MemorySection(mems) => memory_section(&mut cx, &mut stack, full_wasm, mems)?, 50 GlobalSection(globals) => global_section(&mut cx, &mut stack, full_wasm, globals)?, 51 ExportSection(exports) => export_section(&mut cx, &mut stack, full_wasm, exports)?, 52 StartSection { func: _, range } => { 53 stack 54 .top_mut() 55 .module 56 .add_raw_section(&mut cx, SectionId::Start, range, full_wasm) 57 } 58 ElementSection(elems) => stack.top_mut().module.add_raw_section( 59 &mut cx, 60 SectionId::Element, 61 elems.range(), 62 full_wasm, 63 ), 64 DataCountSection { range, .. } => stack.top_mut().module.add_raw_section( 65 &mut cx, 66 SectionId::DataCount, 67 range, 68 full_wasm, 69 ), 70 DataSection(data) => stack.top_mut().module.add_raw_section( 71 &mut cx, 72 SectionId::Data, 73 data.range(), 74 full_wasm, 75 ), 76 CustomSection(c) => stack.top_mut().module.add_raw_section( 77 &mut cx, 78 SectionId::Custom, 79 c.range(), 80 full_wasm, 81 ), 82 CodeSectionStart { 83 range, 84 count: _, 85 size, 86 } => { 87 wasm = &wasm[usize::try_from(size).unwrap()..]; 88 let entry = stack.top_mut(); 89 entry.parser.skip_section(); 90 entry 91 .module 92 .add_raw_section(&mut cx, SectionId::Code, range, full_wasm) 93 } 94 CodeSectionEntry(_) => unreachable!(), 95 UnknownSection { .. } => anyhow::bail!("unknown section"), 96 TagSection(_) => anyhow::bail!("exceptions are not supported yet"), 97 End(_) => { 98 let entry = stack.pop().unwrap(); 99 100 // If we finished parsing the root Wasm module, then we're done. 101 assert!(entry.module.is_root()); 102 assert!(stack.is_empty()); 103 return Ok(cx); 104 } 105 106 ComponentTypeSection(_) 107 | ComponentImportSection(_) 108 | ComponentExportSection(_) 109 | ComponentStartSection { .. } 110 | ComponentAliasSection(_) 111 | CoreTypeSection(_) 112 | InstanceSection(_) 113 | ComponentInstanceSection(_) 114 | ComponentCanonicalSection(_) 115 | ModuleSection { .. } 116 | ComponentSection { .. } => { 117 unreachable!() 118 } 119 } 120 } 121 } 122 123 fn type_section<'a>( 124 cx: &mut ModuleContext<'a>, 125 stack: &mut Vec<StackEntry>, 126 full_wasm: &'a [u8], 127 types: wasmparser::TypeSectionReader<'a>, 128 ) -> anyhow::Result<()> { 129 let module = stack.top().module; 130 module.add_raw_section(cx, SectionId::Type, types.range(), full_wasm); 131 132 // Parse out types, as we will need them later when processing 133 // instance imports. 134 for ty in types { 135 match ty? { 136 ty @ wasmparser::Type::Func(_) => { 137 module.push_type(cx, ty); 138 } 139 } 140 } 141 142 Ok(()) 143 } 144 145 fn import_section<'a>( 146 cx: &mut ModuleContext<'a>, 147 stack: &mut Vec<StackEntry>, 148 full_wasm: &'a [u8], 149 imports: wasmparser::ImportSectionReader<'a>, 150 ) -> anyhow::Result<()> { 151 let module = stack.top().module; 152 stack 153 .top_mut() 154 .module 155 .add_raw_section(cx, SectionId::Import, imports.range(), full_wasm); 156 157 // Check that we can properly handle all imports. 158 for imp in imports { 159 let imp = imp?; 160 161 if imp.module.starts_with("__wizer_") || imp.name.starts_with("__wizer_") { 162 anyhow::bail!( 163 "input Wasm module already imports entities named with the `__wizer_*` prefix" 164 ); 165 } 166 167 check_import_type( 168 cx, 169 stack.top().module.types(cx), 170 stack.top().module.is_root(), 171 &module.entity_type(cx, imp.ty), 172 )?; 173 module.push_import(cx, imp); 174 } 175 Ok(()) 176 } 177 178 fn check_import_type( 179 _cx: &ModuleContext, 180 _types: &[TypeId], 181 is_root: bool, 182 ty: &EntityType, 183 ) -> Result<()> { 184 match ty { 185 EntityType::Function(_) => Ok(()), 186 EntityType::Memory(mem_ty) => { 187 anyhow::ensure!( 188 !mem_ty.shared, 189 "shared memories are not supported by Wizer yet" 190 ); 191 anyhow::ensure!( 192 !mem_ty.memory64, 193 "the memory64 proposal is not supported by Wizer yet" 194 ); 195 anyhow::ensure!( 196 !is_root, 197 "memory imports are not allowed in the root Wasm module" 198 ); 199 Ok(()) 200 } 201 EntityType::Table(_) | EntityType::Global(_) => { 202 anyhow::ensure!( 203 !is_root, 204 "table and global imports are not allowed in the root Wasm module" 205 ); 206 Ok(()) 207 } 208 } 209 } 210 211 fn function_section<'a>( 212 cx: &mut ModuleContext<'a>, 213 stack: &mut Vec<StackEntry>, 214 full_wasm: &'a [u8], 215 funcs: wasmparser::FunctionSectionReader<'a>, 216 ) -> anyhow::Result<()> { 217 let module = stack.top().module; 218 module.add_raw_section(cx, SectionId::Function, funcs.range(), full_wasm); 219 220 for ty_idx in funcs { 221 let ty = module.type_id_at(cx, ty_idx?); 222 module.push_function(cx, ty); 223 } 224 Ok(()) 225 } 226 227 fn table_section<'a>( 228 cx: &mut ModuleContext<'a>, 229 stack: &mut Vec<StackEntry>, 230 full_wasm: &'a [u8], 231 tables: wasmparser::TableSectionReader<'a>, 232 ) -> anyhow::Result<()> { 233 let module = stack.top().module; 234 module.add_raw_section(cx, SectionId::Table, tables.range(), full_wasm); 235 236 for table in tables { 237 module.push_table(cx, table?.ty); 238 } 239 Ok(()) 240 } 241 242 fn memory_section<'a>( 243 cx: &mut ModuleContext<'a>, 244 stack: &mut Vec<StackEntry>, 245 full_wasm: &'a [u8], 246 mems: wasmparser::MemorySectionReader<'a>, 247 ) -> anyhow::Result<()> { 248 let module = stack.top().module; 249 module.add_raw_section(cx, SectionId::Memory, mems.range(), full_wasm); 250 251 for m in mems { 252 module.push_defined_memory(cx, m?); 253 } 254 Ok(()) 255 } 256 257 fn global_section<'a>( 258 cx: &mut ModuleContext<'a>, 259 stack: &mut Vec<StackEntry>, 260 full_wasm: &'a [u8], 261 globals: wasmparser::GlobalSectionReader<'a>, 262 ) -> anyhow::Result<()> { 263 let module = stack.top().module; 264 module.add_raw_section(cx, SectionId::Global, globals.range(), full_wasm); 265 266 for g in globals { 267 module.push_defined_global(cx, g?.ty); 268 } 269 Ok(()) 270 } 271 272 fn export_section<'a>( 273 cx: &mut ModuleContext<'a>, 274 stack: &mut Vec<StackEntry>, 275 full_wasm: &'a [u8], 276 exports: wasmparser::ExportSectionReader<'a>, 277 ) -> anyhow::Result<()> { 278 let module = stack.top().module; 279 module.add_raw_section(cx, SectionId::Export, exports.range(), full_wasm); 280 281 for export in exports { 282 let export = export?; 283 284 if export.name.starts_with("__wizer_") { 285 anyhow::bail!( 286 "input Wasm module already exports entities named with the `__wizer_*` prefix" 287 ); 288 } 289 290 match export.kind { 291 wasmparser::ExternalKind::Tag => { 292 unreachable!("checked in validation") 293 } 294 wasmparser::ExternalKind::Func 295 | wasmparser::ExternalKind::Table 296 | wasmparser::ExternalKind::Memory 297 | wasmparser::ExternalKind::Global => { 298 module.push_export(cx, export); 299 } 300 } 301 } 302 Ok(()) 303 } 304