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

1.1       root        1: /*
                      2:  * Hatari - symbols.c
                      3:  * 
1.1.1.9   root        4:  * Copyright (C) 2010-2017 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:
1.1.1.9   root       13:  * - A program file's DRI/GST or a.out format symbol table, or
1.1.1.5   root       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.1.9   root       37: #include "a.out.h"
1.1       root       38: 
                     39: typedef struct {
                     40:        char *name;
                     41:        Uint32 address;
                     42:        symtype_t type;
                     43: } symbol_t;
                     44: 
                     45: typedef struct {
1.1.1.5   root       46:        int symbols;            /* initial symbol count */
1.1.1.9   root       47:        int namecount;          /* final symbol count */
                     48:        int codecount;          /* TEXT symbol address count */
                     49:        int datacount;          /* DATA/BSS symbol address count */
                     50:        symbol_t *addresses;    /* TEXT + DATA/BSS items sorted by address */
                     51:        symbol_t *names;        /* all items sorted by symbol name */
                     52:        char *strtab;
1.1       root       53: } symbol_list_t;
                     54: 
1.1.1.5   root       55: typedef struct {
                     56:        Uint32 offset;
                     57:        Uint32 end;
                     58: } prg_section_t;
                     59: 
1.1       root       60: 
                     61: /* how many characters the symbol name can have.
                     62:  * NOTE: change also sscanf width arg if you change this!!!
                     63:  */
                     64: #define MAX_SYM_SIZE 32
                     65: 
1.1.1.9   root       66: /* Magic used to denote different symbol table formats */
                     67: #define SYMBOL_FORMAT_GNU  0x474E555f  /* "MiNT" */
                     68: #define SYMBOL_FORMAT_MINT 0x4D694E54  /* "GNU_" */
                     69: #define SYMBOL_FORMAT_DRI  0x0
                     70: 
1.1       root       71: 
                     72: /* TODO: add symbol name/address file names to configuration? */
                     73: static symbol_list_t *CpuSymbolsList;
                     74: static symbol_list_t *DspSymbolsList;
                     75: 
1.1.1.6   root       76: /* path for last loaded program (through GEMDOS HD emulation) */
                     77: static char *CurrentProgramPath;
1.1.1.9   root       78: /* whether current symbols were loaded from a program file */
1.1.1.6   root       79: static bool SymbolsAreForProgram;
1.1.1.9   root       80: /* prevent repeated failing on every debugger invocation */
1.1.1.6   root       81: static bool AutoLoadFailed;
                     82: 
1.1       root       83: 
                     84: /* ------------------ load and free functions ------------------ */
                     85: 
                     86: /**
1.1.1.9   root       87:  * return true if given symbol name is object/library/file name
                     88:  */
                     89: static bool is_obj_file(const char *name)
                     90: {
                     91:        int len = strlen(name);
                     92:        /* object (.a or .o) / file name? */
                     93:        if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
                     94:                    return true;
                     95:        }
                     96:        return false;
                     97: }
                     98: 
                     99: /**
                    100:  * compare function for qsort() to sort according to
                    101:  * symbol type & address.  Text section symbols will
                    102:  * be sorted first.
1.1       root      103:  */
                    104: static int symbols_by_address(const void *s1, const void *s2)
                    105: {
1.1.1.9   root      106:        const symbol_t *sym1 = (const symbol_t*)s1;
                    107:        const symbol_t *sym2 = (const symbol_t*)s2;
1.1       root      108: 
1.1.1.9   root      109:        /* separate TEXT type addresses from others */
                    110:        if (sym1->type != sym2->type) {
                    111:                if (sym1->type == SYMTYPE_TEXT) {
                    112:                        return -1;
                    113:                }
                    114:                if (sym2->type == SYMTYPE_TEXT) {
                    115:                        return 1;
                    116:                }
                    117:        }
                    118:        /* then sort by address */
                    119:        if (sym1->address < sym2->address) {
1.1       root      120:                return -1;
                    121:        }
1.1.1.9   root      122:        if (sym1->address > sym2->address) {
1.1       root      123:                return 1;
                    124:        }
                    125:        return 0;
                    126: }
                    127: 
                    128: /**
1.1.1.9   root      129:  * compare function for qsort() to sort according to
                    130:  * symbol name & address
1.1       root      131:  */
                    132: static int symbols_by_name(const void *s1, const void *s2)
                    133: {
1.1.1.9   root      134:        const symbol_t *sym1 = (const symbol_t*)s1;
                    135:        const symbol_t *sym2 = (const symbol_t*)s2;
1.1       root      136:        int ret;
                    137: 
1.1.1.9   root      138:        /* first by name */
                    139:        ret = strcmp(sym1->name, sym2->name);
                    140:        if (ret) {
                    141:                return ret;
                    142:        }
                    143:        /* then by address */
                    144:        return (sym1->address - sym2->address);
                    145: }
                    146: 
                    147: /**
                    148:  * Check for duplicate addresses in symbol list
                    149:  * (called separately for TEXT & non-TEXT symbols)
                    150:  * Return number of duplicates
                    151:  */
                    152: static int symbols_check_addresses(const symbol_t *syms, int count)
                    153: {
                    154:        int i, j, dups = 0;
                    155: 
                    156:        for (i = 0; i < (count - 1); i++)
                    157:        {
                    158:                /* absolute symbols have values, not addresses */
                    159:                if (syms[i].type == SYMTYPE_ABS) {
                    160:                        continue;
                    161:                }
                    162:                for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
                    163:                        if (syms[j].type == SYMTYPE_ABS) {
                    164:                                continue;
                    165:                        }
                    166:                        /* ASCII symbol files contain also object file addresses,
                    167:                         * those will often have the same address as the first symbol
                    168:                         * in given object -> no point warning about them
                    169:                         */
                    170:                        if (is_obj_file(syms[i].name) || is_obj_file(syms[j].name)) {
                    171:                                continue;
                    172:                        }
                    173:                        fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address\n",
                    174:                                syms[i].name, syms[j].name, syms[i].address);
                    175:                        dups++;
                    176:                        i = j;
                    177:                }
1.1       root      178:        }
1.1.1.9   root      179:        return dups;
1.1       root      180: }
                    181: 
1.1.1.9   root      182: /**
                    183:  * Check for duplicate names in symbol list
                    184:  * Return number of duplicates
                    185:  */
                    186: static int symbols_check_names(const symbol_t *syms, int count)
                    187: {
                    188:        int i, j, dups = 0;
                    189: 
                    190:        for (i = 0; i < (count - 1); i++)
                    191:        {
                    192:                for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
                    193:                        /* this is common case for object files having different sections */
                    194:                        if (syms[i].type != syms[j].type && is_obj_file(syms[i].name)) {
                    195:                                continue;
                    196:                        }
                    197:                        fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name\n",
                    198:                                syms[i].address, syms[j].address, syms[i].name);
                    199:                        dups++;
                    200:                        i = j;
                    201:                }
                    202:        }
                    203:        return dups;
                    204: }
1.1       root      205: 
                    206: /**
1.1.1.5   root      207:  * Allocate symbol list & names for given number of items.
                    208:  * Return allocated list or NULL on failure.
                    209:  */
                    210: static symbol_list_t* symbol_list_alloc(int symbols)
                    211: {
                    212:        symbol_list_t *list;
                    213: 
                    214:        if (!symbols) {
                    215:                return NULL;
                    216:        }
                    217:        list = calloc(1, sizeof(symbol_list_t));
                    218:        if (list) {
                    219:                list->names = malloc(symbols * sizeof(symbol_t));
                    220:                if (!list->names) {
                    221:                        free(list);
                    222:                        list = NULL;
                    223:                }
                    224:        }
                    225:        return list;
                    226: }
                    227: 
                    228: /**
                    229:  * Free symbol list & names.
                    230:  */
                    231: static void symbol_list_free(symbol_list_t *list)
                    232: {
                    233:        if (list) {
                    234:                if (list->names) {
                    235:                        free(list->names);
                    236:                }
                    237:                free(list);
                    238:        }
                    239: }
                    240: 
                    241: /**
1.1.1.6   root      242:  * Return symbol type identifier char
                    243:  */
                    244: static char symbol_char(int type)
                    245: {
                    246:        switch (type) {
                    247:        case SYMTYPE_TEXT: return 'T';
                    248:        case SYMTYPE_DATA: return 'D';
                    249:        case SYMTYPE_BSS:  return 'B';
1.1.1.9   root      250:        case SYMTYPE_ABS:  return 'A';
1.1.1.6   root      251:        default: return '?';
                    252:        }
                    253: }
                    254: 
1.1.1.9   root      255: /**
                    256:  * Return true if symbol name matches internal GCC symbol name,
                    257:  * or is object / file name.
                    258:  */
                    259: static bool symbol_remove_obj(const char *name)
                    260: {
                    261:        static const char *gcc_sym[] = {
                    262:                "___gnu_compiled_c",
                    263:                "gcc2_compiled."
                    264:        };
                    265:        int i;
                    266: 
                    267:        if (is_obj_file(name)) {
                    268:                return true;
                    269:        }
                    270:        /* useless symbols GCC (v2) seems to add to every object? */
                    271:        for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
                    272:                if (strcmp(name, gcc_sym[i]) == 0) {
                    273:                        return true;
                    274:                }
                    275:        }
                    276:        return false;
                    277: }
                    278: 
1.1.1.6   root      279: 
                    280: /**
1.1       root      281:  * Load symbols of given type and the symbol address addresses from
1.1.1.5   root      282:  * DRI/GST format symbol table, and add given offsets to the addresses:
                    283:  *     http://toshyp.atari.org/en/005005.html
1.1       root      284:  * Return symbols list or NULL for failure.
                    285:  */
1.1.1.5   root      286: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize)
1.1       root      287: {
1.1.1.9   root      288:        int i, count, symbols, invalid;
                    289:        int notypes, dtypes, locals, ofiles;
1.1.1.5   root      290:        prg_section_t *section;
1.1       root      291:        symbol_list_t *list;
                    292:        symtype_t symtype;
1.1.1.5   root      293: #define DRI_ENTRY_SIZE 14
                    294:        char name[23];
                    295:        Uint16 symid;
1.1       root      296:        Uint32 address;
1.1.1.5   root      297: 
1.1.1.6   root      298:        if (tablesize % DRI_ENTRY_SIZE || !tablesize) {
1.1.1.5   root      299:                fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
                    300:                return NULL;
                    301:        }
                    302:        symbols = tablesize / DRI_ENTRY_SIZE;
                    303:        if (!(list = symbol_list_alloc(symbols))) {
                    304:                return NULL;
                    305:        }
                    306: 
1.1.1.9   root      307:        invalid = dtypes = notypes = ofiles = locals = count = 0;
1.1.1.5   root      308:        for (i = 1; i <= symbols; i++) {
                    309:                /* read DRI symbol table slot */
                    310:                if (fread(name, 8, 1, fp) != 1 ||
                    311:                    fread(&symid, sizeof(symid), 1, fp) != 1 ||
                    312:                    fread(&address, sizeof(address), 1, fp) != 1) {
                    313:                        break;
                    314:                }
                    315:                address = SDL_SwapBE32(address);
                    316:                symid = SDL_SwapBE16(symid);
                    317: 
                    318:                /* GST extended DRI symbol format? */
                    319:                if ((symid & 0x0048)) {
                    320:                        /* next slot is rest of name */
                    321:                        i += 1;
                    322:                        if (fread(name+8, 14, 1, fp) != 1) {
                    323:                                break;
                    324:                        }
                    325:                        name[22] = '\0';
                    326:                } else {
                    327:                        name[8] = '\0';
                    328:                }
                    329: 
                    330:                /* check section */
                    331:                switch (symid & 0xf00) {
                    332:                case 0x0200:
                    333:                        symtype = SYMTYPE_TEXT;
                    334:                        section = &(sections[0]);
                    335:                        break;
                    336:                case 0x0400:
                    337:                        symtype = SYMTYPE_DATA;
                    338:                        section = &(sections[1]);
                    339:                        break;
                    340:                case 0x0100:
                    341:                        symtype = SYMTYPE_BSS;
                    342:                        section = &(sections[2]);
                    343:                        break;
                    344:                default:
                    345:                        if ((symid & 0xe000) == 0xe000) {
                    346:                                dtypes++;
                    347:                                continue;
                    348:                        }
1.1.1.9   root      349:                        if ((symid & 0x4000) == 0x4000) {
                    350:                                symtype = SYMTYPE_ABS;
                    351:                                section = NULL;
                    352:                                break;
                    353:                        }
1.1.1.5   root      354:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
1.1.1.9   root      355:                        invalid++;
1.1.1.5   root      356:                        continue;
                    357:                }
                    358:                if (!(gettype & symtype)) {
1.1.1.9   root      359:                        notypes++;
1.1.1.5   root      360:                        continue;
                    361:                }
                    362:                if (name[0] == '.' && name[1] == 'L') {
                    363:                        locals++;
                    364:                        continue;
                    365:                }
1.1.1.9   root      366:                if (symbol_remove_obj(name)) {
1.1.1.5   root      367:                        ofiles++;
                    368:                        continue;
                    369:                }
1.1.1.9   root      370:                if (section) {
                    371:                        address += section->offset;
                    372:                        if (address > section->end) {
                    373:                                fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
                    374:                                        name, symbol_char(symtype), i, address, section->end);
                    375:                                invalid++;
                    376:                                continue;
1.1.1.6   root      377:                        }
1.1.1.5   root      378:                }
                    379:                list->names[count].address = address;
                    380:                list->names[count].type = symtype;
                    381:                list->names[count].name = strdup(name);
                    382:                assert(list->names[count].name);
                    383:                count++;
                    384:        }
                    385:        if (i <= symbols) {
                    386:                perror("ERROR: reading symbol failed");
                    387:                symbol_list_free(list);
1.1       root      388:                return NULL;
                    389:        }
1.1.1.9   root      390:        list->symbols = symbols;
                    391:        list->namecount = count;
                    392: 
                    393:        /* skip verbose output when symbol loading is forced */
                    394:        if (ConfigureParams.Debugger.bSymbolsResident) {
                    395:                return list;
                    396:        }
                    397: 
                    398:        if (invalid) {
                    399:                fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
                    400:        }
1.1.1.5   root      401:        if (dtypes) {
1.1.1.9   root      402:                fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
                    403:        }
                    404:        if (notypes) {
                    405:                fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
1.1.1.5   root      406:        }
                    407:        if (locals) {
                    408:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
                    409:        }
                    410:        if (ofiles) {
                    411:                /* object file path names most likely get truncated and
                    412:                 * as result cause unnecessary symbol name conflicts in
                    413:                 * addition to object file addresses conflicting with
                    414:                 * first symbol in the object file.
                    415:                 */
1.1.1.9   root      416:                fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
                    417:        }
                    418:        return list;
                    419: }
                    420: 
                    421: 
                    422: /**
                    423:  * Load symbols of given type and the symbol address addresses from
                    424:  * a.out format symbol table, and add given offsets to the addresses:
                    425:  * Return symbols list or NULL for failure.
                    426:  */
                    427: static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize, Uint32 stroff, Uint32 strsize)
                    428: {
                    429:        size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
                    430:        size_t i;
                    431:        size_t strx;
                    432:        unsigned char *p;
                    433:        char *name;
                    434:        symbol_t *sym;
                    435:        symtype_t symtype;
                    436:        uint32_t address;
                    437:        uint32_t nread;
                    438:        symbol_list_t *list;
                    439:        unsigned char n_type;
                    440:        unsigned char n_other;
                    441:        unsigned short n_desc;
                    442:        static char dummy[] = "<invalid>";
                    443:        int dtypes, locals, ofiles, count, notypes, invalid, weak;
                    444:        prg_section_t *section;
                    445: 
                    446:        if (!(list = symbol_list_alloc(slots))) {
                    447:                return NULL;
                    448:        }
                    449: 
                    450:        list->strtab = (char *)malloc(tablesize + strsize);
                    451: 
                    452:        if (list->strtab == NULL)
                    453:        {
                    454:                symbol_list_free(list);
                    455:                return NULL;
                    456:        }
                    457: 
                    458:        nread = fread(list->strtab, tablesize + strsize, 1, fp);
                    459:        if (nread != 1)
                    460:        {
                    461:                perror("ERROR: reading symbols failed");
                    462:                symbol_list_free(list);
                    463:                return NULL;
                    464:        }
                    465: 
                    466:        p = (unsigned char *)list->strtab;
                    467:        sym = list->names;
                    468: 
                    469:        weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
                    470:        for (i = 0; i < slots; i++)
                    471:        {
                    472:                strx = SDL_SwapBE32(*(Uint32*)p);
                    473:                p += 4;
                    474:                n_type = *p++;
                    475:                n_other = *p++;
                    476:                n_desc = SDL_SwapBE16(*(Uint16*)p);
                    477:                p += 2;
                    478:                address = SDL_SwapBE32(*(Uint32*)p);
                    479:                p += 4;
                    480:                name = dummy;
                    481:                if (!strx) {
                    482:                        invalid++;
                    483:                        continue;
                    484:                }
                    485:                if (strx >= strsize) {
                    486:                        fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
                    487:                        invalid++;
                    488:                        continue;
                    489:                }
                    490:                name = list->strtab + strx + stroff;
                    491: 
                    492:                if (n_type & N_STAB)
                    493:                {
                    494:                        dtypes++;
                    495:                        continue;
                    496:                }
                    497:                section = NULL;
                    498:                switch (n_type & (N_TYPE|N_EXT))
                    499:                {
                    500:                case N_UNDF:
                    501:                case N_UNDF|N_EXT:
                    502:                        /* shouldn't happen here */
                    503:                        weak++;
                    504:                        continue;
                    505:                case N_ABS:
                    506:                case N_ABS|N_EXT:
                    507:                        symtype = SYMTYPE_ABS;
                    508:                        break;
                    509:                case N_TEXT:
                    510:                case N_TEXT|N_EXT:
                    511:                        symtype = SYMTYPE_TEXT;
                    512:                        section = &(sections[0]);
                    513:                        break;
                    514:                case N_DATA:
                    515:                case N_DATA|N_EXT:
                    516:                        symtype = SYMTYPE_DATA;
                    517:                        section = &(sections[1]);
                    518:                        break;
                    519:                case N_BSS:
                    520:                case N_BSS|N_EXT:
                    521:                case N_COMM:
                    522:                case N_COMM|N_EXT:
                    523:                        symtype = SYMTYPE_BSS;
                    524:                        section = &(sections[2]);
                    525:                        break;
                    526:                case N_FN: /* filenames, not object addresses? */
                    527:                        dtypes++;
                    528:                        continue;
                    529:                case N_SIZE:
                    530:                case N_WARNING:
                    531:                case N_SETA:
                    532:                case N_SETT:
                    533:                case N_SETD:
                    534:                case N_SETB:
                    535:                case N_SETV:
                    536:                        dtypes++;
                    537:                        continue;
                    538:                case N_WEAKU:
                    539:                case N_WEAKT:
                    540:                case N_WEAKD:
                    541:                case N_WEAKB:
                    542:                        weak++;
                    543:                        continue;
                    544:                default:
                    545:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
                    546:                        invalid++;
                    547:                        continue;
                    548:                }
                    549:                /*
                    550:                 * the value of a common symbol is its size, not its address:
                    551:                 */
                    552:                if (((n_type & N_TYPE) == N_COMM) ||
                    553:                        (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
                    554:                {
                    555:                        /* if we ever want to know a symbols size, get that here */
                    556:                        fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i);
                    557:                        dtypes++;
                    558:                        continue;
                    559:                }
                    560:                if (!(gettype & symtype)) {
                    561:                        notypes++;
                    562:                        continue;
                    563:                }
                    564:                if (name[0] == '.' && name[1] == 'L') {
                    565:                        locals++;
                    566:                        continue;
                    567:                }
                    568:                if (symbol_remove_obj(name)) {
                    569:                        ofiles++;
                    570:                        continue;
                    571:                }
                    572:                if (section) {
                    573:                        address += sections[0].offset;  /* all GNU symbol addresses are TEXT relative */
                    574:                        if (address > section->end) {
                    575:                                fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
                    576:                                        name, symbol_char(symtype), (unsigned int)i, address, section->end);
                    577:                                invalid++;
                    578:                                continue;
                    579:                        }
                    580:                }
                    581:                sym->address = address;
                    582:                sym->type = symtype;
                    583:                sym->name = name;
                    584:                sym++;
                    585:                count++;
                    586:                (void) n_desc;
                    587:                (void) n_other;
                    588:        }
                    589:        list->symbols = slots;
                    590:        list->namecount = count;
                    591: 
                    592:        /* skip verbose output when symbol loading is forced */
                    593:        if (ConfigureParams.Debugger.bSymbolsResident) {
                    594:                return list;
                    595:        }
                    596: 
                    597:        if (invalid) {
                    598:                fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
                    599:        }
                    600:        if (dtypes) {
                    601:                fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
                    602:        }
                    603:        if (weak) {
                    604:                fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
                    605:        }
                    606:        if (notypes) {
                    607:                fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
                    608:        }
                    609:        if (locals) {
                    610:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
                    611:        }
                    612:        if (ofiles) {
                    613:                /* object file path names most likely get truncated and
                    614:                 * as result cause unnecessary symbol name conflicts in
                    615:                 * addition to object file addresses conflicting with
                    616:                 * first symbol in the object file.
                    617:                 */
                    618:                fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
1.1.1.5   root      619:        }
                    620:        return list;
                    621: }
                    622: 
1.1.1.7   root      623: 
                    624: /**
                    625:  * Print program header information.
                    626:  * Return false for unrecognized symbol table type.
                    627:  */
                    628: static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
                    629: {
                    630:        static const struct {
                    631:                Uint32 flag;
                    632:                const char *name;
                    633:        } flags[] = {
                    634:                { 0x0001, "FASTLOAD"   },
                    635:                { 0x0002, "TTRAMLOAD"  },
                    636:                { 0x0004, "TTRAMMEM"   },
                    637:                { 0x0008, "MINIMUM"    }, /* MagiC */
                    638:                { 0x1000, "SHAREDTEXT" }
                    639:        };
                    640:        const char *info;
                    641:        int i;
                    642: 
                    643:        switch (tabletype) {
1.1.1.9   root      644:        case SYMBOL_FORMAT_MINT: /* "MiNT" */
1.1.1.7   root      645:                info = "GCC/MiNT executable, GST symbol table";
                    646:                break;
1.1.1.9   root      647:        case SYMBOL_FORMAT_GNU:  /* "GNU_" */
                    648:                info = "GCC/MiNT executable, a.out symbol table";
                    649:                break;
                    650:        case SYMBOL_FORMAT_DRI:
1.1.1.7   root      651:                info = "TOS executable, DRI / GST symbol table";
                    652:                break;
                    653:        default:
                    654:                fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
                    655:                return false;
                    656:        }
                    657:        fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
                    658:        /* bit flags */
1.1.1.8   root      659:        for (i = 0; i < ARRAY_SIZE(flags); i++) {
1.1.1.7   root      660:                if (prgflags & flags[i].flag) {
                    661:                        fprintf(stderr, " %s", flags[i].name);
                    662:                }
                    663:        }
                    664:        /* memory protection flags */
                    665:        switch((prgflags >> 4) & 3) {
                    666:                case 0: info = "PRIVATE";  break;
                    667:                case 1: info = "GLOBAL";   break;
                    668:                case 2: info = "SUPER";    break;
                    669:                case 3: info = "READONLY"; break;
                    670:        }
                    671:        fprintf(stderr, " %s (0x%x)\n", info, prgflags);
                    672:        return true;
                    673: }
                    674: 
1.1.1.5   root      675: /**
                    676:  * Parse program header and use symbol table format specific loader
                    677:  * loader function to load the symbols.
                    678:  * Return symbols list or NULL for failure.
                    679:  */
                    680: static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
                    681: {
1.1.1.6   root      682:        Uint32 textlen, datalen, bsslen, start, tablesize, tabletype, prgflags;
1.1.1.5   root      683:        prg_section_t sections[3];
                    684:        int offset, reads = 0;
1.1.1.6   root      685:        Uint16 relocflag;
                    686:        symbol_list_t* symbols;
1.1.1.9   root      687:        Uint32 symoff = 0;
                    688:        Uint32 stroff = 0;
                    689:        Uint32 strsize = 0;
1.1.1.5   root      690: 
                    691:        /* get TEXT, DATA & BSS section sizes */
1.1.1.6   root      692:        fseek(fp, 2, SEEK_SET);
1.1.1.5   root      693:        reads += fread(&textlen, sizeof(textlen), 1, fp);
                    694:        textlen = SDL_SwapBE32(textlen);
                    695:        reads += fread(&datalen, sizeof(datalen), 1, fp);
                    696:        datalen = SDL_SwapBE32(datalen);
                    697:        reads += fread(&bsslen, sizeof(bsslen), 1, fp);
                    698:        bsslen = SDL_SwapBE32(bsslen);
                    699: 
                    700:        /* get symbol table size & type and check that all reads succeeded */
                    701:        reads += fread(&tablesize, sizeof(tablesize), 1, fp);
                    702:        tablesize = SDL_SwapBE32(tablesize);
                    703:        reads += fread(&tabletype, sizeof(tabletype), 1, fp);
                    704:        tabletype = SDL_SwapBE32(tabletype);
1.1.1.6   root      705: 
                    706:        /* get program header and whether there's reloc table */
                    707:        reads += fread(&prgflags, sizeof(prgflags), 1, fp);
                    708:        prgflags = SDL_SwapBE32(prgflags);
                    709:        reads += fread(&relocflag, sizeof(relocflag), 1, fp);
                    710:        relocflag = SDL_SwapBE32(relocflag);
                    711:        
                    712:        if (reads != 7) {
1.1.1.5   root      713:                fprintf(stderr, "ERROR: program header reading failed!\n");
                    714:                return NULL;
                    715:        }
1.1.1.9   root      716:        /*
                    717:         * check for GNU-style symbol table in aexec header
                    718:         */
                    719:        if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
                    720:                Uint32 magic1, magic2;
                    721:                Uint32 dummy;
                    722:                Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
                    723:                Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
                    724: 
                    725:                reads  = fread(&magic1, sizeof(magic1), 1, fp);
                    726:                magic1 = SDL_SwapBE32(magic1);
                    727:                reads += fread(&magic2, sizeof(magic2), 1, fp);
                    728:                magic2 = SDL_SwapBE32(magic2);
                    729:                if (reads == 2 &&
                    730:                        ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) ||      /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
                    731:                         (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) {     /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
                    732:                        reads += fread(&dummy, sizeof(dummy), 1, fp);   /* skip a_info */
                    733:                        reads += fread(&a_text, sizeof(a_text), 1, fp);
                    734:                        a_text = SDL_SwapBE32(a_text);
                    735:                        reads += fread(&a_data, sizeof(a_data), 1, fp);
                    736:                        a_data = SDL_SwapBE32(a_data);
                    737:                        reads += fread(&a_bss, sizeof(a_bss), 1, fp);
                    738:                        a_bss = SDL_SwapBE32(a_bss);
                    739:                        reads += fread(&a_syms, sizeof(a_syms), 1, fp);
                    740:                        a_syms = SDL_SwapBE32(a_syms);
                    741:                        reads += fread(&a_entry, sizeof(a_entry), 1, fp);
                    742:                        a_entry = SDL_SwapBE32(a_entry);
                    743:                        reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
                    744:                        a_trsize = SDL_SwapBE32(a_trsize);
                    745:                        reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
                    746:                        a_drsize = SDL_SwapBE32(a_drsize);
                    747:                        reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
                    748:                        g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
                    749:                        reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
                    750:                        g_tparel_size = SDL_SwapBE32(g_tparel_size);
                    751:                        reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
                    752:                        g_stkpos = SDL_SwapBE32(g_stkpos);
                    753:                        reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
                    754:                        g_symbol_format = SDL_SwapBE32(g_symbol_format);
                    755:                        if (g_symbol_format == 0)
                    756:                        {
                    757:                                tabletype = SYMBOL_FORMAT_GNU;
                    758:                        }
                    759:                        if ((a_text + (256 - 28)) != textlen)
                    760:                                fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
                    761:                        if (a_data != datalen)
                    762:                                fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
                    763:                        if (a_bss != bsslen)
                    764:                                fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
                    765:                        /*
                    766:                         * the symbol table size in the GEMDOS header includes the string table,
                    767:                         * the symbol table size in the exec header does not.
                    768:                         */
                    769:                        if (tabletype == SYMBOL_FORMAT_GNU)
                    770:                        {
                    771:                                strsize = tablesize - a_syms;
                    772:                                tablesize = a_syms;
                    773:                                stroff = a_syms;
                    774:                        }
                    775: 
                    776:                        textlen = a_text + (256 - 28);
                    777:                        datalen = a_data;
                    778:                        bsslen = a_bss;
                    779:                        symoff = 0x100 + /* sizeof(extended exec header) */
                    780:                                a_text +
                    781:                                a_data +
                    782:                                a_trsize +
                    783:                                a_drsize;
                    784:                }
                    785:        }
1.1.1.7   root      786:        if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
                    787:                return NULL;
                    788:        }
                    789:        if (!tablesize) {
                    790:                fprintf(stderr, "ERROR: symbol table missing from the program!\n");
                    791:                return NULL;
                    792:        }
1.1.1.5   root      793: 
                    794:        /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
                    795:        start = DebugInfo_GetTEXT();
                    796:        if (!start) {
                    797:                fprintf(stderr, "ERROR: no valid program basepage!\n");
                    798:                return NULL;
                    799:        }
                    800:        sections[0].offset = start;
                    801:        sections[0].end = start + textlen;
1.1.1.9   root      802:        if (DebugInfo_GetTEXTEnd() != sections[0].end) {
1.1.1.5   root      803:                fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
                    804:                return NULL;
                    805:        }
                    806: 
                    807:        start = DebugInfo_GetDATA();
1.1.1.6   root      808:        sections[1].offset = start;
1.1.1.9   root      809:        sections[1].end = start + datalen;
1.1.1.5   root      810: 
                    811:        start = DebugInfo_GetBSS();
1.1.1.6   root      812:        sections[2].offset = start;
1.1.1.9   root      813:        sections[2].end = start + bsslen;
1.1.1.5   root      814: 
1.1.1.9   root      815:        if (sections[0].end != sections[1].offset) {
                    816:                fprintf(stderr, "WARNIGN: DATA start doesn't match TEXT start + size!\n");
                    817:        }
                    818:        if (sections[1].end != sections[2].offset) {
                    819:                fprintf(stderr, "WARNIGN: BSS start doesn't match DATA start + size!\n");
1.1.1.6   root      820:        }
                    821: 
1.1.1.9   root      822:        if (tabletype == SYMBOL_FORMAT_GNU) {
                    823:                /* go to start of symbol table */
                    824:                offset = symoff;
                    825:                if (fseek(fp, offset, SEEK_SET) < 0) {
                    826:                        perror("ERROR: seeking to symbol table failed");
                    827:                        return NULL;
                    828:                }
                    829:                fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
                    830:                symbols = symbols_load_gnu(fp, sections, gettype, tablesize, stroff, strsize);
                    831:        } else {
                    832:                /* go to start of symbol table */
                    833:                offset = 0x1C + textlen + datalen;
                    834:                if (fseek(fp, offset, SEEK_SET) < 0) {
                    835:                        perror("ERROR: seeking to symbol table failed");
                    836:                        return NULL;
                    837:                }
                    838:                fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
1.1.1.6   root      839:                symbols = symbols_load_dri(fp, sections, gettype, tablesize);
                    840:        }
                    841:        return symbols;
1.1.1.5   root      842: }
                    843: 
                    844: /**
                    845:  * Load symbols of given type and the symbol address addresses from
                    846:  * the given ASCII file and add given offsets to the addresses.
                    847:  * Return symbols list or NULL for failure.
                    848:  */
                    849: static symbol_list_t* symbols_load_ascii(FILE *fp, Uint32 *offsets, Uint32 maxaddr, symtype_t gettype)
                    850: {
                    851:        symbol_list_t *list;
                    852:        char symchar, buffer[128], name[MAX_SYM_SIZE+1], *buf;
                    853:        int count, line, symbols;
                    854:        Uint32 address, offset;
                    855:        symtype_t symtype;
1.1       root      856: 
                    857:        /* count content lines */
1.1.1.9   root      858:        line = symbols = 0;
1.1       root      859:        while (fgets(buffer, sizeof(buffer), fp)) {
1.1.1.9   root      860:                line++;
                    861: 
1.1.1.3   root      862:                /* skip comments (AHCC SYM file comments start with '*') */
                    863:                if (*buffer == '#' || *buffer == '*') {
1.1       root      864:                        continue;
                    865:                }
                    866:                /* skip empty lines */
1.1.1.6   root      867:                for (buf = buffer; isspace((unsigned char)*buf); buf++);
1.1       root      868:                if (!*buf) {
                    869:                        continue;
                    870:                }
1.1.1.9   root      871:                if (!isxdigit(*buf)) {
                    872:                        fprintf(stderr, "ERROR: line %d doesn't start with an address.\n", line);
                    873:                        return NULL;
                    874:                }
1.1       root      875:                symbols++;
                    876:        }
1.1.1.6   root      877:        if (!symbols) {
                    878:                fprintf(stderr, "ERROR: no symbols.\n");
1.1.1.9   root      879:                return NULL;
1.1.1.6   root      880:        }
                    881: 
1.1       root      882:        fseek(fp, 0, SEEK_SET);
                    883: 
1.1.1.5   root      884:        /* allocate space for symbol list & names */
                    885:        if (!(list = symbol_list_alloc(symbols))) {
1.1       root      886:                return NULL;
                    887:        }
                    888: 
                    889:        /* read symbols */
                    890:        count = 0;
                    891:        for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) {
1.1.1.3   root      892:                /* skip comments (AHCC SYM file comments start with '*') */
                    893:                if (*buffer == '#' || *buffer == '*') {
1.1       root      894:                        continue;
                    895:                }
                    896:                /* skip empty lines */
1.1.1.6   root      897:                for (buf = buffer; isspace((unsigned char)*buf); buf++);
1.1       root      898:                if (!*buf) {
                    899:                        continue;
                    900:                }
                    901:                assert(count < symbols); /* file not modified in meanwhile? */
1.1.1.5   root      902:                if (sscanf(buffer, "%x %c %32[0-9A-Za-z_.-]s", &address, &symchar, name) != 3) {
                    903:                        fprintf(stderr, "WARNING: syntax error on line %d, skipping.\n", line);
1.1       root      904:                        continue;
                    905:                }
1.1.1.6   root      906:                switch (toupper((unsigned char)symchar)) {
1.1.1.5   root      907:                case 'T':
                    908:                        symtype = SYMTYPE_TEXT;
                    909:                        offset = offsets[0];
                    910:                        break;
                    911:                case 'O':       /* AHCC type for _StkSize etc */
                    912:                case 'D':
                    913:                        symtype = SYMTYPE_DATA;
                    914:                        offset = offsets[1];
                    915:                        break;
                    916:                case 'B':
                    917:                        symtype = SYMTYPE_BSS;
                    918:                        offset = offsets[2];
                    919:                        break;
1.1.1.9   root      920:                case 'A':
                    921:                        symtype = SYMTYPE_ABS;
                    922:                        offset = 0;
                    923:                        break;
1.1       root      924:                default:
1.1.1.5   root      925:                        fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d, skipping.\n", symchar, line);
1.1       root      926:                        continue;
                    927:                }
                    928:                if (!(gettype & symtype)) {
                    929:                        continue;
                    930:                }
1.1.1.5   root      931:                address += offset;
                    932:                if (address > maxaddr) {
                    933:                        fprintf(stderr, "WARNING: invalid address 0x%x on line %d, skipping.\n", address, line);
                    934:                        continue;
                    935:                }
1.1       root      936:                list->names[count].address = address;
                    937:                list->names[count].type = symtype;
                    938:                list->names[count].name = strdup(name);
                    939:                assert(list->names[count].name);
                    940:                count++;
                    941:        }
1.1.1.5   root      942:        list->symbols = symbols;
1.1.1.9   root      943:        list->namecount = count;
1.1.1.5   root      944:        return list;
                    945: }
1.1       root      946: 
1.1.1.5   root      947: /**
1.1.1.9   root      948:  * Remove full duplicates from the sorted names list
                    949:  * and trim the allocation to remaining symbols
                    950:  */
                    951: static void symbols_trim_names(symbol_list_t* list)
                    952: {
                    953:        symbol_t *sym = list->names;
                    954:        int i, next, count, dups;
                    955: 
                    956:        count = list->namecount;
                    957:        for (dups = i = 0; i < count - 1; i++) {
                    958:                next = i + 1;
                    959:                if (strcmp(sym[i].name, sym[next].name) == 0 &&
                    960:                    sym[i].address == sym[next].address &&
                    961:                    sym[i].type == sym[next].type) {
                    962:                        /* remove duplicate */
                    963:                        memmove(sym+i, sym+next, (count-next) * sizeof(symbol_t));
                    964:                        count--;
                    965:                        dups++;
                    966:                }
                    967:        }
                    968:        if (dups || list->namecount < list->symbols) {
                    969:                list->names = realloc(list->names, i * sizeof(symbol_t));
                    970:                assert(list->names);
                    971:                list->namecount = i;
                    972:        }
                    973:        if (dups) {
                    974:                fprintf(stderr, "WARNING: removed %d complete symbol duplicates\n", dups);
                    975:        }
                    976: }
                    977: 
                    978: /**
                    979:  * Separate TEXT symbols from other symbols in address list.
                    980:  */
                    981: static void symbols_trim_addresses(symbol_list_t* list)
                    982: {
                    983:        symbol_t *sym = list->addresses;
                    984:        int i;
                    985: 
                    986:        for (i = 0; i < list->namecount; i++) {
                    987:                if (sym[i].type != SYMTYPE_TEXT) {
                    988:                        break;
                    989:                }
                    990:        }
                    991:        list->codecount = i;
                    992:        list->datacount = list->namecount - i;
                    993: }
                    994: 
                    995: /**
1.1.1.5   root      996:  * Load symbols of given type and the symbol address addresses from
                    997:  * the given file and add given offsets to the addresses.
                    998:  * Return symbols list or NULL for failure.
                    999:  */
                   1000: static symbol_list_t* Symbols_Load(const char *filename, Uint32 *offsets, Uint32 maxaddr)
                   1001: {
                   1002:        symbol_list_t *list;
                   1003:        FILE *fp;
                   1004: 
1.1.1.7   root     1005:        if (!File_Exists(filename)) {
                   1006:                fprintf(stderr, "ERROR: file '%s' doesn't exist or isn't readable!\n", filename);
1.1.1.5   root     1007:                return NULL;
                   1008:        }
1.1.1.7   root     1009:        if (Opt_IsAtariProgram(filename)) {
1.1.1.6   root     1010:                const char *last = CurrentProgramPath;
                   1011:                if (!last) {
                   1012:                        /* "pc=text" breakpoint used as point for loading program symbols gives false hits during bootup */
                   1013:                        fprintf(stderr, "WARNING: no program loaded yet (through GEMDOS HD emu)!\n");
                   1014:                } else if (strcmp(last, filename) != 0) {
                   1015:                        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     1016:                }
1.1.1.6   root     1017:                fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
1.1.1.7   root     1018:                fp = fopen(filename, "rb");
1.1.1.5   root     1019:                list = symbols_load_binary(fp, SYMTYPE_ALL);
1.1.1.6   root     1020:                SymbolsAreForProgram = true;
1.1.1.5   root     1021:        } else {
                   1022:                fprintf(stderr, "Reading 'nm' style ASCII symbols from '%s'...\n", filename);
1.1.1.7   root     1023:                fp = fopen(filename, "r");
1.1.1.5   root     1024:                list = symbols_load_ascii(fp, offsets, maxaddr, SYMTYPE_ALL);
1.1.1.6   root     1025:                SymbolsAreForProgram = false;
1.1.1.5   root     1026:        }
                   1027:        fclose(fp);
                   1028: 
                   1029:        if (!list) {
1.1.1.6   root     1030:                fprintf(stderr, "ERROR: reading symbols from '%s' failed!\n", filename);
1.1.1.5   root     1031:                return NULL;
                   1032:        }
                   1033: 
1.1.1.9   root     1034:        if (!list->namecount) {
                   1035:                fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename);
                   1036:                symbol_list_free(list);
                   1037:                return NULL;
1.1       root     1038:        }
                   1039: 
1.1.1.9   root     1040:        /* sort and trim names list */
                   1041:        qsort(list->names, list->namecount, sizeof(symbol_t), symbols_by_name);
                   1042:        symbols_trim_names(list);
                   1043: 
1.1       root     1044:        /* copy name list to address list */
1.1.1.9   root     1045:        list->addresses = malloc(list->namecount * sizeof(symbol_t));
1.1       root     1046:        assert(list->addresses);
1.1.1.9   root     1047:        memcpy(list->addresses, list->names, list->namecount * sizeof(symbol_t));
1.1       root     1048: 
1.1.1.9   root     1049:        /* sort address list and trim to contain just TEXT symbols */
                   1050:        qsort(list->addresses, list->namecount, sizeof(symbol_t), symbols_by_address);
                   1051:        symbols_trim_addresses(list);
1.1       root     1052: 
1.1.1.9   root     1053:        /* skip verbose output when symbol loading is forced */
                   1054:        if (!ConfigureParams.Debugger.bSymbolsResident) {
                   1055:                /* check for duplicate names */
                   1056:                if (symbols_check_names(list->names, list->namecount)) {
                   1057:                        fprintf(stderr, "-> Hatari symbol expansion can match only one of the addresses for name duplicates!\n");
                   1058:                }
                   1059:                /* check for duplicate TEXT & other addresses */
                   1060:                if (symbols_check_addresses(list->addresses, list->codecount)) {
                   1061:                        fprintf(stderr, "-> Hatari profile/dissassembly will show only one of the TEXT symbols for given address!\n");
                   1062:                }
                   1063:                if (symbols_check_addresses(list->addresses + list->codecount, list->datacount)) {
                   1064:                        fprintf(stderr, "-> Hatari dissassembly will show only one of the symbols for given address!\n");
                   1065:                }
                   1066:        }
                   1067: 
                   1068:        fprintf(stderr, "Loaded %d symbols (%d TEXT) from '%s'.\n",
                   1069:                list->namecount, list->codecount, filename);
1.1       root     1070:        return list;
                   1071: }
                   1072: 
                   1073: 
                   1074: /**
                   1075:  * Free read symbols.
                   1076:  */
                   1077: static void Symbols_Free(symbol_list_t* list)
                   1078: {
1.1.1.5   root     1079:        int i;
1.1       root     1080: 
                   1081:        if (!list) {
                   1082:                return;
                   1083:        }
1.1.1.9   root     1084:        assert(list->namecount);
                   1085:        if (list->strtab) {
                   1086:                free(list->strtab);
                   1087:                list->strtab = NULL;
                   1088:        } else {
                   1089:                for (i = 0; i < list->namecount; i++) {
                   1090:                        free(list->names[i].name);
                   1091:                }
1.1       root     1092:        }
                   1093:        free(list->addresses);
                   1094:        free(list->names);
1.1.1.5   root     1095: 
                   1096:        /* catch use of freed list */
                   1097:        list->addresses = NULL;
1.1.1.9   root     1098:        list->codecount = 0;
                   1099:        list->datacount = 0;
1.1.1.5   root     1100:        list->names = NULL;
1.1.1.9   root     1101:        list->namecount = 0;
1.1       root     1102:        free(list);
                   1103: }
                   1104: 
                   1105: 
                   1106: /* ---------------- symbol name completion support ------------------ */
                   1107: 
                   1108: /**
                   1109:  * Helper for symbol name completion and finding their addresses.
                   1110:  * STATE = 0 -> different text from previous one.
                   1111:  * Return (copy of) next name or NULL if no matches.
                   1112:  */
                   1113: static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state)
                   1114: {
1.1.1.5   root     1115:        static int i, len;
1.1       root     1116:        const symbol_t *entry;
                   1117:        
                   1118:        if (!list) {
                   1119:                return NULL;
                   1120:        }
                   1121: 
                   1122:        if (!state) {
                   1123:                /* first match */
                   1124:                len = strlen(text);
                   1125:                i = 0;
                   1126:        }
                   1127: 
                   1128:        /* next match */
                   1129:        entry = list->names;
1.1.1.9   root     1130:        while (i < list->namecount) {
1.1       root     1131:                if ((entry[i].type & symtype) &&
                   1132:                    strncmp(entry[i].name, text, len) == 0) {
                   1133:                        return strdup(entry[i++].name);
                   1134:                } else {
                   1135:                        i++;
                   1136:                }
                   1137:        }
                   1138:        return NULL;
                   1139: }
                   1140: 
                   1141: /**
                   1142:  * Readline match callbacks for CPU symbol name completion.
                   1143:  * STATE = 0 -> different text from previous one.
                   1144:  * Return next match or NULL if no matches.
                   1145:  */
                   1146: char* Symbols_MatchCpuAddress(const char *text, int state)
                   1147: {
                   1148:        return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
                   1149: }
                   1150: char* Symbols_MatchCpuCodeAddress(const char *text, int state)
                   1151: {
1.1.1.9   root     1152:        if (ConfigureParams.Debugger.bMatchAllSymbols) {
                   1153:                return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
                   1154:        } else {
                   1155:                return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_TEXT, text, state);
                   1156:        }
1.1       root     1157: }
                   1158: char* Symbols_MatchCpuDataAddress(const char *text, int state)
                   1159: {
1.1.1.9   root     1160:        if (ConfigureParams.Debugger.bMatchAllSymbols) {
                   1161:                return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
                   1162:        } else {
                   1163:                return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
                   1164:        }
1.1       root     1165: }
                   1166: 
                   1167: /**
                   1168:  * Readline match callback for DSP symbol name completion.
                   1169:  * STATE = 0 -> different text from previous one.
                   1170:  * Return next match or NULL if no matches.
                   1171:  */
                   1172: char* Symbols_MatchDspAddress(const char *text, int state)
                   1173: {
                   1174:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state);
                   1175: }
                   1176: char* Symbols_MatchDspCodeAddress(const char *text, int state)
                   1177: {
                   1178:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_TEXT, text, state);
                   1179: }
                   1180: char* Symbols_MatchDspDataAddress(const char *text, int state)
                   1181: {
                   1182:        return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
                   1183: }
                   1184: 
                   1185: 
                   1186: /* ---------------- symbol name -> address search ------------------ */
                   1187: 
                   1188: /**
1.1.1.9   root     1189:  * Binary search symbol of given type by name.
1.1       root     1190:  * Return symbol if name matches, zero otherwise.
                   1191:  */
1.1.1.9   root     1192: static const symbol_t* Symbols_SearchByName(symbol_t* entries, int count, symtype_t symtype, const char *name)
1.1       root     1193: {
                   1194:        /* left, right, middle */
                   1195:         int l, r, m, dir;
                   1196: 
                   1197:        /* bisect */
                   1198:        l = 0;
1.1.1.9   root     1199:        r = count - 1;
1.1       root     1200:        do {
                   1201:                m = (l+r) >> 1;
                   1202:                dir = strcmp(entries[m].name, name);
                   1203:                if (dir == 0 && (entries[m].type & symtype)) {
                   1204:                        return &(entries[m]);
                   1205:                }
                   1206:                if (dir > 0) {
                   1207:                        r = m-1;
                   1208:                } else {
                   1209:                        l = m+1;
                   1210:                }
                   1211:        } while (l <= r);
                   1212:        return NULL;
                   1213: }
                   1214: 
                   1215: /**
1.1.1.9   root     1216:  * Set given symbol's address to variable and return true if one
                   1217:  * was found from given list.
1.1       root     1218:  */
1.1.1.9   root     1219: static bool Symbols_GetAddress(symbol_list_t* list, symtype_t symtype, const char *name, Uint32 *addr)
1.1       root     1220: {
                   1221:        const symbol_t *entry;
1.1.1.9   root     1222:        if (!(list && list->names)) {
                   1223:                return false;
                   1224:        }
                   1225:        entry = Symbols_SearchByName(list->names, list->namecount, symtype, name);
1.1       root     1226:        if (entry) {
                   1227:                *addr = entry->address;
                   1228:                return true;
                   1229:        }
                   1230:        return false;
                   1231: }
1.1.1.9   root     1232: bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, Uint32 *addr)
                   1233: {
                   1234:        return Symbols_GetAddress(CpuSymbolsList, symtype, name, addr);
                   1235: }
1.1       root     1236: bool Symbols_GetDspAddress(symtype_t symtype, const char *name, Uint32 *addr)
                   1237: {
1.1.1.9   root     1238:        return Symbols_GetAddress(DspSymbolsList, symtype, name, addr);
1.1       root     1239: }
                   1240: 
                   1241: 
                   1242: /* ---------------- symbol address -> name search ------------------ */
                   1243: 
                   1244: /**
1.1.1.9   root     1245:  * Binary search symbol by address in given sorted list.
1.1.1.5   root     1246:  * Return symbol index if address matches, -1 otherwise.
1.1       root     1247:  */
1.1.1.9   root     1248: static int Symbols_SearchByAddress(symbol_t* entries, int count, Uint32 addr)
1.1       root     1249: {
                   1250:        /* left, right, middle */
                   1251:         int l, r, m;
                   1252:        Uint32 curr;
                   1253: 
                   1254:        /* bisect */
                   1255:        l = 0;
1.1.1.9   root     1256:        r = count - 1;
1.1       root     1257:        do {
                   1258:                m = (l+r) >> 1;
                   1259:                curr = entries[m].address;
                   1260:                if (curr == addr) {
1.1.1.5   root     1261:                        return m;
1.1       root     1262:                }
                   1263:                if (curr > addr) {
                   1264:                        r = m-1;
                   1265:                } else {
                   1266:                        l = m+1;
                   1267:                }
                   1268:        } while (l <= r);
1.1.1.5   root     1269:        return -1;
1.1       root     1270: }
                   1271: 
                   1272: /**
1.1.1.9   root     1273:  * Search symbol in given list by type & address.
                   1274:  * Return symbol name if there's a match, NULL otherwise.
                   1275:  * TEXT symbols will be matched before other symbol types.
1.1       root     1276:  * Returned name is valid only until next Symbols_* function call.
                   1277:  */
1.1.1.9   root     1278: static const char* Symbols_GetByAddress(symbol_list_t* list, Uint32 addr, symtype_t type)
1.1       root     1279: {
1.1.1.9   root     1280:        if (!(list && list->addresses)) {
1.1.1.5   root     1281:                return NULL;
                   1282:        }
1.1.1.9   root     1283:        if (type & SYMTYPE_TEXT) {
                   1284:                int i = Symbols_SearchByAddress(list->addresses, list->codecount, addr);
                   1285:                if (i >= 0) {
                   1286:                        return list->addresses[i].name;
                   1287:                }
                   1288:        }
                   1289:        if (type & ~SYMTYPE_TEXT) {
                   1290:                int i = Symbols_SearchByAddress(list->addresses + list->codecount, list->datacount, addr);
                   1291:                if (i >= 0) {
                   1292:                        return list->addresses[list->codecount + i].name;
                   1293:                }
                   1294:        }
                   1295:        return NULL;
1.1       root     1296: }
1.1.1.9   root     1297: const char* Symbols_GetByCpuAddress(Uint32 addr, symtype_t type)
1.1       root     1298: {
1.1.1.9   root     1299:        return Symbols_GetByAddress(CpuSymbolsList, addr, type);
1.1.1.5   root     1300: }
1.1.1.9   root     1301: const char* Symbols_GetByDspAddress(Uint32 addr, symtype_t type)
1.1.1.5   root     1302: {
1.1.1.9   root     1303:        return Symbols_GetByAddress(DspSymbolsList, addr, type);
1.1.1.5   root     1304: }
                   1305: 
                   1306: /**
1.1.1.9   root     1307:  * Search given list for TEXT symbol by address.
1.1.1.5   root     1308:  * Return symbol index if address matches, -1 otherwise.
                   1309:  */
1.1.1.9   root     1310: static int Symbols_GetCodeIndex(symbol_list_t* list, Uint32 addr)
                   1311: {
                   1312:        if (!list) {
                   1313:                return -1;
                   1314:        }
                   1315:        return Symbols_SearchByAddress(list->addresses, list->codecount, addr);
                   1316: }
                   1317: int Symbols_GetCpuCodeIndex(Uint32 addr)
                   1318: {
                   1319:        return Symbols_GetCodeIndex(CpuSymbolsList, addr);
                   1320: }
                   1321: int Symbols_GetDspCodeIndex(Uint32 addr)
1.1.1.5   root     1322: {
1.1.1.9   root     1323:        return Symbols_GetCodeIndex(DspSymbolsList, addr);
1.1       root     1324: }
                   1325: 
1.1.1.5   root     1326: /**
1.1.1.9   root     1327:  * Return how many TEXT symbols are loaded/available
1.1.1.5   root     1328:  */
1.1.1.9   root     1329: int Symbols_CpuCodeCount(void)
1.1.1.5   root     1330: {
1.1.1.9   root     1331:        return (CpuSymbolsList ? CpuSymbolsList->codecount : 0);
1.1.1.5   root     1332: }
1.1.1.9   root     1333: int Symbols_DspCodeCount(void)
1.1.1.5   root     1334: {
1.1.1.9   root     1335:        return (DspSymbolsList ? DspSymbolsList->codecount : 0);
1.1.1.5   root     1336: }
1.1       root     1337: 
1.1.1.6   root     1338: /* ---------------- symbol showing ------------------ */
1.1       root     1339: 
                   1340: /**
                   1341:  * Show symbols from given list with paging.
                   1342:  */
1.1.1.9   root     1343: static void Symbols_Show(symbol_list_t* list, const char *sortcmd)
1.1       root     1344: {
                   1345:        symbol_t *entry, *entries;
1.1.1.9   root     1346:        const char *symtype, *sorttype;
                   1347:        int i, rows, count;
1.1       root     1348:        char symchar;
1.1.1.9   root     1349:        char line[80];
1.1       root     1350:        
                   1351:        if (!list) {
                   1352:                fprintf(stderr, "No symbols!\n");
                   1353:                return;
                   1354:        }
                   1355: 
1.1.1.9   root     1356:        if (strcmp("code", sortcmd) == 0) {
                   1357:                sorttype = "address";
1.1       root     1358:                entries = list->addresses;
1.1.1.9   root     1359:                count = list->codecount;
                   1360:                symtype = " TEXT";
                   1361:        } else if (strcmp("data", sortcmd) == 0) {
                   1362:                sorttype = "address";
                   1363:                entries = list->addresses + list->codecount;
                   1364:                count = list->datacount;
                   1365:                symtype = " DATA/BSS/ABS";
1.1       root     1366:        } else {
1.1.1.9   root     1367:                sorttype = "name";
1.1       root     1368:                entries = list->names;
1.1.1.9   root     1369:                count = list->namecount;
                   1370:                symtype = "";
1.1       root     1371:        }
1.1.1.9   root     1372:        rows = DebugUI_GetPageLines(ConfigureParams.Debugger.nSymbolLines, 20);
1.1       root     1373: 
1.1.1.9   root     1374:        for (entry = entries, i = 0; i < count; i++, entry++) {
1.1.1.6   root     1375:                symchar = symbol_char(entry->type);
1.1       root     1376:                fprintf(stderr, "0x%08x %c %s\n",
                   1377:                        entry->address, symchar, entry->name);
1.1.1.9   root     1378:                if ((i + 1) % rows == 0) {
1.1       root     1379:                        fprintf(stderr, "--- q to exit listing, just enter to continue --- ");
1.1.1.9   root     1380:                        if (fgets(line, sizeof(line), stdin) == NULL ||
                   1381:                                toupper(line[0]) == 'Q') {
                   1382:                                break;
1.1       root     1383:                        }
                   1384:                }
                   1385:        }
1.1.1.9   root     1386:        fprintf(stderr, "%d %s%s symbols (of %d) sorted by %s.\n", i,
                   1387:                (list == CpuSymbolsList ? "CPU" : "DSP"),
                   1388:                symtype, count, sorttype);
1.1       root     1389: }
                   1390: 
1.1.1.6   root     1391: /* ---------------- binary load handling ------------------ */
                   1392: 
                   1393: /**
1.1.1.9   root     1394:  * If symbols are set resident, load them if they aren't yet loaded,
                   1395:  * otherwise remove them along with program path.
                   1396:  *
                   1397:  * Called on GEMDOS reset and when program terminates
                   1398:  * (unless terminated with Ptermres()).
1.1.1.6   root     1399:  */
                   1400: void Symbols_RemoveCurrentProgram(void)
                   1401: {
                   1402:        if (CurrentProgramPath) {
1.1.1.9   root     1403:                if (ConfigureParams.Debugger.bSymbolsResident) {
                   1404:                        Symbols_LoadCurrentProgram();
                   1405:                }
1.1.1.6   root     1406:                free(CurrentProgramPath);
                   1407:                CurrentProgramPath = NULL;
                   1408: 
1.1.1.9   root     1409:                if (CpuSymbolsList && SymbolsAreForProgram && !ConfigureParams.Debugger.bSymbolsResident) {
1.1.1.6   root     1410:                        Symbols_Free(CpuSymbolsList);
1.1.1.9   root     1411:                        fprintf(stderr, "Program exit, removing its symbols.\n");
1.1.1.6   root     1412:                        CpuSymbolsList = NULL;
                   1413:                }
                   1414:        }
                   1415:        AutoLoadFailed = false;
                   1416: }
                   1417: 
                   1418: /**
1.1.1.9   root     1419:  * Set last opened program path and remove symbols if they
                   1420:  * didn't get remove beforehand.
                   1421:  *
                   1422:  * Called on first Fopen() after Pexec().
1.1.1.6   root     1423:  */
1.1.1.7   root     1424: void Symbols_ChangeCurrentProgram(const char *path)
1.1.1.6   root     1425: {
1.1.1.7   root     1426:        if (Opt_IsAtariProgram(path)) {
1.1.1.9   root     1427:                if (ConfigureParams.Debugger.bSymbolsResident) {
                   1428:                        if (CpuSymbolsList && SymbolsAreForProgram) {
                   1429:                                Symbols_Free(CpuSymbolsList);
                   1430:                                fprintf(stderr, "Program launch, removing previous program symbols.\n");
                   1431:                                CpuSymbolsList = NULL;
                   1432:                        }
                   1433:                        if (CurrentProgramPath) {
                   1434:                                free(CurrentProgramPath);
                   1435:                        }
                   1436:                } else {
                   1437:                        Symbols_RemoveCurrentProgram();
                   1438:                }
1.1.1.6   root     1439:                CurrentProgramPath = strdup(path);
                   1440:        }
                   1441: }
                   1442: 
                   1443: /**
                   1444:  * Load symbols for last opened program.
1.1.1.9   root     1445:  * Called when debugger is invoked.
1.1.1.6   root     1446:  */
                   1447: void Symbols_LoadCurrentProgram(void)
                   1448: {
                   1449:        /* symbols already loaded, program path missing or previous load failed? */
                   1450:        if (CpuSymbolsList || !CurrentProgramPath || AutoLoadFailed) {
                   1451:                return;
                   1452:        }
                   1453:        CpuSymbolsList = Symbols_Load(CurrentProgramPath, NULL, 0);
                   1454:        if (!CpuSymbolsList) {
                   1455:                AutoLoadFailed = true;
                   1456:        } else {
                   1457:                AutoLoadFailed = false;
                   1458:        }
                   1459: }
                   1460: 
                   1461: /* ---------------- command parsing ------------------ */
                   1462: 
                   1463: /**
                   1464:  * Readline match callback to list symbols subcommands.
                   1465:  * STATE = 0 -> different text from previous one.
                   1466:  * Return next match or NULL if no matches.
                   1467:  */
                   1468: char *Symbols_MatchCommand(const char *text, int state)
                   1469: {
                   1470:        static const char* subs[] = {
1.1.1.9   root     1471:                "code", "data", "free", "match", "name", "prg", "resident"
1.1.1.6   root     1472:        };
1.1.1.8   root     1473:        return DebugUI_MatchHelper(subs, ARRAY_SIZE(subs), text, state);
1.1.1.6   root     1474: }
                   1475: 
1.1       root     1476: const char Symbols_Description[] =
1.1.1.10! root     1477:        "<code|data|name> -- list symbols\n"
1.1.1.9   root     1478:        "\tsymbols <prg|free> -- load/free symbols\n"
                   1479:        "\tsymbols <filename> [<T offset> [<D offset> <B offset>]]\n"
                   1480:        "\tsymbols <resident|match> -- toggle symbol options\n"
1.1.1.5   root     1481:        "\n"
1.1.1.9   root     1482:        "\t'name' command lists the currently loaded symbols, sorted by name.\n"
                   1483:        "\t'code' and 'data' commands list them sorted by address; 'code' lists\n"
                   1484:        "\tonly TEXT symbols, 'data' lists DATA/BSS/ABS symbols.\n"
1.1.1.5   root     1485:        "\n"
1.1.1.9   root     1486:        "\tBy default, symbols are loaded from the currently executing program's\n"
                   1487:        "\tbinary when entering the debugger, IF program is started through\n"
                   1488:        "\tGEMDOS HD, and they're freed when that program terminates.\n"
1.1.1.5   root     1489:        "\n"
1.1.1.9   root     1490:        "\tThat corresponds to 'prg' command which loads (DRI/GST or a.out\n"
                   1491:        "\tformat) symbol table from the last program executed through\n"
                   1492:        "\tthe GEMDOS HD emulation.\n"
                   1493:        "\n"
                   1494:        "\t'free' command removes the loaded symbols.\n"
                   1495:        "\n"
                   1496:        "\tIf program lacks symbols, or it's not run through the GEMDOS HD\n"
                   1497:        "\temulation, user can ask symbols to be loaded from a file that's\n"
                   1498:        "\tan unstripped version of the binary. Or from an ASCII symbols file\n"
                   1499:        "\tproduced by the 'nm' and (Hatari) 'gst2ascii' tools.\n"
                   1500:        "\n"
                   1501:        "\tWith ASCII symbols files, given non-zero offset(s) are added to\n"
                   1502:        "\tthe text (T), data (D) and BSS (B) symbols.  Typically one uses\n"
                   1503:        "\tTEXT variable, sometimes also DATA & BSS, variables for this.\n"
                   1504:        "\n"
                   1505:        "\t'resident' command toggles whether debugger will load symbols\n"
                   1506:        "\tbefore program terminates (if user hasn't entered debugger before\n"
                   1507:        "\tthis), and defers symbol freeing until another program is started.\n"
                   1508:        "\n"
                   1509:        "\t'match' command toggles whether TAB completion matches all symbols,\n"
                   1510:        "\tor only symbol types that should be relevant for given command.";
                   1511: 
1.1       root     1512: 
                   1513: /**
                   1514:  * Handle debugger 'symbols' command and its arguments
                   1515:  */
                   1516: int Symbols_Command(int nArgc, char *psArgs[])
                   1517: {
1.1.1.9   root     1518:        enum { TYPE_CPU, TYPE_DSP } listtype;
1.1.1.5   root     1519:        Uint32 offsets[3], maxaddr;
1.1       root     1520:        symbol_list_t *list;
                   1521:        const char *file;
1.1.1.5   root     1522:        int i;
1.1       root     1523: 
                   1524:        if (strcmp("dspsymbols", psArgs[0]) == 0) {
                   1525:                listtype = TYPE_DSP;
                   1526:                maxaddr = 0xFFFF;
1.1.1.9   root     1527:        } else {
1.1       root     1528:                listtype = TYPE_CPU;
1.1.1.7   root     1529:                if ( ConfigureParams.System.bAddressSpace24 )
                   1530:                        maxaddr = 0x00FFFFFF;
                   1531:                else
                   1532:                        maxaddr = 0xFFFFFFFF;
1.1.1.9   root     1533:        }
                   1534:        if (nArgc < 2) {
                   1535:                file = "name";
1.1       root     1536:        } else {
1.1.1.9   root     1537:                file = psArgs[1];
1.1       root     1538:        }
1.1.1.9   root     1539: 
                   1540:        /* toggle whether to autoload symbols on program start,
                   1541:         * and keep them until next program start (=resident),
                   1542:         * OR only loading them when entering the debugger and
                   1543:         * freeing them when program terminates.
                   1544:         */
                   1545:        if (strcmp(file, "resident") == 0) {
                   1546:                ConfigureParams.Debugger.bSymbolsResident = !ConfigureParams.Debugger.bSymbolsResident;
                   1547:                if (ConfigureParams.Debugger.bSymbolsResident) {
                   1548:                        Symbols_LoadCurrentProgram();
                   1549:                        fprintf(stderr, "Program symbols will always be loaded (with reduced warnings)\nand kept resident until next program start.\n");
                   1550:                } else {
                   1551:                        fprintf(stderr, "Program symbols will be removed when program terminates.\n");
                   1552:                        if (!CurrentProgramPath) {
                   1553:                                /* make sure normal autoloading isn't prevented */
                   1554:                                Symbols_Free(CpuSymbolsList);
                   1555:                                CpuSymbolsList = NULL;
                   1556:                        }
                   1557:                }
                   1558:                return DEBUGGER_CMDDONE;
                   1559:        }
                   1560:        /* toggling whether all or only specific symbols types get TAB completed */
                   1561:        if (strcmp(file, "match") == 0) {
                   1562:                ConfigureParams.Debugger.bMatchAllSymbols = !ConfigureParams.Debugger.bMatchAllSymbols;
                   1563:                if (ConfigureParams.Debugger.bMatchAllSymbols) {
                   1564:                        fprintf(stderr, "Matching all symbols types.\n");
                   1565:                } else {
                   1566:                        fprintf(stderr, "Matching only symbols (most) relevant for given command.\n");
                   1567:                }
                   1568:                return DEBUGGER_CMDDONE;
1.1       root     1569:        }
                   1570: 
                   1571:        /* handle special cases */
1.1.1.9   root     1572:        if (strcmp(file, "name") == 0 || strcmp(file, "code") == 0 || strcmp(file, "data") == 0) {
1.1       root     1573:                list = (listtype == TYPE_DSP ? DspSymbolsList : CpuSymbolsList);
                   1574:                Symbols_Show(list, file);
                   1575:                return DEBUGGER_CMDDONE;
                   1576:        }
                   1577:        if (strcmp(file, "free") == 0) {
                   1578:                if (listtype == TYPE_DSP) {
                   1579:                        Symbols_Free(DspSymbolsList);
                   1580:                        DspSymbolsList = NULL;
                   1581:                } else {
                   1582:                        Symbols_Free(CpuSymbolsList);
                   1583:                        CpuSymbolsList = NULL;
                   1584:                }
                   1585:                return DEBUGGER_CMDDONE;
                   1586:        }
1.1.1.5   root     1587: 
                   1588:        /* get offsets */
                   1589:        offsets[0] = 0;
1.1.1.8   root     1590:        for (i = 0; i < ARRAY_SIZE(offsets); i++) {
1.1.1.5   root     1591:                if (i+2 < nArgc) {
                   1592:                        int dummy;
                   1593:                        Eval_Expression(psArgs[i+2], &(offsets[i]), &dummy, listtype==TYPE_DSP);
                   1594:                } else {
                   1595:                        /* default to first (text) offset */
                   1596:                        offsets[i] = offsets[0];
                   1597:                }
1.1       root     1598:        }
                   1599: 
1.1.1.5   root     1600:        if (strcmp(file, "prg") == 0) {
1.1.1.6   root     1601:                file = CurrentProgramPath;
1.1.1.5   root     1602:                if (!file) {
                   1603:                        fprintf(stderr, "ERROR: no program loaded (through GEMDOS HD emu)!\n");
                   1604:                        return DEBUGGER_CMDDONE;
                   1605:                }
                   1606:        }
                   1607:        list = Symbols_Load(file, offsets, maxaddr);
1.1       root     1608:        if (list) {
                   1609:                if (listtype == TYPE_CPU) {
                   1610:                        Symbols_Free(CpuSymbolsList);
                   1611:                        CpuSymbolsList = list;
                   1612:                } else {
                   1613:                        Symbols_Free(DspSymbolsList);
                   1614:                        DspSymbolsList = list;
                   1615:                }
                   1616:        } else {
                   1617:                DebugUI_PrintCmdHelp(psArgs[0]);
                   1618:        }
                   1619:        return DEBUGGER_CMDDONE;
                   1620: }

unix.superglobalmegacorp.com

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