mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-07-03 16:41:59 +00:00
import section, examples
This commit is contained in:
25
examples/info.rs
Normal file
25
examples/info.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
extern crate parity_wasm;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use parity_wasm::Section;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = env::args().collect::<Vec<_>>();
|
||||||
|
if args.len() != 2 {
|
||||||
|
println!("Usage: {} somefile.wasm", args[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||||
|
|
||||||
|
println!("Module sections: {}", module.sections().len());
|
||||||
|
|
||||||
|
for section in module.sections() {
|
||||||
|
match section {
|
||||||
|
&Section::Import(ref import_section) => {
|
||||||
|
println!("Imports {}", import_section.entries().len());
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
src/elements/import_entry.rs
Normal file
142
src/elements/import_entry.rs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
use std::io;
|
||||||
|
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, ValueType};
|
||||||
|
|
||||||
|
pub struct GlobalType {
|
||||||
|
content_type: ValueType,
|
||||||
|
is_mutable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalType {
|
||||||
|
pub fn content_type(&self) -> ValueType { self.content_type }
|
||||||
|
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for GlobalType {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let content_type = ValueType::deserialize(reader)?;
|
||||||
|
let is_mutable = VarUint1::deserialize(reader)?;
|
||||||
|
Ok(GlobalType {
|
||||||
|
content_type: content_type,
|
||||||
|
is_mutable: is_mutable.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TableType {
|
||||||
|
_elem_type: i8,
|
||||||
|
limits: ResizableLimits,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableType {
|
||||||
|
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for TableType {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let elem_type = VarInt7::deserialize(reader)?;
|
||||||
|
let limits = ResizableLimits::deserialize(reader)?;
|
||||||
|
Ok(TableType {
|
||||||
|
_elem_type: elem_type.into(),
|
||||||
|
limits: limits,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ResizableLimits {
|
||||||
|
initial: u32,
|
||||||
|
maximum: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResizableLimits {
|
||||||
|
pub fn initial(&self) -> u32 { self.initial }
|
||||||
|
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for ResizableLimits {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let has_max = VarUint1::deserialize(reader)?;
|
||||||
|
let initial = VarUint32::deserialize(reader)?;
|
||||||
|
let maximum = if has_max.into() {
|
||||||
|
Some(VarUint32::deserialize(reader)?.into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ResizableLimits {
|
||||||
|
initial: initial.into(),
|
||||||
|
maximum: maximum,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemoryType(ResizableLimits);
|
||||||
|
|
||||||
|
impl MemoryType {
|
||||||
|
pub fn limits(&self) -> &ResizableLimits {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for MemoryType {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum External {
|
||||||
|
Function(u32),
|
||||||
|
Table(TableType),
|
||||||
|
Memory(MemoryType),
|
||||||
|
Global(GlobalType),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for External {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let kind = VarUint7::deserialize(reader)?;
|
||||||
|
match kind.into() {
|
||||||
|
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
||||||
|
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
||||||
|
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
||||||
|
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
||||||
|
_ => Err(Error::UnknownExternalKind(kind.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImportEntry {
|
||||||
|
module_str: String,
|
||||||
|
field_str: String,
|
||||||
|
external: External,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportEntry {
|
||||||
|
pub fn module(&self) -> &str { &self.module_str }
|
||||||
|
pub fn field(&self) -> &str { &self.field_str }
|
||||||
|
pub fn external(&self) -> &External { &self.external }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for ImportEntry {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let module_str = String::deserialize(reader)?;
|
||||||
|
let field_str = String::deserialize(reader)?;
|
||||||
|
let external = External::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok(ImportEntry {
|
||||||
|
module_str: module_str,
|
||||||
|
field_str: field_str,
|
||||||
|
external: external,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -4,10 +4,13 @@ mod module;
|
|||||||
mod section;
|
mod section;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod import_entry;
|
||||||
|
|
||||||
pub use self::module::Module;
|
pub use self::module::Module;
|
||||||
pub use self::section::Section;
|
pub use self::section::Section;
|
||||||
|
pub use self::import_entry::ImportEntry;
|
||||||
pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, CountedList};
|
pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, CountedList};
|
||||||
|
pub use self::types::ValueType;
|
||||||
|
|
||||||
pub trait Deserialize : Sized {
|
pub trait Deserialize : Sized {
|
||||||
type Error;
|
type Error;
|
||||||
@ -21,6 +24,8 @@ pub enum Error {
|
|||||||
Other(&'static str),
|
Other(&'static str),
|
||||||
HeapOther(String),
|
HeapOther(String),
|
||||||
UnknownValueType(i8),
|
UnknownValueType(i8),
|
||||||
|
NonUtf8String,
|
||||||
|
UnknownExternalKind(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
@ -48,7 +53,7 @@ impl From<Unparsed> for Vec<u8> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
@ -57,7 +62,7 @@ fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error>
|
|||||||
deserialize_buffer(contents)
|
deserialize_buffer(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
|
pub fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
|
||||||
let mut reader = io::Cursor::new(contents);
|
let mut reader = io::Cursor::new(contents);
|
||||||
T::deserialize(&mut reader)
|
T::deserialize(&mut reader)
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use super::{Deserialize, VarUint32, Error, Uint32};
|
use super::{Deserialize, Error, Uint32};
|
||||||
use super::section::Section;
|
use super::section::Section;
|
||||||
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
magic: u32,
|
_magic: u32,
|
||||||
version: u32,
|
version: u32,
|
||||||
sections: Vec<Section>,
|
sections: Vec<Section>,
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ impl Deserialize for Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
magic: magic.into(),
|
_magic: magic.into(),
|
||||||
version: version.into(),
|
version: version.into(),
|
||||||
sections: sections,
|
sections: sections,
|
||||||
})
|
})
|
||||||
@ -48,19 +48,12 @@ mod integration_tests {
|
|||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use super::super::Deserialize;
|
use super::super::{Deserialize, deserialize_file};
|
||||||
use super::Module;
|
use super::Module;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello() {
|
fn hello() {
|
||||||
let mut contents = Vec::new();
|
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
||||||
File::open("./res/cases/v1/hello.wasm")
|
|
||||||
.expect("readable file")
|
|
||||||
.read_to_end(&mut contents)
|
|
||||||
.expect("read succeeds");
|
|
||||||
|
|
||||||
let mut reader = io::Cursor::new(contents);
|
|
||||||
let module = Module::deserialize(&mut reader).expect("Should be deserialized");
|
|
||||||
|
|
||||||
assert_eq!(module.version(), 1);
|
assert_eq!(module.version(), 1);
|
||||||
assert_eq!(module.sections().len(), 8);
|
assert_eq!(module.sections().len(), 8);
|
||||||
|
@ -25,7 +25,6 @@ impl Deserialize for VarUint32 {
|
|||||||
let mut shift = 0;
|
let mut shift = 0;
|
||||||
let mut u8buf = [0u8; 1];
|
let mut u8buf = [0u8; 1];
|
||||||
loop {
|
loop {
|
||||||
println!("read 1 byte");
|
|
||||||
reader.read_exact(&mut u8buf)?;
|
reader.read_exact(&mut u8buf)?;
|
||||||
let b = u8buf[0] as u32;
|
let b = u8buf[0] as u32;
|
||||||
res |= (b & 0x7f) << shift;
|
res |= (b & 0x7f) << shift;
|
||||||
@ -119,6 +118,22 @@ impl Deserialize for VarUint1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deserialize for String {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
let length = VarUint32::deserialize(reader)?.into();
|
||||||
|
if length > 0 {
|
||||||
|
let mut buf = vec![0u8; length];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
String::from_utf8(buf).map_err(|_| Error::NonUtf8String)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ok(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CountedList<T: Deserialize>(Vec<T>);
|
pub struct CountedList<T: Deserialize>(Vec<T>);
|
||||||
|
|
||||||
impl<T: Deserialize> CountedList<T> {
|
impl<T: Deserialize> CountedList<T> {
|
||||||
@ -130,13 +145,13 @@ impl<T: Deserialize> Deserialize for CountedList<T> where T::Error : From<Error>
|
|||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let count: usize = VarUint32::deserialize(reader)?.into();
|
let count: usize = VarUint32::deserialize(reader)?.into();
|
||||||
println!("count={}", count);
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for _ in 0..count { result.push(T::deserialize(reader)?); }
|
for _ in 0..count { result.push(T::deserialize(reader)?); }
|
||||||
Ok(CountedList(result))
|
Ok(CountedList(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::super::deserialize_buffer;
|
use super::super::deserialize_buffer;
|
||||||
@ -162,5 +177,4 @@ mod tests {
|
|||||||
let v3: i8 = (*vars.get(1).unwrap()).into();
|
let v3: i8 = (*vars.get(1).unwrap()).into();
|
||||||
assert_eq!(-0x03i8, v3);
|
assert_eq!(-0x03i8, v3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList};
|
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList, ImportEntry};
|
||||||
use super::types::Type;
|
use super::types::Type;
|
||||||
|
|
||||||
pub enum Section {
|
pub enum Section {
|
||||||
@ -9,6 +9,7 @@ pub enum Section {
|
|||||||
},
|
},
|
||||||
Custom(Vec<u8>),
|
Custom(Vec<u8>),
|
||||||
Type(TypeSection),
|
Type(TypeSection),
|
||||||
|
Import(ImportSection),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Section {
|
impl Deserialize for Section {
|
||||||
@ -29,6 +30,9 @@ impl Deserialize for Section {
|
|||||||
1 => {
|
1 => {
|
||||||
Section::Type(TypeSection::deserialize(reader)?)
|
Section::Type(TypeSection::deserialize(reader)?)
|
||||||
},
|
},
|
||||||
|
2 => {
|
||||||
|
Section::Import(ImportSection::deserialize(reader)?)
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() }
|
Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() }
|
||||||
}
|
}
|
||||||
@ -37,13 +41,11 @@ impl Deserialize for Section {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypeSection {
|
pub struct TypeSection(Vec<Type>);
|
||||||
types: Vec<Type>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeSection {
|
impl TypeSection {
|
||||||
fn types(&self) -> &[Type] {
|
pub fn types(&self) -> &[Type] {
|
||||||
&self.types
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,15 +56,50 @@ impl Deserialize for TypeSection {
|
|||||||
// todo: maybe use reader.take(section_length)
|
// todo: maybe use reader.take(section_length)
|
||||||
let _section_length = VarUint32::deserialize(reader)?;
|
let _section_length = VarUint32::deserialize(reader)?;
|
||||||
let types: Vec<Type> = CountedList::deserialize(reader)?.into_inner();
|
let types: Vec<Type> = CountedList::deserialize(reader)?.into_inner();
|
||||||
Ok(TypeSection { types: types })
|
Ok(TypeSection(types))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImportSection(Vec<ImportEntry>);
|
||||||
|
|
||||||
|
impl ImportSection {
|
||||||
|
pub fn entries(&self) -> &[ImportEntry] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for ImportSection {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
// todo: maybe use reader.take(section_length)
|
||||||
|
let _section_length = VarUint32::deserialize(reader)?;
|
||||||
|
let entries: Vec<ImportEntry> = CountedList::deserialize(reader)?.into_inner();
|
||||||
|
Ok(ImportSection(entries))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::super::{deserialize_buffer};
|
use super::super::{deserialize_buffer, deserialize_file};
|
||||||
use super::{TypeSection, Type};
|
use super::{Section, TypeSection, Type};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_section() {
|
||||||
|
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
|
let mut found = false;
|
||||||
|
for section in module.sections() {
|
||||||
|
match section {
|
||||||
|
&Section::Import(ref import_section) => {
|
||||||
|
assert_eq!(25, import_section.entries().len());
|
||||||
|
found = true
|
||||||
|
},
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(found, "There should be import section in test5.wasm");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn type_section() {
|
fn type_section() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use super::{Deserialize, Unparsed, Error, VarUint7, VarInt7, VarUint32, VarUint1};
|
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint1, CountedList};
|
||||||
|
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Function(FunctionType),
|
Function(FunctionType),
|
||||||
@ -13,6 +13,7 @@ impl Deserialize for Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum ValueType {
|
pub enum ValueType {
|
||||||
I32,
|
I32,
|
||||||
I64,
|
I64,
|
||||||
@ -42,20 +43,19 @@ pub struct FunctionType {
|
|||||||
return_type: Option<ValueType>,
|
return_type: Option<ValueType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionType {
|
||||||
|
pub fn form(&self) -> u8 { self.form }
|
||||||
|
pub fn params(&self) -> &[ValueType] { &self.params }
|
||||||
|
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
||||||
|
}
|
||||||
|
|
||||||
impl Deserialize for FunctionType {
|
impl Deserialize for FunctionType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let form: u8 = VarUint7::deserialize(reader)?.into();
|
let form: u8 = VarUint7::deserialize(reader)?.into();
|
||||||
println!("function form {}", form);
|
|
||||||
let param_count: usize = VarUint32::deserialize(reader)?.into();
|
|
||||||
|
|
||||||
println!("type param count {}", param_count);
|
let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
|
||||||
|
|
||||||
let mut params = Vec::new();
|
|
||||||
for _ in 0..param_count {
|
|
||||||
params.push(ValueType::deserialize(reader)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let has_return_type = VarUint1::deserialize(reader)?;
|
let has_return_type = VarUint1::deserialize(reader)?;
|
||||||
let return_type = if has_return_type.into() {
|
let return_type = if has_return_type.into() {
|
||||||
|
@ -2,4 +2,4 @@ extern crate byteorder;
|
|||||||
|
|
||||||
mod elements;
|
mod elements;
|
||||||
|
|
||||||
pub use elements::{Section, Module, Error as DeserializeError};
|
pub use elements::{Section, Module, Error as DeserializeError, deserialize_buffer, deserialize_file};
|
||||||
|
Reference in New Issue
Block a user