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

1.1       root        1: /*
                      2:  * Hatari - symbols.c
                      3:  * 
1.1.1.5 ! root        4:  * Copyright (C) 2010-2013 by Eero Tamminen
1.1       root        5:  * 
1.1.1.5 ! root        6:  * This file is distributed under the GNU General Public License, version 2
        !             7:  * or at your option any later version. Read the file gpl.txt for details.
1.1       root        8:  * 
                      9:  * symbols.c - Hatari debugger symbol/address handling; parsing, sorting,
                     10:  * matching, TAB completion support etc.
                     11:  * 
1.1.1.5 ! root       12:  * Symbol/address information is read either from:
        !            13:  * - A program file's DRI/GST format symbol table, or
        !            14:  * - ASCII file which contents are subset of "nm" output i.e. composed of
        !            15:  *   a hexadecimal addresses followed by a space, letter indicating symbol
        !            16:  *   type (T = text/code, D = data, B = BSS), space and the symbol name.
        !            17:  *   Empty lines and lines starting with '#' are ignored.  It's AHCC SYM
        !            18:  *   output compatible.
1.1       root       19:  */
                     20: const char Symbols_fileid[] = "Hatari symbols.c : " __DATE__ " " __TIME__;
                     21: 
                     22: #include <ctype.h>
                     23: #include <stdio.h>
                     24: #include <string.h>
                     25: #include <assert.h>
                     26: #include <SDL_types.h>
1.1.1.5 ! root       27: #include <SDL_endian.h>
1.1       root       28: #include "main.h"
                     29: #include "symbols.h"
                     30: #include "debugui.h"
                     31: #include "debug_priv.h"
1.1.1.5 ! root       32: #include "debugInfo.h"
1.1       root       33: #include "evaluate.h"
1.1.1.5 ! root       34: #include "gemdos.h"
1.1       root       35: 
                     36: typedef struct {
                     37:        char *name;
                     38:        Uint32 address;
                     39:        symtype_t type;
                     40: } symbol_t;
                     41: 
                     42: typedef struct {
1.1.1.5 ! root       43:        int count;              /* final symbol count */
        !            44:        int symbols;            /* initial symbol count */
1.1       root       45:        symbol_t *addresses;    /* items sorted by address */
                     46:        symbol_t *names;        /* items sorted by symbol name */
                     47: } symbol_list_t;
                     48: 
1.1.1.5 ! root       49: typedef struct {
        !            50:        Uint32 offset;
        !            51:        Uint32 end;
        !            52: } prg_section_t;
        !            53: 
1.1       root       54: 
                     55: /* how many characters the symbol name can have.
                     56:  * NOTE: change also sscanf width arg if you change this!!!
                     57:  */
                     58: #define MAX_SYM_SIZE 32
                     59: 
                     60: 
                     61: /* TODO: add symbol name/address file names to configuration? */
                     62: static symbol_list_t *CpuSymbolsList;
                     63: static symbol_list_t *DspSymbolsList;
                     64: 
                     65: 
                     66: /* ------------------ load and free functions ------------------ */
                     67: 
                     68: /**
                     69:  * compare function for qsort() to sort according to symbol address
                     70:  */
                     71: static int symbols_by_address(const void *s1, const void *s2)
                     72: {
                     73:        Uint32 addr1 = ((const symbol_t*)s1)->address;
                     74:        Uint32 addr2 = ((const symbol_t*)s2)->address;
                     75: 
                     76:        if (addr1 < addr2) {
                     77:                return -1;
                     78:        }
                     79:        if (addr1 > addr2) {
                     80:                return 1;
                     81:        }
                     82:        fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
                     83:                ((const symbol_t*)s1)->name, ((const symbol_t*)s2)->name, addr1);
                     84:        return 0;
                     85: }
                     86: 
                     87: /**
                     88:  * compare function for qsort() to sort according to symbol name
                     89:  */
                     90: static int symbols_by_name(const void *s1, const void *s2)
                     91: {
                     92:        const char* name1 = ((const symbol_t*)s1)->name;
                     93:        const char* name2 = ((const symbol_t*)s2)->name;
                     94:        int ret;
                     95: 
                     96:        ret = strcmp(name1, name2);
                     97:        if (!ret) {
1.1.1.4   root       98:                fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
                     99:                        ((const symbol_t*)s1)->address, ((const symbol_t*)s2)->address, name1);
1.1       root      100:        }
                    101:        return ret;
                    102: }
                    103: 
                    104: 
                    105: /**
1.1.1.5 ! root      106:  * Allocate symbol list & names for given number of items.
        !           107:  * Return allocated list or NULL on failure.
        !           108:  */
        !           109: static symbol_list_t* symbol_list_alloc(int symbols)
        !           110: {
        !           111:        symbol_list_t *list;
        !           112: 
        !           113:        if (!symbols) {
        !           114:                return NULL;
        !           115:        }
        !           116:        list = calloc(1, sizeof(symbol_list_t));
        !           117:        if (list) {
        !           118:                list->names = malloc(symbols * sizeof(symbol_t));
        !           119:                if (!list->names) {
        !           120:                        free(list);
        !           121:                        list = NULL;
        !           122:                }
        !           123:        }
        !           124:        return list;
        !           125: }
        !           126: 
        !           127: /**
        !           128:  * Free symbol list & names.
        !           129:  */
        !           130: static void symbol_list_free(symbol_list_t *list)
        !           131: {
        !           132:        if (list) {
        !           133:                if (list->names) {
        !           134:                        free(list->names);
        !           135:                }
        !           136:                free(list);
        !           137:        }
        !           138: }
        !           139: 
        !           140: /**
1.1       root      141:  * Load symbols of given type and the symbol address addresses from
1.1.1.5 ! root      142:  * DRI/GST format symbol table, and add given offsets to the addresses:
        !           143:  *     http://toshyp.atari.org/en/005005.html
1.1       root      144:  * Return symbols list or NULL for failure.
                    145:  */
1.1.1.5 ! root      146: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize)
1.1       root      147: {
1.1.1.5 ! root      148:        int i, count, symbols, len;
        !           149:        int dtypes, locals, ofiles;
        !           150:        prg_section_t *section;
1.1       root      151:        symbol_list_t *list;
                    152:        symtype_t symtype;
1.1.1.5 ! root      153: #define DRI_ENTRY_SIZE 14
        !           154:        char name[23];
        !           155:        Uint16 symid;
1.1       root      156:        Uint32 address;
1.1.1.5 ! root      157: 
        !           158:        if (tablesize % DRI_ENTRY_SIZE) {
        !           159:                fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
        !           160:                return NULL;
        !           161:        }
        !           162:        symbols = tablesize / DRI_ENTRY_SIZE;
        !           163:        if (!(list = symbol_list_alloc(symbols))) {
        !           164:                return NULL;
        !           165:        }
        !           166: 
        !           167:        dtypes = ofiles = locals = count = 0;
        !           168:        for (i = 1; i <= symbols; i++) {
        !           169:                /* read DRI symbol table slot */
        !           170:                if (fread(name, 8, 1, fp) != 1 ||
        !           171:                    fread(&symid, sizeof(symid), 1, fp) != 1 ||
        !           172:                    fread(&address, sizeof(address), 1, fp) != 1) {
        !           173:                        break;
        !           174:                }
        !           175:                address = SDL_SwapBE32(address);
        !           176:                symid = SDL_SwapBE16(symid);
        !           177: 
        !           178:                /* GST extended DRI symbol format? */
        !           179:                if ((symid & 0x0048)) {
        !           180:                        /* next slot is rest of name */
        !           181:                        i += 1;
        !           182:                        if (fread(name+8, 14, 1, fp) != 1) {
        !           183:                                break;
        !           184:                        }
        !           185:                        name[22] = '\0';
        !           186:                } else {
        !           187:                        name[8] = '\0';
        !           188:                }
        !           189: 
        !           190:                /* check section */
        !           191:                switch (symid & 0xf00) {
        !           192:                case 0x0200:
        !           193:                        symtype = SYMTYPE_TEXT;
        !           194:                        section = &(sections[0]);
        !           195:                        break;
        !           196:                case 0x0400:
        !           197:                        symtype = SYMTYPE_DATA;
        !           198:                        section = &(sections[1]);
        !           199:                        break;
        !           200:                case 0x0100:
        !           201:                        symtype = SYMTYPE_BSS;
        !           202:                        section = &(sections[2]);
        !           203:                        break;
        !           204:                default:
        !           205:                        if ((symid & 0xe000) == 0xe000) {
        !           206:                                dtypes++;
        !           207:                                continue;
        !           208:                        }
        !           209:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
        !           210:                        continue;
        !           211:                }
        !           212:                if (!(gettype & symtype)) {
        !           213:                        continue;
        !           214:                }
        !           215:                if (name[0] == '.' && name[1] == 'L') {
        !           216:                        locals++;
        !           217:                        continue;
        !           218:                }
        !           219:                len = strlen(name);
        !           220:                if (strchr(name, '/') || (len > 2 && name[len-2] == '.' && name[len-1] == 'o')) {
        !           221:                        ofiles++;
        !           222:                        continue;
        !           223:                }
        !           224:                address += section->offset;
        !           225:                if (address > section->end) {
        !           226:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d with invalid offset 0x%x (>= 0x%x).\n", name, i, address, section->end);
        !           227:                        continue;
        !           228:                }
        !           229:                list->names[count].address = address;
        !           230:                list->names[count].type = symtype;
        !           231:                list->names[count].name = strdup(name);
        !           232:                assert(list->names[count].name);
        !           233:                count++;
        !           234:        }
        !           235:        if (i <= symbols) {
        !           236:                perror("ERROR: reading symbol failed");
        !           237:                symbol_list_free(list);
1.1       root      238:                return NULL;
                    239:        }
1.1.1.5 ! root      240:        if (dtypes) {
        !           241:                fprintf(stderr, "NOTE: ignored %d globally defined equated values.\n", dtypes);
        !           242:        }
        !           243:        if (locals) {
        !           244:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
        !           245:        }
        !           246:        if (ofiles) {
        !           247:                /* object file path names most likely get truncated and
        !           248:                 * as result cause unnecessary symbol name conflicts in
        !           249:                 * addition to object file addresses conflicting with
        !           250:                 * first symbol in the object file.
        !           251:                 */
        !           252:                fprintf(stderr, "NOTE: ignored %d object file names (= name has '/' or ends in '.o').\n", ofiles);
        !           253:        }
        !           254:        list->symbols = symbols;
        !           255:        list->count = count;
        !           256:        return list;
        !           257: }
        !           258: 
        !           259: /**
        !           260:  * Parse program header and use symbol table format specific loader
        !           261:  * loader function to load the symbols.
        !           262:  * Return symbols list or NULL for failure.
        !           263:  */
        !           264: static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
        !           265: {
        !           266:        Uint32 textlen, datalen, bsslen, start, tablesize, tabletype;
        !           267:        prg_section_t sections[3];
        !           268:        int offset, reads = 0;
        !           269: 
        !           270:        /* get TEXT, DATA & BSS section sizes */
        !           271:        reads += fread(&textlen, sizeof(textlen), 1, fp);
        !           272:        textlen = SDL_SwapBE32(textlen);
        !           273:        reads += fread(&datalen, sizeof(datalen), 1, fp);
        !           274:        datalen = SDL_SwapBE32(datalen);
        !           275:        reads += fread(&bsslen, sizeof(bsslen), 1, fp);
        !           276:        bsslen = SDL_SwapBE32(bsslen);
        !           277: 
        !           278:        /* get symbol table size & type and check that all reads succeeded */
        !           279:        reads += fread(&tablesize, sizeof(tablesize), 1, fp);
        !           280:        tablesize = SDL_SwapBE32(tablesize);
        !           281:        if (!tablesize) {
        !           282:                fprintf(stderr, "ERROR: symbol table missing from the program!\n");
        !           283:                return NULL;
        !           284:        }
        !           285:        reads += fread(&tabletype, sizeof(tabletype), 1, fp);
        !           286:        tabletype = SDL_SwapBE32(tabletype);
        !           287:        if (reads != 5) {
        !           288:                fprintf(stderr, "ERROR: program header reading failed!\n");
        !           289:                return NULL;
        !           290:        }
        !           291: 
        !           292:        /* go to start of symbol table */
        !           293:        offset = 0x1C + textlen + datalen;
        !           294:        if (fseek(fp, offset, SEEK_SET) < 0) {
        !           295:                perror("ERROR: seeking to symbol table failed");
        !           296:                return NULL;
        !           297:        }
        !           298:        /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
        !           299:        start = DebugInfo_GetTEXT();
        !           300:        if (!start) {
        !           301:                fprintf(stderr, "ERROR: no valid program basepage!\n");
        !           302:                return NULL;
        !           303:        }
        !           304:        sections[0].offset = start;
        !           305:        sections[0].end = start + textlen;
        !           306:        if (DebugInfo_GetTEXTEnd() != sections[0].end - 1) {
        !           307:                fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
        !           308:                return NULL;
        !           309:        }
        !           310: 
        !           311:        start = DebugInfo_GetDATA();
        !           312:        sections[1].offset = start - textlen;
        !           313:        sections[1].end = start + datalen - 1;
        !           314: 
        !           315:        start = DebugInfo_GetBSS();
        !           316:        sections[2].offset = start - textlen - datalen;
        !           317:        sections[2].end = start + bsslen - 1;
        !           318: 
        !           319:        switch (tabletype) {
        !           320:        case 0x4D694E54:        /* "MiNT" */
        !           321:                fprintf(stderr, "MiNT executable, trying to load GST symbol table at offset 0x%x...\n", offset);
        !           322:                return symbols_load_dri(fp, sections, gettype, tablesize);
        !           323:        case 0x0:
        !           324:                fprintf(stderr, "Old style excutable, loading DRI / GST symbol table at offset 0x%x.\n", offset);
        !           325:                return symbols_load_dri(fp, sections, gettype, tablesize);
        !           326:        default:
        !           327:                fprintf(stderr, "ERROR: unknown executable type 0x%x at offset 0x%x!\n", tabletype, offset);
        !           328:        }
        !           329:        return NULL;
        !           330: }
        !           331: 
        !           332: /**
        !           333:  * Load symbols of given type and the symbol address addresses from
        !           334:  * the given ASCII file and add given offsets to the addresses.
        !           335:  * Return symbols list or NULL for failure.
        !           336:  */
        !           337: static symbol_list_t* symbols_load_ascii(FILE *fp, Uint32 *offsets, Uint32 maxaddr, symtype_t gettype)
        !           338: {
        !           339:        symbol_list_t *list;
        !           340:        char symchar, buffer[128], name[MAX_SYM_SIZE+1], *buf;
        !           341:        int count, line, symbols;
        !           342:        Uint32 address, offset;
        !           343:        symtype_t symtype;
1.1       root      344: 
                    345:        /* count content lines */
                    346:        symbols = 0;
                    347:        while (fgets(buffer, sizeof(buffer), fp)) {
1.1.1.3   root      348:                /* skip comments (AHCC SYM file comments start with '*') */
                    349:                if (*buffer == '#' || *buffer == '*') {
1.1       root      350:                        continue;
                    351:                }
                    352:                /* skip empty lines */
                    353:                for (buf = buffer; isspace(*buf); buf++);
                    354:                if (!*buf) {
                    355:                        continue;
                    356:                }
                    357:                symbols++;
                    358:        }
                    359:        fseek(fp, 0, SEEK_SET);
                    360: 
1.1.1.5 ! root      361:        /* allocate space for symbol list & names */
        !           362:        if (!(list = symbol_list_alloc(symbols))) {
1.1       root      363:                return NULL;
                    364:        }
                    365: 
                    366:        /* read symbols */
                    367:        count = 0;
                    368:        for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) {
1.1.1.3   root      369:                /* skip comments (AHCC SYM file comments start with '*') */
                    370:                if (*buffer == '#' || *buffer == '*') {
1.1       root      371:                        continue;
                    372:                }
                    373:                /* skip empty lines */
                    374:                for (buf = buffer; isspace(*buf); buf++);
                    375:                if (!*buf) {
                    376:                        continue;
                    377:                }
                    378:                assert(count < symbols); /* file not modified in meanwhile? */
1.1.1.5 ! root      379:                if (sscanf(buffer, "%x %c %32[0-9A-Za-z_.-]s", &address, &symchar, name) != 3) {
        !           380:                        fprintf(stderr, "WARNING: syntax error on line %d, skipping.\n", line);
1.1       root      381:                        continue;
                    382:                }
                    383:                switch (toupper(symchar)) {
1.1.1.5 ! root      384:                case 'T':
        !           385:                        symtype = SYMTYPE_TEXT;
        !           386:                        offset = offsets[0];
        !           387:                        break;
        !           388:                case 'O':       /* AHCC type for _StkSize etc */
        !           389:                case 'D':
        !           390:                        symtype = SYMTYPE_DATA;
        !           391:                        offset = offsets[1];
        !           392:                        break;
        !           393:                case 'B':
        !           394:                        symtype = SYMTYPE_BSS;
        !           395:                        offset = offsets[2];
        !           396:                        break;
1.1       root      397:                default:
1.1.1.5 ! root      398:                        fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d, skipping.\n", symchar, line);
1.1       root      399:                        continue;
                    400:                }
                    401:                if (!(gettype & symtype)) {
                    402:                        continue;
                    403:                }
1.1.1.5 ! root      404:                address += offset;
        !           405:                if (address > maxaddr) {
        !           406:                        fprintf(stderr, "WARNING: invalid address 0x%x on line %d, skipping.\n", address, line);
        !           407:                        continue;
        !           408:                }
1.1       root      409:                list->names[count].address = address;
                    410:                list->names[count].type = symtype;
                    411:                list->names[count].name = strdup(name);
                    412:                assert(list->names[count].name);
                    413:                count++;
                    414:        }
1.1.1.5 ! root      415:        list->symbols = symbols;
        !           416:        list->count = count;
        !           417:        return list;
        !           418: }
1.1       root      419: 
1.1.1.5 ! root      420: /**
        !           421:  * Load symbols of given type and the symbol address addresses from
        !           422:  * the given file and add given offsets to the addresses.
        !           423:  * Return symbols list or NULL for failure.
        !           424:  */
        !           425: static symbol_list_t* Symbols_Load(const char *filename, Uint32 *offsets, Uint32 maxaddr)
        !           426: {
        !           427:        symbol_list_t *list;
        !           428:        Uint16 magic;
        !           429:        FILE *fp;
        !           430: 
        !           431:        if (!(fp = fopen(filename, "r"))) {
        !           432:                fprintf(stderr, "ERROR: opening '%s' failed!\n", filename);
        !           433:                return NULL;
        !           434:        }
        !           435:        if (fread(&magic, sizeof(magic), 1, fp) != 1) {
        !           436:                fprintf(stderr, "ERROR: reading file '%s' failed.\n", filename);
        !           437:                fclose(fp);
        !           438:                return NULL;
        !           439:        }
        !           440: 
        !           441:        if (SDL_SwapBE16(magic) == 0x601A) {
        !           442:                const char *last = GemDOS_GetLastProgramPath();
        !           443:                fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
        !           444:                if (strcmp(last, filename) != 0) {
        !           445:                        fprintf(stderr, "WARNING: given program doesn't match last program executed by GEMDOS HD emulation:\n\t%s", last);
        !           446:                }
        !           447:                list = symbols_load_binary(fp, SYMTYPE_ALL);
        !           448:        } else {
        !           449:                fprintf(stderr, "Reading 'nm' style ASCII symbols from '%s'...\n", filename);
        !           450:                list = symbols_load_ascii(fp, offsets, maxaddr, SYMTYPE_ALL);
        !           451:        }
        !           452:        fclose(fp);
        !           453: 
        !           454:        if (!list) {
        !           455:                fprintf(stderr, "ERROR: no symbols, or reading them from '%s' failed!\n", filename);
        !           456:                return NULL;
        !           457:        }
        !           458: 
        !           459:        if (list->count < list->symbols) {
        !           460:                if (!list->count) {
1.1       root      461:                        fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename);
1.1.1.5 ! root      462:                        symbol_list_free(list);
1.1       root      463:                        return NULL;
                    464:                }
                    465:                /* parsed less than there were "content" lines */
1.1.1.5 ! root      466:                list->names = realloc(list->names, list->count * sizeof(symbol_t));
1.1       root      467:                assert(list->names);
                    468:        }
                    469: 
                    470:        /* copy name list to address list */
1.1.1.5 ! root      471:        list->addresses = malloc(list->count * sizeof(symbol_t));
1.1       root      472:        assert(list->addresses);
1.1.1.5 ! root      473:        memcpy(list->addresses, list->names, list->count * sizeof(symbol_t));
1.1       root      474: 
                    475:        /* sort both lists, with different criteria */
1.1.1.5 ! root      476:        qsort(list->addresses, list->count, sizeof(symbol_t), symbols_by_address);
        !           477:        qsort(list->names, list->count, sizeof(symbol_t), symbols_by_name);
1.1       root      478: 
1.1.1.5 ! root      479:        fprintf(stderr, "Loaded %d symbols from '%s'.\n", list->count, filename);
1.1       root      480:        return list;
                    481: }
                    482: 
                    483: 
                    484: /**
                    485:  * Free read symbols.
                    486:  */
                    487: static void Symbols_Free(symbol_list_t* list)
                    488: {
1.1.1.5 ! root      489:        int i;
1.1       root      490: 
                    491:        if (!list) {
                    492:                return;
                    493:        }
                    494:        assert(list->count);
                    495:        for (i = 0; i < list->count; i++) {
                    496:                free(list->names[i].name);
                    497:        }
                    498:        free(list->addresses);
                    499:        free(list->names);
1.1.1.5 ! root      500: 
        !           501:        /* catch use of freed list */
        !           502:        list->addresses = NULL;
        !           503:        list->names = NULL;
        !           504:        list->count = 0;
1.1       root      505:        free(list);
                    506: }
                    507: 
                    508: 
                    509: /* ---------------- symbol name completion support ------------------ */
                    510: 
                    511: /**
                    512:  * Helper for symbol name completion and finding their addresses.
                    513:  * STATE = 0 -> different text from previous one.
                    514:  * Return (copy of) next name or NULL if no matches.
                    515:  */
                    516: static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state)
                    517: {
1.1.1.5 ! root      518:        static int i, len;
1.1       root      519:        const symbol_t *entry;
                    520:        
                    521:        if (!list) {
                    522:                return NULL;
                    523:        }
                    524: 
                    525:        if (!state) {
                    526:                /* first match */
                    527:                len = strlen(text);
                    528:                i = 0;
                    529:        }
                    530: 
                    531:        /* next match */
                    532:        entry = list->names;
                    533:        while (i < list->count) {
                    534:                if ((entry[i].type & symtype) &&
                    535:                    strncmp(entry[i].name, text, len) == 0) {
                    536:                        return strdup(entry[i++].name);
                    537:                } else {
                    538:                        i++;
                    539:                }
                    540:        }
                    541:        return NULL;
                    542: }
                    543: 
                    544: /**
                    545:  * Readline match callbacks for CPU symbol name completion.
                    546:  * STATE = 0 -> different text from previous one.
                    547:  * Return next match or NULL if no matches.
                    548:  */
                    549: char* Symbols_MatchCpuAddress(const char *text, int state)
                    550: {
                    551:        return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
                    552: }
                    553: char* Symbols_MatchCpuCodeAddress(const char *text, int state)
                    554: {
                    555:        return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_TEXT, text, state);
                    556: }
                    557: char* Symbols_MatchCpuDataAddress(const char *text, int state)
                    558: {
                    559:        return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
                    560: }
                    561: 
                    562: /**
                    563:  * Readline match callback for DSP symbol name completion.
                    564:  * STATE = 0 -> different text from previous one.
                    565:  * Return next match or NULL if no matches.
                    566:  */
                    567: char* Symbols_MatchDspAddress(const char *text, int state)
                    568: {
                    569:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state);
                    570: }
                    571: char* Symbols_MatchDspCodeAddress(const char *text, int state)
                    572: {
                    573:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_TEXT, text, state);
                    574: }
                    575: char* Symbols_MatchDspDataAddress(const char *text, int state)
                    576: {
                    577:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
                    578: }
                    579: 
                    580: 
                    581: /* ---------------- symbol name -> address search ------------------ */
                    582: 
                    583: /**
                    584:  * Search symbol of given type by name.
                    585:  * Return symbol if name matches, zero otherwise.
                    586:  */
                    587: static const symbol_t* Symbols_SearchByName(symbol_list_t* list, symtype_t symtype, const char *name)
                    588: {
                    589:        symbol_t *entries;
                    590:        /* left, right, middle */
                    591:         int l, r, m, dir;
                    592: 
                    593:        if (!list) {
                    594:                return NULL;
                    595:        }
                    596:        entries = list->names;
                    597: 
                    598:        /* bisect */
                    599:        l = 0;
                    600:        r = list->count - 1;
                    601:        do {
                    602:                m = (l+r) >> 1;
                    603:                dir = strcmp(entries[m].name, name);
                    604:                if (dir == 0 && (entries[m].type & symtype)) {
                    605:                        return &(entries[m]);
                    606:                }
                    607:                if (dir > 0) {
                    608:                        r = m-1;
                    609:                } else {
                    610:                        l = m+1;
                    611:                }
                    612:        } while (l <= r);
                    613:        return NULL;
                    614: }
                    615: 
                    616: /**
                    617:  * Set given CPU symbol's address to variable and return TRUE if one was found.
                    618:  */
                    619: bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, Uint32 *addr)
                    620: {
                    621:        const symbol_t *entry;
                    622:        entry = Symbols_SearchByName(CpuSymbolsList, symtype, name);
                    623:        if (entry) {
                    624:                *addr = entry->address;
                    625:                return true;
                    626:        }
                    627:        return false;
                    628: }
                    629: 
                    630: /**
                    631:  * Set given DSP symbol's address to variable and return TRUE if one was found.
                    632:  */
                    633: bool Symbols_GetDspAddress(symtype_t symtype, const char *name, Uint32 *addr)
                    634: {
                    635:        const symbol_t *entry;
                    636:        entry = Symbols_SearchByName(DspSymbolsList, symtype, name);
                    637:        if (entry) {
                    638:                *addr = entry->address;
                    639:                return true;
                    640:        }
                    641:        return false;
                    642: }
                    643: 
                    644: 
                    645: /* ---------------- symbol address -> name search ------------------ */
                    646: 
                    647: /**
                    648:  * Search symbol by address.
1.1.1.5 ! root      649:  * Return symbol index if address matches, -1 otherwise.
1.1       root      650:  */
1.1.1.5 ! root      651: static int Symbols_SearchByAddress(symbol_list_t* list, Uint32 addr)
1.1       root      652: {
                    653:        symbol_t *entries;
                    654:        /* left, right, middle */
                    655:         int l, r, m;
                    656:        Uint32 curr;
                    657: 
                    658:        if (!list) {
1.1.1.5 ! root      659:                return -1;
1.1       root      660:        }
                    661:        entries = list->addresses;
                    662: 
                    663:        /* bisect */
                    664:        l = 0;
                    665:        r = list->count - 1;
                    666:        do {
                    667:                m = (l+r) >> 1;
                    668:                curr = entries[m].address;
                    669:                if (curr == addr) {
1.1.1.5 ! root      670:                        return m;
1.1       root      671:                }
                    672:                if (curr > addr) {
                    673:                        r = m-1;
                    674:                } else {
                    675:                        l = m+1;
                    676:                }
                    677:        } while (l <= r);
1.1.1.5 ! root      678:        return -1;
1.1       root      679: }
                    680: 
                    681: /**
                    682:  * Search CPU symbol by address.
                    683:  * Return symbol name if address matches, NULL otherwise.
                    684:  * Returned name is valid only until next Symbols_* function call.
                    685:  */
                    686: const char* Symbols_GetByCpuAddress(Uint32 addr)
                    687: {
1.1.1.5 ! root      688:        int idx = Symbols_SearchByAddress(CpuSymbolsList, addr);
        !           689:        if (idx < 0) {
        !           690:                return NULL;
        !           691:        }
        !           692:        return CpuSymbolsList->addresses[idx].name;
1.1       root      693: }
                    694: /**
                    695:  * Search DSP symbol by address.
                    696:  * Return symbol name if address matches, NULL otherwise.
                    697:  * Returned name is valid only until next Symbols_* function call.
                    698:  */
                    699: const char* Symbols_GetByDspAddress(Uint32 addr)
                    700: {
1.1.1.5 ! root      701:        int idx = Symbols_SearchByAddress(DspSymbolsList, addr);
        !           702:        if (idx < 0) {
        !           703:                return NULL;
        !           704:        }
        !           705:        return DspSymbolsList->addresses[idx].name;
        !           706: }
        !           707: 
        !           708: /**
        !           709:  * Search CPU symbol by address.
        !           710:  * Return symbol index if address matches, -1 otherwise.
        !           711:  */
        !           712: int Symbols_GetCpuAddressIndex(Uint32 addr)
        !           713: {
        !           714:        return Symbols_SearchByAddress(CpuSymbolsList, addr);   
        !           715: }
        !           716: 
        !           717: /**
        !           718:  * Search DSP symbol by address.
        !           719:  * Return symbol index if address matches, -1 otherwise.
        !           720:  */
        !           721: int Symbols_GetDspAddressIndex(Uint32 addr)
        !           722: {
        !           723:        return Symbols_SearchByAddress(DspSymbolsList, addr);   
1.1       root      724: }
                    725: 
1.1.1.5 ! root      726: /**
        !           727:  * Return how many symbols are loaded/available
        !           728:  */
        !           729: int Symbols_CpuCount(void)
        !           730: {
        !           731:        return (CpuSymbolsList ? CpuSymbolsList->count : 0);
        !           732: }
        !           733: int Symbols_DspCount(void)
        !           734: {
        !           735:        return (DspSymbolsList ? DspSymbolsList->count : 0);
        !           736: }
1.1       root      737: 
                    738: /* ---------------- symbol showing and command parsing ------------------ */
                    739: 
                    740: /**
                    741:  * Show symbols from given list with paging.
                    742:  */
                    743: static void Symbols_Show(symbol_list_t* list, const char *sorttype)
                    744: {
                    745:        symbol_t *entry, *entries;
                    746:        char symchar;
1.1.1.5 ! root      747:        int i;
1.1       root      748:        
                    749:        if (!list) {
                    750:                fprintf(stderr, "No symbols!\n");
                    751:                return;
                    752:        }
                    753: 
                    754:        if (strcmp("addr", sorttype) == 0) {
                    755:                entries = list->addresses;
                    756:        } else {
                    757:                entries = list->names;
                    758:        }
                    759:        fprintf(stderr, "%s symbols sorted by %s:\n",
                    760:                (list == CpuSymbolsList ? "CPU" : "DSP"), sorttype);
                    761: 
                    762:        for (entry = entries, i = 0; i < list->count; i++, entry++) {
                    763:                switch (entry->type) {
                    764:                case SYMTYPE_TEXT:
                    765:                        symchar = 'T';
                    766:                        break;
                    767:                case SYMTYPE_DATA:
                    768:                        symchar = 'D';
                    769:                        break;
                    770:                case SYMTYPE_BSS:
                    771:                        symchar = 'B';
                    772:                        break;
                    773:                default:
                    774:                        symchar = '?';
                    775:                }
                    776:                fprintf(stderr, "0x%08x %c %s\n",
                    777:                        entry->address, symchar, entry->name);
                    778:                if (i && i % 20 == 0) {
                    779:                        fprintf(stderr, "--- q to exit listing, just enter to continue --- ");
                    780:                        if (toupper(getchar()) == 'Q') {
                    781:                                return;
                    782:                        }
                    783:                }
                    784:        }
                    785: }
                    786: 
                    787: const char Symbols_Description[] =
1.1.1.5 ! root      788:        "<filename|prg|addr|name|free> [<T offset> [<D offset> <B offset>]]\n"
        !           789:        "\tLoads symbol names and their addresses from the given file.\n"
        !           790:        "\tIf there were previously loaded symbols, they're replaced.\n"
        !           791:        "\n"
        !           792:        "\tGiving 'prg' instead of a file name, loads DRI/GST symbol table\n"
        !           793:        "\tfrom the last program executed through the GEMDOS HD emulation.\n"
        !           794:        "\n"
        !           795:        "\tGiving either 'name' or 'addr' instead of a file name, will\n"
        !           796:        "\tlist the currently loaded symbols.  Giving 'free' will remove\n"
        !           797:        "\tthe loaded symbols.\n"
        !           798:        "\n"
        !           799:        "\tIf one base address/offset is given, its added to all addresses.\n"
        !           800:        "\tIf three offsets are given (and non-zero), they're applied to\n"
        !           801:        "\ttext (T), data (D) and BSS (B) symbols.  Given offsets are used\n"
        !           802:        "\tonly when loading ASCII symbol files.";
1.1       root      803: 
                    804: /**
                    805:  * Handle debugger 'symbols' command and its arguments
                    806:  */
                    807: int Symbols_Command(int nArgc, char *psArgs[])
                    808: {
                    809:        enum { TYPE_NONE, TYPE_CPU, TYPE_DSP } listtype;
1.1.1.5 ! root      810:        Uint32 offsets[3], maxaddr;
1.1       root      811:        symbol_list_t *list;
                    812:        const char *file;
1.1.1.5 ! root      813:        int i;
1.1       root      814: 
                    815:        if (strcmp("dspsymbols", psArgs[0]) == 0) {
                    816:                listtype = TYPE_DSP;
                    817:                maxaddr = 0xFFFF;
                    818:        } else if (strcmp("symbols", psArgs[0]) == 0) {
                    819:                listtype = TYPE_CPU;
                    820:                maxaddr = 0xFFFFFF;
                    821:        } else {
                    822:                listtype = TYPE_NONE;
                    823:                maxaddr = 0;
                    824:        }
                    825:        if (nArgc < 2 || listtype == TYPE_NONE) {
                    826:                DebugUI_PrintCmdHelp(psArgs[0]);
                    827:                return DEBUGGER_CMDDONE;
                    828:        }
                    829:        file = psArgs[1];
                    830: 
                    831:        /* handle special cases */
                    832:        if (strcmp(file, "name") == 0 || strcmp(file, "addr") == 0) {
                    833:                list = (listtype == TYPE_DSP ? DspSymbolsList : CpuSymbolsList);
                    834:                Symbols_Show(list, file);
                    835:                return DEBUGGER_CMDDONE;
                    836:        }
                    837:        if (strcmp(file, "free") == 0) {
                    838:                if (listtype == TYPE_DSP) {
                    839:                        Symbols_Free(DspSymbolsList);
                    840:                        DspSymbolsList = NULL;
                    841:                } else {
                    842:                        Symbols_Free(CpuSymbolsList);
                    843:                        CpuSymbolsList = NULL;
                    844:                }
                    845:                return DEBUGGER_CMDDONE;
                    846:        }
1.1.1.5 ! root      847: 
        !           848:        /* get offsets */
        !           849:        offsets[0] = 0;
        !           850:        for (i = 0; i < ARRAYSIZE(offsets); i++) {
        !           851:                if (i+2 < nArgc) {
        !           852:                        int dummy;
        !           853:                        Eval_Expression(psArgs[i+2], &(offsets[i]), &dummy, listtype==TYPE_DSP);
        !           854:                } else {
        !           855:                        /* default to first (text) offset */
        !           856:                        offsets[i] = offsets[0];
        !           857:                }
1.1       root      858:        }
                    859: 
1.1.1.5 ! root      860:        if (strcmp(file, "prg") == 0) {
        !           861:                file = GemDOS_GetLastProgramPath();
        !           862:                if (!file) {
        !           863:                        fprintf(stderr, "ERROR: no program loaded (through GEMDOS HD emu)!\n");
        !           864:                        return DEBUGGER_CMDDONE;
        !           865:                }
        !           866:        }
        !           867:        list = Symbols_Load(file, offsets, maxaddr);
1.1       root      868:        if (list) {
                    869:                if (listtype == TYPE_CPU) {
                    870:                        Symbols_Free(CpuSymbolsList);
                    871:                        CpuSymbolsList = list;
                    872:                } else {
                    873:                        Symbols_Free(DspSymbolsList);
                    874:                        DspSymbolsList = list;
                    875:                }
                    876:        } else {
                    877:                DebugUI_PrintCmdHelp(psArgs[0]);
                    878:        }
                    879:        return DEBUGGER_CMDDONE;
                    880: }

unix.superglobalmegacorp.com

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