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