1use crate::module::{
2 AnyfuncIndex, Initializer, MemoryInitialization, MemoryInitializer, MemoryPlan, Module,
3 ModuleType, TableInitializer, TablePlan,
4};
5use crate::{
6 DataIndex, DefinedFuncIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global,
7 GlobalIndex, GlobalInit, MemoryIndex, ModuleTypesBuilder, PrimaryMap, SignatureIndex,
8 TableIndex, TableInitialization, Tunables, TypeIndex, WasmError, WasmFuncType, WasmResult,
9};
10use cranelift_entity::packed_option::ReservedValue;
11use std::borrow::Cow;
12use std::collections::HashMap;
13use std::convert::{TryFrom, TryInto};
14use std::path::PathBuf;
15use std::sync::Arc;
16use wasmparser::{
17 types::Types, CustomSectionReader, DataKind, ElementItems, ElementKind, Encoding, ExternalKind,
18 FuncToValidate, FunctionBody, NameSectionReader, Naming, Operator, Parser, Payload, Type,
19 TypeRef, Validator, ValidatorResources,
20};
21
22pub struct ModuleEnvironment<'a, 'data> {
24 result: ModuleTranslation<'data>,
26
27 types: &'a mut ModuleTypesBuilder,
29
30 validator: &'a mut Validator,
32 tunables: &'a Tunables,
33}
34
35#[derive(Default)]
39pub struct ModuleTranslation<'data> {
40 pub module: Module,
42
43 pub wasm: &'data [u8],
49
50 pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
52
53 pub exported_signatures: Vec<SignatureIndex>,
57
58 pub debuginfo: DebugInfoData<'data>,
60
61 pub has_unparsed_debuginfo: bool,
64
65 pub data: Vec<Cow<'data, [u8]>>,
71
72 pub data_align: Option<u64>,
79
80 total_data: u32,
82
83 pub passive_data: Vec<&'data [u8]>,
86
87 total_passive_data: u32,
89
90 code_index: u32,
93
94 types: Option<Types>,
97}
98
99impl<'data> ModuleTranslation<'data> {
100 pub fn get_types(&self) -> &Types {
102 self.types
103 .as_ref()
104 .expect("module type information to be available")
105 }
106}
107
108pub struct FunctionBodyData<'a> {
110 pub body: FunctionBody<'a>,
112 pub validator: FuncToValidate<ValidatorResources>,
114}
115
116#[derive(Debug, Default)]
117#[allow(missing_docs)]
118pub struct DebugInfoData<'a> {
119 pub dwarf: Dwarf<'a>,
120 pub name_section: NameSection<'a>,
121 pub wasm_file: WasmFileInfo,
122 debug_loc: gimli::DebugLoc<Reader<'a>>,
123 debug_loclists: gimli::DebugLocLists<Reader<'a>>,
124 pub debug_ranges: gimli::DebugRanges<Reader<'a>>,
125 pub debug_rnglists: gimli::DebugRngLists<Reader<'a>>,
126}
127
128#[allow(missing_docs)]
129pub type Dwarf<'input> = gimli::Dwarf<Reader<'input>>;
130
131type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
132
133#[derive(Debug, Default)]
134#[allow(missing_docs)]
135pub struct NameSection<'a> {
136 pub module_name: Option<&'a str>,
137 pub func_names: HashMap<FuncIndex, &'a str>,
138 pub locals_names: HashMap<FuncIndex, HashMap<u32, &'a str>>,
139}
140
141#[derive(Debug, Default)]
142#[allow(missing_docs)]
143pub struct WasmFileInfo {
144 pub path: Option<PathBuf>,
145 pub code_section_offset: u64,
146 pub imported_func_count: u32,
147 pub funcs: Vec<FunctionMetadata>,
148}
149
150#[derive(Debug)]
151#[allow(missing_docs)]
152pub struct FunctionMetadata {
153 pub params: Box<[wasmparser::ValType]>,
154 pub locals: Box<[(u32, wasmparser::ValType)]>,
155}
156
157impl<'a, 'data> ModuleEnvironment<'a, 'data> {
158 pub fn new(
160 tunables: &'a Tunables,
161 validator: &'a mut Validator,
162 types: &'a mut ModuleTypesBuilder,
163 ) -> Self {
164 Self {
165 result: ModuleTranslation::default(),
166 types,
167 tunables,
168 validator,
169 }
170 }
171
172 pub fn translate(
181 mut self,
182 parser: Parser,
183 data: &'data [u8],
184 ) -> WasmResult<ModuleTranslation<'data>> {
185 self.result.wasm = data;
186
187 for payload in parser.parse_all(data) {
188 self.translate_payload(payload?)?;
189 }
190
191 Ok(self.result)
192 }
193
194 fn translate_payload(&mut self, payload: Payload<'data>) -> WasmResult<()> {
195 match payload {
196 Payload::Version {
197 num,
198 encoding,
199 range,
200 } => {
201 self.validator.version(num, encoding, &range)?;
202 match encoding {
203 Encoding::Module => {}
204 Encoding::Component => {
205 return Err(WasmError::Unsupported(format!("component model")));
206 }
207 }
208 }
209
210 Payload::End(offset) => {
211 self.result.types = Some(self.validator.end(offset)?);
212
213 self.result.exported_signatures = self
217 .result
218 .module
219 .functions
220 .iter()
221 .filter_map(|(_, func)| {
222 if func.is_escaping() {
223 Some(func.signature)
224 } else {
225 None
226 }
227 })
228 .collect();
229 self.result.exported_signatures.sort_unstable();
230 self.result.exported_signatures.dedup();
231 }
232
233 Payload::TypeSection(types) => {
234 self.validator.type_section(&types)?;
235 let num = usize::try_from(types.count()).unwrap();
236 self.result.module.types.reserve(num);
237 self.types.reserve_wasm_signatures(num);
238
239 for ty in types {
240 match ty? {
241 Type::Func(wasm_func_ty) => {
242 self.declare_type_func(wasm_func_ty.try_into()?)?;
243 }
244 }
245 }
246 }
247
248 Payload::ImportSection(imports) => {
249 self.validator.import_section(&imports)?;
250
251 let cnt = usize::try_from(imports.count()).unwrap();
252 self.result.module.initializers.reserve(cnt);
253
254 for entry in imports {
255 let import = entry?;
256 let ty = match import.ty {
257 TypeRef::Func(index) => {
258 let index = TypeIndex::from_u32(index);
259 let sig_index = self.result.module.types[index].unwrap_function();
260 self.result.module.num_imported_funcs += 1;
261 self.result.debuginfo.wasm_file.imported_func_count += 1;
262 EntityType::Function(sig_index)
263 }
264 TypeRef::Memory(ty) => {
265 self.result.module.num_imported_memories += 1;
266 EntityType::Memory(ty.into())
267 }
268 TypeRef::Global(ty) => {
269 self.result.module.num_imported_globals += 1;
270 EntityType::Global(Global::new(ty, GlobalInit::Import)?)
271 }
272 TypeRef::Table(ty) => {
273 self.result.module.num_imported_tables += 1;
274 EntityType::Table(ty.try_into()?)
275 }
276
277 TypeRef::Tag(_) => unreachable!(),
279 };
280 self.declare_import(import.module, import.name, ty);
281 }
282 }
283
284 Payload::FunctionSection(functions) => {
285 self.validator.function_section(&functions)?;
286
287 let cnt = usize::try_from(functions.count()).unwrap();
288 self.result.module.functions.reserve_exact(cnt);
289
290 for entry in functions {
291 let sigindex = entry?;
292 let ty = TypeIndex::from_u32(sigindex);
293 let sig_index = self.result.module.types[ty].unwrap_function();
294 self.result.module.push_function(sig_index);
295 }
296 }
297
298 Payload::TableSection(tables) => {
299 self.validator.table_section(&tables)?;
300 let cnt = usize::try_from(tables.count()).unwrap();
301 self.result.module.table_plans.reserve_exact(cnt);
302
303 for entry in tables {
304 let table = entry?.ty.try_into()?;
305 let plan = TablePlan::for_table(table, &self.tunables);
306 self.result.module.table_plans.push(plan);
307 }
308 }
309
310 Payload::MemorySection(memories) => {
311 self.validator.memory_section(&memories)?;
312
313 let cnt = usize::try_from(memories.count()).unwrap();
314 self.result.module.memory_plans.reserve_exact(cnt);
315
316 for entry in memories {
317 let memory = entry?;
318 let plan = MemoryPlan::for_memory(memory.into(), &self.tunables);
319 self.result.module.memory_plans.push(plan);
320 }
321 }
322
323 Payload::TagSection(tags) => {
324 self.validator.tag_section(&tags)?;
325
326 unreachable!();
329 }
330
331 Payload::GlobalSection(globals) => {
332 self.validator.global_section(&globals)?;
333
334 let cnt = usize::try_from(globals.count()).unwrap();
335 self.result.module.globals.reserve_exact(cnt);
336
337 for entry in globals {
338 let wasmparser::Global { ty, init_expr } = entry?;
339 let mut init_expr_reader = init_expr.get_binary_reader();
340 let initializer = match init_expr_reader.read_operator()? {
341 Operator::I32Const { value } => GlobalInit::I32Const(value),
342 Operator::I64Const { value } => GlobalInit::I64Const(value),
343 Operator::F32Const { value } => GlobalInit::F32Const(value.bits()),
344 Operator::F64Const { value } => GlobalInit::F64Const(value.bits()),
345 Operator::V128Const { value } => {
346 GlobalInit::V128Const(u128::from_le_bytes(*value.bytes()))
347 }
348 Operator::RefNull { hty: _ } => GlobalInit::RefNullConst,
349 Operator::RefFunc { function_index } => {
350 let index = FuncIndex::from_u32(function_index);
351 self.flag_func_escaped(index);
352 GlobalInit::RefFunc(index)
353 }
354 Operator::GlobalGet { global_index } => {
355 GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
356 }
357 s => {
358 return Err(WasmError::Unsupported(format!(
359 "unsupported init expr in global section: {:?}",
360 s
361 )));
362 }
363 };
364 let ty = Global::new(ty, initializer)?;
365 self.result.module.globals.push(ty);
366 }
367 }
368
369 Payload::ExportSection(exports) => {
370 self.validator.export_section(&exports)?;
371
372 let cnt = usize::try_from(exports.count()).unwrap();
373 self.result.module.exports.reserve(cnt);
374
375 for entry in exports {
376 let wasmparser::Export { name, kind, index } = entry?;
377 let entity = match kind {
378 ExternalKind::Func => {
379 let index = FuncIndex::from_u32(index);
380 self.flag_func_escaped(index);
381 EntityIndex::Function(index)
382 }
383 ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(index)),
384 ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(index)),
385 ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(index)),
386
387 ExternalKind::Tag => unreachable!(),
389 };
390 self.result
391 .module
392 .exports
393 .insert(String::from(name), entity);
394 }
395 }
396
397 Payload::StartSection { func, range } => {
398 self.validator.start_section(func, &range)?;
399
400 let func_index = FuncIndex::from_u32(func);
401 self.flag_func_escaped(func_index);
402 debug_assert!(self.result.module.start_func.is_none());
403 self.result.module.start_func = Some(func_index);
404 }
405
406 Payload::ElementSection(elements) => {
407 self.validator.element_section(&elements)?;
408
409 for (index, entry) in elements.into_iter().enumerate() {
410 let wasmparser::Element {
411 kind,
412 items,
413 ty: _,
414 range: _,
415 } = entry?;
416
417 let mut elements = Vec::new();
423 match items {
424 ElementItems::Functions(funcs) => {
425 elements.reserve(usize::try_from(funcs.count()).unwrap());
426 for func in funcs {
427 let func = FuncIndex::from_u32(func?);
428 self.flag_func_escaped(func);
429 elements.push(func);
430 }
431 }
432 ElementItems::Expressions(funcs) => {
433 elements.reserve(usize::try_from(funcs.count()).unwrap());
434 for func in funcs {
435 let func = match func?.get_binary_reader().read_operator()? {
436 Operator::RefNull { .. } => FuncIndex::reserved_value(),
437 Operator::RefFunc { function_index } => {
438 let func = FuncIndex::from_u32(function_index);
439 self.flag_func_escaped(func);
440 func
441 }
442 s => {
443 return Err(WasmError::Unsupported(format!(
444 "unsupported init expr in element section: {:?}",
445 s
446 )));
447 }
448 };
449 elements.push(func);
450 }
451 }
452 }
453
454 match kind {
455 ElementKind::Active {
456 table_index,
457 offset_expr,
458 } => {
459 let table_index = TableIndex::from_u32(table_index);
460 let mut offset_expr_reader = offset_expr.get_binary_reader();
461 let (base, offset) = match offset_expr_reader.read_operator()? {
462 Operator::I32Const { value } => (None, value as u32),
463 Operator::GlobalGet { global_index } => {
464 (Some(GlobalIndex::from_u32(global_index)), 0)
465 }
466 ref s => {
467 return Err(WasmError::Unsupported(format!(
468 "unsupported init expr in element section: {:?}",
469 s
470 )));
471 }
472 };
473
474 let table_segments = match &mut self.result.module.table_initialization
475 {
476 TableInitialization::Segments { segments } => segments,
477 TableInitialization::FuncTable { .. } => unreachable!(),
478 };
479 table_segments.push(TableInitializer {
480 table_index,
481 base,
482 offset,
483 elements: elements.into(),
484 });
485 }
486
487 ElementKind::Passive => {
488 let elem_index = ElemIndex::from_u32(index as u32);
489 let index = self.result.module.passive_elements.len();
490 self.result.module.passive_elements.push(elements.into());
491 self.result
492 .module
493 .passive_elements_map
494 .insert(elem_index, index);
495 }
496
497 ElementKind::Declared => {}
498 }
499 }
500 }
501
502 Payload::CodeSectionStart { count, range, .. } => {
503 self.validator.code_section_start(count, &range)?;
504 let cnt = usize::try_from(count).unwrap();
505 self.result.function_body_inputs.reserve_exact(cnt);
506 self.result.debuginfo.wasm_file.code_section_offset = range.start as u64;
507 }
508
509 Payload::CodeSectionEntry(mut body) => {
510 let validator = self.validator.code_section_entry(&body)?;
511 let func_index =
512 self.result.code_index + self.result.module.num_imported_funcs as u32;
513 let func_index = FuncIndex::from_u32(func_index);
514
515 if self.tunables.generate_native_debuginfo {
516 let sig_index = self.result.module.functions[func_index].signature;
517 let sig = &self.types[sig_index];
518 let mut locals = Vec::new();
519 for pair in body.get_locals_reader()? {
520 locals.push(pair?);
521 }
522 self.result
523 .debuginfo
524 .wasm_file
525 .funcs
526 .push(FunctionMetadata {
527 locals: locals.into_boxed_slice(),
528 params: sig.params().iter().cloned().map(|i| i.into()).collect(),
529 });
530 }
531 body.allow_memarg64(self.validator.features().memory64);
532 self.result
533 .function_body_inputs
534 .push(FunctionBodyData { validator, body });
535 self.result.code_index += 1;
536 }
537
538 Payload::DataSection(data) => {
539 self.validator.data_section(&data)?;
540
541 let initializers = match &mut self.result.module.memory_initialization {
542 MemoryInitialization::Segmented(i) => i,
543 _ => unreachable!(),
544 };
545
546 let cnt = usize::try_from(data.count()).unwrap();
547 initializers.reserve_exact(cnt);
548 self.result.data.reserve_exact(cnt);
549
550 for (index, entry) in data.into_iter().enumerate() {
551 let wasmparser::Data {
552 kind,
553 data,
554 range: _,
555 } = entry?;
556 let mk_range = |total: &mut u32| -> Result<_, WasmError> {
557 let range = u32::try_from(data.len())
558 .ok()
559 .and_then(|size| {
560 let start = *total;
561 let end = start.checked_add(size)?;
562 Some(start..end)
563 })
564 .ok_or_else(|| {
565 WasmError::Unsupported(format!(
566 "more than 4 gigabytes of data in wasm module",
567 ))
568 })?;
569 *total += range.end - range.start;
570 Ok(range)
571 };
572 match kind {
573 DataKind::Active {
574 memory_index,
575 offset_expr,
576 } => {
577 let range = mk_range(&mut self.result.total_data)?;
578 let memory_index = MemoryIndex::from_u32(memory_index);
579 let mut offset_expr_reader = offset_expr.get_binary_reader();
580 let (base, offset) = match offset_expr_reader.read_operator()? {
581 Operator::I32Const { value } => (None, value as u64),
582 Operator::I64Const { value } => (None, value as u64),
583 Operator::GlobalGet { global_index } => {
584 (Some(GlobalIndex::from_u32(global_index)), 0)
585 }
586 s => {
587 return Err(WasmError::Unsupported(format!(
588 "unsupported init expr in data section: {:?}",
589 s
590 )));
591 }
592 };
593
594 initializers.push(MemoryInitializer {
595 memory_index,
596 base,
597 offset,
598 data: range,
599 });
600 self.result.data.push(data.into());
601 }
602 DataKind::Passive => {
603 let data_index = DataIndex::from_u32(index as u32);
604 let range = mk_range(&mut self.result.total_passive_data)?;
605 self.result.passive_data.push(data);
606 self.result
607 .module
608 .passive_data_map
609 .insert(data_index, range);
610 }
611 }
612 }
613 }
614
615 Payload::DataCountSection { count, range } => {
616 self.validator.data_count_section(count, &range)?;
617
618 }
624
625 Payload::CustomSection(s) if s.name() == "name" => {
626 let result = self.name_section(NameSectionReader::new(s.data(), s.data_offset()));
627 if let Err(e) = result {
628 log::warn!("failed to parse name section {:?}", e);
629 }
630 }
631
632 Payload::CustomSection(s)
633 if s.name() == "webidl-bindings" || s.name() == "wasm-interface-types" =>
634 {
635 return Err(WasmError::Unsupported(
636 "\
637Support for interface types has temporarily been removed from `wasmtime`.
638
639For more information about this temporary change you can read on the issue online:
640
641 https://github.com/bytecodealliance/wasmtime/issues/1271
642
643and for re-adding support for interface types you can see this issue:
644
645 https://github.com/bytecodealliance/wasmtime/issues/677
646"
647 .to_string(),
648 ))
649 }
650
651 Payload::CustomSection(s) => {
652 self.register_dwarf_section(&s);
653 }
654
655 other => {
660 self.validator.payload(&other)?;
661 panic!("unimplemented section in wasm file {:?}", other);
662 }
663 }
664 Ok(())
665 }
666
667 fn register_dwarf_section(&mut self, section: &CustomSectionReader<'data>) {
668 let name = section.name();
669 if !name.starts_with(".debug_") {
670 return;
671 }
672 if !self.tunables.generate_native_debuginfo && !self.tunables.parse_wasm_debuginfo {
673 self.result.has_unparsed_debuginfo = true;
674 return;
675 }
676 let info = &mut self.result.debuginfo;
677 let dwarf = &mut info.dwarf;
678 let endian = gimli::LittleEndian;
679 let data = section.data();
680 let slice = gimli::EndianSlice::new(data, endian);
681
682 match name {
683 ".debug_abbrev" => dwarf.debug_abbrev = gimli::DebugAbbrev::new(data, endian),
685 ".debug_addr" => dwarf.debug_addr = gimli::DebugAddr::from(slice),
686 ".debug_info" => dwarf.debug_info = gimli::DebugInfo::new(data, endian),
687 ".debug_line" => dwarf.debug_line = gimli::DebugLine::new(data, endian),
688 ".debug_line_str" => dwarf.debug_line_str = gimli::DebugLineStr::from(slice),
689 ".debug_str" => dwarf.debug_str = gimli::DebugStr::new(data, endian),
690 ".debug_str_offsets" => dwarf.debug_str_offsets = gimli::DebugStrOffsets::from(slice),
691 ".debug_str_sup" => {
692 let mut dwarf_sup: Dwarf<'data> = Default::default();
693 dwarf_sup.debug_str = gimli::DebugStr::from(slice);
694 dwarf.sup = Some(Arc::new(dwarf_sup));
695 }
696 ".debug_types" => dwarf.debug_types = gimli::DebugTypes::from(slice),
697
698 ".debug_loc" => info.debug_loc = gimli::DebugLoc::from(slice),
700 ".debug_loclists" => info.debug_loclists = gimli::DebugLocLists::from(slice),
701 ".debug_ranges" => info.debug_ranges = gimli::DebugRanges::new(data, endian),
702 ".debug_rnglists" => info.debug_rnglists = gimli::DebugRngLists::new(data, endian),
703
704 ".debug_aranges" | ".debug_pubnames" | ".debug_pubtypes" => return,
706
707 other => {
708 log::warn!("unknown debug section `{}`", other);
709 return;
710 }
711 }
712
713 dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
714 dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
715 }
716
717 fn declare_import(&mut self, module: &'data str, field: &'data str, ty: EntityType) {
730 let index = self.push_type(ty);
731 self.result.module.initializers.push(Initializer::Import {
732 name: module.to_owned(),
733 field: field.to_owned(),
734 index,
735 });
736 }
737
738 fn push_type(&mut self, ty: EntityType) -> EntityIndex {
739 match ty {
740 EntityType::Function(ty) => EntityIndex::Function(self.result.module.push_function(ty)),
741 EntityType::Table(ty) => {
742 let plan = TablePlan::for_table(ty, &self.tunables);
743 EntityIndex::Table(self.result.module.table_plans.push(plan))
744 }
745 EntityType::Memory(ty) => {
746 let plan = MemoryPlan::for_memory(ty, &self.tunables);
747 EntityIndex::Memory(self.result.module.memory_plans.push(plan))
748 }
749 EntityType::Global(ty) => EntityIndex::Global(self.result.module.globals.push(ty)),
750 EntityType::Tag(_) => unimplemented!(),
751 }
752 }
753
754 fn flag_func_escaped(&mut self, func: FuncIndex) {
755 let ty = &mut self.result.module.functions[func];
756 if ty.is_escaping() {
758 return;
759 }
760 let index = self.result.module.num_escaped_funcs as u32;
761 ty.anyfunc = AnyfuncIndex::from_u32(index);
762 self.result.module.num_escaped_funcs += 1;
763 }
764
765 fn declare_type_func(&mut self, wasm: WasmFuncType) -> WasmResult<()> {
766 let sig_index = self.types.wasm_func_type(wasm);
767 self.result
768 .module
769 .types
770 .push(ModuleType::Function(sig_index));
771 Ok(())
772 }
773
774 fn name_section(&mut self, names: NameSectionReader<'data>) -> WasmResult<()> {
776 for subsection in names {
777 match subsection? {
778 wasmparser::Name::Function(names) => {
779 for name in names {
780 let Naming { index, name } = name?;
781 if (index as usize) >= self.result.module.functions.len() {
784 continue;
785 }
786
787 let index = FuncIndex::from_u32(index);
792 self.result
793 .debuginfo
794 .name_section
795 .func_names
796 .insert(index, name);
797 }
798 }
799 wasmparser::Name::Module { name, .. } => {
800 self.result.module.name = Some(name.to_string());
801 if self.tunables.generate_native_debuginfo {
802 self.result.debuginfo.name_section.module_name = Some(name);
803 }
804 }
805 wasmparser::Name::Local(reader) => {
806 if !self.tunables.generate_native_debuginfo {
807 continue;
808 }
809 for f in reader {
810 let f = f?;
811 if (f.index as usize) >= self.result.module.functions.len() {
814 continue;
815 }
816 for name in f.names {
817 let Naming { index, name } = name?;
818
819 self.result
820 .debuginfo
821 .name_section
822 .locals_names
823 .entry(FuncIndex::from_u32(f.index))
824 .or_insert(HashMap::new())
825 .insert(index, name);
826 }
827 }
828 }
829 wasmparser::Name::Label(_)
830 | wasmparser::Name::Type(_)
831 | wasmparser::Name::Table(_)
832 | wasmparser::Name::Global(_)
833 | wasmparser::Name::Memory(_)
834 | wasmparser::Name::Element(_)
835 | wasmparser::Name::Data(_)
836 | wasmparser::Name::Unknown { .. } => {}
837 }
838 }
839 Ok(())
840 }
841}