Skip to main content

wasmer_compiler/engine/
artifact.rs

1//! Define `Artifact`, based on `ArtifactBuild`
2//! to allow compiling and instantiating to be done as separate steps.
3
4use std::{
5    fs::File,
6    io::BufReader,
7    mem::size_of,
8    path::{Path, PathBuf},
9    sync::{
10        Arc,
11        atomic::{AtomicUsize, Ordering::SeqCst},
12    },
13};
14
15#[cfg(feature = "compiler")]
16use crate::ModuleEnvironment;
17use crate::{
18    ArtifactBuild, ArtifactBuildFromArchive, ArtifactCreate, Engine, EngineInner, Features,
19    FrameInfosVariant, FunctionExtent, GlobalFrameInfoRegistration, InstantiationError, Tunables,
20    WASMER_TRAP_FUNCTION_OFFSETS_SECTION_NAME, WASMER_TRAPS_SECTION_NAME,
21    engine::{link::link_module, resolver::resolve_tags, trap::register_frame_info_source},
22    resolve_imports,
23    serialize::{MetadataHeader, SerializableCompilation, SerializableModule},
24    types::relocation::{RelocationLike, RelocationTarget},
25};
26#[cfg(feature = "static-artifact-create")]
27use crate::{Compiler, FunctionBodyData, ModuleTranslationState, types::module::CompileModuleInfo};
28#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
29use crate::{serialize::RkyvSerializableCompilation, types::symbols::ModuleMetadata};
30use itertools::Itertools;
31#[cfg(unix)]
32use std::os::fd::AsRawFd;
33use std::vec::IntoIter;
34#[cfg(feature = "compiler")]
35use wasmer_types::CompilationProgressCallback;
36
37use enumset::EnumSet;
38use object::{Object as _, ObjectSection as _, ReadCache, ReadRef};
39use shared_buffer::OwnedBuffer;
40
41use crate::engine::mapped_binary::DebugInfoSource;
42
43#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
44use std::mem;
45
46#[cfg(feature = "static-artifact-create")]
47use crate::object::{
48    Object, ObjectMetadataBuilder, emit_compilation, emit_data, get_object_for_target,
49};
50
51use wasmer_types::{
52    ArchivedDataInitializerLocation, ArchivedOwnedDataInitializer, CompileError, DataInitializer,
53    DataInitializerLike, DataInitializerLocation, DataInitializerLocationLike, DeserializeError,
54    FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, OwnedDataInitializer,
55    SerializeError, SignatureIndex, TableIndex, TrapCode, TrapInformation,
56    entity::{BoxedSlice, EntityRef, PrimaryMap},
57    target::{CpuFeature, Target},
58};
59
60use wasmer_types::VMOffsets;
61use wasmer_vm::{
62    FunctionBodyPtr, InstanceAllocator, MemoryStyle, StoreObjects, TableStyle, TrapHandlerFn,
63    VMConfig, VMExtern, VMInstance, VMSignatureHash, VMTrampoline,
64};
65
66#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
67pub struct AllocatedArtifact {
68    // This shows if the frame info has been registered already or not.
69    // Because the 'GlobalFrameInfoRegistration' ownership can be transferred to EngineInner
70    // this bool is needed to track the status, as 'frame_info_registration' will be None
71    // after the ownership is transferred.
72    frame_info_registered: bool,
73    // frame_info_registered is not staying there but transferred to CodeMemory from EngineInner
74    // using 'Artifact::take_frame_info_registration' method
75    // so the GloabelFrameInfo and MMap stays in sync and get dropped at the same time
76    frame_info_registration: Option<GlobalFrameInfoRegistration>,
77    finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
78
79    #[cfg_attr(feature = "artifact-size", loupe(skip))]
80    finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
81    finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
82    signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
83    finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
84    // The maximum stack size used for each function (available only for the Singlepass compiler).
85    function_max_stack_usage: BoxedSlice<LocalFunctionIndex, Option<usize>>,
86
87    /// Precomputed `VMOffsets` for this artifact's module, cloned by
88    /// `Artifact::instantiate` instead of recomputing on every call.
89    ///
90    /// Safe to cache because `VMOffsets::try_new(pointer_size, module_info)`
91    /// is deterministic, `module_info` is immutable after compile (the
92    /// only mutable field `name` is not a `VMOffsets` input), and the
93    /// host's pointer size is a runtime constant.
94    ///
95    /// Built once in `from_parts` and in the deserialization path
96    /// (`deserialize_object_native`); `VMOffsets::try_new` was ~9% of
97    /// `Instance::new` time on profile traces of a per-request wasm
98    /// host calling `Module::instantiate` in a tight loop.
99    #[cfg_attr(feature = "artifact-size", loupe(skip))]
100    vm_offsets: VMOffsets,
101
102    /// The base address the module's code was loaded at, and the raw ELF
103    /// image bytes it was loaded from, when this artifact was built from a
104    /// native ELF image. Used to lazily build DWARF debug info for frame
105    /// symbolication. `None` for non-ELF artifacts.
106    #[cfg_attr(feature = "artifact-size", loupe(skip))]
107    elf_image: Option<(usize, DebugInfoSource)>,
108}
109
110impl AllocatedArtifact {
111    fn function_extents(&self) -> PrimaryMap<LocalFunctionIndex, FunctionExtent> {
112        assert_eq!(
113            self.finished_functions.len(),
114            self.finished_function_lengths.len(),
115            "finished_functions and finished_function_lengths must have equal length"
116        );
117        self.finished_functions
118            .iter()
119            .map(|(index, &ptr)| {
120                let length = self.finished_function_lengths[index];
121                FunctionExtent { ptr, length }
122            })
123            .collect()
124    }
125}
126
127#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
128#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
129#[repr(transparent)]
130/// A unique identifier for an Artifact.
131pub struct ArtifactId {
132    id: usize,
133}
134
135impl ArtifactId {
136    /// Format this identifier as a string.
137    pub fn id(&self) -> String {
138        format!("{}", self.id)
139    }
140}
141
142impl Clone for ArtifactId {
143    fn clone(&self) -> Self {
144        Self::default()
145    }
146}
147
148impl Default for ArtifactId {
149    fn default() -> Self {
150        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
151        Self {
152            id: NEXT_ID.fetch_add(1, SeqCst),
153        }
154    }
155}
156
157/// A compiled wasm module, ready to be instantiated.
158#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
159pub struct Artifact {
160    id: ArtifactId,
161    artifact: ArtifactBuildVariant,
162    #[cfg_attr(feature = "artifact-size", loupe(skip))]
163    module_file: Option<PathBuf>,
164    // The artifact will only be allocated in memory in case we can execute it
165    // (that means, if the target != host then this will be None).
166    allocated: Option<AllocatedArtifact>,
167}
168
169/// Artifacts may be created as the result of the compilation of a wasm
170/// module, corresponding to `ArtifactBuildVariant::Plain`, or loaded
171/// from an archive, corresponding to `ArtifactBuildVariant::Archived`.
172#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
173#[allow(clippy::large_enum_variant)]
174pub enum ArtifactBuildVariant {
175    Plain(ArtifactBuild),
176    Archived(ArtifactBuildFromArchive),
177}
178
179impl Artifact {
180    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
181    #[cfg(feature = "compiler")]
182    pub fn new(
183        engine: &Engine,
184        data: &[u8],
185        tunables: &dyn Tunables,
186        progress_callback: Option<CompilationProgressCallback>,
187    ) -> Result<Self, CompileError> {
188        let mut inner_engine = engine.inner_mut();
189        let environ = ModuleEnvironment::new();
190        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
191        let module = translation.module;
192        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
193            .memories
194            .values()
195            .map(|memory_type| tunables.memory_style(memory_type))
196            .collect();
197        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
198            .tables
199            .values()
200            .map(|table_type| tunables.table_style(table_type))
201            .collect();
202
203        let artifact = ArtifactBuild::new(
204            &mut inner_engine,
205            data,
206            engine.target(),
207            memory_styles,
208            table_styles,
209            progress_callback.as_ref(),
210        )?;
211
212        Self::from_parts_with_module_file(
213            &mut inner_engine,
214            ArtifactBuildVariant::Plain(artifact),
215            engine.target(),
216            None,
217        )
218        .map_err(|e| match e {
219            DeserializeError::Compiler(c) => c,
220            DeserializeError::Generic(c) => CompileError::Resource(c),
221
222            // `from_parts` only ever returns `CompileError`s when an
223            // `ArtifactBuildVariant::Plain` is passed in. Other cases
224            // of `DeserializeError` can only happen when an
225            // `ArtifactBuildVariant::Archived` is passed in. We don't
226            // wish to change the return type of this method because
227            // a. it makes no sense and b. it would be a breaking change,
228            // hence this match block and the other cases being
229            // unreachable.
230            _ => unreachable!(),
231        })
232    }
233
234    /// This indicates if the Artifact is allocated and can be run by the current
235    /// host. In case it can't be run (for example, if the artifact is cross compiled to
236    /// other architecture), it will return false.
237    pub fn allocated(&self) -> bool {
238        self.allocated.is_some()
239    }
240
241    /// A unique identifier for this object.
242    ///
243    /// This exists to allow us to compare two Artifacts for equality. Otherwise,
244    /// comparing two trait objects unsafely relies on implementation details
245    /// of trait representation.
246    pub fn id(&self) -> &ArtifactId {
247        &self.id
248    }
249
250    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
251    #[cfg(not(feature = "compiler"))]
252    pub fn new(_engine: &Engine, _data: &[u8]) -> Result<Self, CompileError> {
253        Err(CompileError::Codegen(
254            "Compilation is not enabled in the engine".to_string(),
255        ))
256    }
257
258    /// Load an ELF artifact directly from a file-backed memory map.
259    ///
260    /// Unlike [`Self::deserialize`], this entrypoint only accepts ELF artifacts.
261    ///
262    /// # Safety
263    /// This function loads executable code into memory. The file must be trusted
264    /// and must not be modified while the returned artifact is in use.
265    pub unsafe fn deserialize_file(
266        engine: &Engine,
267        path: impl AsRef<Path>,
268    ) -> Result<Self, DeserializeError> {
269        let path = path.as_ref().to_path_buf();
270        let file = File::open(&path)?;
271        let cache = ReadCache::new(BufReader::new(file));
272        let image = object::File::parse(&cache)
273            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
274        if image.format() != object::BinaryFormat::Elf {
275            return Err(DeserializeError::Incompatible(
276                "Artifact::deserialize_file only supports ELF artifacts".to_string(),
277            ));
278        }
279
280        let module_info = image
281            .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
282            .ok_or_else(|| {
283                DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
284            })?
285            .data()
286            .map_err(|e| {
287                DeserializeError::CorruptedBinary(format!(
288                    "cannot load ModuleInfo section data: {e}"
289                ))
290            })?;
291        let serializable = unsafe { SerializableModule::deserialize(module_info)? };
292        if !matches!(serializable.compilation, SerializableCompilation::Elf(_)) {
293            return Err(DeserializeError::Incompatible(
294                "file does not contain an ELF artifact".to_string(),
295            ));
296        }
297
298        let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
299        let mut inner_engine = engine.inner_mut();
300        Self::from_parts_with_module_file(&mut inner_engine, artifact, engine.target(), Some(path))
301    }
302
303    /// Deserialize an ELF artifact held in memory, if the bytes contain one.
304    fn deserialize_elf(engine: &Engine, bytes: &[u8]) -> Result<Option<Self>, DeserializeError> {
305        if !bytes.starts_with(&object::elf::ELFMAG) {
306            return Ok(None);
307        }
308
309        let image = object::File::parse(bytes)
310            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
311        let module_info = image
312            .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
313            .ok_or_else(|| {
314                DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
315            })?
316            .data()
317            .map_err(|e| {
318                DeserializeError::CorruptedBinary(format!(
319                    "cannot load ModuleInfo section data: {e}"
320                ))
321            })?;
322        let mut serializable = unsafe { SerializableModule::deserialize(module_info)? };
323        let SerializableCompilation::Elf(elf) = &mut serializable.compilation else {
324            return Err(DeserializeError::Incompatible(
325                "ELF image does not contain an ELF artifact".to_string(),
326            ));
327        };
328        // The copy embedded in the image has an empty ELF placeholder to avoid
329        // embedding the image in itself. Restore it for allocation and reserialization.
330        *elf = bytes.to_vec();
331
332        let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
333        let mut inner_engine = engine.inner_mut();
334        Self::from_parts(&mut inner_engine, artifact, engine.target()).map(Some)
335    }
336
337    /// Deserialize a serialized artifact.
338    ///
339    /// # Safety
340    /// This function loads executable code into memory.
341    /// You must trust the loaded bytes to be valid for the chosen engine and
342    /// for the host CPU architecture.
343    /// In contrast to [`Self::deserialize_unchecked`] the artifact layout is
344    /// validated, which increases safety.
345    pub unsafe fn deserialize(
346        engine: &Engine,
347        bytes: OwnedBuffer,
348    ) -> Result<Self, DeserializeError> {
349        unsafe {
350            if !ArtifactBuild::has_rkyv_header(bytes.as_ref()) {
351                if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
352                    return Ok(artifact);
353                }
354
355                let static_artifact = Self::deserialize_object(engine, bytes);
356                match static_artifact {
357                    Ok(v) => {
358                        return Ok(v);
359                    }
360                    Err(e) => {
361                        return Err(DeserializeError::Incompatible(format!(
362                            "The provided bytes are not a Wasmer engine artifact: {e}"
363                        )));
364                    }
365                }
366            }
367
368            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
369                let bytes =
370                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
371
372                let metadata_len = MetadataHeader::parse(bytes)?;
373                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
374                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
375
376                SerializableModule::archive_from_slice_checked(metadata_slice)
377            })?;
378
379            let mut inner_engine = engine.inner_mut();
380            Self::from_parts(
381                &mut inner_engine,
382                ArtifactBuildVariant::Archived(artifact),
383                engine.target(),
384            )
385        }
386    }
387
388    /// Deserialize a serialized artifact.
389    ///
390    /// NOTE: You should prefer [`Self::deserialize`].
391    ///
392    /// # Safety
393    /// See [`Self::deserialize`].
394    /// In contrast to the above, this function skips artifact layout validation,
395    /// which increases the risk of loading invalid artifacts.
396    pub unsafe fn deserialize_unchecked(
397        engine: &Engine,
398        bytes: OwnedBuffer,
399    ) -> Result<Self, DeserializeError> {
400        unsafe {
401            if !ArtifactBuild::has_rkyv_header(bytes.as_ref()) {
402                if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
403                    return Ok(artifact);
404                }
405
406                let static_artifact = Self::deserialize_object(engine, bytes);
407                match static_artifact {
408                    Ok(v) => {
409                        return Ok(v);
410                    }
411                    Err(e) => {
412                        return Err(DeserializeError::Incompatible(format!(
413                            "The provided bytes are not a Wasmer engine artifact: {e}"
414                        )));
415                    }
416                }
417            }
418
419            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
420                let bytes =
421                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
422
423                let metadata_len = MetadataHeader::parse(bytes)?;
424                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
425                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
426
427                SerializableModule::archive_from_slice(metadata_slice)
428            })?;
429
430            let mut inner_engine = engine.inner_mut();
431            Self::from_parts(
432                &mut inner_engine,
433                ArtifactBuildVariant::Archived(artifact),
434                engine.target(),
435            )
436        }
437    }
438
439    /// Construct a `ArtifactBuild` from component parts.
440    pub fn from_parts(
441        engine_inner: &mut EngineInner,
442        artifact: ArtifactBuildVariant,
443        target: &Target,
444    ) -> Result<Self, DeserializeError> {
445        Self::from_parts_with_module_file(engine_inner, artifact, target, None)
446    }
447
448    fn from_parts_with_module_file(
449        engine_inner: &mut EngineInner,
450        artifact: ArtifactBuildVariant,
451        target: &Target,
452        module_file: Option<PathBuf>,
453    ) -> Result<Self, DeserializeError> {
454        if !target.is_native() {
455            return Ok(Self {
456                id: Default::default(),
457                artifact,
458                module_file,
459                allocated: None,
460            });
461        } else {
462            // check if cpu features are compatible before anything else
463            let cpu_features = artifact.cpu_features();
464            if !target.cpu_features().is_superset(cpu_features) {
465                return Err(DeserializeError::Incompatible(format!(
466                    "Some CPU Features needed for the artifact are missing: {:?}",
467                    cpu_features.difference(*target.cpu_features())
468                )));
469            }
470        }
471        let module_info = artifact.module_info();
472
473        let elf_file_data = match &artifact {
474            ArtifactBuildVariant::Plain(p) => {
475                if let SerializableCompilation::Elf(data) = &p.serializable.compilation {
476                    Some(data.as_ref())
477                } else {
478                    None
479                }
480            }
481            ArtifactBuildVariant::Archived(a) => a.get_elf_file(),
482        };
483        let mut allocated = if let Some(module_file) = module_file.as_ref() {
484            if elf_file_data.is_none() {
485                return Err(DeserializeError::Incompatible(
486                    "file-backed loading only supports ELF artifacts".to_string(),
487                ));
488            }
489            Self::allocate_elf_artifact_from_path(engine_inner, module_info, module_file)?
490        } else if let Some(elf_file_data) = elf_file_data {
491            Self::allocate_elf_artifact(engine_inner, module_info, elf_file_data)?
492        } else {
493            let (
494                finished_functions,
495                finished_function_call_trampolines,
496                finished_dynamic_function_trampolines,
497                custom_sections,
498            ) = match &artifact {
499                ArtifactBuildVariant::Plain(p) => engine_inner.allocate(
500                    module_info,
501                    p.get_function_bodies_ref()
502                        .expect("RKYV path expected")
503                        .values(),
504                    p.get_function_call_trampolines_ref()
505                        .expect("RKYV path expected")
506                        .values(),
507                    p.get_dynamic_function_trampolines_ref()
508                        .expect("RKYV path expected")
509                        .values(),
510                    p.get_custom_sections_ref()
511                        .expect("RKYV path expected")
512                        .values(),
513                )?,
514
515                ArtifactBuildVariant::Archived(a) => engine_inner.allocate(
516                    module_info,
517                    a.get_function_bodies_ref()
518                        .expect("RKYV path expected")
519                        .values(),
520                    a.get_function_call_trampolines_ref()
521                        .expect("RKYV path expected")
522                        .values(),
523                    a.get_dynamic_function_trampolines_ref()
524                        .expect("RKYV path expected")
525                        .values(),
526                    a.get_custom_sections_ref()
527                        .expect("RKYV path expected")
528                        .values(),
529                )?,
530            };
531
532            let get_got_address: Box<dyn Fn(RelocationTarget) -> Option<usize>> = match &artifact {
533                ArtifactBuildVariant::Plain(p) => {
534                    if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
535                        let relocs: Vec<_> = p
536                            .get_custom_section_relocations_ref()
537                            .expect("RKYV path expected")[got]
538                            .iter()
539                            .map(|v| (v.reloc_target, v.offset))
540                            .collect();
541                        let got_base = custom_sections[got].0 as usize;
542                        Box::new(move |t: RelocationTarget| {
543                            relocs
544                                .iter()
545                                .find(|(v, _)| v == &t)
546                                .map(|(_, o)| got_base + (*o as usize))
547                        })
548                    } else {
549                        Box::new(|_: RelocationTarget| None)
550                    }
551                }
552
553                ArtifactBuildVariant::Archived(p) => {
554                    if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
555                        let relocs: Vec<_> = p
556                            .get_custom_section_relocations_ref()
557                            .expect("RKYV path expected")[got]
558                            .iter()
559                            .map(|v| (v.reloc_target(), v.offset))
560                            .collect();
561                        let got_base = custom_sections[got].0 as usize;
562                        Box::new(move |t: RelocationTarget| {
563                            relocs
564                                .iter()
565                                .find(|(v, _)| v == &t)
566                                .map(|(_, o)| got_base + (o.to_native() as usize))
567                        })
568                    } else {
569                        Box::new(|_: RelocationTarget| None)
570                    }
571                }
572            };
573            let functions_max_stack_usage = match &artifact {
574                ArtifactBuildVariant::Plain(p) => p
575                    .get_function_max_stack_usage()
576                    .expect("RKYV path expected")
577                    .values()
578                    .cloned()
579                    .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
580                ArtifactBuildVariant::Archived(a) => a
581                    .get_function_max_stack_usage()
582                    .expect("RKYV path expected")
583                    .values()
584                    .cloned()
585                    .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
586            };
587
588            match &artifact {
589                ArtifactBuildVariant::Plain(p) => link_module(
590                    module_info,
591                    &finished_functions,
592                    &finished_dynamic_function_trampolines,
593                    p.get_function_relocations()
594                        .expect("RKYV path expected")
595                        .iter()
596                        .map(|(k, v)| (k, v.iter())),
597                    &custom_sections,
598                    p.get_custom_section_relocations_ref()
599                        .expect("RKYV path expected")
600                        .iter()
601                        .map(|(k, v)| (k, v.iter())),
602                    p.get_libcall_trampolines().expect("RKYV path expected"),
603                    p.get_libcall_trampoline_len().expect("RKYV path expected"),
604                    &get_got_address,
605                ),
606                ArtifactBuildVariant::Archived(a) => link_module(
607                    module_info,
608                    &finished_functions,
609                    &finished_dynamic_function_trampolines,
610                    a.get_function_relocations()
611                        .expect("RKYV path expected")
612                        .iter()
613                        .map(|(k, v)| (k, v.iter())),
614                    &custom_sections,
615                    a.get_custom_section_relocations_ref()
616                        .expect("RKYV path expected")
617                        .iter()
618                        .map(|(k, v)| (k, v.iter())),
619                    a.get_libcall_trampolines().expect("RKYV path expected"),
620                    a.get_libcall_trampoline_len().expect("RKYV path expected"),
621                    &get_got_address,
622                ),
623            };
624
625            // Compute indices into the shared signature table.
626            let signatures = {
627                let signature_registry = engine_inner.signatures();
628                module_info
629                    .signatures
630                    .values()
631                    .zip(module_info.signature_hashes.values())
632                    .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
633                    .collect::<PrimaryMap<_, _>>()
634            };
635
636            #[allow(unused_variables)]
637            let eh_frame = match &artifact {
638                ArtifactBuildVariant::Plain(p) => p
639                    .get_unwind_info()
640                    .expect("RKYV path expected")
641                    .eh_frame
642                    .map(|v| unsafe {
643                        std::slice::from_raw_parts(
644                            *custom_sections[v],
645                            p.get_custom_sections_ref().expect("RKYV path expected")[v]
646                                .bytes
647                                .len(),
648                        )
649                    }),
650                ArtifactBuildVariant::Archived(a) => a
651                    .get_unwind_info()
652                    .expect("RKYV path expected")
653                    .eh_frame
654                    .map(|v| unsafe {
655                        std::slice::from_raw_parts(
656                            *custom_sections[v],
657                            a.get_custom_sections_ref().expect("RKYV path expected")[v]
658                                .bytes
659                                .len(),
660                        )
661                    }),
662            };
663            #[allow(unused_variables)]
664            let compact_unwind = match &artifact {
665                ArtifactBuildVariant::Plain(p) => p
666                    .get_unwind_info()
667                    .expect("RKYV path expected")
668                    .compact_unwind
669                    .map(|v| unsafe {
670                        std::slice::from_raw_parts(
671                            *custom_sections[v],
672                            p.get_custom_sections_ref().expect("RKYV path expected")[v]
673                                .bytes
674                                .len(),
675                        )
676                    }),
677                ArtifactBuildVariant::Archived(a) => a
678                    .get_unwind_info()
679                    .expect("RKYV path expected")
680                    .compact_unwind
681                    .map(|v| unsafe {
682                        std::slice::from_raw_parts(
683                            *custom_sections[v],
684                            a.get_custom_sections_ref().expect("RKYV path expected")[v]
685                                .bytes
686                                .len(),
687                        )
688                    }),
689            };
690
691            #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
692            {
693                engine_inner.register_perfmap(&finished_functions, module_info)?;
694            }
695
696            // Make all code compiled thus far executable.
697            engine_inner.publish_compiled_code();
698
699            #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
700            if let Some(compact_unwind) = compact_unwind {
701                engine_inner.publish_compact_unwind(
702                    compact_unwind,
703                    get_got_address(RelocationTarget::LibCall(wasmer_vm::LibCall::EHPersonality)),
704                )?;
705            }
706            #[cfg(not(any(
707                target_arch = "wasm32",
708                all(target_os = "macos", target_arch = "aarch64")
709            )))]
710            engine_inner.publish_eh_frame(eh_frame)?;
711
712            drop(get_got_address);
713
714            let finished_function_lengths = finished_functions
715                .values()
716                .map(|extent| extent.length)
717                .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
718                .into_boxed_slice();
719            let finished_functions = finished_functions
720                .values()
721                .map(|extent| extent.ptr)
722                .collect::<PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>>()
723                .into_boxed_slice();
724            let finished_function_call_trampolines =
725                finished_function_call_trampolines.into_boxed_slice();
726            let finished_dynamic_function_trampolines =
727                finished_dynamic_function_trampolines.into_boxed_slice();
728            let signatures = signatures.into_boxed_slice();
729
730            let vm_offsets = VMOffsets::try_new(std::mem::size_of::<usize>() as u8, module_info)
731                .map_err(DeserializeError::Generic)?;
732
733            AllocatedArtifact {
734                frame_info_registered: false,
735                frame_info_registration: None,
736                finished_functions,
737                finished_function_call_trampolines,
738                finished_dynamic_function_trampolines,
739                signatures,
740                finished_function_lengths,
741                vm_offsets,
742                function_max_stack_usage: functions_max_stack_usage.into_boxed_slice(),
743                elf_image: None,
744            }
745        };
746
747        // ELF allocation recovers function addresses from the linked image, but
748        // maximum stack usage is compile metadata rather than an ELF property.
749        // Preserve it from the metadata embedded in the artifact, just as the
750        // in-memory Rkyv path does above.
751        if allocated.elf_image.is_some() {
752            allocated.function_max_stack_usage = match &artifact {
753                ArtifactBuildVariant::Plain(p) => p
754                    .get_function_max_stack_usage()
755                    .expect("function stack usage metadata expected")
756                    .values()
757                    .cloned()
758                    .collect::<PrimaryMap<LocalFunctionIndex, _>>()
759                    .into_boxed_slice(),
760                ArtifactBuildVariant::Archived(a) => a
761                    .get_function_max_stack_usage()
762                    .expect("function stack usage metadata expected")
763                    .values()
764                    .cloned()
765                    .collect::<PrimaryMap<LocalFunctionIndex, _>>()
766                    .into_boxed_slice(),
767            };
768        }
769
770        let mut artifact = Self {
771            id: Default::default(),
772            artifact,
773            module_file,
774            allocated: Some(allocated),
775        };
776
777        let is_elf = artifact
778            .allocated
779            .as_ref()
780            .expect("It must be allocated")
781            .elf_image
782            .is_some();
783
784        artifact
785            .internal_register_frame_info()
786            .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))?;
787        if let Some(frame_info) = artifact.internal_take_frame_info_registration() {
788            if is_elf {
789                engine_inner.register_elf_frame_info(frame_info);
790            } else {
791                engine_inner.register_frame_info(frame_info);
792            }
793        }
794
795        Ok(artifact)
796    }
797
798    /// Build an [`AllocatedArtifact`] from a compiled native ELF image.
799    ///
800    /// Note that, unlike [`Self::allocate_elf_artifact_from_path`], no debugger
801    /// command file is registered here: the image only exists in memory, so
802    /// there is no path a debugger could load symbols from.
803    fn allocate_elf_artifact(
804        engine_inner: &mut EngineInner,
805        module_info: &ModuleInfo,
806        elf_file_data: &[u8],
807    ) -> Result<AllocatedArtifact, DeserializeError> {
808        let image = object::File::parse(elf_file_data)
809            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
810        let base = engine_inner.map_elf_binary(&image, elf_file_data)?;
811        Self::allocate_elf_artifact_from_image(
812            engine_inner,
813            module_info,
814            &image,
815            base,
816            DebugInfoSource::Bytes(Arc::from(elf_file_data)),
817        )
818    }
819
820    #[cfg(unix)]
821    fn allocate_elf_artifact_from_path(
822        engine_inner: &mut EngineInner,
823        module_info: &ModuleInfo,
824        path: &Path,
825    ) -> Result<AllocatedArtifact, DeserializeError> {
826        use std::sync::Mutex;
827
828        let file = File::open(path)?;
829        let fd = file.as_raw_fd();
830        let debug_file = file.try_clone()?;
831        let cache = ReadCache::new(BufReader::new(file));
832        let image = object::File::parse(&cache)
833            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
834        if image.format() != object::BinaryFormat::Elf {
835            return Err(DeserializeError::Incompatible(
836                "file-backed Artifact is not ELF".to_string(),
837            ));
838        }
839        let base = engine_inner.map_elf_binary_file(&image, fd)?;
840        #[cfg(feature = "compiler")]
841        if let Some(debugger) = engine_inner.debugger() {
842            engine_inner.register_debugger(path, base, debugger)?;
843        }
844        Self::allocate_elf_artifact_from_image(
845            engine_inner,
846            module_info,
847            &image,
848            base,
849            DebugInfoSource::File(Arc::new(Mutex::new(debug_file))),
850        )
851    }
852
853    #[cfg(not(unix))]
854    fn allocate_elf_artifact_from_path(
855        _engine_inner: &mut EngineInner,
856        _module_info: &ModuleInfo,
857        _path: &Path,
858    ) -> Result<AllocatedArtifact, DeserializeError> {
859        Err(DeserializeError::Incompatible(
860            "file-backed ELF artifacts are only supported on Unix".to_string(),
861        ))
862    }
863
864    fn allocate_elf_artifact_from_image<'a, R: object::ReadRef<'a>>(
865        engine_inner: &mut EngineInner,
866        module_info: &ModuleInfo,
867        image: &object::File<'a, R>,
868        base: *mut std::ffi::c_void,
869        debug_info: DebugInfoSource,
870    ) -> Result<AllocatedArtifact, DeserializeError> {
871        let mut function_offsets = None;
872        for section in image.sections() {
873            let Ok(section_name) = section.name_bytes() else {
874                continue;
875            };
876            match section_name {
877                crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME => {
878                    let data = section.data().map_err(|e| {
879                        DeserializeError::CorruptedBinary(format!(
880                            "cannot load image section data: {e}"
881                        ))
882                    })?;
883                    function_offsets = Some(
884                        data.chunks_exact(std::mem::size_of::<usize>())
885                            .map(|chunk| usize::from_le_bytes(chunk.try_into().unwrap()))
886                            .collect_vec(),
887                    );
888                }
889                crate::EH_FRAME_SECTION_NAME => {
890                    engine_inner.publish_elf_eh_frame(section.address(), section.size())?;
891                }
892                _ => {}
893            }
894        }
895
896        let Some(function_offsets) = function_offsets else {
897            return Err(DeserializeError::CorruptedBinary(
898                "missing function offset section in the image".to_string(),
899            ));
900        };
901
902        let local_function_count = module_info.local_func_count();
903        let corrupted_offsets = || {
904            DeserializeError::CorruptedBinary(format!(
905                "corrupted {} section",
906                String::from_utf8_lossy(crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME)
907            ))
908        };
909        let signature_count = module_info.signatures.len();
910        let dynamic_trampoline_count = module_info.imported_function_types().count();
911        let expected_offset_count = local_function_count
912            .checked_add(signature_count)
913            .and_then(|count| count.checked_add(dynamic_trampoline_count))
914            .ok_or_else(&corrupted_offsets)?;
915        if function_offsets.len() != expected_offset_count {
916            return Err(corrupted_offsets());
917        }
918
919        let (local_fn_offsets, rest) = function_offsets.split_at(local_function_count);
920        let (trampoline_offsets, dynamic_trampoline_offsets) = rest.split_at(signature_count);
921
922        // Right now, we calculate function sizes as the difference from the next function.
923        let local_fn_sizes = function_offsets
924            .iter()
925            .skip(1)
926            .take(local_function_count)
927            .zip(function_offsets.iter())
928            .map(|(f1, f0)| f1.checked_sub(*f0).ok_or_else(&corrupted_offsets))
929            .collect::<Result<Vec<_>, _>>()?;
930
931        let signatures = {
932            let signature_registry = engine_inner.signatures();
933            module_info
934                .signatures
935                .values()
936                .zip(module_info.signature_hashes.values())
937                .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
938                .collect::<PrimaryMap<_, _>>()
939                .into_boxed_slice()
940        };
941
942        let finished_functions = local_fn_offsets
943            .iter()
944            .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
945            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
946
947        #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
948        let finished_function_extents = local_fn_offsets
949            .iter()
950            .zip(local_fn_sizes.iter())
951            .map(|(&ptr, &length)| FunctionExtent {
952                ptr: FunctionBodyPtr(unsafe { base.add(ptr) as _ }),
953                length,
954            })
955            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
956        #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
957        engine_inner.register_perfmap(&finished_function_extents, module_info)?;
958        let finished_function_call_trampolines = trampoline_offsets
959            .iter()
960            .map(|&offset| unsafe {
961                std::mem::transmute::<*mut std::ffi::c_void, VMTrampoline>(base.add(offset))
962            })
963            .collect::<PrimaryMap<SignatureIndex, _>>()
964            .into_boxed_slice();
965        let finished_dynamic_function_trampolines = dynamic_trampoline_offsets
966            .iter()
967            .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
968            .collect::<PrimaryMap<FunctionIndex, _>>()
969            .into_boxed_slice();
970        let finished_function_lengths =
971            PrimaryMap::<LocalFunctionIndex, _>::from_iter(local_fn_sizes).into_boxed_slice();
972        let function_max_stack_usage = finished_functions
973            .iter()
974            .map(|_| None)
975            .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
976            .into_boxed_slice();
977
978        let vm_offsets = VMOffsets::try_new(std::mem::size_of::<usize>() as u8, module_info)
979            .map_err(DeserializeError::Generic)?;
980
981        Ok(AllocatedArtifact {
982            frame_info_registered: false,
983            frame_info_registration: None,
984            finished_functions: finished_functions.into_boxed_slice(),
985            finished_function_call_trampolines,
986            finished_dynamic_function_trampolines,
987            signatures,
988            finished_function_lengths,
989            vm_offsets,
990            function_max_stack_usage,
991            elf_image: Some((base as usize, debug_info)),
992        })
993    }
994
995    /// Check if the provided bytes look like a serialized `ArtifactBuild`.
996    pub fn is_deserializable(bytes: &[u8]) -> bool {
997        ArtifactBuild::is_deserializable(bytes)
998    }
999}
1000
1001impl PartialEq for Artifact {
1002    fn eq(&self, other: &Self) -> bool {
1003        self.id == other.id
1004    }
1005}
1006impl Eq for Artifact {}
1007
1008impl std::fmt::Debug for Artifact {
1009    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1010        f.debug_struct("Artifact")
1011            .field("artifact_id", &self.id)
1012            .field("module_info", &self.module_info())
1013            .finish()
1014    }
1015}
1016
1017impl<'a> ArtifactCreate<'a> for Artifact {
1018    type OwnedDataInitializer = <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializer;
1019    type OwnedDataInitializerIterator =
1020        <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializerIterator;
1021
1022    fn set_module_info_name(&mut self, name: String) -> bool {
1023        self.artifact.set_module_info_name(name)
1024    }
1025
1026    fn create_module_info(&self) -> Arc<ModuleInfo> {
1027        self.artifact.create_module_info()
1028    }
1029
1030    fn module_info(&self) -> &ModuleInfo {
1031        self.artifact.module_info()
1032    }
1033
1034    fn features(&self) -> &Features {
1035        self.artifact.features()
1036    }
1037
1038    fn cpu_features(&self) -> EnumSet<CpuFeature> {
1039        self.artifact.cpu_features()
1040    }
1041
1042    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1043        self.artifact.data_initializers()
1044    }
1045
1046    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1047        self.artifact.memory_styles()
1048    }
1049
1050    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1051        self.artifact.table_styles()
1052    }
1053
1054    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1055        if let Some(module_file) = &self.module_file {
1056            return std::fs::read(module_file).map_err(|e| {
1057                SerializeError::Generic(format!("Failed to serialize Artifact file: {e}"))
1058            });
1059        }
1060        self.artifact.serialize()
1061    }
1062}
1063
1064impl<'a> ArtifactCreate<'a> for ArtifactBuildVariant {
1065    type OwnedDataInitializer = OwnedDataInitializerVariant<'a>;
1066    type OwnedDataInitializerIterator = IntoIter<Self::OwnedDataInitializer>;
1067
1068    fn create_module_info(&self) -> Arc<ModuleInfo> {
1069        match self {
1070            Self::Plain(artifact) => artifact.create_module_info(),
1071            Self::Archived(artifact) => artifact.create_module_info(),
1072        }
1073    }
1074
1075    fn set_module_info_name(&mut self, name: String) -> bool {
1076        match self {
1077            Self::Plain(artifact) => artifact.set_module_info_name(name),
1078            Self::Archived(artifact) => artifact.set_module_info_name(name),
1079        }
1080    }
1081
1082    fn module_info(&self) -> &ModuleInfo {
1083        match self {
1084            Self::Plain(artifact) => artifact.module_info(),
1085            Self::Archived(artifact) => artifact.module_info(),
1086        }
1087    }
1088
1089    fn features(&self) -> &Features {
1090        match self {
1091            Self::Plain(artifact) => artifact.features(),
1092            Self::Archived(artifact) => artifact.features(),
1093        }
1094    }
1095
1096    fn cpu_features(&self) -> EnumSet<CpuFeature> {
1097        match self {
1098            Self::Plain(artifact) => artifact.cpu_features(),
1099            Self::Archived(artifact) => artifact.cpu_features(),
1100        }
1101    }
1102
1103    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1104        match self {
1105            Self::Plain(artifact) => artifact.memory_styles(),
1106            Self::Archived(artifact) => artifact.memory_styles(),
1107        }
1108    }
1109
1110    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1111        match self {
1112            Self::Plain(artifact) => artifact.table_styles(),
1113            Self::Archived(artifact) => artifact.table_styles(),
1114        }
1115    }
1116
1117    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1118        match self {
1119            Self::Plain(artifact) => artifact
1120                .data_initializers()
1121                .map(OwnedDataInitializerVariant::Plain)
1122                .collect::<Vec<_>>()
1123                .into_iter(),
1124            Self::Archived(artifact) => artifact
1125                .data_initializers()
1126                .map(OwnedDataInitializerVariant::Archived)
1127                .collect::<Vec<_>>()
1128                .into_iter(),
1129        }
1130    }
1131
1132    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1133        match self {
1134            Self::Plain(artifact) => artifact.serialize(),
1135            Self::Archived(artifact) => artifact.serialize(),
1136        }
1137    }
1138}
1139
1140#[derive(Clone, Copy)]
1141pub enum OwnedDataInitializerVariant<'a> {
1142    Plain(&'a OwnedDataInitializer),
1143    Archived(&'a ArchivedOwnedDataInitializer),
1144}
1145
1146impl<'a> DataInitializerLike<'a> for OwnedDataInitializerVariant<'a> {
1147    type Location = DataInitializerLocationVariant<'a>;
1148
1149    fn location(&self) -> Self::Location {
1150        match self {
1151            Self::Plain(plain) => DataInitializerLocationVariant::Plain(plain.location()),
1152            Self::Archived(archived) => {
1153                DataInitializerLocationVariant::Archived(archived.location())
1154            }
1155        }
1156    }
1157
1158    fn data(&self) -> &'a [u8] {
1159        match self {
1160            Self::Plain(plain) => plain.data(),
1161            Self::Archived(archived) => archived.data(),
1162        }
1163    }
1164}
1165
1166#[derive(Clone, Copy)]
1167pub enum DataInitializerLocationVariant<'a> {
1168    Plain(&'a DataInitializerLocation),
1169    Archived(&'a ArchivedDataInitializerLocation),
1170}
1171
1172impl DataInitializerLocationVariant<'_> {
1173    pub fn clone_to_plain(&self) -> DataInitializerLocation {
1174        match self {
1175            Self::Plain(p) => (*p).clone(),
1176            Self::Archived(a) => DataInitializerLocation {
1177                memory_index: a.memory_index(),
1178                offset_expr: a.offset_expr(),
1179            },
1180        }
1181    }
1182}
1183
1184impl DataInitializerLocationLike for DataInitializerLocationVariant<'_> {
1185    fn memory_index(&self) -> MemoryIndex {
1186        match self {
1187            Self::Plain(plain) => plain.memory_index(),
1188            Self::Archived(archived) => archived.memory_index(),
1189        }
1190    }
1191
1192    fn offset_expr(&self) -> wasmer_types::InitExpr {
1193        match self {
1194            Self::Plain(plain) => plain.offset_expr(),
1195            Self::Archived(archived) => archived.offset_expr(),
1196        }
1197    }
1198}
1199
1200impl Artifact {
1201    fn internal_register_frame_info(&mut self) -> Result<(), DeserializeError> {
1202        if self
1203            .allocated
1204            .as_ref()
1205            .expect("It must be allocated")
1206            .frame_info_registered
1207        {
1208            return Ok(()); // already done
1209        }
1210
1211        // ELF artifacts don't carry the RKYV frame-info section (per-instruction
1212        // address maps); they get symbolicated from DWARF debug info instead,
1213        // lazily loaded from the ELF image (see `elf_image` below).
1214        let frame_infos = match &self.artifact {
1215            ArtifactBuildVariant::Plain(p) => p
1216                .get_frame_info_ref()
1217                .map(|f| FrameInfosVariant::Owned(f.clone())),
1218            ArtifactBuildVariant::Archived(a) => a
1219                .get_frame_info_ref()
1220                .map(|_| FrameInfosVariant::Archived(a.clone())),
1221        };
1222
1223        let elf_image = self
1224            .allocated
1225            .as_ref()
1226            .expect("It must be allocated")
1227            .elf_image
1228            .clone();
1229
1230        if frame_infos.is_some() || elf_image.is_some() {
1231            let finished_function_extents = self
1232                .allocated
1233                .as_ref()
1234                .expect("It must be allocated")
1235                .function_extents()
1236                .into_boxed_slice();
1237
1238            let (image_base, elf_data) = match elf_image {
1239                Some((base, data)) => (base, Some(data)),
1240                None => (0, None),
1241            };
1242
1243            let frame_info_registration = &mut self
1244                .allocated
1245                .as_mut()
1246                .expect("It must be allocated")
1247                .frame_info_registration;
1248
1249            *frame_info_registration = register_frame_info_source(
1250                self.artifact.create_module_info(),
1251                &finished_function_extents,
1252                frame_infos,
1253                image_base,
1254                elf_data,
1255            );
1256        }
1257
1258        self.allocated
1259            .as_mut()
1260            .expect("It must be allocated")
1261            .frame_info_registered = true;
1262
1263        Ok(())
1264    }
1265
1266    fn internal_take_frame_info_registration(&mut self) -> Option<GlobalFrameInfoRegistration> {
1267        let frame_info_registration = &mut self
1268            .allocated
1269            .as_mut()
1270            .expect("It must be allocated")
1271            .frame_info_registration;
1272
1273        frame_info_registration.take()
1274    }
1275
1276    /// Returns the functions allocated in memory or this `Artifact`
1277    /// ready to be run.
1278    pub fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
1279        &self
1280            .allocated
1281            .as_ref()
1282            .expect("It must be allocated")
1283            .finished_functions
1284    }
1285
1286    /// Returns the start address and byte length of each locally-defined
1287    /// function body in this artifact.
1288    ///
1289    /// Returns `None` for cross-compiled artifacts (where the artifact has not
1290    /// been allocated into the host process).
1291    ///
1292    /// # Security
1293    ///
1294    /// The returned addresses are host-process pointers. They are not stable
1295    /// across runs and must not be forwarded to untrusted parties, as they
1296    /// reveal ASLR layout information.
1297    pub fn finished_function_extents(&self) -> Option<Vec<(LocalFunctionIndex, FunctionExtent)>> {
1298        let allocated = self.allocated.as_ref()?;
1299        Some(allocated.function_extents().into_iter().collect())
1300    }
1301
1302    /// Return the maximum stack size used for each function (available only for the Singlepass compiler).
1303    pub fn finished_functions_max_stack_usage(
1304        &self,
1305    ) -> Option<Vec<(LocalFunctionIndex, Option<usize>)>> {
1306        let allocated = self.allocated.as_ref()?;
1307        Some(
1308            allocated
1309                .function_max_stack_usage
1310                .into_iter()
1311                .map(|f| (f.0, *f.1))
1312                .collect(),
1313        )
1314    }
1315
1316    /// Returns the function call trampolines allocated in memory of this
1317    /// `Artifact`, ready to be run.
1318    pub fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
1319        &self
1320            .allocated
1321            .as_ref()
1322            .expect("It must be allocated")
1323            .finished_function_call_trampolines
1324    }
1325
1326    /// Returns the dynamic function trampolines allocated in memory
1327    /// of this `Artifact`, ready to be run.
1328    pub fn finished_dynamic_function_trampolines(
1329        &self,
1330    ) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
1331        &self
1332            .allocated
1333            .as_ref()
1334            .expect("It must be allocated")
1335            .finished_dynamic_function_trampolines
1336    }
1337
1338    /// Returns the associated VM signatures for this `Artifact`.
1339    pub fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSignatureHash> {
1340        &self
1341            .allocated
1342            .as_ref()
1343            .expect("It must be allocated")
1344            .signatures
1345    }
1346
1347    /// Do preinstantiation logic that is executed before instantiating
1348    #[allow(clippy::result_large_err)]
1349    pub fn preinstantiate(&self) -> Result<(), InstantiationError> {
1350        Ok(())
1351    }
1352
1353    /// Crate an `Instance` from this `Artifact`.
1354    ///
1355    /// # Safety
1356    ///
1357    /// See [`VMInstance::new`].
1358    #[allow(clippy::result_large_err)]
1359    pub unsafe fn instantiate(
1360        &self,
1361        tunables: &dyn Tunables,
1362        imports: &[VMExtern],
1363        context: &mut StoreObjects,
1364    ) -> Result<VMInstance, InstantiationError> {
1365        unsafe {
1366            // Validate the CPU features this module was compiled with against the
1367            // host CPU features.
1368            let host_cpu_features = CpuFeature::for_host();
1369            if !host_cpu_features.is_superset(self.cpu_features()) {
1370                return Err(InstantiationError::CpuFeature(format!(
1371                    "{:?}",
1372                    self.cpu_features().difference(host_cpu_features)
1373                )));
1374            }
1375
1376            self.preinstantiate()?;
1377
1378            let module = self.create_module_info();
1379
1380            let tags = resolve_tags(&module, imports, context).map_err(InstantiationError::Link)?;
1381
1382            let imports = resolve_imports(
1383                &module,
1384                imports,
1385                context,
1386                self.finished_dynamic_function_trampolines(),
1387                self.memory_styles(),
1388                self.table_styles(),
1389            )
1390            .map_err(InstantiationError::Link)?;
1391
1392            // Get pointers to where metadata about local memories should live in VM memory.
1393            // Get pointers to where metadata about local tables should live in VM memory.
1394
1395            let cached_offsets = self
1396                .allocated
1397                .as_ref()
1398                .map(|a| a.vm_offsets.clone())
1399                .expect("Artifact::instantiate called on a non-host artifact");
1400
1401            let (
1402                allocator,
1403                memory_definition_locations,
1404                table_definition_locations,
1405                global_definition_locations,
1406            ) = InstanceAllocator::new_with_offsets(cached_offsets, &module);
1407            let finished_memories = tunables
1408                .create_memories(
1409                    context,
1410                    &module,
1411                    self.memory_styles(),
1412                    &memory_definition_locations,
1413                )
1414                .map_err(InstantiationError::Link)?
1415                .into_boxed_slice();
1416            let finished_tables = tunables
1417                .create_tables(
1418                    context,
1419                    &module,
1420                    self.table_styles(),
1421                    &table_definition_locations,
1422                )
1423                .map_err(InstantiationError::Link)?
1424                .into_boxed_slice();
1425            let finished_globals = tunables
1426                .create_globals(context, &module, &global_definition_locations)
1427                .map_err(InstantiationError::Link)?
1428                .into_boxed_slice();
1429            let initial_table_elements = module
1430                .tables
1431                .values()
1432                .skip(module.num_imported_tables)
1433                .fold(0u32, |total, ty| total.saturating_add(ty.minimum));
1434            let table_allocation_room = tunables
1435                .max_table_elements()
1436                .saturating_sub(initial_table_elements);
1437
1438            let handle = VMInstance::new(
1439                allocator,
1440                module,
1441                context,
1442                self.finished_functions().clone(),
1443                self.finished_function_call_trampolines().clone(),
1444                finished_memories,
1445                finished_tables,
1446                table_allocation_room,
1447                finished_globals,
1448                tags,
1449                imports,
1450                self.signatures().clone(),
1451            )
1452            .map_err(InstantiationError::Start)?;
1453            Ok(handle)
1454        }
1455    }
1456
1457    /// Finishes the instantiation of a just created `VMInstance`.
1458    ///
1459    /// # Safety
1460    ///
1461    /// See [`VMInstance::finish_instantiation`].
1462    #[allow(clippy::result_large_err)]
1463    pub unsafe fn finish_instantiation(
1464        &self,
1465        config: &VMConfig,
1466        trap_handler: Option<*const TrapHandlerFn<'static>>,
1467        handle: &mut VMInstance,
1468    ) -> Result<(), InstantiationError> {
1469        unsafe {
1470            let data_initializers = self
1471                .data_initializers()
1472                .map(|init| DataInitializer {
1473                    location: init.location().clone_to_plain(),
1474                    data: init.data(),
1475                })
1476                .collect::<Vec<_>>();
1477            handle
1478                .finish_instantiation(config, trap_handler, &data_initializers)
1479                .map_err(InstantiationError::Start)
1480        }
1481    }
1482
1483    #[allow(clippy::type_complexity)]
1484    #[cfg(feature = "static-artifact-create")]
1485    /// Generate a compilation
1486    pub fn generate_metadata<'data>(
1487        data: &'data [u8],
1488        compiler: &dyn Compiler,
1489        tunables: &dyn Tunables,
1490        features: &Features,
1491    ) -> Result<
1492        (
1493            CompileModuleInfo,
1494            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
1495            Vec<DataInitializer<'data>>,
1496            Option<ModuleTranslationState>,
1497        ),
1498        CompileError,
1499    > {
1500        let environ = ModuleEnvironment::new();
1501        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
1502
1503        // We try to apply the middleware first
1504        use crate::translator::ModuleMiddlewareChain;
1505        let mut module = translation.module;
1506        let middlewares = compiler.get_middlewares();
1507        middlewares
1508            .apply_on_module_info(&mut module)
1509            .map_err(|e| CompileError::MiddlewareError(e.to_string()))?;
1510
1511        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
1512            .memories
1513            .values()
1514            .map(|memory_type| tunables.memory_style(memory_type))
1515            .collect();
1516        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
1517            .tables
1518            .values()
1519            .map(|table_type| tunables.table_style(table_type))
1520            .collect();
1521
1522        let compile_info = CompileModuleInfo {
1523            module: Arc::new(module),
1524            features: features.clone(),
1525            memory_styles,
1526            table_styles,
1527            function_max_stack_usage: PrimaryMap::new(),
1528        };
1529        Ok((
1530            compile_info,
1531            translation.function_body_inputs,
1532            translation.data_initializers,
1533            translation.module_translation_state,
1534        ))
1535    }
1536
1537    /// Generate the metadata object for the module
1538    #[cfg(feature = "static-artifact-create")]
1539    #[allow(clippy::type_complexity)]
1540    pub fn metadata<'a>(
1541        compiler: &dyn Compiler,
1542        data: &'a [u8],
1543        metadata_prefix: Option<&str>,
1544        target: &Target,
1545        tunables: &dyn Tunables,
1546        features: &Features,
1547    ) -> Result<
1548        (
1549            ModuleMetadata,
1550            Option<ModuleTranslationState>,
1551            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'a>>,
1552        ),
1553        CompileError,
1554    > {
1555        #[allow(dead_code)]
1556        let (compile_info, function_body_inputs, data_initializers, module_translation) =
1557            Self::generate_metadata(data, compiler, tunables, features)?;
1558
1559        let data_initializers = data_initializers
1560            .iter()
1561            .map(OwnedDataInitializer::new)
1562            .collect::<Vec<_>>()
1563            .into_boxed_slice();
1564
1565        // TODO: we currently supply all-zero function body lengths.
1566        // We don't know the lengths until they're compiled, yet we have to
1567        // supply the metadata as an input to the compile.
1568        let function_body_lengths = function_body_inputs
1569            .keys()
1570            .map(|_function_body| 0u64)
1571            .collect::<PrimaryMap<LocalFunctionIndex, u64>>();
1572
1573        let metadata = ModuleMetadata {
1574            compile_info,
1575            prefix: metadata_prefix.map(|s| s.to_string()).unwrap_or_default(),
1576            data_initializers,
1577            function_body_lengths,
1578            cpu_features: target.cpu_features().as_u64(),
1579        };
1580
1581        Ok((metadata, module_translation, function_body_inputs))
1582    }
1583
1584    /// Compile a module into an object file, which can be statically linked against.
1585    ///
1586    /// The `metadata_prefix` is an optional prefix for the object name to make the
1587    /// function names in the object file unique. When set, the function names will
1588    /// be `wasmer_function_{prefix}_{id}` and the object metadata will be addressable
1589    /// using `WASMER_METADATA_{prefix}_LENGTH` and `WASMER_METADATA_{prefix}_DATA`.
1590    ///
1591    #[cfg(feature = "static-artifact-create")]
1592    pub fn generate_object<'data>(
1593        compiler: &dyn Compiler,
1594        data: &[u8],
1595        metadata_prefix: Option<&str>,
1596        target: &'data Target,
1597        tunables: &dyn Tunables,
1598        features: &Features,
1599    ) -> Result<
1600        (
1601            ModuleInfo,
1602            Object<'data>,
1603            usize,
1604            Box<dyn crate::types::symbols::SymbolRegistry>,
1605        ),
1606        CompileError,
1607    > {
1608        use crate::types::{
1609            function::Compilation,
1610            symbols::{ModuleMetadataSymbolRegistry, SymbolRegistry},
1611        };
1612
1613        fn to_compile_error(err: impl std::error::Error) -> CompileError {
1614            CompileError::Codegen(format!("{err}"))
1615        }
1616
1617        let target_triple = target.triple();
1618        let (mut metadata, module_translation, function_body_inputs) =
1619            Self::metadata(compiler, data, metadata_prefix, target, tunables, features)
1620                .map_err(to_compile_error)?;
1621
1622        /*
1623        In the C file we need:
1624        - imports
1625        - exports
1626
1627        to construct an api::Module which is a Store (can be passed in via argument) and an
1628        Arc<dyn Artifact> which means this struct which includes:
1629        - CompileModuleInfo
1630        - Features
1631        - ModuleInfo
1632        - MemoryIndex -> MemoryStyle
1633        - TableIndex -> TableStyle
1634        - LocalFunctionIndex -> FunctionBodyPtr // finished functions
1635        - FunctionIndex -> FunctionBodyPtr // finished dynamic function trampolines
1636        - SignatureIndex -> VMSignatureHash // signatures
1637         */
1638
1639        let compilation = compiler.compile_module(
1640            target,
1641            &metadata.compile_info,
1642            &[],
1643            module_translation.as_ref().unwrap(),
1644            function_body_inputs,
1645            None,
1646        )?;
1647        let Compilation::Rkyv {
1648            compilation,
1649            function_max_stack_usage,
1650        } = compilation
1651        else {
1652            return Err(CompileError::Codegen(
1653                "ELF compilation unsupported yet".to_string(),
1654            ));
1655        };
1656        metadata.compile_info.function_max_stack_usage = function_max_stack_usage;
1657
1658        let mut metadata_builder =
1659            ObjectMetadataBuilder::new(&metadata, target_triple).map_err(to_compile_error)?;
1660        let (_compile_info, symbol_registry) = metadata.split();
1661        let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
1662
1663        let object_name = ModuleMetadataSymbolRegistry {
1664            prefix: metadata_prefix.unwrap_or_default().to_string(),
1665        }
1666        .symbol_to_name(crate::types::symbols::Symbol::Metadata);
1667
1668        let default_align = match target_triple.architecture {
1669            target_lexicon::Architecture::Aarch64(_) => {
1670                if matches!(
1671                    target_triple.operating_system,
1672                    target_lexicon::OperatingSystem::Darwin(_)
1673                ) {
1674                    8
1675                } else {
1676                    4
1677                }
1678            }
1679            _ => 1,
1680        };
1681
1682        let offset = emit_data(
1683            &mut obj,
1684            object_name.as_bytes(),
1685            metadata_builder.placeholder_data(),
1686            std::cmp::max(MetadataHeader::ALIGN as u64, default_align),
1687        )
1688        .map_err(to_compile_error)?;
1689        metadata_builder.set_section_offset(offset);
1690
1691        emit_compilation(
1692            &mut obj,
1693            compilation,
1694            &symbol_registry,
1695            target_triple,
1696            &metadata_builder,
1697        )
1698        .map_err(to_compile_error)?;
1699        Ok((
1700            Arc::try_unwrap(metadata.compile_info.module).unwrap(),
1701            obj,
1702            metadata_builder.placeholder_data().len(),
1703            Box::new(symbol_registry),
1704        ))
1705    }
1706
1707    /// Deserialize a ArtifactBuild from an object file
1708    ///
1709    /// # Safety
1710    /// The object must be a valid static object generated by wasmer.
1711    #[cfg(not(feature = "static-artifact-load"))]
1712    pub unsafe fn deserialize_object(
1713        _engine: &Engine,
1714        _bytes: OwnedBuffer,
1715    ) -> Result<Self, DeserializeError> {
1716        Err(DeserializeError::Compiler(
1717            CompileError::UnsupportedFeature("static load is not compiled in".to_string()),
1718        ))
1719    }
1720
1721    fn get_byte_slice(input: &[u8], start: usize, end: usize) -> Result<&[u8], DeserializeError> {
1722        if (start == end && input.len() > start)
1723            || (start < end && input.len() > start && input.len() >= end)
1724        {
1725            Ok(&input[start..end])
1726        } else {
1727            Err(DeserializeError::InvalidByteLength {
1728                expected: end - start,
1729                got: input.len(),
1730            })
1731        }
1732    }
1733
1734    /// Deserialize a ArtifactBuild from an object file
1735    ///
1736    /// # Safety
1737    /// The object must be a valid static object generated by wasmer.
1738    #[cfg(feature = "static-artifact-load")]
1739    pub unsafe fn deserialize_object(
1740        engine: &Engine,
1741        bytes: OwnedBuffer,
1742    ) -> Result<Self, DeserializeError> {
1743        unsafe {
1744            use crate::serialize::SerializableCompilation;
1745
1746            let bytes = bytes.as_slice();
1747            let metadata_len = MetadataHeader::parse(bytes)?;
1748            let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
1749            let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
1750            let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?;
1751
1752            const WORD_SIZE: usize = mem::size_of::<usize>();
1753            let mut byte_buffer = [0u8; WORD_SIZE];
1754
1755            let mut cur_offset = MetadataHeader::LEN + metadata_len;
1756
1757            let byte_buffer_slice =
1758                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1759            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1760            cur_offset += WORD_SIZE;
1761
1762            let num_finished_functions = usize::from_ne_bytes(byte_buffer);
1763            let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
1764                PrimaryMap::new();
1765
1766            let engine_inner = engine.inner();
1767            let signature_registry = engine_inner.signatures();
1768
1769            // read finished functions in order now...
1770            for _i in 0..num_finished_functions {
1771                let byte_buffer_slice =
1772                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1773                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1774                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1775                cur_offset += WORD_SIZE;
1776
1777                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1778                finished_functions.push(fp);
1779            }
1780
1781            // We register all the signatures
1782            let signatures = {
1783                let module = &metadata.compile_info.module;
1784                module
1785                    .signatures
1786                    .values()
1787                    .zip(module.signature_hashes.values())
1788                    .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
1789                    .collect::<PrimaryMap<_, _>>()
1790            };
1791
1792            // read trampolines in order
1793            let mut finished_function_call_trampolines = PrimaryMap::new();
1794
1795            let byte_buffer_slice =
1796                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1797            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1798            cur_offset += WORD_SIZE;
1799            let num_function_trampolines = usize::from_ne_bytes(byte_buffer);
1800            for _ in 0..num_function_trampolines {
1801                let byte_buffer_slice =
1802                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1803                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1804                cur_offset += WORD_SIZE;
1805                let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer);
1806                let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes);
1807                finished_function_call_trampolines.push(trampoline);
1808                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1809            }
1810
1811            // read dynamic function trampolines in order now...
1812            let mut finished_dynamic_function_trampolines = PrimaryMap::new();
1813            let byte_buffer_slice =
1814                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1815            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1816            cur_offset += WORD_SIZE;
1817            let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
1818            for _i in 0..num_dynamic_trampoline_functions {
1819                let byte_buffer_slice =
1820                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1821                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1822                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1823                cur_offset += WORD_SIZE;
1824
1825                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1826
1827                finished_dynamic_function_trampolines.push(fp);
1828            }
1829
1830            let artifact = ArtifactBuild::from_serializable(SerializableModule {
1831                compilation: SerializableCompilation::Rkyv(RkyvSerializableCompilation::default()),
1832                compile_info: metadata.compile_info,
1833                data_initializers: metadata.data_initializers,
1834                cpu_features: metadata.cpu_features,
1835            });
1836
1837            let finished_function_lengths = finished_functions
1838                .values()
1839                .map(|_| 0)
1840                .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
1841                .into_boxed_slice();
1842            let function_max_stack_usage = finished_functions
1843                .iter()
1844                .map(|_| None)
1845                .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
1846                .into_boxed_slice();
1847
1848            // Variant is built first so its module_info is available for
1849            // the cached VMOffsets before it is moved into Self.
1850            let artifact_variant = ArtifactBuildVariant::Plain(artifact);
1851            let vm_offsets = VMOffsets::try_new(
1852                std::mem::size_of::<usize>() as u8,
1853                artifact_variant.module_info(),
1854            )
1855            .map_err(DeserializeError::Generic)?;
1856
1857            Ok(Self {
1858                id: Default::default(),
1859                artifact: artifact_variant,
1860                module_file: None,
1861                allocated: Some(AllocatedArtifact {
1862                    frame_info_registered: false,
1863                    frame_info_registration: None,
1864                    finished_functions: finished_functions.into_boxed_slice(),
1865                    finished_function_call_trampolines: finished_function_call_trampolines
1866                        .into_boxed_slice(),
1867                    finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
1868                        .into_boxed_slice(),
1869                    signatures: signatures.into_boxed_slice(),
1870                    finished_function_lengths,
1871                    vm_offsets,
1872                    function_max_stack_usage,
1873                    elf_image: None,
1874                }),
1875            })
1876        }
1877    }
1878}
1879
1880/// On-demand reader of per-function trap information from an ELF artifact.
1881///
1882/// Trap lookups only happen when a trap fires, so the ELF trap sections are
1883/// parsed lazily instead of duplicating all trap tables in memory.
1884pub(crate) struct TrapReader {
1885    source: DebugInfoSource,
1886}
1887
1888impl TrapReader {
1889    pub(crate) fn new(source: DebugInfoSource) -> Self {
1890        Self { source }
1891    }
1892
1893    /// Looks up the trap information for `local_index` at `rel_pos`, the offset
1894    /// relative to the start of the function.
1895    pub(crate) fn lookup(
1896        &self,
1897        local_index: LocalFunctionIndex,
1898        rel_pos: u32,
1899    ) -> Option<TrapInformation> {
1900        match &self.source {
1901            DebugInfoSource::Bytes(data) => {
1902                let image = object::File::parse(&data[..]).ok()?;
1903                Self::lookup_in_image(&image, local_index, rel_pos)
1904            }
1905            DebugInfoSource::File(file) => {
1906                let file = file.lock().unwrap();
1907                let cache = ReadCache::new(BufReader::new(file.try_clone().ok()?));
1908                let image = object::File::parse(&cache).ok()?;
1909                Self::lookup_in_image(&image, local_index, rel_pos)
1910            }
1911        }
1912    }
1913
1914    fn lookup_in_image<'data, R: ReadRef<'data>>(
1915        image: &object::File<'data, R>,
1916        local_index: LocalFunctionIndex,
1917        rel_pos: u32,
1918    ) -> Option<TrapInformation> {
1919        let traps_section = image.section_by_name_bytes(WASMER_TRAPS_SECTION_NAME)?;
1920        let trap_offsets = image
1921            .section_by_name_bytes(WASMER_TRAP_FUNCTION_OFFSETS_SECTION_NAME)?
1922            .data()
1923            .ok()?;
1924        let slot = local_index.index().checked_mul(size_of::<usize>())?;
1925        let offset_bytes = trap_offsets.get(slot..slot + size_of::<usize>())?;
1926
1927        // These slots contain relocated virtual addresses, not section-relative
1928        // offsets. ELF currently emitted by Wasmer is native and little-endian.
1929        let trap_address = usize::from_le_bytes(offset_bytes.try_into().ok()?);
1930        let trap_offset = trap_address.checked_sub(traps_section.address() as usize)?;
1931        let traps = Self::parse_function_traps(traps_section.data().ok()?, trap_offset)?;
1932        traps
1933            .binary_search_by_key(&rel_pos, |info| info.code_offset)
1934            .ok()
1935            .map(|index| traps[index])
1936    }
1937
1938    fn parse_function_traps(
1939        traps_section: &[u8],
1940        trap_offset: usize,
1941    ) -> Option<Vec<TrapInformation>> {
1942        const WORD_SIZE: usize = size_of::<u32>();
1943        const RECORD_SIZE: usize = 2 * WORD_SIZE;
1944
1945        let data = traps_section.get(trap_offset..)?;
1946        let count = u32::from_le_bytes(data.get(..WORD_SIZE)?.try_into().ok()?) as usize;
1947        let records_len = count.checked_mul(RECORD_SIZE)?;
1948        let records = data.get(WORD_SIZE..WORD_SIZE.checked_add(records_len)?)?;
1949
1950        records
1951            .chunks_exact(RECORD_SIZE)
1952            .map(|record| {
1953                let code_offset = u32::from_le_bytes(record[..WORD_SIZE].try_into().ok()?);
1954                let code = u32::from_le_bytes(record[WORD_SIZE..].try_into().ok()?);
1955                let trap_code = TrapCode::try_from(code).ok()?;
1956                Some(TrapInformation {
1957                    code_offset,
1958                    trap_code,
1959                })
1960            })
1961            .collect()
1962    }
1963}