From 8c9e50cd8f84f3bf25713f4510d586a7e6cad323 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 24 Dec 2014 17:44:48 -0500 Subject: [PATCH] Add backtrace support to the debug console. Squashed commit of the following: commit b3afbbf15839d5ad9343d4540674510cbd6cd16d Author: Kelvin Sherlock Date: Wed Dec 24 17:44:20 2014 -0500 improve the debugger help a little bit commit 82e1e4e3e4d802defbf49c965500ffc72c7be1af Author: Kelvin Sherlock Date: Wed Dec 24 17:32:21 2014 -0500 prevent filename tab completion in the debugger. commit 8765e5f428562e5ab6f8d59ec0e0460a834c66b5 Author: Kelvin Sherlock Date: Wed Dec 24 16:06:21 2014 -0500 skip macsbug names when disassembling via ;list commit 9b87cfb3851fedc6423629608f53076741116991 Author: Kelvin Sherlock Date: Wed Dec 24 15:43:13 2014 -0500 improved backtracing. commit f8e364d7c568fe6728c8efd5587f7edeb49f5816 Author: Kelvin Sherlock Date: Wed Dec 24 15:17:28 2014 -0500 BackTrace support --- bin/debugger.cpp | 185 +++++++++++++++++++++++++++++++++++++++++++---- bin/debugger.h | 2 + bin/lexer.rl | 4 + bin/parser.lemon | 5 ++ 4 files changed, 183 insertions(+), 13 deletions(-) diff --git a/bin/debugger.cpp b/bin/debugger.cpp index e7d010b..4d1fb4a 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -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 ErrorTable; std::map GlobalTable; std::map 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 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; } } diff --git a/bin/debugger.h b/bin/debugger.h index 90abf00..035b501 100644 --- a/bin/debugger.h +++ b/bin/debugger.h @@ -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); diff --git a/bin/lexer.rl b/bin/lexer.rl index 1944179..c861cc1 100644 --- a/bin/lexer.rl +++ b/bin/lexer.rl @@ -230,6 +230,10 @@ namespace { # commands... + 'bt'i | 'backtrace'i { + Parse(parser, tkBACKTRACE, 0, command); + }; + 'c'i | 'continue'i { Parse(parser, tkCONTINUE, 0, command); }; diff --git a/bin/parser.lemon b/bin/parser.lemon index 420e3d9..be99c71 100644 --- a/bin/parser.lemon +++ b/bin/parser.lemon @@ -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;