diff options
Diffstat (limited to 'third_party/rust/wasmparser-0.48.2/src/parser.rs')
-rw-r--r-- | third_party/rust/wasmparser-0.48.2/src/parser.rs | 1185 |
1 files changed, 1185 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser-0.48.2/src/parser.rs b/third_party/rust/wasmparser-0.48.2/src/parser.rs new file mode 100644 index 0000000000..9906c6244c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/parser.rs @@ -0,0 +1,1185 @@ +/* Copyright 2017 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. + */ +// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md + +use std::boxed::Box; +use std::vec::Vec; + +use crate::limits::{ + MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_STRING_SIZE, MAX_WASM_TABLE_ENTRIES, +}; + +use crate::primitives::{ + BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType, + ImportSectionEntryType, LinkingType, MemoryType, Naming, Operator, RelocType, Result, + SectionCode, TableType, Type, +}; + +use crate::readers::{ + CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, + ElementKind, ElementSectionReader, Export, ExportSectionReader, FunctionBody, + FunctionSectionReader, Global, GlobalSectionReader, Import, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, ModuleReader, Name, NameSectionReader, NamingReader, + OperatorsReader, Reloc, RelocSectionReader, Section, SectionReader, TableSectionReader, + TypeSectionReader, +}; + +use crate::binary_reader::{BinaryReader, Range}; + +const MAX_DATA_CHUNK_SIZE: usize = MAX_WASM_STRING_SIZE; + +#[derive(Debug)] +pub struct LocalName<'a> { + pub index: u32, + pub locals: Box<[Naming<'a>]>, +} + +#[derive(Debug)] +pub enum NameEntry<'a> { + Module(&'a str), + Function(Box<[Naming<'a>]>), + Local(Box<[LocalName<'a>]>), +} + +#[derive(Debug)] +pub struct RelocEntry { + pub ty: RelocType, + pub offset: u32, + pub index: u32, + pub addend: Option<u32>, +} + +enum InitExpressionContinuationSection { + Global, + Element, + Data, +} + +#[derive(Debug)] +pub enum ParserState<'a> { + Error(BinaryReaderError), + Initial, + BeginWasm { + version: u32, + }, + EndWasm, + BeginSection { + code: SectionCode<'a>, + range: Range, + }, + EndSection, + SkippingSection, + ReadingCustomSection(CustomSectionKind), + ReadingSectionRawData, + SectionRawData(&'a [u8]), + + TypeSectionEntry(FuncType), + ImportSectionEntry { + module: &'a str, + field: &'a str, + ty: ImportSectionEntryType, + }, + FunctionSectionEntry(u32), + TableSectionEntry(TableType), + MemorySectionEntry(MemoryType), + ExportSectionEntry { + field: &'a str, + kind: ExternalKind, + index: u32, + }, + NameSectionEntry(NameEntry<'a>), + StartSectionEntry(u32), + DataCountSectionEntry(u32), + + BeginInitExpressionBody, + InitExpressionOperator(Operator<'a>), + EndInitExpressionBody, + + BeginFunctionBody { + range: Range, + }, + FunctionBodyLocals { + locals: Box<[(u32, Type)]>, + }, + CodeOperator(Operator<'a>), + EndFunctionBody, + SkippingFunctionBody, + + BeginElementSectionEntry { + /// `None` means this is a passive or defined entry + table: ElemSectionEntryTable, + ty: Type, + }, + ElementSectionEntryBody(Box<[ElementItem]>), + EndElementSectionEntry, + + BeginPassiveDataSectionEntry, + BeginActiveDataSectionEntry(u32), + EndDataSectionEntry, + BeginDataSectionEntryBody(u32), + DataSectionEntryBodyChunk(&'a [u8]), + EndDataSectionEntryBody, + + BeginGlobalSectionEntry(GlobalType), + EndGlobalSectionEntry, + + RelocSectionHeader(SectionCode<'a>), + RelocSectionEntry(RelocEntry), + LinkingSectionEntry(LinkingType), + + SourceMappingURL(&'a str), +} + +#[derive(Debug, Copy, Clone)] +pub enum ElemSectionEntryTable { + Passive, + Declared, + Active(u32), +} + +#[derive(Debug, Copy, Clone)] +pub enum ParserInput { + Default, + SkipSection, + SkipFunctionBody, + ReadCustomSection, + ReadSectionRawData, +} + +pub trait WasmDecoder<'a> { + fn read(&mut self) -> &ParserState<'a>; + fn push_input(&mut self, input: ParserInput); + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>; + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b; + fn last_state(&self) -> &ParserState<'a>; +} + +enum ParserSectionReader<'a> { + None, + CodeSectionReader(CodeSectionReader<'a>), + DataSectionReader(DataSectionReader<'a>), + ElementSectionReader(ElementSectionReader<'a>), + ExportSectionReader(ExportSectionReader<'a>), + FunctionSectionReader(FunctionSectionReader<'a>), + GlobalSectionReader(GlobalSectionReader<'a>), + ImportSectionReader(ImportSectionReader<'a>), + MemorySectionReader(MemorySectionReader<'a>), + TableSectionReader(TableSectionReader<'a>), + TypeSectionReader(TypeSectionReader<'a>), + NameSectionReader(NameSectionReader<'a>), + LinkingSectionReader(LinkingSectionReader<'a>), + RelocSectionReader(RelocSectionReader<'a>), +} + +macro_rules! section_reader { + ($self:ident, $ty_and_name:ident) => { + if let ParserSectionReader::$ty_and_name(ref mut reader) = $self.section_reader { + reader + } else { + panic!("expected {} reader", stringify!($ty_and_name)); + } + }; +} + +macro_rules! start_section_reader { + ($self:ident, $ty_and_name:ident, $factory:ident) => {{ + let reader = $self + .current_section + .as_ref() + .expect("section") + .$factory()?; + $self.section_entries_left = reader.get_count(); + $self.section_reader = ParserSectionReader::$ty_and_name(reader); + }}; +} + +/// The `Parser` type. A simple event-driven parser of WebAssembly binary +/// format. The `read(&mut self)` is used to iterate through WebAssembly records. +pub struct Parser<'a> { + data: &'a [u8], + state: ParserState<'a>, + module_reader: Option<ModuleReader<'a>>, + current_section: Option<Section<'a>>, + section_reader: ParserSectionReader<'a>, + element_items: Option<ElementItems<'a>>, + current_function_body: Option<FunctionBody<'a>>, + init_expr_continuation: Option<InitExpressionContinuationSection>, + current_data_segment: Option<&'a [u8]>, + binary_reader: Option<BinaryReader<'a>>, + operators_reader: Option<OperatorsReader<'a>>, + section_entries_left: u32, +} + +impl<'a> Parser<'a> { + /// Constructs `Parser` type. + /// + /// # Examples + /// ``` + /// let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut parser = wasmparser::Parser::new(data); + /// ``` + pub fn new(data: &[u8]) -> Parser { + Parser { + data, + state: ParserState::Initial, + module_reader: None, + current_section: None, + section_reader: ParserSectionReader::None, + element_items: None, + current_function_body: None, + init_expr_continuation: None, + current_data_segment: None, + binary_reader: None, + operators_reader: None, + section_entries_left: 0, + } + } + + pub fn eof(&self) -> bool { + match self.state { + ParserState::EndWasm => true, + ParserState::BeginWasm { .. } | ParserState::EndSection => { + self.module_reader.as_ref().expect("module reader").eof() + } + _ => false, // in-process of reading + } + } + + pub fn current_position(&self) -> usize { + if let ParserState::Initial = self.state { + return 0; + } + if self.binary_reader.is_some() { + return self + .binary_reader + .as_ref() + .expect("binary reader") + .original_position(); + } + if self.operators_reader.is_some() { + return self + .operators_reader + .as_ref() + .expect("operators reader") + .original_position(); + } + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::DataSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::ElementSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ExportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::FunctionSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::GlobalSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ImportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::MemorySectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TableSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TypeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::NameSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::LinkingSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::RelocSectionReader(ref reader) => { + return reader.original_position(); + } + _ => (), + }; + // TODO might not cover all cases + self.module_reader + .as_ref() + .expect("module reader") + .current_position() + } + + fn read_module(&mut self) -> Result<()> { + let module_reader = ModuleReader::new(self.data)?; + let version = module_reader.get_version(); + self.module_reader = Some(module_reader); + self.state = ParserState::BeginWasm { version }; + Ok(()) + } + + fn read_section_header(&mut self) -> Result<()> { + let section = self.module_reader.as_mut().expect("module reader").read()?; + let code = section.code; + let range = section.range(); + self.current_section = Some(section); + self.state = ParserState::BeginSection { code, range }; + Ok(()) + } + + fn read_type_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let type_entry = section_reader!(self, TypeSectionReader).read()?; + self.state = ParserState::TypeSectionEntry(type_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_import_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Import { module, field, ty } = section_reader!(self, ImportSectionReader).read()?; + self.state = ParserState::ImportSectionEntry { module, field, ty }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let func_type = section_reader!(self, FunctionSectionReader).read()?; + self.state = ParserState::FunctionSectionEntry(func_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_memory_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let memory_type = section_reader!(self, MemorySectionReader).read()?; + self.state = ParserState::MemorySectionEntry(memory_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_global_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Global { ty, init_expr } = section_reader!(self, GlobalSectionReader).read()?; + self.state = ParserState::BeginGlobalSectionEntry(ty); + self.operators_reader = Some(init_expr.get_operators_reader()); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_init_expression_body(&mut self, cont: InitExpressionContinuationSection) { + self.state = ParserState::BeginInitExpressionBody; + self.init_expr_continuation = Some(cont); + } + + fn read_init_expression_operator(&mut self) -> Result<()> { + let op = self + .operators_reader + .as_mut() + .expect("operator reader") + .read()?; + if let Operator::End = op { + self.operators_reader = None; + self.state = ParserState::EndInitExpressionBody; + return Ok(()); + } + self.state = ParserState::InitExpressionOperator(op); + Ok(()) + } + + fn read_export_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Export { field, kind, index } = section_reader!(self, ExportSectionReader).read()?; + self.state = ParserState::ExportSectionEntry { field, kind, index }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Element { kind, items, ty } = section_reader!(self, ElementSectionReader).read()?; + let table = match kind { + ElementKind::Passive => ElemSectionEntryTable::Passive, + ElementKind::Declared => ElemSectionEntryTable::Declared, + ElementKind::Active { + table_index, + init_expr, + } => { + self.operators_reader = Some(init_expr.get_operators_reader()); + ElemSectionEntryTable::Active(table_index) + } + }; + self.state = ParserState::BeginElementSectionEntry { table, ty }; + self.element_items = Some(items); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry_body(&mut self) -> Result<()> { + let mut reader = self + .element_items + .take() + .expect("element items") + .get_items_reader()?; + let num_elements = reader.get_count() as usize; + if num_elements > MAX_WASM_TABLE_ENTRIES { + return Err(BinaryReaderError { + message: "num_elements is out of bounds", + offset: 0, // reader.position - 1, // TODO offset + }); + } + let mut elements = Vec::with_capacity(num_elements); + for _ in 0..num_elements { + elements.push(reader.read()?); + } + self.state = ParserState::ElementSectionEntryBody(elements.into_boxed_slice()); + Ok(()) + } + + fn read_function_body(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + self.current_function_body = None; + return self.check_section_end(); + } + let function_body = section_reader!(self, CodeSectionReader).read()?; + let range = function_body.range(); + self.state = ParserState::BeginFunctionBody { range }; + self.current_function_body = Some(function_body); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_body_locals(&mut self) -> Result<()> { + let function_body = self.current_function_body.as_mut().expect("function body"); + let mut reader = function_body.get_locals_reader()?; + let local_count = reader.get_count() as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "local_count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count); + let mut locals_total: usize = 0; + for _ in 0..local_count { + let (count, ty) = reader.read()?; + locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + })?; + if locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + }); + } + locals.push((count, ty)); + } + self.operators_reader = Some(function_body.get_operators_reader()?); + self.state = ParserState::FunctionBodyLocals { + locals: locals.into_boxed_slice(), + }; + Ok(()) + } + + fn read_code_operator(&mut self) -> Result<()> { + if self + .operators_reader + .as_ref() + .expect("operator reader") + .eof() + { + if let ParserState::CodeOperator(Operator::End) = self.state { + self.state = ParserState::EndFunctionBody; + self.operators_reader = None; + self.current_function_body = None; + return Ok(()); + } + let reader = self.operators_reader.as_ref().expect("operator reader"); + return Err(BinaryReaderError { + message: "Expected end of function marker", + offset: reader.original_position(), + }); + } + let reader = self.operators_reader.as_mut().expect("operator reader"); + let op = reader.read()?; + self.state = ParserState::CodeOperator(op); + Ok(()) + } + + fn read_table_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let table_entry = section_reader!(self, TableSectionReader).read()?; + self.state = ParserState::TableSectionEntry(table_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Data { kind, data } = section_reader!(self, DataSectionReader).read()?; + match kind { + DataKind::Passive => { + self.state = ParserState::BeginPassiveDataSectionEntry; + } + DataKind::Active { + memory_index, + init_expr, + } => { + self.state = ParserState::BeginActiveDataSectionEntry(memory_index); + self.operators_reader = Some(init_expr.get_operators_reader()); + } + } + self.current_data_segment = Some(data); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry_body(&mut self) -> Result<()> { + let size = self.current_data_segment.expect("data entry").len(); + self.state = ParserState::BeginDataSectionEntryBody(size as u32); + Ok(()) + } + + fn read_naming<'b>( + mut naming_reader: NamingReader<'a>, + limit: usize, + ) -> Result<Box<[Naming<'b>]>> + where + 'a: 'b, + { + let count = naming_reader.get_count() as usize; + if count > limit { + return Err(BinaryReaderError { + message: "name map size is out of bound", + offset: naming_reader.original_position() - 1, + }); + } + let mut result = Vec::with_capacity(count); + for _ in 0..count { + result.push(naming_reader.read()?); + } + Ok(result.into_boxed_slice()) + } + + fn read_name_entry(&mut self) -> Result<()> { + if section_reader!(self, NameSectionReader).eof() { + return self.position_to_section_end(); + } + let entry = match section_reader!(self, NameSectionReader).read()? { + Name::Module(name) => NameEntry::Module(name.get_name()?), + Name::Function(func) => { + NameEntry::Function(Self::read_naming(func.get_map()?, MAX_WASM_FUNCTIONS)?) + } + Name::Local(locals) => { + let mut reader = locals.get_function_local_reader()?; + let funcs_len = reader.get_count() as usize; + if funcs_len > MAX_WASM_FUNCTIONS { + return Err(BinaryReaderError { + message: "function count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len); + for _ in 0..funcs_len { + let func = reader.read()?; + funcs.push(LocalName { + index: func.func_index, + locals: Self::read_naming(func.get_map()?, MAX_WASM_FUNCTION_LOCALS)?, + }); + } + NameEntry::Local(funcs.into_boxed_slice()) + } + }; + self.state = ParserState::NameSectionEntry(entry); + Ok(()) + } + + fn read_source_mapping(&mut self) -> Result<()> { + let url = self + .current_section + .as_ref() + .expect("section") + .get_sourcemappingurl_section_content()?; + self.state = ParserState::SourceMappingURL(url); + Ok(()) + } + + // See https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md + fn read_reloc_header(&mut self) -> Result<()> { + let section_code = section_reader!(self, RelocSectionReader).get_section_code(); + self.state = ParserState::RelocSectionHeader(section_code); + Ok(()) + } + + fn read_reloc_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Reloc { + ty, + offset, + index, + addend, + } = section_reader!(self, RelocSectionReader).read()?; + self.state = ParserState::RelocSectionEntry(RelocEntry { + ty, + offset, + index, + addend, + }); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_linking_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let entry = section_reader!(self, LinkingSectionReader).read()?; + self.state = ParserState::LinkingSectionEntry(entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::BeginSection { + code: SectionCode::Type, + .. + } => { + start_section_reader!(self, TypeSectionReader, get_type_section_reader); + self.read_type_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Import, + .. + } => { + start_section_reader!(self, ImportSectionReader, get_import_section_reader); + self.read_import_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Function, + .. + } => { + start_section_reader!(self, FunctionSectionReader, get_function_section_reader); + self.read_function_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Memory, + .. + } => { + start_section_reader!(self, MemorySectionReader, get_memory_section_reader); + self.read_memory_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Global, + .. + } => { + start_section_reader!(self, GlobalSectionReader, get_global_section_reader); + self.read_global_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Export, + .. + } => { + start_section_reader!(self, ExportSectionReader, get_export_section_reader); + self.read_export_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Element, + .. + } => { + start_section_reader!(self, ElementSectionReader, get_element_section_reader); + self.read_element_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Code, + .. + } => { + start_section_reader!(self, CodeSectionReader, get_code_section_reader); + self.read_function_body()?; + } + ParserState::BeginSection { + code: SectionCode::Table, + .. + } => { + start_section_reader!(self, TableSectionReader, get_table_section_reader); + self.read_table_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Data, + .. + } => { + start_section_reader!(self, DataSectionReader, get_data_section_reader); + self.read_data_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Start, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_start_section_content()?; + self.state = ParserState::StartSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::DataCount, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_data_count_section_content()?; + self.state = ParserState::DataCountSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::Custom { .. }, + .. + } => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn create_custom_section_binary_reader(&mut self) { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.binary_reader = Some(reader); + } + + fn read_custom_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::ReadingCustomSection(CustomSectionKind::Name) => { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_name_section_reader()?; + self.section_reader = ParserSectionReader::NameSectionReader(reader); + self.read_name_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::SourceMappingURL) => { + self.read_source_mapping()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Reloc) => { + start_section_reader!(self, RelocSectionReader, get_reloc_section_reader); + self.read_reloc_header()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Linking) => { + start_section_reader!(self, LinkingSectionReader, get_linking_section_reader); + self.read_linking_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Producers) + | ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn position_to_section_end(&mut self) -> Result<()> { + self.current_section = None; + self.binary_reader = None; + self.state = ParserState::EndSection; + Ok(()) + } + + fn check_section_end(&mut self) -> Result<()> { + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::DataSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ElementSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ExportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::FunctionSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::GlobalSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ImportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::MemorySectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TableSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TypeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::LinkingSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::RelocSectionReader(ref reader) => reader.ensure_end()?, + _ => unreachable!(), + } + self.position_to_section_end() + } + + fn read_section_body_bytes(&mut self) -> Result<()> { + if self.binary_reader.as_ref().expect("binary reader").eof() { + self.state = ParserState::EndSection; + self.binary_reader = None; + return Ok(()); + } + let binary_reader = self.binary_reader.as_mut().expect("binary reader"); + let to_read = if binary_reader.buffer.len() - binary_reader.position < MAX_DATA_CHUNK_SIZE { + binary_reader.buffer.len() - binary_reader.position + } else { + MAX_DATA_CHUNK_SIZE + }; + let bytes = binary_reader.read_bytes(to_read)?; + self.state = ParserState::SectionRawData(bytes); + Ok(()) + } + + fn read_data_chunk(&mut self) -> Result<()> { + let data = self.current_data_segment.expect("data"); + if data.is_empty() { + self.state = ParserState::EndDataSectionEntryBody; + self.current_data_segment = None; + return Ok(()); + } + let to_read = if data.len() > MAX_DATA_CHUNK_SIZE { + MAX_DATA_CHUNK_SIZE + } else { + data.len() + }; + let (head, tail) = data.split_at(to_read); + self.current_data_segment = Some(tail); + self.state = ParserState::DataSectionEntryBodyChunk(head); + Ok(()) + } + + fn read_next_section(&mut self) -> Result<()> { + if self.module_reader.as_ref().expect("module_reader").eof() { + self.current_section = None; + self.state = ParserState::EndWasm; + } else { + self.read_section_header()?; + } + Ok(()) + } + + fn read_wrapped(&mut self) -> Result<()> { + match self.state { + ParserState::EndWasm => panic!("Parser in end state"), + ParserState::Error(_) => panic!("Parser in error state"), + ParserState::Initial => self.read_module()?, + ParserState::BeginWasm { .. } | ParserState::EndSection => self.read_next_section()?, + ParserState::BeginSection { .. } => self.read_section_body()?, + ParserState::SkippingSection => { + self.position_to_section_end()?; + self.read_next_section()?; + } + ParserState::TypeSectionEntry(_) => self.read_type_entry()?, + ParserState::ImportSectionEntry { .. } => self.read_import_entry()?, + ParserState::FunctionSectionEntry(_) => self.read_function_entry()?, + ParserState::MemorySectionEntry(_) => self.read_memory_entry()?, + ParserState::TableSectionEntry(_) => self.read_table_entry()?, + ParserState::ExportSectionEntry { .. } => self.read_export_entry()?, + ParserState::BeginGlobalSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Global) + } + ParserState::EndGlobalSectionEntry => self.read_global_entry()?, + ParserState::BeginElementSectionEntry { + table: ElemSectionEntryTable::Active(_), + .. + } => self.read_init_expression_body(InitExpressionContinuationSection::Element), + ParserState::BeginElementSectionEntry { .. } => self.read_element_entry_body()?, + ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => { + self.read_init_expression_operator()? + } + ParserState::BeginPassiveDataSectionEntry => self.read_data_entry_body()?, + ParserState::BeginActiveDataSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Data) + } + ParserState::EndInitExpressionBody => { + match self.init_expr_continuation { + Some(InitExpressionContinuationSection::Global) => { + self.state = ParserState::EndGlobalSectionEntry + } + Some(InitExpressionContinuationSection::Element) => { + self.read_element_entry_body()? + } + Some(InitExpressionContinuationSection::Data) => self.read_data_entry_body()?, + None => unreachable!(), + } + self.init_expr_continuation = None; + } + ParserState::BeginFunctionBody { .. } => self.read_function_body_locals()?, + ParserState::FunctionBodyLocals { .. } | ParserState::CodeOperator(_) => { + self.read_code_operator()? + } + ParserState::EndFunctionBody => self.read_function_body()?, + ParserState::SkippingFunctionBody => { + self.current_function_body = None; + self.read_function_body()?; + } + ParserState::EndDataSectionEntry => self.read_data_entry()?, + ParserState::BeginDataSectionEntryBody(_) + | ParserState::DataSectionEntryBodyChunk(_) => self.read_data_chunk()?, + ParserState::EndDataSectionEntryBody => { + self.state = ParserState::EndDataSectionEntry; + } + ParserState::ElementSectionEntryBody(_) => { + self.state = ParserState::EndElementSectionEntry; + } + ParserState::EndElementSectionEntry => self.read_element_entry()?, + ParserState::StartSectionEntry(_) => self.position_to_section_end()?, + ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?, + ParserState::NameSectionEntry(_) => self.read_name_entry()?, + ParserState::SourceMappingURL(_) => self.position_to_section_end()?, + ParserState::RelocSectionHeader(_) => { + let mut reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.section_entries_left = reader.read_var_u32()?; + self.binary_reader = Some(reader); + self.read_reloc_entry()?; + } + ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?, + ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?, + ParserState::ReadingCustomSection(_) => self.read_custom_section_body()?, + ParserState::ReadingSectionRawData | ParserState::SectionRawData(_) => { + self.read_section_body_bytes()? + } + } + Ok(()) + } + + fn skip_section(&mut self) { + match self.state { + ParserState::Initial + | ParserState::EndWasm + | ParserState::Error(_) + | ParserState::BeginWasm { .. } + | ParserState::EndSection => panic!("Invalid reader state during skip section"), + _ => self.state = ParserState::SkippingSection, + } + } + + fn skip_function_body(&mut self) { + match self.state { + ParserState::BeginFunctionBody { .. } + | ParserState::FunctionBodyLocals { .. } + | ParserState::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody, + _ => panic!("Invalid reader state during skip function body"), + } + } + + fn read_custom_section(&mut self) { + match self.state { + ParserState::BeginSection { + code: SectionCode::Custom { kind, .. }, + .. + } => { + self.state = ParserState::ReadingCustomSection(kind); + } + _ => panic!("Invalid reader state during reading custom section"), + } + } + + fn read_raw_section_data(&mut self) { + match self.state { + ParserState::BeginSection { .. } => { + self.binary_reader = Some( + self.current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ); + self.state = ParserState::ReadingSectionRawData; + } + _ => panic!("Invalid reader state during reading raw section data"), + } + } +} + +impl<'a> WasmDecoder<'a> for Parser<'a> { + /// Reads next record from the WebAssembly binary data. The methods returns + /// reference to current state of the parser. See `ParserState` num. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// { + /// let state = parser.read(); + /// println!("First state {:?}", state); + /// } + /// { + /// let state = parser.read(); + /// println!("Second state {:?}", state); + /// } + /// ``` + fn read(&mut self) -> &ParserState<'a> { + let result = self.read_wrapped(); + if result.is_err() { + self.state = ParserState::Error(result.err().unwrap()); + } + &self.state + } + + fn push_input(&mut self, input: ParserInput) { + match input { + ParserInput::Default => (), + ParserInput::SkipSection => self.skip_section(), + ParserInput::SkipFunctionBody => self.skip_function_body(), + ParserInput::ReadCustomSection => self.read_custom_section(), + ParserInput::ReadSectionRawData => self.read_raw_section_data(), + } + } + + /// Creates a BinaryReader when current state is ParserState::BeginSection + /// or ParserState::BeginFunctionBody. + /// + /// # Examples + /// ``` + /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84, + /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80, + /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0, + /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb]; + /// use wasmparser::{WasmDecoder, Parser, ParserState}; + /// let mut parser = Parser::new(data); + /// let mut types = Vec::new(); + /// let mut function_types = Vec::new(); + /// let mut function_readers = Vec::new(); + /// loop { + /// match parser.read() { + /// ParserState::Error(_) | + /// ParserState::EndWasm => break, + /// ParserState::TypeSectionEntry(ty) => { + /// types.push(ty.clone()); + /// } + /// ParserState::FunctionSectionEntry(id) => { + /// function_types.push(id.clone()); + /// } + /// ParserState::BeginFunctionBody {..} => { + /// let reader = parser.create_binary_reader(); + /// function_readers.push(reader); + /// } + /// _ => continue + /// } + /// } + /// for (i, reader) in function_readers.iter_mut().enumerate() { + /// // Access the function type through the types table. + /// let ty = &types[function_types[i] as usize]; + /// println!("\nFunction {} of type {:?}", i, ty); + /// // Read the local declarations required by the function body. + /// let local_decls_len = reader.read_local_count().unwrap(); + /// let mut local_decls = Vec::with_capacity(local_decls_len); + /// let mut local_count = ty.params.len(); + /// for _ in 0..local_decls_len { + /// let local_decl = reader.read_local_decl(&mut local_count).unwrap(); + /// local_decls.push(local_decl); + /// } + /// println!("Function locals: vars {:?}; total {} ", local_decls, local_count); + /// // Read the operations of the function body. + /// while let Ok(ref op) = reader.read_operator() { + /// println!(" {:?}", op); + /// } + /// } + /// ``` + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b, + { + match self.state { + ParserState::BeginSection { .. } => self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ParserState::BeginFunctionBody { .. } | ParserState::FunctionBodyLocals { .. } => self + .current_function_body + .as_ref() + .expect("function body") + .get_binary_reader(), + _ => panic!("Invalid reader state during get binary reader operation"), + } + } + + /// Reads next record from the WebAssembly binary data. It also allows to + /// control how parser will treat the next record(s). The method accepts the + /// `ParserInput` parameter that allows e.g. to skip section or function + /// operators. The methods returns reference to current state of the parser. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// let mut next_input = wasmparser::ParserInput::Default; + /// loop { + /// let state = parser.read_with_input(next_input); + /// match *state { + /// wasmparser::ParserState::EndWasm => break, + /// wasmparser::ParserState::BeginWasm { .. } | + /// wasmparser::ParserState::EndSection => + /// next_input = wasmparser::ParserInput::Default, + /// wasmparser::ParserState::BeginSection { ref code, .. } => { + /// println!("Found section: {:?}", code); + /// next_input = wasmparser::ParserInput::SkipSection; + /// }, + /// _ => unreachable!() + /// } + /// } + /// ``` + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> { + self.push_input(input); + self.read() + } + + fn last_state(&self) -> &ParserState<'a> { + &self.state + } +} |