diff options
Diffstat (limited to 'third_party/rust/wasmparser/src/readers')
27 files changed, 4349 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser/src/readers/component.rs b/third_party/rust/wasmparser/src/readers/component.rs new file mode 100644 index 0000000000..268b264cce --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component.rs @@ -0,0 +1,15 @@ +mod aliases; +mod canonicals; +mod exports; +mod imports; +mod instances; +mod start; +mod types; + +pub use self::aliases::*; +pub use self::canonicals::*; +pub use self::exports::*; +pub use self::imports::*; +pub use self::instances::*; +pub use self::start::*; +pub use self::types::*; diff --git a/third_party/rust/wasmparser/src/readers/component/aliases.rs b/third_party/rust/wasmparser/src/readers/component/aliases.rs new file mode 100644 index 0000000000..2ef6e78338 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/aliases.rs @@ -0,0 +1,127 @@ +use crate::{ + BinaryReader, ComponentExternalKind, ExternalKind, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents the kind of an outer alias in a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentOuterAliasKind { + /// The alias is to a core module. + CoreModule, + /// The alias is to a core type. + CoreType, + /// The alias is to a component type. + Type, + /// The alias is to a component. + Component, +} + +/// Represents an alias in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentAlias<'a> { + /// The alias is to an export of a component instance. + InstanceExport { + /// The alias kind. + kind: ComponentExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, + /// The alias is to an export of a module instance. + CoreInstanceExport { + /// The alias kind. + kind: ExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, + /// The alias is to an outer item. + Outer { + /// The alias kind. + kind: ComponentOuterAliasKind, + /// The outward count, starting at zero for the current component. + count: u32, + /// The index of the item within the outer component. + index: u32, + }, +} + +/// A reader for the alias section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentAliasSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentAliasSectionReader<'a> { + /// Constructs a new `ComponentAliasSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the alias section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentAliasSectionReader; + /// let data: &[u8] = &[0x01, 0x01, 0x00, 0x00, 0x03, b'f', b'o', b'o']; + /// let mut reader = ComponentAliasSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let alias = reader.read().expect("alias"); + /// println!("Alias: {:?}", alias); + /// } + /// ``` + pub fn read(&mut self) -> Result<ComponentAlias<'a>> { + self.reader.read_component_alias() + } +} + +impl<'a> SectionReader for ComponentAliasSectionReader<'a> { + type Item = ComponentAlias<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentAliasSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentAliasSectionReader<'a> { + type Item = Result<ComponentAlias<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/canonicals.rs b/third_party/rust/wasmparser/src/readers/component/canonicals.rs new file mode 100644 index 0000000000..321e63fad0 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/canonicals.rs @@ -0,0 +1,124 @@ +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// Represents options for component functions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CanonicalOption { + /// The string types in the function signature are UTF-8 encoded. + UTF8, + /// The string types in the function signature are UTF-16 encoded. + UTF16, + /// The string types in the function signature are compact UTF-16 encoded. + CompactUTF16, + /// The memory to use if the lifting or lowering of a function requires memory access. + /// + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), +} + +/// Represents a canonical function in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum CanonicalFunction { + /// The function lifts a core WebAssembly function to the canonical ABI. + Lift { + /// The index of the core WebAssembly function to lift. + core_func_index: u32, + /// The index of the lifted function's type. + type_index: u32, + /// The canonical options for the function. + options: Box<[CanonicalOption]>, + }, + /// The function lowers a canonical ABI function to a core WebAssembly function. + Lower { + /// The index of the function to lower. + func_index: u32, + /// The canonical options for the function. + options: Box<[CanonicalOption]>, + }, +} + +/// A reader for the canonical section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentCanonicalSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentCanonicalSectionReader<'a> { + /// Constructs a new `ComponentFunctionSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads function type index from the function section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::ComponentCanonicalSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00]; + /// let mut reader = ComponentCanonicalSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let func = reader.read().expect("func"); + /// println!("Function: {:?}", func); + /// } + /// ``` + pub fn read(&mut self) -> Result<CanonicalFunction> { + self.reader.read_canonical_func() + } +} + +impl<'a> SectionReader for ComponentCanonicalSectionReader<'a> { + type Item = CanonicalFunction; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentCanonicalSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentCanonicalSectionReader<'a> { + type Item = Result<CanonicalFunction>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/exports.rs b/third_party/rust/wasmparser/src/readers/component/exports.rs new file mode 100644 index 0000000000..dc08131c3a --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/exports.rs @@ -0,0 +1,108 @@ +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// Represents the kind of an external items of a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentExternalKind { + /// The external kind is a core module. + Module, + /// The external kind is a function. + Func, + /// The external kind is a value. + Value, + /// The external kind is a type. + Type, + /// The external kind is an instance. + Instance, + /// The external kind is a component. + Component, +} + +/// Represents an export in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentExport<'a> { + /// The name of the exported item. + pub name: &'a str, + /// The kind of the export. + pub kind: ComponentExternalKind, + /// The index of the exported item. + pub index: u32, +} + +/// A reader for the export section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentExportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentExportSectionReader<'a> { + /// Constructs a new `ComponentExportSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the export section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentExportSectionReader; + /// + /// # let data: &[u8] = &[0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; + /// let mut reader = ComponentExportSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let export = reader.read().expect("export"); + /// println!("Export: {:?}", export); + /// } + /// ``` + pub fn read(&mut self) -> Result<ComponentExport<'a>> { + self.reader.read_component_export() + } +} + +impl<'a> SectionReader for ComponentExportSectionReader<'a> { + type Item = ComponentExport<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentExportSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentExportSectionReader<'a> { + type Item = Result<ComponentExport<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/imports.rs b/third_party/rust/wasmparser/src/readers/component/imports.rs new file mode 100644 index 0000000000..0b7b4faf86 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/imports.rs @@ -0,0 +1,125 @@ +use crate::{ + BinaryReader, ComponentValType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents the type bounds for imports and exports. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +/// Represents a reference to a component type. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentTypeRef { + /// The reference is to a core module type. + /// + /// The index is expected to be core type index to a core module type. + Module(u32), + /// The reference is to a function type. + /// + /// The index is expected to be a type index to a function type. + Func(u32), + /// The reference is to a value type. + Value(ComponentValType), + /// The reference is to a bounded type. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// The reference is to an instance type. + /// + /// The index is a type index to an instance type. + Instance(u32), + /// The reference is to a component type. + /// + /// The index is a type index to a component type. + Component(u32), +} + +/// Represents an import in a WebAssembly component +#[derive(Debug, Copy, Clone)] +pub struct ComponentImport<'a> { + /// The name of the imported item. + pub name: &'a str, + /// The type reference for the import. + pub ty: ComponentTypeRef, +} + +/// A reader for the import section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentImportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentImportSectionReader<'a> { + /// Constructs a new `ComponentImportSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the import section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentImportSectionReader; + /// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00]; + /// let mut reader = ComponentImportSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let import = reader.read().expect("import"); + /// println!("Import: {:?}", import); + /// } + /// ``` + pub fn read(&mut self) -> Result<ComponentImport<'a>> { + self.reader.read_component_import() + } +} + +impl<'a> SectionReader for ComponentImportSectionReader<'a> { + type Item = ComponentImport<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentImportSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentImportSectionReader<'a> { + type Item = Result<ComponentImport<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/instances.rs b/third_party/rust/wasmparser/src/readers/component/instances.rs new file mode 100644 index 0000000000..79cacfbe94 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/instances.rs @@ -0,0 +1,240 @@ +use crate::{ + BinaryReader, ComponentExport, ComponentExternalKind, Export, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents the kind of an instantiation argument for a core instance. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum InstantiationArgKind { + /// The instantiation argument is a core instance. + Instance, +} + +/// Represents an argument to instantiating a WebAssembly module. +#[derive(Debug, Clone)] +pub struct InstantiationArg<'a> { + /// The name of the module argument. + pub name: &'a str, + /// The kind of the module argument. + pub kind: InstantiationArgKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance of a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Instance<'a> { + /// The instance is from instantiating a WebAssembly module. + Instantiate { + /// The module index. + module_index: u32, + /// The module's instantiation arguments. + args: Box<[InstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[Export<'a>]>), +} + +/// A reader for the core instance section of a WebAssembly component. +#[derive(Clone)] +pub struct InstanceSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> InstanceSectionReader<'a> { + /// Constructs a new `InstanceSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the instance section. + /// + /// # Examples + /// ``` + /// use wasmparser::InstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; + /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let instance = reader.read().expect("instance"); + /// println!("Instance: {:?}", instance); + /// } + /// ``` + pub fn read(&mut self) -> Result<Instance<'a>> { + self.reader.read_instance() + } +} + +impl<'a> SectionReader for InstanceSectionReader<'a> { + type Item = Instance<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for InstanceSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for InstanceSectionReader<'a> { + type Item = Result<Instance<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + /// Implements iterator over the instance section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::InstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; + /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); + /// for inst in reader { + /// println!("Instance {:?}", inst.expect("instance")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} + +/// Represents an argument to instantiating a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentInstantiationArg<'a> { + /// The name of the component argument. + pub name: &'a str, + /// The kind of the component argument. + pub kind: ComponentExternalKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentInstance<'a> { + /// The instance is from instantiating a WebAssembly component. + Instantiate { + /// The component index. + component_index: u32, + /// The component's instantiation arguments. + args: Box<[ComponentInstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[ComponentExport<'a>]>), +} + +/// A reader for the component instance section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentInstanceSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentInstanceSectionReader<'a> { + /// Constructs a new `ComponentInstanceSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the instance section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentInstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; + /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let instance = reader.read().expect("instance"); + /// println!("Instance: {:?}", instance); + /// } + /// ``` + pub fn read(&mut self) -> Result<ComponentInstance<'a>> { + self.reader.read_component_instance() + } +} + +impl<'a> SectionReader for ComponentInstanceSectionReader<'a> { + type Item = ComponentInstance<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentInstanceSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentInstanceSectionReader<'a> { + type Item = Result<ComponentInstance<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + /// Implements iterator over the instance section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::ComponentInstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; + /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); + /// for inst in reader { + /// println!("Instance {:?}", inst.expect("instance")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/start.rs b/third_party/rust/wasmparser/src/readers/component/start.rs new file mode 100644 index 0000000000..7bfd0c8af4 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/start.rs @@ -0,0 +1,66 @@ +use crate::{BinaryReader, Result, SectionReader}; +use std::ops::Range; + +/// Represents the start function in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentStartFunction { + /// The index to the start function. + pub func_index: u32, + /// The start function arguments. + /// + /// The arguments are specified by value index. + pub arguments: Box<[u32]>, + /// The number of expected results for the start function. + pub results: u32, +} + +/// A reader for the start section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentStartSectionReader<'a>(BinaryReader<'a>); + +impl<'a> ComponentStartSectionReader<'a> { + /// Constructs a new `ComponentStartSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + Ok(Self(BinaryReader::new_with_offset(data, offset))) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.0.original_position() + } + + /// Reads the start function from the section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentStartSectionReader; + /// + /// # let data: &[u8] = &[0x00, 0x03, 0x01, 0x02, 0x03, 0x01]; + /// let mut reader = ComponentStartSectionReader::new(data, 0).unwrap(); + /// let start = reader.read().expect("start"); + /// println!("Start: {:?}", start); + /// ``` + pub fn read(&mut self) -> Result<ComponentStartFunction> { + self.0.read_component_start() + } +} + +impl<'a> SectionReader for ComponentStartSectionReader<'a> { + type Item = ComponentStartFunction; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.0.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.0.range() + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/types.rs b/third_party/rust/wasmparser/src/readers/component/types.rs new file mode 100644 index 0000000000..bf891556ab --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/types.rs @@ -0,0 +1,445 @@ +use crate::{ + BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FuncType, Import, Result, + SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, TypeRef, +}; +use std::ops::Range; + +/// Represents the kind of an outer core alias in a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum OuterAliasKind { + /// The alias is to a core type. + Type, +} + +/// Represents a core type in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum CoreType<'a> { + /// The type is for a core function. + Func(FuncType), + /// The type is for a core module. + Module(Box<[ModuleTypeDeclaration<'a>]>), +} + +/// Represents a module type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ModuleTypeDeclaration<'a> { + /// The module type definition is for a type. + Type(Type), + /// The module type definition is for an export. + Export { + /// The name of the exported item. + name: &'a str, + /// The type reference of the export. + ty: TypeRef, + }, + /// The module type declaration is for an outer alias. + OuterAlias { + /// The alias kind. + kind: OuterAliasKind, + /// The outward count, starting at zero for the current type. + count: u32, + /// The index of the item within the outer type. + index: u32, + }, + /// The module type definition is for an import. + Import(Import<'a>), +} + +/// A reader for the core type section of a WebAssembly component. +#[derive(Clone)] +pub struct CoreTypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> CoreTypeSectionReader<'a> { + /// Constructs a new `CoreTypeSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets a count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::CoreTypeSectionReader; + /// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<CoreType<'a>> { + self.reader.read_core_type() + } +} + +impl<'a> SectionReader for CoreTypeSectionReader<'a> { + type Item = CoreType<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for CoreTypeSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for CoreTypeSectionReader<'a> { + type Item = Result<CoreType<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::CoreTypeSectionReader; + /// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); + /// for ty in reader { + /// println!("Type {:?}", ty.expect("type")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} + +/// Represents a value type in a WebAssembly component. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ComponentValType { + /// The value type is a primitive type. + Primitive(PrimitiveValType), + /// The value type is a reference to a defined type. + Type(u32), +} + +/// Represents a primitive value type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrimitiveValType { + /// The type is a boolean. + Bool, + /// The type is a signed 8-bit integer. + S8, + /// The type is an unsigned 8-bit integer. + U8, + /// The type is a signed 16-bit integer. + S16, + /// The type is an unsigned 16-bit integer. + U16, + /// The type is a signed 32-bit integer. + S32, + /// The type is an unsigned 32-bit integer. + U32, + /// The type is a signed 64-bit integer. + S64, + /// The type is an unsigned 64-bit integer. + U64, + /// The type is a 32-bit floating point number. + Float32, + /// The type is a 64-bit floating point number. + Float64, + /// The type is a Unicode character. + Char, + /// The type is a string. + String, +} + +impl PrimitiveValType { + pub(crate) fn requires_realloc(&self) -> bool { + matches!(self, Self::String) + } + + /// Determines if primitive value type `a` is a subtype of `b`. + pub fn is_subtype_of(a: Self, b: Self) -> bool { + // Subtyping rules according to + // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md + a == b + || matches!( + (a, b), + (Self::S8, Self::S16) + | (Self::S8, Self::S32) + | (Self::S8, Self::S64) + | (Self::U8, Self::U16) + | (Self::U8, Self::U32) + | (Self::U8, Self::U64) + | (Self::U8, Self::S16) + | (Self::U8, Self::S32) + | (Self::U8, Self::S64) + | (Self::S16, Self::S32) + | (Self::S16, Self::S64) + | (Self::U16, Self::U32) + | (Self::U16, Self::U64) + | (Self::U16, Self::S32) + | (Self::U16, Self::S64) + | (Self::S32, Self::S64) + | (Self::U32, Self::U64) + | (Self::U32, Self::S64) + | (Self::Float32, Self::Float64) + ) + } +} + +/// Represents a type in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentType<'a> { + /// The type is a component defined type. + Defined(ComponentDefinedType<'a>), + /// The type is a function type. + Func(ComponentFuncType<'a>), + /// The type is a component type. + Component(Box<[ComponentTypeDeclaration<'a>]>), + /// The type is an instance type. + Instance(Box<[InstanceTypeDeclaration<'a>]>), +} + +/// Represents part of a component type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The component type declaration is for a type. + Type(ComponentType<'a>), + /// The component type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The component type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, + /// The component type declaration is for an import. + Import(ComponentImport<'a>), +} + +/// Represents an instance type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum InstanceTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The instance type declaration is for a type. + Type(ComponentType<'a>), + /// The instance type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The instance type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, +} + +/// Represents the result type of a component function. +#[derive(Debug, Clone)] +pub enum ComponentFuncResult<'a> { + /// The function returns a singular, unnamed type. + Unnamed(ComponentValType), + /// The function returns zero or more named types. + Named(Box<[(&'a str, ComponentValType)]>), +} + +impl ComponentFuncResult<'_> { + /// Gets the count of types returned by the function. + pub fn type_count(&self) -> usize { + match self { + Self::Unnamed(_) => 1, + Self::Named(vec) => vec.len(), + } + } + + /// Iterates over the types returned by the function. + pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> { + enum Either<L, R> { + Left(L), + Right(R), + } + + impl<L, R> Iterator for Either<L, R> + where + L: Iterator, + R: Iterator<Item = L::Item>, + { + type Item = L::Item; + + fn next(&mut self) -> Option<Self::Item> { + match self { + Either::Left(l) => l.next(), + Either::Right(r) => r.next(), + } + } + } + + match self { + Self::Unnamed(ty) => Either::Left(std::iter::once(ty).map(|ty| (None, ty))), + Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))), + } + } +} + +/// Represents a type of a function in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentFuncType<'a> { + /// The function parameters. + pub params: Box<[(&'a str, ComponentValType)]>, + /// The function result. + pub results: ComponentFuncResult<'a>, +} + +/// Represents a case in a variant type. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VariantCase<'a> { + /// The name of the variant case. + pub name: &'a str, + /// The value type of the variant case. + pub ty: Option<ComponentValType>, + /// The index of the variant case that is refined by this one. + pub refines: Option<u32>, +} + +/// Represents a defined type in a WebAssembly component. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ComponentDefinedType<'a> { + /// The type is one of the primitive value types. + Primitive(PrimitiveValType), + /// The type is a record with the given fields. + Record(Box<[(&'a str, ComponentValType)]>), + /// The type is a variant with the given cases. + Variant(Box<[VariantCase<'a>]>), + /// The type is a list of the given value type. + List(ComponentValType), + /// The type is a tuple of the given value types. + Tuple(Box<[ComponentValType]>), + /// The type is flags with the given names. + Flags(Box<[&'a str]>), + /// The type is an enum with the given tags. + Enum(Box<[&'a str]>), + /// The type is a union of the given value types. + Union(Box<[ComponentValType]>), + /// The type is an option of the given value type. + Option(ComponentValType), + /// The type is a result type. + Result { + /// The type returned for success. + ok: Option<ComponentValType>, + /// The type returned for failure. + err: Option<ComponentValType>, + }, +} + +/// A reader for the type section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentTypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentTypeSectionReader<'a> { + /// Constructs a new `ComponentTypeSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets a count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentTypeSectionReader; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; + /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<ComponentType<'a>> { + self.reader.read_component_type() + } +} + +impl<'a> SectionReader for ComponentTypeSectionReader<'a> { + type Item = ComponentType<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentTypeSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentTypeSectionReader<'a> { + type Item = Result<ComponentType<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentTypeSectionReader; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; + /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); + /// for ty in reader { + /// println!("Type {:?}", ty.expect("type")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core.rs b/third_party/rust/wasmparser/src/readers/core.rs new file mode 100644 index 0000000000..941f208548 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core.rs @@ -0,0 +1,37 @@ +mod code; +mod custom; +mod data; +mod elements; +mod exports; +mod functions; +mod globals; +mod imports; +mod init; +mod linking; +mod memories; +mod names; +mod operators; +mod producers; +mod relocs; +mod tables; +mod tags; +mod types; + +pub use self::code::*; +pub use self::custom::*; +pub use self::data::*; +pub use self::elements::*; +pub use self::exports::*; +pub use self::functions::*; +pub use self::globals::*; +pub use self::imports::*; +pub use self::init::*; +pub use self::linking::*; +pub use self::memories::*; +pub use self::names::*; +pub use self::operators::*; +pub use self::producers::*; +pub use self::relocs::*; +pub use self::tables::*; +pub use self::tags::*; +pub use self::types::*; diff --git a/third_party/rust/wasmparser/src/readers/core/code.rs b/third_party/rust/wasmparser/src/readers/core/code.rs new file mode 100644 index 0000000000..500e3ad189 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/code.rs @@ -0,0 +1,270 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, ValType, +}; +use std::ops::Range; + +/// Represents a WebAssembly function body. +#[derive(Debug, Clone, Copy)] +pub struct FunctionBody<'a> { + offset: usize, + data: &'a [u8], + allow_memarg64: bool, +} + +impl<'a> FunctionBody<'a> { + /// Constructs a new `FunctionBody` for the given data and offset. + pub fn new(offset: usize, data: &'a [u8]) -> Self { + Self { + offset, + data, + allow_memarg64: false, + } + } + + /// Whether or not to allow 64-bit memory arguments in the + /// function body. + /// + /// This is intended to be `true` when support for the memory64 + /// WebAssembly proposal is also enabled. + pub fn allow_memarg64(&mut self, allow: bool) { + self.allow_memarg64 = allow; + } + + /// Gets a binary reader for this function body. + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + reader.allow_memarg64(self.allow_memarg64); + reader + } + + fn skip_locals(reader: &mut BinaryReader) -> Result<()> { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.read_var_u32()?; + reader.read_var_u32()?; + } + Ok(()) + } + + /// Gets the locals reader for this function body. + pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + let count = reader.read_var_u32()?; + Ok(LocalsReader { reader, count }) + } + + /// Gets the operators reader for this function body. + pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + Self::skip_locals(&mut reader)?; + let pos = reader.position; + let mut reader = OperatorsReader::new(&self.data[pos..], self.offset + pos); + reader.allow_memarg64(self.allow_memarg64); + Ok(reader) + } + + /// Gets the range of the function body. + pub fn range(&self) -> Range<usize> { + self.offset..self.offset + self.data.len() + } +} + +/// A reader for a function body's locals. +pub struct LocalsReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LocalsReader<'a> { + /// Gets the count of locals in the function body. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Reads an item from the reader. + pub fn read(&mut self) -> Result<(u32, ValType)> { + let count = self.reader.read_var_u32()?; + let value_type = self.reader.read_val_type()?; + Ok((count, value_type)) + } +} + +impl<'a> IntoIterator for LocalsReader<'a> { + type Item = Result<(u32, ValType)>; + type IntoIter = LocalsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + LocalsIterator { + reader: self, + left: count, + err: false, + } + } +} + +/// An iterator over locals in a function body. +pub struct LocalsIterator<'a> { + reader: LocalsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for LocalsIterator<'a> { + type Item = Result<(u32, ValType)>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +/// A reader for the code section of a WebAssembly module. +pub struct CodeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> CodeSectionReader<'a> { + /// Constructs a new `CodeSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(CodeSectionReader { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_body_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError::new( + "function body extends past end of the code section", + self.reader.original_offset + self.reader.buffer.len(), + )); + } + Ok(()) + } + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// use wasmparser::CodeSectionReader; + /// # let data: &[u8] = &[ + /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut binary_reader = body.get_binary_reader(); + /// assert!(binary_reader.read_var_u32().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>> + where + 'a: 'b, + { + let size = self.reader.read_var_u32()? as usize; + let body_start = self.reader.position; + let body_end = body_start + size; + self.verify_body_end(body_end)?; + self.reader.skip_to(body_end); + Ok(FunctionBody { + offset: self.reader.original_offset + body_start, + data: &self.reader.buffer[body_start..body_end], + allow_memarg64: false, + }) + } +} + +impl<'a> SectionReader for CodeSectionReader<'a> { + type Item = FunctionBody<'a>; + fn read(&mut self) -> Result<Self::Item> { + CodeSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + CodeSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> { + fn get_count(&self) -> u32 { + CodeSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for CodeSectionReader<'a> { + type Item = Result<FunctionBody<'a>>; + type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>; + + /// Implements iterator over the code section. + /// + /// # Examples + /// ``` + /// use wasmparser::CodeSectionReader; + /// # let data: &[u8] = &[ + /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); + /// for body in code_reader { + /// let mut binary_reader = body.expect("b").get_binary_reader(); + /// assert!(binary_reader.read_var_u32().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/custom.rs b/third_party/rust/wasmparser/src/readers/core/custom.rs new file mode 100644 index 0000000000..a04fe5a1ac --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/custom.rs @@ -0,0 +1,63 @@ +use crate::{BinaryReader, Result}; +use std::ops::Range; + +/// A reader for custom sections of a WebAssembly module. +#[derive(Clone)] +pub struct CustomSectionReader<'a> { + // NB: these fields are public to the crate to make testing easier. + pub(crate) name: &'a str, + pub(crate) data_offset: usize, + pub(crate) data: &'a [u8], + pub(crate) range: Range<usize>, +} + +impl<'a> CustomSectionReader<'a> { + /// Constructs a new `CustomSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<CustomSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let name = reader.read_string()?; + let data_offset = reader.original_position(); + let data = reader.remaining_buffer(); + let range = reader.range(); + Ok(CustomSectionReader { + name, + data_offset, + data, + range, + }) + } + + /// The name of the custom section. + pub fn name(&self) -> &'a str { + self.name + } + + /// The offset, relative to the start of the original module or component, + /// that the `data` payload for this custom section starts at. + pub fn data_offset(&self) -> usize { + self.data_offset + } + + /// The actual contents of the custom section. + pub fn data(&self) -> &'a [u8] { + self.data + } + + /// The range of bytes that specify this whole custom section (including + /// both the name of this custom section and its data) specified in + /// offsets relative to the start of the byte stream. + pub fn range(&self) -> Range<usize> { + self.range.clone() + } +} + +impl<'a> std::fmt::Debug for CustomSectionReader<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CustomSectionReader") + .field("name", &self.name) + .field("data_offset", &self.data_offset) + .field("data", &"...") + .field("range", &self.range) + .finish() + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/data.rs b/third_party/rust/wasmparser/src/readers/core/data.rs new file mode 100644 index 0000000000..8843f1aa50 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/data.rs @@ -0,0 +1,189 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, BinaryReaderError, ConstExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents a data segment in a core WebAssembly module. +#[derive(Debug, Clone)] +pub struct Data<'a> { + /// The kind of data segment. + pub kind: DataKind<'a>, + /// The data of the data segment. + pub data: &'a [u8], + /// The range of the data segment. + pub range: Range<usize>, +} + +/// The kind of data segment. +#[derive(Debug, Copy, Clone)] +pub enum DataKind<'a> { + /// The data segment is passive. + Passive, + /// The data segment is active. + Active { + /// The memory index for the data segment. + memory_index: u32, + /// The initialization expression for the data segment. + offset_expr: ConstExpr<'a>, + }, +} + +/// A reader for the data section of a WebAssembly module. +#[derive(Clone)] +pub struct DataSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> DataSectionReader<'a> { + /// Constructs a new `DataSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<DataSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(DataSectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_data_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError::new( + "unexpected end of section or function: data segment extends past end of the data section", + self.reader.original_offset + self.reader.buffer.len(), + )); + } + Ok(()) + } + + /// Reads content of the data section. + /// + /// # Examples + /// ``` + /// use wasmparser::{DataSectionReader, DataKind}; + /// # let data: &[u8] = &[ + /// # 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; + /// let mut data_reader = DataSectionReader::new(data, 0).unwrap(); + /// for _ in 0..data_reader.get_count() { + /// let data = data_reader.read().expect("data"); + /// println!("Data: {:?}", data); + /// if let DataKind::Active { offset_expr, .. } = data.kind { + /// let mut offset_expr_reader = offset_expr.get_binary_reader(); + /// let op = offset_expr_reader.read_operator().expect("op"); + /// println!("offset expression: {:?}", op); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Data<'b>> + where + 'a: 'b, + { + let segment_start = self.reader.original_position(); + + // The current handling of the flags is largely specified in the `bulk-memory` proposal, + // which at the time this commend is written has been merged to the main specification + // draft. + // + // Notably, this proposal allows multiple different encodings of the memory index 0. `00` + // and `02 00` are both valid ways to specify the 0-th memory. However it also makes + // another encoding of the 0-th memory `80 00` no longer valid. + // + // We, however maintain this by parsing `flags` as a LEB128 integer. In that case, `80 00` + // encoding is parsed out as `0` and is therefore assigned a `memidx` 0, even though the + // current specification draft does not allow for this. + // + // See also https://github.com/WebAssembly/spec/issues/1439 + let flags = self.reader.read_var_u32()?; + let kind = match flags { + 1 => DataKind::Passive, + 0 | 2 => { + let memory_index = if flags == 0 { + 0 + } else { + self.reader.read_var_u32()? + }; + let offset_expr = { + let expr_offset = self.reader.position; + self.reader.skip_const_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + ConstExpr::new(data, self.reader.original_offset + expr_offset) + }; + DataKind::Active { + memory_index, + offset_expr, + } + } + _ => { + return Err(BinaryReaderError::new( + "invalid flags byte in data segment", + self.reader.original_position() - 1, + )); + } + }; + + let data_len = self.reader.read_var_u32()? as usize; + let data_end = self.reader.position + data_len; + self.verify_data_end(data_end)?; + let data = &self.reader.buffer[self.reader.position..data_end]; + self.reader.skip_to(data_end); + + let segment_end = self.reader.original_position(); + let range = segment_start..segment_end; + + Ok(Data { kind, data, range }) + } +} + +impl<'a> SectionReader for DataSectionReader<'a> { + type Item = Data<'a>; + fn read(&mut self) -> Result<Self::Item> { + DataSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + DataSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for DataSectionReader<'a> { + fn get_count(&self) -> u32 { + DataSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for DataSectionReader<'a> { + type Item = Result<Data<'a>>; + type IntoIter = SectionIteratorLimited<DataSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/elements.rs b/third_party/rust/wasmparser/src/readers/core/elements.rs new file mode 100644 index 0000000000..3eb0735d4f --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/elements.rs @@ -0,0 +1,333 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, ValType, +}; +use std::ops::Range; + +/// Represents a core WebAssembly element segment. +#[derive(Clone)] +pub struct Element<'a> { + /// The kind of the element segment. + pub kind: ElementKind<'a>, + /// The initial elements of the element segment. + pub items: ElementItems<'a>, + /// The type of the elements. + pub ty: ValType, + /// The range of the the element segment. + pub range: Range<usize>, +} + +/// The kind of element segment. +#[derive(Clone)] +pub enum ElementKind<'a> { + /// The element segment is passive. + Passive, + /// The element segment is active. + Active { + /// The index of the table being initialized. + table_index: u32, + /// The initial expression of the element segment. + offset_expr: ConstExpr<'a>, + }, + /// The element segment is declared. + Declared, +} + +/// Represents the items of an element segment. +#[derive(Debug, Copy, Clone)] +pub struct ElementItems<'a> { + exprs: bool, + offset: usize, + data: &'a [u8], +} + +/// Represents an individual item of an element segment. +#[derive(Debug)] +pub enum ElementItem<'a> { + /// The item is a function index. + Func(u32), + /// The item is an initialization expression. + Expr(ConstExpr<'a>), +} + +impl<'a> ElementItems<'a> { + /// Gets an items reader for the items in an element segment. + pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>> + where + 'a: 'b, + { + ElementItemsReader::new(self.data, self.offset, self.exprs) + } +} + +/// A reader for element items in an element segment. +pub struct ElementItemsReader<'a> { + reader: BinaryReader<'a>, + count: u32, + exprs: bool, +} + +impl<'a> ElementItemsReader<'a> { + /// Constructs a new `ElementItemsReader` for the given data and offset. + pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementItemsReader { + reader, + count, + exprs, + }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of element items in the segment. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Whether or not initialization expressions are used. + pub fn uses_exprs(&self) -> bool { + self.exprs + } + + /// Reads an element item from the segment. + pub fn read(&mut self) -> Result<ElementItem<'a>> { + if self.exprs { + let expr = self.reader.read_const_expr()?; + Ok(ElementItem::Expr(expr)) + } else { + let idx = self.reader.read_var_u32()?; + Ok(ElementItem::Func(idx)) + } + } +} + +impl<'a> IntoIterator for ElementItemsReader<'a> { + type Item = Result<ElementItem<'a>>; + type IntoIter = ElementItemsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ElementItemsIterator { + reader: self, + left: count, + err: false, + } + } +} + +/// An iterator over element items in an element segment. +pub struct ElementItemsIterator<'a> { + reader: ElementItemsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ElementItemsIterator<'a> { + type Item = Result<ElementItem<'a>>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +/// A reader for the element section of a WebAssembly module. +#[derive(Clone)] +pub struct ElementSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ElementSectionReader<'a> { + /// Constructs a new `ElementSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<ElementSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementSectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the element section. + /// + /// # Examples + /// + /// ```no_run + /// # let data: &[u8] = &[]; + /// use wasmparser::{ElementSectionReader, ElementKind}; + /// let mut element_reader = ElementSectionReader::new(data, 0).unwrap(); + /// for _ in 0..element_reader.get_count() { + /// let element = element_reader.read().expect("element"); + /// if let ElementKind::Active { offset_expr, .. } = element.kind { + /// let mut offset_expr_reader = offset_expr.get_binary_reader(); + /// let op = offset_expr_reader.read_operator().expect("op"); + /// println!("offset expression: {:?}", op); + /// } + /// let mut items_reader = element.items.get_items_reader().expect("items reader"); + /// for _ in 0..items_reader.get_count() { + /// let item = items_reader.read().expect("item"); + /// println!(" Item: {:?}", item); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Element<'b>> + where + 'a: 'b, + { + let elem_start = self.reader.original_position(); + // The current handling of the flags is largely specified in the `bulk-memory` proposal, + // which at the time this commend is written has been merged to the main specification + // draft. + // + // Notably, this proposal allows multiple different encodings of the table index 0. `00` + // and `02 00` are both valid ways to specify the 0-th table. However it also makes + // another encoding of the 0-th memory `80 00` no longer valid. + // + // We, however maintain this support by parsing `flags` as a LEB128 integer. In that case, + // `80 00` encoding is parsed out as `0` and is therefore assigned a `tableidx` 0, even + // though the current specification draft does not allow for this. + // + // See also https://github.com/WebAssembly/spec/issues/1439 + let flags = self.reader.read_var_u32()?; + if (flags & !0b111) != 0 { + return Err(BinaryReaderError::new( + "invalid flags byte in element segment", + self.reader.original_position() - 1, + )); + } + let kind = if flags & 0b001 != 0 { + if flags & 0b010 != 0 { + ElementKind::Declared + } else { + ElementKind::Passive + } + } else { + let table_index = if flags & 0b010 == 0 { + 0 + } else { + self.reader.read_var_u32()? + }; + let offset_expr = { + let expr_offset = self.reader.position; + self.reader.skip_const_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + ConstExpr::new(data, self.reader.original_offset + expr_offset) + }; + ElementKind::Active { + table_index, + offset_expr, + } + }; + let exprs = flags & 0b100 != 0; + let ty = if flags & 0b011 != 0 { + if exprs { + self.reader.read_val_type()? + } else { + match self.reader.read_external_kind()? { + ExternalKind::Func => ValType::FuncRef, + _ => { + return Err(BinaryReaderError::new( + "only the function external type is supported in elem segment", + self.reader.original_position() - 1, + )); + } + } + } + } else { + ValType::FuncRef + }; + let data_start = self.reader.position; + let items_count = self.reader.read_var_u32()?; + if exprs { + for _ in 0..items_count { + self.reader.skip_const_expr()?; + } + } else { + for _ in 0..items_count { + self.reader.read_var_u32()?; + } + } + let data_end = self.reader.position; + let items = ElementItems { + offset: self.reader.original_offset + data_start, + data: &self.reader.buffer[data_start..data_end], + exprs, + }; + + let elem_end = self.reader.original_position(); + let range = elem_start..elem_end; + + Ok(Element { + kind, + items, + ty, + range, + }) + } +} + +impl<'a> SectionReader for ElementSectionReader<'a> { + type Item = Element<'a>; + fn read(&mut self) -> Result<Self::Item> { + ElementSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ElementSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ElementSectionReader<'a> { + fn get_count(&self) -> u32 { + ElementSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ElementSectionReader<'a> { + type Item = Result<Element<'a>>; + type IntoIter = SectionIteratorLimited<ElementSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/exports.rs b/third_party/rust/wasmparser/src/readers/core/exports.rs new file mode 100644 index 0000000000..0f4eb0a3a9 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/exports.rs @@ -0,0 +1,123 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// External types as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ExternalKind { + /// The external kind is a function. + Func, + /// The external kind if a table. + Table, + /// The external kind is a memory. + Memory, + /// The external kind is a global. + Global, + /// The external kind is a tag. + Tag, +} + +/// Represents an export in a WebAssembly module. +#[derive(Debug, Copy, Clone)] +pub struct Export<'a> { + /// The name of the exported item. + pub name: &'a str, + /// The kind of the export. + pub kind: ExternalKind, + /// The index of the exported item. + pub index: u32, +} + +/// A reader for the export section of a WebAssembly module. +#[derive(Clone)] +pub struct ExportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ExportSectionReader<'a> { + /// Constructs a new `ExportSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the export section. + /// + /// # Examples + /// ``` + /// use wasmparser::ExportSectionReader; + /// + /// # let data: &[u8] = &[0x01, 0x01, 0x65, 0x00, 0x00]; + /// let mut reader = ExportSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let export = reader.read().expect("export"); + /// println!("Export: {:?}", export); + /// } + /// ``` + pub fn read(&mut self) -> Result<Export<'a>> { + self.reader.read_export() + } +} + +impl<'a> SectionReader for ExportSectionReader<'a> { + type Item = Export<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ExportSectionReader<'a> { + type Item = Result<Export<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/functions.rs b/third_party/rust/wasmparser/src/readers/core/functions.rs new file mode 100644 index 0000000000..a98b7fa9fe --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/functions.rs @@ -0,0 +1,95 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// A reader for the function section of a WebAssembly module. +#[derive(Clone)] +pub struct FunctionSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> FunctionSectionReader<'a> { + /// Constructs a new `FunctionSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads function type index from the function section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::FunctionSectionReader; + /// # let data: &[u8] = &[0x01, 0x00]; + /// let mut reader = FunctionSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("function type index"); + /// println!("Function type index: {}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<u32> { + self.reader.read_var_u32() + } +} + +impl<'a> SectionReader for FunctionSectionReader<'a> { + type Item = u32; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for FunctionSectionReader<'a> { + type Item = Result<u32>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/globals.rs b/third_party/rust/wasmparser/src/readers/core/globals.rs new file mode 100644 index 0000000000..49e31c320a --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/globals.rs @@ -0,0 +1,110 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, ConstExpr, GlobalType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents a core WebAssembly global. +#[derive(Debug, Copy, Clone)] +pub struct Global<'a> { + /// The global's type. + pub ty: GlobalType, + /// The global's initialization expression. + pub init_expr: ConstExpr<'a>, +} + +/// A reader for the global section of a WebAssembly module. +#[derive(Clone)] +pub struct GlobalSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> GlobalSectionReader<'a> { + /// Constructs a new `GlobalSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<GlobalSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(GlobalSectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the global section. + /// + /// # Examples + /// ``` + /// use wasmparser::GlobalSectionReader; + /// # let data: &[u8] = &[0x01, 0x7F, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0B]; + /// let mut global_reader = GlobalSectionReader::new(data, 0).unwrap(); + /// for _ in 0..global_reader.get_count() { + /// let global = global_reader.read().expect("global"); + /// println!("Global: {:?}", global); + /// let mut init_expr_reader = global.init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Global<'b>> + where + 'a: 'b, + { + let ty = self.reader.read_global_type()?; + let init_expr = self.reader.read_const_expr()?; + Ok(Global { ty, init_expr }) + } +} + +impl<'a> SectionReader for GlobalSectionReader<'a> { + type Item = Global<'a>; + fn read(&mut self) -> Result<Self::Item> { + GlobalSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + GlobalSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for GlobalSectionReader<'a> { + fn get_count(&self) -> u32 { + GlobalSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for GlobalSectionReader<'a> { + type Item = Result<Global<'a>>; + type IntoIter = SectionIteratorLimited<GlobalSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/imports.rs b/third_party/rust/wasmparser/src/readers/core/imports.rs new file mode 100644 index 0000000000..a8a7a5d5ae --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/imports.rs @@ -0,0 +1,129 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, GlobalType, MemoryType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, TableType, TagType, +}; +use std::ops::Range; + +/// Represents a reference to a type definition in a WebAssembly module. +#[derive(Debug, Clone, Copy)] +pub enum TypeRef { + /// The type is a function. + /// + /// The value is an index into the type section. + Func(u32), + /// The type is a table. + Table(TableType), + /// The type is a memory. + Memory(MemoryType), + /// The type is a global. + Global(GlobalType), + /// The type is a tag. + /// + /// This variant is only used for the exception handling proposal. + /// + /// The value is an index in the types index space. + Tag(TagType), +} + +/// Represents an import in a WebAssembly module. +#[derive(Debug, Copy, Clone)] +pub struct Import<'a> { + /// The module being imported from. + pub module: &'a str, + /// The name of the imported item. + pub name: &'a str, + /// The type of the imported item. + pub ty: TypeRef, +} + +/// A reader for the import section of a WebAssembly module. +#[derive(Clone)] +pub struct ImportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ImportSectionReader<'a> { + /// Constructs a new `ImportSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the import section. + /// + /// # Examples + /// ``` + /// use wasmparser::ImportSectionReader; + /// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00]; + /// let mut reader = ImportSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let import = reader.read().expect("import"); + /// println!("Import: {:?}", import); + /// } + /// ``` + pub fn read(&mut self) -> Result<Import<'a>> { + self.reader.read_import() + } +} + +impl<'a> SectionReader for ImportSectionReader<'a> { + type Item = Import<'a>; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ImportSectionReader<'a> { + type Item = Result<Import<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/init.rs b/third_party/rust/wasmparser/src/readers/core/init.rs new file mode 100644 index 0000000000..ad7e677add --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/init.rs @@ -0,0 +1,46 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, OperatorsReader}; + +/// Represents an initialization expression. +#[derive(Debug, Copy, Clone)] +pub struct ConstExpr<'a> { + offset: usize, + data: &'a [u8], +} + +impl<'a> ConstExpr<'a> { + /// Constructs a new `ConstExpr` from the given data and offset. + pub fn new(data: &[u8], offset: usize) -> ConstExpr { + ConstExpr { offset, data } + } + + /// Gets a binary reader for the initialization expression. + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + /// Gets an operators reader for the initialization expression. + pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader::new(self.data, self.offset) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/linking.rs b/third_party/rust/wasmparser/src/readers/core/linking.rs new file mode 100644 index 0000000000..a619288dd6 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/linking.rs @@ -0,0 +1,88 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// Represents a linking type. +#[derive(Debug, Copy, Clone)] +pub enum LinkingType { + /// The linking uses a stack pointer. + StackPointer(u32), +} + +/// A reader for the linking custom section of a WebAssembly module. +pub struct LinkingSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LinkingSectionReader<'a> { + /// Constructs a new `LinkingSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<LinkingSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(LinkingSectionReader { reader, count }) + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Reads an item from the section. + pub fn read<'b>(&mut self) -> Result<LinkingType> + where + 'a: 'b, + { + self.reader.read_linking_type() + } +} + +impl<'a> SectionReader for LinkingSectionReader<'a> { + type Item = LinkingType; + fn read(&mut self) -> Result<Self::Item> { + LinkingSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + LinkingSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for LinkingSectionReader<'a> { + fn get_count(&self) -> u32 { + LinkingSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for LinkingSectionReader<'a> { + type Item = Result<LinkingType>; + type IntoIter = SectionIteratorLimited<LinkingSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/memories.rs b/third_party/rust/wasmparser/src/readers/core/memories.rs new file mode 100644 index 0000000000..23d1cdcac9 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/memories.rs @@ -0,0 +1,93 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// A reader for the memory section of a WebAssembly module. +#[derive(Clone)] +pub struct MemorySectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> MemorySectionReader<'a> { + /// Constructs a new `MemorySectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<MemorySectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(MemorySectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the memory section. + /// + /// # Examples + /// ``` + /// use wasmparser::MemorySectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x02]; + /// let mut memory_reader = MemorySectionReader::new(data, 0).unwrap(); + /// for _ in 0..memory_reader.get_count() { + /// let memory = memory_reader.read().expect("memory"); + /// println!("Memory: {:?}", memory); + /// } + /// ``` + pub fn read(&mut self) -> Result<MemoryType> { + self.reader.read_memory_type() + } +} + +impl<'a> SectionReader for MemorySectionReader<'a> { + type Item = MemoryType; + fn read(&mut self) -> Result<Self::Item> { + MemorySectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + MemorySectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for MemorySectionReader<'a> { + fn get_count(&self) -> u32 { + MemorySectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for MemorySectionReader<'a> { + type Item = Result<MemoryType>; + type IntoIter = SectionIteratorLimited<MemorySectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/names.rs b/third_party/rust/wasmparser/src/readers/core/names.rs new file mode 100644 index 0000000000..3780b8b193 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/names.rs @@ -0,0 +1,308 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, BinaryReaderError, Result, SectionIterator, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents a name for an index from the names section. +#[derive(Debug, Copy, Clone)] +pub struct Naming<'a> { + /// The index being named. + pub index: u32, + /// The name for the index. + pub name: &'a str, +} + +/// Represents a name map from the names custom section. +#[derive(Debug, Clone)] +pub struct NameMap<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> NameMap<'a> { + /// Creates a new "name map" which parses the input data. + /// + /// This is intended to parse the `namemap` production in the name section + /// appending of the wasm spec. + pub fn new(data: &'a [u8], offset: usize) -> Result<NameMap<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(NameMap { reader, count }) + } +} + +impl<'a> SectionReader for NameMap<'a> { + type Item = Naming<'a>; + + fn read(&mut self) -> Result<Naming<'a>> { + let index = self.reader.read_var_u32()?; + let name = self.reader.read_string()?; + Ok(Naming { index, name }) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl SectionWithLimitedItems for NameMap<'_> { + fn get_count(&self) -> u32 { + self.count + } +} + +impl<'a> IntoIterator for NameMap<'a> { + type Item = Result<Naming<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} + +/// Represents an indirect name in the names custom section. +#[derive(Debug, Clone)] +pub struct IndirectNaming<'a> { + /// The indirect index of the name. + pub index: u32, + /// The map of names within the `index` prior. + pub names: NameMap<'a>, +} + +/// Represents a reader for indirect names from the names custom section. +#[derive(Clone)] +pub struct IndirectNameMap<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> IndirectNameMap<'a> { + fn new(data: &'a [u8], offset: usize) -> Result<IndirectNameMap<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(IndirectNameMap { reader, count }) + } +} + +impl<'a> SectionReader for IndirectNameMap<'a> { + type Item = IndirectNaming<'a>; + + fn read(&mut self) -> Result<IndirectNaming<'a>> { + let index = self.reader.read_var_u32()?; + let start = self.reader.position; + + // Skip the `NameMap` manually here. + // + // FIXME(#188) shouldn't need to skip here + let count = self.reader.read_var_u32()?; + for _ in 0..count { + self.reader.read_var_u32()?; + self.reader.skip_string()?; + } + + let end = self.reader.position; + Ok(IndirectNaming { + index: index, + names: NameMap::new( + &self.reader.buffer[start..end], + self.reader.original_offset + start, + )?, + }) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl SectionWithLimitedItems for IndirectNameMap<'_> { + fn get_count(&self) -> u32 { + self.count + } +} + +impl<'a> IntoIterator for IndirectNameMap<'a> { + type Item = Result<IndirectNaming<'a>>; + type IntoIter = SectionIteratorLimited<Self>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} + +/// Represents a name read from the names custom section. +#[derive(Clone)] +pub enum Name<'a> { + /// The name is for the module. + Module { + /// The specified name. + name: &'a str, + /// The byte range that `name` occupies in the original binary. + name_range: Range<usize>, + }, + /// The name is for the functions. + Function(NameMap<'a>), + /// The name is for the function locals. + Local(IndirectNameMap<'a>), + /// The name is for the function labels. + Label(IndirectNameMap<'a>), + /// The name is for the types. + Type(NameMap<'a>), + /// The name is for the tables. + Table(NameMap<'a>), + /// The name is for the memories. + Memory(NameMap<'a>), + /// The name is for the globals. + Global(NameMap<'a>), + /// The name is for the element segments. + Element(NameMap<'a>), + /// The name is for the data segments. + Data(NameMap<'a>), + /// An unknown [name subsection](https://webassembly.github.io/spec/core/appendix/custom.html#subsections). + Unknown { + /// The identifier for this subsection. + ty: u8, + /// The contents of this subsection. + data: &'a [u8], + /// The range of bytes, relative to the start of the original data + /// stream, that the contents of this subsection reside in. + range: Range<usize>, + }, +} + +/// A reader for the name custom section of a WebAssembly module. +pub struct NameSectionReader<'a> { + reader: BinaryReader<'a>, +} + +impl<'a> NameSectionReader<'a> { + /// Constructs a new `NameSectionReader` from the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<NameSectionReader<'a>> { + Ok(NameSectionReader { + reader: BinaryReader::new_with_offset(data, offset), + }) + } + + fn verify_section_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError::new( + "name entry extends past end of the code section", + self.reader.original_offset + self.reader.buffer.len(), + )); + } + Ok(()) + } + + /// Determines if the reader is at the end of the section. + pub fn eof(&self) -> bool { + self.reader.eof() + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Reads a name from the section. + pub fn read<'b>(&mut self) -> Result<Name<'b>> + where + 'a: 'b, + { + let subsection_id = self.reader.read_u7()?; + let payload_len = self.reader.read_var_u32()? as usize; + let payload_start = self.reader.position; + let payload_end = payload_start + payload_len; + self.verify_section_end(payload_end)?; + let offset = self.reader.original_offset + payload_start; + let data = &self.reader.buffer[payload_start..payload_end]; + self.reader.skip_to(payload_end); + + Ok(match subsection_id { + 0 => { + let mut reader = BinaryReader::new_with_offset(data, offset); + let name = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError::new( + "trailing data at the end of a name", + reader.original_position(), + )); + } + Name::Module { + name, + name_range: offset..offset + reader.position, + } + } + 1 => Name::Function(NameMap::new(data, offset)?), + 2 => Name::Local(IndirectNameMap::new(data, offset)?), + 3 => Name::Label(IndirectNameMap::new(data, offset)?), + 4 => Name::Type(NameMap::new(data, offset)?), + 5 => Name::Table(NameMap::new(data, offset)?), + 6 => Name::Memory(NameMap::new(data, offset)?), + 7 => Name::Global(NameMap::new(data, offset)?), + 8 => Name::Element(NameMap::new(data, offset)?), + 9 => Name::Data(NameMap::new(data, offset)?), + ty => Name::Unknown { + ty, + data, + range: offset..offset + payload_len, + }, + }) + } +} + +impl<'a> SectionReader for NameSectionReader<'a> { + type Item = Name<'a>; + fn read(&mut self) -> Result<Self::Item> { + NameSectionReader::read(self) + } + fn eof(&self) -> bool { + NameSectionReader::eof(self) + } + fn original_position(&self) -> usize { + NameSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> IntoIterator for NameSectionReader<'a> { + type Item = Result<Name<'a>>; + type IntoIter = SectionIterator<NameSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIterator::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/operators.rs b/third_party/rust/wasmparser/src/readers/core/operators.rs new file mode 100644 index 0000000000..9d9dbd8c62 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/operators.rs @@ -0,0 +1,342 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, BinaryReaderError, Result, ValType}; + +/// Represents a block type. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BlockType { + /// The block produces consumes nor produces any values. + Empty, + /// The block produces a singular value of the given type ([] -> \[t]). + Type(ValType), + /// The block is described by a function type. + /// + /// The index is to a function type in the types section. + FuncType(u32), +} + +/// Represents a memory immediate in a WebAssembly memory instruction. +#[derive(Debug, Copy, Clone)] +pub struct MemArg { + /// Alignment, stored as `n` where the actual alignment is `2^n` + pub align: u8, + /// Maximum alignment, stored as `n` where the actual alignment is `2^n`. + /// + /// Note that this field is not actually read from the binary format, it + /// will be a constant depending on which instruction this `MemArg` is a + /// payload for. + pub max_align: u8, + /// A fixed byte-offset that this memory immediate specifies. + /// + /// Note that the memory64 proposal can specify a full 64-bit byte offset + /// while otherwise only 32-bit offsets are allowed. Once validated + /// memory immediates for 32-bit memories are guaranteed to be at most + /// `u32::MAX` whereas 64-bit memories can use the full 64-bits. + pub offset: u64, + /// The index of the memory this immediate points to. + /// + /// Note that this points within the module's own memory index space, and + /// is always zero unless the multi-memory proposal of WebAssembly is + /// enabled. + pub memory: u32, +} + +/// A br_table entries representation. +#[derive(Clone)] +pub struct BrTable<'a> { + pub(crate) reader: crate::BinaryReader<'a>, + pub(crate) cnt: u32, + pub(crate) default: u32, +} + +/// An IEEE binary32 immediate floating point value, represented as a u32 +/// containing the bit pattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee32(pub(crate) u32); + +impl Ieee32 { + /// Gets the underlying bits of the 32-bit float. + pub fn bits(self) -> u32 { + self.0 + } +} + +/// An IEEE binary64 immediate floating point value, represented as a u64 +/// containing the bit pattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee64(pub(crate) u64); + +impl Ieee64 { + /// Gets the underlying bits of the 64-bit float. + pub fn bits(self) -> u64 { + self.0 + } +} + +/// Represents a 128-bit vector value. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct V128(pub(crate) [u8; 16]); + +impl V128 { + /// Gets the bytes of the vector value. + pub fn bytes(&self) -> &[u8; 16] { + &self.0 + } + + /// Gets a signed 128-bit integer value from the vector's bytes. + pub fn i128(&self) -> i128 { + i128::from_le_bytes(self.0) + } +} + +macro_rules! define_operator { + ($(@$proposal:ident $op:ident $({ $($payload:tt)* })? => $visit:ident)*) => { + /// Instructions as defined [here]. + /// + /// [here]: https://webassembly.github.io/spec/core/binary/instructions.html + #[derive(Debug, Clone)] + #[allow(missing_docs)] + pub enum Operator<'a> { + $( + $op $({ $($payload)* })?, + )* + } + } +} +for_each_operator!(define_operator); + +/// A reader for a core WebAssembly function's operators. +#[derive(Clone)] +pub struct OperatorsReader<'a> { + pub(crate) reader: BinaryReader<'a>, +} + +impl<'a> OperatorsReader<'a> { + pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader { + reader: BinaryReader::new_with_offset(data, offset), + } + } + + /// Determines if the reader is at the end of the operators. + pub fn eof(&self) -> bool { + self.reader.eof() + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Whether or not to allow 64-bit memory arguments in the + /// the operators being read. + /// + /// This is intended to be `true` when support for the memory64 + /// WebAssembly proposal is also enabled. + pub fn allow_memarg64(&mut self, allow: bool) { + self.reader.allow_memarg64(allow); + } + + /// Ensures the reader is at the end. + /// + /// This function returns an error if there is extra data after the operators. + pub fn ensure_end(&self) -> Result<()> { + if self.eof() { + return Ok(()); + } + Err(BinaryReaderError::new( + "unexpected data at the end of operators", + self.reader.original_position(), + )) + } + + /// Reads an operator from the reader. + pub fn read<'b>(&mut self) -> Result<Operator<'b>> + where + 'a: 'b, + { + self.reader.read_operator() + } + + /// Converts to an iterator of operators paired with offsets. + pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b> + where + 'a: 'b, + { + OperatorsIteratorWithOffsets { + reader: self, + err: false, + } + } + + /// Reads an operator with its offset. + pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)> + where + 'a: 'b, + { + let pos = self.reader.original_position(); + Ok((self.read()?, pos)) + } + + /// Visit a single operator with the specified [`VisitOperator`] instance. + /// + /// See [`BinaryReader::visit_operator`] for more information. + pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output> + where + T: VisitOperator<'a>, + { + self.reader.visit_operator(visitor) + } + + /// Gets a binary reader from this operators reader. + pub fn get_binary_reader(&self) -> BinaryReader<'a> { + self.reader.clone() + } +} + +impl<'a> IntoIterator for OperatorsReader<'a> { + type Item = Result<Operator<'a>>; + type IntoIter = OperatorsIterator<'a>; + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// use wasmparser::{Operator, CodeSectionReader, Result}; + /// # let data: &[u8] = &[ + /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter().collect::<Result<Vec<Operator>>>().expect("ops"); + /// assert!( + /// if let [Operator::Nop, Operator::End] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + OperatorsIterator { + reader: self, + err: false, + } + } +} + +/// An iterator over a function's operators. +pub struct OperatorsIterator<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIterator<'a> { + type Item = Result<Operator<'a>>; + + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} + +/// An iterator over a function's operators with offsets. +pub struct OperatorsIteratorWithOffsets<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { + type Item = Result<(Operator<'a>, usize)>; + + /// Reads content of the code section with offsets. + /// + /// # Examples + /// ``` + /// use wasmparser::{Operator, CodeSectionReader, Result}; + /// # let data: &[u8] = &[ + /// # 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b]; + /// let mut code_reader = CodeSectionReader::new(data, 20).unwrap(); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter_with_offsets().collect::<Result<Vec<(Operator, usize)>>>().expect("ops"); + /// assert!( + /// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read_with_offset(); + self.err = result.is_err(); + Some(result) + } +} + +macro_rules! define_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output; + )* + } +} + +/// Trait implemented by types that can visit all [`Operator`] variants. +#[allow(missing_docs)] +pub trait VisitOperator<'a> { + /// The result type of the visitor. + type Output: 'a; + + /// Visits the [`Operator`] `op` using the given `offset`. + /// + /// # Note + /// + /// This is a convenience method that is intended for non-performance + /// critical use cases. For performance critical implementations users + /// are recommended to directly use the respective `visit` methods or + /// implement [`VisitOperator`] on their own. + fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { + macro_rules! visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + match op { + $( + Operator::$op $({ $($arg),* })? => self.$visit($($($arg.clone()),*)?), + )* + } + } + + } + for_each_operator!(visit_operator) + } + + for_each_operator!(define_visit_operator); +} diff --git a/third_party/rust/wasmparser/src/readers/core/producers.rs b/third_party/rust/wasmparser/src/readers/core/producers.rs new file mode 100644 index 0000000000..4999aa45be --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/producers.rs @@ -0,0 +1,211 @@ +/* Copyright 2019 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// Represents a field value in the producers custom section. +#[derive(Debug, Copy, Clone)] +pub struct ProducersFieldValue<'a> { + /// The field name. + pub name: &'a str, + /// The field version. + pub version: &'a str, +} + +/// A reader for fields in the producers custom section. +pub struct ProducersFieldValuesReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersFieldValuesReader<'a> { + /// Gets the count of items in the reader. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> { + for _ in 0..values_count { + reader.skip_string()?; + reader.skip_string()?; + } + Ok(()) + } + + /// Reads a field from the reader. + pub fn read<'b>(&mut self) -> Result<ProducersFieldValue<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let version = self.reader.read_string()?; + Ok(ProducersFieldValue { name, version }) + } +} + +impl<'a> IntoIterator for ProducersFieldValuesReader<'a> { + type Item = Result<ProducersFieldValue<'a>>; + type IntoIter = ProducersFieldValuesIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ProducersFieldValuesIterator { + reader: self, + left: count, + err: false, + } + } +} + +/// An iterator over fields in the producers custom section. +pub struct ProducersFieldValuesIterator<'a> { + reader: ProducersFieldValuesReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ProducersFieldValuesIterator<'a> { + type Item = Result<ProducersFieldValue<'a>>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +/// A field from the producers custom section. +#[derive(Debug, Copy, Clone)] +pub struct ProducersField<'a> { + /// The name of the field. + pub name: &'a str, + values_count: u32, + values_data: &'a [u8], + values_offset: usize, +} + +impl<'a> ProducersField<'a> { + /// Gets a reader of values for the field. + pub fn get_producer_field_values_reader<'b>(&self) -> Result<ProducersFieldValuesReader<'b>> + where + 'a: 'b, + { + Ok(ProducersFieldValuesReader { + reader: BinaryReader::new_with_offset(self.values_data, self.values_offset), + count: self.values_count, + }) + } +} + +/// A reader for the producers custom section of a WebAssembly module. +pub struct ProducersSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersSectionReader<'a> { + /// Creates reader for the producers section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; + /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; + /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader"); + /// let field = reader.read().expect("producers field"); + /// assert!(field.name == "language"); + /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader"); + /// let value = values_reader.into_iter().collect::<Result<Vec<ProducersFieldValue>>>().expect("values"); + /// assert!(value.len() == 2); + /// assert!(value[0].name == "wat" && value[0].version == "1"); + /// assert!(value[1].name == "C" && value[1].version == "9.0"); + /// ``` + pub fn new(data: &'a [u8], offset: usize) -> Result<ProducersSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ProducersSectionReader { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the reader. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads an item from the reader. + pub fn read<'b>(&mut self) -> Result<ProducersField<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let values_count = self.reader.read_var_u32()?; + let values_start = self.reader.position; + ProducersFieldValuesReader::skip(&mut self.reader, values_count)?; + let values_end = self.reader.position; + Ok(ProducersField { + name, + values_count, + values_data: &self.reader.buffer[values_start..values_end], + values_offset: self.reader.original_offset + values_start, + }) + } +} + +impl<'a> SectionReader for ProducersSectionReader<'a> { + type Item = ProducersField<'a>; + fn read(&mut self) -> Result<Self::Item> { + ProducersSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ProducersSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> { + fn get_count(&self) -> u32 { + ProducersSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ProducersSectionReader<'a> { + type Item = Result<ProducersField<'a>>; + type IntoIter = SectionIteratorLimited<ProducersSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/relocs.rs b/third_party/rust/wasmparser/src/readers/core/relocs.rs new file mode 100644 index 0000000000..29a9e33faf --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/relocs.rs @@ -0,0 +1,198 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::ops::Range; + +/// Represents a relocation type. +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub enum RelocType { + FunctionIndexLEB, + TableIndexSLEB, + TableIndexI32, + GlobalAddrLEB, + GlobalAddrSLEB, + GlobalAddrI32, + TypeIndexLEB, + GlobalIndexLEB, +} + +/// Represents known custom section kinds. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CustomSectionKind { + /// The custom section is not known. + Unknown, + /// The name custom section. + Name, + /// The producers custom section. + Producers, + /// The source mapping URL custom section. + SourceMappingURL, + /// The reloc custom section. + Reloc, + /// The linking custom section. + Linking, +} + +/// Section code as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum SectionCode<'a> { + /// The custom section. + Custom { + /// The name of the custom section. + name: &'a str, + /// The kind of the custom section. + kind: CustomSectionKind, + }, + /// The type section. + Type, + /// The import section. + Import, + /// The function section. + Function, + /// The table section. + Table, + /// The memory section. + Memory, + /// The global section. + Global, + /// The export section. + Export, + /// The start section. + Start, + /// The element section. + Element, + /// The code section. + Code, + /// The data section. + Data, + /// The passive data count section. + DataCount, + /// The tag section. + Tag, +} + +/// Represents a relocation entry. +#[derive(Debug, Copy, Clone)] +pub struct Reloc { + /// The relocation type. + pub ty: RelocType, + /// The relocation offset. + pub offset: u32, + /// The relocation index. + pub index: u32, + /// The relocation addend. + pub addend: Option<u32>, +} + +/// A reader for the relocations custom section of a WebAssembly module. +pub struct RelocSectionReader<'a> { + reader: BinaryReader<'a>, + section_code: SectionCode<'a>, + count: u32, +} + +impl<'a> RelocSectionReader<'a> { + /// Constructs a new `RelocSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<RelocSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + + let section_id_position = reader.position; + let section_id = reader.read_u7()?; + let section_code = reader.read_section_code(section_id, section_id_position)?; + + let count = reader.read_var_u32()?; + Ok(RelocSectionReader { + reader, + section_code, + count, + }) + } + + /// Gets a count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Gets the section code from the section. + pub fn get_section_code<'b>(&self) -> SectionCode<'b> + where + 'a: 'b, + { + self.section_code + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Reads an item from the reader. + pub fn read(&mut self) -> Result<Reloc> { + let ty = self.reader.read_reloc_type()?; + let offset = self.reader.read_var_u32()?; + let index = self.reader.read_var_u32()?; + let addend = match ty { + RelocType::FunctionIndexLEB + | RelocType::TableIndexSLEB + | RelocType::TableIndexI32 + | RelocType::TypeIndexLEB + | RelocType::GlobalIndexLEB => None, + RelocType::GlobalAddrLEB | RelocType::GlobalAddrSLEB | RelocType::GlobalAddrI32 => { + Some(self.reader.read_var_u32()?) + } + }; + Ok(Reloc { + ty, + offset, + index, + addend, + }) + } +} + +impl<'a> SectionReader for RelocSectionReader<'a> { + type Item = Reloc; + fn read(&mut self) -> Result<Self::Item> { + RelocSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + RelocSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for RelocSectionReader<'a> { + fn get_count(&self) -> u32 { + RelocSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for RelocSectionReader<'a> { + type Item = Result<Reloc>; + type IntoIter = SectionIteratorLimited<RelocSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/tables.rs b/third_party/rust/wasmparser/src/readers/core/tables.rs new file mode 100644 index 0000000000..3121b5fe98 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/tables.rs @@ -0,0 +1,93 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType, +}; +use std::ops::Range; + +/// A reader for the table section of a WebAssembly module. +#[derive(Clone)] +pub struct TableSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TableSectionReader<'a> { + /// Constructs a new `TableSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<TableSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TableSectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the table section. + /// + /// # Examples + /// ``` + /// use wasmparser::TableSectionReader; + /// + /// # let data: &[u8] = &[0x01, 0x70, 0x01, 0x01, 0x01]; + /// let mut table_reader = TableSectionReader::new(data, 0).unwrap(); + /// for _ in 0..table_reader.get_count() { + /// let table = table_reader.read().expect("table"); + /// println!("Table: {:?}", table); + /// } + /// ``` + pub fn read(&mut self) -> Result<TableType> { + self.reader.read_table_type() + } +} + +impl<'a> SectionReader for TableSectionReader<'a> { + type Item = TableType; + fn read(&mut self) -> Result<Self::Item> { + TableSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TableSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for TableSectionReader<'a> { + fn get_count(&self) -> u32 { + TableSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TableSectionReader<'a> { + type Item = Result<TableType>; + type IntoIter = SectionIteratorLimited<TableSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/tags.rs b/third_party/rust/wasmparser/src/readers/core/tags.rs new file mode 100644 index 0000000000..fd40779791 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/tags.rs @@ -0,0 +1,92 @@ +/* Copyright 2020 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{ + BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TagType, +}; +use std::ops::Range; + +/// A reader for the tags section of a WebAssembly module. +#[derive(Clone)] +pub struct TagSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TagSectionReader<'a> { + /// Constructs a new `TagSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<TagSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TagSectionReader { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the tag section. + /// + /// # Examples + /// ``` + /// use wasmparser::TagSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x01]; + /// let mut reader = TagSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("tag type"); + /// println!("Tag type: {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<TagType> { + self.reader.read_tag_type() + } +} + +impl<'a> SectionReader for TagSectionReader<'a> { + type Item = TagType; + fn read(&mut self) -> Result<Self::Item> { + TagSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TagSectionReader::original_position(self) + } + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for TagSectionReader<'a> { + fn get_count(&self) -> u32 { + TagSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TagSectionReader<'a> { + type Item = Result<TagType>; + type IntoIter = SectionIteratorLimited<TagSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/types.rs b/third_party/rust/wasmparser/src/readers/core/types.rs new file mode 100644 index 0000000000..cb6d2e80af --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/core/types.rs @@ -0,0 +1,279 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use std::fmt::Debug; +use std::ops::Range; + +/// Represents the types of values in a WebAssembly module. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ValType { + /// The value type is i32. + I32, + /// The value type is i64. + I64, + /// The value type is f32. + F32, + /// The value type is f64. + F64, + /// The value type is v128. + V128, + /// The value type is a function reference. + FuncRef, + /// The value type is an extern reference. + ExternRef, +} + +impl ValType { + /// Returns whether this value type is a "reference type". + /// + /// Only reference types are allowed in tables, for example, and with some + /// instructions. Current reference types include `funcref` and `externref`. + pub fn is_reference_type(&self) -> bool { + matches!(self, ValType::FuncRef | ValType::ExternRef) + } +} + +/// Represents a type in a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Type { + /// The type is for a function. + Func(FuncType), +} + +/// Represents a type of a function in a WebAssembly module. +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct FuncType { + /// The combined parameters and result types. + params_results: Box<[ValType]>, + /// The number of parameter types. + len_params: usize, +} + +impl Debug for FuncType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FuncType") + .field("params", &self.params()) + .field("returns", &self.results()) + .finish() + } +} + +impl FuncType { + /// Creates a new [`FuncType`] from the given `params` and `results`. + pub fn new<P, R>(params: P, results: R) -> Self + where + P: IntoIterator<Item = ValType>, + R: IntoIterator<Item = ValType>, + { + let mut buffer = params.into_iter().collect::<Vec<_>>(); + let len_params = buffer.len(); + buffer.extend(results); + Self { + params_results: buffer.into(), + len_params, + } + } + + /// Creates a new [`FuncType`] fom its raw parts. + /// + /// # Panics + /// + /// If `len_params` is greater than the length of `params_results` combined. + pub(crate) fn from_raw_parts(params_results: Box<[ValType]>, len_params: usize) -> Self { + assert!(len_params <= params_results.len()); + Self { + params_results, + len_params, + } + } + + /// Returns a shared slice to the parameter types of the [`FuncType`]. + #[inline] + pub fn params(&self) -> &[ValType] { + &self.params_results[..self.len_params] + } + + /// Returns a shared slice to the result types of the [`FuncType`]. + #[inline] + pub fn results(&self) -> &[ValType] { + &self.params_results[self.len_params..] + } +} + +/// Represents a table's type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct TableType { + /// The table's element type. + pub element_type: ValType, + /// Initial size of this table, in elements. + pub initial: u32, + /// Optional maximum size of the table, in elements. + pub maximum: Option<u32>, +} + +/// Represents a memory's type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct MemoryType { + /// Whether or not this is a 64-bit memory, using i64 as an index. If this + /// is false it's a 32-bit memory using i32 as an index. + /// + /// This is part of the memory64 proposal in WebAssembly. + pub memory64: bool, + + /// Whether or not this is a "shared" memory, indicating that it should be + /// send-able across threads and the `maximum` field is always present for + /// valid types. + /// + /// This is part of the threads proposal in WebAssembly. + pub shared: bool, + + /// Initial size of this memory, in wasm pages. + /// + /// For 32-bit memories (when `memory64` is `false`) this is guaranteed to + /// be at most `u32::MAX` for valid types. + pub initial: u64, + + /// Optional maximum size of this memory, in wasm pages. + /// + /// For 32-bit memories (when `memory64` is `false`) this is guaranteed to + /// be at most `u32::MAX` for valid types. This field is always present for + /// valid wasm memories when `shared` is `true`. + pub maximum: Option<u64>, +} + +impl MemoryType { + /// Gets the index type for the memory. + pub fn index_type(&self) -> ValType { + if self.memory64 { + ValType::I64 + } else { + ValType::I32 + } + } +} + +/// Represents a global's type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct GlobalType { + /// The global's type. + pub content_type: ValType, + /// Whether or not the global is mutable. + pub mutable: bool, +} + +/// Represents a tag kind. +#[derive(Clone, Copy, Debug)] +pub enum TagKind { + /// The tag is an exception type. + Exception, +} + +/// A tag's type. +#[derive(Clone, Copy, Debug)] +pub struct TagType { + /// The kind of tag + pub kind: TagKind, + /// The function type this tag uses. + pub func_type_idx: u32, +} + +/// A reader for the type section of a WebAssembly module. +#[derive(Clone)] +pub struct TypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TypeSectionReader<'a> { + /// Constructs a new `TypeSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result<Self> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets a count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::TypeSectionReader; + /// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = TypeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<Type> { + self.reader.read_type() + } +} + +impl<'a> SectionReader for TypeSectionReader<'a> { + type Item = Type; + + fn read(&mut self) -> Result<Self::Item> { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range<usize> { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for TypeSectionReader<'a> { + type Item = Result<Type>; + type IntoIter = SectionIteratorLimited<Self>; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::TypeSectionReader; + /// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = TypeSectionReader::new(data, 0).unwrap(); + /// for ty in reader { + /// println!("Type {:?}", ty.expect("type")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} |