1use anyhow::{Result, anyhow, bail};
2use vec_map::VecMap;
3use wasm_encoder::CustomSection;
4use wasmparser::{BinaryReader, Payload};
5pub use wasmparser::{Element, Export, FuncType, Global, Import, MemoryType, Table, TagType};
6
7use crate::{
8 index::{DefinedFuncId, FuncTypeId, IdVec, IndexedSection},
9 read::target_features::TargetFeatures,
10};
11
12pub mod code;
13pub mod data;
14pub mod linking;
15pub mod names;
16pub mod relocs;
17mod target_features;
18
19use code::CodeSection;
20use data::DataSection;
21use linking::LinkingInfo;
22use names::Names;
23use relocs::Relocation;
24
25type Ind<T> = IndexedSection<T>;
26
27#[derive(Default)]
31pub struct InputModule<'a> {
32 pub types: IdVec<FuncType>,
34 pub imports: IdVec<Import<'a>>,
35 pub exports: IdVec<Export<'a>>,
36 pub tables: IdVec<Table<'a>>,
37 pub elements: IdVec<Element<'a>>,
39 pub tags: IdVec<TagType>,
41 pub globals: IdVec<Global<'a>>,
42 pub memories: IdVec<MemoryType>,
44 pub code: Ind<CodeSection<'a>>,
46 pub data: Ind<DataSection<'a>>,
47
48 pub names: Names<'a>,
51 pub linking: LinkingInfo<'a>,
53 pub relocs: Relocation,
55 pub target_features: TargetFeatures,
57 pub custom_sections: VecMap<Ind<CustomSection<'a>>>,
59}
60
61impl<'a> InputModule<'a> {
62 pub fn parse(wasm: &'a [u8]) -> anyhow::Result<Self> {
63 let mut module = Self {
64 ..Default::default()
65 };
66
67 let mut section_index = 0;
68 let mut end = None;
69
70 let mut function_types: Vec<FuncTypeId> = Vec::new();
71 let mut code_start = None;
72 let mut code_reader_header = None;
73 let mut funcs = Vec::new();
74
75 let mut data_count = None;
76
77 let parser = wasmparser::Parser::new(0);
78 let mut parser = parser.parse_all(wasm);
79 for payload in &mut parser {
80 match payload? {
81 Payload::TypeSection(reader) => {
82 module.types = reader
83 .into_iter_err_on_gc_types()
84 .collect::<Result<IdVec<_>, _>>()?;
85 }
86 Payload::ImportSection(reader) => {
87 module.imports = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
88 }
89 Payload::TableSection(reader) => {
90 module.tables = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
91 }
92 Payload::MemorySection(reader) => {
93 module.memories = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
94 }
95 Payload::TagSection(reader) => {
96 module.tags = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
97 }
98 Payload::GlobalSection(reader) => {
99 module.globals = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
100 }
101 Payload::ElementSection(reader) => {
102 module.elements = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
103 }
104 Payload::FunctionSection(reader) => {
105 function_types = reader
106 .into_iter()
107 .map(|t| t.map(crate::index::Id::from_index))
108 .collect::<Result<Vec<_>, _>>()?;
109 }
110 Payload::ExportSection(reader) => {
111 module.exports = reader.into_iter().collect::<Result<IdVec<_>, _>>()?;
112 }
113 Payload::StartSection { func, .. } => {
114 code_start = Some(crate::index::Id::from_index(func));
115 }
116 Payload::DataCountSection { count, .. } => {
117 data_count = Some(count as usize);
118 }
119 Payload::DataSection(reader) => {
120 let starting_offset = reader.range().start;
121
122 let data = DataSection {
123 data_segments: reader.into_iter().collect::<Result<IdVec<_>, _>>()?,
124 };
125 module.data = Ind {
126 section_payload: data,
127 section_index,
128 starting_offset,
129 };
130 }
131 Payload::CodeSectionStart { range, count, .. } => {
133 code_reader_header = Some((range.start, section_index, count));
134 }
135 Payload::CustomSection(reader) => {
136 let name = reader.name();
137 if name == "name" {
138 let name_reader = wasmparser::NameSectionReader::new(BinaryReader::new(
139 reader.data(),
140 reader.data_offset(),
141 ));
142 module.names = Names::read(name_reader)?;
143 } else if name == "linking" {
144 let linking_reader = wasmparser::LinkingSectionReader::new(
145 BinaryReader::new(reader.data(), reader.data_offset()),
146 )?;
147 module.linking = LinkingInfo::read(linking_reader)?;
148 } else if name.starts_with("reloc.") {
149 let reloc_reader = wasmparser::RelocSectionReader::new(BinaryReader::new(
150 reader.data(),
151 reader.data_offset(),
152 ))?;
153 module.relocs.push_section(reloc_reader)?;
154 } else if name == "target_features" {
155 module.target_features = TargetFeatures::read(BinaryReader::new(
156 reader.data(),
157 reader.data_offset(),
158 ))?;
159 } else {
160 let custom_section = CustomSection {
161 name: reader.name().into(),
162 data: reader.data().into(),
163 };
164 module.custom_sections.insert(
165 section_index,
166 Ind {
167 section_payload: custom_section,
168 section_index,
169 starting_offset: reader.range().start,
170 },
171 );
172 }
173 }
174 Payload::CodeSectionEntry(body) => {
176 funcs.push(body);
177 continue;
179 }
180 Payload::Version { .. } => continue,
181 Payload::End(offset) => {
182 end = Some(offset);
183 break;
184 }
185 section => {
186 bail!("Unknown section: {:?}", section);
187 }
188 }
189
190 section_index += 1;
191 }
192 let _end = end.ok_or_else(|| anyhow!("No end section"))?;
193 if parser.next().is_some() {
194 bail!("Unexpected trailing data");
195 }
196 if let Some(data_count) = data_count {
197 if data_count != module.data.section_payload.data_segments.len() {
198 bail!(
199 "Data count mismatch: {} != {}",
200 data_count,
201 module.data.section_payload.data_segments.len()
202 );
203 }
204 }
205
206 module.code = CodeSection::new(code_start, funcs, function_types, code_reader_header)?;
208
209 Ok(module)
210 }
211 pub fn defined_func_type_id(&self, id: DefinedFuncId) -> FuncTypeId {
212 self.code.section_payload.defined_funcs[id].type_id
213 }
214}
215
216trait CustomSectionReader<'a> {
217 type Reader;
218
219 fn read(reader: Self::Reader) -> Result<Self>
220 where
221 Self: Sized;
222}