A lot more stuff - GDB wtf
This commit is contained in:
parent
87cbf73330
commit
8f52833a10
26
src/chip.rs
26
src/chip.rs
@ -1,21 +1,33 @@
|
|||||||
/*
|
|
||||||
use cpu::CPU;
|
use cpu::CPU;
|
||||||
|
|
||||||
|
use slog;
|
||||||
|
|
||||||
pub struct Chip {
|
pub struct Chip {
|
||||||
cpu: CPU,
|
log: slog::Logger,
|
||||||
rom: Box<[u8]>,
|
pub cpu: CPU,
|
||||||
ram: Box<[u8]>,
|
pub rom: Box<[u8]>,
|
||||||
|
pub ram: Box<[u8]>,
|
||||||
|
|
||||||
// TODO: List of devices
|
// TODO: List of devices
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip {
|
impl Chip {
|
||||||
pub fn new(rom: Box<[u8]>) -> Chip {
|
pub fn new(log: slog::Logger, rom: Box<[u8]>) -> Chip {
|
||||||
Self {
|
Self {
|
||||||
cpu: CPU::new(),
|
log: log.clone(),
|
||||||
|
cpu: CPU::new(log.clone()),
|
||||||
rom: rom,
|
rom: rom,
|
||||||
ram: Box::new([0u8; 8 * 1024 + 1024]),
|
ram: Box::new([0u8; 8 * 1024 + 1024]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn step(&mut self) -> bool {
|
||||||
|
match self.cpu.step(&mut self.rom, &mut self.ram) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(ref e) => {
|
||||||
|
warn!(self.log, "Error occured: {:?}", e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
@ -17,6 +17,7 @@ pub enum CPUError {
|
|||||||
OutOfBoundsException,
|
OutOfBoundsException,
|
||||||
UnsupportedAddress,
|
UnsupportedAddress,
|
||||||
DecodingError(decoder::DecodingError),
|
DecodingError(decoder::DecodingError),
|
||||||
|
Breakpoint,
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sp(&self, mem: &[u8]) -> u16 {
|
pub fn get_sp(&self, mem: &[u8]) -> u16 {
|
||||||
mem[chip_definitions::IOAdress::SPL as usize] as u16 | ((mem[chip_definitions::IOAdress::SPH as usize] as u16) << 8)
|
mem[chip_definitions::IOAdress::SPL as usize] as u16 | ((mem[chip_definitions::IOAdress::SPH as usize] as u16) << 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,6 +739,9 @@ impl CPU {
|
|||||||
let rv = self.get_register(r);
|
let rv = self.get_register(r);
|
||||||
self.set_register(r, rv >> 4 | ((rv << 4) & 0xF0));
|
self.set_register(r, rv >> 4 | ((rv << 4) & 0xF0));
|
||||||
},
|
},
|
||||||
|
Instruction::BREAK => {
|
||||||
|
return Err(CPUError::Breakpoint);
|
||||||
|
}
|
||||||
Instruction::NOP => {},
|
Instruction::NOP => {},
|
||||||
_ => return Err(CPUError::UnimplementedInstruction)
|
_ => return Err(CPUError::UnimplementedInstruction)
|
||||||
}
|
}
|
||||||
|
|||||||
149
src/gdbstub.rs
149
src/gdbstub.rs
@ -1,9 +1,11 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std;
|
use std;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use slog;
|
use slog;
|
||||||
|
|
||||||
|
use chip;
|
||||||
use cpu;
|
use cpu;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -55,7 +57,8 @@ impl GDBPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let checksum = u8::from_str_radix(
|
let checksum = u8::from_str_radix(
|
||||||
std::str::from_utf8(&checksum).map_err(|_| (GDBPacketError::InvalidFormat))?, 16)
|
std::str::from_utf8(&checksum)
|
||||||
|
.map_err(|_| (GDBPacketError::InvalidFormat))?, 16)
|
||||||
.map_err(|_| (GDBPacketError::InvalidFormat))?;
|
.map_err(|_| (GDBPacketError::InvalidFormat))?;
|
||||||
let p = GDBPacket {
|
let p = GDBPacket {
|
||||||
raw_data: decoded_data.clone()
|
raw_data: decoded_data.clone()
|
||||||
@ -93,28 +96,36 @@ impl GDBPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(log: &slog::Logger, cpu: &mut cpu::CPU, rom: &mut [u8], ram: &mut [u8]) -> bool{
|
fn split_definitions(pkg: &str) -> Vec<(String, String)> {
|
||||||
let r = cpu.step(rom, ram);
|
let mut res = Vec::new();
|
||||||
match r {
|
for definition in pkg.split(";") {
|
||||||
Ok(_) => {true}
|
let mut v = definition.split(":");
|
||||||
Err(ref e) => {
|
let first = v.nth(0).unwrap().to_string();
|
||||||
warn!(log, "Error occured: {:?}", e);
|
res.push((first, v.collect::<String>()));
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_reply(cpu: &cpu::CPU) -> Vec<u8> {
|
/*
|
||||||
|
struct GDBStub {
|
||||||
|
chip: &mut chip::Chip,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn stop_reply(chip: &chip::Chip) -> Vec<u8> {
|
||||||
|
// Send SIGTRAP along with SREG/SP/PC.
|
||||||
format!("T0520:{:02X};21:{:04X};22:{:08X};",
|
format!("T0520:{:02X};21:{:04X};22:{:08X};",
|
||||||
cpu.sreg, 1337u16.swap_bytes(), (2 * cpu.pc).swap_bytes()
|
chip.cpu.sreg, chip.cpu.get_sp(&chip.ram).swap_bytes(),
|
||||||
|
(2 * chip.cpu.pc).swap_bytes()
|
||||||
).as_bytes().to_vec()
|
).as_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(log: slog::Logger, cpu: &mut cpu::CPU, rom: &mut [u8], ram: &mut [u8]) {
|
pub fn run(log: slog::Logger, chip: &mut chip::Chip) {
|
||||||
let listener = TcpListener::bind("0.0.0.0:1234").unwrap();
|
let listener = TcpListener::bind("0.0.0.0:1234").unwrap();
|
||||||
let mut conn = listener.incoming().nth(0).unwrap().unwrap();
|
let mut conn = listener.incoming().nth(0).unwrap().unwrap();
|
||||||
info!(log, "Debugger? attached.");
|
info!(log, "Debugger? attached.");
|
||||||
|
|
||||||
|
let mut breakpoints: HashSet<u32> = HashSet::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
@ -128,16 +139,13 @@ pub fn run(log: slog::Logger, cpu: &mut cpu::CPU, rom: &mut [u8], ram: &mut [u8]
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
buf.push(s[0]);
|
buf.push(s[0]);
|
||||||
// warn!(log, "{:?}", std::str::from_utf8(&buf));
|
|
||||||
match GDBPacket::from_packet(&buf) {
|
match GDBPacket::from_packet(&buf) {
|
||||||
Ok(_) => break 'a,
|
Ok(_) => break 'a,
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let pkg = GDBPacket::from_packet(&buf).unwrap();
|
let pkg = GDBPacket::from_packet(&buf).unwrap();
|
||||||
// warn!(log, "Got pkg: {:?}", pkg);
|
|
||||||
warn!(log, "<- {:?}", std::str::from_utf8(&pkg.raw_data));
|
warn!(log, "<- {:?}", std::str::from_utf8(&pkg.raw_data));
|
||||||
// Send ACK
|
|
||||||
{
|
{
|
||||||
let s = [b'+'];
|
let s = [b'+'];
|
||||||
if conn.write(&s).unwrap() != 1 {
|
if conn.write(&s).unwrap() != 1 {
|
||||||
@ -146,39 +154,68 @@ pub fn run(log: slog::Logger, cpu: &mut cpu::CPU, rom: &mut [u8], ram: &mut [u8]
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut response = Vec::new();
|
let mut response = Vec::new();
|
||||||
|
|
||||||
if pkg.raw_data[0] == b'q' {
|
if pkg.raw_data[0] == b'q' {
|
||||||
let query = std::str::from_utf8(&pkg.raw_data).unwrap();
|
let query = std::str::from_utf8(&pkg.raw_data).unwrap();
|
||||||
info!(log, "Got query: {}", query);
|
let query_data = split_definitions(&query[1..]);
|
||||||
// TODO: Let's do this right :(
|
// TODO: Let's do this right :(
|
||||||
if query.chars().skip(1).take(9).collect::<String>() == "Supported" {
|
if query_data[0].0 == "Supported" {
|
||||||
response = "PacketSize=1024".as_bytes().to_vec();
|
response = "qXfer:memory-map:read+;PacketSize=1024".as_bytes().to_vec();
|
||||||
} else if pkg.raw_data[1] == b'C' {
|
} else if query_data[0].0 == "Attached" {
|
||||||
response = "0".as_bytes().to_vec();
|
response = "1".as_bytes().to_vec();
|
||||||
|
} else if query_data[0].0 == "Xfer" {// && query_data[0].1.find("memory-map:read").is_some() {
|
||||||
|
response = format!(
|
||||||
|
"l<memory-map>\n<memory type='ram' start='0x800000' length='0x{:X}' />\n\
|
||||||
|
<memory type='flash' start='0' length='0x{:X}'>\n\
|
||||||
|
<property name='blocksize'>0x80</property>\n</memory></memory-map>", chip.rom.len(), chip.ram.len()
|
||||||
|
).as_bytes().to_vec();
|
||||||
|
} else if query_data[0].0 == "C" {
|
||||||
|
response = "01".as_bytes().to_vec();
|
||||||
} else {
|
} else {
|
||||||
// panic!("Unknown query");
|
info!(log, "Unknown query: {}", query_data[0].0);
|
||||||
}
|
}
|
||||||
} else if pkg.raw_data[0] == b'H' {
|
} else if pkg.raw_data[0] == b'H' {
|
||||||
// TODO: Make sure we have the right stuff here.
|
// Set thread - we only support one thread thus we ignore this.
|
||||||
response = "OK".as_bytes().to_vec();
|
response = "OK".as_bytes().to_vec();
|
||||||
} else if pkg.raw_data[0] == b'?' {
|
} else if pkg.raw_data[0] == b'?' {
|
||||||
|
// S05 = Stopped cause of SIGTRAP.
|
||||||
response = "S05".as_bytes().to_vec();
|
response = "S05".as_bytes().to_vec();
|
||||||
} else if pkg.raw_data[0] == b'g' {
|
} else if pkg.raw_data[0] == b'g' {
|
||||||
|
// Read registers.
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
response.extend(format!("{:02X}", cpu.registers[i]).as_bytes().to_vec());
|
response.extend(format!("{:02X}", chip.cpu.registers[i])
|
||||||
|
.as_bytes().to_vec());
|
||||||
}
|
}
|
||||||
response.extend(format!("{:02X}", cpu.sreg).as_bytes().to_vec());
|
response.extend(format!("{:02X}", chip.cpu.sreg)
|
||||||
response.extend(format!("{:04X}", 0x1337u16.swap_bytes()).as_bytes().to_vec()); // TODO: SP
|
.as_bytes().to_vec());
|
||||||
response.extend(format!("{:08X}", (2*cpu.pc).swap_bytes()).as_bytes().to_vec());
|
response.extend(format!("{:04X}", chip.cpu.get_sp(&chip.ram).swap_bytes())
|
||||||
|
.as_bytes().to_vec());
|
||||||
|
response.extend(format!("{:08X}", (2 * chip.cpu.pc).swap_bytes())
|
||||||
|
.as_bytes().to_vec());
|
||||||
} else if pkg.raw_data[0] == b's' {
|
} else if pkg.raw_data[0] == b's' {
|
||||||
// TODO: Optional PC argument?
|
let resume_from = std::str::from_utf8(&pkg.raw_data[1..])
|
||||||
if !step(&log, cpu, rom, ram) {
|
.unwrap_or("");
|
||||||
|
let resume_from = u32::from_str_radix(resume_from, 16);
|
||||||
|
if let Ok(pc) = resume_from {
|
||||||
|
chip.cpu.pc = pc;
|
||||||
|
}
|
||||||
|
if !chip.step() {
|
||||||
// ERR
|
// ERR
|
||||||
}
|
}
|
||||||
response = stop_reply(cpu);
|
response = stop_reply(&chip);
|
||||||
} else if pkg.raw_data[0] == b'c' {
|
} else if pkg.raw_data[0] == b'c' {
|
||||||
while step(&log, cpu, rom, ram) {}
|
let resume_from = std::str::from_utf8(&pkg.raw_data[1..])
|
||||||
response = stop_reply(cpu);
|
.unwrap_or("");
|
||||||
|
let resume_from = u32::from_str_radix(resume_from, 16);
|
||||||
|
if let Ok(pc) = resume_from {
|
||||||
|
chip.cpu.pc = pc;
|
||||||
|
}
|
||||||
|
while chip.step() {
|
||||||
|
// Maximum efficiency.
|
||||||
|
if breakpoints.contains(&chip.cpu.pc) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = stop_reply(&chip);
|
||||||
} else if pkg.raw_data[0] == b'm' {
|
} else if pkg.raw_data[0] == b'm' {
|
||||||
// Read memory
|
// Read memory
|
||||||
let full_cmd = std::str::from_utf8(&pkg.raw_data).unwrap().chars().skip(1).collect::<String>();
|
let full_cmd = std::str::from_utf8(&pkg.raw_data).unwrap().chars().skip(1).collect::<String>();
|
||||||
@ -196,12 +233,56 @@ pub fn run(log: slog::Logger, cpu: &mut cpu::CPU, rom: &mut [u8], ram: &mut [u8]
|
|||||||
// TODO: Overflow checks.
|
// TODO: Overflow checks.
|
||||||
if addr & 0x00f00000 > 0 {
|
if addr & 0x00f00000 > 0 {
|
||||||
// RAM
|
// RAM
|
||||||
response.extend(format!("{:02X}", ram[addr & 0xFFFFF]).as_bytes().to_vec());
|
response.extend(format!("{:02X}", chip.ram[addr & 0xFFFFF]).as_bytes().to_vec());
|
||||||
} else {
|
} else {
|
||||||
// ROM
|
// ROM
|
||||||
response.extend(format!("{:02X}", rom[addr]).as_bytes().to_vec());
|
response.extend(format!("{:02X}", chip.rom[addr]).as_bytes().to_vec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if pkg.raw_data[0] == b'M' {
|
||||||
|
// Write memory
|
||||||
|
let full_cmd = std::str::from_utf8(&pkg.raw_data).unwrap().chars().skip(1).collect::<String>();
|
||||||
|
let addrlen_content = full_cmd.split(":").collect::<Vec<_>>();
|
||||||
|
let parts = addrlen_content[0].split(",").collect::<Vec<_>>();
|
||||||
|
let value = addrlen_content[1];
|
||||||
|
let mem_addr = usize::from_str_radix(parts[0], 16).unwrap();
|
||||||
|
let len = usize::from_str_radix(parts[1], 16).unwrap();
|
||||||
|
for i in 0..len {
|
||||||
|
// Copied from megumi again <3
|
||||||
|
// GDB uses a special addressing to allow addressing of flash, SRAM, etc.
|
||||||
|
// - flash starts at 0x00000000
|
||||||
|
// - SRAM starts at 0x00800000
|
||||||
|
// - mask for memory space is 0x00f00000
|
||||||
|
// Constants used below are retrieved from GDB sources, in avr-tdep.c.
|
||||||
|
let addr = mem_addr.wrapping_add(i);
|
||||||
|
// Very hax wow
|
||||||
|
if addr & 0x00f00000 > 0 {
|
||||||
|
chip.ram[addr & 0xFFFFF] = u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap();
|
||||||
|
} else {
|
||||||
|
// ROM
|
||||||
|
chip.rom[addr & 0xFFFFF] = u8::from_str_radix(&value[2 * i..2 * (i + 1)], 16).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if pkg.raw_data[0] == b'z' || pkg.raw_data[0] == b'Z' {
|
||||||
|
// insert(Z)/remove(z) breakpoint.
|
||||||
|
let d = std::str::from_utf8(&pkg.raw_data[1..]).unwrap();
|
||||||
|
let values = d.split(",").collect::<Vec<_>>();
|
||||||
|
let bp_type = values[0];
|
||||||
|
let bp_addr = u32::from_str_radix(&values[1], 16).unwrap();
|
||||||
|
let bp_kind = values[2];
|
||||||
|
if pkg.raw_data[0] == b'z' {
|
||||||
|
breakpoints.remove(&bp_addr);
|
||||||
|
} else {
|
||||||
|
breakpoints.insert(bp_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if pkg.raw_data[0] == b'v' {
|
||||||
|
let word = std::str::from_utf8(&pkg.raw_data[1..]).unwrap();
|
||||||
|
let word_payload = word.split(";").collect::<Vec<_>>();
|
||||||
|
let word = word_payload[0];
|
||||||
|
if word == "MustReplyEmpty" {
|
||||||
|
// Empty reply ;)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
info!(log, "Unknown cmd: {}", pkg.raw_data[0]);
|
info!(log, "Unknown cmd: {}", pkg.raw_data[0]);
|
||||||
// Unknown
|
// Unknown
|
||||||
|
|||||||
13
src/main.rs
13
src/main.rs
@ -29,14 +29,15 @@ fn main() {
|
|||||||
);
|
);
|
||||||
info!(log, "AVREmu starting up");
|
info!(log, "AVREmu starting up");
|
||||||
|
|
||||||
let mut rom = read_file(std::env::args().nth(1).unwrap_or("rom.bin".to_string())).unwrap();
|
let rom = read_file(std::env::args().nth(1).unwrap_or("rom.bin".to_string())).unwrap();
|
||||||
let mut ram = [0u8; 8 * 1024 + 8 * 1024];
|
|
||||||
let mut cpu = cpu::CPU::new(log.clone());
|
|
||||||
|
|
||||||
|
let mut chip = chip::Chip::new(log.clone(), rom);
|
||||||
|
|
||||||
|
// Use GDBStub
|
||||||
info!(log, "Enabling GDB backend");
|
info!(log, "Enabling GDB backend");
|
||||||
gdbstub::run(log.clone(), &mut cpu, &mut rom, &mut ram);
|
gdbstub::run(log.clone(), &mut chip);
|
||||||
warn!(log, "{}", cpu);
|
warn!(log, "{}", &chip.cpu);
|
||||||
write_file("ram.dmp", &ram).unwrap();
|
write_file("ram.dmp", &chip.ram).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user