2020-01-28 18:12:31 -05:00
|
|
|
use crate::vm::inst::Inst;
|
|
|
|
|
use byteorder::{ReadBytesExt, LE};
|
|
|
|
|
use snafu::{ensure, Snafu};
|
|
|
|
|
use std::{
|
|
|
|
|
convert::{TryFrom, TryInto},
|
|
|
|
|
fmt::Debug,
|
|
|
|
|
io::{self, Cursor, Read},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-01-28 18:15:07 -05:00
|
|
|
pub struct Object {
|
2020-01-28 18:12:31 -05:00
|
|
|
header: Header,
|
|
|
|
|
sections: Vec<Box<dyn Section>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct Header {
|
|
|
|
|
version: u16,
|
|
|
|
|
sections: u16,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! section_kind {
|
|
|
|
|
(
|
|
|
|
|
pub enum $enum_name:ident {
|
|
|
|
|
$($name:ident = $value:expr),* $(,)?
|
|
|
|
|
}
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
#[repr(u8)]
|
|
|
|
|
pub enum $enum_name {
|
|
|
|
|
$($name = $value),*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TryFrom<u8> for SectionKind {
|
|
|
|
|
type Error = ParseError;
|
|
|
|
|
|
|
|
|
|
fn try_from(other: u8) -> std::result::Result<Self, Self::Error> {
|
|
|
|
|
match other {
|
|
|
|
|
$(
|
|
|
|
|
$value => Ok($enum_name::$name),
|
|
|
|
|
)*
|
|
|
|
|
_ => Err(ParseError::UnknownSectionKind { kind: other }),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
section_kind! {
|
|
|
|
|
pub enum SectionKind {
|
|
|
|
|
Data = 0x00,
|
|
|
|
|
Code = 0x10,
|
|
|
|
|
Meta = 0xFF,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait Section: Debug {
|
|
|
|
|
fn header(&self) -> SectionHeader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct SectionHeader {
|
|
|
|
|
kind: SectionKind,
|
|
|
|
|
checksum: u32,
|
|
|
|
|
len: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct DataSection {
|
|
|
|
|
header: SectionHeader,
|
|
|
|
|
load_location: u64,
|
|
|
|
|
contents: Vec<u8>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Section for DataSection {
|
|
|
|
|
fn header(&self) -> SectionHeader {
|
|
|
|
|
self.header
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct CodeSection {
|
|
|
|
|
header: SectionHeader,
|
|
|
|
|
load_location: u64,
|
|
|
|
|
contents: Vec<Inst>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Section for CodeSection {
|
|
|
|
|
fn header(&self) -> SectionHeader {
|
|
|
|
|
self.header
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct MetaSection {
|
|
|
|
|
header: SectionHeader,
|
|
|
|
|
entry_count: u64,
|
|
|
|
|
entries: Vec<(String, Vec<u8>)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Section for MetaSection {
|
|
|
|
|
fn header(&self) -> SectionHeader {
|
|
|
|
|
self.header
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2020-01-28 18:15:07 -05:00
|
|
|
pub struct ObjectParser {
|
2020-01-28 18:12:31 -05:00
|
|
|
bytes: Cursor<Vec<u8>>,
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-28 18:15:07 -05:00
|
|
|
impl ObjectParser {
|
|
|
|
|
pub fn parse(&mut self) -> Result<Object> {
|
2020-01-28 18:12:31 -05:00
|
|
|
let header = self.parse_header()?;
|
|
|
|
|
let sections = self.parse_sections()?;
|
2020-01-28 18:15:07 -05:00
|
|
|
Ok(Object { header, sections })
|
2020-01-28 18:12:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_header(&mut self) -> Result<Header> {
|
|
|
|
|
let magic = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
ensure!(magic == MAGIC, WrongMagic);
|
|
|
|
|
let version = self.bytes.read_u16::<LE>()?;
|
|
|
|
|
let sections = self.bytes.read_u16::<LE>()?;
|
|
|
|
|
Ok(Header { version, sections })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_sections(&mut self) -> Result<Vec<Box<dyn Section>>> {
|
|
|
|
|
todo!()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_section(&mut self) -> Result<Box<dyn Section>> {
|
|
|
|
|
let header = self.parse_section_header()?;
|
|
|
|
|
let section: Box<dyn Section> = match header.kind {
|
|
|
|
|
SectionKind::Data => self.parse_data_section(header).map(Box::new)?,
|
|
|
|
|
SectionKind::Code => self.parse_code_section(header).map(Box::new)?,
|
|
|
|
|
SectionKind::Meta => self.parse_meta_section(header).map(Box::new)?,
|
|
|
|
|
};
|
|
|
|
|
Ok(section)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_section_header(&mut self) -> Result<SectionHeader> {
|
|
|
|
|
let kind: SectionKind = self.bytes.read_u8()?.try_into()?;
|
|
|
|
|
let checksum = self.bytes.read_u32::<LE>()?;
|
|
|
|
|
let len = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
Ok(SectionHeader {
|
|
|
|
|
kind,
|
|
|
|
|
checksum,
|
|
|
|
|
len,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_data_section(&mut self, header: SectionHeader) -> Result<DataSection> {
|
|
|
|
|
let load_location = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
let contents = self.take_bytes(header.len)?;
|
|
|
|
|
Ok(DataSection {
|
|
|
|
|
header,
|
|
|
|
|
load_location,
|
|
|
|
|
contents,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_code_section(&mut self, _header: SectionHeader) -> Result<CodeSection> {
|
|
|
|
|
let _load_location = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
todo!("instruction parsing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_meta_section(&mut self, header: SectionHeader) -> Result<MetaSection> {
|
|
|
|
|
let entry_count = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
let mut entries = Vec::with_capacity(entry_count as usize);
|
|
|
|
|
for offset in 0 .. entry_count {
|
|
|
|
|
let key_bytes = self.parse_sized_data()?;
|
|
|
|
|
let key = String::from_utf8(key_bytes)?;
|
|
|
|
|
let value = self.parse_sized_data()?;
|
|
|
|
|
entries.push((key, value));
|
|
|
|
|
}
|
|
|
|
|
Ok(MetaSection {
|
|
|
|
|
header,
|
|
|
|
|
entry_count,
|
|
|
|
|
entries,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_sized_data(&mut self) -> Result<Vec<u8>> {
|
|
|
|
|
let size = self.bytes.read_u64::<LE>()?;
|
|
|
|
|
self.take_bytes(size)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn take_bytes(&mut self, count: u64) -> Result<Vec<u8>> {
|
|
|
|
|
let mut contents = vec!(0u8; count as usize);
|
|
|
|
|
self.bytes.read_exact(&mut contents)?;
|
|
|
|
|
Ok(contents)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Snafu)]
|
|
|
|
|
pub enum ParseError {
|
|
|
|
|
#[snafu(display("IO error: {}", source))]
|
|
|
|
|
Io { source: io::Error },
|
|
|
|
|
|
|
|
|
|
#[snafu(display("wrong magic number"))]
|
|
|
|
|
WrongMagic,
|
|
|
|
|
|
|
|
|
|
#[snafu(display("unknown section kind: 0x{:02x}", kind))]
|
|
|
|
|
UnknownSectionKind { kind: u8 },
|
|
|
|
|
|
|
|
|
|
#[snafu(display("invalid UTF-8 string: {}", source))]
|
|
|
|
|
InvalidUtf8String { source: std::string::FromUtf8Error },
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! into_parse_error {
|
|
|
|
|
(
|
|
|
|
|
$($type:ty : $variant:ident),* $(,)?
|
|
|
|
|
) => {
|
|
|
|
|
$(
|
|
|
|
|
impl From<$type> for ParseError {
|
|
|
|
|
fn from(other: $type) -> Self {
|
|
|
|
|
ParseError::$variant { source: other }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)*
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
into_parse_error! {
|
|
|
|
|
io::Error: Io,
|
|
|
|
|
std::string::FromUtf8Error: InvalidUtf8String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub type Result<T> = std::result::Result<T, ParseError>;
|