|
|
1.1 root 1: /*
2: * Hatari - symbols.c
3: *
1.1.1.5 ! root 4: * Copyright (C) 2010-2013 by Eero Tamminen
1.1 root 5: *
1.1.1.5 ! root 6: * This file is distributed under the GNU General Public License, version 2
! 7: * or at your option any later version. Read the file gpl.txt for details.
1.1 root 8: *
9: * symbols.c - Hatari debugger symbol/address handling; parsing, sorting,
10: * matching, TAB completion support etc.
11: *
1.1.1.5 ! root 12: * Symbol/address information is read either from:
! 13: * - A program file's DRI/GST format symbol table, or
! 14: * - ASCII file which contents are subset of "nm" output i.e. composed of
! 15: * a hexadecimal addresses followed by a space, letter indicating symbol
! 16: * type (T = text/code, D = data, B = BSS), space and the symbol name.
! 17: * Empty lines and lines starting with '#' are ignored. It's AHCC SYM
! 18: * output compatible.
1.1 root 19: */
20: const char Symbols_fileid[] = "Hatari symbols.c : " __DATE__ " " __TIME__;
21:
22: #include <ctype.h>
23: #include <stdio.h>
24: #include <string.h>
25: #include <assert.h>
26: #include <SDL_types.h>
1.1.1.5 ! root 27: #include <SDL_endian.h>
1.1 root 28: #include "main.h"
29: #include "symbols.h"
30: #include "debugui.h"
31: #include "debug_priv.h"
1.1.1.5 ! root 32: #include "debugInfo.h"
1.1 root 33: #include "evaluate.h"
1.1.1.5 ! root 34: #include "gemdos.h"
1.1 root 35:
36: typedef struct {
37: char *name;
38: Uint32 address;
39: symtype_t type;
40: } symbol_t;
41:
42: typedef struct {
1.1.1.5 ! root 43: int count; /* final symbol count */
! 44: int symbols; /* initial symbol count */
1.1 root 45: symbol_t *addresses; /* items sorted by address */
46: symbol_t *names; /* items sorted by symbol name */
47: } symbol_list_t;
48:
1.1.1.5 ! root 49: typedef struct {
! 50: Uint32 offset;
! 51: Uint32 end;
! 52: } prg_section_t;
! 53:
1.1 root 54:
55: /* how many characters the symbol name can have.
56: * NOTE: change also sscanf width arg if you change this!!!
57: */
58: #define MAX_SYM_SIZE 32
59:
60:
61: /* TODO: add symbol name/address file names to configuration? */
62: static symbol_list_t *CpuSymbolsList;
63: static symbol_list_t *DspSymbolsList;
64:
65:
66: /* ------------------ load and free functions ------------------ */
67:
68: /**
69: * compare function for qsort() to sort according to symbol address
70: */
71: static int symbols_by_address(const void *s1, const void *s2)
72: {
73: Uint32 addr1 = ((const symbol_t*)s1)->address;
74: Uint32 addr2 = ((const symbol_t*)s2)->address;
75:
76: if (addr1 < addr2) {
77: return -1;
78: }
79: if (addr1 > addr2) {
80: return 1;
81: }
82: fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
83: ((const symbol_t*)s1)->name, ((const symbol_t*)s2)->name, addr1);
84: return 0;
85: }
86:
87: /**
88: * compare function for qsort() to sort according to symbol name
89: */
90: static int symbols_by_name(const void *s1, const void *s2)
91: {
92: const char* name1 = ((const symbol_t*)s1)->name;
93: const char* name2 = ((const symbol_t*)s2)->name;
94: int ret;
95:
96: ret = strcmp(name1, name2);
97: if (!ret) {
1.1.1.4 root 98: fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
99: ((const symbol_t*)s1)->address, ((const symbol_t*)s2)->address, name1);
1.1 root 100: }
101: return ret;
102: }
103:
104:
105: /**
1.1.1.5 ! root 106: * Allocate symbol list & names for given number of items.
! 107: * Return allocated list or NULL on failure.
! 108: */
! 109: static symbol_list_t* symbol_list_alloc(int symbols)
! 110: {
! 111: symbol_list_t *list;
! 112:
! 113: if (!symbols) {
! 114: return NULL;
! 115: }
! 116: list = calloc(1, sizeof(symbol_list_t));
! 117: if (list) {
! 118: list->names = malloc(symbols * sizeof(symbol_t));
! 119: if (!list->names) {
! 120: free(list);
! 121: list = NULL;
! 122: }
! 123: }
! 124: return list;
! 125: }
! 126:
! 127: /**
! 128: * Free symbol list & names.
! 129: */
! 130: static void symbol_list_free(symbol_list_t *list)
! 131: {
! 132: if (list) {
! 133: if (list->names) {
! 134: free(list->names);
! 135: }
! 136: free(list);
! 137: }
! 138: }
! 139:
! 140: /**
1.1 root 141: * Load symbols of given type and the symbol address addresses from
1.1.1.5 ! root 142: * DRI/GST format symbol table, and add given offsets to the addresses:
! 143: * http://toshyp.atari.org/en/005005.html
1.1 root 144: * Return symbols list or NULL for failure.
145: */
1.1.1.5 ! root 146: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize)
1.1 root 147: {
1.1.1.5 ! root 148: int i, count, symbols, len;
! 149: int dtypes, locals, ofiles;
! 150: prg_section_t *section;
1.1 root 151: symbol_list_t *list;
152: symtype_t symtype;
1.1.1.5 ! root 153: #define DRI_ENTRY_SIZE 14
! 154: char name[23];
! 155: Uint16 symid;
1.1 root 156: Uint32 address;
1.1.1.5 ! root 157:
! 158: if (tablesize % DRI_ENTRY_SIZE) {
! 159: fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
! 160: return NULL;
! 161: }
! 162: symbols = tablesize / DRI_ENTRY_SIZE;
! 163: if (!(list = symbol_list_alloc(symbols))) {
! 164: return NULL;
! 165: }
! 166:
! 167: dtypes = ofiles = locals = count = 0;
! 168: for (i = 1; i <= symbols; i++) {
! 169: /* read DRI symbol table slot */
! 170: if (fread(name, 8, 1, fp) != 1 ||
! 171: fread(&symid, sizeof(symid), 1, fp) != 1 ||
! 172: fread(&address, sizeof(address), 1, fp) != 1) {
! 173: break;
! 174: }
! 175: address = SDL_SwapBE32(address);
! 176: symid = SDL_SwapBE16(symid);
! 177:
! 178: /* GST extended DRI symbol format? */
! 179: if ((symid & 0x0048)) {
! 180: /* next slot is rest of name */
! 181: i += 1;
! 182: if (fread(name+8, 14, 1, fp) != 1) {
! 183: break;
! 184: }
! 185: name[22] = '\0';
! 186: } else {
! 187: name[8] = '\0';
! 188: }
! 189:
! 190: /* check section */
! 191: switch (symid & 0xf00) {
! 192: case 0x0200:
! 193: symtype = SYMTYPE_TEXT;
! 194: section = &(sections[0]);
! 195: break;
! 196: case 0x0400:
! 197: symtype = SYMTYPE_DATA;
! 198: section = &(sections[1]);
! 199: break;
! 200: case 0x0100:
! 201: symtype = SYMTYPE_BSS;
! 202: section = &(sections[2]);
! 203: break;
! 204: default:
! 205: if ((symid & 0xe000) == 0xe000) {
! 206: dtypes++;
! 207: continue;
! 208: }
! 209: fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
! 210: continue;
! 211: }
! 212: if (!(gettype & symtype)) {
! 213: continue;
! 214: }
! 215: if (name[0] == '.' && name[1] == 'L') {
! 216: locals++;
! 217: continue;
! 218: }
! 219: len = strlen(name);
! 220: if (strchr(name, '/') || (len > 2 && name[len-2] == '.' && name[len-1] == 'o')) {
! 221: ofiles++;
! 222: continue;
! 223: }
! 224: address += section->offset;
! 225: if (address > section->end) {
! 226: fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d with invalid offset 0x%x (>= 0x%x).\n", name, i, address, section->end);
! 227: continue;
! 228: }
! 229: list->names[count].address = address;
! 230: list->names[count].type = symtype;
! 231: list->names[count].name = strdup(name);
! 232: assert(list->names[count].name);
! 233: count++;
! 234: }
! 235: if (i <= symbols) {
! 236: perror("ERROR: reading symbol failed");
! 237: symbol_list_free(list);
1.1 root 238: return NULL;
239: }
1.1.1.5 ! root 240: if (dtypes) {
! 241: fprintf(stderr, "NOTE: ignored %d globally defined equated values.\n", dtypes);
! 242: }
! 243: if (locals) {
! 244: fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
! 245: }
! 246: if (ofiles) {
! 247: /* object file path names most likely get truncated and
! 248: * as result cause unnecessary symbol name conflicts in
! 249: * addition to object file addresses conflicting with
! 250: * first symbol in the object file.
! 251: */
! 252: fprintf(stderr, "NOTE: ignored %d object file names (= name has '/' or ends in '.o').\n", ofiles);
! 253: }
! 254: list->symbols = symbols;
! 255: list->count = count;
! 256: return list;
! 257: }
! 258:
! 259: /**
! 260: * Parse program header and use symbol table format specific loader
! 261: * loader function to load the symbols.
! 262: * Return symbols list or NULL for failure.
! 263: */
! 264: static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
! 265: {
! 266: Uint32 textlen, datalen, bsslen, start, tablesize, tabletype;
! 267: prg_section_t sections[3];
! 268: int offset, reads = 0;
! 269:
! 270: /* get TEXT, DATA & BSS section sizes */
! 271: reads += fread(&textlen, sizeof(textlen), 1, fp);
! 272: textlen = SDL_SwapBE32(textlen);
! 273: reads += fread(&datalen, sizeof(datalen), 1, fp);
! 274: datalen = SDL_SwapBE32(datalen);
! 275: reads += fread(&bsslen, sizeof(bsslen), 1, fp);
! 276: bsslen = SDL_SwapBE32(bsslen);
! 277:
! 278: /* get symbol table size & type and check that all reads succeeded */
! 279: reads += fread(&tablesize, sizeof(tablesize), 1, fp);
! 280: tablesize = SDL_SwapBE32(tablesize);
! 281: if (!tablesize) {
! 282: fprintf(stderr, "ERROR: symbol table missing from the program!\n");
! 283: return NULL;
! 284: }
! 285: reads += fread(&tabletype, sizeof(tabletype), 1, fp);
! 286: tabletype = SDL_SwapBE32(tabletype);
! 287: if (reads != 5) {
! 288: fprintf(stderr, "ERROR: program header reading failed!\n");
! 289: return NULL;
! 290: }
! 291:
! 292: /* go to start of symbol table */
! 293: offset = 0x1C + textlen + datalen;
! 294: if (fseek(fp, offset, SEEK_SET) < 0) {
! 295: perror("ERROR: seeking to symbol table failed");
! 296: return NULL;
! 297: }
! 298: /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
! 299: start = DebugInfo_GetTEXT();
! 300: if (!start) {
! 301: fprintf(stderr, "ERROR: no valid program basepage!\n");
! 302: return NULL;
! 303: }
! 304: sections[0].offset = start;
! 305: sections[0].end = start + textlen;
! 306: if (DebugInfo_GetTEXTEnd() != sections[0].end - 1) {
! 307: fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
! 308: return NULL;
! 309: }
! 310:
! 311: start = DebugInfo_GetDATA();
! 312: sections[1].offset = start - textlen;
! 313: sections[1].end = start + datalen - 1;
! 314:
! 315: start = DebugInfo_GetBSS();
! 316: sections[2].offset = start - textlen - datalen;
! 317: sections[2].end = start + bsslen - 1;
! 318:
! 319: switch (tabletype) {
! 320: case 0x4D694E54: /* "MiNT" */
! 321: fprintf(stderr, "MiNT executable, trying to load GST symbol table at offset 0x%x...\n", offset);
! 322: return symbols_load_dri(fp, sections, gettype, tablesize);
! 323: case 0x0:
! 324: fprintf(stderr, "Old style excutable, loading DRI / GST symbol table at offset 0x%x.\n", offset);
! 325: return symbols_load_dri(fp, sections, gettype, tablesize);
! 326: default:
! 327: fprintf(stderr, "ERROR: unknown executable type 0x%x at offset 0x%x!\n", tabletype, offset);
! 328: }
! 329: return NULL;
! 330: }
! 331:
! 332: /**
! 333: * Load symbols of given type and the symbol address addresses from
! 334: * the given ASCII file and add given offsets to the addresses.
! 335: * Return symbols list or NULL for failure.
! 336: */
! 337: static symbol_list_t* symbols_load_ascii(FILE *fp, Uint32 *offsets, Uint32 maxaddr, symtype_t gettype)
! 338: {
! 339: symbol_list_t *list;
! 340: char symchar, buffer[128], name[MAX_SYM_SIZE+1], *buf;
! 341: int count, line, symbols;
! 342: Uint32 address, offset;
! 343: symtype_t symtype;
1.1 root 344:
345: /* count content lines */
346: symbols = 0;
347: while (fgets(buffer, sizeof(buffer), fp)) {
1.1.1.3 root 348: /* skip comments (AHCC SYM file comments start with '*') */
349: if (*buffer == '#' || *buffer == '*') {
1.1 root 350: continue;
351: }
352: /* skip empty lines */
353: for (buf = buffer; isspace(*buf); buf++);
354: if (!*buf) {
355: continue;
356: }
357: symbols++;
358: }
359: fseek(fp, 0, SEEK_SET);
360:
1.1.1.5 ! root 361: /* allocate space for symbol list & names */
! 362: if (!(list = symbol_list_alloc(symbols))) {
1.1 root 363: return NULL;
364: }
365:
366: /* read symbols */
367: count = 0;
368: for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) {
1.1.1.3 root 369: /* skip comments (AHCC SYM file comments start with '*') */
370: if (*buffer == '#' || *buffer == '*') {
1.1 root 371: continue;
372: }
373: /* skip empty lines */
374: for (buf = buffer; isspace(*buf); buf++);
375: if (!*buf) {
376: continue;
377: }
378: assert(count < symbols); /* file not modified in meanwhile? */
1.1.1.5 ! root 379: if (sscanf(buffer, "%x %c %32[0-9A-Za-z_.-]s", &address, &symchar, name) != 3) {
! 380: fprintf(stderr, "WARNING: syntax error on line %d, skipping.\n", line);
1.1 root 381: continue;
382: }
383: switch (toupper(symchar)) {
1.1.1.5 ! root 384: case 'T':
! 385: symtype = SYMTYPE_TEXT;
! 386: offset = offsets[0];
! 387: break;
! 388: case 'O': /* AHCC type for _StkSize etc */
! 389: case 'D':
! 390: symtype = SYMTYPE_DATA;
! 391: offset = offsets[1];
! 392: break;
! 393: case 'B':
! 394: symtype = SYMTYPE_BSS;
! 395: offset = offsets[2];
! 396: break;
1.1 root 397: default:
1.1.1.5 ! root 398: fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d, skipping.\n", symchar, line);
1.1 root 399: continue;
400: }
401: if (!(gettype & symtype)) {
402: continue;
403: }
1.1.1.5 ! root 404: address += offset;
! 405: if (address > maxaddr) {
! 406: fprintf(stderr, "WARNING: invalid address 0x%x on line %d, skipping.\n", address, line);
! 407: continue;
! 408: }
1.1 root 409: list->names[count].address = address;
410: list->names[count].type = symtype;
411: list->names[count].name = strdup(name);
412: assert(list->names[count].name);
413: count++;
414: }
1.1.1.5 ! root 415: list->symbols = symbols;
! 416: list->count = count;
! 417: return list;
! 418: }
1.1 root 419:
1.1.1.5 ! root 420: /**
! 421: * Load symbols of given type and the symbol address addresses from
! 422: * the given file and add given offsets to the addresses.
! 423: * Return symbols list or NULL for failure.
! 424: */
! 425: static symbol_list_t* Symbols_Load(const char *filename, Uint32 *offsets, Uint32 maxaddr)
! 426: {
! 427: symbol_list_t *list;
! 428: Uint16 magic;
! 429: FILE *fp;
! 430:
! 431: if (!(fp = fopen(filename, "r"))) {
! 432: fprintf(stderr, "ERROR: opening '%s' failed!\n", filename);
! 433: return NULL;
! 434: }
! 435: if (fread(&magic, sizeof(magic), 1, fp) != 1) {
! 436: fprintf(stderr, "ERROR: reading file '%s' failed.\n", filename);
! 437: fclose(fp);
! 438: return NULL;
! 439: }
! 440:
! 441: if (SDL_SwapBE16(magic) == 0x601A) {
! 442: const char *last = GemDOS_GetLastProgramPath();
! 443: fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
! 444: if (strcmp(last, filename) != 0) {
! 445: fprintf(stderr, "WARNING: given program doesn't match last program executed by GEMDOS HD emulation:\n\t%s", last);
! 446: }
! 447: list = symbols_load_binary(fp, SYMTYPE_ALL);
! 448: } else {
! 449: fprintf(stderr, "Reading 'nm' style ASCII symbols from '%s'...\n", filename);
! 450: list = symbols_load_ascii(fp, offsets, maxaddr, SYMTYPE_ALL);
! 451: }
! 452: fclose(fp);
! 453:
! 454: if (!list) {
! 455: fprintf(stderr, "ERROR: no symbols, or reading them from '%s' failed!\n", filename);
! 456: return NULL;
! 457: }
! 458:
! 459: if (list->count < list->symbols) {
! 460: if (!list->count) {
1.1 root 461: fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename);
1.1.1.5 ! root 462: symbol_list_free(list);
1.1 root 463: return NULL;
464: }
465: /* parsed less than there were "content" lines */
1.1.1.5 ! root 466: list->names = realloc(list->names, list->count * sizeof(symbol_t));
1.1 root 467: assert(list->names);
468: }
469:
470: /* copy name list to address list */
1.1.1.5 ! root 471: list->addresses = malloc(list->count * sizeof(symbol_t));
1.1 root 472: assert(list->addresses);
1.1.1.5 ! root 473: memcpy(list->addresses, list->names, list->count * sizeof(symbol_t));
1.1 root 474:
475: /* sort both lists, with different criteria */
1.1.1.5 ! root 476: qsort(list->addresses, list->count, sizeof(symbol_t), symbols_by_address);
! 477: qsort(list->names, list->count, sizeof(symbol_t), symbols_by_name);
1.1 root 478:
1.1.1.5 ! root 479: fprintf(stderr, "Loaded %d symbols from '%s'.\n", list->count, filename);
1.1 root 480: return list;
481: }
482:
483:
484: /**
485: * Free read symbols.
486: */
487: static void Symbols_Free(symbol_list_t* list)
488: {
1.1.1.5 ! root 489: int i;
1.1 root 490:
491: if (!list) {
492: return;
493: }
494: assert(list->count);
495: for (i = 0; i < list->count; i++) {
496: free(list->names[i].name);
497: }
498: free(list->addresses);
499: free(list->names);
1.1.1.5 ! root 500:
! 501: /* catch use of freed list */
! 502: list->addresses = NULL;
! 503: list->names = NULL;
! 504: list->count = 0;
1.1 root 505: free(list);
506: }
507:
508:
509: /* ---------------- symbol name completion support ------------------ */
510:
511: /**
512: * Helper for symbol name completion and finding their addresses.
513: * STATE = 0 -> different text from previous one.
514: * Return (copy of) next name or NULL if no matches.
515: */
516: static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state)
517: {
1.1.1.5 ! root 518: static int i, len;
1.1 root 519: const symbol_t *entry;
520:
521: if (!list) {
522: return NULL;
523: }
524:
525: if (!state) {
526: /* first match */
527: len = strlen(text);
528: i = 0;
529: }
530:
531: /* next match */
532: entry = list->names;
533: while (i < list->count) {
534: if ((entry[i].type & symtype) &&
535: strncmp(entry[i].name, text, len) == 0) {
536: return strdup(entry[i++].name);
537: } else {
538: i++;
539: }
540: }
541: return NULL;
542: }
543:
544: /**
545: * Readline match callbacks for CPU symbol name completion.
546: * STATE = 0 -> different text from previous one.
547: * Return next match or NULL if no matches.
548: */
549: char* Symbols_MatchCpuAddress(const char *text, int state)
550: {
551: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
552: }
553: char* Symbols_MatchCpuCodeAddress(const char *text, int state)
554: {
555: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_TEXT, text, state);
556: }
557: char* Symbols_MatchCpuDataAddress(const char *text, int state)
558: {
559: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
560: }
561:
562: /**
563: * Readline match callback for DSP symbol name completion.
564: * STATE = 0 -> different text from previous one.
565: * Return next match or NULL if no matches.
566: */
567: char* Symbols_MatchDspAddress(const char *text, int state)
568: {
569: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state);
570: }
571: char* Symbols_MatchDspCodeAddress(const char *text, int state)
572: {
573: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_TEXT, text, state);
574: }
575: char* Symbols_MatchDspDataAddress(const char *text, int state)
576: {
577: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
578: }
579:
580:
581: /* ---------------- symbol name -> address search ------------------ */
582:
583: /**
584: * Search symbol of given type by name.
585: * Return symbol if name matches, zero otherwise.
586: */
587: static const symbol_t* Symbols_SearchByName(symbol_list_t* list, symtype_t symtype, const char *name)
588: {
589: symbol_t *entries;
590: /* left, right, middle */
591: int l, r, m, dir;
592:
593: if (!list) {
594: return NULL;
595: }
596: entries = list->names;
597:
598: /* bisect */
599: l = 0;
600: r = list->count - 1;
601: do {
602: m = (l+r) >> 1;
603: dir = strcmp(entries[m].name, name);
604: if (dir == 0 && (entries[m].type & symtype)) {
605: return &(entries[m]);
606: }
607: if (dir > 0) {
608: r = m-1;
609: } else {
610: l = m+1;
611: }
612: } while (l <= r);
613: return NULL;
614: }
615:
616: /**
617: * Set given CPU symbol's address to variable and return TRUE if one was found.
618: */
619: bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, Uint32 *addr)
620: {
621: const symbol_t *entry;
622: entry = Symbols_SearchByName(CpuSymbolsList, symtype, name);
623: if (entry) {
624: *addr = entry->address;
625: return true;
626: }
627: return false;
628: }
629:
630: /**
631: * Set given DSP symbol's address to variable and return TRUE if one was found.
632: */
633: bool Symbols_GetDspAddress(symtype_t symtype, const char *name, Uint32 *addr)
634: {
635: const symbol_t *entry;
636: entry = Symbols_SearchByName(DspSymbolsList, symtype, name);
637: if (entry) {
638: *addr = entry->address;
639: return true;
640: }
641: return false;
642: }
643:
644:
645: /* ---------------- symbol address -> name search ------------------ */
646:
647: /**
648: * Search symbol by address.
1.1.1.5 ! root 649: * Return symbol index if address matches, -1 otherwise.
1.1 root 650: */
1.1.1.5 ! root 651: static int Symbols_SearchByAddress(symbol_list_t* list, Uint32 addr)
1.1 root 652: {
653: symbol_t *entries;
654: /* left, right, middle */
655: int l, r, m;
656: Uint32 curr;
657:
658: if (!list) {
1.1.1.5 ! root 659: return -1;
1.1 root 660: }
661: entries = list->addresses;
662:
663: /* bisect */
664: l = 0;
665: r = list->count - 1;
666: do {
667: m = (l+r) >> 1;
668: curr = entries[m].address;
669: if (curr == addr) {
1.1.1.5 ! root 670: return m;
1.1 root 671: }
672: if (curr > addr) {
673: r = m-1;
674: } else {
675: l = m+1;
676: }
677: } while (l <= r);
1.1.1.5 ! root 678: return -1;
1.1 root 679: }
680:
681: /**
682: * Search CPU symbol by address.
683: * Return symbol name if address matches, NULL otherwise.
684: * Returned name is valid only until next Symbols_* function call.
685: */
686: const char* Symbols_GetByCpuAddress(Uint32 addr)
687: {
1.1.1.5 ! root 688: int idx = Symbols_SearchByAddress(CpuSymbolsList, addr);
! 689: if (idx < 0) {
! 690: return NULL;
! 691: }
! 692: return CpuSymbolsList->addresses[idx].name;
1.1 root 693: }
694: /**
695: * Search DSP symbol by address.
696: * Return symbol name if address matches, NULL otherwise.
697: * Returned name is valid only until next Symbols_* function call.
698: */
699: const char* Symbols_GetByDspAddress(Uint32 addr)
700: {
1.1.1.5 ! root 701: int idx = Symbols_SearchByAddress(DspSymbolsList, addr);
! 702: if (idx < 0) {
! 703: return NULL;
! 704: }
! 705: return DspSymbolsList->addresses[idx].name;
! 706: }
! 707:
! 708: /**
! 709: * Search CPU symbol by address.
! 710: * Return symbol index if address matches, -1 otherwise.
! 711: */
! 712: int Symbols_GetCpuAddressIndex(Uint32 addr)
! 713: {
! 714: return Symbols_SearchByAddress(CpuSymbolsList, addr);
! 715: }
! 716:
! 717: /**
! 718: * Search DSP symbol by address.
! 719: * Return symbol index if address matches, -1 otherwise.
! 720: */
! 721: int Symbols_GetDspAddressIndex(Uint32 addr)
! 722: {
! 723: return Symbols_SearchByAddress(DspSymbolsList, addr);
1.1 root 724: }
725:
1.1.1.5 ! root 726: /**
! 727: * Return how many symbols are loaded/available
! 728: */
! 729: int Symbols_CpuCount(void)
! 730: {
! 731: return (CpuSymbolsList ? CpuSymbolsList->count : 0);
! 732: }
! 733: int Symbols_DspCount(void)
! 734: {
! 735: return (DspSymbolsList ? DspSymbolsList->count : 0);
! 736: }
1.1 root 737:
738: /* ---------------- symbol showing and command parsing ------------------ */
739:
740: /**
741: * Show symbols from given list with paging.
742: */
743: static void Symbols_Show(symbol_list_t* list, const char *sorttype)
744: {
745: symbol_t *entry, *entries;
746: char symchar;
1.1.1.5 ! root 747: int i;
1.1 root 748:
749: if (!list) {
750: fprintf(stderr, "No symbols!\n");
751: return;
752: }
753:
754: if (strcmp("addr", sorttype) == 0) {
755: entries = list->addresses;
756: } else {
757: entries = list->names;
758: }
759: fprintf(stderr, "%s symbols sorted by %s:\n",
760: (list == CpuSymbolsList ? "CPU" : "DSP"), sorttype);
761:
762: for (entry = entries, i = 0; i < list->count; i++, entry++) {
763: switch (entry->type) {
764: case SYMTYPE_TEXT:
765: symchar = 'T';
766: break;
767: case SYMTYPE_DATA:
768: symchar = 'D';
769: break;
770: case SYMTYPE_BSS:
771: symchar = 'B';
772: break;
773: default:
774: symchar = '?';
775: }
776: fprintf(stderr, "0x%08x %c %s\n",
777: entry->address, symchar, entry->name);
778: if (i && i % 20 == 0) {
779: fprintf(stderr, "--- q to exit listing, just enter to continue --- ");
780: if (toupper(getchar()) == 'Q') {
781: return;
782: }
783: }
784: }
785: }
786:
787: const char Symbols_Description[] =
1.1.1.5 ! root 788: "<filename|prg|addr|name|free> [<T offset> [<D offset> <B offset>]]\n"
! 789: "\tLoads symbol names and their addresses from the given file.\n"
! 790: "\tIf there were previously loaded symbols, they're replaced.\n"
! 791: "\n"
! 792: "\tGiving 'prg' instead of a file name, loads DRI/GST symbol table\n"
! 793: "\tfrom the last program executed through the GEMDOS HD emulation.\n"
! 794: "\n"
! 795: "\tGiving either 'name' or 'addr' instead of a file name, will\n"
! 796: "\tlist the currently loaded symbols. Giving 'free' will remove\n"
! 797: "\tthe loaded symbols.\n"
! 798: "\n"
! 799: "\tIf one base address/offset is given, its added to all addresses.\n"
! 800: "\tIf three offsets are given (and non-zero), they're applied to\n"
! 801: "\ttext (T), data (D) and BSS (B) symbols. Given offsets are used\n"
! 802: "\tonly when loading ASCII symbol files.";
1.1 root 803:
804: /**
805: * Handle debugger 'symbols' command and its arguments
806: */
807: int Symbols_Command(int nArgc, char *psArgs[])
808: {
809: enum { TYPE_NONE, TYPE_CPU, TYPE_DSP } listtype;
1.1.1.5 ! root 810: Uint32 offsets[3], maxaddr;
1.1 root 811: symbol_list_t *list;
812: const char *file;
1.1.1.5 ! root 813: int i;
1.1 root 814:
815: if (strcmp("dspsymbols", psArgs[0]) == 0) {
816: listtype = TYPE_DSP;
817: maxaddr = 0xFFFF;
818: } else if (strcmp("symbols", psArgs[0]) == 0) {
819: listtype = TYPE_CPU;
820: maxaddr = 0xFFFFFF;
821: } else {
822: listtype = TYPE_NONE;
823: maxaddr = 0;
824: }
825: if (nArgc < 2 || listtype == TYPE_NONE) {
826: DebugUI_PrintCmdHelp(psArgs[0]);
827: return DEBUGGER_CMDDONE;
828: }
829: file = psArgs[1];
830:
831: /* handle special cases */
832: if (strcmp(file, "name") == 0 || strcmp(file, "addr") == 0) {
833: list = (listtype == TYPE_DSP ? DspSymbolsList : CpuSymbolsList);
834: Symbols_Show(list, file);
835: return DEBUGGER_CMDDONE;
836: }
837: if (strcmp(file, "free") == 0) {
838: if (listtype == TYPE_DSP) {
839: Symbols_Free(DspSymbolsList);
840: DspSymbolsList = NULL;
841: } else {
842: Symbols_Free(CpuSymbolsList);
843: CpuSymbolsList = NULL;
844: }
845: return DEBUGGER_CMDDONE;
846: }
1.1.1.5 ! root 847:
! 848: /* get offsets */
! 849: offsets[0] = 0;
! 850: for (i = 0; i < ARRAYSIZE(offsets); i++) {
! 851: if (i+2 < nArgc) {
! 852: int dummy;
! 853: Eval_Expression(psArgs[i+2], &(offsets[i]), &dummy, listtype==TYPE_DSP);
! 854: } else {
! 855: /* default to first (text) offset */
! 856: offsets[i] = offsets[0];
! 857: }
1.1 root 858: }
859:
1.1.1.5 ! root 860: if (strcmp(file, "prg") == 0) {
! 861: file = GemDOS_GetLastProgramPath();
! 862: if (!file) {
! 863: fprintf(stderr, "ERROR: no program loaded (through GEMDOS HD emu)!\n");
! 864: return DEBUGGER_CMDDONE;
! 865: }
! 866: }
! 867: list = Symbols_Load(file, offsets, maxaddr);
1.1 root 868: if (list) {
869: if (listtype == TYPE_CPU) {
870: Symbols_Free(CpuSymbolsList);
871: CpuSymbolsList = list;
872: } else {
873: Symbols_Free(DspSymbolsList);
874: DspSymbolsList = list;
875: }
876: } else {
877: DebugUI_PrintCmdHelp(psArgs[0]);
878: }
879: return DEBUGGER_CMDDONE;
880: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.