A lot more stuff - GDB wtf

This commit is contained in:
Edward 2018-02-15 23:51:50 +01:00
parent 87cbf73330
commit 8f52833a10
4 changed files with 151 additions and 53 deletions

View File

@ -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
}
}
}
} }
*/

View File

@ -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)
} }
@ -242,7 +243,7 @@ impl CPU {
} else if addr == 0x320 || addr == 0x321 || addr == 0x322 { } else if addr == 0x320 || addr == 0x321 || addr == 0x322 {
// DAC? @DD2E // 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 if addr >= 0x1f00 {
} else { } else {
@ -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)
} }

View File

@ -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)]
@ -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. 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 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)] #[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
@ -228,8 +309,8 @@ fn main() {
println!("Sample pkg: {:?}", String::from_utf8_lossy(&GDBPacket { raw_data: vec![]}.to_packet_format())); 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"); 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. // 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. // 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 // From megumi: 35 value,s total 39 bytes
// 0-31: Regular regs // 0-31: Regular regs
// 33 SREG // 33 SREG
@ -241,4 +322,4 @@ fn main() {
// m: addr:hex,len:hex // m: addr:hex,len:hex
// s c // s c
} }
*/ */

View File

@ -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> {