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 group in types { 135 for ty in group?.into_types() { 136 match ty.composite_type { 137 ty @ wasmparser::CompositeType::Func(_) => { 138 module.push_type(cx, ty); 139 } 140 wasmparser::CompositeType::Array(_) => todo!(), 141 wasmparser::CompositeType::Struct(_) => todo!(), 142 } 143 } 144 } 145 146 Ok(()) 147 } 148 149 fn import_section<'a>( 150 cx: &mut ModuleContext<'a>, 151 stack: &mut Vec<StackEntry>, 152 full_wasm: &'a [u8], 153 imports: wasmparser::ImportSectionReader<'a>, 154 ) -> anyhow::Result<()> { 155 let module = stack.top().module; 156 stack 157 .top_mut() 158 .module 159 .add_raw_section(cx, SectionId::Import, imports.range(), full_wasm); 160 161 // Check that we can properly handle all imports. 162 for imp in imports { 163 let imp = imp?; 164 165 if imp.module.starts_with("__wizer_") || imp.name.starts_with("__wizer_") { 166 anyhow::bail!( 167 "input Wasm module already imports entities named with the `__wizer_*` prefix" 168 ); 169 } 170 171 check_import_type( 172 cx, 173 stack.top().module.types(cx), 174 stack.top().module.is_root(), 175 &module.entity_type(cx, imp.ty), 176 )?; 177 module.push_import(cx, imp); 178 } 179 Ok(()) 180 } 181 182 fn check_import_type( 183 _cx: &ModuleContext, 184 _types: &[TypeId], 185 is_root: bool, 186 ty: &EntityType, 187 ) -> Result<()> { 188 match ty { 189 EntityType::Function(_) => Ok(()), 190 EntityType::Memory(mem_ty) => { 191 anyhow::ensure!( 192 !mem_ty.shared, 193 "shared memories are not supported by Wizer yet" 194 ); 195 anyhow::ensure!( 196 !mem_ty.memory64, 197 "the memory64 proposal is not supported by Wizer yet" 198 ); 199 anyhow::ensure!( 200 !is_root, 201 "memory imports are not allowed in the root Wasm module" 202 ); 203 Ok(()) 204 } 205 EntityType::Table(_) | EntityType::Global(_) => { 206 anyhow::ensure!( 207 !is_root, 208 "table and global imports are not allowed in the root Wasm module" 209 ); 210 Ok(()) 211 } 212 } 213 } 214 215 fn function_section<'a>( 216 cx: &mut ModuleContext<'a>, 217 stack: &mut Vec<StackEntry>, 218 full_wasm: &'a [u8], 219 funcs: wasmparser::FunctionSectionReader<'a>, 220 ) -> anyhow::Result<()> { 221 let module = stack.top().module; 222 module.add_raw_section(cx, SectionId::Function, funcs.range(), full_wasm); 223 224 for ty_idx in funcs { 225 let ty = module.type_id_at(cx, ty_idx?); 226 module.push_function(cx, ty); 227 } 228 Ok(()) 229 } 230 231 fn table_section<'a>( 232 cx: &mut ModuleContext<'a>, 233 stack: &mut Vec<StackEntry>, 234 full_wasm: &'a [u8], 235 tables: wasmparser::TableSectionReader<'a>, 236 ) -> anyhow::Result<()> { 237 let module = stack.top().module; 238 module.add_raw_section(cx, SectionId::Table, tables.range(), full_wasm); 239 240 for table in tables { 241 module.push_table(cx, table?.ty); 242 } 243 Ok(()) 244 } 245 246 fn memory_section<'a>( 247 cx: &mut ModuleContext<'a>, 248 stack: &mut Vec<StackEntry>, 249 full_wasm: &'a [u8], 250 mems: wasmparser::MemorySectionReader<'a>, 251 ) -> anyhow::Result<()> { 252 let module = stack.top().module; 253 module.add_raw_section(cx, SectionId::Memory, mems.range(), full_wasm); 254 255 for m in mems { 256 module.push_defined_memory(cx, m?); 257 } 258 Ok(()) 259 } 260 261 fn global_section<'a>( 262 cx: &mut ModuleContext<'a>, 263 stack: &mut Vec<StackEntry>, 264 full_wasm: &'a [u8], 265 globals: wasmparser::GlobalSectionReader<'a>, 266 ) -> anyhow::Result<()> { 267 let module = stack.top().module; 268 module.add_raw_section(cx, SectionId::Global, globals.range(), full_wasm); 269 270 for g in globals { 271 module.push_defined_global(cx, g?.ty); 272 } 273 Ok(()) 274 } 275 276 fn export_section<'a>( 277 cx: &mut ModuleContext<'a>, 278 stack: &mut Vec<StackEntry>, 279 full_wasm: &'a [u8], 280 exports: wasmparser::ExportSectionReader<'a>, 281 ) -> anyhow::Result<()> { 282 let module = stack.top().module; 283 module.add_raw_section(cx, SectionId::Export, exports.range(), full_wasm); 284 285 for export in exports { 286 let export = export?; 287 288 if export.name.starts_with("__wizer_") { 289 anyhow::bail!( 290 "input Wasm module already exports entities named with the `__wizer_*` prefix" 291 ); 292 } 293 294 match export.kind { 295 wasmparser::ExternalKind::Tag => { 296 unreachable!("checked in validation") 297 } 298 wasmparser::ExternalKind::Func 299 | wasmparser::ExternalKind::Table 300 | wasmparser::ExternalKind::Memory 301 | wasmparser::ExternalKind::Global => { 302 module.push_export(cx, export); 303 } 304 } 305 } 306 Ok(()) 307 } 308