From 85db28dac6453571758ff7d7c02655fc622cb943 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 17 Oct 2020 05:41:33 -0700 Subject: [PATCH] core: debuggger: load symbols from elf files Former-commit-id: 3b20be6ecff9d540f7ba0c76d9762f87fac81998 Former-commit-id: 8b08fb90c5c163479c8318dd01f1f92fab475efc --- core/Cargo.toml | 4 +- core/src/debugger/command.rs | 130 +++++++++++++++++++++++++++++------ core/src/debugger/mod.rs | 3 + core/src/sysbus.rs | 4 ++ 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index c9f5dab..cc36724 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -53,9 +53,9 @@ criterion = "0.3" [features] default = ["arm7tdmi_dispatch_table"] -debugger = ["nom", "rustyline", "fuzzy-matcher"] -gdb = ["gdbstub"] elf_support = ["goblin"] +debugger = ["nom", "rustyline", "fuzzy-matcher", "elf_support"] +gdb = ["gdbstub"] # Uses lookup tables when executing instructions instead of `match` statements. # Faster, but consumes more memory. arm7tdmi_dispatch_table = [] diff --git a/core/src/debugger/command.rs b/core/src/debugger/command.rs index b61184e..00b6a77 100644 --- a/core/src/debugger/command.rs +++ b/core/src/debugger/command.rs @@ -1,4 +1,5 @@ -use std::path::Path; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; use std::time; use crate::arm7tdmi::arm::ArmInstruction; @@ -19,6 +20,8 @@ use fuzzy_matcher::FuzzyMatcher; use hexdump; +use goblin; + #[derive(Debug, PartialEq, Clone, Copy)] pub enum DisassMode { ModeArm, @@ -64,15 +67,43 @@ pub enum Command { TraceToggle(TraceFlags), SaveState(String), LoadState(String), + AddSymbolsFile(PathBuf, Option), ListSymbols(Option), } +fn find_nearest_symbol(addr: u32, symbols: &HashMap) -> Option<(String, u32)> { + let mut smallest_distance = u32::MAX; + let mut symbol = String::new(); + + for (k, v) in symbols.iter().filter(|(_k, v)| **v > addr) { + let distance = v - addr; + if distance < smallest_distance { + smallest_distance = distance; + symbol = k.to_string(); + } + } + + if smallest_distance < 0x1000 { + let symaddr = *symbols.get(&symbol).unwrap(); + Some((symbol, symaddr)) + } else { + None + } +} + impl Debugger { pub fn run_command(&mut self, command: Command) { use Command::*; #[allow(unreachable_patterns)] match command { Info => { + let pc = self.gba.cpu.pc; + if let Some((sym, addr)) = find_nearest_symbol(pc, &self.symbols) { + println!("PC at {}+{:#x} ({:08x})", sym, addr - pc, pc); + } else { + println!("PC at {:08x}", pc); + } + println!("{}", self.gba.cpu); println!("IME={}", self.gba.sysbus.io.intc.interrupt_master_enable); println!("IE={:#?}", self.gba.sysbus.io.intc.interrupt_enable); @@ -87,13 +118,20 @@ impl Debugger { self.gba.cpu.step(&mut self.gba.sysbus); } if let Some(last_executed) = &self.gba.cpu.last_executed { + let pc = last_executed.get_pc(); + let symbol = + self.symbols + .iter() + .find_map(|(key, &val)| if val == pc { Some(key) } else { None }); + + let text = if let Some(symbol) = symbol { + format!("Executed at {} @0x{:08x}:", symbol, pc) + } else { + format!("Executed at @0x{:08x}:", pc) + }; print!( "{}\t{}", - Colour::Black - .bold() - .italic() - .on(Colour::White) - .paint(format!("Executed at @0x{:08x}:", last_executed.get_pc(),)), + Colour::Black.bold().italic().on(Colour::White).paint(text), last_executed ); println!( @@ -222,30 +260,45 @@ impl Debugger { let save = read_bin_file(&Path::new(&load_path)) .expect("failed to read save state from file"); self.gba - .restore_state(&save) + .restore_state(&save, Box::from(self.gba.sysbus.get_bios())) .expect("failed to deserialize"); } ListSymbols(Some(pattern)) => { - if let Some(symbols) = self.gba.sysbus.cartridge.get_symbols() { - let matcher = SkimMatcherV2::default(); - for (k, v) in symbols - .iter() - .filter(|(k, _v)| matcher.fuzzy_match(k, &pattern).is_some()) - { - println!("{}=0x{:08x}", k, v); - } - } else { - println!("symbols not loaded!"); + let matcher = SkimMatcherV2::default(); + for (k, v) in self + .symbols + .iter() + .filter(|(k, _v)| matcher.fuzzy_match(k, &pattern).is_some()) + { + println!("{}=0x{:08x}", k, v); } } ListSymbols(None) => { - if let Some(symbols) = self.gba.sysbus.cartridge.get_symbols() { - for (k, v) in symbols.iter() { - println!("{}=0x{:08x}", k, v); + for (k, v) in self.symbols.iter() { + println!("{}=0x{:08x}", k, v); + } + } + AddSymbolsFile(elf_file, offset) => { + let offset = offset.unwrap_or(0); + if let Ok(elf_buffer) = read_bin_file(&elf_file) { + if let Ok(elf) = goblin::elf::Elf::parse(&elf_buffer) { + let strtab = elf.strtab; + for sym in elf.syms.iter() { + if let Some(Ok(name)) = strtab.get(sym.st_name) { + self.symbols + .insert(name.to_owned(), offset + (sym.st_value as u32)); + } else { + warn!("failed to parse symbol name sym {:?}", sym); + } + } + } else { + println!("[error] Failed to parse elf file!"); + return; } } else { - println!("symbols not loaded!"); - } + println!("[error] Can't read elf file!"); + return; + }; } _ => println!("Not Implemented",), } @@ -493,6 +546,39 @@ impl Debugger { } } } + "add-symbols-file" | "load-symbols" | "load-syms" => match args.len() { + 1 => { + if let Value::Identifier(elf_file) = &args[0] { + Ok(Command::AddSymbolsFile(PathBuf::from(elf_file), None)) + } else { + Err(DebuggerError::InvalidArgument(String::from( + "expected a filename", + ))) + } + } + 2 => { + if let Value::Identifier(elf_file) = &args[0] { + if let Value::Num(offset) = &args[1] { + Ok(Command::AddSymbolsFile( + PathBuf::from(elf_file), + Some(*offset), + )) + } else { + Err(DebuggerError::InvalidArgument(String::from( + "expected a number", + ))) + } + } else { + Err(DebuggerError::InvalidArgument(String::from( + "expected a filename", + ))) + } + } + _ => Err(DebuggerError::InvalidCommandFormat(format!( + "usage: {} path/to/elf [offset]", + command + ))), + }, "list-symbols" | "list-syms" | "symbols" | "syms" => match args.len() { 0 => Ok(Command::ListSymbols(None)), 1 => { diff --git a/core/src/debugger/mod.rs b/core/src/debugger/mod.rs index ab8766c..729709f 100644 --- a/core/src/debugger/mod.rs +++ b/core/src/debugger/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs::File; use std::io::{prelude::*, BufReader}; @@ -39,6 +40,7 @@ pub struct Debugger { pub gba: GameBoyAdvance, running: bool, pub previous_command: Option, + pub symbols: HashMap, } impl Debugger { @@ -47,6 +49,7 @@ impl Debugger { gba: gba, running: false, previous_command: None, + symbols: HashMap::new(), } } diff --git a/core/src/sysbus.rs b/core/src/sysbus.rs index 60e994c..553e528 100644 --- a/core/src/sysbus.rs +++ b/core/src/sysbus.rs @@ -231,6 +231,10 @@ impl SysBus { self.internal_work_ram.mem = buffer; } + pub fn get_bios(&self) -> &[u8] { + &self.bios.mem + } + pub fn get_ewram(&self) -> &[u8] { &self.onboard_work_ram.mem }