mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-09 22:29:30 +00:00
Improve the command line debugger.
Add next command. Make the debugger somewhat foolproof.
This commit is contained in:
parent
6428f324f6
commit
403c19ca39
|
@ -7,6 +7,7 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <functional> /* without this, MSVC doesn't understand std::function */
|
||||
#include "ppcdisasm.h"
|
||||
|
||||
|
@ -1796,6 +1797,10 @@ static std::function<void(PPCDisasmContext*)> OpcodeDispatchTable[64] = {
|
|||
|
||||
string disassemble_single(PPCDisasmContext* ctx)
|
||||
{
|
||||
if (ctx->instr_addr & 3) {
|
||||
throw std::invalid_argument(string("PPC instruction address must be a multiply of 4!"));
|
||||
}
|
||||
|
||||
OpcodeDispatchTable[ctx->instr_code >> 26](ctx);
|
||||
|
||||
ctx->instr_addr += 4;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define PPCEMU_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include <setjmp.h>
|
||||
#include "endianswap.h"
|
||||
#include "devices/memctrlbase.h"
|
||||
|
@ -664,4 +665,10 @@ extern void ppc_exec(void);
|
|||
extern void ppc_exec_single(void);
|
||||
extern void ppc_exec_until(uint32_t goal_addr);
|
||||
|
||||
/* debugging support API */
|
||||
void print_gprs(void); /* print content of the general purpose registers */
|
||||
void print_fprs(void); /* print content of the floating-point registers */
|
||||
uint64_t get_reg(std::string ®_name); /* get content of the register reg_name */
|
||||
void set_reg(std::string ®_name, uint64_t val); /* set reg_name to val */
|
||||
|
||||
#endif /* PPCEMU_H */
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
//if you want to distribute this.
|
||||
//(divingkatae#1017 or powermax#2286 on Discord)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
#include <setjmp.h>
|
||||
|
@ -12,6 +17,8 @@
|
|||
#include "ppcemu.h"
|
||||
#include "ppcmmu.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
MemCtrlBase *mem_ctrl_instance = 0;
|
||||
|
||||
bool power_on = 1;
|
||||
|
@ -788,3 +795,129 @@ void ppc_cpu_init(uint32_t proc_version)
|
|||
/* redirect code execution to reset vector */
|
||||
ppc_state.ppc_pc = 0xFFF00100;
|
||||
}
|
||||
|
||||
void print_gprs()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
cout << "GPR " << dec << i << " : " << hex << ppc_state.ppc_gpr[i] << endl;
|
||||
|
||||
cout << "PC: " << hex << ppc_state.ppc_pc << endl;
|
||||
cout << "LR: " << hex << ppc_state.ppc_spr[SPR::LR] << endl;
|
||||
cout << "CR: " << hex << ppc_state.ppc_cr << endl;
|
||||
cout << "CTR: " << hex << ppc_state.ppc_spr[SPR::CTR] << endl;
|
||||
cout << "XER: " << hex << ppc_state.ppc_spr[SPR::XER] << endl;
|
||||
cout << "MSR: " << hex << ppc_state.ppc_msr << endl;
|
||||
}
|
||||
|
||||
void print_fprs()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
cout << "FPR " << dec << i << " : " << ppc_state.ppc_fpr[i].dbl64_r << endl;
|
||||
}
|
||||
|
||||
static map<string, int> SPRName2Num = {
|
||||
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, {"DEC", SPR::DEC},
|
||||
{"PVR", SPR::PVR}
|
||||
};
|
||||
|
||||
uint64_t reg_op(string ®_name, uint64_t val, bool is_write)
|
||||
{
|
||||
string reg_name_u, reg_num_str;
|
||||
unsigned reg_num;
|
||||
map<string, int>::iterator spr;
|
||||
|
||||
if (reg_name.length() < 2)
|
||||
goto bail_out;
|
||||
|
||||
reg_name_u = reg_name;
|
||||
|
||||
/* convert reg_name string to uppercase */
|
||||
std::for_each(reg_name_u.begin(), reg_name_u.end(), [](char & c) {
|
||||
c = ::toupper(c);
|
||||
});
|
||||
|
||||
try {
|
||||
if (reg_name_u == "PC") {
|
||||
if (is_write)
|
||||
ppc_state.ppc_pc = val;
|
||||
return ppc_state.ppc_pc;
|
||||
}
|
||||
if (reg_name_u == "MSR") {
|
||||
if (is_write)
|
||||
ppc_state.ppc_msr = val;
|
||||
return ppc_state.ppc_msr;
|
||||
}
|
||||
if (reg_name_u == "CR") {
|
||||
if (is_write)
|
||||
ppc_state.ppc_cr = val;
|
||||
return ppc_state.ppc_cr;
|
||||
}
|
||||
if (reg_name_u == "FPSCR") {
|
||||
if (is_write)
|
||||
ppc_state.ppc_fpscr = val;
|
||||
return ppc_state.ppc_fpscr;
|
||||
}
|
||||
|
||||
if (reg_name_u.substr(0, 1) == "R") {
|
||||
reg_num_str = reg_name_u.substr(1);
|
||||
reg_num = stoul(reg_num_str, NULL, 0);
|
||||
if (reg_num < 32) {
|
||||
if (is_write)
|
||||
ppc_state.ppc_gpr[reg_num] = val;
|
||||
return ppc_state.ppc_gpr[reg_num];
|
||||
}
|
||||
}
|
||||
|
||||
if (reg_name_u.substr(0, 1) == "FR") {
|
||||
reg_num_str = reg_name_u.substr(2);
|
||||
reg_num = stoul(reg_num_str, NULL, 0);
|
||||
if (reg_num < 32) {
|
||||
if (is_write)
|
||||
ppc_state.ppc_fpr[reg_num].int64_r = val;
|
||||
return ppc_state.ppc_fpr[reg_num].int64_r;
|
||||
}
|
||||
}
|
||||
|
||||
if (reg_name_u.substr(0, 3) == "SPR") {
|
||||
reg_num_str = reg_name_u.substr(3);
|
||||
reg_num = stoul(reg_num_str, NULL, 0);
|
||||
if (reg_num < 1024) {
|
||||
if (is_write)
|
||||
ppc_state.ppc_spr[reg_num] = val;
|
||||
return ppc_state.ppc_spr[reg_num];
|
||||
}
|
||||
}
|
||||
|
||||
if (reg_name_u.substr(0, 2) == "SR") {
|
||||
reg_num_str = reg_name_u.substr(2);
|
||||
reg_num = stoul(reg_num_str, NULL, 0);
|
||||
if (reg_num < 16) {
|
||||
if (is_write)
|
||||
ppc_state.ppc_sr[reg_num] = val;
|
||||
return ppc_state.ppc_sr[reg_num];
|
||||
}
|
||||
}
|
||||
|
||||
spr = SPRName2Num.find(reg_name_u);
|
||||
if (spr != SPRName2Num.end()) {
|
||||
if (is_write)
|
||||
ppc_state.ppc_spr[spr->second] = val;
|
||||
return ppc_state.ppc_spr[spr->second];
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
|
||||
bail_out:
|
||||
throw std::invalid_argument(string("Unknown register ") + reg_name);
|
||||
}
|
||||
|
||||
uint64_t get_reg(string ®_name)
|
||||
{
|
||||
return reg_op(reg_name, 0, false);
|
||||
}
|
||||
|
||||
void set_reg(string ®_name, uint64_t val)
|
||||
{
|
||||
reg_op(reg_name, val, true);
|
||||
}
|
||||
|
|
|
@ -18,10 +18,24 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
void show_help()
|
||||
static uint32_t str2addr(string& addr_str)
|
||||
{
|
||||
try {
|
||||
return stoul(addr_str, NULL, 0);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
throw invalid_argument(string("Cannot convert ") + addr_str);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_help()
|
||||
{
|
||||
cout << "Debugger commands:" << endl;
|
||||
cout << " step -- execute single instruction" << endl;
|
||||
cout << " si -- shortcut for step" << endl;
|
||||
cout << " next -- same as step but treats subroutine calls" << endl;
|
||||
cout << " as single instructions." << endl;
|
||||
cout << " ni -- shortcut for next" << endl;
|
||||
cout << " until X -- execute until address X is reached" << endl;
|
||||
cout << " regs -- dump content of the GRPs" << endl;
|
||||
cout << " set R=X -- assign value X to register R" << endl;
|
||||
|
@ -30,33 +44,24 @@ void show_help()
|
|||
cout << " profiler -- show stats related to the processor" << endl;
|
||||
#endif
|
||||
cout << " disas N,X -- disassemble N instructions starting at address X" << endl;
|
||||
cout << " X can be any number or a known register name" << endl;
|
||||
cout << " disas with no arguments defaults to disas 1,pc" << endl;
|
||||
cout << " quit -- quit the debugger" << endl << endl;
|
||||
cout << "Pressing ENTER will repeat last command." << endl;
|
||||
}
|
||||
|
||||
void dump_regs()
|
||||
{
|
||||
for (uint32_t i = 0; i < 32; i++)
|
||||
cout << "GPR " << dec << i << " : " << hex << ppc_state.ppc_gpr[i] << endl;
|
||||
|
||||
cout << "PC: " << hex << ppc_state.ppc_pc << endl;
|
||||
cout << "LR: " << hex << ppc_state.ppc_spr[8] << endl;
|
||||
cout << "CR: " << hex << ppc_state.ppc_cr << endl;
|
||||
cout << "CTR: " << hex << ppc_state.ppc_spr[9] << endl;
|
||||
cout << "XER: " << hex << ppc_state.ppc_spr[1] << endl;
|
||||
cout << "MSR: " << hex << ppc_state.ppc_msr << endl;
|
||||
}
|
||||
|
||||
void disasm(uint32_t inst_num = 1UL, uint32_t address = ppc_state.ppc_pc)
|
||||
static void disasm(uint32_t inst_num = 1UL, uint32_t address = ppc_state.ppc_pc)
|
||||
{
|
||||
PPCDisasmContext ctx;
|
||||
|
||||
quickinstruction_translate(ppc_state.ppc_pc);
|
||||
|
||||
ctx.instr_addr = ppc_state.ppc_pc;
|
||||
ctx.instr_code = ppc_cur_instruction;
|
||||
ctx.instr_addr = address;
|
||||
ctx.simplified = true;
|
||||
cout << hex << ppc_state.ppc_pc << " " << disassemble_single(&ctx) << endl;
|
||||
|
||||
for (int i = 0; i < inst_num; i++) {
|
||||
ctx.instr_code = mem_grab_dword(ctx.instr_addr);
|
||||
cout << uppercase << hex << ctx.instr_addr << " "
|
||||
<< disassemble_single(&ctx) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void enter_debugger()
|
||||
|
@ -65,7 +70,7 @@ void enter_debugger()
|
|||
uint32_t addr, inst_grab;
|
||||
std::stringstream ss;
|
||||
|
||||
cout << "Welcome to the PowerPC debugger." << endl;
|
||||
cout << "Welcome to the DingusPPC command line debugger." << endl;
|
||||
cout << "Please enter a command or 'help'." << endl << endl;
|
||||
|
||||
while (1) {
|
||||
|
@ -98,38 +103,64 @@ void enter_debugger()
|
|||
}
|
||||
#endif
|
||||
else if (cmd == "regs") {
|
||||
dump_regs();
|
||||
print_gprs();
|
||||
}
|
||||
else if (cmd == "set") {
|
||||
ss >> expr_str;
|
||||
reg_expr = expr_str.substr(0, expr_str.find("="));
|
||||
if (reg_expr == "pc") {
|
||||
try {
|
||||
reg_expr = expr_str.substr(0, expr_str.find("="));
|
||||
addr_str = expr_str.substr(expr_str.find("=") + 1);
|
||||
addr = stol(addr_str, NULL, 0);
|
||||
ppc_state.ppc_pc = addr;
|
||||
addr = str2addr(addr_str);
|
||||
set_reg(reg_expr, addr);
|
||||
}
|
||||
else {
|
||||
cout << "Unknown register " << reg_expr << endl;
|
||||
catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "step") {
|
||||
else if (cmd == "step" || cmd == "si") {
|
||||
ppc_exec_single();
|
||||
}
|
||||
else if (cmd == "next" || cmd == "ni") {
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str) + 4;
|
||||
ppc_exec_until(addr);
|
||||
}
|
||||
else if (cmd == "until") {
|
||||
ss >> addr_str;
|
||||
addr = stol(addr_str, NULL, 16);
|
||||
ppc_exec_until(addr);
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
ppc_exec_until(addr);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "disas") {
|
||||
expr_str = "";
|
||||
ss >> expr_str;
|
||||
if (expr_str.length() > 0) {
|
||||
cout << "Parsing disas params." << endl;
|
||||
inst_num_str = expr_str.substr(expr_str.find(" ") + 1, expr_str.find(","));
|
||||
inst_grab = stoul(inst_num_str, NULL, 0);
|
||||
addr_str = expr_str.substr(expr_str.find(",") + 1, expr_str.length() - 1);
|
||||
addr = stoul(addr_str, NULL, 16);
|
||||
disasm(inst_grab, addr);
|
||||
inst_num_str = expr_str.substr(0, expr_str.find(","));
|
||||
inst_grab = stol(inst_num_str, NULL, 0);
|
||||
addr_str = expr_str.substr(expr_str.find(",") + 1);
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
try {
|
||||
/* number conversion failed, trying reg name */
|
||||
addr = get_reg(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
disasm(inst_grab, addr);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
disasm();
|
||||
|
@ -141,4 +172,4 @@ void enter_debugger()
|
|||
}
|
||||
last_cmd = cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user