Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion name-emu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ base64 = "0.21.4"
byteorder = "1.4.3"
serde_json = "1.0.107"
serde = { version = "1.0.188", features = ["derive"] }
toml = "0.7.6"
toml = "0.7.6"
elf = "0.7.3"
5 changes: 5 additions & 0 deletions name-emu/src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub enum ExecutionErrors {
// Can also refer to underflow
IntegerOverflow { rt: usize, rs: usize, value1: u32, value2: u32 },

SyscallInvalidArugment,

SyscallInvalidSyscallNumber,

Event { event: ExecutionEvents }
}

Expand Down Expand Up @@ -97,6 +101,7 @@ pub fn exception_pretty_print(reason: Result<(), ExecutionErrors>) -> ExceptionI
type_name: None, full_type_name: None, evaluate_name: None, stack_trace: None, inner_exception: None })
},

_ => unimplemented!("adf"),
}
}

Expand Down
41 changes: 33 additions & 8 deletions name-emu/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};

use dap::events::{StoppedEventBody, ExitedEventBody, TerminatedEventBody};
use dap::responses::{ReadMemoryResponse, SetExceptionBreakpointsResponse, ThreadsResponse, StackTraceResponse, ScopesResponse, VariablesResponse, ContinueResponse};
use dap::types::{StoppedEventReason, Thread, StackFrame, Scope, Source, Variable};
use elf::endian::{AnyEndian, LittleEndian};
use elf::section::SectionHeader;
use thiserror::Error;

use dap::prelude::*;
Expand All @@ -17,10 +20,16 @@ use exception::{ExecutionErrors, exception_pretty_print, ExecutionEvents};
mod lineinfo;
use lineinfo::{LineInfo, lineinfo_import};

mod syscall;

use base64::{Engine as _, engine::general_purpose};
use std::env;
use std::net::TcpListener;

use elf::ElfBytes;
use elf::segment::ProgramHeader;
use elf::abi::PT_LOAD;

#[derive(Error, Debug)]
enum MyAdapterError {
#[error("Unhandled command")]
Expand All @@ -38,20 +47,34 @@ enum MyAdapterError {

type DynResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

fn reset_mips(program_data: &[u8]) -> Mips {
fn reset_mips(elf_file: &Vec<u8>, elf_parsed: &ElfBytes<'_, LittleEndian>, segments: &Vec<ProgramHeader>) -> Mips {
// Reset execution and begin again.
let mut mips: Mips = Default::default();
let mut mips: Mips = Default::default();
mips.pc = elf_parsed.ehdr.e_entry as usize;

for (i, byte) in program_data.iter().enumerate() {
mips.write_b(mips::DOT_TEXT_START_ADDRESS + i as u32, *byte).unwrap();
for phdr in segments {
mips.memories.push((elf_file[phdr.p_offset as usize .. (phdr.p_offset + phdr.p_filesz) as usize].to_vec(), phdr.p_vaddr as u32, phdr.p_filesz as u32));

// WARNING: BROKEN
if elf_parsed.ehdr.e_entry == phdr.p_vaddr {
mips.stop_address = (phdr.p_vaddr + phdr.p_filesz) as usize;
}
}
mips.stop_address = mips::DOT_TEXT_START_ADDRESS as usize + program_data.len();

mips
}

fn main() -> DynResult<()> {


let elf_file_data = std::fs::read("/home/qwe/Documents/CS4485/Fibonacci_linked").unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded path

let elf_file = ElfBytes::<elf::endian::LittleEndian>::minimal_parse(elf_file_data.as_slice()).unwrap();
let elf_all_load_phdrs: Vec<ProgramHeader> = elf_file.segments().unwrap()
.iter()
.filter(|phdr|{phdr.p_type == PT_LOAD})
.collect();


let args_strings: Vec<String> = env::args().collect();

if args_strings.len() != 5 {
Expand Down Expand Up @@ -165,7 +188,7 @@ loop {

server.send_event(Event::Initialized)?;

mips = reset_mips(&program_data);
mips = reset_mips(&elf_file_data, &elf_file, &elf_all_load_phdrs);

}

Expand Down Expand Up @@ -427,7 +450,7 @@ loop {
}

Command::Restart(_) => {
mips = reset_mips(&program_data);
mips = reset_mips(&elf_file_data, &elf_file, &elf_all_load_phdrs);

let rsp = req.success(
ResponseBody::Restart
Expand Down Expand Up @@ -470,7 +493,9 @@ loop {
}
// OK, what happened?
let stopped_event_body = match mips.prev_ins_result {
Ok(()) => unreachable!(), // It's unreachable.
Ok(()) => {
unreachable!()// It's unreachable.
}
Err(what_happened) => match what_happened {
ExecutionErrors::Event{event} => match event {
ExecutionEvents::ProgramComplete => {
Expand Down
127 changes: 101 additions & 26 deletions name-emu/src/mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ use std::io::Cursor;
use std::fs::File;
use std::io::Write;

use crate::exception::{ExecutionErrors, ExecutionEvents};

pub const DOT_TEXT_START_ADDRESS: u32 = 0x00400000;
const DOT_TEXT_MAX_LENGTH: u32 = 0x1000;
const LEN_TEXT_INITIAL: usize = 200;
use crate::{exception::{ExecutionErrors, ExecutionEvents}, syscall::syscall};

const MIPS_INSTRUCTION_LENGTH: usize = 4;

pub const REGISTER_NAMES: [&str; 32] = [
pub const REGISTER_NAMES: [&str; 33] = [
"$zero",
"$at",
"$v0",
Expand Down Expand Up @@ -43,9 +41,12 @@ pub const REGISTER_NAMES: [&str; 32] = [
"$gp",
"$sp",
"$fp",
"$ra"
"$ra",
// See below constant. Used for exception printing
"Immediate"
];
pub const PC_NAME: &str = "$pc";
pub const IMMEDIATE_PRETTY_PRINT: usize = 32;

#[derive(Debug)]
enum BranchDelays {
Expand All @@ -54,6 +55,12 @@ enum BranchDelays {
Ready
}

// https://www.reddit.com/r/rust/comments/6175al/arbitrary_width_sign_extension_in_rust/
fn sign_extend(x: i32, nbits: u32) -> i32 {
let notherbits = std::mem::size_of_val(&x) as u32 * 8 - nbits;
x.wrapping_shl(notherbits).wrapping_shr(notherbits)
}

#[derive(Debug)]
pub(crate) struct Mips {
pub regs: [u32; 32],
Expand All @@ -64,7 +71,7 @@ pub(crate) struct Mips {

// Branch delay slots are implemented by filling this buffer with the
// branch target, which will be triggered after the following instruction
branch_delay_target: u32,
branch_delay_target: usize,
branch_delay_status: BranchDelays,


Expand All @@ -91,13 +98,11 @@ impl Default for Mips {
floats: [0f32; 32],
mult_hi: 0,
mult_lo: 0,
pc: DOT_TEXT_START_ADDRESS as usize,
pc: 0,
branch_delay_target: 0,
branch_delay_status: BranchDelays::NotActive,
memories: vec![
(vec![0; LEN_TEXT_INITIAL], DOT_TEXT_START_ADDRESS, DOT_TEXT_MAX_LENGTH)
],
stop_address: DOT_TEXT_START_ADDRESS as usize,
memories: vec![],
stop_address: 0,
prev_ins_result: Ok(())
}
}
Expand Down Expand Up @@ -150,6 +155,16 @@ impl Mips {
0x2 => {
self.regs[ins.rd] = self.regs[ins.rt] >> ins.shamt;
}
// Jump Register
0x8 => {
self.pc = self.regs[ins.rs] as usize;
}
// System Call
0xC => {
// Grab 20-bit code field
let code = (opcode >> 6) & 0xFFFFF;
syscall(self, code)?;
}
// Add
0x20 => {
let result = self.regs[ins.rt].checked_add(self.regs[ins.rs]);
Expand Down Expand Up @@ -204,11 +219,52 @@ impl Mips {
}
Ok(())
}

// This is a helper function for doing branches
fn configure_branch(&mut self, ins: Itype) {
self.branch_delay_target = self.pc.wrapping_add_signed(sign_extend(((ins.imm as u32) << 2) as i32, 18) as isize);
self.branch_delay_status = BranchDelays::Set;
}

fn dispatch_i(&mut self, ins: Itype, opcode: u32) -> Result<(), ExecutionErrors> {

let memory_address = (ins.rt as i64 + (ins.imm as i64)) as u32;
let memory_address = self.regs[ins.rs].wrapping_add(ins.imm as u32);

match ins.opcode {
// Branch on Less than Zero
// MIPS manual says: If the contents of GPR rs are less than zero (sign bit is 1)
0x6 => {
if self.regs[ins.rs] as i32 <= 0 {
self.configure_branch(ins);
}
}
// Branch on Greater than Zero
// MIPS manual says: If the contents of GPR rs
// are greater than zero (sign bit is 0 but value not zero)
0x7 => {
if self.regs[ins.rs] > 0 {
self.configure_branch(ins);
}
}
// Add Immediate
0x8 => {
let result = self.regs[ins.rs].checked_add_signed(ins.imm as i16 as i32);
match result {
Some(value) => {self.regs[ins.rt] = value;}
None => {
return Err(ExecutionErrors::IntegerOverflow {
rt: IMMEDIATE_PRETTY_PRINT,
rs: ins.rs,
value1: ins.imm as u32,
value2: self.regs[ins.rs]
});
}
}
}
// Add Immediate Unsigned
0x9 => {
self.regs[ins.rt] = self.regs[ins.rs].wrapping_add(ins.imm as u32);
}
// Set on Less Than Immediate (signed)
// If rs is less than sign-extended 16 bit immediate using signed comparison, then set rt to 1
// Casting on imm is to sign extend. See load byte casts
Expand Down Expand Up @@ -274,15 +330,13 @@ impl Mips {
// Branch if Equal
0x4 => {
if self.regs[ins.rt] == self.regs[ins.rs] {
self.branch_delay_target = (ins.imm as u32) << 2;
self.branch_delay_status = BranchDelays::Set;
self.configure_branch(ins);
}
}
// Branch if Not Equal
0x5 => {
if self.regs[ins.rt] != self.regs[ins.rs] {
self.branch_delay_target = (ins.imm as u32) << 2;
self.branch_delay_status = BranchDelays::Set;
self.configure_branch(ins);
}
}

Expand All @@ -299,14 +353,16 @@ impl Mips {
// Jump absolute
2 => {
self.branch_delay_status = BranchDelays::Set;
self.branch_delay_target = self.pc as u32 & 0xF0000000 | (ins.dest << 2);
self.branch_delay_target = (self.pc as u32 & 0xF0000000 | (ins.dest << 2)) as usize;
}
// Jump And Link
3 => {
self.branch_delay_status = BranchDelays::Set;
self.branch_delay_target = self.pc as u32 & 0xF0000000 | (ins.dest << 2);
self.branch_delay_target = (self.pc as u32 & 0xF0000000 | (ins.dest << 2)) as usize;
// $ra = register 31
self.regs[31] = self.pc as u32 + 8;

// CODE SMELL— This has to be adjusted when branch delays are turned off!!
self.regs[31] = self.pc as u32 + 4;
}
_ => return Err(ExecutionErrors::UndefinedInstruction {instruction: opcode})
}
Expand All @@ -316,7 +372,7 @@ impl Mips {

fn decode(&self, instruction: u32) -> Instructions {
let opcode = instruction >> 26 & 0b111111;
match opcode {
match opcode {
// R-type
0 => {
Instructions::R(Rtype {
Expand Down Expand Up @@ -392,6 +448,15 @@ impl Mips {
self.read_b(address + 2)?, self.read_b(address + 3)?];
Ok(Cursor::new(bytes).read_u32::<LittleEndian>().unwrap())
}
// Returns a reference to a block of memory, if it exists.
pub fn read_block(&mut self, address: u32, len: u32) -> Result<&[u8], ExecutionErrors> {
if let Some((memory, offset)) = self.map_memory(address) {
if memory.len() <= (len + offset) as usize {
return Ok(&memory[offset as usize .. (offset + len) as usize]);
}
}
Err(ExecutionErrors::MemoryIllegalAccess { load_address: address })
}


// Writes one byte
Expand All @@ -413,19 +478,29 @@ impl Mips {
let mut bytes = vec![];
bytes.write_u16::<LittleEndian>(value).unwrap();
self.write_b(address, bytes[0])?;
self.write_b(address, bytes[1])?;
self.write_b(address + 1, bytes[1])?;
Ok(())
}
// Writes a word in little endian form
pub fn write_w(&mut self, address: u32, value: u32) -> Result<(), ExecutionErrors> {
let mut bytes = vec![];
bytes.write_u32::<LittleEndian>(value).unwrap();
self.write_b(address, bytes[0])?;
self.write_b(address, bytes[1])?;
self.write_b(address, bytes[2])?;
self.write_b(address, bytes[3])?;
self.write_b(address + 1, bytes[1])?;
self.write_b(address + 2, bytes[2])?;
self.write_b(address + 3, bytes[3])?;
Ok(())
}
// Writes a block of memory, if it exists
pub fn write_block(&mut self, address: u32, len: u32, data: &[u8]) -> Result<(), ExecutionErrors> {
if let Some((memory, offset)) = self.map_memory(address) {
if memory.len() <= (len + offset) as usize {
memory[offset as usize .. (offset + len) as usize].copy_from_slice(data);
return Ok(())
}
}
Err(ExecutionErrors::MemoryIllegalAccess { load_address: address })
}

pub fn step_one(&mut self, mut f :&mut File) -> Result<(), ExecutionErrors> {
let opcode = self.read_w(self.pc as u32)?;
Expand Down Expand Up @@ -459,7 +534,7 @@ impl Mips {
BranchDelays::NotActive => (),
BranchDelays::Set => self.branch_delay_status = BranchDelays::Ready,
BranchDelays::Ready => {
self.pc = self.branch_delay_target as usize;
self.pc = self.branch_delay_target;
self.branch_delay_status = BranchDelays::NotActive;
}
}
Expand Down
Loading