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