From 7c2cf3d1fd8e00bcdfd24bfee0abf0fa0b0ec964 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 18 Aug 2013 21:07:24 -0400 Subject: [PATCH] debugger completion for symbols --- bin/debugger.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++- toolbox/loader.cpp | 6 +-- toolbox/loader.h | 4 +- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 8642898..a17a3c2 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -73,7 +74,7 @@ namespace { AddressMap wbrkMap; // write breaks. ToolMap tbrkMap; // tool breaks. - std::unordered_map SymbolTable; + std::map SymbolTable; void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0) @@ -839,12 +840,108 @@ void VariableSet(const std::string &key, uint32_t value) SymbolTable.emplace(key, value); } +namespace { + + /* + * returns a list of possible matches. + * Item[0] is the longest match. + */ + char **mpw_completion(const char* text, int _start, int _end) + { + std::string s(text); + + // returns iter to first element _not less_ than key + // ie, >= key. + auto iter = SymbolTable.lower_bound(s); + + unsigned count = 0; + unsigned length = s.length(); + + auto begin = iter; + + for (;;) + { + if (iter == SymbolTable.end()) break; + if (iter->first.compare(0, length, s) != 0) break; + + ++count; + ++iter; + } + auto end = iter; + + if (!count) return NULL; + if (count > 100) return NULL; + + if (count == 1) + { + char **buffer = (char **)malloc(2 * sizeof(char *)); + buffer[0] = strdup(begin->first.c_str()); + buffer[1] = NULL; + return buffer; + } + + char **buffer = (char **)malloc((count + 2) * sizeof(char *)); + + unsigned i = 0; + auto min_length = begin->first.length(); + + // item 0 is the longest match. (fill in later.) + buffer[i++] = NULL; + for (iter = begin; iter != end; ++iter) + { + buffer[i++] = strdup(iter->first.c_str()); + min_length = std::min(min_length, iter->first.length()); + } + buffer[i] = NULL; + + + // assume the first is the longest, then search until not true. + buffer[0] = strdup(begin->first.c_str()); + for (unsigned i = length; ; ++i) + { + + if (i >= min_length) + { + buffer[0][i] = 0; + break; + } + + char c = buffer[0][i]; + if (!c) break; + + bool nomatch = false; + for (int j = 1; ; ++j) + { + char *cp = buffer[j]; + if (!cp) break; + if (cp[i] != c) nomatch = true; + } + + if (nomatch) + { + buffer[0][i] = 0; + break; + } + } + + return buffer; + } + + void readline_init() + { + rl_readline_name = (char *)"mpw"; + rl_attempted_completion_function = mpw_completion; + } +} + // TODO -- RUN command - reload, re-initialize, re-execute // TODO -- parser calls commands directly (except trace/step/run/etc) void Shell() { char *cp; + readline_init(); + add_history("!Andy, it still has history!"); diff --git a/toolbox/loader.cpp b/toolbox/loader.cpp index af4df33..8f81ac3 100644 --- a/toolbox/loader.cpp +++ b/toolbox/loader.cpp @@ -363,7 +363,7 @@ namespace Loader { // - void LoadDebugNames(std::unordered_map &table) + void LoadDebugNames(std::map &table) { if (Segments.empty()) return; @@ -394,10 +394,6 @@ namespace Loader { * name is fixed at 8 or 16 bytes or variable length. * valid characters = [a-zA-Z0-9_%.] and space, to pad fixed length names. * - * fixed length: not yet supported. - * - * - */ uint32_t start = 0; diff --git a/toolbox/loader.h b/toolbox/loader.h index df4c6dc..f9762e2 100644 --- a/toolbox/loader.h +++ b/toolbox/loader.h @@ -2,7 +2,7 @@ #define __mpw_loader_h__ #include -#include +#include #include @@ -21,7 +21,7 @@ namespace Loader { // scans segments for MacsBug debug names. // associates them with the start of the segment. - void LoadDebugNames(std::unordered_map &table); + void LoadDebugNames(std::map &table); }