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    entity::{EntityRef, PrimaryMap},
13    DeserializeError, FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SerializeError,
14    SignatureIndex,
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 [`CpuFeature`](crate::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        let archived = Self::archive_from_slice(metadata_slice)?;
115        Self::deserialize_from_archive(archived)
116    }
117
118    /// Deserialize a Module from a slice.
119    /// The slice must have the following format:
120    /// RKYV serialization (any length) + POS (8 bytes)
121    pub fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
122        let archived = Self::archive_from_slice_checked(metadata_slice)?;
123        Self::deserialize_from_archive(archived)
124    }
125
126    /// # Safety
127    ///
128    /// This method is unsafe.
129    /// Please check `ModuleMetadata::deserialize` for more details.
130    unsafe fn archive_from_slice(
131        metadata_slice: &[u8],
132    ) -> Result<&ArchivedModuleMetadata, DeserializeError> {
133        Ok(rkyv::access_unchecked(metadata_slice))
134    }
135
136    /// # Safety
137    ///
138    /// This method is unsafe.
139    /// Please check `ModuleMetadata::deserialize` for more details.
140    fn archive_from_slice_checked(
141        metadata_slice: &[u8],
142    ) -> Result<&ArchivedModuleMetadata, DeserializeError> {
143        rkyv::access::<_, rkyv::rancor::Error>(metadata_slice)
144            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
145    }
146
147    /// Deserialize a compilation module from an archive
148    pub fn deserialize_from_archive(
149        archived: &ArchivedModuleMetadata,
150    ) -> Result<Self, DeserializeError> {
151        rkyv::deserialize::<_, rkyv::rancor::Error>(archived)
152            .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))
153    }
154}
155
156impl SymbolRegistry for ModuleMetadataSymbolRegistry {
157    fn symbol_to_name(&self, symbol: Symbol) -> String {
158        match symbol {
159            Symbol::Metadata => {
160                format!("WASMER_METADATA_{}", self.prefix.to_uppercase())
161            }
162            Symbol::LocalFunction(index) => {
163                format!("wasmer_function_{}_{}", self.prefix, index.index())
164            }
165            Symbol::Section(index) => format!("wasmer_section_{}_{}", self.prefix, index.index()),
166            Symbol::FunctionCallTrampoline(index) => {
167                format!(
168                    "wasmer_trampoline_function_call_{}_{}",
169                    self.prefix,
170                    index.index()
171                )
172            }
173            Symbol::DynamicFunctionTrampoline(index) => {
174                format!(
175                    "wasmer_trampoline_dynamic_function_{}_{}",
176                    self.prefix,
177                    index.index()
178                )
179            }
180        }
181    }
182
183    fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
184        if name == self.symbol_to_name(Symbol::Metadata) {
185            Some(Symbol::Metadata)
186        } else if let Some(index) = name.strip_prefix(&format!("wasmer_function_{}_", self.prefix))
187        {
188            index
189                .parse::<u32>()
190                .ok()
191                .map(|index| Symbol::LocalFunction(LocalFunctionIndex::from_u32(index)))
192        } else if let Some(index) = name.strip_prefix(&format!("wasmer_section_{}_", self.prefix)) {
193            index
194                .parse::<u32>()
195                .ok()
196                .map(|index| Symbol::Section(SectionIndex::from_u32(index)))
197        } else if let Some(index) =
198            name.strip_prefix(&format!("wasmer_trampoline_function_call_{}_", self.prefix))
199        {
200            index
201                .parse::<u32>()
202                .ok()
203                .map(|index| Symbol::FunctionCallTrampoline(SignatureIndex::from_u32(index)))
204        } else if let Some(index) = name.strip_prefix(&format!(
205            "wasmer_trampoline_dynamic_function_{}_",
206            self.prefix
207        )) {
208            index
209                .parse::<u32>()
210                .ok()
211                .map(|index| Symbol::DynamicFunctionTrampoline(FunctionIndex::from_u32(index)))
212        } else {
213            None
214        }
215    }
216}