diff --git a/src/vm/error.rs b/src/vm/error.rs index dc52452..f0841df 100644 --- a/src/vm/error.rs +++ b/src/vm/error.rs @@ -1,8 +1,11 @@ -use crate::vm::vm::*; +use crate::vm::{vm::*, reg::Reg}; use snafu::Snafu; #[derive(Snafu, Debug, Clone)] pub enum VmError { + #[snafu(display("illegal register: 0x{:02x}", reg))] + IllegalReg { reg: Reg }, + #[snafu(display("memory address out of bounds: 0x{:016x}", addr))] MemOutOfBounds { addr: Addr }, } diff --git a/src/vm/obj/assemble/mod.rs b/src/vm/obj/assemble/mod.rs index 01bb26f..6425827 100644 --- a/src/vm/obj/assemble/mod.rs +++ b/src/vm/obj/assemble/mod.rs @@ -54,7 +54,6 @@ impl<'a> Assemble<'a> { }); } } - self.symbols.globals_mut().extend(exports); } @@ -151,6 +150,8 @@ impl<'a> Assemble<'a> { } } } + // TODO : make sure we aren't trying to export anything that doesn't exist + // only return exports if specified if export { labels.retain(|k, _| exports.contains(k)); diff --git a/src/vm/tick.rs b/src/vm/tick.rs index d6ef601..4a2dd0b 100644 --- a/src/vm/tick.rs +++ b/src/vm/tick.rs @@ -10,7 +10,7 @@ impl Vm { ($mapping:expr) => {{ let (r1, r2) = cursor.next_regs()?; next_ip = cursor.position(); - let value = ($mapping)(self.get_reg(r1), self.get_reg(r2)); + let value = ($mapping)(self.get_reg_checked(r1)?, self.get_reg_checked(r2)?); self.set_reg(r1, value); }}; } @@ -25,7 +25,7 @@ impl Vm { INV => { let r1 = cursor.next_reg()?; next_ip = cursor.position(); - let value = self.get_reg(r1); + let value = self.get_reg_checked(r1)?; self.set_reg(r1, !value); } NOT => { @@ -80,8 +80,8 @@ impl Vm { LOAD => { let (r1, r2) = cursor.next_regs()?; next_ip = cursor.position(); - let value = self.load(r2); - self.set_reg(r1, value); + let value = self.load(r2)?; + self.set_reg_checked(r1, value)?; } REGCOPY => math_inst!(|_: u64, w2: u64| w2), STOREIMM64 => { @@ -101,14 +101,14 @@ impl Vm { MEMCOPY => { let (r1, r2) = cursor.next_regs()?; next_ip = cursor.position(); - let value = self.load(r2); - self.store(r1, value); + let value = self.load(r2)?; + self.store(r1, value)?; } STORE => { let (r1, r2) = cursor.next_regs()?; next_ip = cursor.position(); let value = self.get_reg(r1); - self.store(r2, value); + self.store(r2, value)?; } HALT => { next_ip = cursor.position(); diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 4d9fb17..53ab09b 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,5 +1,5 @@ use crate::vm::{error::*, flags::*, mem::*, reg::*}; -use byteorder::{ReadBytesExt, WriteBytesExt, LE}; +use byteorder::{WriteBytesExt, LE}; use std::{io::Cursor, mem}; pub type Word = u64; @@ -18,7 +18,6 @@ impl Vm { } pub fn mem_cursor(&self, at: usize) -> MemCursor { - // TODO : MemCursor MemCursor::new(&self.mem[at..]) } @@ -37,59 +36,62 @@ impl Vm { self.flags().contains(Flags::HALT) } - pub fn get_word(&self, addr: Word) -> Word { - let mut reader = Cursor::new(&self.mem[(addr as usize)..]); - reader - .read_u64::() - .expect("word outside of address range") + pub fn get_word(&self, addr: Addr) -> Result { + self.check_read(addr, 8)?; + Ok(self.mem_cursor(addr as usize).next_u64().unwrap()) } - pub fn get_halfword(&self, addr: Word) -> HalfWord { - let mut reader = Cursor::new(&self.mem[(addr as usize)..]); - reader - .read_u32::() - .expect("word outside of address range") + pub fn get_halfword(&self, addr: Addr) -> Result { + self.check_read(addr, 4)?; + Ok(self.mem_cursor(addr as usize).next_u32().unwrap()) } - pub fn get_byte(&self, addr: Word) -> u8 { - let mut reader = Cursor::new(&self.mem[(addr as usize)..]); - reader.read_u8().expect("word outside of address range") + pub fn get_byte(&self, addr: Addr) -> Result { + self.check_addr(addr)?; + Ok(self.mem_cursor(addr as usize).next_u8().unwrap()) } - pub fn set_word(&mut self, addr: Word, value: Word) { - let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]); - writer - .write_u64::(value) - .expect("word outside of address range"); + pub fn set_word(&mut self, addr: Addr, value: Word) -> Result<()> { + self.check_read(addr, 8)?; + let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); + Ok(cursor.write_u64::(value).unwrap()) } - pub fn set_halfword(&mut self, addr: Word, value: HalfWord) { - let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]); - writer - .write_u32::(value) - .expect("word outside of address range"); + pub fn set_halfword(&mut self, addr: Addr, value: HalfWord) -> Result<()> { + self.check_read(addr, 4)?; + let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); + Ok(cursor.write_u32::(value).unwrap()) } - pub fn set_byte(&mut self, addr: Word, value: u8) { - let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]); - writer - .write_u8(value) - .expect("word outside of address range"); + pub fn set_byte(&mut self, addr: Addr, value: u8) -> Result<()> { + self.check_addr(addr)?; + let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); + Ok(cursor.write_u8(value).unwrap()) } - pub fn load(&self, reg: Reg) -> Word { - self.get_word(self.get_reg(reg)) + pub fn load(&self, reg: Reg) -> Result { + self.get_word(self.get_reg_checked(reg)?) } - pub fn store(&mut self, reg: Reg, value: Word) { - let addr = self.get_reg(reg); - self.set_word(addr, value); + pub fn store(&mut self, reg: Reg, value: Word) -> Result<()> { + let addr = self.get_reg_checked(reg)?; + self.set_word(addr, value) + } + + pub fn get_reg_checked(&self, reg: Reg) -> Result { + self.check_reg(reg)?; + Ok(self.get_reg(reg)) } pub fn get_reg(&self, reg: Reg) -> Word { self.registers[reg as usize] } + pub fn set_reg_checked(&mut self, reg: Reg, value: Word) -> Result { + self.check_reg(reg)?; + Ok(self.set_reg(reg, value)) + } + pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word { mem::replace(&mut self.registers[reg as usize], value) } @@ -119,4 +121,25 @@ impl Vm { pub fn set_flags(&mut self, flags: Flags) { self.set_reg(FLAGS, flags.bits()); } + + fn check_addr(&self, addr: Addr) -> Result<()> { + if addr >= (self.mem.len() as u64) { + Err(VmError::MemOutOfBounds { addr }) + } else { + Ok(()) + } + } + + fn check_read(&self, addr: Addr, len: Word) -> Result<()> { + self.check_addr(addr) + .and_then(|_| self.check_addr(addr + len - 1)) + } + + fn check_reg(&self, reg: Reg) -> Result<()> { + if reg > LAST_REG { + Err(VmError::IllegalReg { reg }) + } else { + Ok(()) + } + } }