|
|
1.1 root 1: /*
2: * Hatari - symbols.c
3: *
1.1.1.9 root 4: * Copyright (C) 2010-2017 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:
1.1.1.9 root 13: * - A program file's DRI/GST or a.out format symbol table, or
1.1.1.5 root 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.1.9 root 37: #include "a.out.h"
1.1 root 38:
39: typedef struct {
40: char *name;
41: Uint32 address;
42: symtype_t type;
43: } symbol_t;
44:
45: typedef struct {
1.1.1.5 root 46: int symbols; /* initial symbol count */
1.1.1.9 root 47: int namecount; /* final symbol count */
48: int codecount; /* TEXT symbol address count */
49: int datacount; /* DATA/BSS symbol address count */
50: symbol_t *addresses; /* TEXT + DATA/BSS items sorted by address */
51: symbol_t *names; /* all items sorted by symbol name */
52: char *strtab;
1.1 root 53: } symbol_list_t;
54:
1.1.1.5 root 55: typedef struct {
56: Uint32 offset;
57: Uint32 end;
58: } prg_section_t;
59:
1.1 root 60:
61: /* how many characters the symbol name can have.
62: * NOTE: change also sscanf width arg if you change this!!!
63: */
64: #define MAX_SYM_SIZE 32
65:
1.1.1.9 root 66: /* Magic used to denote different symbol table formats */
67: #define SYMBOL_FORMAT_GNU 0x474E555f /* "MiNT" */
68: #define SYMBOL_FORMAT_MINT 0x4D694E54 /* "GNU_" */
69: #define SYMBOL_FORMAT_DRI 0x0
70:
1.1 root 71:
72: /* TODO: add symbol name/address file names to configuration? */
73: static symbol_list_t *CpuSymbolsList;
74: static symbol_list_t *DspSymbolsList;
75:
1.1.1.6 root 76: /* path for last loaded program (through GEMDOS HD emulation) */
77: static char *CurrentProgramPath;
1.1.1.9 root 78: /* whether current symbols were loaded from a program file */
1.1.1.6 root 79: static bool SymbolsAreForProgram;
1.1.1.9 root 80: /* prevent repeated failing on every debugger invocation */
1.1.1.6 root 81: static bool AutoLoadFailed;
82:
1.1 root 83:
84: /* ------------------ load and free functions ------------------ */
85:
86: /**
1.1.1.9 root 87: * return true if given symbol name is object/library/file name
88: */
89: static bool is_obj_file(const char *name)
90: {
91: int len = strlen(name);
92: /* object (.a or .o) / file name? */
93: if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
94: return true;
95: }
96: return false;
97: }
98:
99: /**
100: * compare function for qsort() to sort according to
101: * symbol type & address. Text section symbols will
102: * be sorted first.
1.1 root 103: */
104: static int symbols_by_address(const void *s1, const void *s2)
105: {
1.1.1.9 root 106: const symbol_t *sym1 = (const symbol_t*)s1;
107: const symbol_t *sym2 = (const symbol_t*)s2;
1.1 root 108:
1.1.1.9 root 109: /* separate TEXT type addresses from others */
110: if (sym1->type != sym2->type) {
111: if (sym1->type == SYMTYPE_TEXT) {
112: return -1;
113: }
114: if (sym2->type == SYMTYPE_TEXT) {
115: return 1;
116: }
117: }
118: /* then sort by address */
119: if (sym1->address < sym2->address) {
1.1 root 120: return -1;
121: }
1.1.1.9 root 122: if (sym1->address > sym2->address) {
1.1 root 123: return 1;
124: }
125: return 0;
126: }
127:
128: /**
1.1.1.9 root 129: * compare function for qsort() to sort according to
130: * symbol name & address
1.1 root 131: */
132: static int symbols_by_name(const void *s1, const void *s2)
133: {
1.1.1.9 root 134: const symbol_t *sym1 = (const symbol_t*)s1;
135: const symbol_t *sym2 = (const symbol_t*)s2;
1.1 root 136: int ret;
137:
1.1.1.9 root 138: /* first by name */
139: ret = strcmp(sym1->name, sym2->name);
140: if (ret) {
141: return ret;
142: }
143: /* then by address */
144: return (sym1->address - sym2->address);
145: }
146:
147: /**
148: * Check for duplicate addresses in symbol list
149: * (called separately for TEXT & non-TEXT symbols)
150: * Return number of duplicates
151: */
152: static int symbols_check_addresses(const symbol_t *syms, int count)
153: {
154: int i, j, dups = 0;
155:
156: for (i = 0; i < (count - 1); i++)
157: {
158: /* absolute symbols have values, not addresses */
159: if (syms[i].type == SYMTYPE_ABS) {
160: continue;
161: }
162: for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
163: if (syms[j].type == SYMTYPE_ABS) {
164: continue;
165: }
166: /* ASCII symbol files contain also object file addresses,
167: * those will often have the same address as the first symbol
168: * in given object -> no point warning about them
169: */
170: if (is_obj_file(syms[i].name) || is_obj_file(syms[j].name)) {
171: continue;
172: }
173: fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address\n",
174: syms[i].name, syms[j].name, syms[i].address);
175: dups++;
176: i = j;
177: }
1.1 root 178: }
1.1.1.9 root 179: return dups;
1.1 root 180: }
181:
1.1.1.9 root 182: /**
183: * Check for duplicate names in symbol list
184: * Return number of duplicates
185: */
186: static int symbols_check_names(const symbol_t *syms, int count)
187: {
188: int i, j, dups = 0;
189:
190: for (i = 0; i < (count - 1); i++)
191: {
192: for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
193: /* this is common case for object files having different sections */
194: if (syms[i].type != syms[j].type && is_obj_file(syms[i].name)) {
195: continue;
196: }
197: fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name\n",
198: syms[i].address, syms[j].address, syms[i].name);
199: dups++;
200: i = j;
201: }
202: }
203: return dups;
204: }
1.1 root 205:
206: /**
1.1.1.5 root 207: * Allocate symbol list & names for given number of items.
208: * Return allocated list or NULL on failure.
209: */
210: static symbol_list_t* symbol_list_alloc(int symbols)
211: {
212: symbol_list_t *list;
213:
214: if (!symbols) {
215: return NULL;
216: }
217: list = calloc(1, sizeof(symbol_list_t));
218: if (list) {
219: list->names = malloc(symbols * sizeof(symbol_t));
220: if (!list->names) {
221: free(list);
222: list = NULL;
223: }
224: }
225: return list;
226: }
227:
228: /**
229: * Free symbol list & names.
230: */
231: static void symbol_list_free(symbol_list_t *list)
232: {
233: if (list) {
234: if (list->names) {
235: free(list->names);
236: }
237: free(list);
238: }
239: }
240:
241: /**
1.1.1.6 root 242: * Return symbol type identifier char
243: */
244: static char symbol_char(int type)
245: {
246: switch (type) {
247: case SYMTYPE_TEXT: return 'T';
248: case SYMTYPE_DATA: return 'D';
249: case SYMTYPE_BSS: return 'B';
1.1.1.9 root 250: case SYMTYPE_ABS: return 'A';
1.1.1.6 root 251: default: return '?';
252: }
253: }
254:
1.1.1.9 root 255: /**
256: * Return true if symbol name matches internal GCC symbol name,
257: * or is object / file name.
258: */
259: static bool symbol_remove_obj(const char *name)
260: {
261: static const char *gcc_sym[] = {
262: "___gnu_compiled_c",
263: "gcc2_compiled."
264: };
265: int i;
266:
267: if (is_obj_file(name)) {
268: return true;
269: }
270: /* useless symbols GCC (v2) seems to add to every object? */
271: for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
272: if (strcmp(name, gcc_sym[i]) == 0) {
273: return true;
274: }
275: }
276: return false;
277: }
278:
1.1.1.6 root 279:
280: /**
1.1 root 281: * Load symbols of given type and the symbol address addresses from
1.1.1.5 root 282: * DRI/GST format symbol table, and add given offsets to the addresses:
283: * http://toshyp.atari.org/en/005005.html
1.1 root 284: * Return symbols list or NULL for failure.
285: */
1.1.1.5 root 286: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize)
1.1 root 287: {
1.1.1.9 root 288: int i, count, symbols, invalid;
289: int notypes, dtypes, locals, ofiles;
1.1.1.5 root 290: prg_section_t *section;
1.1 root 291: symbol_list_t *list;
292: symtype_t symtype;
1.1.1.5 root 293: #define DRI_ENTRY_SIZE 14
294: char name[23];
295: Uint16 symid;
1.1 root 296: Uint32 address;
1.1.1.5 root 297:
1.1.1.6 root 298: if (tablesize % DRI_ENTRY_SIZE || !tablesize) {
1.1.1.5 root 299: fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
300: return NULL;
301: }
302: symbols = tablesize / DRI_ENTRY_SIZE;
303: if (!(list = symbol_list_alloc(symbols))) {
304: return NULL;
305: }
306:
1.1.1.9 root 307: invalid = dtypes = notypes = ofiles = locals = count = 0;
1.1.1.5 root 308: for (i = 1; i <= symbols; i++) {
309: /* read DRI symbol table slot */
310: if (fread(name, 8, 1, fp) != 1 ||
311: fread(&symid, sizeof(symid), 1, fp) != 1 ||
312: fread(&address, sizeof(address), 1, fp) != 1) {
313: break;
314: }
315: address = SDL_SwapBE32(address);
316: symid = SDL_SwapBE16(symid);
317:
318: /* GST extended DRI symbol format? */
319: if ((symid & 0x0048)) {
320: /* next slot is rest of name */
321: i += 1;
322: if (fread(name+8, 14, 1, fp) != 1) {
323: break;
324: }
325: name[22] = '\0';
326: } else {
327: name[8] = '\0';
328: }
329:
330: /* check section */
331: switch (symid & 0xf00) {
332: case 0x0200:
333: symtype = SYMTYPE_TEXT;
334: section = &(sections[0]);
335: break;
336: case 0x0400:
337: symtype = SYMTYPE_DATA;
338: section = &(sections[1]);
339: break;
340: case 0x0100:
341: symtype = SYMTYPE_BSS;
342: section = &(sections[2]);
343: break;
344: default:
345: if ((symid & 0xe000) == 0xe000) {
346: dtypes++;
347: continue;
348: }
1.1.1.9 root 349: if ((symid & 0x4000) == 0x4000) {
350: symtype = SYMTYPE_ABS;
351: section = NULL;
352: break;
353: }
1.1.1.5 root 354: fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
1.1.1.9 root 355: invalid++;
1.1.1.5 root 356: continue;
357: }
358: if (!(gettype & symtype)) {
1.1.1.9 root 359: notypes++;
1.1.1.5 root 360: continue;
361: }
362: if (name[0] == '.' && name[1] == 'L') {
363: locals++;
364: continue;
365: }
1.1.1.9 root 366: if (symbol_remove_obj(name)) {
1.1.1.5 root 367: ofiles++;
368: continue;
369: }
1.1.1.9 root 370: if (section) {
371: address += section->offset;
372: if (address > section->end) {
373: fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
374: name, symbol_char(symtype), i, address, section->end);
375: invalid++;
376: continue;
1.1.1.6 root 377: }
1.1.1.5 root 378: }
379: list->names[count].address = address;
380: list->names[count].type = symtype;
381: list->names[count].name = strdup(name);
382: assert(list->names[count].name);
383: count++;
384: }
385: if (i <= symbols) {
386: perror("ERROR: reading symbol failed");
387: symbol_list_free(list);
1.1 root 388: return NULL;
389: }
1.1.1.9 root 390: list->symbols = symbols;
391: list->namecount = count;
392:
393: /* skip verbose output when symbol loading is forced */
394: if (ConfigureParams.Debugger.bSymbolsResident) {
395: return list;
396: }
397:
398: if (invalid) {
399: fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
400: }
1.1.1.5 root 401: if (dtypes) {
1.1.1.9 root 402: fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
403: }
404: if (notypes) {
405: fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
1.1.1.5 root 406: }
407: if (locals) {
408: fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
409: }
410: if (ofiles) {
411: /* object file path names most likely get truncated and
412: * as result cause unnecessary symbol name conflicts in
413: * addition to object file addresses conflicting with
414: * first symbol in the object file.
415: */
1.1.1.9 root 416: fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
417: }
418: return list;
419: }
420:
421:
422: /**
423: * Load symbols of given type and the symbol address addresses from
424: * a.out format symbol table, and add given offsets to the addresses:
425: * Return symbols list or NULL for failure.
426: */
427: static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize, Uint32 stroff, Uint32 strsize)
428: {
429: size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
430: size_t i;
431: size_t strx;
432: unsigned char *p;
433: char *name;
434: symbol_t *sym;
435: symtype_t symtype;
436: uint32_t address;
437: uint32_t nread;
438: symbol_list_t *list;
439: unsigned char n_type;
440: unsigned char n_other;
441: unsigned short n_desc;
442: static char dummy[] = "<invalid>";
443: int dtypes, locals, ofiles, count, notypes, invalid, weak;
444: prg_section_t *section;
445:
446: if (!(list = symbol_list_alloc(slots))) {
447: return NULL;
448: }
449:
450: list->strtab = (char *)malloc(tablesize + strsize);
451:
452: if (list->strtab == NULL)
453: {
454: symbol_list_free(list);
455: return NULL;
456: }
457:
458: nread = fread(list->strtab, tablesize + strsize, 1, fp);
459: if (nread != 1)
460: {
461: perror("ERROR: reading symbols failed");
462: symbol_list_free(list);
463: return NULL;
464: }
465:
466: p = (unsigned char *)list->strtab;
467: sym = list->names;
468:
469: weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
470: for (i = 0; i < slots; i++)
471: {
472: strx = SDL_SwapBE32(*(Uint32*)p);
473: p += 4;
474: n_type = *p++;
475: n_other = *p++;
476: n_desc = SDL_SwapBE16(*(Uint16*)p);
477: p += 2;
478: address = SDL_SwapBE32(*(Uint32*)p);
479: p += 4;
480: name = dummy;
481: if (!strx) {
482: invalid++;
483: continue;
484: }
485: if (strx >= strsize) {
486: fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
487: invalid++;
488: continue;
489: }
490: name = list->strtab + strx + stroff;
491:
492: if (n_type & N_STAB)
493: {
494: dtypes++;
495: continue;
496: }
497: section = NULL;
498: switch (n_type & (N_TYPE|N_EXT))
499: {
500: case N_UNDF:
501: case N_UNDF|N_EXT:
502: /* shouldn't happen here */
503: weak++;
504: continue;
505: case N_ABS:
506: case N_ABS|N_EXT:
507: symtype = SYMTYPE_ABS;
508: break;
509: case N_TEXT:
510: case N_TEXT|N_EXT:
511: symtype = SYMTYPE_TEXT;
512: section = &(sections[0]);
513: break;
514: case N_DATA:
515: case N_DATA|N_EXT:
516: symtype = SYMTYPE_DATA;
517: section = &(sections[1]);
518: break;
519: case N_BSS:
520: case N_BSS|N_EXT:
521: case N_COMM:
522: case N_COMM|N_EXT:
523: symtype = SYMTYPE_BSS;
524: section = &(sections[2]);
525: break;
526: case N_FN: /* filenames, not object addresses? */
527: dtypes++;
528: continue;
529: case N_SIZE:
530: case N_WARNING:
531: case N_SETA:
532: case N_SETT:
533: case N_SETD:
534: case N_SETB:
535: case N_SETV:
536: dtypes++;
537: continue;
538: case N_WEAKU:
539: case N_WEAKT:
540: case N_WEAKD:
541: case N_WEAKB:
542: weak++;
543: continue;
544: default:
545: fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
546: invalid++;
547: continue;
548: }
549: /*
550: * the value of a common symbol is its size, not its address:
551: */
552: if (((n_type & N_TYPE) == N_COMM) ||
553: (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
554: {
555: /* if we ever want to know a symbols size, get that here */
556: fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i);
557: dtypes++;
558: continue;
559: }
560: if (!(gettype & symtype)) {
561: notypes++;
562: continue;
563: }
564: if (name[0] == '.' && name[1] == 'L') {
565: locals++;
566: continue;
567: }
568: if (symbol_remove_obj(name)) {
569: ofiles++;
570: continue;
571: }
572: if (section) {
573: address += sections[0].offset; /* all GNU symbol addresses are TEXT relative */
574: if (address > section->end) {
575: fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
576: name, symbol_char(symtype), (unsigned int)i, address, section->end);
577: invalid++;
578: continue;
579: }
580: }
581: sym->address = address;
582: sym->type = symtype;
583: sym->name = name;
584: sym++;
585: count++;
586: (void) n_desc;
587: (void) n_other;
588: }
589: list->symbols = slots;
590: list->namecount = count;
591:
592: /* skip verbose output when symbol loading is forced */
593: if (ConfigureParams.Debugger.bSymbolsResident) {
594: return list;
595: }
596:
597: if (invalid) {
598: fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
599: }
600: if (dtypes) {
601: fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
602: }
603: if (weak) {
604: fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
605: }
606: if (notypes) {
607: fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
608: }
609: if (locals) {
610: fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
611: }
612: if (ofiles) {
613: /* object file path names most likely get truncated and
614: * as result cause unnecessary symbol name conflicts in
615: * addition to object file addresses conflicting with
616: * first symbol in the object file.
617: */
618: fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
1.1.1.5 root 619: }
620: return list;
621: }
622:
1.1.1.7 root 623:
624: /**
625: * Print program header information.
626: * Return false for unrecognized symbol table type.
627: */
628: static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
629: {
630: static const struct {
631: Uint32 flag;
632: const char *name;
633: } flags[] = {
634: { 0x0001, "FASTLOAD" },
635: { 0x0002, "TTRAMLOAD" },
636: { 0x0004, "TTRAMMEM" },
637: { 0x0008, "MINIMUM" }, /* MagiC */
638: { 0x1000, "SHAREDTEXT" }
639: };
640: const char *info;
641: int i;
642:
643: switch (tabletype) {
1.1.1.9 root 644: case SYMBOL_FORMAT_MINT: /* "MiNT" */
1.1.1.7 root 645: info = "GCC/MiNT executable, GST symbol table";
646: break;
1.1.1.9 root 647: case SYMBOL_FORMAT_GNU: /* "GNU_" */
648: info = "GCC/MiNT executable, a.out symbol table";
649: break;
650: case SYMBOL_FORMAT_DRI:
1.1.1.7 root 651: info = "TOS executable, DRI / GST symbol table";
652: break;
653: default:
654: fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
655: return false;
656: }
657: fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
658: /* bit flags */
1.1.1.8 root 659: for (i = 0; i < ARRAY_SIZE(flags); i++) {
1.1.1.7 root 660: if (prgflags & flags[i].flag) {
661: fprintf(stderr, " %s", flags[i].name);
662: }
663: }
664: /* memory protection flags */
665: switch((prgflags >> 4) & 3) {
666: case 0: info = "PRIVATE"; break;
667: case 1: info = "GLOBAL"; break;
668: case 2: info = "SUPER"; break;
669: case 3: info = "READONLY"; break;
670: }
671: fprintf(stderr, " %s (0x%x)\n", info, prgflags);
672: return true;
673: }
674:
1.1.1.5 root 675: /**
676: * Parse program header and use symbol table format specific loader
677: * loader function to load the symbols.
678: * Return symbols list or NULL for failure.
679: */
680: static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
681: {
1.1.1.6 root 682: Uint32 textlen, datalen, bsslen, start, tablesize, tabletype, prgflags;
1.1.1.5 root 683: prg_section_t sections[3];
684: int offset, reads = 0;
1.1.1.6 root 685: Uint16 relocflag;
686: symbol_list_t* symbols;
1.1.1.9 root 687: Uint32 symoff = 0;
688: Uint32 stroff = 0;
689: Uint32 strsize = 0;
1.1.1.5 root 690:
691: /* get TEXT, DATA & BSS section sizes */
1.1.1.6 root 692: fseek(fp, 2, SEEK_SET);
1.1.1.5 root 693: reads += fread(&textlen, sizeof(textlen), 1, fp);
694: textlen = SDL_SwapBE32(textlen);
695: reads += fread(&datalen, sizeof(datalen), 1, fp);
696: datalen = SDL_SwapBE32(datalen);
697: reads += fread(&bsslen, sizeof(bsslen), 1, fp);
698: bsslen = SDL_SwapBE32(bsslen);
699:
700: /* get symbol table size & type and check that all reads succeeded */
701: reads += fread(&tablesize, sizeof(tablesize), 1, fp);
702: tablesize = SDL_SwapBE32(tablesize);
703: reads += fread(&tabletype, sizeof(tabletype), 1, fp);
704: tabletype = SDL_SwapBE32(tabletype);
1.1.1.6 root 705:
706: /* get program header and whether there's reloc table */
707: reads += fread(&prgflags, sizeof(prgflags), 1, fp);
708: prgflags = SDL_SwapBE32(prgflags);
709: reads += fread(&relocflag, sizeof(relocflag), 1, fp);
710: relocflag = SDL_SwapBE32(relocflag);
711:
712: if (reads != 7) {
1.1.1.5 root 713: fprintf(stderr, "ERROR: program header reading failed!\n");
714: return NULL;
715: }
1.1.1.9 root 716: /*
717: * check for GNU-style symbol table in aexec header
718: */
719: if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
720: Uint32 magic1, magic2;
721: Uint32 dummy;
722: Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
723: Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
724:
725: reads = fread(&magic1, sizeof(magic1), 1, fp);
726: magic1 = SDL_SwapBE32(magic1);
727: reads += fread(&magic2, sizeof(magic2), 1, fp);
728: magic2 = SDL_SwapBE32(magic2);
729: if (reads == 2 &&
730: ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) || /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
731: (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) { /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
732: reads += fread(&dummy, sizeof(dummy), 1, fp); /* skip a_info */
733: reads += fread(&a_text, sizeof(a_text), 1, fp);
734: a_text = SDL_SwapBE32(a_text);
735: reads += fread(&a_data, sizeof(a_data), 1, fp);
736: a_data = SDL_SwapBE32(a_data);
737: reads += fread(&a_bss, sizeof(a_bss), 1, fp);
738: a_bss = SDL_SwapBE32(a_bss);
739: reads += fread(&a_syms, sizeof(a_syms), 1, fp);
740: a_syms = SDL_SwapBE32(a_syms);
741: reads += fread(&a_entry, sizeof(a_entry), 1, fp);
742: a_entry = SDL_SwapBE32(a_entry);
743: reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
744: a_trsize = SDL_SwapBE32(a_trsize);
745: reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
746: a_drsize = SDL_SwapBE32(a_drsize);
747: reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
748: g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
749: reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
750: g_tparel_size = SDL_SwapBE32(g_tparel_size);
751: reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
752: g_stkpos = SDL_SwapBE32(g_stkpos);
753: reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
754: g_symbol_format = SDL_SwapBE32(g_symbol_format);
755: if (g_symbol_format == 0)
756: {
757: tabletype = SYMBOL_FORMAT_GNU;
758: }
759: if ((a_text + (256 - 28)) != textlen)
760: fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
761: if (a_data != datalen)
762: fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
763: if (a_bss != bsslen)
764: fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
765: /*
766: * the symbol table size in the GEMDOS header includes the string table,
767: * the symbol table size in the exec header does not.
768: */
769: if (tabletype == SYMBOL_FORMAT_GNU)
770: {
771: strsize = tablesize - a_syms;
772: tablesize = a_syms;
773: stroff = a_syms;
774: }
775:
776: textlen = a_text + (256 - 28);
777: datalen = a_data;
778: bsslen = a_bss;
779: symoff = 0x100 + /* sizeof(extended exec header) */
780: a_text +
781: a_data +
782: a_trsize +
783: a_drsize;
784: }
785: }
1.1.1.7 root 786: if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
787: return NULL;
788: }
789: if (!tablesize) {
790: fprintf(stderr, "ERROR: symbol table missing from the program!\n");
791: return NULL;
792: }
1.1.1.5 root 793:
794: /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
795: start = DebugInfo_GetTEXT();
796: if (!start) {
797: fprintf(stderr, "ERROR: no valid program basepage!\n");
798: return NULL;
799: }
800: sections[0].offset = start;
801: sections[0].end = start + textlen;
1.1.1.9 root 802: if (DebugInfo_GetTEXTEnd() != sections[0].end) {
1.1.1.5 root 803: fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
804: return NULL;
805: }
806:
807: start = DebugInfo_GetDATA();
1.1.1.6 root 808: sections[1].offset = start;
1.1.1.9 root 809: sections[1].end = start + datalen;
1.1.1.5 root 810:
811: start = DebugInfo_GetBSS();
1.1.1.6 root 812: sections[2].offset = start;
1.1.1.9 root 813: sections[2].end = start + bsslen;
1.1.1.5 root 814:
1.1.1.9 root 815: if (sections[0].end != sections[1].offset) {
816: fprintf(stderr, "WARNIGN: DATA start doesn't match TEXT start + size!\n");
817: }
818: if (sections[1].end != sections[2].offset) {
819: fprintf(stderr, "WARNIGN: BSS start doesn't match DATA start + size!\n");
1.1.1.6 root 820: }
821:
1.1.1.9 root 822: if (tabletype == SYMBOL_FORMAT_GNU) {
823: /* go to start of symbol table */
824: offset = symoff;
825: if (fseek(fp, offset, SEEK_SET) < 0) {
826: perror("ERROR: seeking to symbol table failed");
827: return NULL;
828: }
829: fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
830: symbols = symbols_load_gnu(fp, sections, gettype, tablesize, stroff, strsize);
831: } else {
832: /* go to start of symbol table */
833: offset = 0x1C + textlen + datalen;
834: if (fseek(fp, offset, SEEK_SET) < 0) {
835: perror("ERROR: seeking to symbol table failed");
836: return NULL;
837: }
838: fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
1.1.1.6 root 839: symbols = symbols_load_dri(fp, sections, gettype, tablesize);
840: }
841: return symbols;
1.1.1.5 root 842: }
843:
844: /**
845: * Load symbols of given type and the symbol address addresses from
846: * the given ASCII file and add given offsets to the addresses.
847: * Return symbols list or NULL for failure.
848: */
849: static symbol_list_t* symbols_load_ascii(FILE *fp, Uint32 *offsets, Uint32 maxaddr, symtype_t gettype)
850: {
851: symbol_list_t *list;
852: char symchar, buffer[128], name[MAX_SYM_SIZE+1], *buf;
853: int count, line, symbols;
854: Uint32 address, offset;
855: symtype_t symtype;
1.1 root 856:
857: /* count content lines */
1.1.1.9 root 858: line = symbols = 0;
1.1 root 859: while (fgets(buffer, sizeof(buffer), fp)) {
1.1.1.9 root 860: line++;
861:
1.1.1.3 root 862: /* skip comments (AHCC SYM file comments start with '*') */
863: if (*buffer == '#' || *buffer == '*') {
1.1 root 864: continue;
865: }
866: /* skip empty lines */
1.1.1.6 root 867: for (buf = buffer; isspace((unsigned char)*buf); buf++);
1.1 root 868: if (!*buf) {
869: continue;
870: }
1.1.1.9 root 871: if (!isxdigit(*buf)) {
872: fprintf(stderr, "ERROR: line %d doesn't start with an address.\n", line);
873: return NULL;
874: }
1.1 root 875: symbols++;
876: }
1.1.1.6 root 877: if (!symbols) {
878: fprintf(stderr, "ERROR: no symbols.\n");
1.1.1.9 root 879: return NULL;
1.1.1.6 root 880: }
881:
1.1 root 882: fseek(fp, 0, SEEK_SET);
883:
1.1.1.5 root 884: /* allocate space for symbol list & names */
885: if (!(list = symbol_list_alloc(symbols))) {
1.1 root 886: return NULL;
887: }
888:
889: /* read symbols */
890: count = 0;
891: for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) {
1.1.1.3 root 892: /* skip comments (AHCC SYM file comments start with '*') */
893: if (*buffer == '#' || *buffer == '*') {
1.1 root 894: continue;
895: }
896: /* skip empty lines */
1.1.1.6 root 897: for (buf = buffer; isspace((unsigned char)*buf); buf++);
1.1 root 898: if (!*buf) {
899: continue;
900: }
901: assert(count < symbols); /* file not modified in meanwhile? */
1.1.1.5 root 902: if (sscanf(buffer, "%x %c %32[0-9A-Za-z_.-]s", &address, &symchar, name) != 3) {
903: fprintf(stderr, "WARNING: syntax error on line %d, skipping.\n", line);
1.1 root 904: continue;
905: }
1.1.1.6 root 906: switch (toupper((unsigned char)symchar)) {
1.1.1.5 root 907: case 'T':
908: symtype = SYMTYPE_TEXT;
909: offset = offsets[0];
910: break;
911: case 'O': /* AHCC type for _StkSize etc */
912: case 'D':
913: symtype = SYMTYPE_DATA;
914: offset = offsets[1];
915: break;
916: case 'B':
917: symtype = SYMTYPE_BSS;
918: offset = offsets[2];
919: break;
1.1.1.9 root 920: case 'A':
921: symtype = SYMTYPE_ABS;
922: offset = 0;
923: break;
1.1 root 924: default:
1.1.1.5 root 925: fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d, skipping.\n", symchar, line);
1.1 root 926: continue;
927: }
928: if (!(gettype & symtype)) {
929: continue;
930: }
1.1.1.5 root 931: address += offset;
932: if (address > maxaddr) {
933: fprintf(stderr, "WARNING: invalid address 0x%x on line %d, skipping.\n", address, line);
934: continue;
935: }
1.1 root 936: list->names[count].address = address;
937: list->names[count].type = symtype;
938: list->names[count].name = strdup(name);
939: assert(list->names[count].name);
940: count++;
941: }
1.1.1.5 root 942: list->symbols = symbols;
1.1.1.9 root 943: list->namecount = count;
1.1.1.5 root 944: return list;
945: }
1.1 root 946:
1.1.1.5 root 947: /**
1.1.1.9 root 948: * Remove full duplicates from the sorted names list
949: * and trim the allocation to remaining symbols
950: */
951: static void symbols_trim_names(symbol_list_t* list)
952: {
953: symbol_t *sym = list->names;
954: int i, next, count, dups;
955:
956: count = list->namecount;
957: for (dups = i = 0; i < count - 1; i++) {
958: next = i + 1;
959: if (strcmp(sym[i].name, sym[next].name) == 0 &&
960: sym[i].address == sym[next].address &&
961: sym[i].type == sym[next].type) {
962: /* remove duplicate */
963: memmove(sym+i, sym+next, (count-next) * sizeof(symbol_t));
964: count--;
965: dups++;
966: }
967: }
968: if (dups || list->namecount < list->symbols) {
969: list->names = realloc(list->names, i * sizeof(symbol_t));
970: assert(list->names);
971: list->namecount = i;
972: }
973: if (dups) {
974: fprintf(stderr, "WARNING: removed %d complete symbol duplicates\n", dups);
975: }
976: }
977:
978: /**
979: * Separate TEXT symbols from other symbols in address list.
980: */
981: static void symbols_trim_addresses(symbol_list_t* list)
982: {
983: symbol_t *sym = list->addresses;
984: int i;
985:
986: for (i = 0; i < list->namecount; i++) {
987: if (sym[i].type != SYMTYPE_TEXT) {
988: break;
989: }
990: }
991: list->codecount = i;
992: list->datacount = list->namecount - i;
993: }
994:
995: /**
1.1.1.5 root 996: * Load symbols of given type and the symbol address addresses from
997: * the given file and add given offsets to the addresses.
998: * Return symbols list or NULL for failure.
999: */
1000: static symbol_list_t* Symbols_Load(const char *filename, Uint32 *offsets, Uint32 maxaddr)
1001: {
1002: symbol_list_t *list;
1003: FILE *fp;
1004:
1.1.1.7 root 1005: if (!File_Exists(filename)) {
1006: fprintf(stderr, "ERROR: file '%s' doesn't exist or isn't readable!\n", filename);
1.1.1.5 root 1007: return NULL;
1008: }
1.1.1.7 root 1009: if (Opt_IsAtariProgram(filename)) {
1.1.1.6 root 1010: const char *last = CurrentProgramPath;
1011: if (!last) {
1012: /* "pc=text" breakpoint used as point for loading program symbols gives false hits during bootup */
1013: fprintf(stderr, "WARNING: no program loaded yet (through GEMDOS HD emu)!\n");
1014: } else if (strcmp(last, filename) != 0) {
1015: 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 1016: }
1.1.1.6 root 1017: fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
1.1.1.7 root 1018: fp = fopen(filename, "rb");
1.1.1.5 root 1019: list = symbols_load_binary(fp, SYMTYPE_ALL);
1.1.1.6 root 1020: SymbolsAreForProgram = true;
1.1.1.5 root 1021: } else {
1022: fprintf(stderr, "Reading 'nm' style ASCII symbols from '%s'...\n", filename);
1.1.1.7 root 1023: fp = fopen(filename, "r");
1.1.1.5 root 1024: list = symbols_load_ascii(fp, offsets, maxaddr, SYMTYPE_ALL);
1.1.1.6 root 1025: SymbolsAreForProgram = false;
1.1.1.5 root 1026: }
1027: fclose(fp);
1028:
1029: if (!list) {
1.1.1.6 root 1030: fprintf(stderr, "ERROR: reading symbols from '%s' failed!\n", filename);
1.1.1.5 root 1031: return NULL;
1032: }
1033:
1.1.1.9 root 1034: if (!list->namecount) {
1035: fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename);
1036: symbol_list_free(list);
1037: return NULL;
1.1 root 1038: }
1039:
1.1.1.9 root 1040: /* sort and trim names list */
1041: qsort(list->names, list->namecount, sizeof(symbol_t), symbols_by_name);
1042: symbols_trim_names(list);
1043:
1.1 root 1044: /* copy name list to address list */
1.1.1.9 root 1045: list->addresses = malloc(list->namecount * sizeof(symbol_t));
1.1 root 1046: assert(list->addresses);
1.1.1.9 root 1047: memcpy(list->addresses, list->names, list->namecount * sizeof(symbol_t));
1.1 root 1048:
1.1.1.9 root 1049: /* sort address list and trim to contain just TEXT symbols */
1050: qsort(list->addresses, list->namecount, sizeof(symbol_t), symbols_by_address);
1051: symbols_trim_addresses(list);
1.1 root 1052:
1.1.1.9 root 1053: /* skip verbose output when symbol loading is forced */
1054: if (!ConfigureParams.Debugger.bSymbolsResident) {
1055: /* check for duplicate names */
1056: if (symbols_check_names(list->names, list->namecount)) {
1057: fprintf(stderr, "-> Hatari symbol expansion can match only one of the addresses for name duplicates!\n");
1058: }
1059: /* check for duplicate TEXT & other addresses */
1060: if (symbols_check_addresses(list->addresses, list->codecount)) {
1061: fprintf(stderr, "-> Hatari profile/dissassembly will show only one of the TEXT symbols for given address!\n");
1062: }
1063: if (symbols_check_addresses(list->addresses + list->codecount, list->datacount)) {
1064: fprintf(stderr, "-> Hatari dissassembly will show only one of the symbols for given address!\n");
1065: }
1066: }
1067:
1068: fprintf(stderr, "Loaded %d symbols (%d TEXT) from '%s'.\n",
1069: list->namecount, list->codecount, filename);
1.1 root 1070: return list;
1071: }
1072:
1073:
1074: /**
1075: * Free read symbols.
1076: */
1077: static void Symbols_Free(symbol_list_t* list)
1078: {
1.1.1.5 root 1079: int i;
1.1 root 1080:
1081: if (!list) {
1082: return;
1083: }
1.1.1.9 root 1084: assert(list->namecount);
1085: if (list->strtab) {
1086: free(list->strtab);
1087: list->strtab = NULL;
1088: } else {
1089: for (i = 0; i < list->namecount; i++) {
1090: free(list->names[i].name);
1091: }
1.1 root 1092: }
1093: free(list->addresses);
1094: free(list->names);
1.1.1.5 root 1095:
1096: /* catch use of freed list */
1097: list->addresses = NULL;
1.1.1.9 root 1098: list->codecount = 0;
1099: list->datacount = 0;
1.1.1.5 root 1100: list->names = NULL;
1.1.1.9 root 1101: list->namecount = 0;
1.1 root 1102: free(list);
1103: }
1104:
1105:
1106: /* ---------------- symbol name completion support ------------------ */
1107:
1108: /**
1109: * Helper for symbol name completion and finding their addresses.
1110: * STATE = 0 -> different text from previous one.
1111: * Return (copy of) next name or NULL if no matches.
1112: */
1113: static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state)
1114: {
1.1.1.5 root 1115: static int i, len;
1.1 root 1116: const symbol_t *entry;
1117:
1118: if (!list) {
1119: return NULL;
1120: }
1121:
1122: if (!state) {
1123: /* first match */
1124: len = strlen(text);
1125: i = 0;
1126: }
1127:
1128: /* next match */
1129: entry = list->names;
1.1.1.9 root 1130: while (i < list->namecount) {
1.1 root 1131: if ((entry[i].type & symtype) &&
1132: strncmp(entry[i].name, text, len) == 0) {
1133: return strdup(entry[i++].name);
1134: } else {
1135: i++;
1136: }
1137: }
1138: return NULL;
1139: }
1140:
1141: /**
1142: * Readline match callbacks for CPU symbol name completion.
1143: * STATE = 0 -> different text from previous one.
1144: * Return next match or NULL if no matches.
1145: */
1146: char* Symbols_MatchCpuAddress(const char *text, int state)
1147: {
1148: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
1149: }
1150: char* Symbols_MatchCpuCodeAddress(const char *text, int state)
1151: {
1.1.1.9 root 1152: if (ConfigureParams.Debugger.bMatchAllSymbols) {
1153: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
1154: } else {
1155: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_TEXT, text, state);
1156: }
1.1 root 1157: }
1158: char* Symbols_MatchCpuDataAddress(const char *text, int state)
1159: {
1.1.1.9 root 1160: if (ConfigureParams.Debugger.bMatchAllSymbols) {
1161: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
1162: } else {
1163: return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
1164: }
1.1 root 1165: }
1166:
1167: /**
1168: * Readline match callback for DSP symbol name completion.
1169: * STATE = 0 -> different text from previous one.
1170: * Return next match or NULL if no matches.
1171: */
1172: char* Symbols_MatchDspAddress(const char *text, int state)
1173: {
1174: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state);
1175: }
1176: char* Symbols_MatchDspCodeAddress(const char *text, int state)
1177: {
1178: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_TEXT, text, state);
1179: }
1180: char* Symbols_MatchDspDataAddress(const char *text, int state)
1181: {
1182: return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
1183: }
1184:
1185:
1186: /* ---------------- symbol name -> address search ------------------ */
1187:
1188: /**
1.1.1.9 root 1189: * Binary search symbol of given type by name.
1.1 root 1190: * Return symbol if name matches, zero otherwise.
1191: */
1.1.1.9 root 1192: static const symbol_t* Symbols_SearchByName(symbol_t* entries, int count, symtype_t symtype, const char *name)
1.1 root 1193: {
1194: /* left, right, middle */
1195: int l, r, m, dir;
1196:
1197: /* bisect */
1198: l = 0;
1.1.1.9 root 1199: r = count - 1;
1.1 root 1200: do {
1201: m = (l+r) >> 1;
1202: dir = strcmp(entries[m].name, name);
1203: if (dir == 0 && (entries[m].type & symtype)) {
1204: return &(entries[m]);
1205: }
1206: if (dir > 0) {
1207: r = m-1;
1208: } else {
1209: l = m+1;
1210: }
1211: } while (l <= r);
1212: return NULL;
1213: }
1214:
1215: /**
1.1.1.9 root 1216: * Set given symbol's address to variable and return true if one
1217: * was found from given list.
1.1 root 1218: */
1.1.1.9 root 1219: static bool Symbols_GetAddress(symbol_list_t* list, symtype_t symtype, const char *name, Uint32 *addr)
1.1 root 1220: {
1221: const symbol_t *entry;
1.1.1.9 root 1222: if (!(list && list->names)) {
1223: return false;
1224: }
1225: entry = Symbols_SearchByName(list->names, list->namecount, symtype, name);
1.1 root 1226: if (entry) {
1227: *addr = entry->address;
1228: return true;
1229: }
1230: return false;
1231: }
1.1.1.9 root 1232: bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, Uint32 *addr)
1233: {
1234: return Symbols_GetAddress(CpuSymbolsList, symtype, name, addr);
1235: }
1.1 root 1236: bool Symbols_GetDspAddress(symtype_t symtype, const char *name, Uint32 *addr)
1237: {
1.1.1.9 root 1238: return Symbols_GetAddress(DspSymbolsList, symtype, name, addr);
1.1 root 1239: }
1240:
1241:
1242: /* ---------------- symbol address -> name search ------------------ */
1243:
1244: /**
1.1.1.9 root 1245: * Binary search symbol by address in given sorted list.
1.1.1.5 root 1246: * Return symbol index if address matches, -1 otherwise.
1.1 root 1247: */
1.1.1.9 root 1248: static int Symbols_SearchByAddress(symbol_t* entries, int count, Uint32 addr)
1.1 root 1249: {
1250: /* left, right, middle */
1251: int l, r, m;
1252: Uint32 curr;
1253:
1254: /* bisect */
1255: l = 0;
1.1.1.9 root 1256: r = count - 1;
1.1 root 1257: do {
1258: m = (l+r) >> 1;
1259: curr = entries[m].address;
1260: if (curr == addr) {
1.1.1.5 root 1261: return m;
1.1 root 1262: }
1263: if (curr > addr) {
1264: r = m-1;
1265: } else {
1266: l = m+1;
1267: }
1268: } while (l <= r);
1.1.1.5 root 1269: return -1;
1.1 root 1270: }
1271:
1272: /**
1.1.1.9 root 1273: * Search symbol in given list by type & address.
1274: * Return symbol name if there's a match, NULL otherwise.
1275: * TEXT symbols will be matched before other symbol types.
1.1 root 1276: * Returned name is valid only until next Symbols_* function call.
1277: */
1.1.1.9 root 1278: static const char* Symbols_GetByAddress(symbol_list_t* list, Uint32 addr, symtype_t type)
1.1 root 1279: {
1.1.1.9 root 1280: if (!(list && list->addresses)) {
1.1.1.5 root 1281: return NULL;
1282: }
1.1.1.9 root 1283: if (type & SYMTYPE_TEXT) {
1284: int i = Symbols_SearchByAddress(list->addresses, list->codecount, addr);
1285: if (i >= 0) {
1286: return list->addresses[i].name;
1287: }
1288: }
1289: if (type & ~SYMTYPE_TEXT) {
1290: int i = Symbols_SearchByAddress(list->addresses + list->codecount, list->datacount, addr);
1291: if (i >= 0) {
1292: return list->addresses[list->codecount + i].name;
1293: }
1294: }
1295: return NULL;
1.1 root 1296: }
1.1.1.9 root 1297: const char* Symbols_GetByCpuAddress(Uint32 addr, symtype_t type)
1.1 root 1298: {
1.1.1.9 root 1299: return Symbols_GetByAddress(CpuSymbolsList, addr, type);
1.1.1.5 root 1300: }
1.1.1.9 root 1301: const char* Symbols_GetByDspAddress(Uint32 addr, symtype_t type)
1.1.1.5 root 1302: {
1.1.1.9 root 1303: return Symbols_GetByAddress(DspSymbolsList, addr, type);
1.1.1.5 root 1304: }
1305:
1306: /**
1.1.1.9 root 1307: * Search given list for TEXT symbol by address.
1.1.1.5 root 1308: * Return symbol index if address matches, -1 otherwise.
1309: */
1.1.1.9 root 1310: static int Symbols_GetCodeIndex(symbol_list_t* list, Uint32 addr)
1311: {
1312: if (!list) {
1313: return -1;
1314: }
1315: return Symbols_SearchByAddress(list->addresses, list->codecount, addr);
1316: }
1317: int Symbols_GetCpuCodeIndex(Uint32 addr)
1318: {
1319: return Symbols_GetCodeIndex(CpuSymbolsList, addr);
1320: }
1321: int Symbols_GetDspCodeIndex(Uint32 addr)
1.1.1.5 root 1322: {
1.1.1.9 root 1323: return Symbols_GetCodeIndex(DspSymbolsList, addr);
1.1 root 1324: }
1325:
1.1.1.5 root 1326: /**
1.1.1.9 root 1327: * Return how many TEXT symbols are loaded/available
1.1.1.5 root 1328: */
1.1.1.9 root 1329: int Symbols_CpuCodeCount(void)
1.1.1.5 root 1330: {
1.1.1.9 root 1331: return (CpuSymbolsList ? CpuSymbolsList->codecount : 0);
1.1.1.5 root 1332: }
1.1.1.9 root 1333: int Symbols_DspCodeCount(void)
1.1.1.5 root 1334: {
1.1.1.9 root 1335: return (DspSymbolsList ? DspSymbolsList->codecount : 0);
1.1.1.5 root 1336: }
1.1 root 1337:
1.1.1.6 root 1338: /* ---------------- symbol showing ------------------ */
1.1 root 1339:
1340: /**
1341: * Show symbols from given list with paging.
1342: */
1.1.1.9 root 1343: static void Symbols_Show(symbol_list_t* list, const char *sortcmd)
1.1 root 1344: {
1345: symbol_t *entry, *entries;
1.1.1.9 root 1346: const char *symtype, *sorttype;
1347: int i, rows, count;
1.1 root 1348: char symchar;
1.1.1.9 root 1349: char line[80];
1.1 root 1350:
1351: if (!list) {
1352: fprintf(stderr, "No symbols!\n");
1353: return;
1354: }
1355:
1.1.1.9 root 1356: if (strcmp("code", sortcmd) == 0) {
1357: sorttype = "address";
1.1 root 1358: entries = list->addresses;
1.1.1.9 root 1359: count = list->codecount;
1360: symtype = " TEXT";
1361: } else if (strcmp("data", sortcmd) == 0) {
1362: sorttype = "address";
1363: entries = list->addresses + list->codecount;
1364: count = list->datacount;
1365: symtype = " DATA/BSS/ABS";
1.1 root 1366: } else {
1.1.1.9 root 1367: sorttype = "name";
1.1 root 1368: entries = list->names;
1.1.1.9 root 1369: count = list->namecount;
1370: symtype = "";
1.1 root 1371: }
1.1.1.9 root 1372: rows = DebugUI_GetPageLines(ConfigureParams.Debugger.nSymbolLines, 20);
1.1 root 1373:
1.1.1.9 root 1374: for (entry = entries, i = 0; i < count; i++, entry++) {
1.1.1.6 root 1375: symchar = symbol_char(entry->type);
1.1 root 1376: fprintf(stderr, "0x%08x %c %s\n",
1377: entry->address, symchar, entry->name);
1.1.1.9 root 1378: if ((i + 1) % rows == 0) {
1.1 root 1379: fprintf(stderr, "--- q to exit listing, just enter to continue --- ");
1.1.1.9 root 1380: if (fgets(line, sizeof(line), stdin) == NULL ||
1381: toupper(line[0]) == 'Q') {
1382: break;
1.1 root 1383: }
1384: }
1385: }
1.1.1.9 root 1386: fprintf(stderr, "%d %s%s symbols (of %d) sorted by %s.\n", i,
1387: (list == CpuSymbolsList ? "CPU" : "DSP"),
1388: symtype, count, sorttype);
1.1 root 1389: }
1390:
1.1.1.6 root 1391: /* ---------------- binary load handling ------------------ */
1392:
1393: /**
1.1.1.9 root 1394: * If symbols are set resident, load them if they aren't yet loaded,
1395: * otherwise remove them along with program path.
1396: *
1397: * Called on GEMDOS reset and when program terminates
1398: * (unless terminated with Ptermres()).
1.1.1.6 root 1399: */
1400: void Symbols_RemoveCurrentProgram(void)
1401: {
1402: if (CurrentProgramPath) {
1.1.1.9 root 1403: if (ConfigureParams.Debugger.bSymbolsResident) {
1404: Symbols_LoadCurrentProgram();
1405: }
1.1.1.6 root 1406: free(CurrentProgramPath);
1407: CurrentProgramPath = NULL;
1408:
1.1.1.9 root 1409: if (CpuSymbolsList && SymbolsAreForProgram && !ConfigureParams.Debugger.bSymbolsResident) {
1.1.1.6 root 1410: Symbols_Free(CpuSymbolsList);
1.1.1.9 root 1411: fprintf(stderr, "Program exit, removing its symbols.\n");
1.1.1.6 root 1412: CpuSymbolsList = NULL;
1413: }
1414: }
1415: AutoLoadFailed = false;
1416: }
1417:
1418: /**
1.1.1.9 root 1419: * Set last opened program path and remove symbols if they
1420: * didn't get remove beforehand.
1421: *
1422: * Called on first Fopen() after Pexec().
1.1.1.6 root 1423: */
1.1.1.7 root 1424: void Symbols_ChangeCurrentProgram(const char *path)
1.1.1.6 root 1425: {
1.1.1.7 root 1426: if (Opt_IsAtariProgram(path)) {
1.1.1.9 root 1427: if (ConfigureParams.Debugger.bSymbolsResident) {
1428: if (CpuSymbolsList && SymbolsAreForProgram) {
1429: Symbols_Free(CpuSymbolsList);
1430: fprintf(stderr, "Program launch, removing previous program symbols.\n");
1431: CpuSymbolsList = NULL;
1432: }
1433: if (CurrentProgramPath) {
1434: free(CurrentProgramPath);
1435: }
1436: } else {
1437: Symbols_RemoveCurrentProgram();
1438: }
1.1.1.6 root 1439: CurrentProgramPath = strdup(path);
1440: }
1441: }
1442:
1443: /**
1444: * Load symbols for last opened program.
1.1.1.9 root 1445: * Called when debugger is invoked.
1.1.1.6 root 1446: */
1447: void Symbols_LoadCurrentProgram(void)
1448: {
1449: /* symbols already loaded, program path missing or previous load failed? */
1450: if (CpuSymbolsList || !CurrentProgramPath || AutoLoadFailed) {
1451: return;
1452: }
1453: CpuSymbolsList = Symbols_Load(CurrentProgramPath, NULL, 0);
1454: if (!CpuSymbolsList) {
1455: AutoLoadFailed = true;
1456: } else {
1457: AutoLoadFailed = false;
1458: }
1459: }
1460:
1461: /* ---------------- command parsing ------------------ */
1462:
1463: /**
1464: * Readline match callback to list symbols subcommands.
1465: * STATE = 0 -> different text from previous one.
1466: * Return next match or NULL if no matches.
1467: */
1468: char *Symbols_MatchCommand(const char *text, int state)
1469: {
1470: static const char* subs[] = {
1.1.1.9 root 1471: "code", "data", "free", "match", "name", "prg", "resident"
1.1.1.6 root 1472: };
1.1.1.8 root 1473: return DebugUI_MatchHelper(subs, ARRAY_SIZE(subs), text, state);
1.1.1.6 root 1474: }
1475:
1.1 root 1476: const char Symbols_Description[] =
1.1.1.10! root 1477: "<code|data|name> -- list symbols\n"
1.1.1.9 root 1478: "\tsymbols <prg|free> -- load/free symbols\n"
1479: "\tsymbols <filename> [<T offset> [<D offset> <B offset>]]\n"
1480: "\tsymbols <resident|match> -- toggle symbol options\n"
1.1.1.5 root 1481: "\n"
1.1.1.9 root 1482: "\t'name' command lists the currently loaded symbols, sorted by name.\n"
1483: "\t'code' and 'data' commands list them sorted by address; 'code' lists\n"
1484: "\tonly TEXT symbols, 'data' lists DATA/BSS/ABS symbols.\n"
1.1.1.5 root 1485: "\n"
1.1.1.9 root 1486: "\tBy default, symbols are loaded from the currently executing program's\n"
1487: "\tbinary when entering the debugger, IF program is started through\n"
1488: "\tGEMDOS HD, and they're freed when that program terminates.\n"
1.1.1.5 root 1489: "\n"
1.1.1.9 root 1490: "\tThat corresponds to 'prg' command which loads (DRI/GST or a.out\n"
1491: "\tformat) symbol table from the last program executed through\n"
1492: "\tthe GEMDOS HD emulation.\n"
1493: "\n"
1494: "\t'free' command removes the loaded symbols.\n"
1495: "\n"
1496: "\tIf program lacks symbols, or it's not run through the GEMDOS HD\n"
1497: "\temulation, user can ask symbols to be loaded from a file that's\n"
1498: "\tan unstripped version of the binary. Or from an ASCII symbols file\n"
1499: "\tproduced by the 'nm' and (Hatari) 'gst2ascii' tools.\n"
1500: "\n"
1501: "\tWith ASCII symbols files, given non-zero offset(s) are added to\n"
1502: "\tthe text (T), data (D) and BSS (B) symbols. Typically one uses\n"
1503: "\tTEXT variable, sometimes also DATA & BSS, variables for this.\n"
1504: "\n"
1505: "\t'resident' command toggles whether debugger will load symbols\n"
1506: "\tbefore program terminates (if user hasn't entered debugger before\n"
1507: "\tthis), and defers symbol freeing until another program is started.\n"
1508: "\n"
1509: "\t'match' command toggles whether TAB completion matches all symbols,\n"
1510: "\tor only symbol types that should be relevant for given command.";
1511:
1.1 root 1512:
1513: /**
1514: * Handle debugger 'symbols' command and its arguments
1515: */
1516: int Symbols_Command(int nArgc, char *psArgs[])
1517: {
1.1.1.9 root 1518: enum { TYPE_CPU, TYPE_DSP } listtype;
1.1.1.5 root 1519: Uint32 offsets[3], maxaddr;
1.1 root 1520: symbol_list_t *list;
1521: const char *file;
1.1.1.5 root 1522: int i;
1.1 root 1523:
1524: if (strcmp("dspsymbols", psArgs[0]) == 0) {
1525: listtype = TYPE_DSP;
1526: maxaddr = 0xFFFF;
1.1.1.9 root 1527: } else {
1.1 root 1528: listtype = TYPE_CPU;
1.1.1.7 root 1529: if ( ConfigureParams.System.bAddressSpace24 )
1530: maxaddr = 0x00FFFFFF;
1531: else
1532: maxaddr = 0xFFFFFFFF;
1.1.1.9 root 1533: }
1534: if (nArgc < 2) {
1535: file = "name";
1.1 root 1536: } else {
1.1.1.9 root 1537: file = psArgs[1];
1.1 root 1538: }
1.1.1.9 root 1539:
1540: /* toggle whether to autoload symbols on program start,
1541: * and keep them until next program start (=resident),
1542: * OR only loading them when entering the debugger and
1543: * freeing them when program terminates.
1544: */
1545: if (strcmp(file, "resident") == 0) {
1546: ConfigureParams.Debugger.bSymbolsResident = !ConfigureParams.Debugger.bSymbolsResident;
1547: if (ConfigureParams.Debugger.bSymbolsResident) {
1548: Symbols_LoadCurrentProgram();
1549: fprintf(stderr, "Program symbols will always be loaded (with reduced warnings)\nand kept resident until next program start.\n");
1550: } else {
1551: fprintf(stderr, "Program symbols will be removed when program terminates.\n");
1552: if (!CurrentProgramPath) {
1553: /* make sure normal autoloading isn't prevented */
1554: Symbols_Free(CpuSymbolsList);
1555: CpuSymbolsList = NULL;
1556: }
1557: }
1558: return DEBUGGER_CMDDONE;
1559: }
1560: /* toggling whether all or only specific symbols types get TAB completed */
1561: if (strcmp(file, "match") == 0) {
1562: ConfigureParams.Debugger.bMatchAllSymbols = !ConfigureParams.Debugger.bMatchAllSymbols;
1563: if (ConfigureParams.Debugger.bMatchAllSymbols) {
1564: fprintf(stderr, "Matching all symbols types.\n");
1565: } else {
1566: fprintf(stderr, "Matching only symbols (most) relevant for given command.\n");
1567: }
1568: return DEBUGGER_CMDDONE;
1.1 root 1569: }
1570:
1571: /* handle special cases */
1.1.1.9 root 1572: if (strcmp(file, "name") == 0 || strcmp(file, "code") == 0 || strcmp(file, "data") == 0) {
1.1 root 1573: list = (listtype == TYPE_DSP ? DspSymbolsList : CpuSymbolsList);
1574: Symbols_Show(list, file);
1575: return DEBUGGER_CMDDONE;
1576: }
1577: if (strcmp(file, "free") == 0) {
1578: if (listtype == TYPE_DSP) {
1579: Symbols_Free(DspSymbolsList);
1580: DspSymbolsList = NULL;
1581: } else {
1582: Symbols_Free(CpuSymbolsList);
1583: CpuSymbolsList = NULL;
1584: }
1585: return DEBUGGER_CMDDONE;
1586: }
1.1.1.5 root 1587:
1588: /* get offsets */
1589: offsets[0] = 0;
1.1.1.8 root 1590: for (i = 0; i < ARRAY_SIZE(offsets); i++) {
1.1.1.5 root 1591: if (i+2 < nArgc) {
1592: int dummy;
1593: Eval_Expression(psArgs[i+2], &(offsets[i]), &dummy, listtype==TYPE_DSP);
1594: } else {
1595: /* default to first (text) offset */
1596: offsets[i] = offsets[0];
1597: }
1.1 root 1598: }
1599:
1.1.1.5 root 1600: if (strcmp(file, "prg") == 0) {
1.1.1.6 root 1601: file = CurrentProgramPath;
1.1.1.5 root 1602: if (!file) {
1603: fprintf(stderr, "ERROR: no program loaded (through GEMDOS HD emu)!\n");
1604: return DEBUGGER_CMDDONE;
1605: }
1606: }
1607: list = Symbols_Load(file, offsets, maxaddr);
1.1 root 1608: if (list) {
1609: if (listtype == TYPE_CPU) {
1610: Symbols_Free(CpuSymbolsList);
1611: CpuSymbolsList = list;
1612: } else {
1613: Symbols_Free(DspSymbolsList);
1614: DspSymbolsList = list;
1615: }
1616: } else {
1617: DebugUI_PrintCmdHelp(psArgs[0]);
1618: }
1619: return DEBUGGER_CMDDONE;
1620: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.