Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
39586 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/20/*21* Copyright 2009 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/2425/*26* Create and parse buffers containing CTF data.27*/2829#include <sys/types.h>30#include <stdio.h>31#include <stdlib.h>32#include <strings.h>33#include <ctype.h>34#include <zlib.h>35#include <elf.h>3637#include "ctf_headers.h"38#include "ctftools.h"39#include "strtab.h"40#include "memory.h"4142/*43* Name of the file currently being read, used to print error messages. We44* assume that only one file will be read at a time, and thus make no attempt45* to allow curfile to be used simultaneously by multiple threads.46*47* The value is only valid during a call to ctf_load.48*/49static char *curfile;5051#define CTF_BUF_CHUNK_SIZE (64 * 1024)52#define RES_BUF_CHUNK_SIZE (64 * 1024)5354struct ctf_buf {55strtab_t ctb_strtab; /* string table */56caddr_t ctb_base; /* pointer to base of buffer */57caddr_t ctb_end; /* pointer to end of buffer */58caddr_t ctb_ptr; /* pointer to empty buffer space */59size_t ctb_size; /* size of buffer */60uint_t nptent; /* number of processed types */61};6263/*64* Macros to reverse byte order65*/66#define BSWAP_8(x) ((x) & 0xff)67#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))68#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))6970#define SWAP_16(x) (x) = BSWAP_16(x)71#define SWAP_32(x) (x) = BSWAP_32(x)7273static int target_requires_swap;7475/*PRINTFLIKE1*/76static void77parseterminate(const char *fmt, ...)78{79static char msgbuf[1024]; /* sigh */80va_list ap;8182va_start(ap, fmt);83vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap);84va_end(ap);8586terminate("%s: %s\n", curfile, msgbuf);87}8889static void90ctf_buf_grow(ctf_buf_t *b)91{92off_t ptroff = b->ctb_ptr - b->ctb_base;9394b->ctb_size += CTF_BUF_CHUNK_SIZE;95b->ctb_base = xrealloc(b->ctb_base, b->ctb_size);96b->ctb_end = b->ctb_base + b->ctb_size;97b->ctb_ptr = b->ctb_base + ptroff;98}99100static ctf_buf_t *101ctf_buf_new(void)102{103ctf_buf_t *b = xcalloc(sizeof (ctf_buf_t));104105strtab_create(&b->ctb_strtab);106ctf_buf_grow(b);107108return (b);109}110111static void112ctf_buf_free(ctf_buf_t *b)113{114strtab_destroy(&b->ctb_strtab);115free(b->ctb_base);116free(b);117}118119static uint_t120ctf_buf_cur(ctf_buf_t *b)121{122return (b->ctb_ptr - b->ctb_base);123}124125static void126ctf_buf_write(ctf_buf_t *b, void const *p, size_t n)127{128size_t len;129130while (n != 0) {131if (b->ctb_ptr == b->ctb_end)132ctf_buf_grow(b);133134len = MIN((size_t)(b->ctb_end - b->ctb_ptr), n);135bcopy(p, b->ctb_ptr, len);136b->ctb_ptr += len;137138p = (char const *)p + len;139n -= len;140}141}142143static int144write_label(void *arg1, void *arg2)145{146labelent_t *le = arg1;147ctf_buf_t *b = arg2;148ctf_lblent_t ctl;149150ctl.ctl_label = strtab_insert(&b->ctb_strtab, le->le_name);151ctl.ctl_typeidx = le->le_idx;152153if (target_requires_swap) {154SWAP_32(ctl.ctl_label);155SWAP_32(ctl.ctl_typeidx);156}157158ctf_buf_write(b, &ctl, sizeof (ctl));159160return (1);161}162163static void164write_objects(iidesc_t *idp, ctf_buf_t *b)165{166uint_t id = (idp ? idp->ii_dtype->t_id : 0);167168if (target_requires_swap) {169SWAP_32(id);170}171172ctf_buf_write(b, &id, sizeof (id));173174debug(3, "Wrote object %s (%d)\n", (idp ? idp->ii_name : "(null)"), id);175}176177static void178write_functions(iidesc_t *idp, ctf_buf_t *b)179{180uint_t fdata[2];181uint_t id;182int nargs;183int i;184185if (!idp) {186fdata[0] = 0;187ctf_buf_write(b, &fdata[0], sizeof (fdata[0]));188189debug(3, "Wrote function (null)\n");190return;191}192193nargs = idp->ii_nargs + (idp->ii_vargs != 0);194195if (nargs > CTF_V3_MAX_VLEN) {196terminate("function %s has too many args: %d > %d\n",197idp->ii_name, nargs, CTF_V3_MAX_VLEN);198}199200fdata[0] = CTF_V3_TYPE_INFO(CTF_K_FUNCTION, 1, nargs);201fdata[1] = idp->ii_dtype->t_id;202203if (target_requires_swap) {204SWAP_32(fdata[0]);205SWAP_32(fdata[1]);206}207208ctf_buf_write(b, fdata, sizeof (fdata));209210for (i = 0; i < idp->ii_nargs; i++) {211id = idp->ii_args[i]->t_id;212213if (target_requires_swap) {214SWAP_32(id);215}216217ctf_buf_write(b, &id, sizeof (id));218}219220if (idp->ii_vargs) {221id = 0;222ctf_buf_write(b, &id, sizeof (id));223}224225debug(3, "Wrote function %s (%d args)\n", idp->ii_name, nargs);226}227228/*229* Depending on the size of the type being described, either a ctf_stype_t (for230* types with size < CTF_LSTRUCT_THRESH) or a ctf_type_t (all others) will be231* written. We isolate the determination here so the rest of the writer code232* doesn't need to care.233*/234static void235write_sized_type_rec(ctf_buf_t *b, struct ctf_type_v3 *ctt, size_t size)236{237if (size > CTF_V3_MAX_SIZE) {238ctt->ctt_size = CTF_V3_LSIZE_SENT;239ctt->ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);240ctt->ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);241if (target_requires_swap) {242SWAP_32(ctt->ctt_name);243SWAP_32(ctt->ctt_info);244SWAP_32(ctt->ctt_size);245SWAP_32(ctt->ctt_lsizehi);246SWAP_32(ctt->ctt_lsizelo);247}248ctf_buf_write(b, ctt, sizeof (*ctt));249} else {250struct ctf_stype_v3 *cts = (struct ctf_stype_v3 *)ctt;251252cts->ctt_size = size;253254if (target_requires_swap) {255SWAP_32(cts->ctt_name);256SWAP_32(cts->ctt_info);257SWAP_32(cts->ctt_size);258}259260ctf_buf_write(b, cts, sizeof (*cts));261}262}263264static void265write_unsized_type_rec(ctf_buf_t *b, struct ctf_type_v3 *ctt)266{267struct ctf_stype_v3 *cts = (struct ctf_stype_v3 *)ctt;268269if (target_requires_swap) {270SWAP_32(cts->ctt_name);271SWAP_32(cts->ctt_info);272SWAP_32(cts->ctt_size);273}274275ctf_buf_write(b, cts, sizeof (*cts));276}277278static int279write_type(void *arg1, void *arg2)280{281tdesc_t *tp = arg1;282ctf_buf_t *b = arg2;283elist_t *ep;284mlist_t *mp;285intr_t *ip;286287size_t offset;288uint_t encoding;289uint_t data;290int isroot = tp->t_flags & TDESC_F_ISROOT;291int i;292293struct ctf_type_v3 ctt;294struct ctf_array_v3 cta;295struct ctf_member_v3 ctm;296struct ctf_lmember_v3 ctlm;297struct ctf_enum cte;298uint_t id;299300/*301* There shouldn't be any holes in the type list (where a hole is302* defined as two consecutive tdescs without consecutive ids), but303* check for them just in case. If we do find holes, we need to make304* fake entries to fill the holes, or we won't be able to reconstruct305* the tree from the written data.306*/307if (++b->nptent < CTF_V3_TYPE_TO_INDEX(tp->t_id)) {308debug(2, "genctf: type hole from %d < x < %d\n",309b->nptent - 1, CTF_V3_TYPE_TO_INDEX(tp->t_id));310311ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, 0);312ctt.ctt_info = CTF_V3_TYPE_INFO(0, 0, 0);313while (b->nptent < CTF_V3_TYPE_TO_INDEX(tp->t_id)) {314write_sized_type_rec(b, &ctt, 0);315b->nptent++;316}317}318319offset = strtab_insert(&b->ctb_strtab, tp->t_name);320ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset);321322switch (tp->t_type) {323case INTRINSIC:324ip = tp->t_intr;325if (ip->intr_type == INTR_INT)326ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_INTEGER,327isroot, 1);328else329ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FLOAT, isroot, 1);330write_sized_type_rec(b, &ctt, tp->t_size);331332encoding = 0;333334if (ip->intr_type == INTR_INT) {335if (ip->intr_signed)336encoding |= CTF_INT_SIGNED;337if (ip->intr_iformat == 'c')338encoding |= CTF_INT_CHAR;339else if (ip->intr_iformat == 'b')340encoding |= CTF_INT_BOOL;341else if (ip->intr_iformat == 'v')342encoding |= CTF_INT_VARARGS;343} else344encoding = ip->intr_fformat;345346data = CTF_INT_DATA(encoding, ip->intr_offset, ip->intr_nbits);347if (target_requires_swap) {348SWAP_32(data);349}350ctf_buf_write(b, &data, sizeof (data));351break;352353case POINTER:354ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_POINTER, isroot, 0);355ctt.ctt_type = tp->t_tdesc->t_id;356write_unsized_type_rec(b, &ctt);357break;358359case ARRAY:360ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_ARRAY, isroot, 1);361write_sized_type_rec(b, &ctt, tp->t_size);362363cta.cta_contents = tp->t_ardef->ad_contents->t_id;364cta.cta_index = tp->t_ardef->ad_idxtype->t_id;365cta.cta_nelems = tp->t_ardef->ad_nelems;366if (target_requires_swap) {367SWAP_32(cta.cta_contents);368SWAP_32(cta.cta_index);369SWAP_32(cta.cta_nelems);370}371ctf_buf_write(b, &cta, sizeof (cta));372break;373374case STRUCT:375case UNION:376for (i = 0, mp = tp->t_members; mp != NULL; mp = mp->ml_next)377i++; /* count up struct or union members */378379if (i > CTF_V3_MAX_VLEN) {380terminate("sou %s has too many members: %d > %d\n",381tdesc_name(tp), i, CTF_V3_MAX_VLEN);382}383384if (tp->t_type == STRUCT)385ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_STRUCT, isroot, i);386else387ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_UNION, isroot, i);388389write_sized_type_rec(b, &ctt, tp->t_size);390391if (tp->t_size < CTF_V3_LSTRUCT_THRESH) {392for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) {393offset = strtab_insert(&b->ctb_strtab,394mp->ml_name);395396ctm.ctm_name = CTF_TYPE_NAME(CTF_STRTAB_0,397offset);398ctm.ctm_type = mp->ml_type->t_id;399ctm.ctm_offset = mp->ml_offset;400if (target_requires_swap) {401SWAP_32(ctm.ctm_name);402SWAP_32(ctm.ctm_type);403SWAP_32(ctm.ctm_offset);404}405ctf_buf_write(b, &ctm, sizeof (ctm));406}407} else {408for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) {409offset = strtab_insert(&b->ctb_strtab,410mp->ml_name);411412ctlm.ctlm_name = CTF_TYPE_NAME(CTF_STRTAB_0,413offset);414ctlm.ctlm_type = mp->ml_type->t_id;415ctlm.ctlm_offsethi =416CTF_OFFSET_TO_LMEMHI(mp->ml_offset);417ctlm.ctlm_offsetlo =418CTF_OFFSET_TO_LMEMLO(mp->ml_offset);419420if (target_requires_swap) {421SWAP_32(ctlm.ctlm_name);422SWAP_32(ctlm.ctlm_type);423SWAP_32(ctlm.ctlm_offsethi);424SWAP_32(ctlm.ctlm_offsetlo);425}426427ctf_buf_write(b, &ctlm, sizeof (ctlm));428}429}430break;431432case ENUM:433for (i = 0, ep = tp->t_emem; ep != NULL; ep = ep->el_next)434i++; /* count up enum members */435436if (i > CTF_V3_MAX_VLEN) {437i = CTF_V3_MAX_VLEN;438}439440ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_ENUM, isroot, i);441write_sized_type_rec(b, &ctt, tp->t_size);442443for (ep = tp->t_emem; ep != NULL && i > 0; ep = ep->el_next) {444offset = strtab_insert(&b->ctb_strtab, ep->el_name);445cte.cte_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset);446cte.cte_value = ep->el_number;447448if (target_requires_swap) {449SWAP_32(cte.cte_name);450SWAP_32(cte.cte_value);451}452453ctf_buf_write(b, &cte, sizeof (cte));454i--;455}456break;457458case FORWARD:459ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FORWARD, isroot, 0);460ctt.ctt_type = 0;461write_unsized_type_rec(b, &ctt);462break;463464case TYPEDEF:465ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_TYPEDEF, isroot, 0);466ctt.ctt_type = tp->t_tdesc->t_id;467write_unsized_type_rec(b, &ctt);468break;469470case VOLATILE:471ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_VOLATILE, isroot, 0);472ctt.ctt_type = tp->t_tdesc->t_id;473write_unsized_type_rec(b, &ctt);474break;475476case CONST:477ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_CONST, isroot, 0);478ctt.ctt_type = tp->t_tdesc->t_id;479write_unsized_type_rec(b, &ctt);480break;481482case FUNCTION:483i = tp->t_fndef->fn_nargs + tp->t_fndef->fn_vargs;484485if (i > CTF_V3_MAX_VLEN) {486terminate("function %s has too many args: %d > %d\n",487tdesc_name(tp), i, CTF_V3_MAX_VLEN);488}489490ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FUNCTION, isroot, i);491ctt.ctt_type = tp->t_fndef->fn_ret->t_id;492write_unsized_type_rec(b, &ctt);493494for (i = 0; i < (int) tp->t_fndef->fn_nargs; i++) {495id = tp->t_fndef->fn_args[i]->t_id;496497if (target_requires_swap) {498SWAP_32(id);499}500501ctf_buf_write(b, &id, sizeof (id));502}503504if (tp->t_fndef->fn_vargs) {505id = 0;506ctf_buf_write(b, &id, sizeof (id));507i++;508}509510break;511512case RESTRICT:513ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_RESTRICT, isroot, 0);514ctt.ctt_type = tp->t_tdesc->t_id;515write_unsized_type_rec(b, &ctt);516break;517518default:519warning("Can't write unknown type %d\n", tp->t_type);520}521522debug(3, "Wrote type %d %s\n", tp->t_id, tdesc_name(tp));523524return (1);525}526527typedef struct resbuf {528caddr_t rb_base;529caddr_t rb_ptr;530size_t rb_size;531z_stream rb_zstr;532} resbuf_t;533534static void535rbzs_grow(resbuf_t *rb)536{537off_t ptroff = (caddr_t)rb->rb_zstr.next_out - rb->rb_base;538539rb->rb_size += RES_BUF_CHUNK_SIZE;540rb->rb_base = xrealloc(rb->rb_base, rb->rb_size);541rb->rb_ptr = rb->rb_base + ptroff;542rb->rb_zstr.next_out = (Bytef *)(rb->rb_ptr);543rb->rb_zstr.avail_out += RES_BUF_CHUNK_SIZE;544}545546static void547compress_start(resbuf_t *rb)548{549int rc;550551rb->rb_zstr.zalloc = (alloc_func)0;552rb->rb_zstr.zfree = (free_func)0;553rb->rb_zstr.opaque = (voidpf)0;554555if ((rc = deflateInit(&rb->rb_zstr, Z_BEST_COMPRESSION)) != Z_OK)556parseterminate("zlib start failed: %s", zError(rc));557}558559static ssize_t560compress_buffer(void *buf, size_t n, void *data)561{562resbuf_t *rb = (resbuf_t *)data;563int rc;564565rb->rb_zstr.next_out = (Bytef *)rb->rb_ptr;566rb->rb_zstr.avail_out = rb->rb_size - (rb->rb_ptr - rb->rb_base);567rb->rb_zstr.next_in = buf;568rb->rb_zstr.avail_in = n;569570while (rb->rb_zstr.avail_in) {571if (rb->rb_zstr.avail_out == 0)572rbzs_grow(rb);573574if ((rc = deflate(&rb->rb_zstr, Z_NO_FLUSH)) != Z_OK)575parseterminate("zlib deflate failed: %s", zError(rc));576}577rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out;578579return (n);580}581582static void583compress_flush(resbuf_t *rb, int type)584{585int rc;586587for (;;) {588if (rb->rb_zstr.avail_out == 0)589rbzs_grow(rb);590591rc = deflate(&rb->rb_zstr, type);592if ((type == Z_FULL_FLUSH && rc == Z_BUF_ERROR) ||593(type == Z_FINISH && rc == Z_STREAM_END))594break;595else if (rc != Z_OK)596parseterminate("zlib finish failed: %s", zError(rc));597}598rb->rb_ptr = (caddr_t)rb->rb_zstr.next_out;599}600601static void602compress_end(resbuf_t *rb)603{604int rc;605606compress_flush(rb, Z_FINISH);607608if ((rc = deflateEnd(&rb->rb_zstr)) != Z_OK)609parseterminate("zlib end failed: %s", zError(rc));610}611612/*613* Pad the buffer to a power-of-2 boundary614*/615static void616pad_buffer(ctf_buf_t *buf, int align)617{618uint_t cur = ctf_buf_cur(buf);619ssize_t topad = (align - (cur % align)) % align;620static const char pad[8] = { 0 };621622while (topad > 0) {623ctf_buf_write(buf, pad, (topad > 8 ? 8 : topad));624topad -= 8;625}626}627628static ssize_t629bcopy_data(void *buf, size_t n, void *data)630{631caddr_t *posp = (caddr_t *)data;632bcopy(buf, *posp, n);633*posp += n;634return (n);635}636637static caddr_t638write_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp)639{640caddr_t outbuf;641caddr_t bufpos;642643outbuf = xmalloc(sizeof (ctf_header_t) + (buf->ctb_ptr - buf->ctb_base)644+ buf->ctb_strtab.str_size);645646bufpos = outbuf;647(void) bcopy_data(h, sizeof (ctf_header_t), &bufpos);648(void) bcopy_data(buf->ctb_base, buf->ctb_ptr - buf->ctb_base,649&bufpos);650(void) strtab_write(&buf->ctb_strtab, bcopy_data, &bufpos);651*resszp = bufpos - outbuf;652return (outbuf);653}654655/*656* Create the compression buffer, and fill it with the CTF and string657* table data. We flush the compression state between the two so the658* dictionary used for the string tables won't be polluted with values659* that made sense for the CTF data.660*/661static caddr_t662write_compressed_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp)663{664resbuf_t resbuf;665resbuf.rb_size = RES_BUF_CHUNK_SIZE;666resbuf.rb_base = xmalloc(resbuf.rb_size);667bcopy(h, resbuf.rb_base, sizeof (ctf_header_t));668resbuf.rb_ptr = resbuf.rb_base + sizeof (ctf_header_t);669670compress_start(&resbuf);671(void) compress_buffer(buf->ctb_base, buf->ctb_ptr - buf->ctb_base,672&resbuf);673compress_flush(&resbuf, Z_FULL_FLUSH);674(void) strtab_write(&buf->ctb_strtab, compress_buffer, &resbuf);675compress_end(&resbuf);676677*resszp = (resbuf.rb_ptr - resbuf.rb_base);678return (resbuf.rb_base);679}680681caddr_t682ctf_gen(iiburst_t *iiburst, size_t *resszp, int do_compress)683{684ctf_buf_t *buf = ctf_buf_new();685ctf_header_t h;686caddr_t outbuf;687688int i;689690target_requires_swap = do_compress & CTF_SWAP_BYTES;691do_compress &= ~CTF_SWAP_BYTES;692693/*694* Prepare the header, and create the CTF output buffers. The data695* object section and function section are both lists of 2-byte696* integers; we pad these out to the next 4-byte boundary if needed.697*/698h.cth_magic = CTF_MAGIC;699h.cth_version = CTF_VERSION_3;700h.cth_flags = do_compress ? CTF_F_COMPRESS : 0;701h.cth_parlabel = strtab_insert(&buf->ctb_strtab,702iiburst->iib_td->td_parlabel);703h.cth_parname = strtab_insert(&buf->ctb_strtab,704iiburst->iib_td->td_parname);705706h.cth_lbloff = 0;707(void) list_iter(iiburst->iib_td->td_labels, write_label,708buf);709710pad_buffer(buf, 2);711h.cth_objtoff = ctf_buf_cur(buf);712for (i = 0; i < iiburst->iib_nobjts; i++)713write_objects(iiburst->iib_objts[i], buf);714715pad_buffer(buf, 2);716h.cth_funcoff = ctf_buf_cur(buf);717for (i = 0; i < iiburst->iib_nfuncs; i++)718write_functions(iiburst->iib_funcs[i], buf);719720pad_buffer(buf, 4);721h.cth_typeoff = ctf_buf_cur(buf);722(void) list_iter(iiburst->iib_types, write_type, buf);723724debug(2, "CTF wrote %d types\n", list_count(iiburst->iib_types));725726h.cth_stroff = ctf_buf_cur(buf);727h.cth_strlen = strtab_size(&buf->ctb_strtab);728729if (target_requires_swap) {730SWAP_16(h.cth_preamble.ctp_magic);731SWAP_32(h.cth_parlabel);732SWAP_32(h.cth_parname);733SWAP_32(h.cth_lbloff);734SWAP_32(h.cth_objtoff);735SWAP_32(h.cth_funcoff);736SWAP_32(h.cth_typeoff);737SWAP_32(h.cth_stroff);738SWAP_32(h.cth_strlen);739}740741/*742* We only do compression for ctfmerge, as ctfconvert is only743* supposed to be used on intermediary build objects. This is744* significantly faster.745*/746if (do_compress)747outbuf = write_compressed_buffer(&h, buf, resszp);748else749outbuf = write_buffer(&h, buf, resszp);750751ctf_buf_free(buf);752return (outbuf);753}754755static void756get_ctt_info(ctf_header_t *h, void *v, uint_t *kind, uint_t *vlen, int *isroot)757{758if (h->cth_version == CTF_VERSION_2) {759struct ctf_type_v2 *ctt = v;760761*kind = CTF_V2_INFO_KIND(ctt->ctt_info);762*vlen = CTF_V2_INFO_VLEN(ctt->ctt_info);763*isroot = CTF_V2_INFO_ISROOT(ctt->ctt_info);764} else {765struct ctf_type_v3 *ctt = v;766767*kind = CTF_V3_INFO_KIND(ctt->ctt_info);768*vlen = CTF_V3_INFO_VLEN(ctt->ctt_info);769*isroot = CTF_V3_INFO_ISROOT(ctt->ctt_info);770}771}772773static void774get_ctt_size(ctf_header_t *h, void *v, size_t *sizep, size_t *incrementp)775{776if (h->cth_version == CTF_VERSION_2) {777struct ctf_type_v2 *ctt = v;778779if (ctt->ctt_size == CTF_V2_LSIZE_SENT) {780*sizep = (size_t)CTF_TYPE_LSIZE(ctt);781*incrementp = sizeof (struct ctf_type_v2);782} else {783*sizep = ctt->ctt_size;784*incrementp = sizeof (struct ctf_stype_v2);785}786} else {787struct ctf_type_v3 *ctt = v;788789if (ctt->ctt_size == CTF_V3_LSIZE_SENT) {790*sizep = (size_t)CTF_TYPE_LSIZE(ctt);791*incrementp = sizeof (struct ctf_type_v3);792} else {793*sizep = ctt->ctt_size;794*incrementp = sizeof (struct ctf_stype_v3);795}796}797}798799static int800count_types(ctf_header_t *h, caddr_t data)801{802caddr_t dptr = data + h->cth_typeoff;803uint_t version = h->cth_version;804size_t idwidth;805int count = 0;806807idwidth = version == CTF_VERSION_2 ? 2 : 4;808dptr = data + h->cth_typeoff;809while (dptr < data + h->cth_stroff) {810void *v = (void *) dptr;811size_t size, increment;812uint_t vlen, kind;813int isroot;814815get_ctt_info(h, v, &kind, &vlen, &isroot);816get_ctt_size(h, v, &size, &increment);817818switch (kind) {819case CTF_K_INTEGER:820case CTF_K_FLOAT:821dptr += 4;822break;823case CTF_K_POINTER:824case CTF_K_FORWARD:825case CTF_K_TYPEDEF:826case CTF_K_VOLATILE:827case CTF_K_CONST:828case CTF_K_RESTRICT:829case CTF_K_FUNCTION:830dptr += idwidth * vlen;831break;832case CTF_K_ARRAY:833if (version == CTF_VERSION_2)834dptr += sizeof (struct ctf_array_v2);835else836dptr += sizeof (struct ctf_array_v3);837break;838case CTF_K_STRUCT:839case CTF_K_UNION:840if (version == CTF_VERSION_2) {841if (size < CTF_V2_LSTRUCT_THRESH)842dptr += sizeof (struct ctf_member_v2) *843vlen;844else845dptr += sizeof (struct ctf_lmember_v2) *846vlen;847} else {848if (size < CTF_V3_LSTRUCT_THRESH)849dptr += sizeof (struct ctf_member_v3) *850vlen;851else852dptr += sizeof (struct ctf_lmember_v3) *853vlen;854}855break;856case CTF_K_ENUM:857dptr += sizeof (ctf_enum_t) * vlen;858break;859case CTF_K_UNKNOWN:860break;861default:862parseterminate("Unknown CTF type %d (#%d) at %#x",863kind, count, dptr - data);864}865866dptr += increment;867count++;868}869870debug(3, "CTF read %d types\n", count);871872return (count);873}874875/*876* Resurrect the labels stored in the CTF data, returning the index associated877* with a label provided by the caller. There are several cases, outlined878* below. Note that, given two labels, the one associated with the lesser type879* index is considered to be older than the other.880*881* 1. matchlbl == NULL - return the index of the most recent label.882* 2. matchlbl == "BASE" - return the index of the oldest label.883* 3. matchlbl != NULL, but doesn't match any labels in the section - warn884* the user, and proceed as if matchlbl == "BASE" (for safety).885* 4. matchlbl != NULL, and matches one of the labels in the section - return886* the type index associated with the label.887*/888static int889resurrect_labels(ctf_header_t *h, tdata_t *td, caddr_t ctfdata, char *matchlbl)890{891caddr_t buf = ctfdata + h->cth_lbloff;892caddr_t sbuf = ctfdata + h->cth_stroff;893size_t bufsz = h->cth_objtoff - h->cth_lbloff;894int lastidx = 0, baseidx = -1;895char *baselabel = NULL;896ctf_lblent_t *ctl;897void *v = (void *) buf;898899for (ctl = v; (caddr_t)ctl < buf + bufsz; ctl++) {900char *label = sbuf + ctl->ctl_label;901902lastidx = ctl->ctl_typeidx;903904debug(3, "Resurrected label %s type idx %d\n", label, lastidx);905906tdata_label_add(td, label, lastidx);907908if (baseidx == -1) {909baseidx = lastidx;910baselabel = label;911if (matchlbl != NULL && streq(matchlbl, "BASE"))912return (lastidx);913}914915if (matchlbl != NULL && streq(label, matchlbl))916return (lastidx);917}918919if (matchlbl != NULL) {920/* User provided a label that didn't match */921warning("%s: Cannot find label `%s' - using base (%s)\n",922curfile, matchlbl, (baselabel ? baselabel : "NONE"));923924tdata_label_free(td);925tdata_label_add(td, baselabel, baseidx);926927return (baseidx);928}929930return (lastidx);931}932933static void934resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,935caddr_t ctfdata, symit_data_t *si)936{937caddr_t buf = ctfdata + h->cth_objtoff;938size_t bufsz = h->cth_funcoff - h->cth_objtoff;939caddr_t dptr;940size_t idwidth;941942idwidth = h->cth_version == CTF_VERSION_2 ? 2 : 4;943944symit_reset(si);945for (dptr = buf; dptr < buf + bufsz; dptr += idwidth) {946uint32_t id = 0;947948memcpy(&id, (void *) dptr, idwidth);949iidesc_t *ii;950GElf_Sym *sym;951952if (!(sym = symit_next(si, STT_OBJECT)) && id != 0) {953parseterminate(954"Unexpected end of object symbols at %x of %x",955dptr - buf, bufsz);956}957958if (id == 0) {959debug(3, "Skipping null object\n");960continue;961} else if (id >= (uint_t)tdsize) {962parseterminate("Reference to invalid type %d", id);963}964965ii = iidesc_new(symit_name(si));966ii->ii_dtype = tdarr[id];967if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {968ii->ii_type = II_SVAR;969ii->ii_owner = xstrdup(symit_curfile(si));970} else971ii->ii_type = II_GVAR;972hash_add(td->td_iihash, ii);973974debug(3, "Resurrected %s object %s (%d) from %s\n",975(ii->ii_type == II_GVAR ? "global" : "static"),976ii->ii_name, id, (ii->ii_owner ? ii->ii_owner : "(none)"));977}978}979980static void981resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,982caddr_t ctfdata, symit_data_t *si)983{984caddr_t buf = ctfdata + h->cth_funcoff;985size_t bufsz = h->cth_typeoff - h->cth_funcoff;986size_t idwidth;987caddr_t dptr = buf;988iidesc_t *ii;989GElf_Sym *sym;990int i;991992idwidth = h->cth_version == CTF_VERSION_2 ? 2 : 4;993994symit_reset(si);995while (dptr < buf + bufsz) {996uint32_t id, info, retid;997998info = 0;999memcpy(&info, (void *) dptr, idwidth);1000dptr += idwidth;10011002if (!(sym = symit_next(si, STT_FUNC)) && info != 0)1003parseterminate("Unexpected end of function symbols");10041005if (info == 0) {1006debug(3, "Skipping null function (%s)\n",1007symit_name(si));1008continue;1009}10101011retid = 0;1012memcpy(&retid, (void *) dptr, idwidth);1013dptr += idwidth;10141015if (retid >= (uint_t)tdsize)1016parseterminate("Reference to invalid type %d", retid);10171018ii = iidesc_new(symit_name(si));1019ii->ii_dtype = tdarr[retid];1020if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {1021ii->ii_type = II_SFUN;1022ii->ii_owner = xstrdup(symit_curfile(si));1023} else1024ii->ii_type = II_GFUN;1025if (h->cth_version == CTF_VERSION_2)1026ii->ii_nargs = CTF_V2_INFO_VLEN(info);1027else1028ii->ii_nargs = CTF_V3_INFO_VLEN(info);1029if (ii->ii_nargs)1030ii->ii_args =1031xmalloc(sizeof (tdesc_t *) * ii->ii_nargs);10321033for (i = 0; i < ii->ii_nargs; i++, dptr += idwidth) {1034id = 0;1035memcpy(&id, (void *) dptr, idwidth);1036if (id >= (uint_t)tdsize)1037parseterminate("Reference to invalid type %d",1038id);1039ii->ii_args[i] = tdarr[id];1040}10411042if (ii->ii_nargs && ii->ii_args[ii->ii_nargs - 1] == NULL) {1043ii->ii_nargs--;1044ii->ii_vargs = 1;1045}10461047hash_add(td->td_iihash, ii);10481049debug(3, "Resurrected %s function %s (%d, %d args)\n",1050(ii->ii_type == II_GFUN ? "global" : "static"),1051ii->ii_name, retid, ii->ii_nargs);1052}1053}10541055static void1056resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,1057caddr_t ctfdata, int maxid)1058{1059caddr_t buf = ctfdata + h->cth_typeoff;1060size_t bufsz = h->cth_stroff - h->cth_typeoff;1061caddr_t sbuf = ctfdata + h->cth_stroff;1062caddr_t dptr = buf;1063tdesc_t *tdp;1064uint_t data;1065uint_t encoding;1066size_t idwidth, size, increment;1067int tcnt;1068int iicnt = 0;1069tid_t tid, argid;1070int isroot, kind, vlen;1071int i, version;10721073elist_t **epp;1074mlist_t **mpp;1075intr_t *ip;10761077version = h->cth_version;1078idwidth = version == CTF_VERSION_2 ? 2 : 4;10791080/*1081* A maxid of zero indicates a request to resurrect all types, so reset1082* maxid to the maximum type id.1083*/1084if (maxid == 0) {1085maxid = version == CTF_VERSION_2 ?1086CTF_V2_MAX_TYPE : CTF_V3_MAX_TYPE;1087}10881089for (dptr = buf, tcnt = 0, tid = 1; dptr < buf + bufsz; tcnt++, tid++) {1090ctf_enum_t *cte;1091uint_t name, type;1092void *v;10931094if (tid > maxid)1095break;10961097if (tid >= tdsize)1098parseterminate("Reference to invalid type %d", tid);10991100get_ctt_info(h, dptr, &kind, &vlen, &isroot);1101get_ctt_size(h, dptr, &size, &increment);1102if (version == CTF_VERSION_2) {1103struct ctf_type_v2 *ctt = (void *) dptr;11041105name = ctt->ctt_name;1106type = ctt->ctt_type;1107} else {1108struct ctf_type_v3 *ctt = (void *) dptr;11091110name = ctt->ctt_name;1111type = ctt->ctt_type;1112}1113dptr += increment;11141115tdp = tdarr[tid];11161117if (CTF_NAME_STID(name) != CTF_STRTAB_0)1118parseterminate(1119"Unable to cope with non-zero strtab id");1120if (CTF_NAME_OFFSET(name) != 0) {1121tdp->t_name = xstrdup(sbuf + CTF_NAME_OFFSET(name));1122} else1123tdp->t_name = NULL;11241125switch (kind) {1126case CTF_K_INTEGER:1127tdp->t_type = INTRINSIC;1128tdp->t_size = size;11291130v = (void *) dptr;1131data = *((uint_t *)v);1132dptr += sizeof (uint_t);1133encoding = CTF_INT_ENCODING(data);11341135ip = xmalloc(sizeof (intr_t));1136ip->intr_type = INTR_INT;1137ip->intr_signed = (encoding & CTF_INT_SIGNED) ? 1 : 0;11381139if (encoding & CTF_INT_CHAR)1140ip->intr_iformat = 'c';1141else if (encoding & CTF_INT_BOOL)1142ip->intr_iformat = 'b';1143else if (encoding & CTF_INT_VARARGS)1144ip->intr_iformat = 'v';1145else1146ip->intr_iformat = '\0';11471148ip->intr_offset = CTF_INT_OFFSET(data);1149ip->intr_nbits = CTF_INT_BITS(data);1150tdp->t_intr = ip;1151break;11521153case CTF_K_FLOAT:1154tdp->t_type = INTRINSIC;1155tdp->t_size = size;11561157v = (void *) dptr;1158data = *((uint_t *)v);1159dptr += sizeof (uint_t);11601161ip = xcalloc(sizeof (intr_t));1162ip->intr_type = INTR_REAL;1163ip->intr_fformat = CTF_FP_ENCODING(data);1164ip->intr_offset = CTF_FP_OFFSET(data);1165ip->intr_nbits = CTF_FP_BITS(data);1166tdp->t_intr = ip;1167break;11681169case CTF_K_POINTER:1170tdp->t_type = POINTER;1171tdp->t_tdesc = tdarr[type];1172break;11731174case CTF_K_ARRAY: {1175uint_t contents, index, nelems;11761177tdp->t_type = ARRAY;1178tdp->t_size = size;11791180if (version == CTF_VERSION_2) {1181struct ctf_array_v2 *cta = (void *) dptr;1182contents = cta->cta_contents;1183index = cta->cta_index;1184nelems = cta->cta_nelems;1185dptr += sizeof (*cta);1186} else {1187struct ctf_array_v3 *cta = (void *) dptr;1188contents = cta->cta_contents;1189index = cta->cta_index;1190nelems = cta->cta_nelems;1191dptr += sizeof (*cta);1192}11931194tdp->t_ardef = xmalloc(sizeof (ardef_t));1195tdp->t_ardef->ad_contents = tdarr[contents];1196tdp->t_ardef->ad_idxtype = tdarr[index];1197tdp->t_ardef->ad_nelems = nelems;1198break;1199}12001201case CTF_K_STRUCT:1202case CTF_K_UNION: {1203tdp->t_type = (kind == CTF_K_STRUCT ? STRUCT : UNION);1204tdp->t_size = size;12051206if (version == CTF_VERSION_2) {1207if (size < CTF_V2_LSTRUCT_THRESH) {1208for (i = 0, mpp = &tdp->t_members; i < vlen;1209i++, mpp = &((*mpp)->ml_next)) {1210v = (void *) dptr;1211struct ctf_member_v2 *ctm = v;1212dptr += sizeof (struct ctf_member_v2);12131214*mpp = xmalloc(sizeof (mlist_t));1215(*mpp)->ml_name = xstrdup(sbuf +1216ctm->ctm_name);1217(*mpp)->ml_type = tdarr[ctm->ctm_type];1218(*mpp)->ml_offset = ctm->ctm_offset;1219(*mpp)->ml_size = 0;1220}1221} else {1222for (i = 0, mpp = &tdp->t_members; i < vlen;1223i++, mpp = &((*mpp)->ml_next)) {1224v = (void *) dptr;1225struct ctf_lmember_v2 *ctlm = v;1226dptr += sizeof (struct ctf_lmember_v2);12271228*mpp = xmalloc(sizeof (mlist_t));1229(*mpp)->ml_name = xstrdup(sbuf +1230ctlm->ctlm_name);1231(*mpp)->ml_type =1232tdarr[ctlm->ctlm_type];1233(*mpp)->ml_offset =1234(int)CTF_LMEM_OFFSET(ctlm);1235(*mpp)->ml_size = 0;1236}1237}1238} else {1239if (size < CTF_V3_LSTRUCT_THRESH) {1240for (i = 0, mpp = &tdp->t_members; i < vlen;1241i++, mpp = &((*mpp)->ml_next)) {1242v = (void *) dptr;1243struct ctf_member_v3 *ctm = v;1244dptr += sizeof (struct ctf_member_v3);12451246*mpp = xmalloc(sizeof (mlist_t));1247(*mpp)->ml_name = xstrdup(sbuf +1248ctm->ctm_name);1249(*mpp)->ml_type = tdarr[ctm->ctm_type];1250(*mpp)->ml_offset = ctm->ctm_offset;1251(*mpp)->ml_size = 0;1252}1253} else {1254for (i = 0, mpp = &tdp->t_members; i < vlen;1255i++, mpp = &((*mpp)->ml_next)) {1256v = (void *) dptr;1257struct ctf_lmember_v3 *ctlm = v;1258dptr += sizeof (struct ctf_lmember_v3);12591260*mpp = xmalloc(sizeof (mlist_t));1261(*mpp)->ml_name = xstrdup(sbuf +1262ctlm->ctlm_name);1263(*mpp)->ml_type =1264tdarr[ctlm->ctlm_type];1265(*mpp)->ml_offset =1266(int)CTF_LMEM_OFFSET(ctlm);1267(*mpp)->ml_size = 0;1268}1269}1270}12711272*mpp = NULL;1273break;1274}12751276case CTF_K_ENUM:1277tdp->t_type = ENUM;1278tdp->t_size = size;12791280for (i = 0, epp = &tdp->t_emem; i < vlen;1281i++, epp = &((*epp)->el_next)) {1282v = (void *) dptr;1283cte = v;1284dptr += sizeof (ctf_enum_t);12851286*epp = xmalloc(sizeof (elist_t));1287(*epp)->el_name = xstrdup(sbuf + cte->cte_name);1288(*epp)->el_number = cte->cte_value;1289}1290*epp = NULL;1291break;12921293case CTF_K_FORWARD:1294tdp->t_type = FORWARD;1295list_add(&td->td_fwdlist, tdp);1296break;12971298case CTF_K_TYPEDEF:1299tdp->t_type = TYPEDEF;1300tdp->t_tdesc = tdarr[type];1301break;13021303case CTF_K_VOLATILE:1304tdp->t_type = VOLATILE;1305tdp->t_tdesc = tdarr[type];1306break;13071308case CTF_K_CONST:1309tdp->t_type = CONST;1310tdp->t_tdesc = tdarr[type];1311break;13121313case CTF_K_FUNCTION:1314tdp->t_type = FUNCTION;1315tdp->t_fndef = xcalloc(sizeof (fndef_t));1316tdp->t_fndef->fn_ret = tdarr[type];13171318v = (void *) (dptr + (idwidth * (vlen - 1)));1319if (vlen > 0 && *(uint_t *)v == 0)1320tdp->t_fndef->fn_vargs = 1;13211322tdp->t_fndef->fn_nargs = vlen - tdp->t_fndef->fn_vargs;1323tdp->t_fndef->fn_args = xcalloc(sizeof (tdesc_t) *1324vlen - tdp->t_fndef->fn_vargs);13251326for (i = 0; i < vlen; i++) {1327v = (void *) dptr;1328memcpy(&argid, v, idwidth);1329dptr += idwidth;13301331if (argid != 0)1332tdp->t_fndef->fn_args[i] = tdarr[argid];1333}13341335dptr = (caddr_t) roundup2((uintptr_t) dptr, 4);1336break;13371338case CTF_K_RESTRICT:1339tdp->t_type = RESTRICT;1340tdp->t_tdesc = tdarr[type];1341break;13421343case CTF_K_UNKNOWN:1344break;13451346default:1347warning("Can't parse unknown CTF type %d\n", kind);1348}13491350if (isroot) {1351iidesc_t *ii = iidesc_new(tdp->t_name);1352if (tdp->t_type == STRUCT || tdp->t_type == UNION ||1353tdp->t_type == ENUM)1354ii->ii_type = II_SOU;1355else1356ii->ii_type = II_TYPE;1357ii->ii_dtype = tdp;1358hash_add(td->td_iihash, ii);13591360iicnt++;1361}13621363debug(3, "Resurrected %d %stype %s (%d)\n", tdp->t_type,1364(isroot ? "root " : ""), tdesc_name(tdp), tdp->t_id);1365}13661367debug(3, "Resurrected %d types (%d were roots)\n", tcnt, iicnt);1368}13691370/*1371* For lack of other inspiration, we're going to take the boring route. We1372* count the number of types. This lets us malloc that many tdesc structs1373* before we start filling them in. This has the advantage of allowing us to1374* avoid a merge-esque remap step.1375*/1376static tdata_t *1377ctf_parse(ctf_header_t *h, caddr_t buf, symit_data_t *si, char *label)1378{1379tdata_t *td = tdata_new();1380tdesc_t **tdarr;1381int ntypes = count_types(h, buf);1382int idx, i;13831384/* shudder */1385tdarr = xcalloc(sizeof (tdesc_t *) * (ntypes + 1));1386tdarr[0] = NULL;1387for (i = 1; i <= ntypes; i++) {1388tdarr[i] = xcalloc(sizeof (tdesc_t));1389tdarr[i]->t_id = i;1390}13911392td->td_parlabel = xstrdup(buf + h->cth_stroff + h->cth_parlabel);13931394/* we have the technology - we can rebuild them */1395idx = resurrect_labels(h, td, buf, label);13961397resurrect_objects(h, td, tdarr, ntypes + 1, buf, si);1398resurrect_functions(h, td, tdarr, ntypes + 1, buf, si);1399resurrect_types(h, td, tdarr, ntypes + 1, buf, idx);14001401free(tdarr);14021403td->td_nextid = ntypes + 1;14041405return (td);1406}14071408static size_t1409decompress_ctf(caddr_t cbuf, size_t cbufsz, caddr_t dbuf, size_t dbufsz)1410{1411z_stream zstr;1412int rc;14131414zstr.zalloc = (alloc_func)0;1415zstr.zfree = (free_func)0;1416zstr.opaque = (voidpf)0;14171418zstr.next_in = (Bytef *)cbuf;1419zstr.avail_in = cbufsz;1420zstr.next_out = (Bytef *)dbuf;1421zstr.avail_out = dbufsz;14221423if ((rc = inflateInit(&zstr)) != Z_OK ||1424(rc = inflate(&zstr, Z_NO_FLUSH)) != Z_STREAM_END ||1425(rc = inflateEnd(&zstr)) != Z_OK) {1426warning("CTF decompress zlib error %s\n", zError(rc));1427return (0);1428}14291430debug(3, "reflated %lu bytes to %lu, pointer at %d\n",1431zstr.total_in, zstr.total_out, (caddr_t)zstr.next_in - cbuf);14321433return (zstr.total_out);1434}14351436/*1437* Reconstruct the type tree from a given buffer of CTF data. Only the types1438* up to the type associated with the provided label, inclusive, will be1439* reconstructed. If a NULL label is provided, all types will be reconstructed.1440*1441* This function won't work on files that have been uniquified.1442*/1443tdata_t *1444ctf_load(char *file, caddr_t buf, size_t bufsz, symit_data_t *si, char *label)1445{1446ctf_header_t *h;1447caddr_t ctfdata;1448size_t ctfdatasz;1449tdata_t *td;14501451curfile = file;14521453if (bufsz < sizeof (ctf_header_t))1454parseterminate("Corrupt CTF - short header");14551456void *v = (void *) buf;1457h = v;1458buf += sizeof (ctf_header_t);1459bufsz -= sizeof (ctf_header_t);14601461if (h->cth_magic != CTF_MAGIC)1462parseterminate("Corrupt CTF - bad magic 0x%x", h->cth_magic);14631464if (h->cth_version != CTF_VERSION_2 && h->cth_version != CTF_VERSION_3)1465parseterminate("Unknown CTF version %d", h->cth_version);14661467ctfdatasz = h->cth_stroff + h->cth_strlen;1468if (h->cth_flags & CTF_F_COMPRESS) {1469size_t actual;14701471ctfdata = xmalloc(ctfdatasz);1472if ((actual = decompress_ctf(buf, bufsz, ctfdata, ctfdatasz)) !=1473ctfdatasz) {1474parseterminate("Corrupt CTF - short decompression "1475"(was %d, expecting %d)", actual, ctfdatasz);1476}1477} else {1478ctfdata = buf;1479ctfdatasz = bufsz;1480}14811482td = ctf_parse(h, ctfdata, si, label);14831484if (h->cth_flags & CTF_F_COMPRESS)1485free(ctfdata);14861487curfile = NULL;14881489return (td);1490}149114921493