wasmer_compiler/types/
symbols.rs

1/*
2 * ! Remove me once rkyv generates doc-comments for fields or generates an #[allow(missing_docs)]
3 * on their own.
4 */
5#![allow(missing_docs)]
6
7//! This module define the required structures for compilation symbols.
8use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
9#[cfg(feature = "enable-serde")]
10use serde::{Deserialize, Serialize};
11use wasmer_types::{
12    DeserializeError, FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SerializeError,
13    SignatureIndex,
14    entity::{EntityRef, PrimaryMap},
15};
16
17use super::{module::CompileModuleInfo, section::SectionIndex};
18
19/// The kinds of wasmer_types objects that might be found in a native object file.
20#[derive(
21    RkyvSerialize, RkyvDeserialize, Archive, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
22)]
23#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
24#[rkyv(derive(Debug), compare(PartialEq, PartialOrd))]
25pub enum Symbol {
26    /// A metadata section, indexed by a unique prefix
27    /// (usually the wasm file SHA256 hash)
28    Metadata,
29
30    /// A function defined in the wasm.
31    LocalFunction(LocalFunctionIndex),
32
33    /// A wasm section.
34    Section(SectionIndex),
35
36    /// The function call trampoline for a given signature.
37    FunctionCallTrampoline(SignatureIndex),
38
39    /// The dynamic function trampoline for a given function.
40    DynamicFunctionTrampoline(FunctionIndex),
41}
42
43/// This trait facilitates symbol name lookups in a native object file.
44pub trait SymbolRegistry: Send + Sync {
45    /// Given a `Symbol` it returns the name for that symbol in the object file
46    fn symbol_to_name(&self, symbol: Symbol) -> String;
47
48    /// Given a name it returns the `Symbol` for that name in the object file
49    ///
50    /// This function is the inverse of [`SymbolRegistry::symbol_to_name`]
51    fn name_to_symbol(&self, name: &str) -> Option<Symbol>;
52}
53
54/// Serializable struct that represents the compiled metadata.
55#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
56#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
57#[rkyv(derive(Debug))]
58pub struct ModuleMetadata {
59    /// Compile info
60    pub compile_info: CompileModuleInfo,
61    /// Prefix for function etc symbols
62    pub prefix: String,
63    /// Data initializers
64    pub data_initializers: Box<[OwnedDataInitializer]>,
65    /// The function body lengths (used to find function by address)
66    pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
67    /// CPU features used (see [`wasmer_types::CpuFeature`])
68    pub cpu_features: u64,
69}
70
71/// A simple metadata registry
72pub struct ModuleMetadataSymbolRegistry {
73    /// Symbol prefix stirng
74    pub prefix: String,
75}
76
77impl ModuleMetadata {
78    /// Get mutable ref to compile info and a copy of the registry
79    pub fn split(&mut self) -> (&mut CompileModuleInfo, ModuleMetadataSymbolRegistry) {
80        let compile_info = &mut self.compile_info;
81        let symbol_registry = ModuleMetadataSymbolRegistry {
82            prefix: self.prefix.clone(),
83        };
84        (compile_info, symbol_registry)
85    }
86
87    /// Returns symbol registry.
88    pub fn get_symbol_registry(&self) -> ModuleMetadataSymbolRegistry {
89        ModuleMetadataSymbolRegistry {
90            prefix: self.prefix.clone(),
91        }
92    }
93    /// Serialize a Module into bytes
94    /// The bytes will have the following format:
95    /// RKYV serialization (any length) + POS (8 bytes)
96    pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
97        rkyv::to_bytes::<rkyv::rancor::Error>(self)
98            .map(|v| v.into_vec())
99            .map_err(|e| SerializeError::Generic(e.to_string()))
100    }
101
102    /// Deserialize a Module from a slice.
103    /// The slice must have the following format:
104    /// RKYV serialization (any length) + POS (8 bytes)
105    ///
106    /// # Safety
107    ///
108    /// This method is unsafe since it deserializes data directly
109    /// from memory.
110    /// Right now we are not doing any extra work for validation, but
111    /// `rkyv` has an option to do bytecheck on the serialized data before
112    /// serializing (via `rkyv::check_archived_value`).
113    pub unsafe fn deserialize_unchecked(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
114        unsafe {
115            let archived = Self::archive_from_slice(metadata_slice)?;
116            Self::deserialize_from_archive(archived)
117        }
118    }
119
120    /// Deserialize a Module from a slice.
121    /// The slice must have the following format:
122    /// RKYV serialization (any length) + POS (8 bytes)
123    pub fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
124        let archived = Self::archive_from_slice_checked(metadata_slice)?;
125        Self::deserialize_from_archive(archived)
126    }
127
128    /// # Safety
129    ///
130    /// This method is unsafe.
131    /// Please check `ModuleMetadata::deserialize` for more details.
132    unsafe fn archive_from_slice(
133        metadata_slice: &[u8],
134    ) -> Result<&ArchivedModuleMetadata, DeserializeError> {
135        unsafe { Ok(rkyv::access_unchecked(metadata_slice)) }
136    }
137
138    /// # Safety
139    ///
140    /// This method is unsafe.
141    /// Please check `ModuleMetadata::deserialize` for more details.
142    fn archive_from_slice_checked(
143        metadata_slice: &[u8],
144    ) -> Result<&ArchivedModuleMetadata, DeserializeError> {
145        rkyv::access::<_, rkyv::rancor::Error>(metadata_slice)
146            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
147    }
148
149    /// Deserialize a compilation module from an archive
150    pub fn deserialize_from_archive(
151        archived: &ArchivedModuleMetadata,
152    ) -> Result<Self, DeserializeError> {
153        rkyv::deserialize::<_, rkyv::rancor::Error>(archived)
154            .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))
155    }
156}
157
158impl SymbolRegistry for ModuleMetadataSymbolRegistry {
159    fn symbol_to_name(&self, symbol: Symbol) -> String {
160        match symbol {
161            Symbol::Metadata => {
162                format!("WASMER_METADATA_{}", self.prefix.to_uppercase())
163            }
164            Symbol::LocalFunction(index) => {
165                format!("wasmer_function_{}_{}", self.prefix, index.index())
166            }
167            Symbol::Section(index) => format!("wasmer_section_{}_{}", self.prefix, index.index()),
168            Symbol::FunctionCallTrampoline(index) => {
169                format!(
170                    "wasmer_trampoline_function_call_{}_{}",
171                    self.prefix,
172                    index.index()
173                )
174            }
175            Symbol::DynamicFunctionTrampoline(index) => {
176                format!(
177                    "wasmer_trampoline_dynamic_function_{}_{}",
178                    self.prefix,
179                    index.index()
180                )
181            }
182        }
183    }
184
185    fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
186        if name == self.symbol_to_name(Symbol::Metadata) {
187            Some(Symbol::Metadata)
188        } else if let Some(index) = name.strip_prefix(&format!("wasmer_function_{}_", self.prefix))
189        {
190            index
191                .parse::<u32>()
192                .ok()
193                .map(|index| Symbol::LocalFunction(LocalFunctionIndex::from_u32(index)))
194        } else if let Some(index) = name.strip_prefix(&format!("wasmer_section_{}_", self.prefix)) {
195            index
196                .parse::<u32>()
197                .ok()
198                .map(|index| Symbol::Section(SectionIndex::from_u32(index)))
199        } else if let Some(index) =
200            name.strip_prefix(&format!("wasmer_trampoline_function_call_{}_", self.prefix))
201        {
202            index
203                .parse::<u32>()
204                .ok()
205                .map(|index| Symbol::FunctionCallTrampoline(SignatureIndex::from_u32(index)))
206        } else if let Some(index) = name.strip_prefix(&format!(
207            "wasmer_trampoline_dynamic_function_{}_",
208            self.prefix
209        )) {
210            index
211                .parse::<u32>()
212                .ok()
213                .map(|index| Symbol::DynamicFunctionTrampoline(FunctionIndex::from_u32(index)))
214        } else {
215            None
216        }
217    }
218}