tetsy_wasm/elements/
mod.rs

1//! Elements of the WebAssembly binary format.
2
3use alloc::{string::String, vec::Vec};
4use crate::io;
5
6use core::fmt;
7
8macro_rules! buffered_read {
9	($buffer_size: expr, $length: expr, $reader: expr) => {
10		{
11			let mut vec_buf = Vec::new();
12			let mut total_read = 0;
13			let mut buf = [0u8; $buffer_size];
14			while total_read < $length {
15				let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read };
16				$reader.read(&mut buf[0..next_to_read])?;
17				vec_buf.extend_from_slice(&buf[0..next_to_read]);
18				total_read += next_to_read;
19			}
20			vec_buf
21		}
22	}
23}
24
25mod primitives;
26mod module;
27mod section;
28mod types;
29mod import_entry;
30mod export_entry;
31mod global_entry;
32mod ops;
33mod func;
34mod segment;
35mod index_map;
36mod name_section;
37mod reloc_section;
38
39pub use self::module::{Module, peek_size, ImportCountType};
40pub use self::section::{
41	Section, FunctionSection, CodeSection, MemorySection, DataSection,
42	ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
43	TableSection, CustomSection,
44};
45pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
46pub use self::export_entry::{ExportEntry, Internal};
47pub use self::global_entry::GlobalEntry;
48pub use self::primitives::{
49	VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
50	Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
51};
52pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
53pub use self::ops::{Instruction, Instructions, InitExpr, opcodes, BrTableData};
54
55#[cfg(feature="atomics")]
56pub use self::ops::AtomicsInstruction;
57
58#[cfg(feature="simd")]
59pub use self::ops::SimdInstruction;
60
61#[cfg(feature="sign_ext")]
62pub use self::ops::SignExtInstruction;
63
64#[cfg(feature="bulk")]
65pub use self::ops::BulkInstruction;
66
67#[cfg(any(feature="simd", feature="atomics"))]
68pub use self::ops::MemArg;
69
70pub use self::func::{Func, FuncBody, Local};
71pub use self::segment::{ElementSegment, DataSegment};
72pub use self::index_map::IndexMap;
73pub use self::name_section::{
74	NameMap, NameSection, ModuleNameSubsection, FunctionNameSubsection,
75	LocalNameSubsection,
76};
77pub use self::reloc_section::{
78	RelocSection, RelocationEntry,
79};
80
81/// Deserialization from serial i/o.
82pub trait Deserialize : Sized {
83	/// Serialization error produced by deserialization routine.
84	type Error: From<io::Error>;
85	/// Deserialize type from serial i/o
86	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
87}
88
89/// Serialization to serial i/o. Takes self by value to consume less memory
90/// (tetsy-wasm IR is being partially freed by filling the result buffer).
91pub trait Serialize {
92	/// Serialization error produced by serialization routine.
93	type Error: From<io::Error>;
94	/// Serialize type to serial i/o
95	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
96}
97
98/// Deserialization/serialization error
99#[derive(Debug, Clone)]
100pub enum Error {
101	/// Unexpected end of input.
102	UnexpectedEof,
103	/// Invalid magic.
104	InvalidMagic,
105	/// Unsupported version.
106	UnsupportedVersion(u32),
107	/// Inconsistence between declared and actual length.
108	InconsistentLength {
109		/// Expected length of the definition.
110		expected: usize,
111		/// Actual length of the definition.
112		actual: usize
113	},
114	/// Other static error.
115	Other(&'static str),
116	/// Other allocated error.
117	HeapOther(String),
118	/// Invalid/unknown value type declaration.
119	UnknownValueType(i8),
120	/// Invalid/unknown table element type declaration.
121	UnknownTableElementType(i8),
122	/// Non-utf8 string.
123	NonUtf8String,
124	/// Unknown external kind code.
125	UnknownExternalKind(u8),
126	/// Unknown internal kind code.
127	UnknownInternalKind(u8),
128	/// Unknown opcode encountered.
129	UnknownOpcode(u8),
130	#[cfg(feature="simd")]
131	/// Unknown SIMD opcode encountered.
132	UnknownSimdOpcode(u32),
133	/// Invalid VarUint1 value.
134	InvalidVarUint1(u8),
135	/// Invalid VarInt32 value.
136	InvalidVarInt32,
137	/// Invalid VarInt64 value.
138	InvalidVarInt64,
139	/// Invalid VarUint32 value.
140	InvalidVarUint32,
141	/// Invalid VarUint64 value.
142	InvalidVarUint64,
143	/// Inconsistent metadata.
144	InconsistentMetadata,
145	/// Invalid section id.
146	InvalidSectionId(u8),
147	/// Sections are out of order.
148	SectionsOutOfOrder,
149	/// Duplicated sections.
150	DuplicatedSections(u8),
151	/// Invalid memory reference (should be 0).
152	InvalidMemoryReference(u8),
153	/// Invalid table reference (should be 0).
154	InvalidTableReference(u8),
155	/// Invalid value used for flags in limits type.
156	InvalidLimitsFlags(u8),
157	/// Unknown function form (should be 0x60).
158	UnknownFunctionForm(u8),
159	/// Invalid varint7 (should be in -64..63 range).
160	InvalidVarInt7(u8),
161	/// Number of function body entries and signatures does not match.
162	InconsistentCode,
163	/// Only flags 0, 1, and 2 are accepted on segments.
164	InvalidSegmentFlags(u32),
165	/// Sum of counts of locals is greater than 2^32.
166	TooManyLocals,
167	/// Duplicated name subsections.
168	DuplicatedNameSubsections(u8),
169	/// Unknown name subsection type.
170	UnknownNameSubsectionType(u8),
171}
172
173impl fmt::Display for Error {
174	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175		match *self {
176			Error::UnexpectedEof => write!(f, "Unexpected end of input"),
177			Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
178			Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
179			Error::InconsistentLength { expected, actual } => {
180				write!(f, "Expected length {}, found {}", expected, actual)
181			}
182			Error::Other(msg) => write!(f, "{}", msg),
183			Error::HeapOther(ref msg) => write!(f, "{}", msg),
184			Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
185			Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
186			Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
187			Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
188			Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
189			Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
190			#[cfg(feature="simd")]
191			Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode),
192			Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
193			Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val),
194			Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
195			Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"),
196			Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
197			Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"),
198			Error::InconsistentMetadata =>  write!(f, "Inconsistent metadata"),
199			Error::InvalidSectionId(ref id) =>  write!(f, "Invalid section id: {}", id),
200			Error::SectionsOutOfOrder =>  write!(f, "Sections out of order"),
201			Error::DuplicatedSections(ref id) =>  write!(f, "Duplicated sections ({})", id),
202			Error::InvalidMemoryReference(ref mem_ref) =>  write!(f, "Invalid memory reference ({})", mem_ref),
203			Error::InvalidTableReference(ref table_ref) =>  write!(f, "Invalid table reference ({})", table_ref),
204			Error::InvalidLimitsFlags(ref flags) =>  write!(f, "Invalid limits flags ({})", flags),
205			Error::UnknownFunctionForm(ref form) =>  write!(f, "Unknown function form ({})", form),
206			Error::InconsistentCode =>  write!(f, "Number of function body entries and signatures does not match"),
207			Error::InvalidSegmentFlags(n) =>  write!(f, "Invalid segment flags: {}", n),
208			Error::TooManyLocals => write!(f, "Too many locals"),
209			Error::DuplicatedNameSubsections(n) =>  write!(f, "Duplicated name subsections: {}", n),
210			Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
211		}
212	}
213}
214
215#[cfg(feature = "std")]
216impl ::std::error::Error for Error {
217	fn description(&self) -> &str {
218		match *self {
219			Error::UnexpectedEof => "Unexpected end of input",
220			Error::InvalidMagic => "Invalid magic number at start of file",
221			Error::UnsupportedVersion(_) => "Unsupported wasm version",
222			Error::InconsistentLength { .. } => "Inconsistent length",
223			Error::Other(msg) => msg,
224			Error::HeapOther(ref msg) => &msg[..],
225			Error::UnknownValueType(_) => "Invalid or unknown value type",
226			Error::UnknownTableElementType(_) => "Unknown table element type",
227			Error::NonUtf8String => "Non-UTF-8 string",
228			Error::UnknownExternalKind(_) => "Unknown external kind",
229			Error::UnknownInternalKind(_) => "Unknown internal kind",
230			Error::UnknownOpcode(_) => "Unknown opcode",
231			#[cfg(feature="simd")]
232			Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode",
233			Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
234			Error::InvalidVarInt32 => "Not a signed 32-bit integer",
235			Error::InvalidVarInt7(_) => "Not a signed 7-bit integer",
236			Error::InvalidVarUint32 => "Not an unsigned 32-bit integer",
237			Error::InvalidVarInt64 => "Not a signed 64-bit integer",
238			Error::InvalidVarUint64 => "Not an unsigned 64-bit integer",
239			Error::InconsistentMetadata => "Inconsistent metadata",
240			Error::InvalidSectionId(_) =>  "Invalid section id",
241			Error::SectionsOutOfOrder =>  "Sections out of order",
242			Error::DuplicatedSections(_) =>  "Duplicated section",
243			Error::InvalidMemoryReference(_) =>  "Invalid memory reference",
244			Error::InvalidTableReference(_) =>  "Invalid table reference",
245			Error::InvalidLimitsFlags(_) => "Invalid limits flags",
246			Error::UnknownFunctionForm(_) =>  "Unknown function form",
247			Error::InconsistentCode =>  "Number of function body entries and signatures does not match",
248			Error::InvalidSegmentFlags(_) =>  "Invalid segment flags",
249			Error::TooManyLocals => "Too many locals",
250			Error::DuplicatedNameSubsections(_) =>  "Duplicated name subsections",
251			Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
252		}
253	}
254}
255
256impl From<io::Error> for Error {
257	fn from(err: io::Error) -> Self {
258		Error::HeapOther(format!("I/O Error: {:?}", err))
259	}
260}
261
262// These are emitted by section parsers, such as `parse_names` and `parse_reloc`.
263impl From<(Vec<(usize, Error)>, Module)> for Error {
264	fn from(err: (Vec<(usize, Error)>, Module)) -> Self {
265		let ret = err.0.iter()
266			.fold(
267				String::new(),
268				|mut acc, item| { acc.push_str(&format!("In section {}: {}\n", item.0, item.1)); acc }
269			);
270		Error::HeapOther(ret)
271	}
272}
273
274/// Unparsed part of the module/section.
275pub struct Unparsed(pub Vec<u8>);
276
277impl Deserialize for Unparsed {
278	type Error = Error;
279
280	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
281		let len = VarUint32::deserialize(reader)?.into();
282		let mut vec = vec![0u8; len];
283		reader.read(&mut vec[..])?;
284		Ok(Unparsed(vec))
285	}
286}
287
288impl From<Unparsed> for Vec<u8> {
289	fn from(u: Unparsed) -> Vec<u8> {
290		u.0
291	}
292}
293
294/// Deserialize deserializable type from buffer.
295pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
296	let mut reader = io::Cursor::new(contents);
297	let result = T::deserialize(&mut reader)?;
298	if reader.position() != contents.len() {
299		// It's a TrailingData, since if there is not enough data then
300		// UnexpectedEof must have been returned earlier in T::deserialize.
301		return Err(io::Error::TrailingData.into())
302	}
303	Ok(result)
304}
305
306/// Create buffer with serialized value.
307pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
308	let mut buf = Vec::new();
309	val.serialize(&mut buf)?;
310	Ok(buf)
311}
312
313/// Deserialize module from the file.
314#[cfg(feature = "std")]
315pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
316	let mut f = ::std::fs::File::open(p)
317		.map_err(|e| Error::HeapOther(format!("Can't read from the file: {:?}", e)))?;
318
319	Module::deserialize(&mut f)
320}
321
322/// Serialize module to the file
323#[cfg(feature = "std")]
324pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> {
325	let mut io = ::std::fs::File::create(p)
326		.map_err(|e|
327			Error::HeapOther(format!("Can't create the file: {:?}", e))
328		)?;
329
330	module.serialize(&mut io)?;
331	Ok(())
332}