/src/wasm-tools/crates/wit-component/src/linking/metadata.rs
Line | Count | Source |
1 | | //! Support for parsing and analyzing [dynamic |
2 | | //! library](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md) modules. |
3 | | |
4 | | use { |
5 | | anyhow::{Context, Error, Result, bail}, |
6 | | std::{ |
7 | | collections::{BTreeSet, HashMap, HashSet}, |
8 | | fmt, |
9 | | }, |
10 | | wasmparser::{ |
11 | | Dylink0Subsection, ExternalKind, FuncType, KnownCustom, MemInfo, Parser, Payload, RefType, |
12 | | SymbolFlags, TableType, TagKind, TagType, TypeRef, ValType, |
13 | | }, |
14 | | }; |
15 | | |
16 | | pub const ENV: &str = "env"; |
17 | | pub const GOT_MEM: &str = "GOT.mem"; |
18 | | pub const GOT_FUNC: &str = "GOT.func"; |
19 | | pub const MEMORY: &str = "memory"; |
20 | | pub const MEMORY_BASE: &str = "__memory_base"; |
21 | | pub const TABLE_BASE: &str = "__table_base"; |
22 | | pub const STACK_POINTER: &str = "__stack_pointer"; |
23 | | pub const INIT_STACK_POINTER: &str = "__init_stack_pointer"; |
24 | | pub const ASYNCIFY_DATA: &str = "__asyncify_data"; |
25 | | pub const ASYNCIFY_STATE: &str = "__asyncify_state"; |
26 | | pub const INDIRECT_FUNCTION_TABLE: &str = "__indirect_function_table"; |
27 | | pub const HEAP_BASE: &str = "__heap_base"; |
28 | | pub const HEAP_END: &str = "__heap_end"; |
29 | | pub const STACK_HIGH: &str = "__stack_high"; |
30 | | pub const STACK_LOW: &str = "__stack_low"; |
31 | | pub const APPLY_DATA_RELOCS: &str = "__wasm_apply_data_relocs"; |
32 | | pub const CALL_CTORS: &str = "__wasm_call_ctors"; |
33 | | pub const INITIALIZE: &str = "_initialize"; |
34 | | pub const START: &str = "_start"; |
35 | | pub const LIBDL_LIBRARIES: &str = "__wasm_libdl_libraries"; |
36 | | pub const TASK_HOOK: &str = "__wasm_task_hook"; |
37 | | pub const ROOT: &str = "$root"; |
38 | | pub const THREAD_NEW_INDIRECT: &str = "[thread-new-indirect-v0]"; |
39 | | pub const CONTEXT_GET_1: &str = "[context-get-1]"; |
40 | | pub const GET_STACK_POINTER: &str = "__wasm_get_stack_pointer"; |
41 | | pub const SET_STACK_POINTER: &str = "__wasm_set_stack_pointer"; |
42 | | pub const GET_TLS_BASE: &str = "__wasm_get_tls_base"; |
43 | | pub const SET_TLS_BASE: &str = "__wasm_set_tls_base"; |
44 | | pub const PROGRAM_TLS_INFO: &str = "__wasm_program_tls_info"; |
45 | | pub const LIBRARY_TLS_INFO: &str = "__wasm_library_tls_info"; |
46 | | |
47 | | /// Represents a core Wasm value type (not including V128 or reference types, which are not yet supported) |
48 | | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
49 | | pub enum ValueType { |
50 | | I32, |
51 | | I64, |
52 | | F32, |
53 | | F64, |
54 | | } |
55 | | |
56 | | impl TryFrom<ValType> for ValueType { |
57 | | type Error = Error; |
58 | | |
59 | 0 | fn try_from(value: ValType) -> Result<Self> { |
60 | 0 | Ok(match value { |
61 | 0 | ValType::I32 => Self::I32, |
62 | 0 | ValType::I64 => Self::I64, |
63 | 0 | ValType::F32 => Self::F32, |
64 | 0 | ValType::F64 => Self::F64, |
65 | 0 | _ => bail!("{value:?} not yet supported"), |
66 | | }) |
67 | 0 | } |
68 | | } |
69 | | |
70 | | impl From<ValueType> for wasm_encoder::ValType { |
71 | 0 | fn from(value: ValueType) -> Self { |
72 | 0 | match value { |
73 | 0 | ValueType::I32 => Self::I32, |
74 | 0 | ValueType::I64 => Self::I64, |
75 | 0 | ValueType::F32 => Self::F32, |
76 | 0 | ValueType::F64 => Self::F64, |
77 | | } |
78 | 0 | } |
79 | | } |
80 | | |
81 | | /// Represents a core Wasm function type |
82 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
83 | | pub struct FunctionType { |
84 | | pub parameters: Vec<ValueType>, |
85 | | pub results: Vec<ValueType>, |
86 | | } |
87 | | |
88 | | impl fmt::Display for FunctionType { |
89 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
90 | 0 | write!(f, "{:?} -> {:?}", self.parameters, self.results) |
91 | 0 | } |
92 | | } |
93 | | |
94 | | impl TryFrom<&FuncType> for FunctionType { |
95 | | type Error = Error; |
96 | | |
97 | 0 | fn try_from(value: &FuncType) -> Result<Self> { |
98 | | Ok(Self { |
99 | 0 | parameters: value |
100 | 0 | .params() |
101 | 0 | .iter() |
102 | 0 | .map(|&v| ValueType::try_from(v)) |
103 | 0 | .collect::<Result<_>>()?, |
104 | 0 | results: value |
105 | 0 | .results() |
106 | 0 | .iter() |
107 | 0 | .map(|&v| ValueType::try_from(v)) |
108 | 0 | .collect::<Result<_>>()?, |
109 | | }) |
110 | 0 | } |
111 | | } |
112 | | |
113 | | /// Represents a core Wasm global variable type |
114 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
115 | | pub struct GlobalType { |
116 | | pub ty: ValueType, |
117 | | pub mutable: bool, |
118 | | pub shared: bool, |
119 | | } |
120 | | |
121 | | impl fmt::Display for GlobalType { |
122 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
123 | 0 | if self.mutable { |
124 | 0 | write!(f, "mut ")?; |
125 | 0 | } |
126 | 0 | write!(f, "{:?}", self.ty) |
127 | 0 | } |
128 | | } |
129 | | |
130 | | /// Represents a core Wasm export or import type |
131 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
132 | | pub enum Type { |
133 | | Function(FunctionType), |
134 | | Global(GlobalType), |
135 | | Tag(FunctionType), |
136 | | } |
137 | | |
138 | | impl fmt::Display for Type { |
139 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
140 | 0 | match self { |
141 | 0 | Self::Function(ty) => write!(f, "function {ty}"), |
142 | 0 | Self::Global(ty) => write!(f, "global {ty}"), |
143 | 0 | Self::Tag(ty) => write!(f, "tag {ty}"), |
144 | | } |
145 | 0 | } |
146 | | } |
147 | | |
148 | | impl From<&Type> for wasm_encoder::ExportKind { |
149 | 0 | fn from(value: &Type) -> Self { |
150 | 0 | match value { |
151 | 0 | Type::Function(_) => wasm_encoder::ExportKind::Func, |
152 | 0 | Type::Global(_) => wasm_encoder::ExportKind::Global, |
153 | 0 | Type::Tag(_) => wasm_encoder::ExportKind::Tag, |
154 | | } |
155 | 0 | } |
156 | | } |
157 | | |
158 | | /// Represents a core Wasm import |
159 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
160 | | pub struct Import<'a> { |
161 | | pub module: &'a str, |
162 | | pub name: &'a str, |
163 | | pub ty: Type, |
164 | | pub flags: SymbolFlags, |
165 | | } |
166 | | |
167 | | /// Represents a core Wasm export |
168 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
169 | | pub struct ExportKey<'a> { |
170 | | pub name: &'a str, |
171 | | pub ty: Type, |
172 | | } |
173 | | |
174 | | impl<'a> fmt::Display for ExportKey<'a> { |
175 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
176 | 0 | write!(f, "{} ({})", self.name, self.ty) |
177 | 0 | } |
178 | | } |
179 | | |
180 | | /// Represents a core Wasm export, including dylink.0 flags |
181 | | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
182 | | pub struct Export<'a> { |
183 | | pub key: ExportKey<'a>, |
184 | | pub flags: SymbolFlags, |
185 | | } |
186 | | |
187 | | /// Metadata extracted from a dynamic library module |
188 | | #[derive(Debug)] |
189 | | pub struct Metadata<'a> { |
190 | | /// The name of the module |
191 | | /// |
192 | | /// This is currently not part of the file itself and must be provided separately, but the plan is to add |
193 | | /// something like a `WASM_DYLINK_SO_NAME` field to the dynamic linking tool convention so we can parse it |
194 | | /// along with everything else. |
195 | | pub name: &'a str, |
196 | | |
197 | | /// Whether this module should be resolvable via `dlopen` |
198 | | pub dl_openable: bool, |
199 | | |
200 | | /// The `WASM_DYLINK_MEM_INFO` value (or all zeros if not found) |
201 | | pub mem_info: MemInfo, |
202 | | |
203 | | /// The `WASM_DYLINK_NEEDED` values, if any |
204 | | pub needed_libs: Vec<&'a str>, |
205 | | |
206 | | /// The `WASM_DYLINK_RUNTIME_PATH` values, if any |
207 | | pub runtime_path: Vec<&'a str>, |
208 | | |
209 | | /// Whether this module exports `__wasm_apply_data_relocs` |
210 | | pub has_data_relocs: bool, |
211 | | |
212 | | /// Whether this module exports `__wasm_call_ctors` |
213 | | pub has_ctors: bool, |
214 | | |
215 | | /// Whether this module exports `_initialize` |
216 | | pub has_initialize: bool, |
217 | | |
218 | | /// Whether this module exports `_start` |
219 | | pub has_wasi_start: bool, |
220 | | |
221 | | /// Whether this module imports `__wasm_libdl_libraries` |
222 | | pub needs_libdl_libraries: bool, |
223 | | |
224 | | /// Whether this module includes any `component-type*` custom sections which include exports |
225 | | pub has_component_exports: bool, |
226 | | |
227 | | /// Whether this module imports `__asyncify_state` or `__asyncify_data`, indicating that it is |
228 | | /// asyncified with `--pass-arg=asyncify-relocatable` option. |
229 | | pub is_asyncified: bool, |
230 | | |
231 | | /// Whether this module imports `__stack_pointer` |
232 | | pub needs_stack_pointer: bool, |
233 | | |
234 | | /// Whether this module imports `__init_stack_pointer` |
235 | | pub needs_init_stack_pointer: bool, |
236 | | |
237 | | /// Whether this module imports `__heap_base` |
238 | | pub needs_heap_base: bool, |
239 | | |
240 | | /// Whether this module imports `__heap_end` |
241 | | pub needs_heap_end: bool, |
242 | | |
243 | | /// Whether this module imports `__stack_high` |
244 | | pub needs_stack_high: bool, |
245 | | |
246 | | /// Whether this module imports `__stack_low` |
247 | | pub needs_stack_low: bool, |
248 | | |
249 | | /// Whether this module imports `env::__wasm_get_tls_base` |
250 | | pub needs_get_tls_base: bool, |
251 | | |
252 | | /// Whether this module imports `env::__wasm_set_tls_base` |
253 | | pub needs_set_tls_base: bool, |
254 | | |
255 | | /// Whether this module imports the address of `__wasm_program_tls_info` |
256 | | pub needs_program_tls_info: bool, |
257 | | |
258 | | /// Whether this module imports `$root::[thread-new-indirect-v0]`, meaning |
259 | | /// the program may spawn threads and is thus using cooperative threading. |
260 | | pub uses_thread_new_indirect: bool, |
261 | | |
262 | | /// Whether this module exports a `__wasm_library_tls_info` symbol. |
263 | | pub has_library_tls_info: bool, |
264 | | |
265 | | /// The functions imported from the `env` module, if any |
266 | | pub env_imports: BTreeSet<(&'a str, (FunctionType, SymbolFlags))>, |
267 | | |
268 | | /// The memory addresses imported from `GOT.mem`, if any |
269 | | pub memory_address_imports: BTreeSet<&'a str>, |
270 | | |
271 | | /// The table addresses imported from `GOT.func`, if any |
272 | | pub table_address_imports: BTreeSet<&'a str>, |
273 | | |
274 | | /// Imported exception tags |
275 | | pub tag_imports: BTreeSet<(&'a str, FunctionType)>, |
276 | | |
277 | | /// The symbols exported by this module, if any |
278 | | pub exports: BTreeSet<Export<'a>>, |
279 | | |
280 | | /// The symbols imported by this module (and not accounted for in the above fields), if any |
281 | | pub imports: BTreeSet<Import<'a>>, |
282 | | } |
283 | | |
284 | | impl<'a> Metadata<'a> { |
285 | | /// Parse the specified module and extract its metadata. |
286 | 0 | pub fn try_new( |
287 | 0 | name: &'a str, |
288 | 0 | dl_openable: bool, |
289 | 0 | module: &'a [u8], |
290 | 0 | adapter_names: &HashSet<&str>, |
291 | 0 | ) -> Result<Self> { |
292 | 0 | let bindgen = crate::metadata::decode(module)?.1; |
293 | 0 | let has_component_exports = !bindgen.resolve.worlds[bindgen.world].exports.is_empty(); |
294 | | |
295 | 0 | let mut result = Self { |
296 | 0 | name, |
297 | 0 | dl_openable, |
298 | 0 | mem_info: MemInfo { |
299 | 0 | memory_size: 0, |
300 | 0 | memory_alignment: 1, |
301 | 0 | table_size: 0, |
302 | 0 | table_alignment: 1, |
303 | 0 | }, |
304 | 0 | needed_libs: Vec::new(), |
305 | 0 | runtime_path: Vec::new(), |
306 | 0 | has_data_relocs: false, |
307 | 0 | has_ctors: false, |
308 | 0 | has_initialize: false, |
309 | 0 | has_wasi_start: false, |
310 | 0 | needs_libdl_libraries: false, |
311 | 0 | has_component_exports, |
312 | 0 | is_asyncified: false, |
313 | 0 | needs_stack_pointer: false, |
314 | 0 | needs_init_stack_pointer: false, |
315 | 0 | needs_heap_base: false, |
316 | 0 | needs_heap_end: false, |
317 | 0 | needs_stack_high: false, |
318 | 0 | needs_stack_low: false, |
319 | 0 | needs_get_tls_base: false, |
320 | 0 | needs_set_tls_base: false, |
321 | 0 | needs_program_tls_info: false, |
322 | 0 | uses_thread_new_indirect: false, |
323 | 0 | has_library_tls_info: false, |
324 | 0 | env_imports: BTreeSet::new(), |
325 | 0 | memory_address_imports: BTreeSet::new(), |
326 | 0 | table_address_imports: BTreeSet::new(), |
327 | 0 | exports: BTreeSet::new(), |
328 | 0 | imports: BTreeSet::new(), |
329 | 0 | tag_imports: BTreeSet::new(), |
330 | 0 | }; |
331 | 0 | let mut types = Vec::new(); |
332 | 0 | let mut function_types = Vec::new(); |
333 | 0 | let mut global_types = Vec::new(); |
334 | 0 | let mut tag_types = Vec::new(); |
335 | 0 | let mut import_info = HashMap::new(); |
336 | 0 | let mut export_info = HashMap::new(); |
337 | | |
338 | 0 | for payload in Parser::new(0).parse_all(module) { |
339 | 0 | match payload? { |
340 | 0 | Payload::CustomSection(section) => { |
341 | 0 | if let KnownCustom::Dylink0(reader) = section.as_known() { |
342 | 0 | for subsection in reader { |
343 | 0 | match subsection.context("failed to parse `dylink.0` subsection")? { |
344 | 0 | Dylink0Subsection::MemInfo(info) => result.mem_info = info, |
345 | 0 | Dylink0Subsection::Needed(needed) => { |
346 | 0 | result.needed_libs = needed.clone() |
347 | | } |
348 | 0 | Dylink0Subsection::ExportInfo(info) => { |
349 | 0 | export_info |
350 | 0 | .extend(info.iter().map(|info| (info.name, info.flags))); |
351 | | } |
352 | 0 | Dylink0Subsection::ImportInfo(info) => { |
353 | 0 | import_info.extend( |
354 | 0 | info.iter() |
355 | 0 | .map(|info| ((info.module, info.field), info.flags)), |
356 | | ); |
357 | | } |
358 | 0 | Dylink0Subsection::RuntimePath(runtime_path) => { |
359 | 0 | result.runtime_path.extend(runtime_path.iter()); |
360 | 0 | } |
361 | 0 | Dylink0Subsection::Unknown { ty, .. } => { |
362 | 0 | bail!("unrecognized `dylink.0` subsection: {ty}") |
363 | | } |
364 | | } |
365 | | } |
366 | 0 | } |
367 | | } |
368 | | |
369 | 0 | Payload::TypeSection(reader) => { |
370 | 0 | types = reader |
371 | 0 | .into_iter_err_on_gc_types() |
372 | 0 | .collect::<Result<Vec<_>, _>>()?; |
373 | | } |
374 | | |
375 | 0 | Payload::ImportSection(reader) => { |
376 | 0 | for import in reader.into_imports() { |
377 | 0 | let import = import?; |
378 | | |
379 | 0 | match import.ty { |
380 | 0 | TypeRef::Func(ty) => function_types.push(usize::try_from(ty).unwrap()), |
381 | 0 | TypeRef::Global(ty) => { |
382 | 0 | global_types.push(ty); |
383 | 0 | } |
384 | 0 | TypeRef::Tag(ty) => tag_types.push(ty), |
385 | 0 | _ => (), |
386 | | } |
387 | | |
388 | 0 | let type_error = || { |
389 | 0 | bail!( |
390 | | "unexpected type for {}:{}: {:?}", |
391 | | import.module, |
392 | | import.name, |
393 | | import.ty |
394 | | ) |
395 | 0 | }; |
396 | | |
397 | 0 | match (import.module, import.name) { |
398 | 0 | (self::ENV, self::MEMORY) => { |
399 | 0 | if !matches!(import.ty, TypeRef::Memory(_)) { |
400 | 0 | return type_error(); |
401 | 0 | } |
402 | | } |
403 | 0 | (self::ENV, self::ASYNCIFY_DATA | self::ASYNCIFY_STATE) => { |
404 | 0 | result.is_asyncified = true; |
405 | 0 | if !matches!( |
406 | 0 | import.ty, |
407 | | TypeRef::Global(wasmparser::GlobalType { |
408 | | content_type: ValType::I32, |
409 | | .. |
410 | | }) |
411 | | ) { |
412 | 0 | return type_error(); |
413 | 0 | } |
414 | | } |
415 | | ( |
416 | | self::ENV, |
417 | 0 | self::MEMORY_BASE |
418 | 0 | | self::TABLE_BASE |
419 | 0 | | self::STACK_POINTER |
420 | 0 | | self::INIT_STACK_POINTER, |
421 | | ) => { |
422 | 0 | if matches!( |
423 | 0 | import.ty, |
424 | | TypeRef::Global(wasmparser::GlobalType { |
425 | | content_type: ValType::I32, |
426 | | .. |
427 | | }) |
428 | | ) { |
429 | 0 | match import.name { |
430 | 0 | self::STACK_POINTER => result.needs_stack_pointer = true, |
431 | 0 | self::INIT_STACK_POINTER => { |
432 | 0 | result.needs_init_stack_pointer = true |
433 | | } |
434 | 0 | _ => {} |
435 | | } |
436 | | } else { |
437 | 0 | return type_error(); |
438 | | } |
439 | | } |
440 | 0 | (self::ENV, self::INDIRECT_FUNCTION_TABLE) => { |
441 | | if let TypeRef::Table(TableType { |
442 | 0 | element_type, |
443 | | maximum: None, |
444 | | .. |
445 | 0 | }) = import.ty |
446 | | { |
447 | 0 | if element_type != RefType::FUNCREF { |
448 | 0 | return type_error(); |
449 | 0 | } |
450 | | } else { |
451 | 0 | return type_error(); |
452 | | } |
453 | | } |
454 | | ( |
455 | | self::ENV, |
456 | 0 | name @ (self::GET_STACK_POINTER |
457 | 0 | | self::SET_STACK_POINTER |
458 | 0 | | self::GET_TLS_BASE |
459 | 0 | | self::SET_TLS_BASE), |
460 | | ) => { |
461 | 0 | if !matches!(import.ty, TypeRef::Func(_)) { |
462 | 0 | return type_error(); |
463 | 0 | } |
464 | 0 | match name { |
465 | 0 | self::GET_TLS_BASE => result.needs_get_tls_base = true, |
466 | 0 | self::SET_TLS_BASE => result.needs_set_tls_base = true, |
467 | 0 | _ => {} |
468 | | } |
469 | | } |
470 | 0 | (self::ENV, name) => match import.ty { |
471 | 0 | TypeRef::Func(ty) => { |
472 | 0 | result.env_imports.insert(( |
473 | 0 | name, |
474 | | ( |
475 | 0 | FunctionType::try_from( |
476 | 0 | &types[usize::try_from(ty).unwrap()], |
477 | 0 | )?, |
478 | 0 | import_info |
479 | 0 | .get(&(self::ENV, name)) |
480 | 0 | .copied() |
481 | 0 | .unwrap_or_default(), |
482 | | ), |
483 | | )); |
484 | | } |
485 | | TypeRef::Tag(TagType { |
486 | | kind: TagKind::Exception, |
487 | 0 | func_type_idx, |
488 | | }) => { |
489 | 0 | result.tag_imports.insert(( |
490 | 0 | name, |
491 | 0 | FunctionType::try_from( |
492 | 0 | &types[usize::try_from(func_type_idx).unwrap()], |
493 | 0 | )?, |
494 | | )); |
495 | | } |
496 | 0 | _ => return type_error(), |
497 | | }, |
498 | 0 | (self::GOT_MEM, name) => { |
499 | | if let TypeRef::Global(wasmparser::GlobalType { |
500 | | content_type: ValType::I32, |
501 | | .. |
502 | 0 | }) = import.ty |
503 | | { |
504 | 0 | match name { |
505 | 0 | self::HEAP_BASE => result.needs_heap_base = true, |
506 | 0 | self::HEAP_END => result.needs_heap_end = true, |
507 | 0 | self::STACK_HIGH => result.needs_stack_high = true, |
508 | 0 | self::STACK_LOW => result.needs_stack_low = true, |
509 | 0 | self::LIBDL_LIBRARIES => { |
510 | 0 | result.needs_libdl_libraries = true; |
511 | 0 | } |
512 | 0 | self::PROGRAM_TLS_INFO => { |
513 | 0 | result.needs_program_tls_info = true; |
514 | 0 | } |
515 | | |
516 | 0 | _ => { |
517 | 0 | result.memory_address_imports.insert(name); |
518 | 0 | } |
519 | | } |
520 | | } else { |
521 | 0 | return type_error(); |
522 | | } |
523 | | } |
524 | 0 | (self::GOT_FUNC, name) => { |
525 | | if let TypeRef::Global(wasmparser::GlobalType { |
526 | | content_type: ValType::I32, |
527 | | .. |
528 | 0 | }) = import.ty |
529 | 0 | { |
530 | 0 | result.table_address_imports.insert(name); |
531 | 0 | } else { |
532 | 0 | return type_error(); |
533 | | } |
534 | | } |
535 | 0 | (self::ROOT, self::THREAD_NEW_INDIRECT) => { |
536 | 0 | result.uses_thread_new_indirect = true; |
537 | 0 | } |
538 | 0 | (module, name) if adapter_names.contains(module) => { |
539 | 0 | let ty = match import.ty { |
540 | | TypeRef::Global(wasmparser::GlobalType { |
541 | 0 | content_type, |
542 | 0 | mutable, |
543 | 0 | shared, |
544 | | }) => Type::Global(GlobalType { |
545 | 0 | ty: content_type.try_into()?, |
546 | 0 | mutable, |
547 | 0 | shared, |
548 | | }), |
549 | 0 | TypeRef::Func(ty) => Type::Function(FunctionType::try_from( |
550 | 0 | &types[usize::try_from(ty).unwrap()], |
551 | 0 | )?), |
552 | 0 | ty => { |
553 | 0 | bail!("unsupported import kind for {module}.{name}: {ty:?}",) |
554 | | } |
555 | | }; |
556 | 0 | let flags = import_info |
557 | 0 | .get(&(module, name)) |
558 | 0 | .copied() |
559 | 0 | .unwrap_or_default(); |
560 | 0 | result.imports.insert(Import { |
561 | 0 | module, |
562 | 0 | name, |
563 | 0 | ty, |
564 | 0 | flags, |
565 | 0 | }); |
566 | | } |
567 | | _ => { |
568 | 0 | if !matches!(import.ty, TypeRef::Func(_) | TypeRef::Global(_)) { |
569 | 0 | return type_error(); |
570 | 0 | } |
571 | | } |
572 | | } |
573 | | } |
574 | | } |
575 | | |
576 | 0 | Payload::FunctionSection(reader) => { |
577 | 0 | for function in reader { |
578 | 0 | function_types.push(usize::try_from(function?).unwrap()); |
579 | | } |
580 | | } |
581 | | |
582 | 0 | Payload::GlobalSection(reader) => { |
583 | 0 | for global in reader { |
584 | 0 | let global = global?; |
585 | 0 | global_types.push(global.ty); |
586 | | } |
587 | | } |
588 | | |
589 | 0 | Payload::TagSection(reader) => { |
590 | 0 | for tag in reader { |
591 | 0 | tag_types.push(tag?); |
592 | | } |
593 | | } |
594 | | |
595 | 0 | Payload::ExportSection(reader) => { |
596 | 0 | for export in reader { |
597 | 0 | let export = export?; |
598 | | |
599 | 0 | match export.name { |
600 | 0 | self::APPLY_DATA_RELOCS => result.has_data_relocs = true, |
601 | 0 | self::CALL_CTORS => result.has_ctors = true, |
602 | 0 | self::INITIALIZE => result.has_initialize = true, |
603 | 0 | self::START => result.has_wasi_start = true, |
604 | 0 | self::LIBRARY_TLS_INFO => result.has_library_tls_info = true, |
605 | | _ => { |
606 | 0 | let ty = match export.kind { |
607 | 0 | ExternalKind::Func => Type::Function(FunctionType::try_from( |
608 | 0 | &types[function_types |
609 | 0 | [usize::try_from(export.index).unwrap()]], |
610 | 0 | )?), |
611 | | ExternalKind::Global => { |
612 | 0 | let ty = |
613 | 0 | global_types[usize::try_from(export.index).unwrap()]; |
614 | | Type::Global(GlobalType { |
615 | 0 | ty: ValueType::try_from(ty.content_type)?, |
616 | 0 | mutable: ty.mutable, |
617 | 0 | shared: ty.shared, |
618 | | }) |
619 | | } |
620 | 0 | ExternalKind::Tag => Type::Tag(FunctionType::try_from( |
621 | 0 | &types[usize::try_from( |
622 | 0 | tag_types[usize::try_from(export.index).unwrap()] |
623 | 0 | .func_type_idx, |
624 | 0 | ) |
625 | 0 | .unwrap()], |
626 | 0 | )?), |
627 | 0 | kind => { |
628 | 0 | bail!( |
629 | | "unsupported export kind for {}: {kind:?}", |
630 | | export.name |
631 | | ) |
632 | | } |
633 | | }; |
634 | 0 | let flags = |
635 | 0 | export_info.get(&export.name).copied().unwrap_or_default(); |
636 | 0 | result.exports.insert(Export { |
637 | 0 | key: ExportKey { |
638 | 0 | name: export.name, |
639 | 0 | ty, |
640 | 0 | }, |
641 | 0 | flags, |
642 | 0 | }); |
643 | | } |
644 | | } |
645 | | } |
646 | | } |
647 | | |
648 | 0 | _ => {} |
649 | | } |
650 | | } |
651 | | |
652 | 0 | Ok(result) |
653 | 0 | } |
654 | | } |