Coverage Report

Created: 2026-10-12 08:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
0
fn validate_intrinsic_signature(
114
0
    types: &[FuncType],
115
0
    import: wasmparser::Import<'_>,
116
0
    parameters: &[ValueType],
117
0
    results: &[ValueType],
118
0
) -> Result<()> {
119
0
    let module = import.module;
120
0
    let name = import.name;
121
0
    let TypeRef::Func(type_index) = import.ty else {
122
0
        bail!("unexpected type for {module}:{name}: {:?}", import.ty);
123
    };
124
0
    let type_index = usize::try_from(type_index).context("function type index is too large")?;
125
0
    let ty = types.get(type_index).with_context(|| {
126
0
        format!("invalid function type index {type_index} for `{module}.{name}`")
127
0
    })?;
128
0
    let actual = FunctionType::try_from(ty)
129
0
        .with_context(|| format!("failed to read function type for `{module}.{name}`"))?;
130
0
    ensure_linker_abi(
131
0
        &format!("function `{module}.{name}`"),
132
0
        &actual,
133
0
        parameters,
134
0
        results,
135
    )
136
0
}
137
138
/// Checks an export that the linker's generated start function calls, such as
139
/// `__wasm_call_ctors`, against the `[] -> []` type it is called with.
140
///
141
/// `_initialize` and `_start` aren't checked here: the component encoder
142
/// already rejects those with the wrong type when it classifies the exports.
143
0
fn validate_linker_called_export(
144
0
    types: &[FuncType],
145
0
    function_types: &[usize],
146
0
    export: wasmparser::Export<'_>,
147
0
) -> Result<()> {
148
0
    let name = export.name;
149
0
    if export.kind != ExternalKind::Func {
150
0
        bail!("unexpected kind for export `{name}`: {:?}", export.kind);
151
0
    }
152
0
    let actual =
153
0
        FunctionType::try_from(&types[function_types[usize::try_from(export.index).unwrap()]])
154
0
            .with_context(|| format!("failed to read function type for export `{name}`"))?;
155
0
    ensure_linker_abi(&format!("export `{name}`"), &actual, &[], &[])
156
0
}
157
158
0
fn ensure_linker_abi(
159
0
    what: &str,
160
0
    actual: &FunctionType,
161
0
    parameters: &[ValueType],
162
0
    results: &[ValueType],
163
0
) -> Result<()> {
164
0
    if actual.parameters.as_slice() != parameters || actual.results.as_slice() != results {
165
0
        let expected = FunctionType {
166
0
            parameters: parameters.to_vec(),
167
0
            results: results.to_vec(),
168
0
        };
169
0
        bail!("type mismatch for {what}: required linker ABI `{expected}` but found `{actual}`");
170
0
    }
171
0
    Ok(())
172
0
}
173
174
/// Represents a core Wasm global variable type
175
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
176
pub struct GlobalType {
177
    pub ty: ValueType,
178
    pub mutable: bool,
179
    pub shared: bool,
180
}
181
182
impl fmt::Display for GlobalType {
183
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184
0
        if self.mutable {
185
0
            write!(f, "mut ")?;
186
0
        }
187
0
        write!(f, "{:?}", self.ty)
188
0
    }
189
}
190
191
/// Represents a core Wasm export or import type
192
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
193
pub enum Type {
194
    Function(FunctionType),
195
    Global(GlobalType),
196
    Tag(FunctionType),
197
}
198
199
impl fmt::Display for Type {
200
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201
0
        match self {
202
0
            Self::Function(ty) => write!(f, "function {ty}"),
203
0
            Self::Global(ty) => write!(f, "global {ty}"),
204
0
            Self::Tag(ty) => write!(f, "tag {ty}"),
205
        }
206
0
    }
207
}
208
209
impl From<&Type> for wasm_encoder::ExportKind {
210
0
    fn from(value: &Type) -> Self {
211
0
        match value {
212
0
            Type::Function(_) => wasm_encoder::ExportKind::Func,
213
0
            Type::Global(_) => wasm_encoder::ExportKind::Global,
214
0
            Type::Tag(_) => wasm_encoder::ExportKind::Tag,
215
        }
216
0
    }
217
}
218
219
/// Represents a core Wasm import
220
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
221
pub struct Import<'a> {
222
    pub module: &'a str,
223
    pub name: &'a str,
224
    pub ty: Type,
225
    pub flags: SymbolFlags,
226
}
227
228
/// Represents a core Wasm export
229
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
230
pub struct ExportKey<'a> {
231
    pub name: &'a str,
232
    pub ty: Type,
233
}
234
235
impl<'a> fmt::Display for ExportKey<'a> {
236
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237
0
        write!(f, "{} ({})", self.name, self.ty)
238
0
    }
239
}
240
241
/// Represents a core Wasm export, including dylink.0 flags
242
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
243
pub struct Export<'a> {
244
    pub key: ExportKey<'a>,
245
    pub flags: SymbolFlags,
246
}
247
248
/// Metadata extracted from a dynamic library module
249
#[derive(Debug)]
250
pub struct Metadata<'a> {
251
    /// The name of the module
252
    ///
253
    /// This is currently not part of the file itself and must be provided separately, but the plan is to add
254
    /// something like a `WASM_DYLINK_SO_NAME` field to the dynamic linking tool convention so we can parse it
255
    /// along with everything else.
256
    pub name: &'a str,
257
258
    /// Whether this module should be resolvable via `dlopen`
259
    pub dl_openable: bool,
260
261
    /// The `WASM_DYLINK_MEM_INFO` value (or all zeros if not found)
262
    pub mem_info: MemInfo,
263
264
    /// The `WASM_DYLINK_NEEDED` values, if any
265
    pub needed_libs: Vec<&'a str>,
266
267
    /// The `WASM_DYLINK_RUNTIME_PATH` values, if any
268
    pub runtime_path: Vec<&'a str>,
269
270
    /// Whether this module exports `__wasm_apply_data_relocs`
271
    pub has_data_relocs: bool,
272
273
    /// Whether this module exports `__wasm_call_ctors`
274
    pub has_ctors: bool,
275
276
    /// Whether this module exports `_initialize`
277
    pub has_initialize: bool,
278
279
    /// Whether this module exports `_start`
280
    pub has_wasi_start: bool,
281
282
    /// Whether this module imports `__wasm_libdl_libraries`
283
    pub needs_libdl_libraries: bool,
284
285
    /// Whether this module includes any `component-type*` custom sections which include exports
286
    pub has_component_exports: bool,
287
288
    /// Whether this module imports `__asyncify_state` or `__asyncify_data`, indicating that it is
289
    /// asyncified with `--pass-arg=asyncify-relocatable` option.
290
    pub is_asyncified: bool,
291
292
    /// Whether this module imports `__stack_pointer`
293
    pub needs_stack_pointer: bool,
294
295
    /// Whether this module imports `__init_stack_pointer`
296
    pub needs_init_stack_pointer: bool,
297
298
    /// Whether this module imports `__heap_base`
299
    pub needs_heap_base: bool,
300
301
    /// Whether this module imports `__heap_end`
302
    pub needs_heap_end: bool,
303
304
    /// Whether this module imports `__stack_high`
305
    pub needs_stack_high: bool,
306
307
    /// Whether this module imports `__stack_low`
308
    pub needs_stack_low: bool,
309
310
    /// Whether this module imports `env::__wasm_get_tls_base`
311
    pub needs_get_tls_base: bool,
312
313
    /// Whether this module imports `env::__wasm_set_tls_base`
314
    pub needs_set_tls_base: bool,
315
316
    /// Whether this module imports the address of `__wasm_program_tls_info`
317
    pub needs_program_tls_info: bool,
318
319
    /// Whether this module imports `$root::[thread-new-indirect-v0]`, meaning
320
    /// the program may spawn threads and is thus using cooperative threading.
321
    pub uses_thread_new_indirect: bool,
322
323
    /// Whether this module exports a `__wasm_library_tls_info` symbol.
324
    pub has_library_tls_info: bool,
325
326
    /// The functions imported from the `env` module, if any
327
    pub env_imports: BTreeSet<(&'a str, (FunctionType, SymbolFlags))>,
328
329
    /// The memory addresses imported from `GOT.mem`, if any
330
    pub memory_address_imports: BTreeSet<&'a str>,
331
332
    /// The table addresses imported from `GOT.func`, if any
333
    pub table_address_imports: BTreeSet<&'a str>,
334
335
    /// Imported exception tags
336
    pub tag_imports: BTreeSet<(&'a str, FunctionType)>,
337
338
    /// The symbols exported by this module, if any
339
    pub exports: BTreeSet<Export<'a>>,
340
341
    /// The symbols imported by this module (and not accounted for in the above fields), if any
342
    pub imports: BTreeSet<Import<'a>>,
343
}
344
345
impl<'a> Metadata<'a> {
346
    /// Parse the specified module and extract its metadata.
347
0
    pub fn try_new(
348
0
        name: &'a str,
349
0
        dl_openable: bool,
350
0
        module: &'a [u8],
351
0
        adapter_names: &HashSet<&str>,
352
0
    ) -> Result<Self> {
353
0
        let bindgen = crate::metadata::decode(module)?.1;
354
0
        let has_component_exports = !bindgen.resolve.worlds[bindgen.world].exports.is_empty();
355
356
0
        let mut result = Self {
357
0
            name,
358
0
            dl_openable,
359
0
            mem_info: MemInfo {
360
0
                memory_size: 0,
361
0
                memory_alignment: 1,
362
0
                table_size: 0,
363
0
                table_alignment: 1,
364
0
            },
365
0
            needed_libs: Vec::new(),
366
0
            runtime_path: Vec::new(),
367
0
            has_data_relocs: false,
368
0
            has_ctors: false,
369
0
            has_initialize: false,
370
0
            has_wasi_start: false,
371
0
            needs_libdl_libraries: false,
372
0
            has_component_exports,
373
0
            is_asyncified: false,
374
0
            needs_stack_pointer: false,
375
0
            needs_init_stack_pointer: false,
376
0
            needs_heap_base: false,
377
0
            needs_heap_end: false,
378
0
            needs_stack_high: false,
379
0
            needs_stack_low: false,
380
0
            needs_get_tls_base: false,
381
0
            needs_set_tls_base: false,
382
0
            needs_program_tls_info: false,
383
0
            uses_thread_new_indirect: false,
384
0
            has_library_tls_info: false,
385
0
            env_imports: BTreeSet::new(),
386
0
            memory_address_imports: BTreeSet::new(),
387
0
            table_address_imports: BTreeSet::new(),
388
0
            exports: BTreeSet::new(),
389
0
            imports: BTreeSet::new(),
390
0
            tag_imports: BTreeSet::new(),
391
0
        };
392
0
        let mut types = Vec::new();
393
0
        let mut function_types = Vec::new();
394
0
        let mut global_types = Vec::new();
395
0
        let mut tag_types = Vec::new();
396
0
        let mut import_info = HashMap::new();
397
0
        let mut export_info = HashMap::new();
398
399
0
        for payload in Parser::new(0).parse_all(module) {
400
0
            match payload? {
401
0
                Payload::CustomSection(section) => {
402
0
                    if let KnownCustom::Dylink0(reader) = section.as_known() {
403
0
                        for subsection in reader {
404
0
                            match subsection.context("failed to parse `dylink.0` subsection")? {
405
0
                                Dylink0Subsection::MemInfo(info) => result.mem_info = info,
406
0
                                Dylink0Subsection::Needed(needed) => {
407
0
                                    result.needed_libs = needed.clone()
408
                                }
409
0
                                Dylink0Subsection::ExportInfo(info) => {
410
0
                                    export_info
411
0
                                        .extend(info.iter().map(|info| (info.name, info.flags)));
412
                                }
413
0
                                Dylink0Subsection::ImportInfo(info) => {
414
0
                                    import_info.extend(
415
0
                                        info.iter()
416
0
                                            .map(|info| ((info.module, info.field), info.flags)),
417
                                    );
418
                                }
419
0
                                Dylink0Subsection::RuntimePath(runtime_path) => {
420
0
                                    result.runtime_path.extend(runtime_path.iter());
421
0
                                }
422
0
                                Dylink0Subsection::TargetArch(arch) => {
423
0
                                    if arch != "wasm32" {
424
0
                                        bail!("unsupported `dylink.0` target architecture: {arch}")
425
0
                                    }
426
                                }
427
0
                                Dylink0Subsection::Unknown { ty, .. } => {
428
0
                                    bail!("unrecognized `dylink.0` subsection: {ty}")
429
                                }
430
                            }
431
                        }
432
0
                    }
433
                }
434
435
0
                Payload::TypeSection(reader) => {
436
0
                    types = reader
437
0
                        .into_iter_err_on_gc_types()
438
0
                        .collect::<Result<Vec<_>, _>>()?;
439
                }
440
441
0
                Payload::ImportSection(reader) => {
442
0
                    for import in reader.into_imports() {
443
0
                        let import = import?;
444
445
0
                        match import.ty {
446
0
                            TypeRef::Func(ty) => function_types.push(usize::try_from(ty).unwrap()),
447
0
                            TypeRef::Global(ty) => {
448
0
                                global_types.push(ty);
449
0
                            }
450
0
                            TypeRef::Tag(ty) => tag_types.push(ty),
451
0
                            _ => (),
452
                        }
453
454
0
                        let type_error = || {
455
0
                            bail!(
456
                                "unexpected type for {}:{}: {:?}",
457
                                import.module,
458
                                import.name,
459
                                import.ty
460
                            )
461
0
                        };
462
463
0
                        match (import.module, import.name) {
464
0
                            (self::ENV, self::MEMORY) => {
465
0
                                if !matches!(import.ty, TypeRef::Memory(_)) {
466
0
                                    return type_error();
467
0
                                }
468
                            }
469
0
                            (self::ENV, self::ASYNCIFY_DATA | self::ASYNCIFY_STATE) => {
470
0
                                result.is_asyncified = true;
471
0
                                if !matches!(
472
0
                                    import.ty,
473
                                    TypeRef::Global(wasmparser::GlobalType {
474
                                        content_type: ValType::I32,
475
                                        ..
476
                                    })
477
                                ) {
478
0
                                    return type_error();
479
0
                                }
480
                            }
481
                            (
482
                                self::ENV,
483
0
                                self::MEMORY_BASE
484
0
                                | self::TABLE_BASE
485
0
                                | self::STACK_POINTER
486
0
                                | self::INIT_STACK_POINTER,
487
                            ) => {
488
0
                                if matches!(
489
0
                                    import.ty,
490
                                    TypeRef::Global(wasmparser::GlobalType {
491
                                        content_type: ValType::I32,
492
                                        ..
493
                                    })
494
                                ) {
495
0
                                    match import.name {
496
0
                                        self::STACK_POINTER => result.needs_stack_pointer = true,
497
0
                                        self::INIT_STACK_POINTER => {
498
0
                                            result.needs_init_stack_pointer = true
499
                                        }
500
0
                                        _ => {}
501
                                    }
502
                                } else {
503
0
                                    return type_error();
504
                                }
505
                            }
506
0
                            (self::ENV, self::INDIRECT_FUNCTION_TABLE) => {
507
                                if let TypeRef::Table(TableType {
508
0
                                    element_type,
509
                                    maximum: None,
510
                                    ..
511
0
                                }) = import.ty
512
                                {
513
0
                                    if element_type != RefType::FUNCREF {
514
0
                                        return type_error();
515
0
                                    }
516
                                } else {
517
0
                                    return type_error();
518
                                }
519
                            }
520
                            (
521
                                self::ENV,
522
0
                                name @ (self::GET_STACK_POINTER
523
0
                                | self::SET_STACK_POINTER
524
0
                                | self::GET_TLS_BASE
525
0
                                | self::SET_TLS_BASE),
526
                            ) => {
527
0
                                let (parameters, results) = match name {
528
0
                                    self::GET_STACK_POINTER | self::GET_TLS_BASE => {
529
0
                                        (&[][..], &[ValueType::I32][..])
530
                                    }
531
0
                                    self::SET_STACK_POINTER | self::SET_TLS_BASE => {
532
0
                                        (&[ValueType::I32][..], &[][..])
533
                                    }
534
0
                                    _ => unreachable!(),
535
                                };
536
0
                                validate_intrinsic_signature(&types, import, parameters, results)?;
537
0
                                match name {
538
0
                                    self::GET_TLS_BASE => result.needs_get_tls_base = true,
539
0
                                    self::SET_TLS_BASE => result.needs_set_tls_base = true,
540
0
                                    _ => {}
541
                                }
542
                            }
543
0
                            (self::ENV, name) => match import.ty {
544
0
                                TypeRef::Func(ty) => {
545
0
                                    result.env_imports.insert((
546
0
                                        name,
547
                                        (
548
0
                                            FunctionType::try_from(
549
0
                                                &types[usize::try_from(ty).unwrap()],
550
0
                                            )?,
551
0
                                            import_info
552
0
                                                .get(&(self::ENV, name))
553
0
                                                .copied()
554
0
                                                .unwrap_or_default(),
555
                                        ),
556
                                    ));
557
                                }
558
                                TypeRef::Tag(TagType {
559
                                    kind: TagKind::Exception,
560
0
                                    func_type_idx,
561
                                }) => {
562
0
                                    result.tag_imports.insert((
563
0
                                        name,
564
0
                                        FunctionType::try_from(
565
0
                                            &types[usize::try_from(func_type_idx).unwrap()],
566
0
                                        )?,
567
                                    ));
568
                                }
569
0
                                _ => return type_error(),
570
                            },
571
0
                            (self::GOT_MEM, name) => {
572
                                if let TypeRef::Global(wasmparser::GlobalType {
573
                                    content_type: ValType::I32,
574
                                    ..
575
0
                                }) = import.ty
576
                                {
577
0
                                    match name {
578
0
                                        self::HEAP_BASE => result.needs_heap_base = true,
579
0
                                        self::HEAP_END => result.needs_heap_end = true,
580
0
                                        self::STACK_HIGH => result.needs_stack_high = true,
581
0
                                        self::STACK_LOW => result.needs_stack_low = true,
582
0
                                        self::LIBDL_LIBRARIES => {
583
0
                                            result.needs_libdl_libraries = true;
584
0
                                        }
585
0
                                        self::PROGRAM_TLS_INFO => {
586
0
                                            result.needs_program_tls_info = true;
587
0
                                        }
588
589
0
                                        _ => {
590
0
                                            result.memory_address_imports.insert(name);
591
0
                                        }
592
                                    }
593
                                } else {
594
0
                                    return type_error();
595
                                }
596
                            }
597
0
                            (self::GOT_FUNC, name) => {
598
                                if let TypeRef::Global(wasmparser::GlobalType {
599
                                    content_type: ValType::I32,
600
                                    ..
601
0
                                }) = import.ty
602
0
                                {
603
0
                                    result.table_address_imports.insert(name);
604
0
                                } else {
605
0
                                    return type_error();
606
                                }
607
                            }
608
0
                            (self::ROOT, self::THREAD_NEW_INDIRECT) => {
609
0
                                validate_intrinsic_signature(
610
0
                                    &types,
611
0
                                    import,
612
0
                                    &[ValueType::I32, ValueType::I32],
613
0
                                    &[ValueType::I32],
614
0
                                )?;
615
0
                                result.uses_thread_new_indirect = true;
616
                            }
617
0
                            (module, name) if adapter_names.contains(module) => {
618
0
                                let ty = match import.ty {
619
                                    TypeRef::Global(wasmparser::GlobalType {
620
0
                                        content_type,
621
0
                                        mutable,
622
0
                                        shared,
623
                                    }) => Type::Global(GlobalType {
624
0
                                        ty: content_type.try_into()?,
625
0
                                        mutable,
626
0
                                        shared,
627
                                    }),
628
0
                                    TypeRef::Func(ty) => Type::Function(FunctionType::try_from(
629
0
                                        &types[usize::try_from(ty).unwrap()],
630
0
                                    )?),
631
0
                                    ty => {
632
0
                                        bail!("unsupported import kind for {module}.{name}: {ty:?}",)
633
                                    }
634
                                };
635
0
                                let flags = import_info
636
0
                                    .get(&(module, name))
637
0
                                    .copied()
638
0
                                    .unwrap_or_default();
639
0
                                result.imports.insert(Import {
640
0
                                    module,
641
0
                                    name,
642
0
                                    ty,
643
0
                                    flags,
644
0
                                });
645
                            }
646
                            _ => {
647
0
                                if !matches!(import.ty, TypeRef::Func(_) | TypeRef::Global(_)) {
648
0
                                    return type_error();
649
0
                                }
650
                            }
651
                        }
652
                    }
653
                }
654
655
0
                Payload::FunctionSection(reader) => {
656
0
                    for function in reader {
657
0
                        function_types.push(usize::try_from(function?).unwrap());
658
                    }
659
                }
660
661
0
                Payload::GlobalSection(reader) => {
662
0
                    for global in reader {
663
0
                        let global = global?;
664
0
                        global_types.push(global.ty);
665
                    }
666
                }
667
668
0
                Payload::TagSection(reader) => {
669
0
                    for tag in reader {
670
0
                        tag_types.push(tag?);
671
                    }
672
                }
673
674
0
                Payload::ExportSection(reader) => {
675
0
                    for export in reader {
676
0
                        let export = export?;
677
678
0
                        match export.name {
679
0
                            self::APPLY_DATA_RELOCS => {
680
0
                                validate_linker_called_export(&types, &function_types, export)?;
681
0
                                result.has_data_relocs = true;
682
                            }
683
0
                            self::CALL_CTORS => {
684
0
                                validate_linker_called_export(&types, &function_types, export)?;
685
0
                                result.has_ctors = true;
686
                            }
687
0
                            self::INITIALIZE => result.has_initialize = true,
688
0
                            self::START => result.has_wasi_start = true,
689
0
                            self::LIBRARY_TLS_INFO => result.has_library_tls_info = true,
690
                            _ => {
691
0
                                let ty = match export.kind {
692
0
                                    ExternalKind::Func => Type::Function(FunctionType::try_from(
693
0
                                        &types[function_types
694
0
                                            [usize::try_from(export.index).unwrap()]],
695
0
                                    )?),
696
                                    ExternalKind::Global => {
697
0
                                        let ty =
698
0
                                            global_types[usize::try_from(export.index).unwrap()];
699
                                        Type::Global(GlobalType {
700
0
                                            ty: ValueType::try_from(ty.content_type)?,
701
0
                                            mutable: ty.mutable,
702
0
                                            shared: ty.shared,
703
                                        })
704
                                    }
705
0
                                    ExternalKind::Tag => Type::Tag(FunctionType::try_from(
706
0
                                        &types[usize::try_from(
707
0
                                            tag_types[usize::try_from(export.index).unwrap()]
708
0
                                                .func_type_idx,
709
0
                                        )
710
0
                                        .unwrap()],
711
0
                                    )?),
712
0
                                    kind => {
713
0
                                        bail!(
714
                                            "unsupported export kind for {}: {kind:?}",
715
                                            export.name
716
                                        )
717
                                    }
718
                                };
719
0
                                let flags =
720
0
                                    export_info.get(&export.name).copied().unwrap_or_default();
721
0
                                result.exports.insert(Export {
722
0
                                    key: ExportKey {
723
0
                                        name: export.name,
724
0
                                        ty,
725
0
                                    },
726
0
                                    flags,
727
0
                                });
728
                            }
729
                        }
730
                    }
731
                }
732
733
0
                _ => {}
734
            }
735
        }
736
737
0
        Ok(result)
738
0
    }
739
}