From 7691267dea8637e69bff5601c75e492cc181c4f0 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 00:12:47 -0500 Subject: [PATCH 01/24] template lecture and parser code --- bin/CMakeLists.txt | 37 ++++- bin/template.h | 45 ++++++ bin/template_loader.rl | 288 ++++++++++++++++++++++++++++++++++++++ bin/template_parser.lemon | 114 +++++++++++++++ 4 files changed, 477 insertions(+), 7 deletions(-) create mode 100644 bin/template.h create mode 100644 bin/template_loader.rl create mode 100644 bin/template_parser.lemon diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 41ea2ff..9f2dd5b 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -20,7 +20,7 @@ add_custom_command( MAIN_DEPENDENCY lexer.rl ) -add_custom_command( +add_custom_command( OUTPUT parser.cpp parser.h COMMAND cp -f "${CMAKE_CURRENT_SOURCE_DIR}/parser.lemon" "parser.lemon" COMMAND lemon parser.lemon @@ -31,6 +31,20 @@ add_custom_command( DEPENDS debugger.h ) + +add_custom_command( + OUTPUT template_parser.cpp template_parser.h + COMMAND cp -f "${CMAKE_CURRENT_SOURCE_DIR}/template_parser.lemon" "template_parser.lemon" + COMMAND lemon template_parser.lemon + COMMAND cp -f template_parser.h "${CMAKE_CURRENT_SOURCE_DIR}/" + COMMAND cp -f template_parser.out "${CMAKE_CURRENT_SOURCE_DIR}/" + COMMAND mv -f template_parser.c template_parser.cpp + MAIN_DEPENDENCY template_parser.lemon + DEPENDS debugger.h +) + + + add_custom_command( OUTPUT loadtrap.cpp COMMAND ragel -p -G2 -o loadtrap.cpp "${CMAKE_CURRENT_SOURCE_DIR}/loadtrap.rl" @@ -39,16 +53,25 @@ add_custom_command( ) -set_source_files_properties( - loadtrap.cpp lexer.cpp - PROPERTIES - COMPILE_FLAGS - "${CMAKE_CXX_FLAGS} -Wno-unused-variable" +add_custom_command( + OUTPUT template_loader.cpp + COMMAND ragel -p -G2 -o template_loader.cpp "${CMAKE_CURRENT_SOURCE_DIR}/template_loader.rl" + MAIN_DEPENDENCY template_loader.rl + DEPENDS debugger.h template_parser.h ) +set_source_files_properties( + loadtrap.cpp lexer.cpp template_loader.cpp + PROPERTIES + COMPILE_FLAGS + "${CMAKE_CXX_FLAGS} -Wno-unused-variable" +) + add_executable(mpw loader.cpp debugger.cpp debugger_internal.cpp - address_map.cpp lexer.cpp parser.cpp loadtrap.cpp commands.cpp) + address_map.cpp lexer.cpp parser.cpp loadtrap.cpp + commands.cpp + template_loader.cpp template_parser.cpp) target_link_libraries(mpw CPU_LIB) target_link_libraries(mpw TOOLBOX_LIB) diff --git a/bin/template.h b/bin/template.h new file mode 100644 index 0000000..68c1c93 --- /dev/null +++ b/bin/template.h @@ -0,0 +1,45 @@ +#ifndef __debug_template_h__ +#define __debug_template_h__ + +#include + +namespace Debug { + + + + enum { + kUnknown = 0, + kStringPtr, // p-string + kCStringPtr, // c-string + kPtr, + kOSType, // four-cc + kBoolean, // unsigned char, display true/false + }; + + + struct Template; + struct FieldEntry; + + struct FieldEntry { + std::string *name; + unsigned type; + unsigned count; + Template *tmpl; + FieldEntry *next; + }; + + struct Template { + unsigned type; // 0 for structs, < 256 for types. + + FieldEntry *firstField; + unsigned size; + }; + + void CreateTypedef(const std::string *name, int type); + void CreateTemplate(const std::string *name, FieldEntry *firstField); + + + extern std::unordered_map Templates; + extern int TemplateLine; +} +#endif diff --git a/bin/template_loader.rl b/bin/template_loader.rl new file mode 100644 index 0000000..97b24ab --- /dev/null +++ b/bin/template_loader.rl @@ -0,0 +1,288 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "template_parser.h" +#include "template.h" + +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, + [](uint32_t value, char c){ + return value * 10 + c - '0'; + }); + } + + uint32_t scan16(const char *begin, const char *end) + { + return std::accumulate(begin, end, 0, + [](uint32_t value, char c){ + return (value << 4) + tox(c); + }); + } + + + + unsigned int DJBHash(const char* begin, const char *end) + { + unsigned int hash = 5381; + unsigned int i = 0; + + for(const char *iter = begin; iter != end; ++iter) + { + hash = ((hash << 5) + hash) + (*iter); + } + + return hash; + } + + std::unordered_multimap InternTable; + + const std::string *InternString(const char *begin, const char *end) + { + bool found = false; + unsigned hash = DJBHash(begin, end); + size_t length = end - begin; + + auto range = InternTable.equal_range(hash); + auto iter = range.first; + auto endit = range.second; + + for( ; iter != endit; ++iter) + { + // hash matches, make sure the string does. + const std::string *s = iter->second; + + if (s->length() == length && std::memcmp(s->data(), begin, length) == 0) + return s; + } + + // insert it. + std::string *s = new std::string(begin, end); + InternTable.emplace(std::make_pair(hash, s)); + return s; + } + +} + +void TemplateParse(void *yyp, int yymajor, void *yyminor); +void *TemplateParseAlloc(void *(*mallocProc)(size_t)); +void TemplateParseFree(void *p, void (*freeProc)(void*)); + +void TemplateParse(void *yyp, int yymajor, int yyminor) +{ + TemplateParse(yyp, yymajor, &yyminor); +} + +void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) +{ + TemplateParse(yyp, yymajor, (void *)yyminor); +} + +%%{ + machine lexer; + + # this exits with cs == lexer_en_error. + error := any* ${ fbreak; }; + + block_comment := |* + [\n\r] { TemplateLine++; }; + '*/' { fgoto main; }; + any ; + *|; + + main := |* + + [\n\r] { TemplateLine++; }; + [ \t]+; + + '//' [^\r\n]* ; + '/*' { fgoto block_comment; }; + + ';' { TemplateParse(parser, tkSEMI, 0); }; + '{' { TemplateParse(parser, tkLBRACE, 0); }; + '}' { TemplateParse(parser, tkRBRACE, 0); }; + '[' { TemplateParse(parser, tkLBRACKET, 0); }; + ']' { TemplateParse(parser, tkRBRACKET, 0); }; + '*' { TemplateParse(parser, tkSTAR, 0); }; + + 'struct' { TemplateParse(parser, tkSTRUCT, 0); }; + 'typedef' { TemplateParse(parser, tkTYPEDEF, 0); }; + + + 'int' { TemplateParse(parser, tkINT, 0); }; + 'long' { TemplateParse(parser, tkLONG, 0); }; + 'short' { TemplateParse(parser, tkSHORT, 0); }; + 'volatile' { TemplateParse(parser, tkVOLATILE, 0); }; + #'const' { TemplateParse(parser, tkCONST, 0); }; + 'char' { TemplateParse(parser, tkCHAR, 0); }; + #'bool' { TemplateParse(parser, tkBOOL, 0); }; + 'void' { TemplateParse(parser, tkVOID, 0); }; + + 'signed' { TemplateParse(parser, tkSIGNED, 0); }; + 'unsigned' { TemplateParse(parser, tkUNSIGNED, 0); }; + + 'int64_t' { TemplateParse(parser, tkTYPECODE, 'q'); }; + 'uint64_t' { TemplateParse(parser, tkTYPECODE, 'Q'); }; + + 'int32_t' { TemplateParse(parser, tkTYPECODE, 'l'); }; + 'uint32_t' { TemplateParse(parser, tkTYPECODE, 'L'); }; + + 'int16_t' { TemplateParse(parser, tkTYPECODE, 's'); }; + 'uint16_t' { TemplateParse(parser, tkTYPECODE, 'S'); }; + + 'int8_t' { TemplateParse(parser, tkTYPECODE, 'c'); }; + 'uint8_t' { TemplateParse(parser, tkTYPECODE, 'C'); }; + + + 'StringPtr' { TemplateParse(parser, tkTYPECODE, kStringPtr); }; + 'CStringPtr' { TemplateParse(parser, tkTYPECODE, kCStringPtr); }; + 'Ptr' { TemplateParse(parser, tkTYPECODE, kPtr); }; + 'OSType' { TemplateParse(parser, tkTYPECODE, kOSType); }; + 'Boolean' { TemplateParse(parser, tkTYPECODE, kBoolean); }; + + + # numbers. negative numbers are not allowed. + + '0x'i xdigit+ { + // hexadecimal + uint32_t value = scan16(ts + 2, te); + TemplateParse(parser, tkINTEGER, value); + }; + + digit+ { + uint32_t value = scan10(ts, te); + TemplateParse(parser, tkINTEGER, value); + }; + + # identifier ... but also need to check if it's a type. + [A-Za-z_][A-Za-z0-9_]+ { + + // intern the string. + + const std::string *name = InternString(ts, te); + + auto iter = Templates.find(*name); + if (iter != Templates.end()) + { + unsigned type = iter->second->type; + if (type) TemplateParse(parser, tkTYPECODE, type); + else TemplateParse(parser, tkTEMPLATE, iter->second); + } + else + { + TemplateParse(parser, tkIDENTIFIER, name); + } + }; + + *|; + +}%% + +namespace Debug { + +std::unordered_map Templates; + +void CreateTypedef(const std::string *name, int type) +{ +} +void CreateTemplate(const std::string *name, FieldEntry *firstField) +{ +} + +int TemplateLine; + +bool ParseTemplates(const std::string &filename) +{ + %% write data; + + void *parser; + + int fd; + struct stat st; + char *buffer; + + if (stat(filename.c_str(), &st) < 0) return false; + if (st.st_size == 0) return false; + + fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + perror("Error opening template file: "); + return false; + } + + buffer = (char *)mmap(nullptr, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + if (buffer == MAP_FAILED) { + perror("Error mapping template file: "); + close(fd); + return false; + } + close(fd); + + + + + parser = TemplateParseAlloc(malloc); + + + TemplateLine = 1; + + const char *p = buffer; + const char *pe = buffer + st.st_size; + const char *eof = pe; + const char *ts; + const char *te; + int cs, act; + + for(;;) + { + + %% write init; + %% write exec; + + if (cs == lexer_error) + { + fprintf(stderr, "illegal character: `%c'\n", *p); + TemplateParseFree(parser, free); + munmap(buffer, st.st_size); + return false; + } + if (cs == lexer_en_error) + { + TemplateParseFree(parser, free); + munmap(buffer, st.st_size); + return false; + } + if (p == pe) + { + TemplateParse(parser, tkEOF, 0); + break; + } + } + + TemplateParse(parser, 0, 0); + TemplateParseFree(parser, free); + + munmap(buffer, st.st_size); + + return true; +} + +} \ No newline at end of file diff --git a/bin/template_parser.lemon b/bin/template_parser.lemon new file mode 100644 index 0000000..9cb1e20 --- /dev/null +++ b/bin/template_parser.lemon @@ -0,0 +1,114 @@ +%token_prefix tk +%name TemplateParse + +%include { + + #include + #include + + #include "template.h" + + using namespace Debug; +} + +%type struct_fields { FieldEntry * } +%type struct_field { FieldEntry * } +%type array_count { int } +%type opt_star { int } +%type typecode { int } +%type type { int } + +start ::= templates EOF. + +templates ::= templates struct. +templates ::= templates typedef. +templates ::= . + +typedef ::= TYPEDEF type(a) IDENTIFIER(b). { + CreateTypedef((std::string *)b, a); +} + +struct ::= STRUCT IDENTIFIER(a) LBRACE struct_fields(b) RBRACE SEMI. +{ + CreateTemplate((std::string *)a, b); +} + +struct_fields(rhs) ::= struct_fields(a) struct_field(b). { + // reverse order? + b->next = a; + rhs = b; +} + +struct_fields(rhs) ::= struct_field(a). { + rhs = a; +} + +struct_field(rhs) ::= type(a) IDENTIFIER(b) array_count(c) SEMI. +{ + FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1); + + e->name = (std::string *)b; + e->type = a; + e->count = c; + rhs = e; +} + +struct_field(rhs) ::= opt_volatile TEMPLATE(a) opt_star(star) IDENTIFIER(b) array_count(c) SEMI. { + FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1); + + e->name = (std::string *)b; + e->type = star ? kPtr : 0; + e->tmpl = (Template *)a; + e->count = c; + + rhs = e; +} + +array_count(rhs) ::= . { rhs = -1; } +array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { rhs = *(int *)a; } + +// this is an expected error... +type(rhs) ::= opt_volatile IDENTIFIER(xxx). { + + // ugh, Lemon will blindly replace text within a string. + fprintf(stderr, "Template error: line %u: %s is not a known type.\n", + TemplateLine, ((std::string *)xxx)->c_str()); + + rhs = 'i'; +} + +type(rhs) ::= opt_volatile typecode(a). { rhs = a; } + +opt_volatile ::= . +opt_volatile ::= VOLATILE. + +typecode(rhs) ::= SIGNED. { rhs = 'i'; } +typecode(rhs) ::= UNSIGNED. {rhs = 'I'; } + +typecode(rhs) ::= opt_signed CHAR. { rhs = 'c'; } +typecode(rhs) ::= UNSIGNED CHAR. { rhs = 'C'; } + +typecode(rhs) ::= opt_signed SHORT. { rhs = 's'; } +typecode(rhs) ::= UNSIGNED SHORT. { rhs = 'S'; } + +typecode(rhs) ::= opt_signed LONG opt_int. { rhs = 'l'; } +typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = 'L'; } + +typecode(rhs) ::= opt_signed LONG LONG. { rhs = 'q'; } +typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = 'Q'; } + +typecode(rhs) ::= TYPECODE(a). { rhs = *(int *)a; } + +/* pointers are not fully supported yet */ +typecode(rhs) ::= VOID STAR. { rhs = kPtr; } + +opt_signed ::= . +opt_signed ::= SIGNED. + +opt_int ::= . +opt_int ::= INT. + + +opt_star(rhs) ::= . { rhs = 0; } +opt_star(rhs) ::= STAR. { rhs = 1; } + From 1cd59d36f38146a594cb09d0f46c8e355f082380 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 15:15:34 -0500 Subject: [PATCH 02/24] more template code --- bin/debugger.cpp | 8 +- bin/intern.cpp | 101 +++++++++++++++++ bin/intern.h | 14 +++ bin/template.h | 122 +++++++++++++++++--- bin/template_loader.rl | 229 +++++++++++++++++++++++++------------- bin/template_parser.lemon | 63 ++++++----- 6 files changed, 416 insertions(+), 121 deletions(-) create mode 100644 bin/intern.cpp create mode 100644 bin/intern.h diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 9f1891d..6ff3cb6 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -49,6 +49,7 @@ #include "debugger.h" #include "debugger_internal.h" +#include "template.h" #include #include @@ -62,8 +63,6 @@ #include #include - - namespace { using namespace Debug::Internal; @@ -84,6 +83,8 @@ namespace { ToolMap tbrkMap; // tool breaks. + std::unordered_map TemplateTable; + struct BackTraceInfo { uint32_t a[8]; uint32_t d[8]; @@ -1255,6 +1256,9 @@ void Shell() LoadTrapFile(MPW::RootDirPathForFile("Globals.text"), GlobalTable); LoadTrapFile(MPW::RootDirPathForFile("Traps.text"), TrapTable); + LoadTemplateFile(MPW::RootDirPathForFile("Templates.text"), TemplateTable); + + // load the error code to error mnemonic ErrorTableInvert.reserve(ErrorTable.size()); diff --git a/bin/intern.cpp b/bin/intern.cpp new file mode 100644 index 0000000..2a65947 --- /dev/null +++ b/bin/intern.cpp @@ -0,0 +1,101 @@ +#include "intern.h" +#include + +namespace { + + std::unordered_multimap InternTable; + + std::string EmptyString; + + unsigned int DJBHash(const char* begin, size_t length) + { + unsigned int hash = 5381; + + for(size_t i = 0; i < length; ++i) + { + hash = ((hash << 5) + hash) + (begin[i]); + } + + return hash; + } +} + +namespace Intern { + + const std::string *String(std::string &&str) + { + size_t size = str.size(); + if (!size) return &EmptyString; + + unsigned hash = DJBHash(str.data(), size); + + auto range = InternTable.equal_range(hash); + auto iter = range.first; + auto endit = range.second; + + for( ; iter != endit; ++iter) + { + // hash matches, make sure the string does. + const std::string *s = iter->second; + + if (s->size() == size && std::memcmp(s->data(), str.data(), size) == 0) + return s; + } + + // insert it. I suppose this could throw, in which case a string would leak. + std::string *s = new std::string(std::move(str)); + InternTable.emplace(std::make_pair(hash, s)); + return s; + } + + const std::string *String(const char *begin, size_t size) + { + if (!size) return &EmptyString; + + unsigned hash = DJBHash(begin, size); + + auto range = InternTable.equal_range(hash); + auto iter = range.first; + auto endit = range.second; + + for( ; iter != endit; ++iter) + { + // hash matches, make sure the string does. + const std::string *s = iter->second; + + if (s->size() == size && std::memcmp(s->data(), begin, size) == 0) + return s; + } + + // insert it. I suppose this could throw, in which case a string would leak. + std::string *s = new std::string(begin, size); + InternTable.emplace(std::make_pair(hash, s)); + return s; + } + + const std::string *String(const char *begin, const char *end) + { + return String(begin, end - begin); + } + + + const std::string *String(const char *cp) + { + if (!cp || !*cp) return &EmptyString; + + return String(cp, strlen(cp)); + } + + const std::string *String(const std::string &s) + { + return String(s.data(), s.size()); + } + + + + +} + + + + diff --git a/bin/intern.h b/bin/intern.h new file mode 100644 index 0000000..8d319cd --- /dev/null +++ b/bin/intern.h @@ -0,0 +1,14 @@ +#ifndef __intern_h__ +#define __intern_h__ + +#include + +namespace Intern { + const std::string *String(const std::string &s); + const std::string *String(std::string &&s); + const std::string *String(const char *); + const std::string *String(const char *, size_t size); + const std::string *String(const char *, const char *); +}; + +#endif \ No newline at end of file diff --git a/bin/template.h b/bin/template.h index 68c1c93..aae9f80 100644 --- a/bin/template.h +++ b/bin/template.h @@ -6,40 +6,128 @@ namespace Debug { + enum { + + // 0x8000 = pointer + // 0x1000 = unsigned + // 0x0f00 = size + // 0-255 - type + + kSInt64 = 0x0800, + kUInt64 = 0x1800, + + kSInt32 = 0x0400, + kUInt32 = 0x1400, + + kSInt16 = 0x0200, + kUInt16 = 0x1200, + + kSInt8 = 0x0100, + kUInt8 = 0x1100, + + kStruct = 0x0000, + kStructPtr = 0x8000, + + // ptrs are a special case where size = 0 + //kVoid = 0x0001, + kVoidPtr = 0x8001, + + // these exist for display purposes. + kCStringPtr = 0x8002, + kPStringPtr = 0x8003, + + kOSType = 0x00404, + kBoolean = 0x0105, + kOSErr = 0x0206, + kHandle = 0x04007, + + }; + + inline unsigned MakePtr(unsigned type) { return type | 0x8000; } + inline unsigned MakeType(unsigned size, bool sign, bool ptr) { + unsigned rv = size << 8; + if (!sign) rv |= 0x0100; + if (ptr) rv |= 0x8000; + return rv; + } enum { - kUnknown = 0, - kStringPtr, // p-string - kCStringPtr, // c-string - kPtr, - kOSType, // four-cc - kBoolean, // unsigned char, display true/false + kDisplayNative = 0, + kDisplayStringPtr, // p-string + kDisplayCStringPtr, // c-string + kDisplayOSType, // four-cc + kDisplayBoolean, // unsigned char, display true/false + kDisplayOSErr, }; - struct Template; +#if 0 + + struct Type { + enum { + kSimpleType, + kStructType, + kPointerType, + }; + uint16_t tag; + uint16_t size; + }; + + // handles [signed/unsigned] type, type[], *type, and *type[] + struct SimpleType : public Type { + unsigned rank:16; // int == int[1] + unsigned display:14; // + + unsigned sign:1; + unsigned pointer:1; + + SimpleType() { + tag = kSimpleType; + size = 0; + rank = 0; + display = 0; + sign = 0; + pointer = 0; + } + }; + + struct PointerType: public Type { + Type *type; + }; + + struct StructType : public Type { + unsigned total_size; + FieldEntry *firstField; + }; + +#endif + struct FieldEntry; + typedef FieldEntry *Template; struct FieldEntry { std::string *name; unsigned type; unsigned count; - Template *tmpl; + Template tmpl; FieldEntry *next; + unsigned struct_size; // only populated for head entry. }; - struct Template { - unsigned type; // 0 for structs, < 256 for types. - - FieldEntry *firstField; - unsigned size; + struct TemplateParseInfo { + std::unordered_map *templates; + std::unordered_map *types; + int LineNumber; }; - void CreateTypedef(const std::string *name, int type); - void CreateTemplate(const std::string *name, FieldEntry *firstField); + + void CreateTypedef(const std::string *name, int type, TemplateParseInfo *); + void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *); + + + bool LoadTemplateFile(const std::string &filename, std::unordered_map &); + - extern std::unordered_map Templates; - extern int TemplateLine; } #endif diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 97b24ab..56bd46e 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -12,6 +12,7 @@ #include "template_parser.h" #include "template.h" +#include "intern.h" namespace { @@ -39,63 +40,26 @@ namespace { } - - unsigned int DJBHash(const char* begin, const char *end) - { - unsigned int hash = 5381; - unsigned int i = 0; - - for(const char *iter = begin; iter != end; ++iter) - { - hash = ((hash << 5) + hash) + (*iter); - } - - return hash; - } - - std::unordered_multimap InternTable; - - const std::string *InternString(const char *begin, const char *end) - { - bool found = false; - unsigned hash = DJBHash(begin, end); - size_t length = end - begin; - - auto range = InternTable.equal_range(hash); - auto iter = range.first; - auto endit = range.second; - - for( ; iter != endit; ++iter) - { - // hash matches, make sure the string does. - const std::string *s = iter->second; - - if (s->length() == length && std::memcmp(s->data(), begin, length) == 0) - return s; - } - - // insert it. - std::string *s = new std::string(begin, end); - InternTable.emplace(std::make_pair(hash, s)); - return s; - } - } -void TemplateParse(void *yyp, int yymajor, void *yyminor); void *TemplateParseAlloc(void *(*mallocProc)(size_t)); void TemplateParseFree(void *p, void (*freeProc)(void*)); -void TemplateParse(void *yyp, int yymajor, int yyminor) +void TemplateParse(void *yyp, int yymajor, void *yyminor, Debug::TemplateParseInfo *); + + +void TemplateParse(void *yyp, int yymajor, int yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, &yyminor); + TemplateParse(yyp, yymajor, &yyminor, info); } -void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) +void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, (void *)yyminor); + TemplateParse(yyp, yymajor, (void *)yyminor, info); } +#define TemplateParse(a,b,c) TemplateParse(a,b,c, &info) + %%{ machine lexer; @@ -103,14 +67,14 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) error := any* ${ fbreak; }; block_comment := |* - [\n\r] { TemplateLine++; }; + [\n\r] { info.LineNumber++; }; '*/' { fgoto main; }; any ; *|; main := |* - [\n\r] { TemplateLine++; }; + [\n\r] { info.LineNumber++; }; [ \t]+; '//' [^\r\n]* ; @@ -139,24 +103,26 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) 'signed' { TemplateParse(parser, tkSIGNED, 0); }; 'unsigned' { TemplateParse(parser, tkUNSIGNED, 0); }; - 'int64_t' { TemplateParse(parser, tkTYPECODE, 'q'); }; - 'uint64_t' { TemplateParse(parser, tkTYPECODE, 'Q'); }; + 'int64_t' { TemplateParse(parser, tkTYPECODE, kSInt64); }; + 'uint64_t' { TemplateParse(parser, tkTYPECODE, kUInt64); }; - 'int32_t' { TemplateParse(parser, tkTYPECODE, 'l'); }; - 'uint32_t' { TemplateParse(parser, tkTYPECODE, 'L'); }; + 'int32_t' { TemplateParse(parser, tkTYPECODE, kSInt32); }; + 'uint32_t' { TemplateParse(parser, tkTYPECODE, kUInt32); }; - 'int16_t' { TemplateParse(parser, tkTYPECODE, 's'); }; - 'uint16_t' { TemplateParse(parser, tkTYPECODE, 'S'); }; + 'int16_t' { TemplateParse(parser, tkTYPECODE, kSInt16); }; + 'uint16_t' { TemplateParse(parser, tkTYPECODE, kUInt16); }; - 'int8_t' { TemplateParse(parser, tkTYPECODE, 'c'); }; - 'uint8_t' { TemplateParse(parser, tkTYPECODE, 'C'); }; + 'int8_t' { TemplateParse(parser, tkTYPECODE, kSInt8); }; + 'uint8_t' { TemplateParse(parser, tkTYPECODE, kUInt8); }; - 'StringPtr' { TemplateParse(parser, tkTYPECODE, kStringPtr); }; + 'StringPtr' { TemplateParse(parser, tkTYPECODE, kPStringPtr); }; 'CStringPtr' { TemplateParse(parser, tkTYPECODE, kCStringPtr); }; - 'Ptr' { TemplateParse(parser, tkTYPECODE, kPtr); }; + 'Ptr' { TemplateParse(parser, tkTYPECODE, kVoidPtr); }; 'OSType' { TemplateParse(parser, tkTYPECODE, kOSType); }; + 'OSErr' { TemplateParse(parser, tkTYPECODE, kOSErr); }; 'Boolean' { TemplateParse(parser, tkTYPECODE, kBoolean); }; + 'Handle' { TemplateParse(parser, tkTYPECODE, kHandle); }; # numbers. negative numbers are not allowed. @@ -177,16 +143,26 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) // intern the string. - const std::string *name = InternString(ts, te); + const std::string *name = Intern::String(ts, te); + bool ok = false; - auto iter = Templates.find(*name); - if (iter != Templates.end()) - { - unsigned type = iter->second->type; - if (type) TemplateParse(parser, tkTYPECODE, type); - else TemplateParse(parser, tkTEMPLATE, iter->second); + if (!ok) { + auto iter = Types.find(*name); + if (iter != Types.end()) + { + TemplateParse(parser, tkTYPECODE, iter->second); + ok = true; + } } - else + if (!ok) { + auto iter = Templates.find(*name); + if (iter != Templates.end()) + { + TemplateParse(parser, tkTEMPLATE, iter->second); + ok = true; + } + } + if (!ok) { TemplateParse(parser, tkIDENTIFIER, name); } @@ -198,18 +174,108 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) namespace Debug { -std::unordered_map Templates; -void CreateTypedef(const std::string *name, int type) -{ -} -void CreateTemplate(const std::string *name, FieldEntry *firstField) +void CreateTypedef(const std::string *name, int type, TemplateParseInfo *info) { + // check if it's an existing typedef... + + auto &Templates = *info->templates; + auto &Types = *info->types; + + + auto iter = Types.find(*name); + if (iter != Types.end()) + { + if (iter->second == type) return; // ok, just a duplicate. + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + Types.emplace(std::make_pair(*name, type)); } -int TemplateLine; +unsigned CalcSize(FieldEntry *e) +{ + unsigned size = 0; -bool ParseTemplates(const std::string &filename) + while (e) + { + unsigned s = (e->type & 0x0f00) >> 8; + + if (!s) { + // struct or pointer... + if (e->type & 0x8000) s = 4; + else if (e->tmpl) s = e->tmpl->struct_size; + } + + if (e->count != 0) s *= e->count; + + size += s; + e = e->next; + } + return size; +} + +FieldEntry *Reverse(FieldEntry *e) +{ + if (!e) return e; + + // reverse the order... + FieldEntry *prev; + FieldEntry *next; + + prev = nullptr; + for(;;) + { + next = e->next; + e->next = prev; + + prev = e; + e = next; + if (!e) return prev; + } +} + + +void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *info) +{ + auto &Templates = *info->templates; + auto &Types = *info->types; + + // check if it exists... + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + if (Types.find(*name) != Types.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + firstField = Reverse(firstField); + firstField->struct_size = CalcSize(firstField); + + Templates.emplace(std::make_pair(*name, firstField)); +} + + +bool LoadTemplateFile(const std::string &filename, std::unordered_map &Templates) { %% write data; @@ -219,6 +285,17 @@ bool ParseTemplates(const std::string &filename) struct stat st; char *buffer; + std::unordered_map Types; + TemplateParseInfo info; + + info.LineNumber = 1; + info.templates = &Templates; + info.types = &Types; + + // simple types are handled via the lexer so no need to populate them here. + + + if (stat(filename.c_str(), &st) < 0) return false; if (st.st_size == 0) return false; @@ -241,9 +318,6 @@ bool ParseTemplates(const std::string &filename) parser = TemplateParseAlloc(malloc); - - TemplateLine = 1; - const char *p = buffer; const char *pe = buffer + st.st_size; const char *eof = pe; @@ -272,7 +346,8 @@ bool ParseTemplates(const std::string &filename) } if (p == pe) { - TemplateParse(parser, tkEOF, 0); + // ? + //TemplateParse(parser, tkEOF, 0); break; } } diff --git a/bin/template_parser.lemon b/bin/template_parser.lemon index 9cb1e20..88f7632 100644 --- a/bin/template_parser.lemon +++ b/bin/template_parser.lemon @@ -1,5 +1,7 @@ %token_prefix tk %name TemplateParse +%extra_argument { Debug::TemplateParseInfo *info } + %include { @@ -13,24 +15,22 @@ %type struct_fields { FieldEntry * } %type struct_field { FieldEntry * } -%type array_count { int } -%type opt_star { int } -%type typecode { int } -%type type { int } -start ::= templates EOF. +start ::= templates. templates ::= templates struct. templates ::= templates typedef. templates ::= . +// typedeffing arrays or pointers is not allowed. + typedef ::= TYPEDEF type(a) IDENTIFIER(b). { - CreateTypedef((std::string *)b, a); + CreateTypedef((std::string *)b, a, info); } struct ::= STRUCT IDENTIFIER(a) LBRACE struct_fields(b) RBRACE SEMI. { - CreateTemplate((std::string *)a, b); + CreateTemplate((std::string *)a, b, info); } struct_fields(rhs) ::= struct_fields(a) struct_field(b). { @@ -57,50 +57,63 @@ struct_field(rhs) ::= opt_volatile TEMPLATE(a) opt_star(star) IDENTIFIER(b) arra FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1); e->name = (std::string *)b; - e->type = star ? kPtr : 0; - e->tmpl = (Template *)a; + e->type = star ? kStruct : kStructPtr; + e->tmpl = (Template)a; e->count = c; rhs = e; } -array_count(rhs) ::= . { rhs = -1; } -array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { rhs = *(int *)a; } +%type array_count { int } +array_count(rhs) ::= . { rhs = 0; } +array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { + int i = *(int *)a; + if (i == 0) { + fprintf(stderr, "Template error: line %u: 0-sized arrays are not allowed.\n", + info->LineNumber); + i = 1; + } + rhs = i; +} + +%type type { int } +type(rhs) ::= opt_volatile typecode(a). { rhs = a; } // this is an expected error... type(rhs) ::= opt_volatile IDENTIFIER(xxx). { // ugh, Lemon will blindly replace text within a string. fprintf(stderr, "Template error: line %u: %s is not a known type.\n", - TemplateLine, ((std::string *)xxx)->c_str()); + info->LineNumber, ((std::string *)xxx)->c_str()); rhs = 'i'; } -type(rhs) ::= opt_volatile typecode(a). { rhs = a; } opt_volatile ::= . opt_volatile ::= VOLATILE. -typecode(rhs) ::= SIGNED. { rhs = 'i'; } -typecode(rhs) ::= UNSIGNED. {rhs = 'I'; } -typecode(rhs) ::= opt_signed CHAR. { rhs = 'c'; } -typecode(rhs) ::= UNSIGNED CHAR. { rhs = 'C'; } +%type typecode { int } +typecode(rhs) ::= SIGNED. { rhs = kSInt32; } +typecode(rhs) ::= UNSIGNED. {rhs = kUInt32; } -typecode(rhs) ::= opt_signed SHORT. { rhs = 's'; } -typecode(rhs) ::= UNSIGNED SHORT. { rhs = 'S'; } +typecode(rhs) ::= opt_signed CHAR. { rhs = kSInt8; } +typecode(rhs) ::= UNSIGNED CHAR. { rhs = kUInt8; } -typecode(rhs) ::= opt_signed LONG opt_int. { rhs = 'l'; } -typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = 'L'; } +typecode(rhs) ::= opt_signed SHORT. { rhs = kSInt16; } +typecode(rhs) ::= UNSIGNED SHORT. { rhs = kUInt16; } -typecode(rhs) ::= opt_signed LONG LONG. { rhs = 'q'; } -typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = 'Q'; } +typecode(rhs) ::= opt_signed LONG opt_int. { rhs = kSInt32; } +typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = kUInt32; } + +typecode(rhs) ::= opt_signed LONG LONG. { rhs = kSInt64; } +typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = kUInt64; } typecode(rhs) ::= TYPECODE(a). { rhs = *(int *)a; } /* pointers are not fully supported yet */ -typecode(rhs) ::= VOID STAR. { rhs = kPtr; } +typecode(rhs) ::= VOID STAR. { rhs = kVoidPtr; } opt_signed ::= . opt_signed ::= SIGNED. @@ -108,7 +121,7 @@ opt_signed ::= SIGNED. opt_int ::= . opt_int ::= INT. - +%type opt_star { int } opt_star(rhs) ::= . { rhs = 0; } opt_star(rhs) ::= STAR. { rhs = 1; } From d400bfb4dabc63008901ad8d75fba29eb53f5fb5 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 15:51:57 -0500 Subject: [PATCH 03/24] fix integer tokens. --- bin/template_loader.rl | 2 +- bin/template_parser.lemon | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 56bd46e..1e91e0e 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -50,7 +50,7 @@ void TemplateParse(void *yyp, int yymajor, void *yyminor, Debug::TemplateParseIn void TemplateParse(void *yyp, int yymajor, int yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, &yyminor, info); + TemplateParse(yyp, yymajor, (void *)yyminor, info); } void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::TemplateParseInfo *info) diff --git a/bin/template_parser.lemon b/bin/template_parser.lemon index 88f7632..f3f64a7 100644 --- a/bin/template_parser.lemon +++ b/bin/template_parser.lemon @@ -67,7 +67,7 @@ struct_field(rhs) ::= opt_volatile TEMPLATE(a) opt_star(star) IDENTIFIER(b) arra %type array_count { int } array_count(rhs) ::= . { rhs = 0; } array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { - int i = *(int *)a; + int i = (int)(ptrdiff_t)a; if (i == 0) { fprintf(stderr, "Template error: line %u: 0-sized arrays are not allowed.\n", info->LineNumber); @@ -110,7 +110,7 @@ typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = kUInt32; } typecode(rhs) ::= opt_signed LONG LONG. { rhs = kSInt64; } typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = kUInt64; } -typecode(rhs) ::= TYPECODE(a). { rhs = *(int *)a; } +typecode(rhs) ::= TYPECODE(a). { rhs = (int)(ptrdiff_t)a; } /* pointers are not fully supported yet */ typecode(rhs) ::= VOID STAR. { rhs = kVoidPtr; } From 8e434d39f8d488b773e9882eb8fed9a17a509b9f Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 16:58:01 -0500 Subject: [PATCH 04/24] apply template --- bin/CMakeLists.txt | 3 +- bin/debugger.cpp | 16 +++ bin/debugger.h | 2 + bin/lexer.rl | 20 +++- bin/parser.lemon | 6 +- bin/template.cpp | 224 +++++++++++++++++++++++++++++++++++++++++ bin/template.h | 4 + bin/template_loader.rl | 99 +----------------- 8 files changed, 273 insertions(+), 101 deletions(-) create mode 100644 bin/template.cpp diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 9f2dd5b..5e1ffff 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -71,7 +71,8 @@ set_source_files_properties( add_executable(mpw loader.cpp debugger.cpp debugger_internal.cpp address_map.cpp lexer.cpp parser.cpp loadtrap.cpp commands.cpp - template_loader.cpp template_parser.cpp) + template_loader.cpp template_parser.cpp intern.cpp template.cpp) + target_link_libraries(mpw CPU_LIB) target_link_libraries(mpw TOOLBOX_LIB) diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 6ff3cb6..0a5d243 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -1136,8 +1136,24 @@ void Info(uint32_t address) cp = nullptr; } } + } + void ApplyTemplate(int32_t address, const std::string &name) + { + // find the template.. + + auto iter = TemplateTable.find(name); + if (iter == TemplateTable.end()) { + fprintf(stderr, "Unknown template: %s\n", name.c_str()); + return; + } + + FieldEntry *e = iter->second; + ApplyTemplate(address, e); + } + + namespace { /* diff --git a/bin/debugger.h b/bin/debugger.h index 4666eab..1596896 100644 --- a/bin/debugger.h +++ b/bin/debugger.h @@ -144,6 +144,8 @@ void ReadWriteBreak(int32_t address); void PrintError(uint32_t value); void PrintDate(uint32_t value); +void ApplyTemplate(int32_t address, const std::string &name); + } #endif diff --git a/bin/lexer.rl b/bin/lexer.rl index e4c4a35..80a06da 100644 --- a/bin/lexer.rl +++ b/bin/lexer.rl @@ -105,6 +105,21 @@ namespace { # this exits with cs == lexer_en_error. error := any* ${ fbreak; }; + # identifiers. + ident := |* + + [ \t\r\n]+; + + [_A-Za-z][_A-Za-z0-9]* { + + std::unique_ptr sp(new std::string(ts, te)); + + Parse(parser, tkIDENTIFIER, Token::Make(sp.get(), 0), command); + Strings.push_back(std::move(sp)); + }; + + *|; + # semi-colon commands. semi := |* @@ -130,7 +145,10 @@ namespace { Parse(parser, tkSEMIERROR, 0, command); }; - + 't'i { + Parse(parser, tkSEMIT, 0, command); + fgoto ident; + }; *|; diff --git a/bin/parser.lemon b/bin/parser.lemon index c27502c..3797f8b 100644 --- a/bin/parser.lemon +++ b/bin/parser.lemon @@ -200,7 +200,6 @@ stmt ::= expr(a) COLON expr(b) SEMI SEMIL EOL. Debug::List(a.intValue, b.intValue); } - stmt ::= expr(a) SEMI SEMIDATE EOL. { Debug::PrintDate(a.intValue); @@ -212,6 +211,11 @@ stmt ::= expr(a) SEMI SEMIERROR EOL. Debug::PrintError(a.intValue); } +stmt ::= expr(a) SEMI SEMIT IDENTIFIER(b) EOL. +{ + Debug::ApplyTemplate(a.intValue, *b.stringValue); +} + stmt ::= DREGISTER(a) EQ expr(b) EOL. { diff --git a/bin/template.cpp b/bin/template.cpp new file mode 100644 index 0000000..a17fab5 --- /dev/null +++ b/bin/template.cpp @@ -0,0 +1,224 @@ +#include "template.h" +#include "debugger.h" + +namespace Debug { + + namespace { + + + unsigned CalcOneSize(FieldEntry *e) + { + unsigned s = (e->type & 0x0f00) >> 8; + + if (!s) { + // struct or pointer... + if (e->type & 0x8000) s = 4; + else if (e->tmpl) s = e->tmpl->struct_size; + } + + if (e->count) s *= e->count; + + return s; + } + + unsigned CalcSize(FieldEntry *e) + { + unsigned size = 0; + + while (e) + { + size += CalcOneSize(e); + e = e->next; + } + return size; + } + + FieldEntry *Reverse(FieldEntry *e) + { + if (!e) return e; + + // reverse the order... + FieldEntry *prev; + FieldEntry *next; + + prev = nullptr; + for(;;) + { + next = e->next; + e->next = prev; + + prev = e; + e = next; + if (!e) return prev; + } + } + + + } + + void CreateTypedef(const std::string *name, int type, TemplateParseInfo *info) + { + // check if it's an existing typedef... + + auto &Templates = *info->templates; + auto &Types = *info->types; + + + auto iter = Types.find(*name); + if (iter != Types.end()) + { + if (iter->second == type) return; // ok, just a duplicate. + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + Types.emplace(std::make_pair(*name, type)); + } + + + void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *info) + { + auto &Templates = *info->templates; + auto &Types = *info->types; + + // check if it exists... + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + if (Types.find(*name) != Types.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + firstField = Reverse(firstField); + firstField->struct_size = CalcSize(firstField); + + Templates.emplace(std::make_pair(*name, firstField)); + } + + + void PrettyPrint(uint32_t value, unsigned type) + { + + switch (type) + { + case kOSType: + // print 4-cc code + return; + case kOSErr: + // print value + short name + return; + + case kPStringPtr: + // read the string... + return; + + case kCStringPtr: + // read the string... + return; + + case kBoolean: + fputs(value ? "true" : "false", stdout); + return; + + case kHandle: + // print address, size, locked stats. + return; + + } + + // int/signed int - print base 10. + + } + + + void ApplyTemplate(uint32_t address, FieldEntry *e, unsigned indent) + { + unsigned offset = 0; + + for( ; e ; e = e->next) + { + + unsigned count = e->count; + unsigned type = e->type; + unsigned s = (type & 0x0f00) >> 8; + + if (!s) { + // struct or pointer... + if (e->type & 0x8000) s = 4; + else if (e->tmpl) s = e->tmpl->struct_size; + } + + + printf("%-20s", e->name->c_str()); + + // todo -- support arrays + // todo -- pretty print values (boolean, oserr, ostype, etc.) + switch(s) + { + case 1: + { + uint8_t value = ReadByte(address + offset); + printf(" %02x", value); + PrettyPrint(value, type); + break; + } + + case 2: + { + uint16_t value = ReadWord(address + offset); + printf(" %04x", value); + PrettyPrint(value, type); + break; + } + + case 4: + { + uint32_t value = ReadLong(address + offset); + printf("%08x", value); + PrettyPrint(value, type); + break; + } + + case 0: + // either a pointer or a struct + if (type & 0x8000) { + // pointer. + uint32_t value = ReadLong(address + offset); + printf("%08x", value); + PrettyPrint(value, type); + break; + } + if (type == 0) { + // struct ... recurse. + + break; + } + } + + printf("\n"); + offset += CalcOneSize(e); + + } + + + } + +} diff --git a/bin/template.h b/bin/template.h index aae9f80..d1e65b1 100644 --- a/bin/template.h +++ b/bin/template.h @@ -2,6 +2,7 @@ #define __debug_template_h__ #include +#include namespace Debug { @@ -128,6 +129,9 @@ namespace Debug { bool LoadTemplateFile(const std::string &filename, std::unordered_map &); + void ApplyTemplate(uint32_t address, FieldEntry *e, unsigned indent = 0); + + } #endif diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 1e91e0e..931e252 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -50,7 +50,7 @@ void TemplateParse(void *yyp, int yymajor, void *yyminor, Debug::TemplateParseIn void TemplateParse(void *yyp, int yymajor, int yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, (void *)yyminor, info); + TemplateParse(yyp, yymajor, (void *)(ptrdiff_t)yyminor, info); } void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::TemplateParseInfo *info) @@ -175,104 +175,7 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::Te namespace Debug { -void CreateTypedef(const std::string *name, int type, TemplateParseInfo *info) -{ - // check if it's an existing typedef... - auto &Templates = *info->templates; - auto &Types = *info->types; - - - auto iter = Types.find(*name); - if (iter != Types.end()) - { - if (iter->second == type) return; // ok, just a duplicate. - fprintf(stderr, "Template Error: line %d - redefining %s\n", - info->LineNumber, name->c_str()); - - return; - } - - if (Templates.find(*name) != Templates.end()) - { - fprintf(stderr, "Template Error: line %d - redefining %s\n", - info->LineNumber, name->c_str()); - - return; - } - - Types.emplace(std::make_pair(*name, type)); -} - -unsigned CalcSize(FieldEntry *e) -{ - unsigned size = 0; - - while (e) - { - unsigned s = (e->type & 0x0f00) >> 8; - - if (!s) { - // struct or pointer... - if (e->type & 0x8000) s = 4; - else if (e->tmpl) s = e->tmpl->struct_size; - } - - if (e->count != 0) s *= e->count; - - size += s; - e = e->next; - } - return size; -} - -FieldEntry *Reverse(FieldEntry *e) -{ - if (!e) return e; - - // reverse the order... - FieldEntry *prev; - FieldEntry *next; - - prev = nullptr; - for(;;) - { - next = e->next; - e->next = prev; - - prev = e; - e = next; - if (!e) return prev; - } -} - - -void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *info) -{ - auto &Templates = *info->templates; - auto &Types = *info->types; - - // check if it exists... - - if (Templates.find(*name) != Templates.end()) - { - fprintf(stderr, "Template Error: line %d - redefining %s\n", - info->LineNumber, name->c_str()); - return; - } - - if (Types.find(*name) != Types.end()) - { - fprintf(stderr, "Template Error: line %d - redefining %s\n", - info->LineNumber, name->c_str()); - return; - } - - firstField = Reverse(firstField); - firstField->struct_size = CalcSize(firstField); - - Templates.emplace(std::make_pair(*name, firstField)); -} bool LoadTemplateFile(const std::string &filename, std::unordered_map &Templates) From f7bee265ccb32aba447d379f22b2a89ce496a058 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 17:18:43 -0500 Subject: [PATCH 05/24] fix printing for template within a template --- bin/template.cpp | 21 +++++++++-------- bin/template.h | 49 --------------------------------------- bin/template_loader.rl | 4 ++-- bin/template_parser.lemon | 2 +- 4 files changed, 14 insertions(+), 62 deletions(-) diff --git a/bin/template.cpp b/bin/template.cpp index a17fab5..b5a1bc5 100644 --- a/bin/template.cpp +++ b/bin/template.cpp @@ -135,6 +135,7 @@ namespace Debug { return; case kBoolean: + fputc(' ', stdout); fputs(value ? "true" : "false", stdout); return; @@ -153,21 +154,19 @@ namespace Debug { { unsigned offset = 0; + if (!e) return; + for( ; e ; e = e->next) { + bool nonl = false; unsigned count = e->count; unsigned type = e->type; unsigned s = (type & 0x0f00) >> 8; - if (!s) { - // struct or pointer... - if (e->type & 0x8000) s = 4; - else if (e->tmpl) s = e->tmpl->struct_size; - } - - - printf("%-20s", e->name->c_str()); + for (unsigned i = 0; i < indent; ++i) fputc('>',stdout); + fputs(e->name->c_str(),stdout); + for(unsigned i = indent + e->name->length(); i < 40; ++i) fputc(' ',stdout); // todo -- support arrays // todo -- pretty print values (boolean, oserr, ostype, etc.) @@ -208,12 +207,14 @@ namespace Debug { } if (type == 0) { // struct ... recurse. - + fputc('\n', stdout); + nonl = true; + ApplyTemplate(address + offset, e->tmpl, indent + 1); break; } } - printf("\n"); + if (!nonl) fputc('\n', stdout); offset += CalcOneSize(e); } diff --git a/bin/template.h b/bin/template.h index d1e65b1..a1dc023 100644 --- a/bin/template.h +++ b/bin/template.h @@ -52,57 +52,8 @@ namespace Debug { return rv; } - enum { - kDisplayNative = 0, - kDisplayStringPtr, // p-string - kDisplayCStringPtr, // c-string - kDisplayOSType, // four-cc - kDisplayBoolean, // unsigned char, display true/false - kDisplayOSErr, - }; -#if 0 - - struct Type { - enum { - kSimpleType, - kStructType, - kPointerType, - }; - uint16_t tag; - uint16_t size; - }; - - // handles [signed/unsigned] type, type[], *type, and *type[] - struct SimpleType : public Type { - unsigned rank:16; // int == int[1] - unsigned display:14; // - - unsigned sign:1; - unsigned pointer:1; - - SimpleType() { - tag = kSimpleType; - size = 0; - rank = 0; - display = 0; - sign = 0; - pointer = 0; - } - }; - - struct PointerType: public Type { - Type *type; - }; - - struct StructType : public Type { - unsigned total_size; - FieldEntry *firstField; - }; - -#endif - struct FieldEntry; typedef FieldEntry *Template; diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 931e252..2a65746 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -139,7 +139,7 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::Te }; # identifier ... but also need to check if it's a type. - [A-Za-z_][A-Za-z0-9_]+ { + [A-Za-z_][A-Za-z0-9_]* { // intern the string. @@ -236,7 +236,7 @@ bool LoadTemplateFile(const std::string &filename, std::unordered_mapname = (std::string *)b; - e->type = star ? kStruct : kStructPtr; + e->type = star ? kStructPtr : kStruct; e->tmpl = (Template)a; e->count = c; From f6cc3925a7ec1e45e51972afecbde1d834dbdb3b Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 30 Dec 2014 15:02:51 -0500 Subject: [PATCH 06/24] pretty print OSErr and OSType --- bin/template.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bin/template.cpp b/bin/template.cpp index b5a1bc5..1eeec80 100644 --- a/bin/template.cpp +++ b/bin/template.cpp @@ -1,8 +1,14 @@ #include "template.h" #include "debugger.h" +#include "debugger_internal.h" + +#include + namespace Debug { + using namespace Debug::Internal; + namespace { @@ -121,9 +127,17 @@ namespace Debug { { case kOSType: // print 4-cc code + fputc(' ', stdout); + fputs(ToolBox::TypeToString(value).c_str(), stdout); return; + case kOSErr: // print value + short name + { + printf(" %6d", (int16_t)value); + auto iter = ErrorTableInvert.find(value); + if (iter != ErrorTableInvert.end()) printf(" %s", iter->second.c_str()); + } return; case kPStringPtr: From f946dc18841e44efe1f1970bfb6e5ca57baf24d5 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 30 Dec 2014 15:27:34 -0500 Subject: [PATCH 07/24] pretty print CStringPtr/PStringPts --- bin/debugger.cpp | 28 ++++++++++++++++++++++++++++ bin/debugger.h | 3 +++ bin/template.cpp | 28 +++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 0a5d243..594faf9 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -480,6 +480,34 @@ namespace { namespace Debug { +std::string ReadPString(uint32_t address) +{ + std::string tmp; + unsigned size = ReadByte(address++); + + tmp.reserve(size); + for (unsigned i = 0; i < size; ++i) + tmp.push_back(ReadByte(address++)); + + + return tmp; +} + +std::string ReadCString(uint32_t address) +{ + std::string tmp; + + for (;;) + { + char c = ReadByte(address++); + if (!c) break; + tmp.push_back(c); + } + + return tmp; +} + + uint32_t ReadLong(uint32_t address) { uint32_t tmp = 0; diff --git a/bin/debugger.h b/bin/debugger.h index 1596896..03784ee 100644 --- a/bin/debugger.h +++ b/bin/debugger.h @@ -110,6 +110,9 @@ uint32_t ReadLong(uint32_t); uint16_t ReadWord(uint32_t); uint8_t ReadByte(uint32_t); +std::string ReadPString(uint32_t); +std::string ReadCString(uint32_t); + void Print(uint32_t value); void PrintRegisters(); diff --git a/bin/template.cpp b/bin/template.cpp index 1eeec80..b6bdee2 100644 --- a/bin/template.cpp +++ b/bin/template.cpp @@ -119,7 +119,18 @@ namespace Debug { Templates.emplace(std::make_pair(*name, firstField)); } + void CleanupString(std::string &s) + { + // replace non-printables. + std::transform(s.begin(), s.end(), s.begin(), [](char c){ + return isprint(c) ? c : '.'; + }); + if (s.size() > 40) { + s.resize(37); + s.append("..."); + } + } void PrettyPrint(uint32_t value, unsigned type) { @@ -134,7 +145,7 @@ namespace Debug { case kOSErr: // print value + short name { - printf(" %6d", (int16_t)value); + printf(" %-6d", (int16_t)value); auto iter = ErrorTableInvert.find(value); if (iter != ErrorTableInvert.end()) printf(" %s", iter->second.c_str()); } @@ -142,10 +153,25 @@ namespace Debug { case kPStringPtr: // read the string... + if (!value) return; + // need function to check if it's a valid pointer? + { + std::string tmp = ReadPString(value); + CleanupString(tmp); + printf(" '%s'", tmp.c_str()); + } return; case kCStringPtr: // read the string... + if (!value) return; + // need function to check if it's a valid pointer? + { + std::string tmp = ReadCString(value); + CleanupString(tmp); + printf(" '%s'", tmp.c_str()); + } + return; return; case kBoolean: From cbe66b679885b43e07ed3e6babdef9d796573beb Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 31 Dec 2014 15:45:22 -0500 Subject: [PATCH 08/24] sc / stackcrawl debugger command --- bin/commands.cpp | 108 +++++++++++++++++++++++++++++++++++++---------- bin/debugger.cpp | 2 +- bin/debugger.h | 2 + bin/lexer.rl | 7 +++ bin/parser.lemon | 7 ++- 5 files changed, 102 insertions(+), 24 deletions(-) diff --git a/bin/commands.cpp b/bin/commands.cpp index 2dd3685..df61ec3 100644 --- a/bin/commands.cpp +++ b/bin/commands.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include + #include "debugger.h" #include "debugger_internal.h" @@ -66,6 +69,7 @@ namespace Debug { struct tm *tm; time_t t = OS::MacToUnix(value); + // localtime vs gmtime? tm = ::localtime(&t); strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M:%S %p", tm); puts(buffer); @@ -76,30 +80,90 @@ namespace Debug { { puts(""); - puts(" ## "); - puts(" ## ## #### "); - puts(" ## #### ## "); - puts(" ## ## "); - puts(" ## ## ## ## "); - puts(" ## ## #### "); - puts("## ## ## ## "); - puts(" ######## #### ## ## "); - puts(" ## #################### ## "); - puts(" ## ############## ## "); - puts(" #### ############ ## "); - puts(" ###### ###### ## "); - puts(" ###### ## "); - puts(" #### ## "); - puts(" ## ## "); - puts(" ## ################ ## "); - puts(" ## ## ## ## "); - puts(" ## ## ## ## "); - puts(" ## ## ## ## "); - puts(" ## ## ## ## "); - puts(" ## ## ## ## "); - puts(" ###### ###### "); + puts(" ## "); + puts(" ## ## #### "); + puts(" ## #### ## "); + puts(" ## ## "); + puts(" ## ## ## ## "); + puts(" ## ## #### "); + puts(" ## ## ## ## "); + puts(" ######## #### ## ## "); + puts(" ## #################### ## "); + puts(" ## ############## ## "); + puts(" #### ############ ## "); + puts(" ###### ###### ## "); + puts(" ###### ## "); + puts(" #### ## "); + puts(" ## ## "); + puts(" ## ################ ## "); + puts(" ## ## ## ## "); + puts(" ## ## ## ## "); + puts(" ## ## ## ## "); + puts(" ## ## ## ## "); + puts(" ## ## ## ## "); + puts(" ###### ###### "); puts(""); } + + void StackCrawl(void) + { + // stack crawl based on a6 frame pointers. (link/unlink) + // start with current a6. + + uint32_t a6 = cpuGetAReg(6); + + /* + * a6: previous a6 + * a6+4 return pc + * .... parameters, locals, stack data + * previous a6 + * return pc + * .... + */ + // todo -- need a function to verify address is w/in stack range. + + + if (!a6) return; + printf("a6: %08x\n", a6); + + while(a6) + { + + uint32_t prevA6 = ReadLong(a6); + uint32_t pc = ReadLong(a6+4); // + + puts("------------"); + printf("a6: %08x\n", prevA6); + printf("pc: %08x", pc); + + // find the routine name... + for (const auto &kv : SymbolTable) + { + const auto &name = kv.first; + auto range = kv.second; + + // range end may be 0 + if ((pc == range.first) || (pc >= range.first && pc < range.second)) + { + uint32_t offset = pc - range.first; + if (offset) + printf(" %s+$%x", name.c_str(), offset); + else + printf(" %s", name.c_str()); + break; + } + } + puts(""); + + // hexdump contents between pc and previous.... + + + a6 = prevA6; + } + + + } + } \ No newline at end of file diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 594faf9..e267bb8 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -759,7 +759,7 @@ void PrintRegisters(const BackTraceInfo &i) i.a[4], i.a[5], i.a[6], i.a[7] ); - printf("PC: %08X CSR: %04x %s\n", i.pc, i.csr, srbits); + printf("PC: %08x CSR: %04x %s\n", i.pc, i.csr, srbits); } diff --git a/bin/debugger.h b/bin/debugger.h index 03784ee..46b7bbf 100644 --- a/bin/debugger.h +++ b/bin/debugger.h @@ -147,6 +147,8 @@ void ReadWriteBreak(int32_t address); void PrintError(uint32_t value); void PrintDate(uint32_t value); +void StackCrawl(void); + void ApplyTemplate(int32_t address, const std::string &name); } diff --git a/bin/lexer.rl b/bin/lexer.rl index 80a06da..49e1f9a 100644 --- a/bin/lexer.rl +++ b/bin/lexer.rl @@ -150,6 +150,7 @@ namespace { fgoto ident; }; + *|; main := |* @@ -268,6 +269,12 @@ namespace { Parse(parser, tkDUMP, 0, command); }; + + 'sc'i | 'stackcrawl'i { + Parse(parser, tkSTACKCRAWL, 0, command); + }; + + 'h'i | 'help'i { Parse(parser, tkHELP, 0, command); }; diff --git a/bin/parser.lemon b/bin/parser.lemon index 3797f8b..762f0cb 100644 --- a/bin/parser.lemon +++ b/bin/parser.lemon @@ -162,6 +162,10 @@ stmt ::= LIST expr(a) EOL. Debug::List(a.intValue); } +stmt ::= STACKCRAWL EOL. +{ + Debug::StackCrawl(); +} stmt ::= expr(a) SEMI SEMIH EOL. { @@ -205,12 +209,13 @@ stmt ::= expr(a) SEMI SEMIDATE EOL. Debug::PrintDate(a.intValue); } - stmt ::= expr(a) SEMI SEMIERROR EOL. { Debug::PrintError(a.intValue); } + + stmt ::= expr(a) SEMI SEMIT IDENTIFIER(b) EOL. { Debug::ApplyTemplate(a.intValue, *b.stringValue); From b707e02295672b62de42c1b2ebda783372ce121d Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 31 Dec 2014 16:49:42 -0500 Subject: [PATCH 09/24] fix lexer bugs with bad input. --- bin/lexer.rl | 52 ++++++++++++++++++++++++++++++------------------ bin/parser.lemon | 6 ++++++ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/bin/lexer.rl b/bin/lexer.rl index 49e1f9a..9ac0b8c 100644 --- a/bin/lexer.rl +++ b/bin/lexer.rl @@ -215,6 +215,7 @@ namespace { Parse(parser, tkINTEGER, value, command); }; + # todo -- (\['\]|[^'\]){1,4} ? ['] [^']{1,4} ['] { // 4 cc code @@ -375,28 +376,41 @@ bool ParseLine(const char *iter, Command *command) const char *te; int cs, act; - for(;;) + %% write init; + + + %% write exec; + + if (cs < lexer_first_final /* == lexer_error */) { + putchar(' '); putchar(' '); // 2 leading spaces. + for (size_t i = 0, l = p - iter; i < l; ++i) putchar(' '); puts("^"); + if (*p == 0) fprintf(stderr, "Unexpected end of line\n"); + else fprintf(stderr, "unexpected character: `%c'\n", *p); + + ParseFree(parser, free); + return false; + } - %% write init; - %% write exec; + /* + if (cs == lexer_en_error) + { + ParseFree(parser, free); + return false; + } - if (cs == lexer_error) - { - fprintf(stderr, "illegal character: `%c'\n", *p); - ParseFree(parser, free); - return false; - } - if (cs == lexer_en_error) - { - ParseFree(parser, free); - return false; - } - if (p == pe) - { - Parse(parser, tkEOL, 0, command); - break; - } + if (cs < lexer_first_final) + { + fprintf(stderr, "Incomplete command\n"); + ParseFree(parser, free); + return false; + } + */ + + if (p == pe) + { + // always true? + Parse(parser, tkEOL, 0, command); } Parse(parser, 0, 0, command); diff --git a/bin/parser.lemon b/bin/parser.lemon index 762f0cb..6c6b19f 100644 --- a/bin/parser.lemon +++ b/bin/parser.lemon @@ -222,6 +222,12 @@ stmt ::= expr(a) SEMI SEMIT IDENTIFIER(b) EOL. } +stmt ::= expr SEMI SEMIT error EOL. +{ + fprintf(stderr, "usage: expression ; t TemplateName\n"); +} + + stmt ::= DREGISTER(a) EQ expr(b) EOL. { Debug::SetDRegister(a.intValue, b.intValue); From 5aa9f08870208be7545cb0dad97215f43f908f8f Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 31 Dec 2014 17:42:18 -0500 Subject: [PATCH 10/24] clean up lexer errors a little more --- bin/lexer.rl | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/bin/lexer.rl b/bin/lexer.rl index 9ac0b8c..45e8510 100644 --- a/bin/lexer.rl +++ b/bin/lexer.rl @@ -381,13 +381,21 @@ bool ParseLine(const char *iter, Command *command) %% write exec; - if (cs < lexer_first_final /* == lexer_error */) + if (cs == lexer_error || cs < lexer_first_final) { - putchar(' '); putchar(' '); // 2 leading spaces. - for (size_t i = 0, l = p - iter; i < l; ++i) putchar(' '); puts("^"); - if (*p == 0) fprintf(stderr, "Unexpected end of line\n"); - else fprintf(stderr, "unexpected character: `%c'\n", *p); - + if (p == eof) + { + fprintf(stderr, "Unexpected end of line\n"); + } + else + { + for (size_t i = 0, l = 2 + (p - iter); i < l; ++i) + fputc(' ', stderr); + + fprintf(stderr, "^\nunexpected character: `%c'\n", *p); + + } + ParseFree(parser, free); return false; } From 427a4a6f3127ddd4926e06844bd182bd17cd8f01 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 31 Dec 2014 18:12:10 -0500 Subject: [PATCH 11/24] remove dead code --- bin/loader.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/bin/loader.cpp b/bin/loader.cpp index 49f5161..063710e 100644 --- a/bin/loader.cpp +++ b/bin/loader.cpp @@ -69,28 +69,6 @@ const uint32_t kGlobalSize = 0x10000; uint8_t *Memory = nullptr; uint32_t MemorySize = 0; -#if 0 -uint32_t EmulatedNewPtr(uint32_t size) -{ - if (size & 0x01) size++; - - if (HighWater + size > MemorySize) - { - fprintf(stderr, "Insufficient Memory!\n"); - exit(EX_CONFIG); - } - - - uint32_t address = HighWater; - - - HighWater += size; - - std::memset(Memory + HighWater, 0, size); - - return address; -} -#endif uint8_t ReadByte(const void *data, uint32_t offset) { From 15d0eded636e681b5991e5f20755bf611f2951ac Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 31 Dec 2014 18:46:38 -0500 Subject: [PATCH 12/24] fix template lexer errors. --- bin/template_loader.rl | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 2a65746..7edd15e 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -228,33 +228,21 @@ bool LoadTemplateFile(const std::string &filename, std::unordered_map Date: Wed, 31 Dec 2014 18:47:08 -0500 Subject: [PATCH 13/24] template -- check if ptr is valid --- bin/template.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/template.cpp b/bin/template.cpp index b6bdee2..ff927a5 100644 --- a/bin/template.cpp +++ b/bin/template.cpp @@ -1,6 +1,7 @@ #include "template.h" #include "debugger.h" #include "debugger_internal.h" +#include "loader.h" // Flags. #include @@ -60,6 +61,12 @@ namespace Debug { } + inline bool ValidPointer(uint32_t value) + { + return value && value < Flags.memorySize; + } + + } void CreateTypedef(const std::string *name, int type, TemplateParseInfo *info) @@ -153,8 +160,7 @@ namespace Debug { case kPStringPtr: // read the string... - if (!value) return; - // need function to check if it's a valid pointer? + if (ValidPointer(value)) { std::string tmp = ReadPString(value); CleanupString(tmp); @@ -164,8 +170,7 @@ namespace Debug { case kCStringPtr: // read the string... - if (!value) return; - // need function to check if it's a valid pointer? + if (ValidPointer(value)) { std::string tmp = ReadCString(value); CleanupString(tmp); From 6acd7797af3571ba763fe27b5d30cf373ff65d43 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sat, 3 Jan 2015 09:02:29 -0500 Subject: [PATCH 14/24] hex dump stack during stack crawl --- bin/commands.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++++--- bin/debugger.cpp | 58 --------------------------------- 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/bin/commands.cpp b/bin/commands.cpp index df61ec3..83093a8 100644 --- a/bin/commands.cpp +++ b/bin/commands.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -11,12 +12,59 @@ #include "debugger.h" #include "debugger_internal.h" +#include "loader.h" // Flags namespace Debug { using namespace Internal; + + void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0) + { + const char *HexMap = "0123456789abcdef"; + + char buffer1[16 * 3 + 1 + 1]; + char buffer2[16 + 1]; + ssize_t offset = 0; + unsigned i, j; + + + while(size > 0) + { + std::memset(buffer1, ' ', sizeof(buffer1)); + std::memset(buffer2, ' ', sizeof(buffer2)); + + unsigned linelen = (unsigned)std::min(size, (ssize_t)16); + + + for (i = 0, j = 0; i < linelen; i++) + { + unsigned x = data[i]; + buffer1[j++] = HexMap[x >> 4]; + buffer1[j++] = HexMap[x & 0x0f]; + j++; + if (i == 7) j++; + + // isascii not part of std:: and may be a macro. + buffer2[i] = isascii(x) && std::isprint(x) ? x : '.'; + + } + + buffer1[sizeof(buffer1)-1] = 0; + buffer2[sizeof(buffer2)-1] = 0; + + + std::printf("%06x: %s %s\n", address + (unsigned)offset, buffer1, buffer2); + offset += 16; + data += 16; + size -= 16; + } + std::printf("\n"); + } + + + void PrintError(uint32_t value) { /* expr ; error -- interpret expr as an OSErr */ @@ -124,6 +172,7 @@ namespace Debug { */ // todo -- need a function to verify address is w/in stack range. + // todo print in reverse order so newest frame doesn't scroll away. if (!a6) return; printf("a6: %08x\n", a6); @@ -132,8 +181,18 @@ namespace Debug { { uint32_t prevA6 = ReadLong(a6); + if (prevA6 <= a6) break; + uint32_t pc = ReadLong(a6+4); // + + + // hexdump contents between pc and previous.... + ssize_t size = prevA6 - a6 - 8; + hexdump(Flags.memory + a6 + 8, size); + + + puts("------------"); printf("a6: %08x\n", prevA6); printf("pc: %08x", pc); @@ -157,13 +216,27 @@ namespace Debug { } puts(""); - // hexdump contents between pc and previous.... - - a6 = prevA6; } - - } + void Dump(uint32_t start, int size) + { + // TODO -- if no address, use previous address. + // TODO -- support range? + + + if (size <= 0) return; + + uint32_t end = start + size; + + if (start >= Flags.memorySize) return; + + end = std::min(end, Flags.memorySize); + size = end - start; + + hexdump(Flags.memory + start, size, start); + } + + } \ No newline at end of file diff --git a/bin/debugger.cpp b/bin/debugger.cpp index e267bb8..a0e6f77 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -104,48 +104,7 @@ namespace { std::deque BackTrace; - void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0) - { - const char *HexMap = "0123456789abcdef"; - char buffer1[16 * 3 + 1 + 1]; - char buffer2[16 + 1]; - ssize_t offset = 0; - unsigned i, j; - - - while(size > 0) - { - std::memset(buffer1, ' ', sizeof(buffer1)); - std::memset(buffer2, ' ', sizeof(buffer2)); - - unsigned linelen = (unsigned)std::min(size, (ssize_t)16); - - - for (i = 0, j = 0; i < linelen; i++) - { - unsigned x = data[i]; - buffer1[j++] = HexMap[x >> 4]; - buffer1[j++] = HexMap[x & 0x0f]; - j++; - if (i == 7) j++; - - // isascii not part of std:: and may be a macro. - buffer2[i] = isascii(x) && std::isprint(x) ? x : '.'; - - } - - buffer1[sizeof(buffer1)-1] = 0; - buffer2[sizeof(buffer2)-1] = 0; - - - std::printf("%06x: %s %s\n", address + (unsigned)offset, buffer1, buffer2); - offset += 16; - data += 16; - size -= 16; - } - std::printf("\n"); - } void printMacsbug(uint32_t pc, uint32_t opcode, uint32_t *newPC = nullptr) @@ -662,23 +621,6 @@ void Print(uint32_t data) } -void Dump(uint32_t start, int size) -{ - // TODO -- if no address, use previous address. - // TODO -- support range? - - - if (size <= 0) return; - - uint32_t end = start + size; - - if (start >= Flags.memorySize) return; - - end = std::min(end, Flags.memorySize); - size = end - start; - - hexdump(Flags.memory + start, size, start); -} From a78226c5369eb89884ac52e298e646be709b20c8 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sat, 3 Jan 2015 13:45:00 -0500 Subject: [PATCH 15/24] .n files (MrC/MrCpp temp file) are binary. --- toolbox/os.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toolbox/os.cpp b/toolbox/os.cpp index d664a42..8f1531c 100644 --- a/toolbox/os.cpp +++ b/toolbox/os.cpp @@ -264,6 +264,12 @@ namespace OS return true; break; + case 'n': + // MrC / MrCpp temp file. + if (ext == "n") + return true; + break; + case 'o': if (ext == "o") return true; From 806a4b7eaf64c0dc87bfacd866297bce82417d57 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sat, 3 Jan 2015 14:14:36 -0500 Subject: [PATCH 16/24] increase size of backtrace --- bin/debugger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/debugger.cpp b/bin/debugger.cpp index a0e6f77..3549aa5 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -68,7 +68,7 @@ namespace { using namespace Debug::Internal; const uint32_t kGlobalSize = 0x10000; - const uint32_t kBackTraceSize = 20; + const uint32_t kBackTraceSize = 50; bool sigInt = false; bool memBreak = false; From ac66233f404a0fbcfb1f914fc65292b31aba0c5f Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 4 Jan 2015 19:12:35 -0500 Subject: [PATCH 17/24] MWDump68K support - DATA and TEXT resource types - HGetFileInfo - use directory id - PtrAndHand tool call --- toolbox/mm.cpp | 51 +++++++++++++++++++++++++++++++++++++++-- toolbox/os_fileinfo.cpp | 31 +++++++++++++++++-------- toolbox/rm.cpp | 2 ++ toolbox/toolbox.cpp | 5 +++- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/toolbox/mm.cpp b/toolbox/mm.cpp index f1778e3..46464b3 100644 --- a/toolbox/mm.cpp +++ b/toolbox/mm.cpp @@ -1265,7 +1265,7 @@ namespace MM * A0 destination Handle * D0 Result code * - */ + */ uint32_t srcHandle = cpuGetAReg(0); @@ -1303,7 +1303,7 @@ namespace MM * A0 destination pointer * D0 Result code * - */ + */ uint32_t mcptr = cpuGetAReg(0); uint32_t size = cpuGetDReg(0); @@ -1322,6 +1322,53 @@ namespace MM return d0; // SetMemError called by Native::NewHandle. } + uint16_t PtrAndHand(uint16_t trap) + { + // FUNCTION PtrAndHand (pntr: Ptr; hndl: Handle; size: LongInt): OSErr; + + /* + * on entry: + * A0 source Pointer + * A1 dest Handle + * D0 number of bytes to concatenate + * + * on exit: + * A0 destination Handle + * D0 Result code + * + */ + + uint32_t ptr = cpuGetAReg(0); + uint32_t handle = cpuGetAReg(1); + uint32_t size = cpuGetDReg(0); + + Log("%04x PtrAndHand(%08x, %08x, %08x)\n", trap, ptr, handle, size); + + cpuSetAReg(0, handle); + + uint32_t oldSize = 0; + uint32_t d0; + + d0 = Native::GetHandleSize(handle, oldSize); + if (d0) return d0; + + if ((uint64_t)oldSize + (uint64_t)size > UINT32_MAX) + return SetMemError(MacOS::memFullErr); + + + d0 = Native::SetHandleSize(handle, oldSize + size); + if (d0) return d0; + + auto iter = HandleMap.find(handle); + if (iter == HandleMap.end()) + return SetMemError(MacOS::memWZErr); + + auto const info = iter->second; + + std::memmove(memoryPointer(info.address + oldSize), memoryPointer(ptr), size); + + return SetMemError(0); + } diff --git a/toolbox/os_fileinfo.cpp b/toolbox/os_fileinfo.cpp index a4e5fb7..badddab 100644 --- a/toolbox/os_fileinfo.cpp +++ b/toolbox/os_fileinfo.cpp @@ -52,6 +52,7 @@ #include "os_internal.h" #include "toolbox.h" #include "stackframe.h" +#include "fs_spec.h" using ToolBox::Log; @@ -115,6 +116,8 @@ namespace OS { _ioFlRPyLen = 68, _ioFlCrDat = 72, _ioFlMdDat = 76, + + _ioDirID = 48, }; @@ -145,11 +148,15 @@ namespace OS { } sname = ToolBox::ReadPString(ioNamePtr, true); + // a20c HGetFileInfo uses a the dir id + if (trap == 0xa20c) + { + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); + sname = FSSpecManager::ExpandPath(sname, ioDirID); + } Log(" GetFileInfo(%s)\n", sname.c_str()); - // todo -- how are absolute, relative, etc paths handled... - struct stat st; @@ -237,6 +244,8 @@ namespace OS { _ioFlRPyLen = 68, _ioFlCrDat = 72, _ioFlMdDat = 76, + + _ioDirID = 48, }; @@ -254,13 +263,6 @@ namespace OS { //uint8_t ioFVersNum = memoryReadByte(parm + _ioFVersNum); //int16_t ioFDirIndex = memoryReadWord(parm + _ioFDirIndex); - // + 32 = finder data - 16 bytes. - - //uint32_t ioFlCrDat = memoryReadLong(parm + 72); - //uint32_t ioFlMdDat = memoryReadLong(parm + 76); - - // currently, only sets finder info. - if (!ioNamePtr) { d0 = MacOS::bdNamErr; @@ -269,8 +271,19 @@ namespace OS { } sname = ToolBox::ReadPString(ioNamePtr, true); + + // a20d HSetFileInfo uses a the dir id + if (trap == 0xa20d) + { + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); + sname = FSSpecManager::ExpandPath(sname, ioDirID); + } + Log(" SetFileInfo(%s)\n", sname.c_str()); + + + // check if the file actually exists { struct stat st; diff --git a/toolbox/rm.cpp b/toolbox/rm.cpp index e327f90..23c9d66 100644 --- a/toolbox/rm.cpp +++ b/toolbox/rm.cpp @@ -108,6 +108,8 @@ namespace case 0x4b4f4445: // 'KODE' (Link 32-bit Startup) case 0x45525253: // 'ERRS' (PPCLink) case 0x63667267: // 'cfrg' (PPCLink) + case 0x44415441: // 'DATA' (MetroWorks tools) + case 0x54455854: // 'TEXT' (MetroWorks tools) return true; default: return false; diff --git a/toolbox/toolbox.cpp b/toolbox/toolbox.cpp index ca2f0c1..8187404 100644 --- a/toolbox/toolbox.cpp +++ b/toolbox/toolbox.cpp @@ -289,7 +289,10 @@ namespace ToolBox { case 0xa9e3: d0 = MM::PtrToHand(trap); break; - + case 0xa9ef: + d0 = MM::PtrAndHand(trap); + break; + case 0xa11a: d0 = MM::GetZone(trap); break; From 6449892f51941e5565bce1ea85ba4dd8d92d5d3a Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 11:56:33 -0500 Subject: [PATCH 18/24] HSetState toolcall --- toolbox/mm.cpp | 29 +++++++++++++++++++++++++++++ toolbox/mm.h | 1 + toolbox/toolbox.cpp | 5 +++++ 3 files changed, 35 insertions(+) diff --git a/toolbox/mm.cpp b/toolbox/mm.cpp index 46464b3..7ca6fc6 100644 --- a/toolbox/mm.cpp +++ b/toolbox/mm.cpp @@ -1180,7 +1180,36 @@ namespace MM return flags; } + uint16_t HSetState(uint16_t trap) + { + /* + * on entry: + * A0 Handle + * D0 flags + * + * on exit: + * D0 flag byte + * + */ + uint32_t hh = cpuGetAReg(0); + uint16_t flags = cpuGetDReg(0); + + Log("%04x HSetState(%08x, %04x)\n", trap, hh, flags); + + auto iter = HandleMap.find(hh); + + if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); + + auto &info = iter->second; + + info.resource = (flags & (1 << 5)); + info.purgeable = (flags & (1 << 6)); + info.locked = (flags & (1 << 7)); + + + return SetMemError(0); + } uint16_t HPurge(uint16_t trap) { diff --git a/toolbox/mm.h b/toolbox/mm.h index 9602f71..345956a 100644 --- a/toolbox/mm.h +++ b/toolbox/mm.h @@ -62,6 +62,7 @@ namespace MM uint32_t RecoverHandle(uint16_t); uint16_t HGetState(uint16_t trap); + uint16_t HSetState(uint16_t trap); uint16_t HLock(uint16_t trap); uint16_t HUnlock(uint16_t trap); diff --git a/toolbox/toolbox.cpp b/toolbox/toolbox.cpp index 8187404..956fbce 100644 --- a/toolbox/toolbox.cpp +++ b/toolbox/toolbox.cpp @@ -277,6 +277,11 @@ namespace ToolBox { d0 = MM::HGetState(trap); break; + case 0xa06a: + d0 = MM::HSetState(trap); + break; + + // MoveHHi (h: Handle); case 0xa064: d0 = MM::MoveHHi(trap); From 183078925e0a4c403d166827c59e9df6505d75b8 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 12:32:34 -0500 Subject: [PATCH 19/24] ":" path is "." in unix --- toolbox/pathnames.rl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/toolbox/pathnames.rl b/toolbox/pathnames.rl index 96c9a5e..22e755f 100644 --- a/toolbox/pathnames.rl +++ b/toolbox/pathnames.rl @@ -42,10 +42,10 @@ namespace { * file -> file * :directory:file -> directory/file * volume:directory -> /volume/directory + * : -> ./ * :: -> ../ * ::: -> ../../ * - * * To Unix: * file -> file * directory/file -> :directory:file @@ -77,6 +77,12 @@ namespace { }; ':' { + /* + if (ts == begin) + rv.append("./"); + else + rv.push_back('/'); + */ if (ts != begin) rv.push_back('/'); }; @@ -151,6 +157,8 @@ namespace ToolBox // no colon - no problem. if (!colon) return path; + // special case ":" -> "." + if (colon && path.length() == 1) return "."; const char *p = path.c_str(); const char *pe = p + path.length(); From 24e47c7f9b464eafa067e09c7acd044bd7aa321c Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 12:33:29 -0500 Subject: [PATCH 20/24] PBGetCatInfo uses fs spec / dirID --- toolbox/os_hfs_dispatch.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/toolbox/os_hfs_dispatch.cpp b/toolbox/os_hfs_dispatch.cpp index 8a45c4b..65dfe9b 100644 --- a/toolbox/os_hfs_dispatch.cpp +++ b/toolbox/os_hfs_dispatch.cpp @@ -52,7 +52,8 @@ #include "os_internal.h" #include "toolbox.h" #include "stackframe.h" - +#include "fs_spec.h" + using ToolBox::Log; using MacOS::macos_error_from_errno; @@ -187,9 +188,16 @@ namespace OS { } sname = ToolBox::ReadPString(ioNamePtr, true); + { + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); + sname = FSSpecManager::ExpandPath(sname, ioDirID); + } Log(" PBGetCatInfo(%s)\n", sname.c_str()); + + + struct stat st; if (::stat(sname.c_str(), &st) < 0) @@ -341,6 +349,10 @@ namespace OS { } std::string sname = ToolBox::ReadPString(ioNamePtr, true); + { + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); + sname = FSSpecManager::ExpandPath(sname, ioDirID); + } Log(" PBSetCatInfo(%s)\n", sname.c_str()); From 7eb33de4356629fe6271e20228447a5655afb9ca Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 13:11:50 -0500 Subject: [PATCH 21/24] fix stack frames with byte values --- toolbox/stackframe.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/toolbox/stackframe.h b/toolbox/stackframe.h index 9b72394..590d39a 100644 --- a/toolbox/stackframe.h +++ b/toolbox/stackframe.h @@ -26,6 +26,9 @@ template uint32_t StackFrame__(uint32_t sp, uint32_t &x, Args&&... args); template uint32_t StackFrame__(uint32_t sp, uint16_t &x, Args&&... args); +template +uint32_t StackFrame__(uint32_t sp, uint8_t &x, Args&&... args); + template uint32_t StackFrame__(uint32_t sp); @@ -55,6 +58,16 @@ uint32_t StackFrame__(uint32_t sp, uint16_t &x, Args&&... args) return StackFrame__(sp, std::forward(args)...); } + +template +uint32_t StackFrame__(uint32_t sp, uint8_t &x, Args&&... args) +{ + // byte pushes as 2 bytes with 1 garbage byte + x = memoryReadByte(sp + Offset - 2); + + return StackFrame__(sp, std::forward(args)...); +} + template uint32_t StackFrame(Args&&... args) { From 1e2c1a8f5ddc30fd42d3e959e5ba1deee0c78896 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 13:12:06 -0500 Subject: [PATCH 22/24] FSpOpenDF --- toolbox/os_highlevel.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/toolbox/os_highlevel.cpp b/toolbox/os_highlevel.cpp index 74738b2..8506906 100644 --- a/toolbox/os_highlevel.cpp +++ b/toolbox/os_highlevel.cpp @@ -182,6 +182,34 @@ namespace OS { return 0; } + uint16_t FSpOpenDF() + { + // FUNCTION FSpOpenDF (spec: FSSpec; permission: SignedByte; VAR refNum: Integer): OSErr; + + uint32_t spec; + uint8_t permission; + uint32_t refNum; + + StackFrame<10>(spec, permission, refNum); + + int parentID = memoryReadLong(spec + 2); + std::string sname = ToolBox::ReadPString(spec + 6, false); + + Log(" FSpOpenDF(%s, %02x, %04x)\n", sname.c_str(), permission, refNum); + + sname = OS::FSSpecManager::ExpandPath(sname, parentID); + if (sname.empty()) + { + return MacOS::dirNFErr; + } + + int fd = Internal::FDEntry::open(sname, permission, 0); + if (fd < 0) return fd; + + memoryWriteWord(fd, refNum); + + return 0; + } uint16_t FSpGetFInfo() { @@ -363,6 +391,9 @@ namespace OS { case 0x0001: d0 = FSMakeFSSpec(); break; + case 0x0002: + d0 = FSpOpenDF(); + break; case 0x0004: d0 = FSpCreate(); From 02e95874d1a4648d792b69d4108b7e6d40767e0d Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 13:13:14 -0500 Subject: [PATCH 23/24] fix SignedByte stackframe --- toolbox/rm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolbox/rm.cpp b/toolbox/rm.cpp index 23c9d66..2d7e30c 100644 --- a/toolbox/rm.cpp +++ b/toolbox/rm.cpp @@ -604,7 +604,7 @@ namespace RM uint16_t vRefNum; uint32_t dirID; uint32_t fileName; - uint16_t permission; + uint8_t permission; sp = StackFrame<12>(vRefNum, dirID, fileName, permission); @@ -638,7 +638,7 @@ namespace RM uint32_t sp; uint32_t spec; - uint16_t permission; + uint8_t permission; sp = StackFrame<6>(spec, permission); From 42a1f5030d21913b8d5d090c0952425d8ab91a16 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 5 Jan 2015 20:11:10 -0500 Subject: [PATCH 24/24] HGetVInfo stub --- toolbox/os.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++ toolbox/os.h | 1 + toolbox/toolbox.cpp | 4 ++++ 3 files changed, 56 insertions(+) diff --git a/toolbox/os.cpp b/toolbox/os.cpp index 8f1531c..b7a8091 100644 --- a/toolbox/os.cpp +++ b/toolbox/os.cpp @@ -747,6 +747,57 @@ namespace OS } + + uint16_t HGetVInfo(uint16_t trap) + { + enum { + /* HVolumeParam */ + _qLink = 0, + _qType = 4, + _ioTrap = 6, + _ioCmdAddr = 8, + _ioCompletion = 12, + _ioResult = 16, + _ioNamePtr = 18, + _ioVRefNum = 22, + _filler2 = 24, + _ioVolIndex = 28, + _ioVCrDate = 30, + _ioVLsMod = 34, + _ioVAtrb = 38, + _ioVNmFls = 40, + _ioVBitMap = 42, + _ioAllocPtr = 44, + _ioVNmAlBlks = 46, + _ioVAlBlkSiz = 48, + _ioVClpSiz = 52, + _ioAlBlSt = 56, + _ioVNxtCNID = 58, + _ioVFrBlk = 62, + _ioVSigWord = 64, + _ioVDrvInfo = 66, + _ioVDRefNum = 68, + _ioVFSID = 70, + _ioVBkUp = 72, + _ioVSeqNum = 76, + _ioVWrCnt = 78, + _ioVFilCnt = 82, + _ioVDirCnt = 86, + _ioVFndrInfo = 90, + }; + + + + uint16_t d0; + + uint32_t parm = cpuGetAReg(0); + + Log("%04x HGetVInfo(%08x)\n", trap, parm); + + return MacOS::nsvErr; + } + + #pragma mark - String Utilities uint16_t CmpString(uint16_t trap) diff --git a/toolbox/os.h b/toolbox/os.h index c49f67a..fc7aaa5 100644 --- a/toolbox/os.h +++ b/toolbox/os.h @@ -56,6 +56,7 @@ namespace OS uint16_t GetVol(uint16_t trap); uint16_t HGetVol(uint16_t trap); + uint16_t HGetVInfo(uint16_t trap); uint16_t SetVol(uint16_t trap); diff --git a/toolbox/toolbox.cpp b/toolbox/toolbox.cpp index 956fbce..b769992 100644 --- a/toolbox/toolbox.cpp +++ b/toolbox/toolbox.cpp @@ -119,6 +119,10 @@ namespace ToolBox { d0 = OS::Write(trap); break; + case 0xa207: + d0 = OS::HGetVInfo(trap); + break; + case 0xa008: // Create case 0xa208: // HCreate d0 = OS::Create(trap);