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

1.1       root        1: /*
                      2:  * Hatari - gst2ascii.c
                      3:  * 
                      4:  * Copyright (C) 2013 by Eero Tamminen
                      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:  * 
                      9:  * Convert DRI/GST symbol table in a binary into ASCII symbols file accepted
                     10:  * by Hatari debugger and its profiler data post-processor.  This will also
                     11:  * allow manual editing of the symbol table (removing irrelevant labels or
                     12:  * adding missing symbols for functions).
                     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>
                     28: 
                     29: typedef enum {
                     30:        SYMTYPE_TEXT = 1,
                     31:        SYMTYPE_DATA = 2,
                     32:        SYMTYPE_BSS  = 4
                     33: } symtype_t;
                     34: 
                     35: typedef struct {
                     36:        char *name;
                     37:        uint32_t address;
                     38:        symtype_t type;
                     39: } symbol_t;
                     40: 
                     41: typedef struct {
                     42:        int count;              /* final symbol count */
                     43:        int symbols;            /* initial symbol count */
                     44:        symbol_t *addresses;    /* items sorted by address */
                     45:        symbol_t *names;        /* items sorted by symbol name */
                     46: } symbol_list_t;
                     47: 
                     48: typedef struct {
                     49:        uint32_t offset;
                     50:        uint32_t end;
                     51: } prg_section_t;
                     52: 
                     53: /* ------------------ options & usage ------------------ */
                     54: 
                     55: #ifdef WIN32
                     56: #define PATHSEP '\\'
                     57: #else
                     58: #define PATHSEP '/'
                     59: #endif
                     60: 
                     61: #define ARRAYSIZE(x) (int)(sizeof(x)/sizeof(x[0]))
                     62: 
                     63: static const char *PrgPath;
                     64: 
                     65: static struct {
                     66:        symtype_t notypes;
                     67:        bool no_obj;
                     68:        bool no_local;
                     69:        bool sort_name;
                     70: } Options;
                     71: 
                     72: /*
                     73:  * Show program usage, given error message
                     74:  * return empty list
                     75:  */
                     76: static symbol_list_t* usage(const char *msg)
                     77: {
                     78:        const struct {
                     79:                const char opt;
                     80:                const char *desc;
                     81:        } OptInfo[] = {
                     82:                { 'n', "sort by name (not address)" },
                     83:                { 'b', "no BSS symbols" },
                     84:                { 'd', "no DATA symbols" },
                     85:                { 't', "no TEXT symbols" },
                     86:                { 'l', "no local (.L*) symbols" },
                     87:                { 'o', "no object symbols (filenames or GCC internals)" },
                     88:        };
                     89:        const char *name;
                     90:        int i;
                     91: 
                     92:        if ((name = strrchr(PrgPath, PATHSEP))) {
                     93:                name++;
                     94:        } else {
                     95:                name = PrgPath;
                     96:        }
                     97:        fprintf(stderr,
                     98:                "\n"
                     99:                "Usage: %s [options] <Atari program>\n"
                    100:                "\n"
                    101:                "Outputs given program DRI/GST symbol table content\n"
                    102:                "in ASCII format accepted by Hatari debugger and\n"
                    103:                "its profiler data post-processor.\n"
                    104:                "\n"
                    105:                "Options:\n", name);
                    106:        for (i = 0; i < ARRAYSIZE(OptInfo); i++) {
                    107:                fprintf(stderr, "\t-%c\t%s\n", OptInfo[i].opt, OptInfo[i].desc);
                    108:        }
                    109:        if (msg) {
                    110:                fprintf(stderr, "\nERROR: %s!\n", msg);
                    111:        }
                    112:        return NULL;
                    113: }
                    114: 
                    115: /* ------------------ load and free functions ------------------ */
                    116: 
                    117: /**
                    118:  * compare function for qsort() to sort according to symbol address
                    119:  */
                    120: static int symbols_by_address(const void *s1, const void *s2)
                    121: {
                    122:        uint32_t addr1 = ((const symbol_t*)s1)->address;
                    123:        uint32_t addr2 = ((const symbol_t*)s2)->address;
                    124: 
                    125:        if (addr1 < addr2) {
                    126:                return -1;
                    127:        }
                    128:        if (addr1 > addr2) {
                    129:                return 1;
                    130:        }
                    131:        fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
                    132:                ((const symbol_t*)s1)->name, ((const symbol_t*)s2)->name, addr1);
                    133:        return 0;
                    134: }
                    135: 
                    136: /**
                    137:  * compare function for qsort() to sort according to symbol name
                    138:  */
                    139: static int symbols_by_name(const void *s1, const void *s2)
                    140: {
                    141:        const char* name1 = ((const symbol_t*)s1)->name;
                    142:        const char* name2 = ((const symbol_t*)s2)->name;
                    143:        int ret;
                    144: 
                    145:        ret = strcmp(name1, name2);
                    146:        if (!ret) {
                    147:                fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
                    148:                        ((const symbol_t*)s1)->address, ((const symbol_t*)s2)->address, name1);
                    149:        }
                    150:        return ret;
                    151: }
                    152: 
                    153: /**
                    154:  * Allocate symbol list & names for given number of items.
                    155:  * Return allocated list or NULL on failure.
                    156:  */
                    157: static symbol_list_t* symbol_list_alloc(int symbols)
                    158: {
                    159:        symbol_list_t *list;
                    160: 
                    161:        if (!symbols) {
                    162:                return NULL;
                    163:        }
                    164:        list = calloc(1, sizeof(symbol_list_t));
                    165:        if (list) {
                    166:                list->names = malloc(symbols * sizeof(symbol_t));
                    167:                if (!list->names) {
                    168:                        free(list);
                    169:                        list = NULL;
                    170:                }
                    171:        }
                    172:        return list;
                    173: }
                    174: 
                    175: /**
                    176:  * Free symbol list & names.
                    177:  */
                    178: static void symbol_list_free(symbol_list_t *list)
                    179: {
                    180:        if (list) {
                    181:                if (list->names) {
                    182:                        free(list->names);
                    183:                }
                    184:                free(list);
                    185:        }
                    186: }
                    187: 
                    188: /**
                    189:  * Load symbols of given type and the symbol address addresses from
                    190:  * DRI/GST format symbol table, and add given offsets to the addresses:
                    191:  *     http://toshyp.atari.org/en/005005.html
                    192:  * Return symbols list or NULL for failure.
                    193:  */
                    194: static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, uint32_t tablesize)
                    195: {
                    196:        int i, count, symbols;
                    197:        int notypes, dtypes, locals, ofiles;
                    198:        prg_section_t *section;
                    199:        symbol_list_t *list;
                    200:        symtype_t symtype;
                    201: #define DRI_ENTRY_SIZE 14
                    202:        char name[23];
                    203:        uint16_t symid;
                    204:        uint32_t address;
                    205: 
                    206:        if (tablesize % DRI_ENTRY_SIZE) {
                    207:                fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
                    208:                return NULL;
                    209:        }
                    210:        symbols = tablesize / DRI_ENTRY_SIZE;
                    211:        if (!(list = symbol_list_alloc(symbols))) {
                    212:                return NULL;
                    213:        }
                    214: 
                    215:        dtypes = notypes = ofiles = locals = count = 0;
                    216:        for (i = 1; i <= symbols; i++) {
                    217:                /* read DRI symbol table slot */
                    218:                if (fread(name, 8, 1, fp) != 1 ||
                    219:                    fread(&symid, sizeof(symid), 1, fp) != 1 ||
                    220:                    fread(&address, sizeof(address), 1, fp) != 1) {
                    221:                        break;
                    222:                }
                    223:                address = SDL_SwapBE32(address);
                    224:                symid = SDL_SwapBE16(symid);
                    225: 
                    226:                /* GST extended DRI symbol format? */
                    227:                if ((symid & 0x0048)) {
                    228:                        /* next slot is rest of name */
                    229:                        i += 1;
                    230:                        if (fread(name+8, 14, 1, fp) != 1) {
                    231:                                break;
                    232:                        }
                    233:                        name[22] = '\0';
                    234:                } else {
                    235:                        name[8] = '\0';
                    236:                }
                    237: 
                    238:                /* check section */
                    239:                switch (symid & 0xf00) {
                    240:                case 0x0200:
                    241:                        symtype = SYMTYPE_TEXT;
                    242:                        section = &(sections[0]);
                    243:                        break;
                    244:                case 0x0400:
                    245:                        symtype = SYMTYPE_DATA;
                    246:                        section = &(sections[1]);
                    247:                        break;
                    248:                case 0x0100:
                    249:                        symtype = SYMTYPE_BSS;
                    250:                        section = &(sections[2]);
                    251:                        break;
                    252:                default:
                    253:                        if ((symid & 0xe000) == 0xe000) {
                    254:                                dtypes++;
                    255:                                continue;
                    256:                        }
                    257:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
                    258:                        continue;
                    259:                }
                    260:                if (Options.notypes & symtype) {
                    261:                        notypes++;
                    262:                        continue;
                    263:                }
                    264:                if (Options.no_local) {
                    265:                        if (name[0] == '.' && name[1] == 'L') {
                    266:                                locals++;
                    267:                                continue;
                    268:                        }
                    269:                }
                    270:                if (Options.no_obj) {
                    271:                        const char *gcc_sym[] = {
                    272:                                "___gnu_compiled_c",
                    273:                                "gcc2_compiled."
                    274:                        };
                    275:                        int j, len = strlen(name);
                    276:                        /* object / file name? */
                    277:                        if (len > 2 && ((name[len-2] == '.' && name[len-1] == 'o') || strchr(name, '/'))) {
                    278:                                ofiles++;
                    279:                                continue;
                    280:                        }
                    281:                        /* useless symbols GCC (v2) seems to add to every object? */
                    282:                        for (j = 0; j < ARRAYSIZE(gcc_sym); j++) {
                    283:                                if (strcmp(name, gcc_sym[j]) == 0) {
                    284:                                        ofiles++;
                    285:                                        j = -1;
                    286:                                        break;
                    287:                                }
                    288:                        }
                    289:                        if (j < 0) {
                    290:                                continue;
                    291:                        }
                    292:                }
                    293:                address += section->offset;
                    294:                if (address > section->end) {
                    295:                        fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d with invalid offset 0x%x (>= 0x%x).\n", name, i, address, section->end);
                    296:                        continue;
                    297:                }
                    298:                list->names[count].address = address;
                    299:                list->names[count].type = symtype;
                    300:                list->names[count].name = strdup(name);
                    301:                assert(list->names[count].name);
                    302:                count++;
                    303:        }
                    304:        if (i <= symbols) {
                    305:                perror("ERROR: reading symbol failed");
                    306:                symbol_list_free(list);
                    307:                return NULL;
                    308:        }
                    309:        if (notypes) {
                    310:                fprintf(stderr, "NOTE: ignored %d unwanted symbol types.\n", notypes);
                    311:        }
                    312:        if (dtypes) {
                    313:                fprintf(stderr, "NOTE: ignored %d globally defined equated values.\n", dtypes);
                    314:        }
                    315:        if (locals) {
                    316:                fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
                    317:        }
                    318:        if (ofiles) {
                    319:                /* object file path names most likely get truncated and
                    320:                 * as result cause unnecessary symbol name conflicts in
                    321:                 * addition to object file addresses conflicting with
                    322:                 * first symbol in the object file.
                    323:                 */
                    324:                fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.o' or is GCC internal).\n", ofiles);
                    325:        }
                    326:        list->symbols = symbols;
                    327:        list->count = count;
                    328:        return list;
                    329: }
                    330: 
                    331: /**
                    332:  * Parse program header and use symbol table format specific loader
                    333:  * loader function to load the symbols.
                    334:  * Return symbols list or NULL for failure.
                    335:  */
                    336: static symbol_list_t* symbols_load_binary(FILE *fp)
                    337: {
                    338:        uint32_t textlen, datalen, bsslen, tablesize, tabletype;
                    339:        prg_section_t sections[3];
                    340:        int offset, reads = 0;
                    341: 
                    342:        /* get TEXT, DATA & BSS section sizes */
                    343:        reads += fread(&textlen, sizeof(textlen), 1, fp);
                    344:        textlen = SDL_SwapBE32(textlen);
                    345:        reads += fread(&datalen, sizeof(datalen), 1, fp);
                    346:        datalen = SDL_SwapBE32(datalen);
                    347:        reads += fread(&bsslen, sizeof(bsslen), 1, fp);
                    348:        bsslen = SDL_SwapBE32(bsslen);
                    349: 
                    350:        /* get symbol table size & type and check that all reads succeeded */
                    351:        reads += fread(&tablesize, sizeof(tablesize), 1, fp);
                    352:        tablesize = SDL_SwapBE32(tablesize);
                    353:        if (!tablesize) {
                    354:                fprintf(stderr, "ERROR: symbol table missing from the program!\n");
                    355:                return NULL;
                    356:        }
                    357:        reads += fread(&tabletype, sizeof(tabletype), 1, fp);
                    358:        tabletype = SDL_SwapBE32(tabletype);
                    359:        if (reads != 5) {
                    360:                fprintf(stderr, "ERROR: program header reading failed!\n");
                    361:                return NULL;
                    362:        }
                    363: 
                    364:        /* go to start of symbol table */
                    365:        offset = 0x1C + textlen + datalen;
                    366:        if (fseek(fp, offset, SEEK_SET) < 0) {
                    367:                perror("ERROR: seeking to symbol table failed");
                    368:                return NULL;
                    369:        }
                    370:        /* symbols already have suitable offsets, so only acceptable end position needs to be calculated */
                    371:        sections[0].offset = 0;
                    372:        sections[0].end = textlen;
                    373:        sections[1].offset = 0;
                    374:        sections[1].end = textlen + datalen;
                    375:        sections[2].offset = 0;
                    376:        sections[2].end = textlen + datalen + bsslen;
                    377: 
                    378:        switch (tabletype) {
                    379:        case 0x4D694E54:        /* "MiNT" */
                    380:                fprintf(stderr, "MiNT executable, trying to load GST symbol table at offset 0x%x...\n", offset);
                    381:                return symbols_load_dri(fp, sections, tablesize);
                    382:        case 0x0:
                    383:                fprintf(stderr, "Old style excutable, loading DRI / GST symbol table at offset 0x%x.\n", offset);
                    384:                return symbols_load_dri(fp, sections, tablesize);
                    385:        default:
                    386:                fprintf(stderr, "ERROR: unknown executable type 0x%x at offset 0x%x!\n", tabletype, offset);
                    387:        }
                    388:        return NULL;
                    389: }
                    390: 
                    391: /**
                    392:  * Load symbols of given type and the symbol address addresses from
                    393:  * the given file and add given offsets to the addresses.
                    394:  * Return symbols list or NULL for failure.
                    395:  */
                    396: static symbol_list_t* symbols_load(const char *filename)
                    397: {
                    398:        symbol_list_t *list;
                    399:        uint16_t magic;
                    400:        FILE *fp;
                    401: 
                    402:        fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
                    403:        if (!(fp = fopen(filename, "r"))) {
                    404:                return usage("opening program file failed");
                    405:        }
                    406:        if (fread(&magic, sizeof(magic), 1, fp) != 1) {
                    407:                return usage("reading program file failed");
                    408:        }
                    409: 
                    410:        if (SDL_SwapBE16(magic) != 0x601A) {
                    411:                return usage("file isn't an Atari program file");
                    412:        }
                    413:        list = symbols_load_binary(fp);
                    414:        fclose(fp);
                    415: 
                    416:        if (!list) {
                    417:                return usage("no symbols, or reading them failed");
                    418:        }
                    419: 
                    420:        if (list->count < list->symbols) {
                    421:                if (!list->count) {
                    422:                        return usage("no valid symbols in program, symbol table loading failed");
                    423:                }
                    424:                /* parsed less than there were "content" lines */
                    425:                list->names = realloc(list->names, list->count * sizeof(symbol_t));
                    426:                assert(list->names);
                    427:        }
                    428: 
                    429:        /* copy name list to address list */
                    430:        list->addresses = malloc(list->count * sizeof(symbol_t));
                    431:        assert(list->addresses);
                    432:        memcpy(list->addresses, list->names, list->count * sizeof(symbol_t));
                    433: 
                    434:        /* sort both lists, with different criteria */
                    435:        qsort(list->addresses, list->count, sizeof(symbol_t), symbols_by_address);
                    436:        qsort(list->names, list->count, sizeof(symbol_t), symbols_by_name);
                    437:        return list;
                    438: }
                    439: 
                    440: 
                    441: /* ---------------- symbol showing & option parsing ------------------ */
                    442: 
                    443: /**
                    444:  * Show symbols sorted by selected option
                    445:  */
                    446: static int symbols_show(symbol_list_t* list)
                    447: {
                    448:        symbol_t *entry, *entries;
                    449:        char symchar;
                    450:        int i;
                    451:        
                    452:        if (!list) {
                    453:                fprintf(stderr, "No symbols!\n");
                    454:                return 1;
                    455:        }
                    456:        if (Options.sort_name) {
                    457:                entries = list->names;
                    458:        } else {
                    459:                entries = list->addresses;
                    460:        }
                    461:        for (entry = entries, i = 0; i < list->count; i++, entry++) {
                    462:                switch (entry->type) {
                    463:                case SYMTYPE_TEXT:
                    464:                        symchar = 'T';
                    465:                        break;
                    466:                case SYMTYPE_DATA:
                    467:                        symchar = 'D';
                    468:                        break;
                    469:                case SYMTYPE_BSS:
                    470:                        symchar = 'B';
                    471:                        break;
                    472:                default:
                    473:                        symchar = '?';
                    474:                }
                    475:                fprintf(stdout, "0x%08x %c %s\n",
                    476:                        entry->address, symchar, entry->name);
                    477:        }
                    478: 
                    479:        fprintf(stderr, "%d symbols processed.\n", list->count);
                    480:        return 0;
                    481: }
                    482: 
                    483: /**
                    484:  * parse program options and then call symbol load+save
                    485:  */
                    486: int main(int argc, const char *argv[])
                    487: {
                    488:        int i;
                    489: 
                    490:        PrgPath = *argv;
                    491:        for (i = 1; i+1 < argc; i++) {
                    492:                if (argv[i][0] != '-') {
                    493:                        break;
                    494:                }
                    495:                switch(tolower(argv[i][1])) {
                    496:                case 'n':
                    497:                        Options.sort_name = true;
                    498:                case 'b':
                    499:                        Options.notypes |= SYMTYPE_BSS;
                    500:                        break;
                    501:                case 'd':
                    502:                        Options.notypes |= SYMTYPE_DATA;
                    503:                        break;
                    504:                case 't':
                    505:                        Options.notypes |= SYMTYPE_TEXT;
                    506:                        break;
                    507:                case 'l':
                    508:                        Options.no_local = true;
                    509:                        break;
                    510:                case 'o':
                    511:                        Options.no_obj = true;
                    512:                        break;
                    513:                default:
                    514:                        usage("unknown option");
                    515:                        return 1;
                    516:                }
                    517:        }
                    518:        if (i+1 != argc) {
                    519:                usage("incorrect number of arguments");
                    520:                return 1;
                    521:        }
                    522:        return symbols_show(symbols_load(argv[i]));
                    523: }

unix.superglobalmegacorp.com

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