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