1use crate::ast::const_expr::ConstExpr;
2use crate::ast::custom::CustomSection;
3use crate::ast::data::{Data, DataKind};
4use crate::ast::elements::{Element, ElementItems, ElementKind};
5use crate::ast::exports::{Export, ExternalKind};
6use crate::ast::functions::{Func, FuncBody, FuncBodyDef};
7use crate::ast::globals::Global;
8use crate::ast::imports::{Import, ImportType, TagKind, TagType};
9use crate::ast::instructions::Instruction;
10use crate::ast::memories::Memory;
11use crate::ast::module::Module;
12use crate::ast::tables::Table;
13use crate::ast::tags::Tag;
14use crate::ast::types::{
15 ArrayType, CompositeInnerType, CompositeType, ContType, FieldType, FuncType, RecGroup,
16 StorageType, StructType, SubType,
17};
18use crate::error::{Error, Result};
19use crate::Span;
20
21#[derive(Debug, Clone, Default)]
23pub struct DecodeOptions {
24 pub skeleton: bool,
26}
27
28impl Module {
29 pub fn decode(bytes: &[u8]) -> Result<Module> {
31 Self::decode_with_options(bytes, &DecodeOptions::default())
32 }
33
34 pub fn decode_with_options(bytes: &[u8], options: &DecodeOptions) -> Result<Module> {
36 wasmparser::Validator::new().validate_all(bytes)?;
38
39 let mut module = Module::new();
40
41 let parser = wasmparser::Parser::new(0);
42 let mut _code_section_range: Option<std::ops::Range<usize>> = None;
43 let mut custom_section_place: Option<&'static str> = Some("before first");
44
45 for payload in parser.parse_all(bytes) {
46 let payload = payload?;
47 match payload {
48 wasmparser::Payload::Version { .. } => {}
49 wasmparser::Payload::TypeSection(reader) => {
50 let has_content = reader.count() > 0;
51 decode_type_section(&mut module, reader)?;
52 if has_content {
53 custom_section_place = Some("after type");
54 }
55 }
56 wasmparser::Payload::ImportSection(reader) => {
57 let has_content = reader.count() > 0;
58 decode_import_section(&mut module, reader)?;
59 if has_content {
60 custom_section_place = Some("after import");
61 }
62 }
63 wasmparser::Payload::FunctionSection(reader) => {
64 decode_function_section(&mut module, reader)?;
65 }
67 wasmparser::Payload::TableSection(reader) => {
68 let has_content = reader.count() > 0;
69 decode_table_section(&mut module, reader)?;
70 if has_content {
71 custom_section_place = Some("after table");
72 }
73 }
74 wasmparser::Payload::MemorySection(reader) => {
75 let has_content = reader.count() > 0;
76 decode_memory_section(&mut module, reader)?;
77 if has_content {
78 custom_section_place = Some("after memory");
79 }
80 }
81 wasmparser::Payload::TagSection(reader) => {
82 let has_content = reader.count() > 0;
83 decode_tag_section(&mut module, reader)?;
84 if has_content {
85 custom_section_place = Some("after tag");
86 }
87 }
88 wasmparser::Payload::GlobalSection(reader) => {
89 let has_content = reader.count() > 0;
90 decode_global_section(&mut module, reader)?;
91 if has_content {
92 custom_section_place = Some("after global");
93 }
94 }
95 wasmparser::Payload::ExportSection(reader) => {
96 let has_content = reader.count() > 0;
97 decode_export_section(&mut module, reader)?;
98 if has_content {
99 custom_section_place = Some("after export");
100 }
101 }
102 wasmparser::Payload::StartSection { func, range: _ } => {
103 module.start = Some(func);
104 custom_section_place = Some("after start");
105 }
106 wasmparser::Payload::ElementSection(reader) => {
107 let has_content = reader.count() > 0;
108 decode_element_section(&mut module, reader)?;
109 if has_content {
110 custom_section_place = Some("after elem");
111 }
112 }
113 wasmparser::Payload::DataCountSection { count, range: _ } => {
114 module.data_count = Some(count);
115 }
117 wasmparser::Payload::DataSection(reader) => {
118 let has_content = reader.count() > 0;
119 decode_data_section(&mut module, reader)?;
120 if has_content {
121 custom_section_place = Some("after data");
122 }
123 }
124 wasmparser::Payload::CodeSectionStart { count, range, .. } => {
125 _code_section_range = Some(range);
126 module.bodies.reserve(count as usize);
127 if count > 0 {
128 custom_section_place = Some("after code");
129 }
130 }
131 wasmparser::Payload::CodeSectionEntry(body) => {
132 decode_code_entry(&mut module, body, options)?;
133 }
134 wasmparser::Payload::CustomSection(reader) => {
135 decode_custom_section(&mut module, reader, custom_section_place)?;
136 }
137 wasmparser::Payload::End(_) => {}
138 _ => {}
140 }
141 }
142
143 Ok(module)
144 }
145
146 pub fn decode_function(&mut self, idx: usize, bytes: &[u8]) -> Result<&FuncBodyDef> {
150 if let FuncBody::Lazy { offset, len } = self.bodies[idx] {
151 let body_bytes = &bytes[offset..offset + len];
152 let reader =
153 wasmparser::FunctionBody::new(wasmparser::BinaryReader::new(body_bytes, offset));
154 let def = decode_function_body(reader)?;
155 self.bodies[idx] = FuncBody::Decoded(def);
156 }
157 match &self.bodies[idx] {
158 FuncBody::Decoded(def) => Ok(def),
159 FuncBody::Lazy { .. } => unreachable!(),
160 }
161 }
162}
163
164fn decode_type_section(module: &mut Module, reader: wasmparser::TypeSectionReader) -> Result<()> {
165 for rec_group in reader {
166 let rec_group = rec_group?;
167 let is_explicit = rec_group.is_explicit_rec_group();
168 let mut types = Vec::new();
169 let mut first_offset = 0;
170 let mut last_end = 0;
171 for (offset, sub_type) in rec_group.into_types_and_offsets() {
172 if types.is_empty() {
173 first_offset = offset;
174 }
175 last_end = offset;
176 types.push(convert_sub_type(sub_type));
177 }
178 let span = Span::new(first_offset, last_end.saturating_sub(first_offset));
179 module.types.push(RecGroup {
180 span,
181 types,
182 is_explicit,
183 });
184 }
185 Ok(())
186}
187
188fn convert_sub_type(sub: wasmparser::SubType) -> SubType {
189 SubType {
190 is_final: sub.is_final,
191 supertype_idx: sub.supertype_idx.map(|idx| idx.as_module_index().unwrap()),
192 composite_type: convert_composite_type(sub.composite_type),
193 }
194}
195
196fn convert_composite_type(ct: wasmparser::CompositeType) -> CompositeType {
197 CompositeType {
198 shared: ct.shared,
199 inner: match ct.inner {
200 wasmparser::CompositeInnerType::Func(f) => CompositeInnerType::Func(FuncType {
201 params: f.params().to_vec(),
202 results: f.results().to_vec(),
203 }),
204 wasmparser::CompositeInnerType::Array(a) => CompositeInnerType::Array(ArrayType {
205 field_type: convert_field_type(a.0),
206 }),
207 wasmparser::CompositeInnerType::Struct(s) => CompositeInnerType::Struct(StructType {
208 fields: s.fields.iter().map(|f| convert_field_type(*f)).collect(),
209 }),
210 wasmparser::CompositeInnerType::Cont(c) => CompositeInnerType::Cont(ContType {
211 type_index: c.0.as_module_index().unwrap(),
212 }),
213 },
214 }
215}
216
217fn convert_field_type(ft: wasmparser::FieldType) -> FieldType {
218 FieldType {
219 mutable: ft.mutable,
220 element_type: match ft.element_type {
221 wasmparser::StorageType::I8 => StorageType::I8,
222 wasmparser::StorageType::I16 => StorageType::I16,
223 wasmparser::StorageType::Val(v) => StorageType::Val(v),
224 },
225 }
226}
227
228fn decode_import_section(
229 module: &mut Module,
230 reader: wasmparser::ImportSectionReader,
231) -> Result<()> {
232 let section_end = reader.range().end;
233 let mut iter = reader.into_imports_with_offsets().peekable();
234 while let Some(result) = iter.next() {
235 let (start, import) = result?;
236 let end = iter
237 .peek()
238 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
239 .unwrap_or(section_end);
240 let ty = match import.ty {
241 wasmparser::TypeRef::Func(idx) | wasmparser::TypeRef::FuncExact(idx) => {
242 ImportType::Func(idx)
243 }
244 wasmparser::TypeRef::Table(t) => ImportType::Table(t),
245 wasmparser::TypeRef::Memory(m) => ImportType::Memory(m),
246 wasmparser::TypeRef::Global(g) => ImportType::Global(g),
247 wasmparser::TypeRef::Tag(t) => ImportType::Tag(TagType {
248 kind: TagKind::Exception,
249 func_type_idx: t.func_type_idx,
250 }),
251 };
252 module.imports.push(Import {
253 span: Span::new(start, end - start),
254 module: import.module.to_string(),
255 name: import.name.to_string(),
256 ty,
257 });
258 }
259 Ok(())
260}
261
262fn decode_function_section(
263 module: &mut Module,
264 reader: wasmparser::FunctionSectionReader,
265) -> Result<()> {
266 let section_end = reader.range().end;
267 let mut iter = reader.into_iter_with_offsets().peekable();
268 while let Some(result) = iter.next() {
269 let (start, type_index) = result?;
270 let end = iter
271 .peek()
272 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
273 .unwrap_or(section_end);
274 module.functions.push(Func {
275 span: Span::new(start, end - start),
276 type_index,
277 });
278 }
279 Ok(())
280}
281
282fn decode_table_section(module: &mut Module, reader: wasmparser::TableSectionReader) -> Result<()> {
283 let section_end = reader.range().end;
284 let mut iter = reader.into_iter_with_offsets().peekable();
285 while let Some(result) = iter.next() {
286 let (start, table) = result?;
287 let end = iter
288 .peek()
289 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
290 .unwrap_or(section_end);
291 let init = match &table.init {
292 wasmparser::TableInit::Expr(expr) => Some(decode_const_expr(expr.clone())?),
293 wasmparser::TableInit::RefNull => None,
294 };
295 module.tables.push(Table {
296 span: Span::new(start, end - start),
297 ty: table.ty,
298 init,
299 });
300 }
301 Ok(())
302}
303
304fn decode_memory_section(
305 module: &mut Module,
306 reader: wasmparser::MemorySectionReader,
307) -> Result<()> {
308 let section_end = reader.range().end;
309 let mut iter = reader.into_iter_with_offsets().peekable();
310 while let Some(result) = iter.next() {
311 let (start, memory) = result?;
312 let end = iter
313 .peek()
314 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
315 .unwrap_or(section_end);
316 module.memories.push(Memory {
317 span: Span::new(start, end - start),
318 ty: memory,
319 });
320 }
321 Ok(())
322}
323
324fn decode_tag_section(module: &mut Module, reader: wasmparser::TagSectionReader) -> Result<()> {
325 let section_end = reader.range().end;
326 let mut iter = reader.into_iter_with_offsets().peekable();
327 while let Some(result) = iter.next() {
328 let (start, tag) = result?;
329 let end = iter
330 .peek()
331 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
332 .unwrap_or(section_end);
333 module.tags.push(Tag {
334 span: Span::new(start, end - start),
335 ty: TagType {
336 kind: TagKind::Exception,
337 func_type_idx: tag.func_type_idx,
338 },
339 });
340 }
341 Ok(())
342}
343
344fn decode_global_section(
345 module: &mut Module,
346 reader: wasmparser::GlobalSectionReader,
347) -> Result<()> {
348 let section_end = reader.range().end;
349 let mut iter = reader.into_iter_with_offsets().peekable();
350 while let Some(result) = iter.next() {
351 let (start, global) = result?;
352 let end = iter
353 .peek()
354 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
355 .unwrap_or(section_end);
356 let init_expr = decode_const_expr(global.init_expr)?;
357 module.globals.push(Global {
358 span: Span::new(start, end - start),
359 ty: global.ty,
360 init_expr,
361 });
362 }
363 Ok(())
364}
365
366fn decode_export_section(
367 module: &mut Module,
368 reader: wasmparser::ExportSectionReader,
369) -> Result<()> {
370 let section_end = reader.range().end;
371 let mut iter = reader.into_iter_with_offsets().peekable();
372 while let Some(result) = iter.next() {
373 let (start, export) = result?;
374 let end = iter
375 .peek()
376 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
377 .unwrap_or(section_end);
378 module.exports.push(Export {
379 span: Span::new(start, end - start),
380 name: export.name.to_string(),
381 kind: ExternalKind::from(export.kind),
382 index: export.index,
383 });
384 }
385 Ok(())
386}
387
388fn decode_element_section(
389 module: &mut Module,
390 reader: wasmparser::ElementSectionReader,
391) -> Result<()> {
392 let section_end = reader.range().end;
393 let mut iter = reader.into_iter_with_offsets().peekable();
394 while let Some(result) = iter.next() {
395 let (start, element) = result?;
396 let end = iter
397 .peek()
398 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
399 .unwrap_or(section_end);
400 let kind = match element.kind {
401 wasmparser::ElementKind::Passive => ElementKind::Passive,
402 wasmparser::ElementKind::Active {
403 table_index,
404 offset_expr,
405 } => ElementKind::Active {
406 table_index,
407 offset_expr: decode_const_expr(offset_expr)?,
408 },
409 wasmparser::ElementKind::Declared => ElementKind::Declared,
410 };
411 let items = match element.items {
412 wasmparser::ElementItems::Functions(reader) => {
413 let funcs: std::result::Result<Vec<u32>, _> = reader.into_iter().collect();
414 ElementItems::Functions(funcs?)
415 }
416 wasmparser::ElementItems::Expressions(ref_type, reader) => {
417 let exprs: std::result::Result<Vec<_>, _> = reader
418 .into_iter()
419 .map(|e| {
420 e.and_then(|e| {
421 decode_const_expr(e).map_err(|e| match e {
422 Error::BinaryReader(e) => e,
423 _ => unreachable!(),
424 })
425 })
426 })
427 .collect();
428 ElementItems::Expressions(ref_type, exprs?)
429 }
430 };
431 module.elements.push(Element {
432 span: Span::new(start, end - start),
433 kind,
434 items,
435 });
436 }
437 Ok(())
438}
439
440fn decode_data_section(module: &mut Module, reader: wasmparser::DataSectionReader) -> Result<()> {
441 let section_end = reader.range().end;
442 let mut iter = reader.into_iter_with_offsets().peekable();
443 while let Some(result) = iter.next() {
444 let (start, data) = result?;
445 let end = iter
446 .peek()
447 .and_then(|r| r.as_ref().ok().map(|(off, _)| *off))
448 .unwrap_or(section_end);
449 let kind = match data.kind {
450 wasmparser::DataKind::Passive => DataKind::Passive,
451 wasmparser::DataKind::Active {
452 memory_index,
453 offset_expr,
454 } => DataKind::Active {
455 memory_index,
456 offset_expr: decode_const_expr(offset_expr)?,
457 },
458 };
459 module.data.push(Data {
460 span: Span::new(start, end - start),
461 kind,
462 data: data.data.to_vec(),
463 });
464 }
465 Ok(())
466}
467
468fn decode_code_entry(
469 module: &mut Module,
470 body: wasmparser::FunctionBody,
471 options: &DecodeOptions,
472) -> Result<()> {
473 if options.skeleton {
474 let range = body.range();
475 module.bodies.push(FuncBody::Lazy {
476 offset: range.start,
477 len: range.end - range.start,
478 });
479 } else {
480 let def = decode_function_body(body)?;
481 module.bodies.push(FuncBody::Decoded(def));
482 }
483 Ok(())
484}
485
486fn decode_function_body(body: wasmparser::FunctionBody) -> Result<FuncBodyDef> {
487 let range = body.range();
488 let span = Span::new(range.start, range.end - range.start);
489
490 let mut locals = Vec::new();
491 let local_reader = body.get_locals_reader()?;
492 for local in local_reader {
493 let (count, val_type) = local?;
494 locals.push((count, val_type));
495 }
496
497 let mut instructions = Vec::new();
498 let mut ops_reader = body.get_operators_reader()?;
499 while !ops_reader.eof() {
500 let pos = ops_reader.original_position();
501 let op = ops_reader.read()?;
502 let end = ops_reader.original_position();
503 let instr = Instruction::from_operator(&op);
504 instructions.push((Span::new(pos, end - pos), instr));
505 }
506
507 Ok(FuncBodyDef {
508 span,
509 locals,
510 instructions,
511 })
512}
513
514fn decode_const_expr(expr: wasmparser::ConstExpr) -> Result<ConstExpr> {
515 let range = expr.get_binary_reader().range();
516 let span = Span::new(range.start, range.end - range.start);
517 let mut ops = Vec::new();
518 let mut reader = expr.get_operators_reader();
519 while !reader.eof() {
520 let op = reader.read()?;
521 match op {
522 wasmparser::Operator::End => break,
523 _ => ops.push(Instruction::from_operator(&op)),
524 }
525 }
526 Ok(ConstExpr { span, ops })
527}
528
529fn decode_custom_section(
530 module: &mut Module,
531 reader: wasmparser::CustomSectionReader,
532 placement: Option<&str>,
533) -> Result<()> {
534 match reader.as_known() {
535 wasmparser::KnownCustom::Name(name_reader) => {
536 decode_name_section(module, name_reader)?;
537 }
538 _ => {
539 let range = reader.range();
540 module.custom_sections.push(CustomSection {
541 span: Span::new(range.start, range.end - range.start),
542 name: reader.name().to_string(),
543 data: reader.data().to_vec(),
544 placement: placement.map(|s| s.to_string()),
545 });
546 }
547 }
548 Ok(())
549}
550
551fn decode_name_section(module: &mut Module, reader: wasmparser::NameSectionReader) -> Result<()> {
552 for name in reader {
553 match name? {
554 wasmparser::Name::Module { name, .. } => {
555 module.names.module_name = Some(name.to_string());
556 }
557 wasmparser::Name::Function(map) => {
558 for naming in map {
559 let naming = naming?;
560 module
561 .names
562 .function_names
563 .insert(naming.index, naming.name.to_string());
564 }
565 }
566 wasmparser::Name::Local(indirect) => {
567 for func_names in indirect {
568 let func_names = func_names?;
569 let func_idx = func_names.index;
570 let mut local_map = std::collections::HashMap::new();
571 for naming in func_names.names {
572 let naming = naming?;
573 local_map.insert(naming.index, naming.name.to_string());
574 }
575 module.names.local_names.insert(func_idx, local_map);
576 }
577 }
578 wasmparser::Name::Label(indirect) => {
579 for func_labels in indirect {
580 let func_labels = func_labels?;
581 let func_idx = func_labels.index;
582 let mut label_map = std::collections::HashMap::new();
583 for naming in func_labels.names {
584 let naming = naming?;
585 label_map.insert(naming.index, naming.name.to_string());
586 }
587 module.names.label_names.insert(func_idx, label_map);
588 }
589 }
590 wasmparser::Name::Type(map) => {
591 for naming in map {
592 let naming = naming?;
593 module
594 .names
595 .type_names
596 .insert(naming.index, naming.name.to_string());
597 }
598 }
599 wasmparser::Name::Table(map) => {
600 for naming in map {
601 let naming = naming?;
602 module
603 .names
604 .table_names
605 .insert(naming.index, naming.name.to_string());
606 }
607 }
608 wasmparser::Name::Memory(map) => {
609 for naming in map {
610 let naming = naming?;
611 module
612 .names
613 .memory_names
614 .insert(naming.index, naming.name.to_string());
615 }
616 }
617 wasmparser::Name::Global(map) => {
618 for naming in map {
619 let naming = naming?;
620 module
621 .names
622 .global_names
623 .insert(naming.index, naming.name.to_string());
624 }
625 }
626 wasmparser::Name::Element(map) => {
627 for naming in map {
628 let naming = naming?;
629 module
630 .names
631 .element_names
632 .insert(naming.index, naming.name.to_string());
633 }
634 }
635 wasmparser::Name::Data(map) => {
636 for naming in map {
637 let naming = naming?;
638 module
639 .names
640 .data_names
641 .insert(naming.index, naming.name.to_string());
642 }
643 }
644 wasmparser::Name::Tag(map) => {
645 for naming in map {
646 let naming = naming?;
647 module
648 .names
649 .tag_names
650 .insert(naming.index, naming.name.to_string());
651 }
652 }
653 wasmparser::Name::Field(indirect) => {
654 for type_fields in indirect {
655 let type_fields = type_fields?;
656 let type_idx = type_fields.index;
657 let mut field_map = std::collections::HashMap::new();
658 for naming in type_fields.names {
659 let naming = naming?;
660 field_map.insert(naming.index, naming.name.to_string());
661 }
662 module.names.field_names.insert(type_idx, field_map);
663 }
664 }
665 wasmparser::Name::Unknown { .. } => {}
666 }
667 }
668 Ok(())
669}