mirror of https://github.com/ksherlock/mpw.git
Add backtrace support to the debug console.
Squashed commit of the following: commit b3afbbf15839d5ad9343d4540674510cbd6cd16d Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Wed Dec 24 17:44:20 2014 -0500 improve the debugger help a little bit commit 82e1e4e3e4d802defbf49c965500ffc72c7be1af Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Wed Dec 24 17:32:21 2014 -0500 prevent filename tab completion in the debugger. commit 8765e5f428562e5ab6f8d59ec0e0460a834c66b5 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Wed Dec 24 16:06:21 2014 -0500 skip macsbug names when disassembling via ;list commit 9b87cfb3851fedc6423629608f53076741116991 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Wed Dec 24 15:43:13 2014 -0500 improved backtracing. commit f8e364d7c568fe6728c8efd5587f7edeb49f5816 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Wed Dec 24 15:17:28 2014 -0500 BackTrace support
This commit is contained in:
parent
45fae53ef5
commit
8c9e50cd8f
185
bin/debugger.cpp
185
bin/debugger.cpp
|
@ -37,6 +37,7 @@
|
|||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include <bitset>
|
||||
|
||||
|
@ -62,6 +63,7 @@
|
|||
namespace {
|
||||
|
||||
const uint32_t kGlobalSize = 0x10000;
|
||||
const uint32_t kBackTraceSize = 20;
|
||||
|
||||
bool sigInt = false;
|
||||
bool memBreak = false;
|
||||
|
@ -80,6 +82,26 @@ namespace {
|
|||
std::map<std::string, uint16_t> ErrorTable;
|
||||
std::map<std::string, uint16_t> GlobalTable;
|
||||
std::map<std::string, uint16_t> TrapTable;
|
||||
|
||||
|
||||
struct BackTraceInfo {
|
||||
uint32_t a[8];
|
||||
uint32_t d[8];
|
||||
uint32_t pc;
|
||||
uint16_t csr;
|
||||
|
||||
BackTraceInfo(bool populate = false) {
|
||||
if (populate)
|
||||
{
|
||||
for (unsigned i = 0; i < 8; ++i) a[i] = cpuGetAReg(i);
|
||||
for (unsigned i = 0; i < 8; ++i) d[i] = cpuGetDReg(i);
|
||||
pc = cpuGetPC();
|
||||
csr = cpuGetSR();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::deque<BackTraceInfo> BackTrace;
|
||||
|
||||
void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0)
|
||||
{
|
||||
|
@ -125,8 +147,9 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
void printMacsbug(uint32_t pc, uint32_t opcode)
|
||||
void printMacsbug(uint32_t pc, uint32_t opcode, uint32_t *newPC = nullptr)
|
||||
{
|
||||
// pc is actually pc after the opcode.
|
||||
|
||||
unsigned mboffset;
|
||||
switch(opcode)
|
||||
|
@ -160,6 +183,14 @@ namespace {
|
|||
s.push_back(Debug::ReadByte(pc++));
|
||||
}
|
||||
printf("%s\n", s.c_str());
|
||||
|
||||
// word-align
|
||||
pc = pc + 1 & ~0x01;
|
||||
|
||||
// and possibly a zero-word after it.
|
||||
if (Debug::ReadWord(pc) == 0x0000) pc += 2;
|
||||
|
||||
if (newPC) *newPC = pc;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -206,7 +237,7 @@ namespace {
|
|||
uint32_t newpc = cpuDisOpcode(pc, strings[0], strings[1], strings[2], strings[3]);
|
||||
printf("%s %-10s %-40s ; %s\n", strings[0], strings[2], strings[3], strings[1]);
|
||||
|
||||
printMacsbug(pc, opcode);
|
||||
printMacsbug(pc, opcode, &newpc);
|
||||
|
||||
return newpc;
|
||||
}
|
||||
|
@ -219,9 +250,26 @@ namespace {
|
|||
uint16_t op;
|
||||
memBreak = false;
|
||||
|
||||
uint32_t prevPC = cpuGetPC();
|
||||
|
||||
|
||||
|
||||
//uint32_t prevPC = cpuGetPC();
|
||||
|
||||
// backtracing. store contents before the instruction.
|
||||
if (BackTrace.size() == kBackTraceSize)
|
||||
{
|
||||
BackTrace.pop_front();
|
||||
}
|
||||
BackTrace.emplace_back(true);
|
||||
|
||||
//BackTrace.back().pc = prevPC;
|
||||
|
||||
cpuExecuteInstruction();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t pc = cpuGetPC();
|
||||
|
||||
if (trace) disasm(pc, &op);
|
||||
|
@ -424,6 +472,10 @@ void Help()
|
|||
printf("list expression\n");
|
||||
printf("dump expression\n");
|
||||
printf("register=expression\n");
|
||||
printf("bt | backtrace -- print cpu backtrace\n");
|
||||
printf("expression;h -- print hexdump\n");
|
||||
printf("expression;i -- print information\n");
|
||||
printf("expression;l -- print assembly listing\n");
|
||||
printf("\n");
|
||||
printf("registers: a0-7, d0-7, pc, sp, fp, csr\n");
|
||||
printf("\n");
|
||||
|
@ -583,12 +635,9 @@ void List(uint32_t pc, uint32_t endpc)
|
|||
|
||||
}
|
||||
|
||||
|
||||
void PrintRegisters()
|
||||
const char *srBits(uint16_t sr)
|
||||
{
|
||||
char srbits[20];
|
||||
|
||||
uint16_t sr = cpuGetSR();
|
||||
static char srbits[20];
|
||||
|
||||
srbits[0] = sr & (1 << 15) ? 'T' : ' ';
|
||||
srbits[1] = sr & (1 << 14) ? 'T' : ' ';
|
||||
|
@ -608,15 +657,43 @@ void PrintRegisters()
|
|||
srbits[15] = sr & (1 << 0) ? 'C' : ' ';
|
||||
srbits[16] = 0;
|
||||
|
||||
return srbits;
|
||||
}
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7\n");
|
||||
printf("D: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
|
||||
void PrintRegisters(const BackTraceInfo &i)
|
||||
{
|
||||
const char *srbits = srBits(i.csr);
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7\n");
|
||||
printf("D: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
i.d[0], i.d[1], i.d[2], i.d[3],
|
||||
i.d[4], i.d[5], i.d[6], i.d[7]
|
||||
|
||||
);
|
||||
|
||||
printf("A: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
i.a[0], i.a[1], i.a[2], i.a[3],
|
||||
i.a[4], i.a[5], i.a[6], i.a[7]
|
||||
);
|
||||
|
||||
printf("PC: %08X CSR: %04x %s\n", i.pc, i.csr, srbits);
|
||||
|
||||
}
|
||||
|
||||
void PrintRegisters()
|
||||
{
|
||||
uint16_t sr = cpuGetSR();
|
||||
const char *srbits = srBits(sr);
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7\n");
|
||||
printf("D: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
cpuGetDReg(0), cpuGetDReg(1), cpuGetDReg(2), cpuGetDReg(3),
|
||||
cpuGetDReg(4), cpuGetDReg(5), cpuGetDReg(6), cpuGetDReg(7)
|
||||
|
||||
);
|
||||
|
||||
printf("A: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
printf("A: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
cpuGetAReg(0), cpuGetAReg(1), cpuGetAReg(2), cpuGetAReg(3),
|
||||
cpuGetAReg(4), cpuGetAReg(5), cpuGetAReg(6), cpuGetAReg(7)
|
||||
);
|
||||
|
@ -625,6 +702,81 @@ void PrintRegisters()
|
|||
|
||||
}
|
||||
|
||||
void btdiff(const BackTraceInfo &prev, const BackTraceInfo ¤t)
|
||||
{
|
||||
bool nl = false;
|
||||
|
||||
for (unsigned i = 0; i < 8; ++i)
|
||||
if (current.d[i] != prev.d[i]) {
|
||||
printf(" D%u: %08x\n", i, current.d[i]);
|
||||
nl = true;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 8; ++i)
|
||||
if (current.a[i] != prev.a[i]) {
|
||||
printf(" A%u: %08x\n", i, current.a[i]);
|
||||
nl = true;
|
||||
}
|
||||
|
||||
|
||||
// pc always changes, but it's included in the listing.
|
||||
//printf("PC: %08x\n", current.pc);
|
||||
if (current.csr != prev.csr) {
|
||||
printf(" CSR: %04x %s\n", current.csr, srBits(current.csr));
|
||||
nl = true;
|
||||
}
|
||||
|
||||
if (nl) printf("\n");
|
||||
}
|
||||
void PrintBackTrace()
|
||||
{
|
||||
// backtrace.
|
||||
|
||||
auto iter = BackTrace.cbegin();
|
||||
auto end = BackTrace.cend();
|
||||
|
||||
if (iter == end) return;
|
||||
|
||||
const BackTraceInfo *prev;
|
||||
|
||||
{
|
||||
const BackTraceInfo &info = *iter;
|
||||
|
||||
// print all registers for the first entry.
|
||||
// for subsequent entries, print changed registers.
|
||||
|
||||
//disasm(info.pc);
|
||||
PrintRegisters(info);
|
||||
printf("\n");
|
||||
|
||||
prev = &info;
|
||||
++iter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for ( ; iter != end; ++iter)
|
||||
{
|
||||
const BackTraceInfo ¤t = *iter;
|
||||
|
||||
disasm(prev->pc);
|
||||
btdiff(*prev, current);
|
||||
|
||||
//
|
||||
prev = ¤t;
|
||||
}
|
||||
|
||||
// print current registers.
|
||||
{
|
||||
BackTraceInfo current(true);
|
||||
disasm(prev->pc);
|
||||
btdiff(*prev, current);
|
||||
}
|
||||
|
||||
// finally, print the current instruction.
|
||||
printf("---------\n");
|
||||
disasm(cpuGetPC());
|
||||
}
|
||||
|
||||
void ToolBreak(int32_t tool)
|
||||
{
|
||||
|
@ -928,7 +1080,7 @@ namespace {
|
|||
* returns a list of possible matches.
|
||||
* Item[0] is the longest match.
|
||||
*/
|
||||
char **mpw_completion(const char* text, int _start, int _end)
|
||||
char **mpw_attempted_completion_function(const char* text, int _start, int _end)
|
||||
{
|
||||
std::string s(text);
|
||||
|
||||
|
@ -1009,10 +1161,17 @@ namespace {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
// this is here to prevent filename tab completion, for now.
|
||||
char *mpw_completion_entry_function(const char *text, int state)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void readline_init()
|
||||
{
|
||||
rl_readline_name = (char *)"mpw";
|
||||
rl_attempted_completion_function = mpw_completion;
|
||||
rl_attempted_completion_function = mpw_attempted_completion_function;
|
||||
rl_completion_entry_function = (Function *)mpw_completion_entry_function;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,8 @@ uint8_t ReadByte(uint32_t);
|
|||
void Print(uint32_t value);
|
||||
void PrintRegisters();
|
||||
|
||||
void PrintBackTrace();
|
||||
|
||||
void Info(uint32_t address);
|
||||
|
||||
void Dump(uint32_t address, int count = 256);
|
||||
|
|
|
@ -230,6 +230,10 @@ namespace {
|
|||
|
||||
# commands...
|
||||
|
||||
'bt'i | 'backtrace'i {
|
||||
Parse(parser, tkBACKTRACE, 0, command);
|
||||
};
|
||||
|
||||
'c'i | 'continue'i {
|
||||
Parse(parser, tkCONTINUE, 0, command);
|
||||
};
|
||||
|
|
|
@ -81,6 +81,11 @@ stmt ::= BREAK expr(a) EOL.
|
|||
Debug::Break(a.intValue);
|
||||
}
|
||||
|
||||
stmt ::= BACKTRACE EOL.
|
||||
{
|
||||
Debug::PrintBackTrace();
|
||||
}
|
||||
|
||||
stmt ::= CONTINUE EOL.
|
||||
{
|
||||
command->action = Debug::cmdContinue;
|
||||
|
|
Loading…
Reference in New Issue