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

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

unix.superglobalmegacorp.com

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