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