Annotation of hatari/src/debug/symbols.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.