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

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.9 ! root     1477:        "<|code|data|name> -- list symbols\n"
        !          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.