use crate::vm::{addr::*, error::*, inst::*, reg::*}; use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use std::io::Cursor; pub struct MemCursor { cursor: Cursor, } impl MemCursor where Cursor: ReadBytesExt, T: AsRef<[u8]> { pub fn new(mem: T) -> Self { MemCursor { cursor: Cursor::new(mem) } } pub fn position(&self) -> u64 { self.cursor.position() } pub fn set_position>(&mut self, position: P) { self.cursor.set_position((position.into()).0) } pub fn next_u8_unchecked(&mut self) -> u8 { self.cursor.read_u8().unwrap() } pub fn next_u8(&mut self) -> Result { self.check_addr(self.position()) .map(|_| self.next_u8_unchecked()) } pub fn next_u16_unchecked(&mut self) -> u16 { self.cursor.read_u16::().unwrap() } pub fn next_u16(&mut self) -> Result { self.check_addr(self.position()) .map(|_| self.next_u16_unchecked()) } pub fn next_u32_unchecked(&mut self) -> u32 { self.cursor.read_u32::().unwrap() } pub fn next_u32(&mut self) -> Result { self.check_addr(self.position()) .map(|_| self.next_u32_unchecked()) } pub fn next_u64_unchecked(&mut self) -> u64 { self.cursor.read_u64::().unwrap() } pub fn next_u64(&mut self) -> Result { self.check_addr(self.position()) .map(|_| self.next_u64_unchecked()) } pub fn next_addr(&mut self) -> Result { self.check_addr(self.position()) .map(|_| self.next_addr_unchecked()) } pub fn next_addr_unchecked(&mut self) -> Addr { Addr(self.next_u64_unchecked()) } pub fn next_inst(&mut self) -> Result { let start = self.position(); let op = self.next_u16()?; macro_rules! dest_source { ($variant:ident) => {{ let (d, s) = self.next_dest_source()?; Ok(Inst::$variant(d, s)) }}; } macro_rules! source_source { ($variant:ident) => {{ let (s1, s2) = self.next_source_source()?; Ok(Inst::$variant(s1, s2)) }}; } macro_rules! source { ($variant:ident) => {{ let spec = (self.next_u8()? & 0xF0) >> 4; let source = self.next_source(spec)?; Ok(Inst::$variant(source)) }}; } let inst = match op { ADD => dest_source!(Add), SUB => dest_source!(Sub), MUL => dest_source!(Mul), DIV => dest_source!(Div), MOD => dest_source!(Mod), AND => dest_source!(And), OR => dest_source!(Or), XOR => dest_source!(Xor), SHL => dest_source!(Shl), SHR => dest_source!(Shr), INEG => dest_source!(INeg), INV => dest_source!(Inv), NOT => dest_source!(Not), CMPEQ => source_source!(CmpEq), CMPLT => source_source!(CmpLt), JMP => source!(Jmp), JZ => source!(Jz), JNZ => source!(Jnz), MOV => dest_source!(Mov), HALT => Ok(Inst::Halt), NOP => Ok(Inst::Nop), DUMP => Ok(Inst::Dump), _ => Err(VmError::IllegalOp { op }), }?; let end = self.position(); let len = (end - start) as usize; assert_eq!(len, inst.len()); Ok(inst) } fn next_source_source(&mut self) -> Result<(Source, Source)> { let spec = self.next_u8()?; let s1_spec = (spec & 0xF0) >> 4; let s2_spec = spec & 0x0F; let s1 = self.next_source(s1_spec)?; let s2 = self.next_source(s2_spec)?; Ok((s1, s2)) } fn next_dest_source(&mut self) -> Result<(Dest, Source)> { let spec = self.next_u8()?; let dest_spec = (spec & 0xF0) >> 4; let source_spec = spec & 0x0F; let dest = self.next_dest(dest_spec)?; let source = self.next_source(source_spec)?; Ok((dest, source)) } fn next_dest(&mut self, spec: u8) -> Result { match spec { DEST_ADDR64 => Ok(Dest::Addr64(self.next_addr()?)), DEST_ADDR32 => Ok(Dest::Addr32(self.next_addr()?)), DEST_ADDR16 => Ok(Dest::Addr16(self.next_addr()?)), DEST_ADDR8 => Ok(Dest::Addr8(self.next_addr()?)), DEST_REG_ADDR64 => Ok(Dest::RegAddr64(self.next_reg()?)), DEST_REG_ADDR32 => Ok(Dest::RegAddr32(self.next_reg()?)), DEST_REG_ADDR16 => Ok(Dest::RegAddr16(self.next_reg()?)), DEST_REG_ADDR8 => Ok(Dest::RegAddr8(self.next_reg()?)), DEST_REG => Ok(Dest::Reg(self.next_reg()?)), _ => Err(VmError::IllegalDestSpec { spec }), } } fn next_source(&mut self, spec: u8) -> Result { match spec { SOURCE_ADDR64 => Ok(Source::Addr64(self.next_addr()?)), SOURCE_ADDR32 => Ok(Source::Addr32(self.next_addr()?)), SOURCE_ADDR16 => Ok(Source::Addr16(self.next_addr()?)), SOURCE_ADDR8 => Ok(Source::Addr8(self.next_addr()?)), SOURCE_REG_ADDR64 => Ok(Source::RegAddr64(self.next_reg()?)), SOURCE_REG_ADDR32 => Ok(Source::RegAddr32(self.next_reg()?)), SOURCE_REG_ADDR16 => Ok(Source::RegAddr16(self.next_reg()?)), SOURCE_REG_ADDR8 => Ok(Source::RegAddr8(self.next_reg()?)), SOURCE_REG => Ok(Source::Reg(self.next_reg()?)), SOURCE_IMM64 => Ok(Source::Imm(self.next_u64()?)), SOURCE_IMM32 => Ok(Source::Imm(self.next_u32()? as u64)), SOURCE_IMM16 => Ok(Source::Imm(self.next_u16()? as u64)), SOURCE_IMM8 => Ok(Source::Imm(self.next_u8()? as u64)), _ => Err(VmError::IllegalSourceSpec { spec }), } } fn next_reg(&mut self) -> Result { let reg = self.next_u8()?; if (reg as usize) >= NUM_REGS { Err(VmError::IllegalReg { reg }) } else { Ok(reg) } } } impl MemCursor where T: AsRef<[u8]> { fn check_addr(&self, addr: u64) -> Result<()> { if addr > (self.cursor.get_ref().as_ref().len() as u64) { Err(VmError::MemOutOfBounds { addr: Addr(addr) }) } else { Ok(()) } } } impl MemCursor where Cursor: WriteBytesExt, T: AsRef<[u8]> { pub fn write_u8_unchecked(&mut self, value: u8) { self.cursor.write_u8(value).unwrap(); } pub fn write_u8(&mut self, value: u8) -> Result<()> { self.check_addr(self.position()) .map(|_| self.write_u8_unchecked(value)) } pub fn write_u16_unchecked(&mut self, value: u16) { self.cursor.write_u16::(value).unwrap(); } pub fn write_u16(&mut self, value: u16) -> Result<()> { self.check_addr(self.position()) .map(|_| self.write_u16_unchecked(value)) } pub fn write_u32_unchecked(&mut self, value: u32) { self.cursor.write_u32::(value).unwrap(); } pub fn write_u32(&mut self, value: u32) -> Result<()> { self.check_addr(self.position()) .map(|_| self.write_u32_unchecked(value)) } pub fn write_u64_unchecked(&mut self, value: u64) { self.cursor.write_u64::(value).unwrap(); } pub fn write_u64(&mut self, value: u64) -> Result<()> { self.check_addr(self.position()) .map(|_| self.write_u64_unchecked(value)) } } /* //////////////////////////////////////////////////////////////////////////////// // Index impl //////////////////////////////////////////////////////////////////////////////// impl> Index for MemCursor { type Output = u8; fn index(&self, addr: usize) -> &Self::Output { self.mem.as_ref().index(addr) } } impl> Index for MemCursor { type Output = u8; fn index(&self, addr: u64) -> &Self::Output { self.index(addr as usize) } } impl> Index for MemCursor { type Output = u8; fn index(&self, addr: Addr) -> &Self::Output { self.index(addr.0) } } */