Annotation of hatari/tools/debugger/gst2ascii.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * Hatari - gst2ascii.c
                      3:  * 
1.1.1.5 ! root        4:  * Copyright (C) 2013-2017 by Eero Tamminen
1.1       root        5:  * 
                      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.
                      8:  * 
1.1.1.5 ! root        9:  * Convert DRI/GST and a.out format symbol table in a binary into ASCII symbols
        !            10:  * file accepted by Hatari debugger and its profiler data post-processor.
        !            11:  * This will also allow manual editing of the symbol table (removing irrelevant
        !            12:  * labels or adding missing symbols for functions).
1.1       root       13:  */
                     14: 
                     15: #include <ctype.h>
                     16: #include <stdio.h>
                     17: #include <string.h>
                     18: #include <stdlib.h>
                     19: #include <stdint.h>
                     20: #include <stdbool.h>
                     21: #if defined(__MINT__)  /* assume MiNT/lib is always big-endian */
                     22: # define SDL_SwapBE16(x) x
                     23: # define SDL_SwapBE32(x) x
                     24: #else
                     25: # include <SDL_endian.h>
                     26: #endif
                     27: #include <assert.h>
1.1.1.5 ! root       28: #include "../../src/debug/a.out.h"
1.1       root       29: 
                     30: typedef enum {
                     31:        SYMTYPE_TEXT = 1,
                     32:        SYMTYPE_DATA = 2,
1.1.1.5 ! root       33:        SYMTYPE_BSS  = 4,
        !            34:        SYMTYPE_ABS  = 8
1.1       root       35: } symtype_t;
                     36: 
                     37: typedef struct {
                     38:        char *name;
                     39:        uint32_t address;
                     40:        symtype_t type;
                     41: } symbol_t;
                     42: 
                     43: typedef struct {
                     44:        int count;              /* final symbol count */
                     45:        int symbols;            /* initial symbol count */
                     46:        symbol_t *addresses;    /* items sorted by address */
                     47:        symbol_t *names;        /* items sorted by symbol name */
1.1.1.5 ! root       48:        char *strtab;
1.1       root       49: } symbol_list_t;
                     50: 
                     51: typedef struct {
                     52:        uint32_t offset;
                     53:        uint32_t end;
                     54: } prg_section_t;
                     55: 
1.1.1.5 ! root       56: /* Magic used to denote different symbol table formats */
        !            57: #define SYMBOL_FORMAT_GNU  0x474E555f  /* "MiNT" */
        !            58: #define SYMBOL_FORMAT_MINT 0x4D694E54  /* "GNU_" */
        !            59: #define SYMBOL_FORMAT_DRI  0x0
        !            60: 
        !            61: /* Magic identifying Atari programs */
        !            62: #define ATARI_PROGRAM_MAGIC 0x601A
        !            63: 
        !            64: 
1.1       root       65: /* ------------------ options & usage ------------------ */
                     66: 
                     67: #ifdef WIN32
                     68: #define PATHSEP '\\'
                     69: #else
                     70: #define PATHSEP '/'
                     71: #endif
                     72: 
1.1.1.4   root       73: #define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
1.1       root       74: 
                     75: static const char *PrgPath;
                     76: 
                     77: static struct {
                     78:        symtype_t notypes;
                     79:        bool no_local;
1.1.1.5 ! root       80:        bool no_obj;
1.1       root       81:        bool sort_name;
                     82: } Options;
                     83: 
                     84: /*
1.1.1.5 ! root       85:  * Show program usage, given error message, and exit
1.1       root       86:  */
1.1.1.5 ! root       87: static void usage(const char *msg)
1.1       root       88: {
                     89:        const struct {
                     90:                const char opt;
                     91:                const char *desc;
                     92:        } OptInfo[] = {
1.1.1.5 ! root       93:                { 'a', "no absolute symbols (are values, not addresses)" },
1.1       root       94:                { 'b', "no BSS symbols" },
                     95:                { 'd', "no DATA symbols" },
                     96:                { 't', "no TEXT symbols" },
                     97:                { 'l', "no local (.L*) symbols" },
                     98:                { 'o', "no object symbols (filenames or GCC internals)" },
1.1.1.5 ! root       99:                { 'n', "sort by name (not address)" },
1.1       root      100:        };
                    101:        const char *name;
                    102:        int i;
                    103: 
                    104:        if ((name = strrchr(PrgPath, PATHSEP))) {
                    105:                name++;
                    106:        } else {
                    107:                name = PrgPath;
                    108:        }
                    109:        fprintf(stderr,
                    110:                "\n"
                    111:                "Usage: %s [options] <Atari program>\n"
                    112:                "\n"
1.1.1.5 ! root      113:                "Outputs given program (DRI/GST or a.out format) symbol table\n"
        !           114:                "content in ASCII format accepted by Hatari debugger and its\n"
        !           115:                "profiler data post-processor.\n"
        !           116:                "\n"
        !           117:                "All symbol addresses are output as TEXT relative, i.e. you need\n"
        !           118:                "to give only that as section address for the Hatari debugger:\n"
        !           119:                "\tsymbols <filename> TEXT\n"
1.1       root      120:                "\n"
                    121:                "Options:\n", name);
1.1.1.4   root      122:        for (i = 0; i < ARRAY_SIZE(OptInfo); i++) {
1.1       root      123:                fprintf(stderr, "\t-%c\t%s\n", OptInfo[i].opt, OptInfo[i].desc);
                    124:        }
                    125:        if (msg) {
                    126:                fprintf(stderr, "\nERROR: %s!\n", msg);
                    127:        }
1.1.1.5 ! root      128: 
        !           129:        exit(msg != NULL);
1.1       root      130: }
                    131: 
                    132: /* ------------------ load and free functions ------------------ */
                    133: 
                    134: /**
                    135:  * compare function for qsort() to sort according to symbol address
                    136:  */
                    137: static int symbols_by_address(const void *s1, const void *s2)
                    138: {
                    139:        uint32_t addr1 = ((const symbol_t*)s1)->address;
                    140:        uint32_t addr2 = ((const symbol_t*)s2)->address;
                    141: 
                    142:        if (addr1 < addr2) {
                    143:                return -1;
                    144:        }
                    145:        if (addr1 > addr2) {
                    146:                return 1;
                    147:        }
                    148:        return 0;
                    149: }
                    150: 
                    151: /**
                    152:  * compare function for qsort() to sort according to symbol name
                    153:  */
                    154: static int symbols_by_name(const void *s1, const void *s2)
                    155: {
                    156:        const char* name1 = ((const symbol_t*)s1)->name;
                    157:        const char* name2 = ((const symbol_t*)s2)->name;
                    158:        int ret;
                    159: 
                    160:        ret = strcmp(name1, name2);
                    161:        return ret;
                    162: }
                    163: 
                    164: /**
1.1.1.5 ! root      165:  * check for duplicate addresses in symbol list
        !           166:  */
        !           167: static void symbols_check_addresses(const symbol_t *syms, int count)
        !           168: {
        !           169:        int i, j;
        !           170: 
        !           171:        for (i = 0; i < (count - 1); i++)
        !           172:        {
        !           173:                /* absolute symbols have values, not addresses */
        !           174:                if (syms[i].type == SYMTYPE_ABS) {
        !           175:                        continue;
        !           176:                }
        !           177:                for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
        !           178:                        if (syms[j].type == SYMTYPE_ABS) {
        !           179:                                continue;
        !           180:                        }
        !           181:                        fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
        !           182:                                syms[i].name, syms[j].name, syms[i].address);
        !           183:                        i = j;
        !           184:                }
        !           185:        }
        !           186: }
        !           187: 
        !           188: /**
        !           189:  * check for duplicate names in symbol list
        !           190:  */
        !           191: static void symbols_check_names(const symbol_t *syms, int count)
        !           192: {
        !           193:        int i, j;
        !           194: 
        !           195:        for (i = 0; i < (count - 1); i++)
        !           196:        {
        !           197:                for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
        !           198:                        fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
        !           199:                                syms[i].address, syms[j].address, syms[i].name);
        !           200:                        i = j;
        !           201:                }
        !           202:        }
        !           203: }
        !           204: 
        !           205: /**
1.1       root      206:  * Allocate symbol list & names for given number of items.
                    207:  * Return allocated list or NULL on failure.
                    208:  */
                    209: static symbol_list_t* symbol_list_alloc(int symbols)
                    210: {
                    211:        symbol_list_t *list;
                    212: 
                    213:        if (!symbols) {
                    214:                return NULL;
                    215:        }
                    216:        list = calloc(1, sizeof(symbol_list_t));
                    217:        if (list) {
                    218:                list->names = malloc(symbols * sizeof(symbol_t));
                    219:                if (!list->names) {
                    220:                        free(list);
                    221:                        list = NULL;
                    222:                }
                    223:        }
                    224:        return list;
                    225: }
                    226: 
                    227: /**
                    228:  * Free symbol list & names.
                    229:  */
                    230: static void symbol_list_free(symbol_list_t *list)
                    231: {
                    232:        if (list) {
                    233:                if (list->names) {
                    234:                        free(list->names);
                    235:                }
                    236:                free(list);
                    237:        }
                    238: }
                    239: 
                    240: /**
1.1.1.2   root      241:  * Return symbol type identifier char
                    242:  */
                    243: static char symbol_char(int type)
                    244: {
                    245:        switch (type) {
                    246:        case SYMTYPE_TEXT: return 'T';
                    247:        case SYMTYPE_DATA: return 'D';
                    248:        case SYMTYPE_BSS:  return 'B';
1.1.1.5 ! root      249:        case SYMTYPE_ABS:  return 'A';
1.1.1.2   root      250:        default: return '?';
                    251:        }
                    252: }
                    253: 
1.1.1.5 ! root      254: /**
        !           255:  * Return true if symbol name matches internal GCC symbol name,
        !           256:  * or is object / file name.
        !           257:  */
        !           258: static bool symbol_remove_obj(const char *name)
        !           259: {
        !           260:        static const char *gcc_sym[] = {
        !           261:                "___gnu_compiled_c",
        !           262:                "gcc2_compiled."
        !           263:        };
        !           264:        int i, len = strlen(name);
        !           265:        /* object (.a or .o) / file name? */
        !           266:        if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
        !           267:                    return true;
        !           268:        }
        !           269:        /* useless symbols GCC (v2) seems to add to every object? */
        !           270:        for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
        !           271:                if (strcmp(name, gcc_sym[i]) == 0) {
        !           272:                        return true;
        !           273:                }
        !           274:        }
        !           275:        return false;
        !           276: }
        !           277: 
1.1.1.2   root      278: 
                    279: /**
1.1       root      280:  * Load symbols of given type and the symbol address addresses from
                    281:  * DRI/GST format symbol table, and add given offsets to the addresses:
                    282:  *     http://toshyp.atari.org/en/005005.html
                    283:  * Return symbols list or NULL for failure.
                    284:  */
                    285: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, uint32_t tablesize)
                    286: {
1.1.1.5 ! root      287:        int i, count, symbols, invalid;
1.1       root      288:        int notypes, dtypes, locals, ofiles;
                    289:        prg_section_t *section;
                    290:        symbol_list_t *list;
                    291:        symtype_t symtype;
                    292: #define DRI_ENTRY_SIZE 14
                    293:        char name[23];
                    294:        uint16_t symid;
                    295:        uint32_t address;
                    296: 
                    297:        if (tablesize % DRI_ENTRY_SIZE) {
                    298:                fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
                    299:                return NULL;
                    300:        }
                    301:        symbols = tablesize / DRI_ENTRY_SIZE;
                    302:        if (!(list = symbol_list_alloc(symbols))) {
                    303:                return NULL;
                    304:        }
                    305: 
1.1.1.5 ! root      306:        invalid = dtypes = notypes = ofiles = locals = count = 0;
1.1       root      307:        for (i = 1; i <= symbols; i++) {
                    308:                /* read DRI symbol table slot */
                    309:                if (fread(name, 8, 1, fp) != 1 ||
                    310:                    fread(&symid, sizeof(symid), 1, fp) != 1 ||
                    311:                    fread(&address, sizeof(address), 1, fp) != 1) {
                    312:                        break;
                    313:                }
                    314:                address = SDL_SwapBE32(address);
                    315:                symid = SDL_SwapBE16(symid);
                    316: 
                    317:                /* GST extended DRI symbol format? */
                    318:                if ((symid & 0x0048)) {
                    319:                        /* next slot is rest of name */
                    320:                        i += 1;
                    321:                        if (fread(name+8, 14, 1, fp) != 1) {
                    322:                                break;
                    323:                        }
                    324:                        name[22] = '\0';
                    325:                } else {
                    326:                        name[8] = '\0';
                    327:                }
                    328: 
                    329:                /* check section */
                    330:                switch (symid & 0xf00) {
                    331:                case 0x0200:
                    332:                        symtype = SYMTYPE_TEXT;
                    333:                        section = &(sections[0]);
                    334:                        break;
                    335:                case 0x0400:
                    336:                        symtype = SYMTYPE_DATA;
                    337:                        section = &(sections[1]);
                    338:                        break;
                    339:                case 0x0100:
                    340:                        symtype = SYMTYPE_BSS;
                    341:                        section = &(sections[2]);
                    342:                        break;
                    343:                default:
                    344:                        if ((symid & 0xe000) == 0xe000) {
                    345:                                dtypes++;
                    346:                                continue;
                    347:                        }
1.1.1.5 ! root      348:                        if ((symid & 0x4000) == 0x4000) {
        !           349:                                symtype = SYMTYPE_ABS;
        !           350:                                section = NULL;
        !           351:                                break;
        !           352:                        }
1.1       root      353:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
1.1.1.5 ! root      354:                        invalid++;
1.1       root      355:                        continue;
                    356:                }
                    357:                if (Options.notypes & symtype) {
                    358:                        notypes++;
                    359:                        continue;
                    360:                }
                    361:                if (Options.no_local) {
                    362:                        if (name[0] == '.' && name[1] == 'L') {
                    363:                                locals++;
                    364:                                continue;
                    365:                        }
                    366:                }
                    367:                if (Options.no_obj) {
1.1.1.5 ! root      368:                        if (symbol_remove_obj(name)) {
1.1       root      369:                                ofiles++;
                    370:                                continue;
                    371:                        }
                    372:                }
1.1.1.5 ! root      373:                if (section) {
        !           374:                        address += section->offset;
        !           375:                        if (address > section->end) {
        !           376:                                fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
        !           377:                                        name, symbol_char(symtype), i, address, section->end);
        !           378:                                invalid++;
        !           379:                                continue;
1.1.1.2   root      380:                        }
1.1       root      381:                }
                    382:                list->names[count].address = address;
                    383:                list->names[count].type = symtype;
                    384:                list->names[count].name = strdup(name);
                    385:                assert(list->names[count].name);
                    386:                count++;
                    387:        }
                    388:        if (i <= symbols) {
                    389:                perror("ERROR: reading symbol failed");
                    390:                symbol_list_free(list);
                    391:                return NULL;
                    392:        }
1.1.1.5 ! root      393:        if (invalid) {
        !           394:                fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
1.1       root      395:        }
                    396:        if (dtypes) {
1.1.1.5 ! root      397:                fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
        !           398:        }
        !           399:        if (notypes) {
        !           400:                fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
1.1       root      401:        }
                    402:        if (locals) {
                    403:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
                    404:        }
                    405:        if (ofiles) {
                    406:                /* object file path names most likely get truncated and
                    407:                 * as result cause unnecessary symbol name conflicts in
                    408:                 * addition to object file addresses conflicting with
                    409:                 * first symbol in the object file.
                    410:                 */
1.1.1.5 ! root      411:                fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
1.1       root      412:        }
                    413:        list->symbols = symbols;
                    414:        list->count = count;
                    415:        return list;
                    416: }
                    417: 
1.1.1.5 ! root      418: 
        !           419: /**
        !           420:  * Load symbols of given type and the symbol address addresses from
        !           421:  * a.out format symbol table, and add given offsets to the addresses:
        !           422:  * Return symbols list or NULL for failure.
        !           423:  */
        !           424: static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, Uint32 tablesize, Uint32 stroff, Uint32 strsize)
        !           425: {
        !           426:        size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
        !           427:        size_t i;
        !           428:        size_t strx;
        !           429:        unsigned char *p;
        !           430:        char *name;
        !           431:        symbol_t *sym;
        !           432:        symtype_t symtype;
        !           433:        uint32_t address;
        !           434:        uint32_t nread;
        !           435:        symbol_list_t *list;
        !           436:        unsigned char n_type;
        !           437:        unsigned char n_other;
        !           438:        unsigned short n_desc;
        !           439:        static char dummy[] = "<invalid>";
        !           440:        int dtypes, locals, ofiles, count, notypes, invalid, weak;
        !           441:        prg_section_t *section;
        !           442: 
        !           443:        if (!(list = symbol_list_alloc(slots))) {
        !           444:                return NULL;
        !           445:        }
        !           446: 
        !           447:        list->strtab = (char *)malloc(tablesize + strsize);
        !           448: 
        !           449:        if (list->strtab == NULL)
        !           450:        {
        !           451:                symbol_list_free(list);
        !           452:                return NULL;
        !           453:        }
        !           454: 
        !           455:        nread = fread(list->strtab, tablesize + strsize, 1, fp);
        !           456:        if (nread != 1)
        !           457:        {
        !           458:                perror("ERROR: reading symbols failed");
        !           459:                symbol_list_free(list);
        !           460:                return NULL;
        !           461:        }
        !           462: 
        !           463:        p = (unsigned char *)list->strtab;
        !           464:        sym = list->names;
        !           465: 
        !           466:        weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
        !           467:        for (i = 0; i < slots; i++)
        !           468:        {
        !           469:                strx = SDL_SwapBE32(*(Uint32*)p);
        !           470:                p += 4;
        !           471:                n_type = *p++;
        !           472:                n_other = *p++;
        !           473:                n_desc = SDL_SwapBE16(*(Uint16*)p);
        !           474:                p += 2;
        !           475:                address = SDL_SwapBE32(*(Uint32*)p);
        !           476:                p += 4;
        !           477:                name = dummy;
        !           478:                if (!strx) {
        !           479:                        invalid++;
        !           480:                        continue;
        !           481:                }
        !           482:                if (strx >= strsize) {
        !           483:                        fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
        !           484:                        invalid++;
        !           485:                        continue;
        !           486:                }
        !           487:                name = list->strtab + strx + stroff;
        !           488: 
        !           489:                if (n_type & N_STAB)
        !           490:                {
        !           491:                        dtypes++;
        !           492:                        continue;
        !           493:                }
        !           494:                section = NULL;
        !           495:                switch (n_type & (N_TYPE|N_EXT))
        !           496:                {
        !           497:                case N_UNDF:
        !           498:                case N_UNDF|N_EXT:
        !           499:                        /* shouldn't happen here */
        !           500:                        weak++;
        !           501:                        continue;
        !           502:                case N_ABS:
        !           503:                case N_ABS|N_EXT:
        !           504:                        symtype = SYMTYPE_ABS;
        !           505:                        break;
        !           506:                case N_TEXT:
        !           507:                case N_TEXT|N_EXT:
        !           508:                        symtype = SYMTYPE_TEXT;
        !           509:                        section = &(sections[0]);
        !           510:                        break;
        !           511:                case N_DATA:
        !           512:                case N_DATA|N_EXT:
        !           513:                        symtype = SYMTYPE_DATA;
        !           514:                        section = &(sections[1]);
        !           515:                        break;
        !           516:                case N_BSS:
        !           517:                case N_BSS|N_EXT:
        !           518:                case N_COMM:
        !           519:                case N_COMM|N_EXT:
        !           520:                        symtype = SYMTYPE_BSS;
        !           521:                        section = &(sections[2]);
        !           522:                        break;
        !           523:                case N_FN: /* filenames, not object addresses? */
        !           524:                        dtypes++;
        !           525:                        continue;
        !           526:                case N_SIZE:
        !           527:                case N_WARNING:
        !           528:                case N_SETA:
        !           529:                case N_SETT:
        !           530:                case N_SETD:
        !           531:                case N_SETB:
        !           532:                case N_SETV:
        !           533:                        dtypes++;
        !           534:                        continue;
        !           535:                case N_WEAKU:
        !           536:                case N_WEAKT:
        !           537:                case N_WEAKD:
        !           538:                case N_WEAKB:
        !           539:                        weak++;
        !           540:                        continue;
        !           541:                default:
        !           542:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
        !           543:                        invalid++;
        !           544:                        continue;
        !           545:                }
        !           546:                /*
        !           547:                 * the value of a common symbol is its size, not its address:
        !           548:                 */
        !           549:                if (((n_type & N_TYPE) == N_COMM) ||
        !           550:                        (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
        !           551:                {
        !           552:                        /* if we ever want to know a symbols size, get that here */
        !           553:                        fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", sym->name, (unsigned int)i);
        !           554:                        dtypes++;
        !           555:                        continue;
        !           556:                }
        !           557:                if (Options.notypes & symtype) {
        !           558:                        notypes++;
        !           559:                        continue;
        !           560:                }
        !           561:                if (Options.no_local) {
        !           562:                        if (name[0] == '.' && name[1] == 'L') {
        !           563:                                locals++;
        !           564:                                continue;
        !           565:                        }
        !           566:                }
        !           567:                if (Options.no_obj) {
        !           568:                        if (symbol_remove_obj(name)) {
        !           569:                                ofiles++;
        !           570:                                continue;
        !           571:                        }
        !           572:                }
        !           573:                if (section) {
        !           574:                        address += sections[0].offset;  /* all GNU symbol addresses are TEXT relative */
        !           575:                        if (address > section->end) {
        !           576:                                fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
        !           577:                                        name, symbol_char(symtype), (unsigned int)i, address, section->end);
        !           578:                                invalid++;
        !           579:                                continue;
        !           580:                        }
        !           581:                }
        !           582:                sym->address = address;
        !           583:                sym->type = symtype;
        !           584:                sym->name = name;
        !           585:                sym++;
        !           586:                count++;
        !           587:                (void) n_desc;
        !           588:                (void) n_other;
        !           589:        }
        !           590: 
        !           591:        if (invalid) {
        !           592:                fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
        !           593:        }
        !           594:        if (dtypes) {
        !           595:                fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
        !           596:        }
        !           597:        if (weak) {
        !           598:                fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
        !           599:        }
        !           600:        if (notypes) {
        !           601:                fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
        !           602:        }
        !           603:        if (locals) {
        !           604:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
        !           605:        }
        !           606:        if (ofiles) {
        !           607:                /* object file path names most likely get truncated and
        !           608:                 * as result cause unnecessary symbol name conflicts in
        !           609:                 * addition to object file addresses conflicting with
        !           610:                 * first symbol in the object file.
        !           611:                 */
        !           612:                fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
        !           613:        }
        !           614: 
        !           615:        list->symbols = slots;
        !           616:        list->count = count;
        !           617:        return list;
        !           618: }
        !           619: 
        !           620: 
1.1       root      621: /**
1.1.1.3   root      622:  * Print program header information.
                    623:  * Return false for unrecognized symbol table type.
                    624:  */
                    625: static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
                    626: {
                    627:        static const struct {
                    628:                Uint32 flag;
                    629:                const char *name;
                    630:        } flags[] = {
                    631:                { 0x0001, "FASTLOAD"   },
                    632:                { 0x0002, "TTRAMLOAD"  },
                    633:                { 0x0004, "TTRAMMEM"   },
                    634:                { 0x0008, "MINIMUM"    }, /* MagiC */
                    635:                { 0x1000, "SHAREDTEXT" }
                    636:        };
                    637:        const char *info;
                    638:        int i;
                    639: 
                    640:        switch (tabletype) {
1.1.1.5 ! root      641:        case SYMBOL_FORMAT_MINT: /* "MiNT" */
1.1.1.3   root      642:                info = "GCC/MiNT executable, GST symbol table";
                    643:                break;
1.1.1.5 ! root      644:        case SYMBOL_FORMAT_GNU:  /* "GNU_" */
        !           645:                info = "GCC/MiNT executable, a.out symbol table";
        !           646:                break;
        !           647:        case SYMBOL_FORMAT_DRI:
1.1.1.3   root      648:                info = "TOS executable, DRI / GST symbol table";
                    649:                break;
                    650:        default:
                    651:                fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
                    652:                return false;
                    653:        }
                    654:        fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
                    655:        /* bit flags */
1.1.1.4   root      656:        for (i = 0; i < ARRAY_SIZE(flags); i++) {
1.1.1.3   root      657:                if (prgflags & flags[i].flag) {
                    658:                        fprintf(stderr, " %s", flags[i].name);
                    659:                }
                    660:        }
                    661:        /* memory protection flags */
                    662:        switch((prgflags >> 4) & 3) {
                    663:                case 0: info = "PRIVATE";  break;
                    664:                case 1: info = "GLOBAL";   break;
                    665:                case 2: info = "SUPER";    break;
                    666:                case 3: info = "READONLY"; break;
                    667:        }
                    668:        fprintf(stderr, " %s (0x%x)\n", info, prgflags);
                    669:        return true;
                    670: }
                    671: 
                    672: /**
1.1       root      673:  * Parse program header and use symbol table format specific loader
                    674:  * loader function to load the symbols.
                    675:  * Return symbols list or NULL for failure.
                    676:  */
                    677: static symbol_list_t* symbols_load_binary(FILE *fp)
                    678: {
1.1.1.2   root      679:        Uint32 textlen, datalen, bsslen, tablesize, tabletype, prgflags;
1.1       root      680:        prg_section_t sections[3];
                    681:        int offset, reads = 0;
1.1.1.2   root      682:        Uint16 relocflag;
                    683:        symbol_list_t* symbols;
1.1.1.5 ! root      684:        Uint32 symoff = 0;
        !           685:        Uint32 stroff = 0;
        !           686:        Uint32 strsize = 0;
1.1       root      687: 
                    688:        /* get TEXT, DATA & BSS section sizes */
                    689:        reads += fread(&textlen, sizeof(textlen), 1, fp);
                    690:        textlen = SDL_SwapBE32(textlen);
                    691:        reads += fread(&datalen, sizeof(datalen), 1, fp);
                    692:        datalen = SDL_SwapBE32(datalen);
                    693:        reads += fread(&bsslen, sizeof(bsslen), 1, fp);
                    694:        bsslen = SDL_SwapBE32(bsslen);
                    695: 
                    696:        /* get symbol table size & type and check that all reads succeeded */
                    697:        reads += fread(&tablesize, sizeof(tablesize), 1, fp);
                    698:        tablesize = SDL_SwapBE32(tablesize);
                    699:        reads += fread(&tabletype, sizeof(tabletype), 1, fp);
                    700:        tabletype = SDL_SwapBE32(tabletype);
1.1.1.2   root      701: 
                    702:        /* get program header and whether there's reloc table */
                    703:        reads += fread(&prgflags, sizeof(prgflags), 1, fp);
                    704:        prgflags = SDL_SwapBE32(prgflags);
                    705:        reads += fread(&relocflag, sizeof(relocflag), 1, fp);
                    706:        relocflag = SDL_SwapBE32(relocflag);
                    707:        
                    708:        if (reads != 7) {
1.1       root      709:                fprintf(stderr, "ERROR: program header reading failed!\n");
                    710:                return NULL;
                    711:        }
1.1.1.5 ! root      712:        /*
        !           713:         * check for GNU-style symbol table in aexec header
        !           714:         */
        !           715:        if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
        !           716:                Uint32 magic1, magic2;
        !           717:                Uint32 dummy;
        !           718:                Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
        !           719:                Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
        !           720: 
        !           721:                reads  = fread(&magic1, sizeof(magic1), 1, fp);
        !           722:                magic1 = SDL_SwapBE32(magic1);
        !           723:                reads += fread(&magic2, sizeof(magic2), 1, fp);
        !           724:                magic2 = SDL_SwapBE32(magic2);
        !           725:                if (reads == 2 &&
        !           726:                        ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) ||      /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
        !           727:                         (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) {     /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
        !           728:                        reads += fread(&dummy, sizeof(dummy), 1, fp);   /* skip a_info */
        !           729:                        reads += fread(&a_text, sizeof(a_text), 1, fp);
        !           730:                        a_text = SDL_SwapBE32(a_text);
        !           731:                        reads += fread(&a_data, sizeof(a_data), 1, fp);
        !           732:                        a_data = SDL_SwapBE32(a_data);
        !           733:                        reads += fread(&a_bss, sizeof(a_bss), 1, fp);
        !           734:                        a_bss = SDL_SwapBE32(a_bss);
        !           735:                        reads += fread(&a_syms, sizeof(a_syms), 1, fp);
        !           736:                        a_syms = SDL_SwapBE32(a_syms);
        !           737:                        reads += fread(&a_entry, sizeof(a_entry), 1, fp);
        !           738:                        a_entry = SDL_SwapBE32(a_entry);
        !           739:                        reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
        !           740:                        a_trsize = SDL_SwapBE32(a_trsize);
        !           741:                        reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
        !           742:                        a_drsize = SDL_SwapBE32(a_drsize);
        !           743:                        reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
        !           744:                        g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
        !           745:                        reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
        !           746:                        g_tparel_size = SDL_SwapBE32(g_tparel_size);
        !           747:                        reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
        !           748:                        g_stkpos = SDL_SwapBE32(g_stkpos);
        !           749:                        reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
        !           750:                        g_symbol_format = SDL_SwapBE32(g_symbol_format);
        !           751:                        if (g_symbol_format == 0)
        !           752:                        {
        !           753:                                tabletype = SYMBOL_FORMAT_GNU;
        !           754:                        }
        !           755:                        if ((a_text + (256 - 28)) != textlen)
        !           756:                                fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
        !           757:                        if (a_data != datalen)
        !           758:                                fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
        !           759:                        if (a_bss != bsslen)
        !           760:                                fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
        !           761:                        /*
        !           762:                         * the symbol table size in the GEMDOS header includes the string table,
        !           763:                         * the symbol table size in the exec header does not.
        !           764:                         */
        !           765:                        if (tabletype == SYMBOL_FORMAT_GNU)
        !           766:                        {
        !           767:                                strsize = tablesize - a_syms;
        !           768:                                tablesize = a_syms;
        !           769:                                stroff = a_syms;
        !           770:                        }
        !           771: 
        !           772:                        textlen = a_text + (256 - 28);
        !           773:                        datalen = a_data;
        !           774:                        bsslen = a_bss;
        !           775:                        symoff = 0x100 + /* sizeof(extended exec header) */
        !           776:                                a_text +
        !           777:                                a_data +
        !           778:                                a_trsize +
        !           779:                                a_drsize;
        !           780:                }
        !           781:        }
1.1.1.3   root      782:        if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
                    783:                return NULL;
                    784:        }
1.1.1.5 ! root      785:        fprintf(stderr, "Program section sizes:\n- text: %d\n- data: %d\n- bss:  %d\n",
        !           786:                textlen, datalen, bsslen);
        !           787: 
1.1.1.3   root      788:        if (!tablesize) {
                    789:                fprintf(stderr, "ERROR: symbol table missing from the program!\n");
                    790:                return NULL;
                    791:        }
1.1.1.5 ! root      792:        fprintf(stderr, "- syms: %d\n", tablesize);
1.1       root      793: 
1.1.1.2   root      794:        /* symbols already have suitable offsets, so only acceptable end position needs to be calculated */
                    795:        sections[0].offset = 0;
                    796:        sections[0].end = textlen;
1.1.1.5 ! root      797:        sections[1].offset = textlen;
        !           798:        sections[1].end = textlen + datalen;
        !           799:        sections[2].offset = textlen + datalen;
        !           800:        sections[2].end = textlen + datalen + bsslen;
        !           801: 
        !           802:        if (tabletype == SYMBOL_FORMAT_GNU) {
        !           803:                /* go to start of symbol table */
        !           804:                offset = symoff;
        !           805:                if (fseek(fp, offset, SEEK_SET) < 0) {
        !           806:                        perror("ERROR: seeking to symbol table failed");
        !           807:                        return NULL;
1.1.1.2   root      808:                }
1.1.1.5 ! root      809:                fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
        !           810:                symbols = symbols_load_gnu(fp, sections, tablesize, stroff, strsize);
1.1.1.2   root      811:        } else {
1.1.1.5 ! root      812:                /* go to start of symbol table */
        !           813:                offset = 0x1C + textlen + datalen;
        !           814:                if (fseek(fp, offset, SEEK_SET) < 0) {
        !           815:                        perror("ERROR: seeking to symbol table failed");
        !           816:                        return NULL;
        !           817:                }
        !           818:                fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
        !           819:                symbols = symbols_load_dri(fp, sections, tablesize);
1.1.1.2   root      820:        }
1.1.1.5 ! root      821:        if (!symbols) {
1.1.1.2   root      822:                fprintf(stderr, "\n\n*** Try with 'nm -n <program>' (Atari/cross-compiler tool) instead ***\n\n");
                    823:                return NULL;
                    824:        }
1.1.1.5 ! root      825:        fprintf(stderr, "Load the listed symbols to Hatari debugger with 'symbols <filename> TEXT'.\n");
1.1.1.2   root      826:        return symbols;
1.1       root      827: }
                    828: 
                    829: /**
                    830:  * Load symbols of given type and the symbol address addresses from
                    831:  * the given file and add given offsets to the addresses.
                    832:  * Return symbols list or NULL for failure.
                    833:  */
                    834: static symbol_list_t* symbols_load(const char *filename)
                    835: {
                    836:        symbol_list_t *list;
                    837:        uint16_t magic;
                    838:        FILE *fp;
                    839: 
                    840:        fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
1.1.1.3   root      841:        if (!(fp = fopen(filename, "rb"))) {
1.1.1.5 ! root      842:                usage("opening program file failed");
1.1       root      843:        }
                    844:        if (fread(&magic, sizeof(magic), 1, fp) != 1) {
1.1.1.5 ! root      845:                usage("reading program file failed");
1.1       root      846:        }
                    847: 
1.1.1.5 ! root      848:        if (SDL_SwapBE16(magic) != ATARI_PROGRAM_MAGIC) {
        !           849:                usage("file isn't an Atari program file");
1.1       root      850:        }
                    851:        list = symbols_load_binary(fp);
                    852:        fclose(fp);
                    853: 
                    854:        if (!list) {
1.1.1.5 ! root      855:                usage("no symbols, or reading them failed");
1.1       root      856:        }
                    857: 
                    858:        if (list->count < list->symbols) {
                    859:                if (!list->count) {
1.1.1.5 ! root      860:                        usage("no valid symbols in program, symbol table loading failed");
1.1       root      861:                }
                    862:                /* parsed less than there were "content" lines */
                    863:                list->names = realloc(list->names, list->count * sizeof(symbol_t));
                    864:                assert(list->names);
                    865:        }
                    866: 
                    867:        /* copy name list to address list */
                    868:        list->addresses = malloc(list->count * sizeof(symbol_t));
                    869:        assert(list->addresses);
                    870:        memcpy(list->addresses, list->names, list->count * sizeof(symbol_t));
                    871: 
                    872:        /* sort both lists, with different criteria */
                    873:        qsort(list->addresses, list->count, sizeof(symbol_t), symbols_by_address);
                    874:        qsort(list->names, list->count, sizeof(symbol_t), symbols_by_name);
1.1.1.5 ! root      875: 
        !           876:        /* check for duplicate addresses */
        !           877:        symbols_check_addresses(list->addresses, list->count);
        !           878: 
        !           879:        /* check for duplicate names */
        !           880:        symbols_check_names(list->names, list->count);
        !           881: 
1.1       root      882:        return list;
                    883: }
                    884: 
                    885: 
                    886: /* ---------------- symbol showing & option parsing ------------------ */
                    887: 
                    888: /**
                    889:  * Show symbols sorted by selected option
                    890:  */
                    891: static int symbols_show(symbol_list_t* list)
                    892: {
                    893:        symbol_t *entry, *entries;
                    894:        char symchar;
                    895:        int i;
                    896:        
                    897:        if (!list) {
                    898:                fprintf(stderr, "No symbols!\n");
                    899:                return 1;
                    900:        }
                    901:        if (Options.sort_name) {
                    902:                entries = list->names;
                    903:        } else {
                    904:                entries = list->addresses;
                    905:        }
                    906:        for (entry = entries, i = 0; i < list->count; i++, entry++) {
1.1.1.5 ! root      907:                symchar = symbol_char(entry->type);
1.1       root      908:                fprintf(stdout, "0x%08x %c %s\n",
                    909:                        entry->address, symchar, entry->name);
                    910:        }
                    911: 
1.1.1.5 ! root      912:        fprintf(stderr, "%d (unignored) symbols processed.\n", list->count);
1.1       root      913:        return 0;
                    914: }
                    915: 
                    916: /**
                    917:  * parse program options and then call symbol load+save
                    918:  */
                    919: int main(int argc, const char *argv[])
                    920: {
                    921:        int i;
                    922: 
                    923:        PrgPath = *argv;
                    924:        for (i = 1; i+1 < argc; i++) {
                    925:                if (argv[i][0] != '-') {
                    926:                        break;
                    927:                }
1.1.1.2   root      928:                switch(tolower((unsigned char)argv[i][1])) {
1.1.1.5 ! root      929:                case 'a':
        !           930:                        Options.notypes |= SYMTYPE_ABS;
        !           931:                        break;
1.1       root      932:                case 'b':
                    933:                        Options.notypes |= SYMTYPE_BSS;
                    934:                        break;
                    935:                case 'd':
                    936:                        Options.notypes |= SYMTYPE_DATA;
                    937:                        break;
                    938:                case 't':
                    939:                        Options.notypes |= SYMTYPE_TEXT;
                    940:                        break;
                    941:                case 'l':
                    942:                        Options.no_local = true;
                    943:                        break;
                    944:                case 'o':
                    945:                        Options.no_obj = true;
                    946:                        break;
1.1.1.5 ! root      947:                case 'n':
        !           948:                        Options.sort_name = true;
        !           949:                        break;
1.1       root      950:                default:
                    951:                        usage("unknown option");
                    952:                }
                    953:        }
                    954:        if (i+1 != argc) {
                    955:                usage("incorrect number of arguments");
                    956:        }
                    957:        return symbols_show(symbols_load(argv[i]));
                    958: }

unix.superglobalmegacorp.com

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