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