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