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 slog;
|
||||
|
||||
pub struct Chip {
|
||||
cpu: CPU,
|
||||
rom: Box<[u8]>,
|
||||
ram: Box<[u8]>,
|
||||
log: slog::Logger,
|
||||
pub cpu: CPU,
|
||||
pub rom: Box<[u8]>,
|
||||
pub ram: Box<[u8]>,
|
||||
|
||||
// TODO: List of devices
|
||||
}
|
||||
|
||||
impl Chip {
|
||||
pub fn new(rom: Box<[u8]>) -> Chip {
|
||||
pub fn new(log: slog::Logger, rom: Box<[u8]>) -> Chip {
|
||||
Self {
|
||||
cpu: CPU::new(),
|
||||
log: log.clone(),
|
||||
cpu: CPU::new(log.clone()),
|
||||
rom: rom,
|
||||
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,
|
||||
UnsupportedAddress,
|
||||
DecodingError(decoder::DecodingError),
|
||||
Breakpoint,
|
||||
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)
|
||||
}
|
||||
|
||||
@ -242,7 +243,7 @@ impl CPU {
|
||||
|
||||
} else if addr == 0x320 || addr == 0x321 || addr == 0x322 {
|
||||
// DAC? @DD2E
|
||||
} else if addr == 0x230 || addr == 0x231 || addr == 0x234 || addr == 0x235 { // ADC
|
||||
} else if addr == 0x230 || addr == 0x231 || addr == 0x234 || addr == 0x235 { // ADC
|
||||
} else if addr >= 0x1f00 {
|
||||
|
||||
} else {
|
||||
@ -738,6 +739,9 @@ impl CPU {
|
||||
let rv = self.get_register(r);
|
||||
self.set_register(r, rv >> 4 | ((rv << 4) & 0xF0));
|
||||
},
|
||||
Instruction::BREAK => {
|
||||
return Err(CPUError::Breakpoint);
|
||||
}
|
||||
Instruction::NOP => {},
|
||||
_ => return Err(CPUError::UnimplementedInstruction)
|
||||
}
|
||||
|
||||
157
src/gdbstub.rs
157
src/gdbstub.rs
@ -1,9 +1,11 @@
|
||||
use std::collections::HashSet;
|
||||
use std;
|
||||
use std::net::TcpListener;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use slog;
|
||||
|
||||
use chip;
|
||||
use cpu;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -14,7 +16,7 @@ pub struct GDBPacket {
|
||||
/*
|
||||
At a minimum, a stub is required to support the ‘g’ and ‘G’ commands for register access, and the ‘m’ and ‘M’ commands for memory access.
|
||||
Stubs that only control single-threaded targets can implement run control with the ‘c’ (continue), and ‘s’ (step) commands.
|
||||
Stubs that support multi-threading targets should support the ‘vCont’ command. All other commands are optional.
|
||||
Stubs that support multi-threading targets should support the ‘vCont’ command. All other commands are optional.
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -55,7 +57,8 @@ impl GDBPacket {
|
||||
}
|
||||
|
||||
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))?;
|
||||
let p = GDBPacket {
|
||||
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{
|
||||
let r = cpu.step(rom, ram);
|
||||
match r {
|
||||
Ok(_) => {true}
|
||||
Err(ref e) => {
|
||||
warn!(log, "Error occured: {:?}", e);
|
||||
false
|
||||
}
|
||||
fn split_definitions(pkg: &str) -> Vec<(String, String)> {
|
||||
let mut res = Vec::new();
|
||||
for definition in pkg.split(";") {
|
||||
let mut v = definition.split(":");
|
||||
let first = v.nth(0).unwrap().to_string();
|
||||
res.push((first, v.collect::<String>()));
|
||||
}
|
||||
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};",
|
||||
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()
|
||||
}
|
||||
|
||||
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 mut conn = listener.incoming().nth(0).unwrap().unwrap();
|
||||
info!(log, "Debugger? attached.");
|
||||
|
||||
let mut breakpoints: HashSet<u32> = HashSet::new();
|
||||
|
||||
loop {
|
||||
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;
|
||||
}
|
||||
buf.push(s[0]);
|
||||
// warn!(log, "{:?}", std::str::from_utf8(&buf));
|
||||
match GDBPacket::from_packet(&buf) {
|
||||
Ok(_) => break 'a,
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
let pkg = GDBPacket::from_packet(&buf).unwrap();
|
||||
// warn!(log, "Got pkg: {:?}", pkg);
|
||||
warn!(log, "<- {:?}", std::str::from_utf8(&pkg.raw_data));
|
||||
// Send ACK
|
||||
{
|
||||
let s = [b'+'];
|
||||
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();
|
||||
|
||||
if pkg.raw_data[0] == b'q' {
|
||||
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 :(
|
||||
if query.chars().skip(1).take(9).collect::<String>() == "Supported" {
|
||||
response = "PacketSize=1024".as_bytes().to_vec();
|
||||
} else if pkg.raw_data[1] == b'C' {
|
||||
response = "0".as_bytes().to_vec();
|
||||
if query_data[0].0 == "Supported" {
|
||||
response = "qXfer:memory-map:read+;PacketSize=1024".as_bytes().to_vec();
|
||||
} else if query_data[0].0 == "Attached" {
|
||||
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 {
|
||||
// panic!("Unknown query");
|
||||
info!(log, "Unknown query: {}", query_data[0].0);
|
||||
}
|
||||
} 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();
|
||||
} else if pkg.raw_data[0] == b'?' {
|
||||
// S05 = Stopped cause of SIGTRAP.
|
||||
response = "S05".as_bytes().to_vec();
|
||||
} else if pkg.raw_data[0] == b'g' {
|
||||
// Read registers.
|
||||
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!("{:04X}", 0x1337u16.swap_bytes()).as_bytes().to_vec()); // TODO: SP
|
||||
response.extend(format!("{:08X}", (2*cpu.pc).swap_bytes()).as_bytes().to_vec());
|
||||
response.extend(format!("{:02X}", chip.cpu.sreg)
|
||||
.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' {
|
||||
// TODO: Optional PC argument?
|
||||
if !step(&log, cpu, rom, ram) {
|
||||
let resume_from = std::str::from_utf8(&pkg.raw_data[1..])
|
||||
.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
|
||||
}
|
||||
response = stop_reply(cpu);
|
||||
response = stop_reply(&chip);
|
||||
} else if pkg.raw_data[0] == b'c' {
|
||||
while step(&log, cpu, rom, ram) {}
|
||||
response = stop_reply(cpu);
|
||||
let resume_from = std::str::from_utf8(&pkg.raw_data[1..])
|
||||
.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' {
|
||||
// Read memory
|
||||
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.
|
||||
if addr & 0x00f00000 > 0 {
|
||||
// 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 {
|
||||
// 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 {
|
||||
info!(log, "Unknown cmd: {}", pkg.raw_data[0]);
|
||||
// Unknown
|
||||
@ -228,8 +309,8 @@ fn main() {
|
||||
println!("Sample pkg: {:?}", String::from_utf8_lossy(&GDBPacket { raw_data: vec![]}.to_packet_format()));
|
||||
let pkg = GDBPacket::from_packet(&"$#00".as_bytes().iter().map(|v| *v).collect::<Vec<_>>()).expect("Could not parse pkg");
|
||||
|
||||
// Handler for g: Read general registers.
|
||||
// Each byte of register data is described by two hex digits. The bytes with the register are transmitted in target byte order. The size of each register and their position within the ‘g’ packet are determined by the GDB internal gdbarch functions DEPRECATED_REGISTER_RAW_SIZE and gdbarch_register_name.
|
||||
// Handler for g: Read general registers.
|
||||
// Each byte of register data is described by two hex digits. The bytes with the register are transmitted in target byte order. The size of each register and their position within the ‘g’ packet are determined by the GDB internal gdbarch functions DEPRECATED_REGISTER_RAW_SIZE and gdbarch_register_name.
|
||||
// From megumi: 35 value,s total 39 bytes
|
||||
// 0-31: Regular regs
|
||||
// 33 SREG
|
||||
@ -241,4 +322,4 @@ fn main() {
|
||||
// m: addr:hex,len:hex
|
||||
// s c
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
13
src/main.rs
13
src/main.rs
@ -29,14 +29,15 @@ fn main() {
|
||||
);
|
||||
info!(log, "AVREmu starting up");
|
||||
|
||||
let mut 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 rom = read_file(std::env::args().nth(1).unwrap_or("rom.bin".to_string())).unwrap();
|
||||
|
||||
let mut chip = chip::Chip::new(log.clone(), rom);
|
||||
|
||||
// Use GDBStub
|
||||
info!(log, "Enabling GDB backend");
|
||||
gdbstub::run(log.clone(), &mut cpu, &mut rom, &mut ram);
|
||||
warn!(log, "{}", cpu);
|
||||
write_file("ram.dmp", &ram).unwrap();
|
||||
gdbstub::run(log.clone(), &mut chip);
|
||||
warn!(log, "{}", &chip.cpu);
|
||||
write_file("ram.dmp", &chip.ram).unwrap();
|
||||
}
|
||||
|
||||
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user