[BACK]Return to ctfconv.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ctfconv

Annotation of src/usr.bin/ctfconv/ctfconv.c, Revision 1.7

1.7     ! jasper      1: /*     $OpenBSD: ctfconv.c,v 1.6 2017/08/11 20:49:26 jasper Exp $ */
1.2       jasper      2:
1.1       mpi         3: /*
                      4:  * Copyright (c) 2016-2017 Martin Pieuchot
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/param.h>
                     20: #include <sys/types.h>
                     21: #include <sys/stat.h>
                     22: #include <sys/exec_elf.h>
                     23: #include <sys/mman.h>
                     24: #include <sys/queue.h>
                     25: #include <sys/tree.h>
                     26: #include <sys/ctf.h>
                     27:
                     28: #include <assert.h>
                     29: #include <err.h>
                     30: #include <fcntl.h>
                     31: #include <locale.h>
                     32: #include <stdio.h>
                     33: #include <stdint.h>
                     34: #include <stdlib.h>
                     35: #include <string.h>
                     36: #include <unistd.h>
                     37:
                     38: #include "itype.h"
                     39: #include "xmalloc.h"
                     40:
                     41: #ifndef nitems
                     42: #define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
                     43: #endif
                     44:
                     45: #define DEBUG_ABBREV   ".debug_abbrev"
                     46: #define DEBUG_INFO     ".debug_info"
                     47: #define DEBUG_LINE     ".debug_line"
                     48: #define DEBUG_STR      ".debug_str"
                     49:
                     50: __dead void     usage(void);
                     51: int             convert(const char *);
                     52: int             generate(const char *, const char *, int);
                     53: int             elf_convert(char *, size_t);
                     54: void            elf_sort(void);
                     55: void            dump_type(struct itype *);
                     56: void            dump_func(struct itype *, int *);
                     57: void            dump_obj(struct itype *, int *);
                     58:
                     59: /* elf.c */
                     60: int             iself(const char *, size_t);
                     61: int             elf_getshstab(const char *, size_t, const char **, size_t *);
                     62: ssize_t                 elf_getsymtab(const char *, const char *, size_t,
                     63:                     const Elf_Sym **, size_t *);
                     64: ssize_t                 elf_getsection(char *, const char *, const char *,
                     65:                     size_t, const char **, size_t *);
                     66:
                     67: /* parse.c */
                     68: void            dwarf_parse(const char *, size_t, const char *, size_t);
                     69:
                     70: const char     *ctf_enc2name(unsigned short);
                     71:
                     72: /* lists of parsed types and functions */
                     73: struct itype_queue itypeq = TAILQ_HEAD_INITIALIZER(itypeq);
                     74: struct itype_queue ifuncq = TAILQ_HEAD_INITIALIZER(ifuncq);
                     75: struct itype_queue iobjq = TAILQ_HEAD_INITIALIZER(iobjq);
                     76:
                     77: __dead void
                     78: usage(void)
                     79: {
1.7     ! jasper     80:        fprintf(stderr, "usage: %s [-d] -l label -o outfile file\n",
1.1       mpi        81:            getprogname());
                     82:        exit(1);
                     83: }
                     84:
                     85: int
                     86: main(int argc, char *argv[])
                     87: {
                     88:        const char *filename, *label = NULL, *outfile = NULL;
                     89:        int dump = 0;
                     90:        int ch, error = 0;
                     91:        struct itype *it;
                     92:
                     93:        setlocale(LC_ALL, "");
                     94:
1.6       jasper     95:        if (pledge("stdio rpath wpath cpath", NULL) == -1)
                     96:                err(1, "pledge");
                     97:
1.1       mpi        98:        while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
                     99:                switch (ch) {
                    100:                case 'd':
1.5       jasper    101:                        dump = 1;       /* ctfdump(1)-like SUNW_ctf sections */
1.1       mpi       102:                        break;
                    103:                case 'l':
                    104:                        if (label != NULL)
                    105:                                usage();
                    106:                        label = optarg;
                    107:                        break;
                    108:                case 'o':
                    109:                        if (outfile != NULL)
                    110:                                usage();
                    111:                        outfile = optarg;
                    112:                        break;
                    113:                default:
                    114:                        usage();
                    115:                }
                    116:        }
                    117:
                    118:        argc -= optind;
                    119:        argv += optind;
                    120:
                    121:        if (argc != 1)
                    122:                usage();
                    123:
1.5       jasper    124:        /* Either dump the sections, or write it out. */
                    125:        if ((dump && (outfile != NULL || label != NULL)) ||
                    126:            (!dump && (outfile == NULL || label == NULL)))
1.1       mpi       127:                usage();
                    128:
                    129:        filename = *argv;
                    130:        error = convert(filename);
                    131:        if (error != 0)
                    132:                return error;
                    133:
1.6       jasper    134:        if (outfile != NULL) {
                    135:                if (pledge("stdio wpath cpath", NULL) == -1)
                    136:                        err(1, "pledge");
                    137:
                    138:                error = generate(outfile, label, 1);
                    139:                if (error != 0)
                    140:                        return error;
                    141:        }
                    142:
1.1       mpi       143:        if (dump) {
1.6       jasper    144:                if (pledge("stdio", NULL) == -1)
                    145:                        err(1, "pledge");
                    146:
1.1       mpi       147:                int fidx = -1, oidx = -1;
                    148:
                    149:                TAILQ_FOREACH(it, &iobjq, it_symb)
                    150:                        dump_obj(it, &oidx);
                    151:                printf("\n");
                    152:
                    153:                TAILQ_FOREACH(it, &ifuncq, it_symb)
                    154:                        dump_func(it, &fidx);
                    155:                printf("\n");
                    156:
                    157:                TAILQ_FOREACH(it, &itypeq, it_next) {
                    158:                        if (it->it_flags & (ITF_FUNC|ITF_OBJ))
                    159:                                continue;
                    160:
                    161:                        dump_type(it);
                    162:                }
1.5       jasper    163:
                    164:                return 0;
1.1       mpi       165:        }
                    166:
                    167:        return 0;
                    168: }
                    169:
                    170: int
                    171: convert(const char *path)
                    172: {
                    173:        struct stat              st;
                    174:        int                      fd, error = 1;
                    175:        char                    *p;
                    176:
                    177:        fd = open(path, O_RDONLY);
                    178:        if (fd == -1) {
                    179:                warn("open %s", path);
                    180:                return 1;
                    181:        }
                    182:        if (fstat(fd, &st) == -1) {
                    183:                warn("fstat %s", path);
                    184:                return 1;
                    185:        }
                    186:        if ((uintmax_t)st.st_size > SIZE_MAX) {
                    187:                warnx("file too big to fit memory");
                    188:                return 1;
                    189:        }
                    190:
                    191:        p = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
                    192:        if (p == MAP_FAILED)
                    193:                err(1, "mmap");
                    194:
                    195:        if (iself(p, st.st_size))
                    196:                error = elf_convert(p, st.st_size);
                    197:
                    198:        munmap(p, st.st_size);
                    199:        close(fd);
                    200:
                    201:        return error;
                    202: }
                    203:
                    204: const char             *dstrbuf;
                    205: size_t                  dstrlen;
                    206: const char             *strtab;
                    207: const Elf_Sym          *symtab;
                    208: size_t                  strtabsz, nsymb;
                    209:
                    210: int
                    211: elf_convert(char *p, size_t filesize)
                    212: {
                    213:        const char              *shstab;
                    214:        const char              *infobuf, *abbuf;
                    215:        size_t                   infolen, ablen;
                    216:        size_t                   shstabsz;
                    217:
                    218:        /* Find section header string table location and size. */
                    219:        if (elf_getshstab(p, filesize, &shstab, &shstabsz))
                    220:                return 1;
                    221:
                    222:        /* Find symbol table location and number of symbols. */
                    223:        if (elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb) == -1)
                    224:                warnx("symbol table not found");
                    225:
                    226:        /* Find string table location and size. */
                    227:        if (elf_getsection(p, ELF_STRTAB, shstab, shstabsz, &strtab,
                    228:            &strtabsz) == -1)
                    229:                warnx("string table not found");
                    230:
                    231:        /* Find abbreviation location and size. */
                    232:        if (elf_getsection(p, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
                    233:            &ablen) == -1) {
                    234:                warnx("%s section not found", DEBUG_ABBREV);
                    235:                return 1;
                    236:        }
                    237:
                    238:        if (elf_getsection(p, DEBUG_INFO, shstab, shstabsz, &infobuf,
                    239:            &infolen) == -1) {
                    240:                warnx("%s section not found", DEBUG_INFO);
                    241:                return 1;
                    242:        }
                    243:
                    244:        /* Find string table location and size. */
                    245:        if (elf_getsection(p, DEBUG_STR, shstab, shstabsz, &dstrbuf,
                    246:            &dstrlen) == -1)
                    247:                warnx("%s section not found", DEBUG_STR);
                    248:
                    249:        dwarf_parse(infobuf, infolen, abbuf, ablen);
                    250:
                    251:        /* Sort functions */
                    252:        elf_sort();
                    253:
                    254:        return 0;
                    255: }
                    256:
                    257: void
                    258: elf_sort(void)
                    259: {
                    260:        struct itype            *it, tmp;
                    261:        size_t                   i;
                    262:
                    263:        memset(&tmp, 0, sizeof(tmp));
                    264:        for (i = 0; i < nsymb; i++) {
                    265:                const Elf_Sym   *st = &symtab[i];
                    266:                char            *sname;
                    267:
                    268:                if (st->st_shndx == SHN_UNDEF || st->st_shndx == SHN_COMMON)
                    269:                        continue;
                    270:
                    271:                switch (ELF_ST_TYPE(st->st_info)) {
                    272:                case STT_FUNC:
                    273:                        tmp.it_flags = ITF_FUNC;
                    274:                        break;
                    275:                case STT_OBJECT:
                    276:                        tmp.it_flags = ITF_OBJ;
                    277:                        break;
                    278:                default:
                    279:                        continue;
                    280:                }
                    281:
                    282:                /*
                    283:                 * Skip local suffix
                    284:                 *
                    285:                 * FIXME: only skip local copies.
                    286:                 */
                    287:                sname = xstrdup(strtab + st->st_name);
                    288:                strlcpy(tmp.it_name, strtok(sname, "."), ITNAME_MAX);
                    289:                it = RB_FIND(isymb_tree, &isymbt, &tmp);
                    290:                strlcpy(tmp.it_name, (strtab + st->st_name), ITNAME_MAX);
                    291:                free(sname);
                    292:
                    293:                if (it == NULL) {
                    294:                        /* Insert 'unknown' entry to match symbol order. */
                    295:                        it = it_dup(&tmp);
                    296:                        it->it_refp = it;
                    297: #ifdef DEBUG
                    298:                        warnx("symbol not found: %s", it_name(it));
                    299: #endif
                    300:                }
                    301:
                    302:                if (it->it_flags & ITF_INSERTED) {
                    303: #ifdef DEBUG
                    304:                        warnx("%s: already inserted", it_name(it));
                    305: #endif
                    306:                        it = it_dup(it);
                    307:                }
                    308:
                    309:                /* Save symbol index for dump. */
                    310:                it->it_ref = i;
                    311:
                    312:                it->it_flags |= ITF_INSERTED;
                    313:                if (it->it_flags & ITF_FUNC)
                    314:                        TAILQ_INSERT_TAIL(&ifuncq, it, it_symb);
                    315:                else
                    316:                        TAILQ_INSERT_TAIL(&iobjq, it, it_symb);
                    317:        }
                    318: }
                    319:
                    320: const char *
                    321: type_name(struct itype *it)
                    322: {
                    323:        const char *name;
                    324:
                    325:        name = it_name(it);
                    326:        if (name == NULL)
                    327:                return "(anon)";
                    328:
                    329:        return name;
                    330: }
                    331:
                    332: /* Display parsed types a la ctfdump(1) */
                    333: void
                    334: dump_type(struct itype *it)
                    335: {
                    336:        struct imember *im;
                    337:
                    338: #ifdef DEBUG
                    339:        switch (it->it_type) {
                    340:        case CTF_K_POINTER:
                    341:        case CTF_K_TYPEDEF:
                    342:        case CTF_K_VOLATILE:
                    343:        case CTF_K_CONST:
                    344:        case CTF_K_RESTRICT:
                    345:        case CTF_K_ARRAY:
                    346:        case CTF_K_FUNCTION:
                    347:                if (it->it_refp == NULL) {
                    348:                        printf("unresolved: %s type=%d\n", it_name(it),
                    349:                            it->it_type);
                    350:                        return;
                    351:                }
                    352:        default:
                    353:                break;
                    354:        }
                    355: #endif
                    356:
                    357:        switch (it->it_type) {
                    358:        case CTF_K_FLOAT:
                    359:        case CTF_K_INTEGER:
                    360:                printf("  [%u] %s %s encoding=%s offset=0 bits=%u\n",
                    361:                    it->it_idx,
                    362:                    (it->it_type == CTF_K_INTEGER) ? "INTEGER" : "FLOAT",
                    363:                    it_name(it), ctf_enc2name(it->it_enc), it->it_size);
                    364:                break;
                    365:        case CTF_K_POINTER:
                    366:                printf("  <%u> POINTER %s refers to %u\n", it->it_idx,
                    367:                    type_name(it), it->it_refp->it_idx);
                    368:                break;
                    369:        case CTF_K_TYPEDEF:
                    370:                printf("  <%u> TYPEDEF %s refers to %u\n",
                    371:                    it->it_idx, it_name(it), it->it_refp->it_idx);
                    372:                break;
                    373:        case CTF_K_VOLATILE:
                    374:                printf("  <%u> VOLATILE %s refers to %u\n", it->it_idx,
                    375:                    type_name(it), it->it_refp->it_idx);
                    376:                break;
                    377:        case CTF_K_CONST:
                    378:                printf("  <%u> CONST %s refers to %u\n", it->it_idx,
                    379:                    type_name(it), it->it_refp->it_idx);
                    380:                break;
                    381:        case CTF_K_RESTRICT:
                    382:                printf("  <%u> RESTRICT %s refers to %u\n", it->it_idx,
                    383:                    it_name(it), it->it_refp->it_idx);
                    384:                break;
                    385:        case CTF_K_ARRAY:
                    386:                printf("  [%u] ARRAY %s content: %u index: %u nelems: %u\n",
                    387:                    it->it_idx, type_name(it), it->it_refp->it_idx, long_tidx,
                    388:                    it->it_nelems);
                    389:                printf("\n");
                    390:                break;
                    391:        case CTF_K_STRUCT:
                    392:        case CTF_K_UNION:
                    393:                printf("  [%u] %s %s (%u bytes)\n", it->it_idx,
                    394:                    (it->it_type == CTF_K_STRUCT) ? "STRUCT" : "UNION",
                    395:                    type_name(it), it->it_size);
                    396:                TAILQ_FOREACH(im, &it->it_members, im_next) {
                    397:                        printf("\t%s type=%u off=%zd\n",
1.3       mpi       398:                            (im_name(im) == NULL) ? "unknown" : im_name(im),
1.4       mpi       399:                            im->im_refp ? im->im_refp->it_idx : 0, im->im_off);
1.1       mpi       400:                }
                    401:                printf("\n");
                    402:                break;
                    403:        case CTF_K_ENUM:
                    404:                printf("  [%u] ENUM %s\n\n", it->it_idx, type_name(it));
                    405:                break;
                    406:        case CTF_K_FUNCTION:
                    407:                printf("  [%u] FUNCTION (%s) returns: %u args: (",
                    408:                    it->it_idx, (it_name(it) != NULL) ? it_name(it) : "anon",
                    409:                    it->it_refp->it_idx);
                    410:                TAILQ_FOREACH(im, &it->it_members, im_next) {
                    411:                        printf("%u%s", im->im_refp->it_idx,
                    412:                            TAILQ_NEXT(im, im_next) ? ", " : "");
                    413:                }
                    414:                printf(")\n");
                    415:                break;
                    416:        default:
                    417:                assert(0 == 1);
                    418:        }
                    419: }
                    420:
                    421: void
                    422: dump_func(struct itype *it, int *idx)
                    423: {
                    424:        struct imember *im;
                    425:
                    426:        (*idx)++;
                    427:
                    428:        if (it->it_type == CTF_K_UNKNOWN && it->it_nelems == 0)
                    429:                return;
                    430:
                    431:        printf("  [%u] FUNC (%s) returns: %u args: (", (*idx),
                    432:            (it_name(it) != NULL) ? it_name(it) : "unknown",
                    433:            it->it_refp->it_idx);
                    434:        TAILQ_FOREACH(im, &it->it_members, im_next) {
                    435:                printf("%u%s", im->im_refp->it_idx,
                    436:                    TAILQ_NEXT(im, im_next) ? ", " : "");
                    437:        }
                    438:        printf(")\n");
                    439: }
                    440:
                    441: void
                    442: dump_obj(struct itype *it, int *idx)
                    443: {
                    444:        int l;
                    445:
                    446:        (*idx)++;
                    447:
                    448:        l = printf("  [%u] %u", (*idx), it->it_refp->it_idx);
                    449:        printf("%*s %s (%llu)\n", 14 - l, "", it_name(it), it->it_ref);
                    450: }
                    451:
                    452: const char *
                    453: ctf_enc2name(unsigned short enc)
                    454: {
                    455:        static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
                    456:            "BOOL", "SIGNED BOOL" };
                    457:        static char invalid[7];
                    458:
                    459:        if (enc == CTF_INT_VARARGS)
                    460:                return "VARARGS";
                    461:
                    462:        if (enc > 0 && enc < nitems(enc_name))
                    463:                return enc_name[enc - 1];
                    464:
                    465:        snprintf(invalid, sizeof(invalid), "0x%x", enc);
                    466:        return invalid;
                    467: }