summaryrefslogtreecommitdiffstats
path: root/vendor/object/src/read/wasm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/read/wasm.rs')
-rw-r--r--vendor/object/src/read/wasm.rs447
1 files changed, 245 insertions, 202 deletions
diff --git a/vendor/object/src/read/wasm.rs b/vendor/object/src/read/wasm.rs
index 0113f5971..b950ef2b2 100644
--- a/vendor/object/src/read/wasm.rs
+++ b/vendor/object/src/read/wasm.rs
@@ -6,6 +6,7 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::marker::PhantomData;
+use core::ops::Range;
use core::{slice, str};
use wasmparser as wp;
@@ -17,27 +18,33 @@ use crate::read::{
SymbolScope, SymbolSection,
};
-const SECTION_CUSTOM: usize = 0;
-const SECTION_TYPE: usize = 1;
-const SECTION_IMPORT: usize = 2;
-const SECTION_FUNCTION: usize = 3;
-const SECTION_TABLE: usize = 4;
-const SECTION_MEMORY: usize = 5;
-const SECTION_GLOBAL: usize = 6;
-const SECTION_EXPORT: usize = 7;
-const SECTION_START: usize = 8;
-const SECTION_ELEMENT: usize = 9;
-const SECTION_CODE: usize = 10;
-const SECTION_DATA: usize = 11;
-const SECTION_DATA_COUNT: usize = 12;
+#[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,
+}
// Update this constant when adding new section id:
-const MAX_SECTION_ID: usize = SECTION_DATA_COUNT;
+const MAX_SECTION_ID: usize = SectionId::DataCount as usize;
/// A WebAssembly object file.
#[derive(Debug)]
pub struct WasmFile<'data, R = &'data [u8]> {
+ data: &'data [u8],
+ has_memory64: bool,
// All sections, including custom sections.
- sections: Vec<wp::Section<'data>>,
+ 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.
@@ -49,6 +56,13 @@ pub struct WasmFile<'data, R = &'data [u8]> {
marker: PhantomData<R>,
}
+#[derive(Debug)]
+struct SectionHeader<'data> {
+ id: SectionId,
+ range: Range<usize>,
+ name: &'data str,
+}
+
#[derive(Clone)]
enum LocalFunctionKind {
Unknown,
@@ -67,9 +81,11 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
pub fn parse(data: R) -> Result<Self> {
let len = data.len().read_error("Unknown Wasm file size")?;
let data = data.read_bytes_at(0, len).read_error("Wasm read failed")?;
- let module = wp::ModuleReader::new(data).read_error("Invalid Wasm header")?;
+ let parser = wp::Parser::new(0).parse_all(data);
let mut file = WasmFile {
+ data,
+ has_memory64: false,
sections: Vec::new(),
id_sections: Default::default(),
has_debug_symbols: false,
@@ -90,18 +106,23 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
let mut imported_funcs_count = 0;
let mut local_func_kinds = Vec::new();
let mut entry_func_id = None;
+ let mut code_range_start = 0;
+ let mut code_func_index = 0;
+ // One-to-one mapping of globals to their value (if the global is a constant integer).
+ let mut global_values = Vec::new();
- for section in module {
- let section = section.read_error("Invalid Wasm section header")?;
+ for payload in parser {
+ let payload = payload.read_error("Invalid Wasm section header")?;
- match section.code {
- wp::SectionCode::Import => {
+ match payload {
+ wp::Payload::TypeSection(section) => {
+ file.add_section(SectionId::Type, section.range(), "");
+ }
+ wp::Payload::ImportSection(section) => {
+ file.add_section(SectionId::Import, section.range(), "");
let mut last_module_name = None;
- for import in section
- .get_import_section_reader()
- .read_error("Couldn't read header of the import section")?
- {
+ for import in section {
let import = import.read_error("Couldn't read an import item")?;
let module_name = import.module;
@@ -118,17 +139,20 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
}
let kind = match import.ty {
- wp::ImportSectionEntryType::Function(_) => {
+ wp::TypeRef::Func(_) => {
imported_funcs_count += 1;
SymbolKind::Text
}
- wp::ImportSectionEntryType::Table(_)
- | wp::ImportSectionEntryType::Memory(_)
- | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,
+ wp::TypeRef::Memory(memory) => {
+ file.has_memory64 |= memory.memory64;
+ SymbolKind::Data
+ }
+ wp::TypeRef::Table(_) | wp::TypeRef::Global(_) => SymbolKind::Data,
+ wp::TypeRef::Tag(_) => SymbolKind::Unknown,
};
file.symbols.push(WasmSymbolInternal {
- name: import.field,
+ name: import.name,
address: 0,
size: 0,
kind,
@@ -137,28 +161,49 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
});
}
}
- wp::SectionCode::Function => {
- local_func_kinds = vec![
- LocalFunctionKind::Unknown;
- section
- .get_function_section_reader()
- .read_error("Couldn't read header of the function section")?
- .get_count() as usize
- ];
+ 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")?;
+ let mut 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::SectionCode::Export => {
+ wp::Payload::ExportSection(section) => {
+ file.add_section(SectionId::Export, section.range(), "");
if let Some(main_file_symbol) = main_file_symbol.take() {
file.symbols.push(main_file_symbol);
}
- for export in section
- .get_export_section_reader()
- .read_error("Couldn't read header of the export section")?
- {
+ for export in section {
let export = export.read_error("Couldn't read an export item")?;
let (kind, section_idx) = match export.kind {
- wp::ExternalKind::Function => {
+ wp::ExternalKind::Func => {
if let Some(local_func_id) =
export.index.checked_sub(imported_funcs_count)
{
@@ -175,133 +220,149 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
};
symbol_ids.push(file.symbols.len() as u32);
}
- (SymbolKind::Text, SECTION_CODE)
+ (SymbolKind::Text, SectionId::Code)
}
wp::ExternalKind::Table
| wp::ExternalKind::Memory
- | wp::ExternalKind::Global => (SymbolKind::Data, SECTION_DATA),
+ | 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.
+ let mut address = 0;
+ if export.kind == wp::ExternalKind::Global {
+ if let Some(&Some(x)) = global_values.get(export.index as usize) {
+ address = x;
+ }
+ }
+
file.symbols.push(WasmSymbolInternal {
- name: export.field,
- address: 0,
+ name: export.name,
+ address,
size: 0,
kind,
- section: SymbolSection::Section(SectionIndex(section_idx)),
+ section: SymbolSection::Section(SectionIndex(section_idx as usize)),
scope: SymbolScope::Dynamic,
});
}
}
- wp::SectionCode::Start => {
- entry_func_id = Some(
- section
- .get_start_section_content()
- .read_error("Couldn't read contents of the start section")?,
- );
+ wp::Payload::StartSection { func, range, .. } => {
+ file.add_section(SectionId::Start, range, "");
+ entry_func_id = Some(func);
}
- wp::SectionCode::Code => {
+ wp::Payload::ElementSection(section) => {
+ file.add_section(SectionId::Element, section.range(), "");
+ }
+ wp::Payload::CodeSectionStart { range, .. } => {
+ code_range_start = range.start;
+ file.add_section(SectionId::Code, range, "");
if let Some(main_file_symbol) = main_file_symbol.take() {
file.symbols.push(main_file_symbol);
}
+ }
+ wp::Payload::CodeSectionEntry(body) => {
+ let i = code_func_index;
+ code_func_index += 1;
- for (i, (body, local_func_kind)) in section
- .get_code_section_reader()
- .read_error("Couldn't read header of the code section")?
- .into_iter()
- .zip(&mut local_func_kinds)
- .enumerate()
- {
- let body = body.read_error("Couldn't read a function body")?;
- let range = body.range();
-
- let address = range.start as u64 - section.range().start as u64;
- let size = (range.end - range.start) as u64;
-
- if entry_func_id == Some(i as u32) {
- file.entry = address;
- }
+ let range = body.range();
- 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(SECTION_CODE)),
- 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;
- }
+ 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 = &mut local_func_kinds[i];
+ 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!(),
}
+ _ => unreachable!(),
}
}
- wp::SectionCode::Custom {
- kind: wp::CustomSectionKind::Name,
- ..
- } => {
- for name in section
- .get_name_section_reader()
- .read_error("Couldn't read header of the name section")?
- {
- // 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.
- if let Ok(wp::Name::Function(name)) = name {
- let mut name_map = name.get_map().read_error(
- "Couldn't read header of the function name subsection",
- )?;
- for _ in 0..name_map.get_count() {
- let naming = name_map
- .read()
- .read_error("Couldn't read a function name")?;
- if let Some(local_index) =
- naming.index.checked_sub(imported_funcs_count)
- {
- if let LocalFunctionKind::Local { symbol_id } =
- local_func_kinds[local_index as usize]
+ wp::Payload::DataSection(section) => {
+ file.add_section(SectionId::Data, section.range(), "");
+ }
+ wp::Payload::DataCountSection { range, .. } => {
+ file.add_section(SectionId::DataCount, range, "");
+ }
+ wp::Payload::CustomSection(section) => {
+ let name = section.name();
+ let size = section.data().len();
+ let mut range = section.range();
+ range.start = range.end - size;
+ file.add_section(SectionId::Custom, range, name);
+ if name == "name" {
+ for name in
+ wp::NameSectionReader::new(section.data(), section.data_offset())
+ {
+ // 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.
+ if let Ok(wp::Name::Function(name_map)) = name {
+ for naming in name_map {
+ let naming =
+ naming.read_error("Couldn't read a function name")?;
+ if let Some(local_index) =
+ naming.index.checked_sub(imported_funcs_count)
{
- file.symbols[symbol_id as usize].name = naming.name;
+ if let LocalFunctionKind::Local { symbol_id } =
+ local_func_kinds[local_index as usize]
+ {
+ file.symbols[symbol_id as usize].name = naming.name;
+ }
}
}
}
}
+ } else if name.starts_with(".debug_") {
+ file.has_debug_symbols = true;
}
}
- wp::SectionCode::Custom { name, .. } if name.starts_with(".debug_") => {
- file.has_debug_symbols = true;
- }
_ => {}
}
-
- let id = section_code_to_id(section.code);
- file.id_sections[id] = Some(file.sections.len());
-
- file.sections.push(section);
}
Ok(file)
}
+
+ fn add_section(&mut self, id: SectionId, range: Range<usize>, name: &'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, 'file, R> Object<'data, 'file> for WasmFile<'data, R>
+impl<'data, 'file, R: ReadRef<'data>> Object<'data, 'file> for WasmFile<'data, R>
where
'data: 'file,
R: 'file,
@@ -319,7 +380,11 @@ where
#[inline]
fn architecture(&self) -> Architecture {
- Architecture::Wasm32
+ if self.has_memory64 {
+ Architecture::Wasm64
+ } else {
+ Architecture::Wasm32
+ }
}
#[inline]
@@ -329,7 +394,7 @@ where
#[inline]
fn is_64(&self) -> bool {
- false
+ self.has_memory64
}
fn kind(&self) -> ObjectKind {
@@ -358,15 +423,15 @@ where
.read_error("Invalid Wasm section index")?;
let section = self.sections.get(id_section).unwrap();
Ok(WasmSection {
+ file: self,
section,
- marker: PhantomData,
})
}
fn sections(&'file self) -> Self::SectionIterator {
WasmSectionIterator {
+ file: self,
sections: self.sections.iter(),
- marker: PhantomData,
}
}
@@ -513,8 +578,8 @@ impl<'data, 'file, R> ObjectSegment<'data> for WasmSegment<'data, 'file, R> {
/// An iterator over the sections of a `WasmFile`.
#[derive(Debug)]
pub struct WasmSectionIterator<'data, 'file, R = &'data [u8]> {
- sections: slice::Iter<'file, wp::Section<'data>>,
- marker: PhantomData<R>,
+ file: &'file WasmFile<'data, R>,
+ sections: slice::Iter<'file, SectionHeader<'data>>,
}
impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> {
@@ -523,8 +588,8 @@ impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> {
fn next(&mut self) -> Option<Self::Item> {
let section = self.sections.next()?;
Some(WasmSection {
+ file: self.file,
section,
- marker: PhantomData,
})
}
}
@@ -532,20 +597,20 @@ impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> {
/// A section of a `WasmFile`.
#[derive(Debug)]
pub struct WasmSection<'data, 'file, R = &'data [u8]> {
- section: &'file wp::Section<'data>,
- marker: PhantomData<R>,
+ 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> ObjectSection<'data> 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(section_code_to_id(self.section.code))
+ SectionIndex(self.section.id as usize)
}
#[inline]
@@ -555,7 +620,7 @@ impl<'data, 'file, R> ObjectSection<'data> for WasmSection<'data, 'file, R> {
#[inline]
fn size(&self) -> u64 {
- let range = self.section.range();
+ let range = &self.section.range;
(range.end - range.start) as u64
}
@@ -566,16 +631,17 @@ impl<'data, 'file, R> ObjectSection<'data> for WasmSection<'data, 'file, R> {
#[inline]
fn file_range(&self) -> Option<(u64, u64)> {
- let range = self.section.range();
+ let range = &self.section.range;
Some((range.start as _, range.end as _))
}
#[inline]
fn data(&self) -> Result<&'data [u8]> {
- let mut reader = self.section.get_binary_reader();
- // TODO: raise a feature request upstream to be able
- // to get remaining slice from a BinaryReader directly.
- Ok(reader.read_bytes(reader.bytes_remaining()).unwrap())
+ 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")
}
fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
@@ -599,20 +665,20 @@ impl<'data, 'file, R> ObjectSection<'data> for WasmSection<'data, 'file, R> {
#[inline]
fn name(&self) -> Result<&str> {
- Ok(match self.section.code {
- wp::SectionCode::Custom { name, .. } => name,
- wp::SectionCode::Type => "<type>",
- wp::SectionCode::Import => "<import>",
- wp::SectionCode::Function => "<function>",
- wp::SectionCode::Table => "<table>",
- wp::SectionCode::Memory => "<memory>",
- wp::SectionCode::Global => "<global>",
- wp::SectionCode::Export => "<export>",
- wp::SectionCode::Start => "<start>",
- wp::SectionCode::Element => "<element>",
- wp::SectionCode::Code => "<code>",
- wp::SectionCode::Data => "<data>",
- wp::SectionCode::DataCount => "<data_count>",
+ Ok(match self.section.id {
+ SectionId::Custom => self.section.name,
+ SectionId::Type => "<type>",
+ SectionId::Import => "<import>",
+ SectionId::Function => "<function>",
+ SectionId::Table => "<table>",
+ SectionId::Memory => "<memory>",
+ SectionId::Global => "<global>",
+ SectionId::Export => "<export>",
+ SectionId::Start => "<start>",
+ SectionId::Element => "<element>",
+ SectionId::Code => "<code>",
+ SectionId::Data => "<data>",
+ SectionId::DataCount => "<data_count>",
})
}
@@ -628,25 +694,23 @@ impl<'data, 'file, R> ObjectSection<'data> for WasmSection<'data, 'file, R> {
#[inline]
fn kind(&self) -> SectionKind {
- match self.section.code {
- wp::SectionCode::Custom { kind, .. } => match kind {
- wp::CustomSectionKind::Reloc | wp::CustomSectionKind::Linking => {
- SectionKind::Linker
- }
+ match self.section.id {
+ SectionId::Custom => match self.section.name {
+ "reloc." | "linking" => SectionKind::Linker,
_ => SectionKind::Other,
},
- wp::SectionCode::Type => SectionKind::Metadata,
- wp::SectionCode::Import => SectionKind::Linker,
- wp::SectionCode::Function => SectionKind::Metadata,
- wp::SectionCode::Table => SectionKind::UninitializedData,
- wp::SectionCode::Memory => SectionKind::UninitializedData,
- wp::SectionCode::Global => SectionKind::Data,
- wp::SectionCode::Export => SectionKind::Linker,
- wp::SectionCode::Start => SectionKind::Linker,
- wp::SectionCode::Element => SectionKind::Data,
- wp::SectionCode::Code => SectionKind::Text,
- wp::SectionCode::Data => SectionKind::Data,
- wp::SectionCode::DataCount => SectionKind::UninitializedData,
+ SectionId::Type => SectionKind::Metadata,
+ SectionId::Import => SectionKind::Linker,
+ SectionId::Function => SectionKind::Metadata,
+ SectionId::Table => SectionKind::UninitializedData,
+ SectionId::Memory => SectionKind::UninitializedData,
+ SectionId::Global => SectionKind::Data,
+ SectionId::Export => SectionKind::Linker,
+ SectionId::Start => SectionKind::Linker,
+ SectionId::Element => SectionKind::Data,
+ SectionId::Code => SectionKind::Text,
+ SectionId::Data => SectionKind::Data,
+ SectionId::DataCount => SectionKind::UninitializedData,
}
}
@@ -717,10 +781,7 @@ impl<'data, 'file, R> ObjectComdat<'data> for WasmComdat<'data, 'file, R> {
/// An iterator over the sections in a COMDAT section group of a `WasmFile`.
#[derive(Debug)]
-pub struct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]>
-where
- 'data: 'file,
-{
+pub struct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]> {
#[allow(unused)]
file: &'file WasmFile<'data, R>,
}
@@ -869,7 +930,7 @@ impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> {
}
#[inline]
- fn flags(&self) -> SymbolFlags<SectionIndex> {
+ fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
SymbolFlags::None
}
}
@@ -888,21 +949,3 @@ impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> {
None
}
}
-
-fn section_code_to_id(code: wp::SectionCode) -> usize {
- match code {
- wp::SectionCode::Custom { .. } => SECTION_CUSTOM,
- wp::SectionCode::Type => SECTION_TYPE,
- wp::SectionCode::Import => SECTION_IMPORT,
- wp::SectionCode::Function => SECTION_FUNCTION,
- wp::SectionCode::Table => SECTION_TABLE,
- wp::SectionCode::Memory => SECTION_MEMORY,
- wp::SectionCode::Global => SECTION_GLOBAL,
- wp::SectionCode::Export => SECTION_EXPORT,
- wp::SectionCode::Start => SECTION_START,
- wp::SectionCode::Element => SECTION_ELEMENT,
- wp::SectionCode::Code => SECTION_CODE,
- wp::SectionCode::Data => SECTION_DATA,
- wp::SectionCode::DataCount => SECTION_DATA_COUNT,
- }
-}