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

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

1.7     ! anton       1: /*     $OpenBSD: generate.c,v 1.6 2024/02/22 13:15:17 claudio Exp $ */
1.2       jasper      2:
1.1       mpi         3: /*
                      4:  * Copyright (c) 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/types.h>
                     20: #include <sys/queue.h>
                     21: #include <sys/tree.h>
                     22: #include <sys/ctf.h>
                     23:
                     24: #include <assert.h>
                     25: #include <err.h>
                     26: #include <fcntl.h>
                     27: #include <string.h>
                     28: #include <stdlib.h>
                     29: #include <stddef.h>
                     30: #include <stdint.h>
                     31: #include <unistd.h>
                     32:
                     33: #ifdef ZLIB
                     34: #include <zlib.h>
                     35: #endif /* ZLIB */
                     36:
                     37: #include "itype.h"
                     38: #include "xmalloc.h"
                     39: #include "hash.h"
                     40:
                     41: #define ROUNDUP(x, y) ((((x) + (y) - 1) / (y)) * (y))
                     42:
                     43: /*
                     44:  * Dynamic buffer, used for content & string table.
                     45:  */
                     46: struct dbuf {
                     47:        char            *data;  /* start data buffer */
                     48:        size_t           size;  /* size of the buffer */
                     49:
                     50:        char            *cptr; /* position in [data, data + size] */
                     51:        size_t           coff; /* number of written bytes */
                     52: };
                     53:
                     54: #define DBUF_CHUNKSZ   (64 * 1024)
                     55:
                     56: /* In-memory representation of a CTF section. */
                     57: struct imcs {
                     58:        struct dbuf      body;
                     59:        struct dbuf      stab;  /* corresponding string table */
                     60:        struct hash     *htab;  /* hash table of known strings */
                     61: };
                     62:
                     63: struct strentry {
                     64:        struct hash_entry se_key;       /* Must be first */
                     65: #define se_str se_key.hkey
                     66:        size_t           se_off;
                     67: };
                     68:
                     69: #ifdef ZLIB
1.5       millert    70: char           *data_compress(const char *, size_t, size_t, size_t *);
1.1       mpi        71: #endif /* ZLIB */
                     72:
                     73: void
                     74: dbuf_realloc(struct dbuf *dbuf, size_t len)
                     75: {
                     76:        assert(dbuf != NULL);
                     77:        assert(len != 0);
                     78:
                     79:        dbuf->data = xrealloc(dbuf->data, dbuf->size + len);
                     80:        dbuf->size += len;
                     81:        dbuf->cptr = dbuf->data + dbuf->coff;
                     82: }
                     83:
                     84: void
                     85: dbuf_copy(struct dbuf *dbuf, void const *data, size_t len)
                     86: {
1.5       millert    87:        size_t left;
1.1       mpi        88:
                     89:        assert(dbuf->cptr != NULL);
                     90:        assert(dbuf->data != NULL);
                     91:        assert(dbuf->size != 0);
                     92:
                     93:        if (len == 0)
                     94:                return;
                     95:
                     96:        left = dbuf->size - dbuf->coff;
1.5       millert    97:        if (left < len)
1.1       mpi        98:                dbuf_realloc(dbuf, ROUNDUP((len - left), DBUF_CHUNKSZ));
                     99:
                    100:        memcpy(dbuf->cptr, data, len);
                    101:        dbuf->cptr += len;
                    102:        dbuf->coff += len;
                    103: }
                    104:
                    105: size_t
                    106: dbuf_pad(struct dbuf *dbuf, int align)
                    107: {
                    108:        int i = (align - (dbuf->coff % align)) % align;
                    109:
                    110:        while (i-- > 0)
                    111:                dbuf_copy(dbuf, "", 1);
                    112:
                    113:        return dbuf->coff;
                    114: }
                    115:
                    116: size_t
                    117: imcs_add_string(struct imcs *imcs, const char *str)
                    118: {
                    119:        struct strentry *se;
                    120:        unsigned int slot;
                    121:
                    122:        if (str == NULL || *str == '\0')
                    123:                return 0;
                    124:
                    125:        se = (struct strentry *)hash_find(imcs->htab, str, &slot);
                    126:        if (se == NULL) {
                    127:                se = xmalloc(sizeof(*se));
                    128:                hash_insert(imcs->htab, slot, &se->se_key, str);
                    129:                se->se_off = imcs->stab.coff;
                    130:
                    131:                dbuf_copy(&imcs->stab, str, strlen(str) + 1);
                    132:        }
                    133:
                    134:        return se->se_off;
                    135: }
                    136:
                    137: void
                    138: imcs_add_func(struct imcs *imcs, struct itype *it)
                    139: {
                    140:        uint16_t                 func, arg;
                    141:        struct imember          *im;
                    142:        int                      kind, root, vlen;
                    143:
                    144:        vlen = it->it_nelems;
                    145:        kind = it->it_type;
                    146:        root = 0;
                    147:
                    148:        func = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN);
                    149:        dbuf_copy(&imcs->body, &func, sizeof(func));
                    150:
                    151:        if (kind == CTF_K_UNKNOWN)
                    152:                return;
                    153:
                    154:        func = it->it_refp->it_idx;
                    155:        dbuf_copy(&imcs->body, &func, sizeof(func));
                    156:
                    157:        TAILQ_FOREACH(im, &it->it_members, im_next) {
                    158:                arg = im->im_refp->it_idx;
                    159:                dbuf_copy(&imcs->body, &arg, sizeof(arg));
                    160:        }
                    161: }
                    162:
                    163: void
                    164: imcs_add_obj(struct imcs *imcs, struct itype *it)
                    165: {
                    166:        uint16_t                 type;
                    167:
                    168:        type = it->it_refp->it_idx;
                    169:        dbuf_copy(&imcs->body, &type, sizeof(type));
                    170: }
                    171:
                    172: void
                    173: imcs_add_type(struct imcs *imcs, struct itype *it)
                    174: {
                    175:        struct imember          *im;
                    176:        struct ctf_type          ctt;
                    177:        struct ctf_array         cta;
                    178:        unsigned int             eob;
                    179:        uint32_t                 size;
                    180:        uint16_t                 arg;
                    181:        size_t                   ctsz;
                    182:        int                      kind, root, vlen;
                    183:
                    184:        assert(it->it_type != CTF_K_UNKNOWN && it->it_type != CTF_K_FORWARD);
                    185:
                    186:        vlen = it->it_nelems;
                    187:        size = it->it_size;
                    188:        kind = it->it_type;
                    189:        root = 0;
                    190:
                    191:        ctt.ctt_name = imcs_add_string(imcs, it_name(it));
                    192:        ctt.ctt_info = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN);
                    193:
                    194:        /* Base types don't have reference, typedef & pointer don't have size */
                    195:        if (it->it_refp != NULL && kind != CTF_K_ARRAY) {
                    196:                ctt.ctt_type = it->it_refp->it_idx;
                    197:                ctsz = sizeof(struct ctf_stype);
                    198:        } else if (size <= CTF_MAX_SIZE) {
1.6       claudio   199:                if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) {
1.7     ! anton     200:                        assert(size <= 128);
1.6       claudio   201:                        if (size == 0)
                    202:                                ctt.ctt_size = 0;
                    203:                        else if (size <= 8)
                    204:                                ctt.ctt_size = 1;
                    205:                        else if (size <= 16)
                    206:                                ctt.ctt_size = 2;
                    207:                        else if (size <= 32)
                    208:                                ctt.ctt_size = 4;
1.7     ! anton     209:                        else if (size <= 64)
        !           210:                                ctt.ctt_size = 8;
1.6       claudio   211:                        else
1.7     ! anton     212:                                ctt.ctt_size = 16;
1.6       claudio   213:                } else
                    214:                        ctt.ctt_size = size;
1.1       mpi       215:                ctsz = sizeof(struct ctf_stype);
                    216:        } else {
                    217:                ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
                    218:                ctt.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
                    219:                ctt.ctt_size = CTF_LSIZE_SENT;
                    220:                ctsz = sizeof(struct ctf_type);
                    221:        }
                    222:
                    223:        dbuf_copy(&imcs->body, &ctt, ctsz);
                    224:
                    225:        switch (kind) {
                    226:                assert(1 == 0);
                    227:                break;
                    228:        case CTF_K_INTEGER:
                    229:        case CTF_K_FLOAT:
                    230:                eob = CTF_INT_DATA(it->it_enc, 0, size);
                    231:                dbuf_copy(&imcs->body, &eob, sizeof(eob));
                    232:                break;
                    233:        case CTF_K_ARRAY:
                    234:                memset(&cta, 0, sizeof(cta));
                    235:                cta.cta_contents = it->it_refp->it_idx;
                    236:                cta.cta_index = long_tidx;
                    237:                cta.cta_nelems = it->it_nelems;
                    238:                dbuf_copy(&imcs->body, &cta, sizeof(cta));
                    239:                break;
                    240:        case CTF_K_STRUCT:
                    241:        case CTF_K_UNION:
                    242:                if (size < CTF_LSTRUCT_THRESH) {
                    243:                        struct ctf_member        ctm;
                    244:
                    245:                        memset(&ctm, 0, sizeof(ctm));
                    246:                        TAILQ_FOREACH(im, &it->it_members, im_next) {
                    247:                                ctm.ctm_name =
1.3       mpi       248:                                    imcs_add_string(imcs, im_name(im));
1.1       mpi       249:                                ctm.ctm_type = im->im_refp->it_idx;
                    250:                                ctm.ctm_offset = im->im_off;
                    251:
                    252:                                dbuf_copy(&imcs->body, &ctm, sizeof(ctm));
                    253:                        }
                    254:                } else {
                    255:                        struct ctf_lmember       ctlm;
                    256:
                    257:                        memset(&ctlm, 0, sizeof(ctlm));
                    258:                        TAILQ_FOREACH(im, &it->it_members, im_next) {
                    259:                                ctlm.ctlm_name =
1.3       mpi       260:                                    imcs_add_string(imcs, im_name(im));
1.1       mpi       261:                                ctlm.ctlm_type = im->im_refp->it_idx;
                    262:                                ctlm.ctlm_offsethi =
                    263:                                    CTF_OFFSET_TO_LMEMHI(im->im_off);
                    264:                                ctlm.ctlm_offsetlo =
                    265:                                    CTF_OFFSET_TO_LMEMLO(im->im_off);
                    266:
                    267:
                    268:                                dbuf_copy(&imcs->body, &ctlm, sizeof(ctlm));
                    269:                        }
                    270:                }
                    271:                break;
                    272:        case CTF_K_FUNCTION:
                    273:                TAILQ_FOREACH(im, &it->it_members, im_next) {
                    274:                        arg = im->im_refp->it_idx;
                    275:                        dbuf_copy(&imcs->body, &arg, sizeof(arg));
                    276:                }
                    277:                if (vlen & 1) {
                    278:                        arg = 0;
                    279:                        dbuf_copy(&imcs->body, &arg, sizeof(arg));
                    280:                }
                    281:                break;
                    282:        case CTF_K_ENUM:
                    283:                TAILQ_FOREACH(im, &it->it_members, im_next) {
                    284:                        struct ctf_enum cte;
                    285:
1.3       mpi       286:                        cte.cte_name = imcs_add_string(imcs, im_name(im));
1.1       mpi       287:                        cte.cte_value = im->im_ref;
                    288:
                    289:                        dbuf_copy(&imcs->body, &cte, sizeof(cte));
                    290:                }
                    291:                break;
                    292:        case CTF_K_POINTER:
                    293:        case CTF_K_TYPEDEF:
                    294:        case CTF_K_VOLATILE:
                    295:        case CTF_K_CONST:
                    296:        case CTF_K_RESTRICT:
                    297:        default:
                    298:                break;
                    299:        }
                    300: }
                    301:
                    302: void
                    303: imcs_generate(struct imcs *imcs, struct ctf_header *cth, const char *label)
                    304: {
                    305:        struct itype            *it;
                    306:        struct ctf_lblent        lbl;
                    307:
                    308:        memset(imcs, 0, sizeof(*imcs));
                    309:
                    310:        dbuf_realloc(&imcs->body, DBUF_CHUNKSZ);
                    311:        dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ);
                    312:
                    313:        imcs->htab = hash_init(10);
                    314:        if (imcs->htab == NULL)
                    315:                err(1, "hash_init");
                    316:
                    317:        /* Add empty string */
                    318:        dbuf_copy(&imcs->stab, "", 1);
                    319:
                    320:        /* We don't use parent label */
                    321:        cth->cth_parlabel = 0;
                    322:        cth->cth_parname = 0;
                    323:
                    324:        /* Insert a single label for all types. */
                    325:        cth->cth_lbloff = 0;
                    326:        lbl.ctl_label = imcs_add_string(imcs, label);
                    327:        lbl.ctl_typeidx = tidx;
                    328:        dbuf_copy(&imcs->body, &lbl, sizeof(lbl));
                    329:
                    330:        /* Insert objects */
                    331:        cth->cth_objtoff = dbuf_pad(&imcs->body, 2);
                    332:        TAILQ_FOREACH(it, &iobjq, it_symb)
                    333:                imcs_add_obj(imcs, it);
                    334:
                    335:        /* Insert functions */
                    336:        cth->cth_funcoff = dbuf_pad(&imcs->body, 2);
                    337:        TAILQ_FOREACH(it, &ifuncq, it_symb)
                    338:                imcs_add_func(imcs, it);
                    339:
                    340:        /* Insert types */
                    341:        cth->cth_typeoff = dbuf_pad(&imcs->body, 4);
                    342:        TAILQ_FOREACH(it, &itypeq, it_next) {
                    343:                if (it->it_flags & (ITF_FUNC|ITF_OBJ))
                    344:                        continue;
                    345:
                    346:                imcs_add_type(imcs, it);
                    347:        }
                    348:
                    349:        /* String table is written from its own buffer. */
                    350:        cth->cth_stroff = imcs->body.coff;
                    351:        cth->cth_strlen = imcs->stab.coff;
                    352: }
                    353:
                    354: /*
                    355:  * Generate a CTF buffer from the internal type representation.
                    356:  */
                    357: int
                    358: generate(const char *path, const char *label, int compress)
                    359: {
                    360:        char                    *p, *ctfdata = NULL;
                    361:        ssize_t                  ctflen;
                    362:        struct ctf_header        cth;
                    363:        struct imcs              imcs;
1.4       mpi       364:        int                      error = 0, fd;
1.1       mpi       365:
                    366:        memset(&cth, 0, sizeof(cth));
                    367:
                    368:        cth.cth_magic = CTF_MAGIC;
                    369:        cth.cth_version = CTF_VERSION;
                    370:
                    371: #ifdef ZLIB
                    372:        if (compress)
                    373:                cth.cth_flags = CTF_F_COMPRESS;
                    374: #endif /* ZLIB */
                    375:
                    376:        imcs_generate(&imcs, &cth, label);
                    377:
                    378:        ctflen = sizeof(cth) + imcs.body.coff + imcs.stab.coff;
                    379:        p = ctfdata = xmalloc(ctflen);
                    380:
                    381:        memcpy(p, &cth, sizeof(cth));
                    382:        p += sizeof(cth);
                    383:
                    384:        memcpy(p, imcs.body.data, imcs.body.coff);
                    385:        p += imcs.body.coff;
                    386:
                    387:        memcpy(p, imcs.stab.data, imcs.stab.coff);
                    388:        p += imcs.stab.coff;
                    389:
                    390:        assert((p - ctfdata) == ctflen);
                    391:
                    392: #ifdef ZLIB
                    393:        if (compress) {
                    394:                char *cdata;
                    395:                size_t clen;
                    396:
                    397:                cdata = data_compress(ctfdata + sizeof(cth),
                    398:                    ctflen - sizeof(cth), ctflen - sizeof(cth), &clen);
                    399:                if (cdata == NULL) {
                    400:                        warnx("compressing CTF data");
                    401:                        free(ctfdata);
                    402:                        return -1;
                    403:                }
                    404:
                    405:                memcpy(ctfdata + sizeof(cth), cdata, clen);
                    406:                ctflen = clen + sizeof(cth);
                    407:
                    408:                free(cdata);
                    409:        }
                    410: #endif /* ZLIB */
                    411:
                    412:        fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
                    413:        if (fd == -1) {
                    414:                warn("open %s", path);
                    415:                free(ctfdata);
                    416:                return -1;
                    417:        }
                    418:
                    419:        if (write(fd, ctfdata, ctflen) != ctflen) {
                    420:                warn("unable to write %zd bytes for %s", ctflen, path);
                    421:                error = -1;
                    422:        }
                    423:
                    424:        close(fd);
                    425:        free(ctfdata);
1.4       mpi       426:        return error;
1.1       mpi       427: }
                    428:
                    429: #ifdef ZLIB
                    430: char *
1.5       millert   431: data_compress(const char *buf, size_t size, size_t len, size_t *pclen)
1.1       mpi       432: {
                    433:        z_stream                 stream;
                    434:        char                    *data;
                    435:        int                      error;
                    436:
                    437:        data = malloc(len);
                    438:        if (data == NULL) {
                    439:                warn(NULL);
                    440:                return NULL;
                    441:        }
                    442:
                    443:        memset(&stream, 0, sizeof(stream));
                    444:        stream.zalloc = Z_NULL;
                    445:        stream.zfree = Z_NULL;
                    446:        stream.opaque = Z_NULL;
                    447:
                    448:        if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)) != Z_OK) {
                    449:                warnx("zlib deflateInit failed: %s", zError(error));
                    450:                goto exit;
                    451:        }
                    452:
                    453:        stream.next_in = (void *)buf;
                    454:        stream.avail_in = size;
                    455:        stream.next_out = (unsigned char *)data;
                    456:        stream.avail_out = len;
                    457:
                    458:        if ((error = deflate(&stream, Z_FINISH)) != Z_STREAM_END) {
                    459:                warnx("zlib deflate failed: %s", zError(error));
                    460:                deflateEnd(&stream);
                    461:                goto exit;
                    462:        }
                    463:
                    464:        if ((error = deflateEnd(&stream)) != Z_OK) {
                    465:                warnx("zlib deflateEnd failed: %s", zError(error));
                    466:                goto exit;
                    467:        }
                    468:
                    469:        if (pclen != NULL)
                    470:                *pclen = stream.total_out;
                    471:
                    472:        return data;
                    473:
                    474: exit:
                    475:        free(data);
                    476:        return NULL;
                    477: }
                    478: #endif /* ZLIB */