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

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

unix.superglobalmegacorp.com

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