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

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

unix.superglobalmegacorp.com

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