From dccdd7cb260d7eb8897e228960eed6e9948b0405 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 3 Jul 2013 17:05:00 -0400 Subject: [PATCH] Debugger Shell --- CMakeLists.txt | 1 + debugger/CMakeLists.txt | 23 +++ debugger/commands.h | 25 ++++ debugger/lexer.re.cpp | 324 ++++++++++++++++++++++++++++++++++++++++ debugger/parser.lemon | 163 ++++++++++++++++++++ 5 files changed, 536 insertions(+) create mode 100644 debugger/CMakeLists.txt create mode 100644 debugger/commands.h create mode 100644 debugger/lexer.re.cpp create mode 100644 debugger/parser.lemon diff --git a/CMakeLists.txt b/CMakeLists.txt index f7e308a..796b644 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,3 +12,4 @@ add_subdirectory(toolbox) add_subdirectory(mplite) add_subdirectory(mpw) add_subdirectory(macos) +add_subdirectory(debugger) \ No newline at end of file diff --git a/debugger/CMakeLists.txt b/debugger/CMakeLists.txt new file mode 100644 index 0000000..0125950 --- /dev/null +++ b/debugger/CMakeLists.txt @@ -0,0 +1,23 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) + + +set(DEBUGGER_SRC lexer.cpp parser.c) + +add_custom_command( + OUTPUT lexer.cpp + COMMAND re2c -b -i -o lexer.cpp "${CMAKE_CURRENT_SOURCE_DIR}/lexer.re.cpp" + MAIN_DEPENDENCY lexer.re.cpp + DEPENDS commands.h parser.h +) + +add_custom_command( + OUTPUT parser.cpp parser.h + COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/parser.lemon" "parser.lemon" + COMMAND lemon parser.lemon + COMMAND cp parser.h "${CMAKE_CURRENT_SOURCE_DIR}/" + COMMAND cp parser.out "${CMAKE_CURRENT_SOURCE_DIR}/" + MAIN_DEPENDENCY parser.lemon + DEPENDS commands.h +) + +add_library(DEBUGGER_LIB ${DEBUGGER_SRC}) \ No newline at end of file diff --git a/debugger/commands.h b/debugger/commands.h new file mode 100644 index 0000000..3de2117 --- /dev/null +++ b/debugger/commands.h @@ -0,0 +1,25 @@ +#ifndef __debugger_commands__ +#define __debugger_commands__ + +enum { + Print, + Dump, + List, + Break, + TBreak, + Continue, + Step, + SetARegister, + SetDRegister, + SetXRegister, +}; + +struct Command { + bool valid; + int action; + uint32_t argc; + uint32_t argv[10]; +}; + + +#endif \ No newline at end of file diff --git a/debugger/lexer.re.cpp b/debugger/lexer.re.cpp new file mode 100644 index 0000000..cc1404e --- /dev/null +++ b/debugger/lexer.re.cpp @@ -0,0 +1,324 @@ + +#include +#include +#include + +#include +#include + +#include "commands.h" +#include "parser.h" + +// re2c -b -i + + +extern "C" { + + void *ParseAlloc(void *(*mallocProc)(size_t)); + void ParseFree(void *p, void (*freeProc)(void*)); + void Parse(void *yyp, int yymajor, uint32_t yyminor, Command *command); + +} + + // p / print expression + // hd / hexdump expression [:expression] + // stack ? + // brk expression + // tbrk expression +namespace { + int tox(char c) + { + c |= 0x20; // lowercase it. + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return 0; + } + + uint32_t scan10(const char *begin, const char *end) + { + return std::accumulate(begin, end, 0, + [](char c, uint32_t value){ + return value * 10 + c - '0'; + }); + } + + uint32_t scan16(const char *begin, const char *end) + { + return std::accumulate(begin, end, 0, + [](char c, uint32_t value){ + return (value << 4) + tox(c); + }); + } +} + +#if 0 +/* + * unordered_set of breakpoints? + * bloom filter via std::bitset<16 * 1024> ? + */ + + class AddressFilter { + std::bitset<4096> pageSet; + std::unordered_set addSet; + + bool test(uint32_t address) const + { + if (address > 0xffffff) return false; + if (!pageSet[address >> 12]) return false; + + return addSet.find(address) != addSet.end(); + } + + void add(uint32_t address) + { + if (address > 0xffffff) return; + + pageSet[address >> 12] = true; + addSet.insert(address); + } + + void remove(uint32_t address) + { + if (address > 0xffffff) return; + + auto iter = addSet.find(address); + if (iter != addSet.end()) + { + addSet.remove(); + // need to re-scan all addresses to update the pageSet... + uint32_t page = address >> 12; + pageSet[page] = false; + for (auto x : addSet) + { + if ((x >> 12) == page) + { + addSet[page] = true; + break; + } + } + } + } + + }; + +#endif + +bool ParseLine(const char *iter, Command *command) +{ + void *parser; + + parser = ParseAlloc(malloc); + + for (;;) + { + const char *begin = iter; + const char *marker; + + /*!re2c + re2c:define:YYCURSOR = iter; + re2c:define:YYMARKER = marker; + re2c:define:YYCTYPE = char; + re2c:yyfill:enable = 0; + + [ \t\f\r\n]+ { + // white space + continue; + } + + '>=' { Parse(&parser, tkGTEQ, 0, command); continue; } + '>>' { Parse(&parser, tkGTGT, 0, command); continue; } + '<=' { Parse(&parser, tkLTEQ, 0, command); continue; } + '<<' { Parse(&parser, tkLTLT, 0, command); continue; } + '!=' { Parse(&parser, tkBANGEQ, 0, command); continue; } + '==' { Parse(&parser, tkEQEQ, 0, command); continue; } + '||' { Parse(&parser, tkPIPEPIPE, 0, command); continue; } + '&&' { Parse(&parser, tkAMPAMP, 0, command); continue; } + + + '(' { Parse(&parser, tkLPAREN, 0, command); continue; } + ')' { Parse(&parser, tkRPAREN, 0, command); continue; } + '=' { Parse(&parser, tkEQ, 0, command); continue; } + '+' { Parse(&parser, tkPLUS, 0, command); continue; } + '-' { Parse(&parser, tkMINUS, 0, command); continue; } + '*' { Parse(&parser, tkSTAR, 0, command); continue; } + '/' { Parse(&parser, tkSLASH, 0, command); continue; } + '%' { Parse(&parser, tkPERCENT, 0, command); continue; } + '~' { Parse(&parser, tkTILDE, 0, command); continue; } + '!' { Parse(&parser, tkBANG, 0, command); continue; } + '^' { Parse(&parser, tkCARET, 0, command); continue; } + '&' { Parse(&parser, tkAMP, 0, command); continue; } + '|' { Parse(&parser, tkPIPE, 0, command); continue; } + '<' { Parse(&parser, tkLT, 0, command); continue; } + '>' { Parse(&parser, tkGT, 0, command); continue; } + + [0-9]+ { + // integer + uint32_t data; + + data = std::accumulate(begin, iter, 0, + [](char c, uint32_t value){ + return value * 10 + c - '0'; + }); + + Parse(&parser, tkINTEGER, data, command); + continue; + } + + '$' [0-9A-Fa-f]+ { + // hex number + uint32_t data; + + data = std::accumulate(begin + 1, iter, 0, + [](char c, uint32_t value){ + return (value << 4) + tox(c); + } + ); + Parse(&parser, tkINTEGER, data, command); + continue; + } + + '0x' [0-9A-Fa-f]+ { + // hex number + uint32_t data; + + data = std::accumulate(begin + 2, iter, 0, + [](char c, uint32_t value){ + return (value << 4) + tox(c); + } + ); + Parse(&parser, tkINTEGER, data, command); + continue; + } + + ['] [^']{1,4} ['] { + // 4 cc code + uint32_t data; + + data = std::accumulate(begin + 1, iter - 1, 0, + [](char c, uint32_t value) + { + return (value << 8) + (unsigned)c; + } + ); + Parse(&parser, tkINTEGER, data, command); + continue; + } + + + 'd' [0-7] { + // data register + uint32_t data = begin[1] - '0'; + Parse(&parser, tkDREGISTER, data, command); + continue; + } + + 'a' [0-7] { + // address register + uint32_t data = begin[1] - '0'; + Parse(&parser, tkAREGISTER, data, command); + continue; + } + + 'pc' { + // program counter... + Parse(&parser, tkXREGISTER, 0, command); + continue; + } + + 'csr' { + // condition status register. + Parse(&parser, tkXREGISTER, 1, command); + continue; + } + + 'sp' { + // stack pointer aka a7 + Parse(&parser, tkAREGISTER, 7, command); + continue; + } + + 'fp' { + // frame pointer aka a6 + Parse(&parser, tkAREGISTER, 6, command); + continue; + } + + + 'c' | 'continue' { + Parse(&parser, tkCONTINUE, 0, command); + continue; + } + + 'hd' | 'dump' { + Parse(&parser, tkDUMP, 0, command); + continue; + } + + 'h' | 'help' { + Parse(&parser, tkHELP, 0, command); + continue; + } + + 'n' | 'next' { + Parse(&parser, tkSTEP, 0, command); + continue; + } + + 's' | 'step' { + Parse(&parser, tkSTEP, 0, command); + continue; + } + + 'b' | 'brk' | 'break' { + Parse(&parser, tkBREAK, 0, command); + continue; + } + + 'g' | 'go' { + Parse(&parser, tkGO, 0, command); + continue; + } + + 'r' | 'run' { + Parse(&parser, tkRUN, 0, command); + continue; + } + + + ';l' | ';list' { + Parse(&parser, tkSEMIL, 0, command); + continue; + } + + ';h' | ';hd' | ';hexdump' { + Parse(&parser, tkSEMIH, 0, command); + continue; + } + + [_A-Za-z][_A-Za-z0-9] + { + // identifier. lookup global address, tool number, etc. + fprintf(stderr, "illegal identifier: %*.s\n", (int)(iter - begin), begin); + return false; + } + + + [\x00] { + // eol. + Parse(&parser, tkEOL, 0, command); + break; + } + + [^] { + fprintf(stderr, "illegal character: `%c`\n", *begin); + return false; + } + + */ + + } + + Parse(&parser, 0, 0, command); + ParseFree(&parser, free); + + return command->valid; +} \ No newline at end of file diff --git a/debugger/parser.lemon b/debugger/parser.lemon new file mode 100644 index 0000000..b6371ca --- /dev/null +++ b/debugger/parser.lemon @@ -0,0 +1,163 @@ + +%extra_argument { struct Command *command } +%token_prefix tk + +%token_type {uint32_t} + + +%parse_failure { + fprintf(stderr,"I don't understand.\n"); + command->valid = false; +} + +%parse_accept { + command->valid = true; +} + + +%left PIPEPIPE. +%left AMPAMP. +%left PIPE. +%left CARET. +%left AMP. +%left EQEQ BANGEQ. +%left LT LTEQ GT GTEQ. +%left LTLT GTGT. +%left PLUS MINUS. +%left STAR SLASH PERCENT. +%right BANG TILDE. + + + + + +stmt ::= assignment EOL. +stmt ::= expr(a) EOL. +{ + // print the value. + // hex, base 10, signed 16-bit (if appropriate) + printf("$%08x - %u", a, a); + + if (a & 0x80000000) + printf(" %d", (int32_t)a); + + if ((a & 0xffff8000) == 0x8000) + printf(" %h", (int16_t)a); + + printf("\n"); + + command->action = PRINT; + command->arg = a; +} + +stmt ::= BREAK expr(a) EOL. +{ + command->action = tkBREAK; + command->arg = a; +} + +stmt ::= NEXT EOL. +{ + command->action = tkNEXT; + command->arg = 1; +} + +stmt ::= NEXT expr(a) EOL. +{ + command->action = tkNEXT; + command->arg = a; +} + +stmt ::= PRINT expr(a) EOL. +{ + command->action = tkPRINT; + command->arg = a; +} + +stmt ::= DUMP expr(a) EOL . +{ + command->action = tkDUMP; + command->arg = a; +} + +stmt ::= LIST expr(a) EOL . +{ + command->action = tkLIST; + command->arg = a; +} + +stmt ::= expr(a) SEMIL EOL. +{ + command->action = tkLIST; + command->arg = a; +} + +stmt ::= expr(a) SEMIH EOL. +{ + command->action = tkDUMP; + command->arg = a; +} + + +assignment ::= DREGISTER(a) EQ expr(b). { cpuSetDReg(a, b); } +assignment ::= AREGISTER(a) EQ expr(b). { cpuSetAReg(a, b); } +assignment ::= XREGISTER(a) EQ expr(b). +{ + switch(a) + { + case 0: + cpuSetPC(b); + break; + case 1: + cpuSetSR(b); + break; + } +} + +expr(rhs) ::= unary(a). { rhs = a; } +expr(rhs) ::= term(a) PLUS term(b). { rhs = a + b; } +expr(rhs) ::= term(a) MINUS term(b). { rhs = a + b; } +expr(rhs) ::= term(a) STAR term(b). { rhs = a * b; } +expr(rhs) ::= term(a) SLASH term(b). { rhs = a / b; } +expr(rhs) ::= term(a) PERCENT term(b). { rhs = a % b; } +expr(rhs) ::= term(a) LTLT term(b). { rhs = a << b; } +expr(rhs) ::= term(a) GTGT term(b). { rhs = a >> b; } +expr(rhs) ::= term(a) LT term(b). { rhs = a < b; } +expr(rhs) ::= term(a) LTEQ term(b). { rhs = a <= b; } +expr(rhs) ::= term(a) GT term(b). { rhs = a > b; } +expr(rhs) ::= term(a) GTEQ term(b). { rhs = a >= b; } +expr(rhs) ::= term(a) EQEQ term(b). { rhs = a == b; } +expr(rhs) ::= term(a) BANGEQ term(b). { rhs = a != b; } +expr(rhs) ::= term(a) AMP term(b). { rhs = a & b; } +expr(rhs) ::= term(a) CARET term(b). { rhs = a ^ b; } +expr(rhs) ::= term(a) PIPE term(b). { rhs = a | b; } +expr(rhs) ::= term(a) AMPAMP term(b). { rhs = a && b; } +expr(rhs) ::= term(a) PIPEPIPE term(b). { rhs = a || b; } + + +unary(rhs) ::= term(a). { rhs = a; } +unary(rhs) ::= PLUS unary(a). [BANG] { rhs = a; } +unary(rhs) ::= MINUS unary(a). [BANG] { rhs = -a; } +unary(rhs) ::= TILDE unary(a). { rhs = ~a; } +unary(rhs) ::= BANG unary(a). { rhs = !a; } +unary(rhs) ::= STAR unary(a). [BANG] { rhs = cpuMemoryReadLong(a); } + + +term(rhs) ::= LPAREN expr(a) RPAREN. { rhs = a; } +term(rhs) ::= INTEGER(a). { rhs = a; } +term(rhs) ::= DREGISTER(a). { rhs = cpuGetDReg(a); } +term(rhs) ::= AREGISTER(a). { rhs = cpuGetAReg(a); } +term(rhs) ::= XREGISTER(a). +{ + switch(a) + { + case 0: + rhs = cpuGetPC(); + break; + case 1: + rhs = cpuGetSR(); + break; + default: + rhs = 0; + } +}