use std::result;
use limits::{MAX_WASM_FUNCTION_LOCALS, MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS,
MAX_WASM_FUNCTION_SIZE, MAX_WASM_STRING_SIZE, MAX_WASM_FUNCTIONS,
MAX_WASM_TABLE_ENTRIES};
const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
#[derive(Debug,Copy,Clone)]
pub struct BinaryReaderError {
pub message: &'static str,
pub offset: usize,
}
pub type Result<T> = result::Result<T, BinaryReaderError>;
#[derive(Debug,Copy,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum CustomSectionKind {
Unknown,
Name,
SourceMappingURL,
Reloc,
Linking,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum SectionCode<'a> {
Custom {
name: &'a [u8],
kind: CustomSectionKind,
},
Type, Import, Function, Table, Memory, Global, Export, Start, Element, Code, Data, }
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum Type {
I32,
I64,
F32,
F64,
AnyFunc,
Func,
EmptyBlockType,
}
#[derive(Debug)]
pub enum NameType {
Module,
Function,
Local,
}
#[derive(Debug)]
pub struct Naming<'a> {
pub index: u32,
pub name: &'a [u8],
}
#[derive(Debug)]
pub struct LocalName<'a> {
pub index: u32,
pub locals: Vec<Naming<'a>>,
}
#[derive(Debug)]
pub enum NameEntry<'a> {
Module(&'a [u8]),
Function(Vec<Naming<'a>>),
Local(Vec<LocalName<'a>>),
}
#[derive(Debug, Copy, Clone)]
pub enum ExternalKind {
Function,
Table,
Memory,
Global,
}
#[derive(Debug,Clone)]
pub struct FuncType {
pub form: Type,
pub params: Vec<Type>,
pub returns: Vec<Type>,
}
#[derive(Debug,Copy,Clone)]
pub struct ResizableLimits {
pub flags: u32,
pub initial: u32,
pub maximum: Option<u32>,
}
#[derive(Debug,Copy,Clone)]
pub struct TableType {
pub element_type: Type,
pub limits: ResizableLimits,
}
#[derive(Debug,Copy,Clone)]
pub struct MemoryType {
pub limits: ResizableLimits,
}
#[derive(Debug,Copy,Clone)]
pub struct GlobalType {
pub content_type: Type,
pub mutability: u32,
}
#[derive(Debug)]
pub struct MemoryImmediate {
pub flags: u32,
pub offset: u32,
}
#[derive(Debug)]
pub struct BrTable<'a> {
pub size: usize,
buffer: &'a [u8],
}
impl<'a> BrTable<'a> {
pub fn read_table(&self) -> (Vec<u32>, u32) {
let mut reader = BinaryReader::new(self.buffer);
let mut table = Vec::with_capacity(self.size);
for _ in 0..self.size {
table.push(reader.read_var_u32().unwrap());
}
let default_target = reader.read_var_u32().unwrap();
assert!(reader.eof());
(table, default_target)
}
}
pub struct BrTableIterator<'a> {
reader: BinaryReader<'a>,
left: usize,
}
impl<'a> IntoIterator for &'a BrTable<'a> {
type Item = u32;
type IntoIter = BrTableIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
BrTableIterator {
reader: BinaryReader::new(self.buffer),
left: self.size + 1,
}
}
}
impl<'a> Iterator for BrTableIterator<'a> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.left == 0 {
return None;
}
self.left -= 1;
Some(self.reader.read_var_u32().unwrap())
}
}
#[derive(Debug)]
pub enum ImportSectionEntryType {
Function(u32),
Table(TableType),
Memory(MemoryType),
Global(GlobalType),
}
#[derive(Debug)]
pub enum RelocType {
FunctionIndexLEB,
TableIndexSLEB,
TableIndexI32,
GlobalAddrLEB,
GlobalAddrSLEB,
GlobalAddrI32,
TypeIndexLEB,
GlobalIndexLEB,
}
#[derive(Debug)]
pub enum LinkingType {
StackPointer(u32),
}
#[derive(Debug)]
pub struct RelocEntry {
pub ty: RelocType,
pub offset: u32,
pub index: u32,
pub addend: Option<u32>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Ieee32(u32);
impl Ieee32 {
pub fn bits(&self) -> u32 {
self.0
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Ieee64(u64);
impl Ieee64 {
pub fn bits(&self) -> u64 {
self.0
}
}
#[derive(Debug)]
pub enum Operator<'a> {
Unreachable,
Nop,
Block { ty: Type },
Loop { ty: Type },
If { ty: Type },
Else,
End,
Br { relative_depth: u32 },
BrIf { relative_depth: u32 },
BrTable { table: BrTable<'a> },
Return,
Call { function_index: u32 },
CallIndirect { index: u32, table_index: u32 },
Drop,
Select,
GetLocal { local_index: u32 },
SetLocal { local_index: u32 },
TeeLocal { local_index: u32 },
GetGlobal { global_index: u32 },
SetGlobal { global_index: u32 },
I32Load { memory_immediate: MemoryImmediate },
I64Load { memory_immediate: MemoryImmediate },
F32Load { memory_immediate: MemoryImmediate },
F64Load { memory_immediate: MemoryImmediate },
I32Load8S { memory_immediate: MemoryImmediate },
I32Load8U { memory_immediate: MemoryImmediate },
I32Load16S { memory_immediate: MemoryImmediate },
I32Load16U { memory_immediate: MemoryImmediate },
I64Load8S { memory_immediate: MemoryImmediate },
I64Load8U { memory_immediate: MemoryImmediate },
I64Load16S { memory_immediate: MemoryImmediate },
I64Load16U { memory_immediate: MemoryImmediate },
I64Load32S { memory_immediate: MemoryImmediate },
I64Load32U { memory_immediate: MemoryImmediate },
I32Store { memory_immediate: MemoryImmediate },
I64Store { memory_immediate: MemoryImmediate },
F32Store { memory_immediate: MemoryImmediate },
F64Store { memory_immediate: MemoryImmediate },
I32Store8 { memory_immediate: MemoryImmediate },
I32Store16 { memory_immediate: MemoryImmediate },
I64Store8 { memory_immediate: MemoryImmediate },
I64Store16 { memory_immediate: MemoryImmediate },
I64Store32 { memory_immediate: MemoryImmediate },
CurrentMemory { reserved: u32 },
GrowMemory { reserved: u32 },
I32Const { value: i32 },
I64Const { value: i64 },
F32Const { value: Ieee32 },
F64Const { value: Ieee64 },
I32Eqz,
I32Eq,
I32Ne,
I32LtS,
I32LtU,
I32GtS,
I32GtU,
I32LeS,
I32LeU,
I32GeS,
I32GeU,
I64Eqz,
I64Eq,
I64Ne,
I64LtS,
I64LtU,
I64GtS,
I64GtU,
I64LeS,
I64LeU,
I64GeS,
I64GeU,
F32Eq,
F32Ne,
F32Lt,
F32Gt,
F32Le,
F32Ge,
F64Eq,
F64Ne,
F64Lt,
F64Gt,
F64Le,
F64Ge,
I32Clz,
I32Ctz,
I32Popcnt,
I32Add,
I32Sub,
I32Mul,
I32DivS,
I32DivU,
I32RemS,
I32RemU,
I32And,
I32Or,
I32Xor,
I32Shl,
I32ShrS,
I32ShrU,
I32Rotl,
I32Rotr,
I64Clz,
I64Ctz,
I64Popcnt,
I64Add,
I64Sub,
I64Mul,
I64DivS,
I64DivU,
I64RemS,
I64RemU,
I64And,
I64Or,
I64Xor,
I64Shl,
I64ShrS,
I64ShrU,
I64Rotl,
I64Rotr,
F32Abs,
F32Neg,
F32Ceil,
F32Floor,
F32Trunc,
F32Nearest,
F32Sqrt,
F32Add,
F32Sub,
F32Mul,
F32Div,
F32Min,
F32Max,
F32Copysign,
F64Abs,
F64Neg,
F64Ceil,
F64Floor,
F64Trunc,
F64Nearest,
F64Sqrt,
F64Add,
F64Sub,
F64Mul,
F64Div,
F64Min,
F64Max,
F64Copysign,
I32WrapI64,
I32TruncSF32,
I32TruncUF32,
I32TruncSF64,
I32TruncUF64,
I64ExtendSI32,
I64ExtendUI32,
I64TruncSF32,
I64TruncUF32,
I64TruncSF64,
I64TruncUF64,
F32ConvertSI32,
F32ConvertUI32,
F32ConvertSI64,
F32ConvertUI64,
F32DemoteF64,
F64ConvertSI32,
F64ConvertUI32,
F64ConvertSI64,
F64ConvertUI64,
F64PromoteF32,
I32ReinterpretF32,
I64ReinterpretF64,
F32ReinterpretI32,
F64ReinterpretI64,
}
fn is_name(name: &[u8], expected: &'static str) -> bool {
if name.len() != expected.len() {
return false;
}
let expected_bytes = expected.as_bytes();
for i in 0..name.len() {
if name[i] != expected_bytes[i] {
return false;
}
}
true
}
fn is_name_prefix(name: &[u8], prefix: &'static str) -> bool {
if name.len() < prefix.len() {
return false;
}
let expected_bytes = prefix.as_bytes();
for i in 0..expected_bytes.len() {
if name[i] != expected_bytes[i] {
return false;
}
}
true
}
enum InitExpressionContinuation {
GlobalSection,
ElementSection,
DataSection,
}
pub struct BinaryReader<'a> {
buffer: &'a [u8],
position: usize,
end: usize,
}
impl<'a> BinaryReader<'a> {
pub fn new(data: &[u8]) -> BinaryReader {
BinaryReader {
buffer: data,
position: 0,
end: data.len(),
}
}
fn ensure_has_bytes(&self, len: usize) -> Result<()> {
if self.position + len <= self.end {
Ok(())
} else {
Err(BinaryReaderError {
message: "Unexpected EOF",
offset: self.position,
})
}
}
fn read_bytes_till(&mut self, pos: usize) -> Result<&'a [u8]> {
if self.position > pos {
return Err(BinaryReaderError {
message: "Read position advanced more than needed",
offset: pos,
});
}
let size = pos - self.position;
self.read_bytes(size)
}
fn read_var_u1(&mut self) -> Result<u32> {
let b = self.read_u8()?;
if (b & 0xFE) != 0 {
return Err(BinaryReaderError {
message: "Invalid var_u1",
offset: self.position - 1,
});
}
Ok(b)
}
fn read_var_i7(&mut self) -> Result<i32> {
let b = self.read_u8()?;
if (b & 0x80) != 0 {
return Err(BinaryReaderError {
message: "Invalid var_i7",
offset: self.position - 1,
});
}
Ok((b << 25) as i32 >> 25)
}
fn read_var_u7(&mut self) -> Result<u32> {
let b = self.read_u8()?;
if (b & 0x80) != 0 {
return Err(BinaryReaderError {
message: "Invalid var_u7",
offset: self.position - 1,
});
}
Ok(b)
}
fn read_type(&mut self) -> Result<Type> {
let code = self.read_var_i7()?;
match code {
-0x01 => Ok(Type::I32),
-0x02 => Ok(Type::I64),
-0x03 => Ok(Type::F32),
-0x04 => Ok(Type::F64),
-0x10 => Ok(Type::AnyFunc),
-0x20 => Ok(Type::Func),
-0x40 => Ok(Type::EmptyBlockType),
_ => {
Err(BinaryReaderError {
message: "Invalid type",
offset: self.position - 1,
})
}
}
}
fn read_external_kind(&mut self) -> Result<ExternalKind> {
let code = self.read_u8()?;
match code {
0 => Ok(ExternalKind::Function),
1 => Ok(ExternalKind::Table),
2 => Ok(ExternalKind::Memory),
3 => Ok(ExternalKind::Global),
_ => {
Err(BinaryReaderError {
message: "Invalid external kind",
offset: self.position - 1,
})
}
}
}
fn read_func_type(&mut self) -> Result<FuncType> {
let form = self.read_type()?;
let params_len = self.read_var_u32()? as usize;
if params_len > MAX_WASM_FUNCTION_PARAMS {
return Err(BinaryReaderError {
message: "function params size is out of bound",
offset: self.position - 1,
});
}
let mut params: Vec<Type> = Vec::with_capacity(params_len);
for _ in 0..params_len {
params.push(self.read_type()?);
}
let returns_len = self.read_var_u32()? as usize;
if returns_len > MAX_WASM_FUNCTION_RETURNS {
return Err(BinaryReaderError {
message: "function params size is out of bound",
offset: self.position - 1,
});
}
let mut returns: Vec<Type> = Vec::with_capacity(returns_len);
for _ in 0..returns_len {
returns.push(self.read_type()?);
}
Ok(FuncType {
form: form,
params: params,
returns: returns,
})
}
fn read_resizable_limits(&mut self) -> Result<ResizableLimits> {
let flags = self.read_var_u32()?;
let initial = self.read_var_u32()?;
let maximum = if (flags & 0x1) != 0 {
Some(self.read_var_u32()?)
} else {
None
};
Ok(ResizableLimits {
flags: flags,
initial: initial,
maximum: maximum,
})
}
fn read_table_type(&mut self) -> Result<TableType> {
Ok(TableType {
element_type: self.read_type()?,
limits: self.read_resizable_limits()?,
})
}
fn read_memory_type(&mut self) -> Result<MemoryType> {
Ok(MemoryType { limits: self.read_resizable_limits()? })
}
fn read_global_type(&mut self) -> Result<GlobalType> {
Ok(GlobalType {
content_type: self.read_type()?,
mutability: self.read_var_u1()?,
})
}
fn read_memory_immediate(&mut self) -> Result<MemoryImmediate> {
Ok(MemoryImmediate {
flags: self.read_var_u32()?,
offset: self.read_var_u32()?,
})
}
fn read_section_code(&mut self, id: u32, offset: usize) -> Result<SectionCode<'a>> {
match id {
0 => {
let name = self.read_string()?;
let kind = if is_name(name, "name") {
CustomSectionKind::Name
} else if is_name(name, "sourceMappingURL") {
CustomSectionKind::SourceMappingURL
} else if is_name_prefix(name, "reloc.") {
CustomSectionKind::Reloc
} else if is_name(name, "linking") {
CustomSectionKind::Linking
} else {
CustomSectionKind::Unknown
};
Ok(SectionCode::Custom {
name: name,
kind: kind,
})
}
1 => Ok(SectionCode::Type),
2 => Ok(SectionCode::Import),
3 => Ok(SectionCode::Function),
4 => Ok(SectionCode::Table),
5 => Ok(SectionCode::Memory),
6 => Ok(SectionCode::Global),
7 => Ok(SectionCode::Export),
8 => Ok(SectionCode::Start),
9 => Ok(SectionCode::Element),
10 => Ok(SectionCode::Code),
11 => Ok(SectionCode::Data),
_ => {
Err(BinaryReaderError {
message: "Invalid section code",
offset,
})
}
}
}
fn read_br_table(&mut self) -> Result<BrTable<'a>> {
let targets_len = self.read_var_u32()? as usize;
if targets_len > MAX_WASM_BR_TABLE_SIZE {
return Err(BinaryReaderError {
message: "br_table size is out of bound",
offset: self.position - 1,
});
}
let start = self.position;
for _ in 0..targets_len {
self.skip_var_32()?;
}
self.skip_var_32()?;
Ok(BrTable {
size: targets_len,
buffer: &self.buffer[start..self.position],
})
}
fn read_name_map(&mut self, limit: usize) -> Result<Vec<Naming<'a>>> {
let count = self.read_var_u32()? as usize;
if count > limit {
return Err(BinaryReaderError {
message: "name map size is out of bound",
offset: self.position - 1,
});
}
let mut result = Vec::with_capacity(count);
for _ in 0..count {
let index = self.read_var_u32()?;
let name = self.read_string()?;
result.push(Naming {
index: index,
name: name,
});
}
Ok(result)
}
pub fn eof(&self) -> bool {
self.position >= self.end
}
pub fn current_position(&self) -> usize {
self.position
}
pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
self.ensure_has_bytes(size)?;
let start = self.position;
self.position += size;
Ok(&self.buffer[start..self.position])
}
pub fn read_u32(&mut self) -> Result<u32> {
self.ensure_has_bytes(4)?;
let b1 = self.buffer[self.position] as u32;
let b2 = self.buffer[self.position + 1] as u32;
let b3 = self.buffer[self.position + 2] as u32;
let b4 = self.buffer[self.position + 3] as u32;
self.position += 4;
Ok(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24))
}
pub fn read_u64(&mut self) -> Result<u64> {
let w1 = self.read_u32()? as u64;
let w2 = self.read_u32()? as u64;
Ok(w1 | (w2 << 32))
}
pub fn read_u8(&mut self) -> Result<u32> {
self.ensure_has_bytes(1)?;
let b = self.buffer[self.position] as u32;
self.position += 1;
Ok(b)
}
pub fn read_var_u32(&mut self) -> Result<u32> {
let mut result = 0;
let mut shift = 0;
loop {
let byte = self.read_u8()?;
result |= ((byte & 0x7F) as u32) << shift;
shift += 7;
if (byte & 0x80) == 0 {
break;
}
if shift >= 32 {
return Err(BinaryReaderError {
message: "Invalid var_u32",
offset: self.position - 1,
});
}
}
Ok(result)
}
pub fn skip_var_32(&mut self) -> Result<()> {
for _ in 0..5 {
let byte = self.read_u8()?;
if (byte & 0x80) == 0 {
return Ok(());
}
}
Err(BinaryReaderError {
message: "Invalid var_32",
offset: self.position - 1,
})
}
pub fn read_var_i32(&mut self) -> Result<i32> {
let mut result: i32 = 0;
let mut shift = 0;
loop {
let byte = self.read_u8()?;
result |= ((byte & 0x7F) as i32) << shift;
shift += 7;
if (byte & 0x80) == 0 {
break;
}
if shift >= 32 {
return Err(BinaryReaderError {
message: "Invalid var_i32",
offset: self.position,
});
}
}
if shift >= 32 {
return Ok(result);
}
let ashift = 32 - shift;
Ok((result << ashift) >> ashift)
}
pub fn read_var_i64(&mut self) -> Result<i64> {
let mut result: i64 = 0;
let mut shift = 0;
loop {
let byte = self.read_u8()?;
result |= ((byte & 0x7F) as i64) << shift;
shift += 7;
if (byte & 0x80) == 0 {
break;
}
if shift >= 64 {
return Err(BinaryReaderError {
message: "Invalid var_i64",
offset: self.position - 1,
});
}
}
if shift >= 64 {
return Ok(result);
}
let ashift = 64 - shift;
Ok((result << ashift) >> ashift)
}
pub fn read_f32(&mut self) -> Result<Ieee32> {
let value = self.read_u32()?;
Ok(Ieee32(value))
}
pub fn read_f64(&mut self) -> Result<Ieee64> {
let value = self.read_u64()?;
Ok(Ieee64(value))
}
pub fn read_string(&mut self) -> Result<&'a [u8]> {
let len = self.read_var_u32()? as usize;
if len > MAX_WASM_STRING_SIZE {
return Err(BinaryReaderError {
message: "string size in out of bounds",
offset: self.position - 1,
});
}
self.read_bytes(len)
}
pub fn read_operator(&mut self) -> Result<Operator<'a>> {
let code = self.read_u8()?;
Ok(match code {
0x00 => Operator::Unreachable,
0x01 => Operator::Nop,
0x02 => Operator::Block { ty: self.read_type()? },
0x03 => Operator::Loop { ty: self.read_type()? },
0x04 => Operator::If { ty: self.read_type()? },
0x05 => Operator::Else,
0x0b => Operator::End,
0x0c => Operator::Br { relative_depth: self.read_var_u32()? },
0x0d => Operator::BrIf { relative_depth: self.read_var_u32()? },
0x0e => Operator::BrTable { table: self.read_br_table()? },
0x0f => Operator::Return,
0x10 => Operator::Call { function_index: self.read_var_u32()? },
0x11 => {
Operator::CallIndirect {
index: self.read_var_u32()?,
table_index: self.read_var_u1()?,
}
}
0x1a => Operator::Drop,
0x1b => Operator::Select,
0x20 => Operator::GetLocal { local_index: self.read_var_u32()? },
0x21 => Operator::SetLocal { local_index: self.read_var_u32()? },
0x22 => Operator::TeeLocal { local_index: self.read_var_u32()? },
0x23 => Operator::GetGlobal { global_index: self.read_var_u32()? },
0x24 => Operator::SetGlobal { global_index: self.read_var_u32()? },
0x28 => Operator::I32Load { memory_immediate: self.read_memory_immediate()? },
0x29 => Operator::I64Load { memory_immediate: self.read_memory_immediate()? },
0x2a => Operator::F32Load { memory_immediate: self.read_memory_immediate()? },
0x2b => Operator::F64Load { memory_immediate: self.read_memory_immediate()? },
0x2c => Operator::I32Load8S { memory_immediate: self.read_memory_immediate()? },
0x2d => Operator::I32Load8U { memory_immediate: self.read_memory_immediate()? },
0x2e => Operator::I32Load16S { memory_immediate: self.read_memory_immediate()? },
0x2f => Operator::I32Load16U { memory_immediate: self.read_memory_immediate()? },
0x30 => Operator::I64Load8S { memory_immediate: self.read_memory_immediate()? },
0x31 => Operator::I64Load8U { memory_immediate: self.read_memory_immediate()? },
0x32 => Operator::I64Load16S { memory_immediate: self.read_memory_immediate()? },
0x33 => Operator::I64Load16U { memory_immediate: self.read_memory_immediate()? },
0x34 => Operator::I64Load32S { memory_immediate: self.read_memory_immediate()? },
0x35 => Operator::I64Load32U { memory_immediate: self.read_memory_immediate()? },
0x36 => Operator::I32Store { memory_immediate: self.read_memory_immediate()? },
0x37 => Operator::I64Store { memory_immediate: self.read_memory_immediate()? },
0x38 => Operator::F32Store { memory_immediate: self.read_memory_immediate()? },
0x39 => Operator::F64Store { memory_immediate: self.read_memory_immediate()? },
0x3a => Operator::I32Store8 { memory_immediate: self.read_memory_immediate()? },
0x3b => Operator::I32Store16 { memory_immediate: self.read_memory_immediate()? },
0x3c => Operator::I64Store8 { memory_immediate: self.read_memory_immediate()? },
0x3d => Operator::I64Store16 { memory_immediate: self.read_memory_immediate()? },
0x3e => Operator::I64Store32 { memory_immediate: self.read_memory_immediate()? },
0x3f => Operator::CurrentMemory { reserved: self.read_var_u1()? },
0x40 => Operator::GrowMemory { reserved: self.read_var_u1()? },
0x41 => Operator::I32Const { value: self.read_var_i32()? },
0x42 => Operator::I64Const { value: self.read_var_i64()? },
0x43 => Operator::F32Const { value: self.read_f32()? },
0x44 => Operator::F64Const { value: self.read_f64()? },
0x45 => Operator::I32Eqz,
0x46 => Operator::I32Eq,
0x47 => Operator::I32Ne,
0x48 => Operator::I32LtS,
0x49 => Operator::I32LtU,
0x4a => Operator::I32GtS,
0x4b => Operator::I32GtU,
0x4c => Operator::I32LeS,
0x4d => Operator::I32LeU,
0x4e => Operator::I32GeS,
0x4f => Operator::I32GeU,
0x50 => Operator::I64Eqz,
0x51 => Operator::I64Eq,
0x52 => Operator::I64Ne,
0x53 => Operator::I64LtS,
0x54 => Operator::I64LtU,
0x55 => Operator::I64GtS,
0x56 => Operator::I64GtU,
0x57 => Operator::I64LeS,
0x58 => Operator::I64LeU,
0x59 => Operator::I64GeS,
0x5a => Operator::I64GeU,
0x5b => Operator::F32Eq,
0x5c => Operator::F32Ne,
0x5d => Operator::F32Lt,
0x5e => Operator::F32Gt,
0x5f => Operator::F32Le,
0x60 => Operator::F32Ge,
0x61 => Operator::F64Eq,
0x62 => Operator::F64Ne,
0x63 => Operator::F64Lt,
0x64 => Operator::F64Gt,
0x65 => Operator::F64Le,
0x66 => Operator::F64Ge,
0x67 => Operator::I32Clz,
0x68 => Operator::I32Ctz,
0x69 => Operator::I32Popcnt,
0x6a => Operator::I32Add,
0x6b => Operator::I32Sub,
0x6c => Operator::I32Mul,
0x6d => Operator::I32DivS,
0x6e => Operator::I32DivU,
0x6f => Operator::I32RemS,
0x70 => Operator::I32RemU,
0x71 => Operator::I32And,
0x72 => Operator::I32Or,
0x73 => Operator::I32Xor,
0x74 => Operator::I32Shl,
0x75 => Operator::I32ShrS,
0x76 => Operator::I32ShrU,
0x77 => Operator::I32Rotl,
0x78 => Operator::I32Rotr,
0x79 => Operator::I64Clz,
0x7a => Operator::I64Ctz,
0x7b => Operator::I64Popcnt,
0x7c => Operator::I64Add,
0x7d => Operator::I64Sub,
0x7e => Operator::I64Mul,
0x7f => Operator::I64DivS,
0x80 => Operator::I64DivU,
0x81 => Operator::I64RemS,
0x82 => Operator::I64RemU,
0x83 => Operator::I64And,
0x84 => Operator::I64Or,
0x85 => Operator::I64Xor,
0x86 => Operator::I64Shl,
0x87 => Operator::I64ShrS,
0x88 => Operator::I64ShrU,
0x89 => Operator::I64Rotl,
0x8a => Operator::I64Rotr,
0x8b => Operator::F32Abs,
0x8c => Operator::F32Neg,
0x8d => Operator::F32Ceil,
0x8e => Operator::F32Floor,
0x8f => Operator::F32Trunc,
0x90 => Operator::F32Nearest,
0x91 => Operator::F32Sqrt,
0x92 => Operator::F32Add,
0x93 => Operator::F32Sub,
0x94 => Operator::F32Mul,
0x95 => Operator::F32Div,
0x96 => Operator::F32Min,
0x97 => Operator::F32Max,
0x98 => Operator::F32Copysign,
0x99 => Operator::F64Abs,
0x9a => Operator::F64Neg,
0x9b => Operator::F64Ceil,
0x9c => Operator::F64Floor,
0x9d => Operator::F64Trunc,
0x9e => Operator::F64Nearest,
0x9f => Operator::F64Sqrt,
0xa0 => Operator::F64Add,
0xa1 => Operator::F64Sub,
0xa2 => Operator::F64Mul,
0xa3 => Operator::F64Div,
0xa4 => Operator::F64Min,
0xa5 => Operator::F64Max,
0xa6 => Operator::F64Copysign,
0xa7 => Operator::I32WrapI64,
0xa8 => Operator::I32TruncSF32,
0xa9 => Operator::I32TruncUF32,
0xaa => Operator::I32TruncSF64,
0xab => Operator::I32TruncUF64,
0xac => Operator::I64ExtendSI32,
0xad => Operator::I64ExtendUI32,
0xae => Operator::I64TruncSF32,
0xaf => Operator::I64TruncUF32,
0xb0 => Operator::I64TruncSF64,
0xb1 => Operator::I64TruncUF64,
0xb2 => Operator::F32ConvertSI32,
0xb3 => Operator::F32ConvertUI32,
0xb4 => Operator::F32ConvertSI64,
0xb5 => Operator::F32ConvertUI64,
0xb6 => Operator::F32DemoteF64,
0xb7 => Operator::F64ConvertSI32,
0xb8 => Operator::F64ConvertUI32,
0xb9 => Operator::F64ConvertSI64,
0xba => Operator::F64ConvertUI64,
0xbb => Operator::F64PromoteF32,
0xbc => Operator::I32ReinterpretF32,
0xbd => Operator::I64ReinterpretF64,
0xbe => Operator::F32ReinterpretI32,
0xbf => Operator::F64ReinterpretI64,
_ => {
return Err(BinaryReaderError {
message: "Unknown opcode",
offset: self.position - 1,
})
}
})
}
}
#[derive(Debug, Copy, Clone)]
pub struct Range {
pub start: usize,
pub end: usize,
}
impl Range {
pub fn new(start: usize, end: usize) -> Range {
assert!(start <= end);
Range { start, end }
}
pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] {
&data[self.start..self.end]
}
}
#[derive(Debug)]
pub enum ParserState<'a> {
Error(BinaryReaderError),
Initial,
BeginWasm { version: u32 },
EndWasm,
BeginSection { code: SectionCode<'a>, range: Range },
EndSection,
SkippingSection,
ReadingSectionRawData,
SectionRawData(&'a [u8]),
TypeSectionEntry(FuncType),
ImportSectionEntry {
module: &'a [u8],
field: &'a [u8],
ty: ImportSectionEntryType,
},
FunctionSectionEntry(u32),
TableSectionEntry(TableType),
MemorySectionEntry(MemoryType),
ExportSectionEntry {
field: &'a [u8],
kind: ExternalKind,
index: u32,
},
NameSectionEntry(NameEntry<'a>),
StartSectionEntry(u32),
BeginInitExpressionBody,
InitExpressionOperator(Operator<'a>),
EndInitExpressionBody,
BeginFunctionBody {
locals: Vec<(u32, Type)>,
range: Range,
},
CodeOperator(Operator<'a>),
EndFunctionBody,
SkippingFunctionBody,
BeginElementSectionEntry(u32),
ElementSectionEntryBody(Vec<u32>),
EndElementSectionEntry,
BeginDataSectionEntry(u32),
DataSectionEntryBody(&'a [u8]),
EndDataSectionEntry,
BeginGlobalSectionEntry(GlobalType),
EndGlobalSectionEntry,
RelocSectionHeader(SectionCode<'a>),
RelocSectionEntry(RelocEntry),
LinkingSectionEntry(LinkingType),
SourceMappingURL(&'a [u8]),
}
#[derive(Debug, Copy, Clone)]
pub enum ParserInput {
Default,
SkipSection,
SkipFunctionBody,
ReadSectionRawData,
}
pub trait WasmDecoder<'a> {
fn read(&mut self) -> &ParserState;
fn push_input(&mut self, input: ParserInput);
fn read_with_input(&mut self, input: ParserInput) -> &ParserState;
fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> where 'a: 'b;
fn last_state(&self) -> &ParserState;
}
pub struct Parser<'a> {
reader: BinaryReader<'a>,
state: ParserState<'a>,
section_range: Option<Range>,
function_range: Option<Range>,
init_expr_continuation: Option<InitExpressionContinuation>,
section_entries_left: u32,
}
const WASM_MAGIC_NUMBER: u32 = 0x6d736100;
const WASM_EXPERIMENTAL_VERSION: u32 = 0xd;
const WASM_SUPPORTED_VERSION: u32 = 0x1;
impl<'a> Parser<'a> {
pub fn new(data: &[u8]) -> Parser {
Parser {
reader: BinaryReader::new(data),
state: ParserState::Initial,
section_range: None,
function_range: None,
init_expr_continuation: None,
section_entries_left: 0,
}
}
pub fn eof(&self) -> bool {
self.reader.eof()
}
pub fn current_position(&self) -> usize {
self.reader.current_position()
}
fn read_header(&mut self) -> Result<()> {
let magic_number = self.reader.read_u32()?;
if magic_number != WASM_MAGIC_NUMBER {
return Err(BinaryReaderError {
message: "Bad magic number",
offset: self.reader.position - 4,
});
}
let version = self.reader.read_u32()?;
if version != WASM_SUPPORTED_VERSION && version != WASM_EXPERIMENTAL_VERSION {
return Err(BinaryReaderError {
message: "Bad version number",
offset: self.reader.position - 4,
});
}
self.state = ParserState::BeginWasm { version: version };
Ok(())
}
fn read_section_header(&mut self) -> Result<()> {
let id_position = self.reader.position;
let id = self.reader.read_var_u7()?;
let payload_len = self.reader.read_var_u32()? as usize;
let payload_end = self.reader.position + payload_len;
let code = self.reader.read_section_code(id, id_position)?;
if self.reader.end < payload_end {
return Err(BinaryReaderError {
message: "Section body extends past end of file",
offset: self.reader.end,
});
}
if self.reader.position > payload_end {
return Err(BinaryReaderError {
message: "Section header is too big to fit into section body",
offset: payload_end,
});
}
let range = Range {
start: self.reader.position,
end: payload_end,
};
self.state = ParserState::BeginSection { code, range };
self.section_range = Some(range);
Ok(())
}
fn read_type_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::TypeSectionEntry(self.reader.read_func_type()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_import_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
let module = self.reader.read_string()?;
let field = self.reader.read_string()?;
let kind = self.reader.read_external_kind()?;
let ty: ImportSectionEntryType;
match kind {
ExternalKind::Function => {
ty = ImportSectionEntryType::Function(self.reader.read_var_u32()?)
}
ExternalKind::Table => {
ty = ImportSectionEntryType::Table(self.reader.read_table_type()?)
}
ExternalKind::Memory => {
ty = ImportSectionEntryType::Memory(self.reader.read_memory_type()?)
}
ExternalKind::Global => {
ty = ImportSectionEntryType::Global(self.reader.read_global_type()?)
}
}
self.state = ParserState::ImportSectionEntry {
module: module,
field: field,
ty: ty,
};
self.section_entries_left -= 1;
Ok(())
}
fn read_function_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::FunctionSectionEntry(self.reader.read_var_u32()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_memory_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::MemorySectionEntry(self.reader.read_memory_type()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_global_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::BeginGlobalSectionEntry(self.reader.read_global_type()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_init_expression_body(&mut self, cont: InitExpressionContinuation) {
self.state = ParserState::BeginInitExpressionBody;
self.init_expr_continuation = Some(cont);
}
fn read_init_expression_operator(&mut self) -> Result<()> {
let op = self.reader.read_operator()?;
if let Operator::End = op {
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.position_to_section_end();
}
let field = self.reader.read_string()?;
let kind = self.reader.read_external_kind()?;
let index = self.reader.read_var_u32()?;
self.state = ParserState::ExportSectionEntry {
field: field,
kind: kind,
index: index,
};
self.section_entries_left -= 1;
Ok(())
}
fn read_element_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::BeginElementSectionEntry(self.reader.read_var_u32()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_element_entry_body(&mut self) -> Result<()> {
let num_elements = self.reader.read_var_u32()? as usize;
if num_elements > MAX_WASM_TABLE_ENTRIES {
return Err(BinaryReaderError {
message: "num_elements is out of bounds",
offset: self.reader.position - 1,
});
}
let mut elements: Vec<u32> = Vec::with_capacity(num_elements);
for _ in 0..num_elements {
elements.push(self.reader.read_var_u32()?);
}
self.state = ParserState::ElementSectionEntryBody(elements);
Ok(())
}
fn read_function_body(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
let size = self.reader.read_var_u32()? as usize;
let body_end = self.reader.position + size;
let local_count = self.reader.read_var_u32()? as usize;
if local_count > MAX_WASM_FUNCTION_LOCALS {
return Err(BinaryReaderError {
message: "local_count is out of bounds",
offset: self.reader.position - 1,
});
}
let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
let mut locals_total = 0;
for _ in 0..local_count {
let count = self.reader.read_var_u32()?;
locals_total += count as usize;
if locals_total > MAX_WASM_FUNCTION_LOCALS {
return Err(BinaryReaderError {
message: "local_count is out of bounds",
offset: self.reader.position - 1,
});
}
let ty = self.reader.read_type()?;
locals.push((count, ty));
}
let range = Range {
start: self.reader.position,
end: body_end,
};
self.state = ParserState::BeginFunctionBody { locals, range };
self.function_range = Some(range);
self.section_entries_left -= 1;
Ok(())
}
fn read_code_operator(&mut self) -> Result<()> {
let op = self.reader.read_operator()?;
if self.reader.position >= self.function_range.unwrap().end {
if let Operator::End = op {
self.state = ParserState::EndFunctionBody;
self.function_range = None;
return Ok(());
}
return Err(BinaryReaderError {
message: "Expected end of function marker",
offset: self.function_range.unwrap().end,
});
}
self.state = ParserState::CodeOperator(op);
Ok(())
}
fn read_table_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
self.state = ParserState::TableSectionEntry(self.reader.read_table_type()?);
self.section_entries_left -= 1;
Ok(())
}
fn read_data_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
let index = self.reader.read_var_u32()?;
self.state = ParserState::BeginDataSectionEntry(index);
self.section_entries_left -= 1;
Ok(())
}
fn read_data_entry_body(&mut self) -> Result<()> {
self.state = ParserState::DataSectionEntryBody(self.reader.read_string()?);
Ok(())
}
fn read_name_type(&mut self) -> Result<NameType> {
let code = self.reader.read_var_u7()?;
match code {
0 => Ok(NameType::Module),
1 => Ok(NameType::Function),
2 => Ok(NameType::Local),
_ => {
Err(BinaryReaderError {
message: "Invalid name type",
offset: self.reader.position - 1,
})
}
}
}
fn read_name_entry(&mut self) -> Result<()> {
if self.reader.position >= self.section_range.unwrap().end {
return self.position_to_section_end();
}
let ty = self.read_name_type()?;
self.reader.read_var_u32()?; let entry = match ty {
NameType::Module => NameEntry::Module(self.reader.read_string()?),
NameType::Function => {
NameEntry::Function(self.reader.read_name_map(MAX_WASM_FUNCTIONS)?)
}
NameType::Local => {
let funcs_len = self.reader.read_var_u32()? as usize;
if funcs_len > MAX_WASM_FUNCTIONS {
return Err(BinaryReaderError {
message: "function count is out of bounds",
offset: self.reader.position - 1,
});
}
let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len);
for _ in 0..funcs_len {
funcs.push(LocalName {
index: self.reader.read_var_u32()?,
locals: self.reader.read_name_map(MAX_WASM_FUNCTION_LOCALS)?,
});
}
NameEntry::Local(funcs)
}
};
self.state = ParserState::NameSectionEntry(entry);
Ok(())
}
fn read_source_mapping(&mut self) -> Result<()> {
self.state = ParserState::SourceMappingURL(self.reader.read_string()?);
Ok(())
}
fn read_reloc_header(&mut self) -> Result<()> {
let section_id_position = self.reader.position;
let section_id = self.reader.read_var_u7()?;
let section_code = self.reader
.read_section_code(section_id, section_id_position)?;
self.state = ParserState::RelocSectionHeader(section_code);
Ok(())
}
fn read_reloc_type(&mut self) -> Result<RelocType> {
let code = self.reader.read_var_u7()?;
match code {
0 => Ok(RelocType::FunctionIndexLEB),
1 => Ok(RelocType::TableIndexSLEB),
2 => Ok(RelocType::TableIndexI32),
3 => Ok(RelocType::GlobalAddrLEB),
4 => Ok(RelocType::GlobalAddrSLEB),
5 => Ok(RelocType::GlobalAddrI32),
6 => Ok(RelocType::TypeIndexLEB),
7 => Ok(RelocType::GlobalIndexLEB),
_ => {
Err(BinaryReaderError {
message: "Invalid reloc type",
offset: self.reader.position - 1,
})
}
}
}
fn read_reloc_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
let ty = self.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()?),
};
self.state = ParserState::RelocSectionEntry(RelocEntry {
ty: ty,
offset: offset,
index: index,
addend: addend,
});
self.section_entries_left -= 1;
Ok(())
}
fn read_linking_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.position_to_section_end();
}
let ty = self.reader.read_var_u32()?;
let entry = match ty {
1 => LinkingType::StackPointer(self.reader.read_var_u32()?),
_ => {
return Err(BinaryReaderError {
message: "Invalid linking type",
offset: self.reader.position - 1,
});
}
};
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, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_type_entry()?;
}
ParserState::BeginSection { code: SectionCode::Import, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_import_entry()?;
}
ParserState::BeginSection { code: SectionCode::Function, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_function_entry()?;
}
ParserState::BeginSection { code: SectionCode::Memory, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_memory_entry()?;
}
ParserState::BeginSection { code: SectionCode::Global, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_global_entry()?;
}
ParserState::BeginSection { code: SectionCode::Export, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_export_entry()?;
}
ParserState::BeginSection { code: SectionCode::Element, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_element_entry()?;
}
ParserState::BeginSection { code: SectionCode::Code, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_function_body()?;
}
ParserState::BeginSection { code: SectionCode::Table, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_table_entry()?;
}
ParserState::BeginSection { code: SectionCode::Data, .. } => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_data_entry()?;
}
ParserState::BeginSection { code: SectionCode::Start, .. } => {
self.state = ParserState::StartSectionEntry(self.reader.read_var_u32()?);
}
ParserState::BeginSection {
code: SectionCode::Custom { kind: CustomSectionKind::Name, .. }, ..
} => {
self.read_name_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Custom { kind: CustomSectionKind::SourceMappingURL, .. }, ..
} => {
self.read_source_mapping()?;
}
ParserState::BeginSection {
code: SectionCode::Custom { kind: CustomSectionKind::Reloc, .. }, ..
} => {
self.read_reloc_header()?;
}
ParserState::BeginSection {
code: SectionCode::Custom { kind: CustomSectionKind::Linking, .. }, ..
} => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_linking_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Custom { kind: CustomSectionKind::Unknown, .. }, ..
} => {
self.read_section_body_bytes()?;
}
_ => unreachable!(),
}
Ok(())
}
fn position_to_section_end(&mut self) -> Result<()> {
if self.section_range.unwrap().end < self.reader.position {
return Err(BinaryReaderError {
message: "Position past the section end",
offset: self.section_range.unwrap().end,
});
}
self.reader.position = self.section_range.unwrap().end;
self.section_range = None;
self.state = ParserState::EndSection;
Ok(())
}
fn read_section_body_bytes(&mut self) -> Result<()> {
let bytes = self.reader
.read_bytes_till(self.section_range.unwrap().end)?;
self.state = ParserState::SectionRawData(bytes);
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_header()?,
ParserState::BeginWasm { .. } |
ParserState::EndSection => {
if self.reader.eof() {
self.state = ParserState::EndWasm;
} else {
self.read_section_header()?;
}
}
ParserState::BeginSection { .. } => self.read_section_body()?,
ParserState::SkippingSection => self.position_to_section_end()?,
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(InitExpressionContinuation::GlobalSection)
}
ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
ParserState::BeginElementSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::ElementSection)
}
ParserState::BeginInitExpressionBody |
ParserState::InitExpressionOperator(_) => self.read_init_expression_operator()?,
ParserState::BeginDataSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::DataSection)
}
ParserState::EndInitExpressionBody => {
match self.init_expr_continuation {
Some(InitExpressionContinuation::GlobalSection) => {
self.state = ParserState::EndGlobalSectionEntry
}
Some(InitExpressionContinuation::ElementSection) => {
self.read_element_entry_body()?
}
Some(InitExpressionContinuation::DataSection) => self.read_data_entry_body()?,
None => unreachable!(),
}
self.init_expr_continuation = None;
}
ParserState::BeginFunctionBody { .. } |
ParserState::CodeOperator(_) => self.read_code_operator()?,
ParserState::EndFunctionBody => self.read_function_body()?,
ParserState::SkippingFunctionBody => {
assert!(self.reader.position <= self.function_range.unwrap().end);
self.reader.position = self.function_range.unwrap().end;
self.state = ParserState::EndFunctionBody;
self.function_range = None;
}
ParserState::DataSectionEntryBody(_) => {
self.state = ParserState::EndDataSectionEntry;
}
ParserState::EndDataSectionEntry => self.read_data_entry()?,
ParserState::ElementSectionEntryBody(_) => {
self.state = ParserState::EndElementSectionEntry;
}
ParserState::EndElementSectionEntry => self.read_element_entry()?,
ParserState::StartSectionEntry(_) => self.position_to_section_end()?,
ParserState::NameSectionEntry(_) => self.read_name_entry()?,
ParserState::SourceMappingURL(_) => self.position_to_section_end()?,
ParserState::RelocSectionHeader(_) => {
self.section_entries_left = self.reader.read_var_u32()?;
self.read_reloc_entry()?;
}
ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?,
ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?,
ParserState::ReadingSectionRawData => self.read_section_body_bytes()?,
ParserState::SectionRawData(_) => self.position_to_section_end()?,
}
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::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody,
_ => panic!("Invalid reader state during skip function body"),
}
}
fn read_raw_section_data(&mut self) {
match self.state {
ParserState::BeginSection { .. } => self.state = ParserState::ReadingSectionRawData,
_ => panic!("Invalid reader state during reading raw section data"),
}
}
}
impl<'a> WasmDecoder<'a> for Parser<'a> {
fn read(&mut self) -> &ParserState {
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::ReadSectionRawData => self.read_raw_section_data(),
}
}
fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
where 'a: 'b
{
let range;
match self.state {
ParserState::BeginSection { .. } => {
range = self.section_range.unwrap();
self.skip_section();
}
ParserState::BeginFunctionBody { .. } => {
range = self.function_range.unwrap();
self.skip_function_body();
}
_ => panic!("Invalid reader state during get binary reader operation"),
};
BinaryReader::new(range.slice(self.reader.buffer))
}
fn read_with_input(&mut self, input: ParserInput) -> &ParserState {
self.push_input(input);
self.read()
}
fn last_state(&self) -> &ParserState {
&self.state
}
}