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

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

unix.superglobalmegacorp.com

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