|
|
1.1 ! root 1: /* ! 2: * Hatari - symbols.c ! 3: * ! 4: * Copyright (C) 2010 by Eero Tamminen ! 5: * ! 6: * This file is distributed under the GNU Public License, version 2 or at ! 7: * your option any later version. Read the file gpl.txt for details. ! 8: * ! 9: * symbols.c - Hatari debugger symbol/address handling; parsing, sorting, ! 10: * matching, TAB completion support etc. ! 11: * ! 12: * Symbol/address file contents are identical to "nm" output i.e. composed ! 13: * of a hexadecimal addresses followed by a space, letter indicating symbol ! 14: * type (T = text/code, D = data, B = BSS), space and the symbol name. ! 15: * Empty lines and lines starting with '#' are ignored. ! 16: */ ! 17: const char Symbols_fileid[] = "Hatari symbols.c : " __DATE__ " " __TIME__; ! 18: ! 19: #include <ctype.h> ! 20: #include <stdio.h> ! 21: #include <string.h> ! 22: #include <assert.h> ! 23: #include <SDL_types.h> ! 24: #include "main.h" ! 25: #include "symbols.h" ! 26: #include "debugui.h" ! 27: #include "debug_priv.h" ! 28: #include "evaluate.h" ! 29: ! 30: typedef struct { ! 31: char *name; ! 32: Uint32 address; ! 33: symtype_t type; ! 34: } symbol_t; ! 35: ! 36: typedef struct { ! 37: int count; ! 38: symbol_t *addresses; /* items sorted by address */ ! 39: symbol_t *names; /* items sorted by symbol name */ ! 40: } symbol_list_t; ! 41: ! 42: ! 43: /* how many characters the symbol name can have. ! 44: * NOTE: change also sscanf width arg if you change this!!! ! 45: */ ! 46: #define MAX_SYM_SIZE 32 ! 47: ! 48: ! 49: /* TODO: add symbol name/address file names to configuration? */ ! 50: static symbol_list_t *CpuSymbolsList; ! 51: static symbol_list_t *DspSymbolsList; ! 52: ! 53: ! 54: /* ------------------ load and free functions ------------------ */ ! 55: ! 56: /** ! 57: * compare function for qsort() to sort according to symbol address ! 58: */ ! 59: static int symbols_by_address(const void *s1, const void *s2) ! 60: { ! 61: Uint32 addr1 = ((const symbol_t*)s1)->address; ! 62: Uint32 addr2 = ((const symbol_t*)s2)->address; ! 63: ! 64: if (addr1 < addr2) { ! 65: return -1; ! 66: } ! 67: if (addr1 > addr2) { ! 68: return 1; ! 69: } ! 70: fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n", ! 71: ((const symbol_t*)s1)->name, ((const symbol_t*)s2)->name, addr1); ! 72: return 0; ! 73: } ! 74: ! 75: /** ! 76: * compare function for qsort() to sort according to symbol name ! 77: */ ! 78: static int symbols_by_name(const void *s1, const void *s2) ! 79: { ! 80: const char* name1 = ((const symbol_t*)s1)->name; ! 81: const char* name2 = ((const symbol_t*)s2)->name; ! 82: int ret; ! 83: ! 84: ret = strcmp(name1, name2); ! 85: if (!ret) { ! 86: fprintf(stderr, "WARNING: symbol '%s' listed twice.\n", name1); ! 87: } ! 88: return ret; ! 89: } ! 90: ! 91: ! 92: /** ! 93: * Load symbols of given type and the symbol address addresses from ! 94: * the given file and add given offset to the addresses. ! 95: * Return symbols list or NULL for failure. ! 96: */ ! 97: static symbol_list_t* Symbols_Load(const char *filename, Uint32 offset, Uint32 maxaddr, symtype_t gettype) ! 98: { ! 99: symbol_list_t *list; ! 100: char symchar, buffer[80], name[MAX_SYM_SIZE+1], *buf; ! 101: int count, line, symbols; ! 102: symtype_t symtype; ! 103: Uint32 address; ! 104: FILE *fp; ! 105: ! 106: if (!(fp = fopen(filename, "r"))) { ! 107: fprintf(stderr, "ERROR: opening '%s' failed!\n", filename); ! 108: return NULL; ! 109: } ! 110: ! 111: /* count content lines */ ! 112: symbols = 0; ! 113: while (fgets(buffer, sizeof(buffer), fp)) { ! 114: /* skip comments */ ! 115: if (*buffer == '#') { ! 116: continue; ! 117: } ! 118: /* skip empty lines */ ! 119: for (buf = buffer; isspace(*buf); buf++); ! 120: if (!*buf) { ! 121: continue; ! 122: } ! 123: symbols++; ! 124: } ! 125: fseek(fp, 0, SEEK_SET); ! 126: ! 127: if (!symbols) { ! 128: fprintf(stderr, "ERROR: no symbols/addresses in '%s'!\n", filename); ! 129: fclose(fp); ! 130: return NULL; ! 131: } ! 132: ! 133: /* allocate space for symbol list */ ! 134: list = malloc(sizeof(symbol_list_t)); ! 135: assert(list); ! 136: list->names = malloc(symbols * sizeof(symbol_t)); ! 137: assert(list->names); ! 138: ! 139: /* read symbols */ ! 140: count = 0; ! 141: for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) { ! 142: /* skip comments */ ! 143: if (*buffer == '#') { ! 144: continue; ! 145: } ! 146: /* skip empty lines */ ! 147: for (buf = buffer; isspace(*buf); buf++); ! 148: if (!*buf) { ! 149: continue; ! 150: } ! 151: assert(count < symbols); /* file not modified in meanwhile? */ ! 152: if (sscanf(buffer, "%x %c %32[0-9A-Za-z_]s", &address, &symchar, name) != 3) { ! 153: fprintf(stderr, "WARNING: syntax error in '%s' on line %d, skipping.\n", filename, line); ! 154: continue; ! 155: } ! 156: address += offset; ! 157: if (address > maxaddr) { ! 158: fprintf(stderr, "WARNING: invalid address 0x%x in '%s' on line %d, skipping.\n", address, filename, line); ! 159: continue; ! 160: } ! 161: switch (toupper(symchar)) { ! 162: case 'T': symtype = SYMTYPE_TEXT; break; ! 163: case 'D': symtype = SYMTYPE_DATA; break; ! 164: case 'B': symtype = SYMTYPE_BSS; break; ! 165: default: ! 166: fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d in '%s', skipping.\n", symchar, line, filename); ! 167: continue; ! 168: } ! 169: if (!(gettype & symtype)) { ! 170: continue; ! 171: } ! 172: list->names[count].address = address; ! 173: list->names[count].type = symtype; ! 174: list->names[count].name = strdup(name); ! 175: assert(list->names[count].name); ! 176: count++; ! 177: } ! 178: ! 179: if (count < symbols) { ! 180: if (!count) { ! 181: fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename); ! 182: free(list->names); ! 183: free(list); ! 184: fclose(fp); ! 185: return NULL; ! 186: } ! 187: /* parsed less than there were "content" lines */ ! 188: list->names = realloc(list->names, count * sizeof(symbol_t)); ! 189: assert(list->names); ! 190: } ! 191: list->count = count; ! 192: ! 193: /* copy name list to address list */ ! 194: list->addresses = malloc(count * sizeof(symbol_t)); ! 195: assert(list->addresses); ! 196: memcpy(list->addresses, list->names, count * sizeof(symbol_t)); ! 197: ! 198: /* sort both lists, with different criteria */ ! 199: qsort(list->addresses, count, sizeof(symbol_t), symbols_by_address); ! 200: qsort(list->names, count, sizeof(symbol_t), symbols_by_name); ! 201: ! 202: fclose(fp); ! 203: fprintf(stderr, "Loaded %d symbols from '%s'.\n", count, filename); ! 204: return list; ! 205: } ! 206: ! 207: ! 208: /** ! 209: * Free read symbols. ! 210: */ ! 211: static void Symbols_Free(symbol_list_t* list) ! 212: { ! 213: int i; ! 214: ! 215: if (!list) { ! 216: return; ! 217: } ! 218: assert(list->count); ! 219: for (i = 0; i < list->count; i++) { ! 220: free(list->names[i].name); ! 221: } ! 222: free(list->addresses); ! 223: free(list->names); ! 224: list->count = 0; /* catch use of freed list */ ! 225: free(list); ! 226: } ! 227: ! 228: ! 229: /* ---------------- symbol name completion support ------------------ */ ! 230: ! 231: /** ! 232: * Helper for symbol name completion and finding their addresses. ! 233: * STATE = 0 -> different text from previous one. ! 234: * Return (copy of) next name or NULL if no matches. ! 235: */ ! 236: static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state) ! 237: { ! 238: const symbol_t *entry; ! 239: static int i, len; ! 240: ! 241: if (!list) { ! 242: return NULL; ! 243: } ! 244: ! 245: if (!state) { ! 246: /* first match */ ! 247: len = strlen(text); ! 248: i = 0; ! 249: } ! 250: ! 251: /* next match */ ! 252: entry = list->names; ! 253: while (i < list->count) { ! 254: if ((entry[i].type & symtype) && ! 255: strncmp(entry[i].name, text, len) == 0) { ! 256: return strdup(entry[i++].name); ! 257: } else { ! 258: i++; ! 259: } ! 260: } ! 261: return NULL; ! 262: } ! 263: ! 264: /** ! 265: * Readline match callbacks for CPU symbol name completion. ! 266: * STATE = 0 -> different text from previous one. ! 267: * Return next match or NULL if no matches. ! 268: */ ! 269: char* Symbols_MatchCpuAddress(const char *text, int state) ! 270: { ! 271: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state); ! 272: } ! 273: char* Symbols_MatchCpuCodeAddress(const char *text, int state) ! 274: { ! 275: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_TEXT, text, state); ! 276: } ! 277: char* Symbols_MatchCpuDataAddress(const char *text, int state) ! 278: { ! 279: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state); ! 280: } ! 281: ! 282: /** ! 283: * Readline match callback for DSP symbol name completion. ! 284: * STATE = 0 -> different text from previous one. ! 285: * Return next match or NULL if no matches. ! 286: */ ! 287: char* Symbols_MatchDspAddress(const char *text, int state) ! 288: { ! 289: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state); ! 290: } ! 291: char* Symbols_MatchDspCodeAddress(const char *text, int state) ! 292: { ! 293: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_TEXT, text, state); ! 294: } ! 295: char* Symbols_MatchDspDataAddress(const char *text, int state) ! 296: { ! 297: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state); ! 298: } ! 299: ! 300: ! 301: /* ---------------- symbol name -> address search ------------------ */ ! 302: ! 303: /** ! 304: * Search symbol of given type by name. ! 305: * Return symbol if name matches, zero otherwise. ! 306: */ ! 307: static const symbol_t* Symbols_SearchByName(symbol_list_t* list, symtype_t symtype, const char *name) ! 308: { ! 309: symbol_t *entries; ! 310: /* left, right, middle */ ! 311: int l, r, m, dir; ! 312: ! 313: if (!list) { ! 314: return NULL; ! 315: } ! 316: entries = list->names; ! 317: ! 318: /* bisect */ ! 319: l = 0; ! 320: r = list->count - 1; ! 321: do { ! 322: m = (l+r) >> 1; ! 323: dir = strcmp(entries[m].name, name); ! 324: if (dir == 0 && (entries[m].type & symtype)) { ! 325: return &(entries[m]); ! 326: } ! 327: if (dir > 0) { ! 328: r = m-1; ! 329: } else { ! 330: l = m+1; ! 331: } ! 332: } while (l <= r); ! 333: return NULL; ! 334: } ! 335: ! 336: /** ! 337: * Set given CPU symbol's address to variable and return TRUE if one was found. ! 338: */ ! 339: bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, Uint32 *addr) ! 340: { ! 341: const symbol_t *entry; ! 342: entry = Symbols_SearchByName(CpuSymbolsList, symtype, name); ! 343: if (entry) { ! 344: *addr = entry->address; ! 345: return true; ! 346: } ! 347: return false; ! 348: } ! 349: ! 350: /** ! 351: * Set given DSP symbol's address to variable and return TRUE if one was found. ! 352: */ ! 353: bool Symbols_GetDspAddress(symtype_t symtype, const char *name, Uint32 *addr) ! 354: { ! 355: const symbol_t *entry; ! 356: entry = Symbols_SearchByName(DspSymbolsList, symtype, name); ! 357: if (entry) { ! 358: *addr = entry->address; ! 359: return true; ! 360: } ! 361: return false; ! 362: } ! 363: ! 364: ! 365: /* ---------------- symbol address -> name search ------------------ */ ! 366: ! 367: /** ! 368: * Search symbol by address. ! 369: * Return symbol name if address matches, NULL otherwise. ! 370: */ ! 371: static const char* Symbols_SearchByAddress(symbol_list_t* list, Uint32 addr) ! 372: { ! 373: symbol_t *entries; ! 374: /* left, right, middle */ ! 375: int l, r, m; ! 376: Uint32 curr; ! 377: ! 378: if (!list) { ! 379: return NULL; ! 380: } ! 381: entries = list->addresses; ! 382: ! 383: /* bisect */ ! 384: l = 0; ! 385: r = list->count - 1; ! 386: do { ! 387: m = (l+r) >> 1; ! 388: curr = entries[m].address; ! 389: if (curr == addr) { ! 390: return (const char*)entries[m].name; ! 391: } ! 392: if (curr > addr) { ! 393: r = m-1; ! 394: } else { ! 395: l = m+1; ! 396: } ! 397: } while (l <= r); ! 398: return NULL; ! 399: } ! 400: ! 401: /** ! 402: * Search CPU symbol by address. ! 403: * Return symbol name if address matches, NULL otherwise. ! 404: * Returned name is valid only until next Symbols_* function call. ! 405: */ ! 406: const char* Symbols_GetByCpuAddress(Uint32 addr) ! 407: { ! 408: return Symbols_SearchByAddress(CpuSymbolsList, addr); ! 409: } ! 410: /** ! 411: * Search DSP symbol by address. ! 412: * Return symbol name if address matches, NULL otherwise. ! 413: * Returned name is valid only until next Symbols_* function call. ! 414: */ ! 415: const char* Symbols_GetByDspAddress(Uint32 addr) ! 416: { ! 417: return Symbols_SearchByAddress(DspSymbolsList, addr); ! 418: } ! 419: ! 420: ! 421: /* ---------------- symbol showing and command parsing ------------------ */ ! 422: ! 423: /** ! 424: * Show symbols from given list with paging. ! 425: */ ! 426: static void Symbols_Show(symbol_list_t* list, const char *sorttype) ! 427: { ! 428: symbol_t *entry, *entries; ! 429: char symchar; ! 430: int i; ! 431: ! 432: if (!list) { ! 433: fprintf(stderr, "No symbols!\n"); ! 434: return; ! 435: } ! 436: ! 437: if (strcmp("addr", sorttype) == 0) { ! 438: entries = list->addresses; ! 439: } else { ! 440: entries = list->names; ! 441: } ! 442: fprintf(stderr, "%s symbols sorted by %s:\n", ! 443: (list == CpuSymbolsList ? "CPU" : "DSP"), sorttype); ! 444: ! 445: for (entry = entries, i = 0; i < list->count; i++, entry++) { ! 446: switch (entry->type) { ! 447: case SYMTYPE_TEXT: ! 448: symchar = 'T'; ! 449: break; ! 450: case SYMTYPE_DATA: ! 451: symchar = 'D'; ! 452: break; ! 453: case SYMTYPE_BSS: ! 454: symchar = 'B'; ! 455: break; ! 456: default: ! 457: symchar = '?'; ! 458: } ! 459: fprintf(stderr, "0x%08x %c %s\n", ! 460: entry->address, symchar, entry->name); ! 461: if (i && i % 20 == 0) { ! 462: fprintf(stderr, "--- q to exit listing, just enter to continue --- "); ! 463: if (toupper(getchar()) == 'Q') { ! 464: return; ! 465: } ! 466: } ! 467: } ! 468: } ! 469: ! 470: const char Symbols_Description[] = ! 471: "<filename|addr|name|free> [offset]\n" ! 472: "\tLoads symbol names and their addresses (with optional offset)\n" ! 473: "\tfrom given <filename>. If there were previously loaded symbols,\n" ! 474: "\tthey're replaced. Giving either 'name' or 'addr' instead of\n" ! 475: "\ta file name, will list the currently loaded symbols. Giving\n" ! 476: "\t'free' will remove the loaded symbols."; ! 477: ! 478: /** ! 479: * Handle debugger 'symbols' command and its arguments ! 480: */ ! 481: int Symbols_Command(int nArgc, char *psArgs[]) ! 482: { ! 483: enum { TYPE_NONE, TYPE_CPU, TYPE_DSP } listtype; ! 484: Uint32 offset, maxaddr; ! 485: symbol_list_t *list; ! 486: const char *file; ! 487: ! 488: if (strcmp("dspsymbols", psArgs[0]) == 0) { ! 489: listtype = TYPE_DSP; ! 490: maxaddr = 0xFFFF; ! 491: } else if (strcmp("symbols", psArgs[0]) == 0) { ! 492: listtype = TYPE_CPU; ! 493: maxaddr = 0xFFFFFF; ! 494: } else { ! 495: listtype = TYPE_NONE; ! 496: maxaddr = 0; ! 497: } ! 498: if (nArgc < 2 || listtype == TYPE_NONE) { ! 499: DebugUI_PrintCmdHelp(psArgs[0]); ! 500: return DEBUGGER_CMDDONE; ! 501: } ! 502: file = psArgs[1]; ! 503: ! 504: /* handle special cases */ ! 505: if (strcmp(file, "name") == 0 || strcmp(file, "addr") == 0) { ! 506: list = (listtype == TYPE_DSP ? DspSymbolsList : CpuSymbolsList); ! 507: Symbols_Show(list, file); ! 508: return DEBUGGER_CMDDONE; ! 509: } ! 510: if (strcmp(file, "free") == 0) { ! 511: if (listtype == TYPE_DSP) { ! 512: Symbols_Free(DspSymbolsList); ! 513: DspSymbolsList = NULL; ! 514: } else { ! 515: Symbols_Free(CpuSymbolsList); ! 516: CpuSymbolsList = NULL; ! 517: } ! 518: return DEBUGGER_CMDDONE; ! 519: } ! 520: if (nArgc >= 3) { ! 521: int dummy; ! 522: Eval_Expression(psArgs[2], &offset, &dummy, listtype==TYPE_DSP); ! 523: } else { ! 524: offset = 0; ! 525: } ! 526: ! 527: list = Symbols_Load(file, offset, maxaddr, SYMTYPE_ALL); ! 528: if (list) { ! 529: if (listtype == TYPE_CPU) { ! 530: Symbols_Free(CpuSymbolsList); ! 531: CpuSymbolsList = list; ! 532: } else { ! 533: Symbols_Free(DspSymbolsList); ! 534: DspSymbolsList = list; ! 535: } ! 536: } else { ! 537: DebugUI_PrintCmdHelp(psArgs[0]); ! 538: } ! 539: return DEBUGGER_CMDDONE; ! 540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.