//! Support for reading Wasm files. //! //! [`WasmFile`] implements the [`Object`] trait for Wasm files. use alloc::boxed::Box; use alloc::vec::Vec; use core::marker::PhantomData; use core::ops::Range; use core::{slice, str}; use wasmparser as wp;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(usize)] enum SectionId {
Custom = 0, Type = 1,
Import = 2,
Function = 3,
Table = 4,
Memory = 5,
Global = 6,
Export = 7,
Start = 8,
Element = 9,
Code = 10,
Data = 11,
DataCount = 12,
Tag = 13,
} // Update this constant when adding new section id: const MAX_SECTION_ID: usize = SectionId::Tag as usize;
/// A WebAssembly object file. #[derive(Debug)] pubstruct WasmFile<'data, R = &'data [u8]> {
data: &'data [u8],
has_memory64: bool, // All sections, including custom sections.
sections: Vec<SectionHeader<'data>>, // Indices into `sections` of sections with a non-zero id.
id_sections: Box<[Option<usize>; MAX_SECTION_ID + 1]>, // Whether the file has DWARF information.
has_debug_symbols: bool, // Symbols collected from imports, exports, code and name sections.
symbols: Vec<WasmSymbolInternal<'data>>, // Address of the function body for the entry point.
entry: u64,
marker: PhantomData<R>,
}
letmut imported_funcs_count = 0; letmut local_func_kinds = Vec::new(); letmut entry_func_id = None; letmut code_range_start = 0; letmut code_func_index = 0; // One-to-one mapping of globals to their value (if the global is a constant integer). letmut global_values = Vec::new();
for payload in parser { let payload = payload.read_error("Invalid Wasm section header")?;
file.symbols.push(WasmSymbolInternal {
name: import.name,
address: 0,
size: 0,
kind,
section: SymbolSection::Undefined,
scope: SymbolScope::Dynamic,
});
}
}
wp::Payload::FunctionSection(section) => {
file.add_section(SectionId::Function, section.range(), "");
local_func_kinds =
vec![LocalFunctionKind::Unknown; section.into_iter().count()];
}
wp::Payload::TableSection(section) => {
file.add_section(SectionId::Table, section.range(), "");
}
wp::Payload::MemorySection(section) => {
file.add_section(SectionId::Memory, section.range(), ""); for memory in section { let memory = memory.read_error("Couldn't read a memory item")?;
file.has_memory64 |= memory.memory64;
}
}
wp::Payload::GlobalSection(section) => {
file.add_section(SectionId::Global, section.range(), ""); for global in section { let global = global.read_error("Couldn't read a global item")?; letmut address = None; if !global.ty.mutable { // There should be exactly one instruction. let init = global.init_expr.get_operators_reader().read();
address = match init.read_error("Couldn't read a global init expr")? {
wp::Operator::I32Const { value } => Some(value as u64),
wp::Operator::I64Const { value } => Some(value as u64),
_ => None,
};
}
global_values.push(address);
}
}
wp::Payload::ExportSection(section) => {
file.add_section(SectionId::Export, section.range(), ""); iflet Some(main_file_symbol) = main_file_symbol.take() {
file.symbols.push(main_file_symbol);
}
for export in section { let export = export.read_error("Couldn't read an export item")?;
let (kind, section_idx) = match export.kind {
wp::ExternalKind::Func => { iflet Some(local_func_id) =
export.index.checked_sub(imported_funcs_count)
{ let local_func_kind = local_func_kinds
.get_mut(local_func_id as usize)
.read_error("Invalid Wasm export index")?; iflet LocalFunctionKind::Unknown = local_func_kind {
*local_func_kind = LocalFunctionKind::Exported {
symbol_ids: Vec::new(),
};
} let symbol_ids = match local_func_kind {
LocalFunctionKind::Exported { symbol_ids } => symbol_ids,
_ => unreachable!(),
};
symbol_ids.push(file.symbols.len() as u32);
}
(SymbolKind::Text, SectionId::Code)
}
wp::ExternalKind::Table
| wp::ExternalKind::Memory
| wp::ExternalKind::Global => (SymbolKind::Data, SectionId::Data), // TODO
wp::ExternalKind::Tag => continue,
};
// Try to guess the symbol address. Rust and C export a global containing // the address in linear memory of the symbol. letmut address = 0; if export.kind == wp::ExternalKind::Global { iflet Some(&Some(x)) = global_values.get(export.index as usize) {
address = x;
}
}
let address = range.start as u64 - code_range_start as u64; let size = (range.end - range.start) as u64;
if entry_func_id == Some(i as u32) {
file.entry = address;
}
let local_func_kind = local_func_kinds
.get_mut(i)
.read_error("Invalid Wasm code section index")?; match local_func_kind {
LocalFunctionKind::Unknown => {
*local_func_kind = LocalFunctionKind::Local {
symbol_id: file.symbols.len() as u32,
};
file.symbols.push(WasmSymbolInternal {
name: "",
address,
size,
kind: SymbolKind::Text,
section: SymbolSection::Section(SectionIndex(
SectionId::Code as usize,
)),
scope: SymbolScope::Compilation,
});
}
LocalFunctionKind::Exported { symbol_ids } => { for symbol_id in core::mem::take(symbol_ids) { let export_symbol = &mut file.symbols[symbol_id as usize];
export_symbol.address = address;
export_symbol.size = size;
}
}
_ => unreachable!(),
}
}
wp::Payload::DataSection(section) => {
file.add_section(SectionId::Data, section.range(), "");
}
wp::Payload::DataCountSection { range, .. } => {
file.add_section(SectionId::DataCount, range, "");
}
wp::Payload::TagSection(section) => {
file.add_section(SectionId::Tag, section.range(), "");
}
wp::Payload::CustomSection(section) => { let name = section.name(); let size = section.data().len(); letmut range = section.range();
range.start = range.end - size;
file.add_section(SectionId::Custom, range, name); if name == "name" { let reader = wp::BinaryReader::new(
section.data(),
section.data_offset(),
wp::WasmFeatures::all(),
); for name in wp::NameSectionReader::new(reader) { // TODO: Right now, ill-formed name subsections // are silently ignored in order to maintain // compatibility with extended name sections, which // are not yet supported by the version of // `wasmparser` currently used. // A better fix would be to update `wasmparser` to // the newest version, but this requires // a major rewrite of this file. iflet Ok(wp::Name::Function(name_map)) = name { for naming in name_map { let naming =
naming.read_error("Couldn't read a function name")?; iflet Some(local_index) =
naming.index.checked_sub(imported_funcs_count)
{ iflet LocalFunctionKind::Local { symbol_id } =
local_func_kinds[local_index as usize]
{
file.symbols[symbol_id as usize].name = naming.name;
}
}
}
}
}
} elseif name.starts_with(".debug_") {
file.has_debug_symbols = true;
}
}
_ => {}
}
}
Ok(file)
}
fn add_section(&mutself, id: SectionId, range: Range<usize>, name: &<span style='color:blue'>'data str) { let section = SectionHeader { id, range, name }; self.id_sections[id as usize] = Some(self.sections.len()); self.sections.push(section);
}
}
impl<'data, R> read::private::Sealed for WasmFile<'data, R> {}
impl<'data, R: ReadRef<'data>> Object<'data> for WasmFile<'data, R> { type Segment<'file> = WasmSegment<'data, 'file, R> where Self: 'file, 'data: 'file; type SegmentIterator<'file> = WasmSegmentIterator<'data, 'file, R> where Self: 'file, 'data: 'file; type Section<'file> = WasmSection<'data, 'file, R> where Self: 'file, 'data: 'file; type SectionIterator<'file> = WasmSectionIterator<'data, 'file, R> where Self: 'file, 'data: 'file; type Comdat<'file> = WasmComdat<'data, 'file, R> where Self: 'file, 'data: 'file; type ComdatIterator<'file> = WasmComdatIterator<'data, 'file, R> where Self: 'file, 'data: 'file; type Symbol<'file> = WasmSymbol<'data, 'file> where Self: 'file, 'data: 'file; type SymbolIterator<'file> = WasmSymbolIterator<'data, 'file> where Self: 'file, 'data: 'file; type SymbolTable<'file> = WasmSymbolTable<'data, 'file> where Self: 'file, 'data: 'file; type DynamicRelocationIterator<'file> = NoDynamicRelocationIterator where Self: 'file, 'data: 'file;
/// An iterator for the segments in a [`WasmFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmSegmentIterator<'data, 'file, R = &'data [u8]> { #[allow(unused)]
file: &'file WasmFile<'data, R>,
}
impl<'data, 'file, R> Iterator for WasmSegmentIterator<'data, 'file, R> { type Item = WasmSegment<'data, 'file, R>;
/// A segment in a [`WasmFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmSegment<'data, 'file, R = &'data [u8]> { #[allow(unused)]
file: &'file WasmFile<'data, R>,
}
impl<'data, 'file, R> read::private::Sealed for WasmSegment<'data, 'file, R> {}
/// An iterator for the sections in a [`WasmFile`]. #[derive(Debug)] pubstruct WasmSectionIterator<'data, 'file, R = &'data [u8]> {
file: &'file WasmFile<'data, R>,
sections: slice::Iter<'file, SectionHeader<'data>>,
}
impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> { type Item = WasmSection<'data, 'file, R>;
/// A section in a [`WasmFile`]. /// /// Most functionality is provided by the [`ObjectSection`] trait implementation. #[derive(Debug)] pubstruct WasmSection<'data, 'file, R = &'data [u8]> {
file: &'file WasmFile<'data, R>,
section: &'file SectionHeader<'data>,
}
impl<'data, 'file, R> read::private::Sealed for WasmSection<'data, 'file, R> {}
impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for WasmSection<'data, 'file, R> { type RelocationIterator = WasmRelocationIterator<'data, 'file, R>;
#[inline] fn index(&self) -> SectionIndex { // Note that we treat all custom sections as index 0. // This is ok because they are never looked up by index.
SectionIndex(self.section.id as usize)
}
#[inline] fn address(&self) -> u64 { 0
}
#[inline] fn size(&self) -> u64 { let range = &self.section.range;
(range.end - range.start) as u64
}
#[inline] fn align(&self) -> u64 { 1
}
#[inline] fn file_range(&self) -> Option<(u64, u64)> { let range = &self.section.range;
Some((range.start as _, range.end as _))
}
#[inline] fn data(&self) -> Result<&'data [u8]> { let range = &self.section.range; self.file
.data
.read_bytes_at(range.start as u64, range.end as u64 - range.start as u64)
.read_error("Invalid Wasm section size or offset")
}
/// An iterator for the COMDAT section groups in a [`WasmFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmComdatIterator<'data, 'file, R = &'data [u8]> { #[allow(unused)]
file: &'file WasmFile<'data, R>,
}
impl<'data, 'file, R> Iterator for WasmComdatIterator<'data, 'file, R> { type Item = WasmComdat<'data, 'file, R>;
/// A COMDAT section group in a [`WasmFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmComdat<'data, 'file, R = &'data [u8]> { #[allow(unused)]
file: &'file WasmFile<'data, R>,
}
impl<'data, 'file, R> read::private::Sealed for WasmComdat<'data, 'file, R> {}
impl<'data, 'file, R> ObjectComdat<'data> for WasmComdat<'data, 'file, R> { type SectionIterator = WasmComdatSectionIterator<'data, 'file, R>;
/// An iterator for the sections in a COMDAT section group in a [`WasmFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]> { #[allow(unused)]
file: &'file WasmFile<'data, R>,
}
impl<'data, 'file, R> Iterator for WasmComdatSectionIterator<'data, 'file, R> { type Item = SectionIndex;
/// A symbol table in a [`WasmFile`]. #[derive(Debug)] pubstruct WasmSymbolTable<'data, 'file> {
symbols: &'file [WasmSymbolInternal<'data>],
}
impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {}
impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> { type Symbol = WasmSymbol<'data, 'file>; type SymbolIterator = WasmSymbolIterator<'data, 'file>;
fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> { let symbol = self
.symbols
.get(index.0)
.read_error("Invalid Wasm symbol index")?;
Ok(WasmSymbol { index, symbol })
}
}
/// An iterator for the symbols in a [`WasmFile`]. #[derive(Debug)] pubstruct WasmSymbolIterator<'data, 'file> {
symbols: core::iter::Enumerate<slice::Iter<'file, WasmSymbolInternal<'data>>>,
}
impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> { type Item = WasmSymbol<'data, 'file>;
/// A symbol in a [`WasmFile`]. /// /// Most functionality is provided by the [`ObjectSymbol`] trait implementation. #[derive(Clone, Copy, Debug)] pubstruct WasmSymbol<'data, 'file> {
index: SymbolIndex,
symbol: &'file WasmSymbolInternal<'data>,
}
/// An iterator for the relocations for a [`WasmSection`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct WasmRelocationIterator<'data, 'file, R = &'data [u8]>(
PhantomData<(&'data (), &'file (), R)>,
);
impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> { type Item = (u64, Relocation);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.