summaryrefslogtreecommitdiff
path: root/usr/src/common/ctf
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2019-01-17 17:50:46 +0000
committerRobert Mustacchi <rm@joyent.com>2019-02-11 17:40:04 +0000
commitbc1f688b4872ace323eaddbb1a6365d054e7bf56 (patch)
tree3b6f2f4caaa4bafcfb4f757be7ea4de2858201ce /usr/src/common/ctf
parent2b987d42b0ad07d74e39b18a2498709e5195d7e3 (diff)
downloadillumos-gate-bc1f688b4872ace323eaddbb1a6365d054e7bf56.tar.gz
6885 CTF Everywhere Part 1
6886 Want ctfdiff 6887 ctfdump should be written in terms of libctf 6888 ctfmerge should be implemented in terms of libctf 6889 ctfconvert should be implemented in terms of libctf 6890 Want general workq 6891 Want general mergeq 6892 ctf_add_encoded assigns() incorrect byte size to types 6893 ctf_add_{struct,union,enum} can reuse forwards 6894 ctf_add_{struct,union,enum} occasionally forget to dirty the ctf_file_t 6895 ctf_add_member could better handle bitfields 6896 ctf_type_size() reports wrong size for forwards 6897 Want libctf ctf_kind_name() function 6898 Want libctf function to set struct/union size Portions contributed by: John Levon <john.levon@joyent.com> Portions contributed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: John Levon <john.levon@joyent.com> Reviewed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Gergő Doma <domag02@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/common/ctf')
-rw-r--r--usr/src/common/ctf/ctf_create.c842
-rw-r--r--usr/src/common/ctf/ctf_error.c12
-rw-r--r--usr/src/common/ctf/ctf_hash.c3
-rw-r--r--usr/src/common/ctf/ctf_impl.h90
-rw-r--r--usr/src/common/ctf/ctf_open.c40
-rw-r--r--usr/src/common/ctf/ctf_types.c470
-rw-r--r--usr/src/common/ctf/ctf_util.c43
7 files changed, 1332 insertions, 168 deletions
diff --git a/usr/src/common/ctf/ctf_create.c b/usr/src/common/ctf/ctf_create.c
index 239d166f44..c0a4b15055 100644
--- a/usr/src/common/ctf/ctf_create.c
+++ b/usr/src/common/ctf/ctf_create.c
@@ -25,7 +25,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc.
*/
#include <sys/sysmacros.h>
@@ -86,6 +86,48 @@ ctf_create(int *errp)
return (fp);
}
+ctf_file_t *
+ctf_fdcreate(int fd, int *errp)
+{
+ ctf_file_t *fp;
+ static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } };
+
+ const ulong_t hashlen = 128;
+ ctf_dtdef_t **hash;
+ ctf_sect_t cts;
+
+ if (fd == -1)
+ return (ctf_create(errp));
+
+ hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *));
+
+ if (hash == NULL)
+ return (ctf_set_open_errno(errp, EAGAIN));
+
+ cts.cts_name = _CTF_SECTION;
+ cts.cts_type = SHT_PROGBITS;
+ cts.cts_flags = 0;
+ cts.cts_data = &hdr;
+ cts.cts_size = sizeof (hdr);
+ cts.cts_entsize = 1;
+ cts.cts_offset = 0;
+
+ if ((fp = ctf_fdcreate_int(fd, errp, &cts)) == NULL) {
+ ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *));
+ return (NULL);
+ }
+
+ fp->ctf_flags |= LCTF_RDWR;
+ fp->ctf_dthashlen = hashlen;
+ bzero(hash, hashlen * sizeof (ctf_dtdef_t *));
+ fp->ctf_dthash = hash;
+ fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE);
+ fp->ctf_dtnextid = 1;
+ fp->ctf_dtoldid = 0;
+
+ return (fp);
+}
+
static uchar_t *
ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
{
@@ -236,14 +278,24 @@ int
ctf_update(ctf_file_t *fp)
{
ctf_file_t ofp, *nfp;
- ctf_header_t hdr;
+ ctf_header_t hdr, *bhdr;
ctf_dtdef_t *dtd;
- ctf_sect_t cts;
+ ctf_dsdef_t *dsd;
+ ctf_dldef_t *dld;
+ ctf_sect_t cts, *symp, *strp;
uchar_t *s, *s0, *t;
- size_t size;
+ ctf_lblent_t *label;
+ uint16_t *obj, *func;
+ size_t size, objsize, funcsize, labelsize, plen;
void *buf;
int err;
+ ulong_t i;
+ const char *plabel;
+ const char *sname;
+
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
if (!(fp->ctf_flags & LCTF_RDWR))
return (ctf_set_errno(fp, ECTF_RDONLY));
@@ -261,8 +313,26 @@ ctf_update(ctf_file_t *fp)
hdr.cth_magic = CTF_MAGIC;
hdr.cth_version = CTF_VERSION;
- if (fp->ctf_flags & LCTF_CHILD)
- hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */
+ if (fp->ctf_flags & LCTF_CHILD) {
+ if (fp->ctf_parname == NULL) {
+ plen = 0;
+ hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */
+ plabel = NULL;
+ } else {
+ plen = strlen(fp->ctf_parname) + 1;
+ plabel = ctf_label_topmost(fp->ctf_parent);
+ }
+ } else {
+ plabel = NULL;
+ plen = 0;
+ }
+
+ /*
+ * Iterate over the labels that we have.
+ */
+ for (labelsize = 0, dld = ctf_list_next(&fp->ctf_dldefs);
+ dld != NULL; dld = ctf_list_next(dld))
+ labelsize += sizeof (ctf_lblent_t);
/*
* Iterate through the dynamic type definition list and compute the
@@ -304,25 +374,121 @@ ctf_update(ctf_file_t *fp)
}
/*
+ * An entry for each object must exist in the data section. However, if
+ * the symbol is SHN_UNDEF, then it is skipped. For objects, the storage
+ * is just the size of the 2-byte id. For functions it's always 2 bytes,
+ * plus 2 bytes per argument and the return type.
+ */
+ dsd = ctf_list_next(&fp->ctf_dsdefs);
+ for (objsize = 0, funcsize = 0, i = 0; i < fp->ctf_nsyms; i++) {
+ int type;
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+
+ type = ELF32_ST_TYPE(symp->st_info);
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+
+ type = ELF64_ST_TYPE(symp->st_info);
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ }
+
+ while (dsd != NULL && i > dsd->dsd_symidx)
+ dsd = ctf_list_next(dsd);
+ if (type == STT_OBJECT) {
+ objsize += sizeof (uint16_t);
+ } else {
+ /* Every function has a uint16_t info no matter what */
+ if (dsd == NULL || i < dsd->dsd_symidx) {
+ funcsize += sizeof (uint16_t);
+ } else {
+ funcsize += sizeof (uint16_t) *
+ (dsd->dsd_nargs + 2);
+ }
+ }
+ }
+
+ /*
+ * The objtoff and funcoffset must be 2-byte aligned. We're guaranteed
+ * that this is always true for the objtoff because labels are always 8
+ * bytes large. Similarly, because objects are always two bytes of data,
+ * this will always be true for funcoff.
+ */
+ hdr.cth_objtoff = hdr.cth_lbloff + labelsize;
+ hdr.cth_funcoff = hdr.cth_objtoff + objsize;
+
+ /*
+ * The type offset must be 4 byte aligned.
+ */
+ hdr.cth_typeoff = hdr.cth_funcoff + funcsize;
+ if (hdr.cth_typeoff & 3)
+ hdr.cth_typeoff += 4 - (hdr.cth_typeoff & 3);
+ ASSERT((hdr.cth_typeoff & 3) == 0);
+
+ /*
* Fill in the string table offset and size, compute the size of the
* entire CTF buffer we need, and then allocate a new buffer and
* bcopy the finished header to the start of the buffer.
*/
hdr.cth_stroff = hdr.cth_typeoff + size;
- hdr.cth_strlen = fp->ctf_dtstrlen;
+ hdr.cth_strlen = fp->ctf_dtstrlen + plen;
size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
+ ctf_dprintf("lbloff: %u\nobjtoff: %u\nfuncoff: %u\n"
+ "typeoff: %u\nstroff: %u\nstrlen: %u\n",
+ hdr.cth_lbloff, hdr.cth_objtoff, hdr.cth_funcoff,
+ hdr.cth_typeoff, hdr.cth_stroff, hdr.cth_strlen);
if ((buf = ctf_data_alloc(size)) == MAP_FAILED)
return (ctf_set_errno(fp, EAGAIN));
bcopy(&hdr, buf, sizeof (ctf_header_t));
- t = (uchar_t *)buf + sizeof (ctf_header_t);
+ bhdr = buf;
+ label = (ctf_lblent_t *)((uintptr_t)buf + sizeof (ctf_header_t));
+ t = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_typeoff;
s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff;
+ obj = (uint16_t *)((uintptr_t)buf + sizeof (ctf_header_t) +
+ hdr.cth_objtoff);
+ func = (uint16_t *)((uintptr_t)buf + sizeof (ctf_header_t) +
+ hdr.cth_funcoff);
bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE));
s += sizeof (_CTF_STRTAB_TEMPLATE);
/*
+ * We have an actual parent name and we're a child container, therefore
+ * we should make sure to note our parent's name here.
+ */
+ if (plen != 0) {
+ VERIFY(s + plen - s0 <= hdr.cth_strlen);
+ bcopy(fp->ctf_parname, s, plen);
+ bhdr->cth_parname = s - s0;
+ s += plen;
+ }
+
+ /*
+ * First pass over the labels and copy them out.
+ */
+ for (dld = ctf_list_next(&fp->ctf_dldefs); dld != NULL;
+ dld = ctf_list_next(dld), label++) {
+ size_t len = strlen(dld->dld_name) + 1;
+
+ VERIFY(s + len - s0 <= hdr.cth_strlen);
+ bcopy(dld->dld_name, s, len);
+ label->ctl_typeidx = dld->dld_type;
+ label->ctl_label = s - s0;
+ s += len;
+
+ if (plabel != NULL && strcmp(plabel, dld->dld_name) == 0)
+ bhdr->cth_parlabel = label->ctl_label;
+ }
+
+ /*
* We now take a final lap through the dynamic type definition list and
* copy the appropriate type records and strings to the output buffer.
*/
@@ -339,6 +505,7 @@ ctf_update(ctf_file_t *fp)
if (dtd->dtd_name != NULL) {
dtd->dtd_data.ctt_name = (uint_t)(s - s0);
len = strlen(dtd->dtd_name) + 1;
+ VERIFY(s + len - s0 <= hdr.cth_strlen);
bcopy(dtd->dtd_name, s, len);
s += len;
} else
@@ -411,6 +578,61 @@ ctf_update(ctf_file_t *fp)
}
/*
+ * Now we fill in our dynamic data and function sections. We use the
+ * same criteria as above, but also consult the dsd list.
+ */
+ dsd = ctf_list_next(&fp->ctf_dsdefs);
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ int type;
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ type = ELF32_ST_TYPE(symp->st_info);
+
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ type = ELF64_ST_TYPE(symp->st_info);
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ }
+
+ while (dsd != NULL && i > dsd->dsd_symidx) {
+ dsd = ctf_list_next(dsd);
+ }
+ if (type == STT_OBJECT) {
+ if (dsd == NULL || i < dsd->dsd_symidx) {
+ *obj = 0;
+ } else {
+ *obj = dsd->dsd_tid;
+ }
+ obj++;
+ VERIFY((uintptr_t)obj <= (uintptr_t)func);
+ } else {
+ if (dsd == NULL || i < dsd->dsd_symidx) {
+ ushort_t data = CTF_TYPE_INFO(CTF_K_UNKNOWN,
+ 0, 0);
+ *func = data;
+ func++;
+ } else {
+ int j;
+ ushort_t data = CTF_TYPE_INFO(CTF_K_FUNCTION, 0,
+ dsd->dsd_nargs);
+
+ *func = data;
+ func++;
+ *func = dsd->dsd_tid;
+ func++;
+ for (j = 0; j < dsd->dsd_nargs; j++)
+ func[j] = dsd->dsd_argc[j];
+ func += dsd->dsd_nargs;
+ }
+ }
+ }
+
+ /*
* Finally, we are ready to ctf_bufopen() the new container. If this
* is successful, we then switch nfp and fp and free the old container.
*/
@@ -423,7 +645,15 @@ ctf_update(ctf_file_t *fp)
cts.cts_entsize = 1;
cts.cts_offset = 0;
- if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) {
+ if (fp->ctf_nsyms == 0) {
+ symp = NULL;
+ strp = NULL;
+ } else {
+ symp = &fp->ctf_symtab;
+ strp = &fp->ctf_strtab;
+ }
+
+ if ((nfp = ctf_bufopen(&cts, symp, strp, &err)) == NULL) {
ctf_data_free(buf, size);
return (ctf_set_errno(fp, err));
}
@@ -433,10 +663,11 @@ ctf_update(ctf_file_t *fp)
nfp->ctf_refcnt = fp->ctf_refcnt;
nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
- nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */
nfp->ctf_dthash = fp->ctf_dthash;
nfp->ctf_dthashlen = fp->ctf_dthashlen;
nfp->ctf_dtdefs = fp->ctf_dtdefs;
+ nfp->ctf_dsdefs = fp->ctf_dsdefs;
+ nfp->ctf_dldefs = fp->ctf_dldefs;
nfp->ctf_dtstrlen = fp->ctf_dtstrlen;
nfp->ctf_dtnextid = fp->ctf_dtnextid;
nfp->ctf_dtoldid = fp->ctf_dtnextid - 1;
@@ -445,6 +676,23 @@ ctf_update(ctf_file_t *fp)
fp->ctf_dthash = NULL;
fp->ctf_dthashlen = 0;
bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t));
+ bzero(&fp->ctf_dsdefs, sizeof (ctf_list_t));
+ bzero(&fp->ctf_dldefs, sizeof (ctf_list_t));
+
+ /*
+ * Because the various containers share the data sections, we don't want
+ * to have ctf_close free it all. However, the name of the section is in
+ * fact unique to the ctf_sect_t. Thus we save the names of the symbol
+ * and string sections around the bzero() and restore them afterwards,
+ * ensuring that we don't result in a memory leak.
+ */
+ sname = fp->ctf_symtab.cts_name;
+ bzero(&fp->ctf_symtab, sizeof (ctf_sect_t));
+ fp->ctf_symtab.cts_name = sname;
+
+ sname = fp->ctf_strtab.cts_name;
+ bzero(&fp->ctf_strtab, sizeof (ctf_sect_t));
+ fp->ctf_strtab.cts_name = sname;
bcopy(fp, &ofp, sizeof (ctf_file_t));
bcopy(nfp, fp, sizeof (ctf_file_t));
@@ -563,6 +811,101 @@ ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type)
return (dtd);
}
+ctf_dsdef_t *
+ctf_dsd_lookup(ctf_file_t *fp, ulong_t idx)
+{
+ ctf_dsdef_t *dsd;
+
+ for (dsd = ctf_list_next(&fp->ctf_dsdefs); dsd != NULL;
+ dsd = ctf_list_next(dsd)) {
+ if (dsd->dsd_symidx == idx)
+ return (dsd);
+ }
+
+ return (NULL);
+}
+
+/*
+ * We order the ctf_dsdef_t by symbol index to make things better for updates.
+ */
+void
+ctf_dsd_insert(ctf_file_t *fp, ctf_dsdef_t *dsd)
+{
+ ctf_dsdef_t *i;
+
+ for (i = ctf_list_next(&fp->ctf_dsdefs); i != NULL;
+ i = ctf_list_next(i)) {
+ if (i->dsd_symidx > dsd->dsd_symidx)
+ break;
+ }
+
+ if (i == NULL) {
+ ctf_list_append(&fp->ctf_dsdefs, dsd);
+ return;
+ }
+
+ ctf_list_insert_before(&fp->ctf_dsdefs, i, dsd);
+}
+
+/* ARGSUSED */
+void
+ctf_dsd_delete(ctf_file_t *fp, ctf_dsdef_t *dsd)
+{
+ if (dsd->dsd_nargs > 0)
+ ctf_free(dsd->dsd_argc,
+ sizeof (ctf_id_t) * dsd->dsd_nargs);
+ ctf_list_delete(&fp->ctf_dsdefs, dsd);
+ ctf_free(dsd, sizeof (ctf_dsdef_t));
+}
+
+ctf_dldef_t *
+ctf_dld_lookup(ctf_file_t *fp, const char *name)
+{
+ ctf_dldef_t *dld;
+
+ for (dld = ctf_list_next(&fp->ctf_dldefs); dld != NULL;
+ dld = ctf_list_next(dld)) {
+ if (strcmp(name, dld->dld_name) == 0)
+ return (dld);
+ }
+
+ return (NULL);
+}
+
+void
+ctf_dld_insert(ctf_file_t *fp, ctf_dldef_t *dld, uint_t pos)
+{
+ ctf_dldef_t *l;
+
+ if (pos == 0) {
+ ctf_list_prepend(&fp->ctf_dldefs, dld);
+ return;
+ }
+
+ for (l = ctf_list_next(&fp->ctf_dldefs); pos != 0 && dld != NULL;
+ l = ctf_list_next(l), pos--)
+ ;
+
+ if (l == NULL)
+ ctf_list_append(&fp->ctf_dldefs, dld);
+ else
+ ctf_list_insert_before(&fp->ctf_dsdefs, l, dld);
+}
+
+void
+ctf_dld_delete(ctf_file_t *fp, ctf_dldef_t *dld)
+{
+ ctf_list_delete(&fp->ctf_dldefs, dld);
+
+ if (dld->dld_name != NULL) {
+ size_t len = strlen(dld->dld_name) + 1;
+ ctf_free(dld->dld_name, len);
+ fp->ctf_dtstrlen -= len;
+ }
+
+ ctf_free(dld, sizeof (ctf_dldef_t));
+}
+
/*
* Discard all of the dynamic type definitions that have been added to the
* container since the last call to ctf_update(). We locate such types by
@@ -583,10 +926,10 @@ ctf_discard(ctf_file_t *fp)
return (0); /* no update required */
for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+ ntd = ctf_list_prev(dtd);
if (dtd->dtd_type <= fp->ctf_dtoldid)
continue; /* skip types that have been committed */
- ntd = ctf_list_prev(dtd);
ctf_dtd_delete(fp, dtd);
}
@@ -637,26 +980,7 @@ ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp)
return (type);
}
-/*
- * When encoding integer sizes, we want to convert a byte count in the range
- * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function
- * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
- */
-static size_t
-clp2(size_t x)
-{
- x--;
-
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
-
- return (x + 1);
-}
-
-static ctf_id_t
+ctf_id_t
ctf_add_encoded(ctf_file_t *fp, uint_t flag,
const char *name, const ctf_encoding_t *ep, uint_t kind)
{
@@ -670,14 +994,22 @@ ctf_add_encoded(ctf_file_t *fp, uint_t flag,
return (CTF_ERR); /* errno is set for us */
dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
- dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY);
+
+ /*
+ * If the type's size is not an even number of bytes, then we should
+ * round up the type size to the nearest byte.
+ */
+ dtd->dtd_data.ctt_size = ep->cte_bits / NBBY;
+ if ((ep->cte_bits % NBBY) != 0)
+ dtd->dtd_data.ctt_size++;
dtd->dtd_u.dtu_enc = *ep;
return (type);
}
-static ctf_id_t
-ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind)
+ctf_id_t
+ctf_add_reftype(ctf_file_t *fp, uint_t flag,
+ const char *name, ctf_id_t ref, uint_t kind)
{
ctf_dtdef_t *dtd;
ctf_id_t type;
@@ -685,7 +1017,7 @@ ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind)
if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
return (ctf_set_errno(fp, EINVAL));
- if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
+ if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
return (CTF_ERR); /* errno is set for us */
ctf_ref_inc(fp, ref);
@@ -711,9 +1043,9 @@ ctf_add_float(ctf_file_t *fp, uint_t flag,
}
ctf_id_t
-ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+ctf_add_pointer(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
{
- return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER));
+ return (ctf_add_reftype(fp, flag, name, ref, CTF_K_POINTER));
}
ctf_id_t
@@ -728,13 +1060,18 @@ ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp)
fpd = fp;
if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
- ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+ ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) {
+ ctf_dprintf("bad contents for array: %ld\n",
+ arp->ctr_contents);
return (ctf_set_errno(fp, ECTF_BADID));
+ }
fpd = fp;
if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
- ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+ ctf_dtd_lookup(fp, arp->ctr_index) == NULL) {
+ ctf_dprintf("bad index for array: %ld\n", arp->ctr_index);
return (ctf_set_errno(fp, ECTF_BADID));
+ }
if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
return (CTF_ERR); /* errno is set for us */
@@ -781,7 +1118,7 @@ ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
}
ctf_id_t
-ctf_add_function(ctf_file_t *fp, uint_t flag,
+ctf_add_funcptr(ctf_file_t *fp, uint_t flag,
const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
{
ctf_dtdef_t *dtd;
@@ -842,20 +1179,34 @@ ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name)
{
ctf_hash_t *hp = &fp->ctf_structs;
ctf_helem_t *hep = NULL;
- ctf_dtdef_t *dtd;
- ctf_id_t type;
+ ctf_dtdef_t *dtd = NULL;
+ ctf_id_t type = CTF_ERR;
if (name != NULL)
hep = ctf_hash_lookup(hp, fp, name, strlen(name));
- if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
- dtd = ctf_dtd_lookup(fp, type = hep->h_type);
- else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
- return (CTF_ERR); /* errno is set for us */
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) {
+ type = hep->h_type;
+ dtd = ctf_dtd_lookup(fp, type);
+ if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_FORWARD)
+ dtd = NULL;
+ }
+ if (dtd == NULL) {
+ type = ctf_add_generic(fp, flag, name, &dtd);
+ if (type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+ }
+
+ VERIFY(type != CTF_ERR);
dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0);
dtd->dtd_data.ctt_size = 0;
+ /*
+ * Always dirty in case we modified a forward.
+ */
+ fp->ctf_flags |= LCTF_DIRTY;
+
return (type);
}
@@ -864,20 +1215,34 @@ ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name)
{
ctf_hash_t *hp = &fp->ctf_unions;
ctf_helem_t *hep = NULL;
- ctf_dtdef_t *dtd;
- ctf_id_t type;
+ ctf_dtdef_t *dtd = NULL;
+ ctf_id_t type = CTF_ERR;
if (name != NULL)
hep = ctf_hash_lookup(hp, fp, name, strlen(name));
- if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
- dtd = ctf_dtd_lookup(fp, type = hep->h_type);
- else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
- return (CTF_ERR); /* errno is set for us */
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) {
+ type = hep->h_type;
+ dtd = ctf_dtd_lookup(fp, type);
+ if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_FORWARD)
+ dtd = NULL;
+ }
+ if (dtd == NULL) {
+ type = ctf_add_generic(fp, flag, name, &dtd);
+ if (type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+ }
+
+ VERIFY(type != CTF_ERR);
dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0);
dtd->dtd_data.ctt_size = 0;
+ /*
+ * Always dirty in case we modified a forward.
+ */
+ fp->ctf_flags |= LCTF_DIRTY;
+
return (type);
}
@@ -886,20 +1251,34 @@ ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name)
{
ctf_hash_t *hp = &fp->ctf_enums;
ctf_helem_t *hep = NULL;
- ctf_dtdef_t *dtd;
- ctf_id_t type;
+ ctf_dtdef_t *dtd = NULL;
+ ctf_id_t type = CTF_ERR;
if (name != NULL)
hep = ctf_hash_lookup(hp, fp, name, strlen(name));
- if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
- dtd = ctf_dtd_lookup(fp, type = hep->h_type);
- else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
- return (CTF_ERR); /* errno is set for us */
+ if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) {
+ type = hep->h_type;
+ dtd = ctf_dtd_lookup(fp, type);
+ if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_FORWARD)
+ dtd = NULL;
+ }
+ if (dtd == NULL) {
+ type = ctf_add_generic(fp, flag, name, &dtd);
+ if (type == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+ }
+
+ VERIFY(type != CTF_ERR);
dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0);
dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
+ /*
+ * Always dirty in case we modified a forward.
+ */
+ fp->ctf_flags |= LCTF_DIRTY;
+
return (type);
}
@@ -965,21 +1344,21 @@ ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
}
ctf_id_t
-ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+ctf_add_volatile(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
{
- return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE));
+ return (ctf_add_reftype(fp, flag, name, ref, CTF_K_VOLATILE));
}
ctf_id_t
-ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+ctf_add_const(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
{
- return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST));
+ return (ctf_add_reftype(fp, flag, name, ref, CTF_K_CONST));
}
ctf_id_t
-ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
+ctf_add_restrict(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
{
- return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT));
+ return (ctf_add_reftype(fp, flag, name, ref, CTF_K_RESTRICT));
}
int
@@ -1012,8 +1391,10 @@ ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value)
for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next(dmd)) {
- if (strcmp(dmd->dmd_name, name) == 0)
+ if (strcmp(dmd->dmd_name, name) == 0) {
+ ctf_dprintf("encountered duplicate member %s\n", name);
return (ctf_set_errno(fp, ECTF_DUPMEMBER));
+ }
}
if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
@@ -1039,13 +1420,16 @@ ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value)
}
int
-ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
+ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type,
+ ulong_t offset)
{
ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid);
ctf_dmdef_t *dmd;
+ ulong_t mbitsz;
ssize_t msize, malign, ssize;
uint_t kind, vlen, root;
+ int mkind;
char *s = NULL;
if (!(fp->ctf_flags & LCTF_RDWR))
@@ -1064,19 +1448,58 @@ ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
if (vlen == CTF_MAX_VLEN)
return (ctf_set_errno(fp, ECTF_DTFULL));
- if (name != NULL) {
+ /*
+ * Structures may have members which are anonymous. If they have two of
+ * these, then the duplicate member detection would find it due to the
+ * string of "", so we skip it.
+ */
+ if (name != NULL && *name != '\0') {
for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next(dmd)) {
if (dmd->dmd_name != NULL &&
- strcmp(dmd->dmd_name, name) == 0)
+ strcmp(dmd->dmd_name, name) == 0) {
return (ctf_set_errno(fp, ECTF_DUPMEMBER));
+ }
}
}
if ((msize = ctf_type_size(fp, type)) == CTF_ERR ||
- (malign = ctf_type_align(fp, type)) == CTF_ERR)
+ (malign = ctf_type_align(fp, type)) == CTF_ERR ||
+ (mkind = ctf_type_kind(fp, type)) == CTF_ERR)
return (CTF_ERR); /* errno is set for us */
+ /*
+ * ctf_type_size returns sizes in bytes. However, for bitfields, that
+ * means that it may misrepresent and actually rounds it up to a power
+ * of two and store that in bytes. So instead we have to get the
+ * Integers encoding and rely on that.
+ */
+ if (mkind == CTF_K_INTEGER) {
+ ctf_encoding_t e;
+
+ if (ctf_type_encoding(fp, type, &e) == CTF_ERR)
+ return (CTF_ERR); /* errno is set for us */
+ mbitsz = e.cte_bits;
+ } else if (mkind == CTF_K_FORWARD) {
+ /*
+ * This is a rather rare case. In general one cannot add a
+ * forward to a structure. However, the CTF tools traditionally
+ * tried to add a forward to the struct cpu as the last member.
+ * Therefore, if we find one here, we're going to verify the
+ * size and make sure it's zero. It's certainly odd, but that's
+ * life.
+ *
+ * Further, if it's not an absolute position being specified,
+ * then we refuse to add it.
+ */
+ if (offset == ULONG_MAX)
+ return (ctf_set_errno(fp, EINVAL));
+ VERIFY(msize == 0);
+ mbitsz = msize;
+ } else {
+ mbitsz = msize * 8;
+ }
+
if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
return (ctf_set_errno(fp, EAGAIN));
@@ -1092,29 +1515,36 @@ ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
if (kind == CTF_K_STRUCT && vlen != 0) {
ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members);
ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type);
- size_t off = lmd->dmd_offset;
-
- ctf_encoding_t linfo;
- ssize_t lsize;
-
- if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR)
- off += linfo.cte_bits;
- else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR)
- off += lsize * NBBY;
-
- /*
- * Round up the offset of the end of the last member to the
- * next byte boundary, convert 'off' to bytes, and then round
- * it up again to the next multiple of the alignment required
- * by the new member. Finally, convert back to bits and store
- * the result in dmd_offset. Technically we could do more
- * efficient packing if the new member is a bit-field, but
- * we're the "compiler" and ANSI says we can do as we choose.
- */
- off = roundup(off, NBBY) / NBBY;
- off = roundup(off, MAX(malign, 1));
- dmd->dmd_offset = off * NBBY;
- ssize = off + msize;
+ size_t off;
+
+ if (offset == ULONG_MAX) {
+ ctf_encoding_t linfo;
+ ssize_t lsize;
+
+ off = lmd->dmd_offset;
+ if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR)
+ off += linfo.cte_bits;
+ else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR)
+ off += lsize * NBBY;
+
+ /*
+ * Round up the offset of the end of the last member to
+ * the next byte boundary, convert 'off' to bytes, and
+ * then round it up again to the next multiple of the
+ * alignment required by the new member. Finally,
+ * convert back to bits and store the result in
+ * dmd_offset. Technically we could do more efficient
+ * packing if the new member is a bit-field, but we're
+ * the "compiler" and ANSI says we can do as we choose.
+ */
+ off = roundup(off, NBBY) / NBBY;
+ off = roundup(off, MAX(malign, 1));
+ dmd->dmd_offset = off * NBBY;
+ ssize = off + msize;
+ } else {
+ dmd->dmd_offset = offset;
+ ssize = (offset + mbitsz) / NBBY;
+ }
} else {
dmd->dmd_offset = 0;
ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL);
@@ -1380,7 +1810,7 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
if (src_type == CTF_ERR)
return (CTF_ERR); /* errno is set for us */
- dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind);
+ dst_type = ctf_add_reftype(dst_fp, flag, NULL, src_type, kind);
break;
case CTF_K_ARRAY:
@@ -1415,7 +1845,7 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
if (ctc.ctc_return == CTF_ERR)
return (CTF_ERR); /* errno is set for us */
- dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL);
+ dst_type = ctf_add_funcptr(dst_fp, flag, &ctc, NULL);
break;
case CTF_K_STRUCT:
@@ -1540,3 +1970,227 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
return (dst_type);
}
+
+int
+ctf_add_function(ctf_file_t *fp, ulong_t idx, const ctf_funcinfo_t *fip,
+ const ctf_id_t *argc)
+{
+ int i;
+ ctf_dsdef_t *dsd;
+ ctf_file_t *afp;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (ctf_dsd_lookup(fp, idx) != NULL)
+ return (ctf_set_errno(fp, ECTF_CONFLICT));
+
+ if (symbase == NULL)
+ return (ctf_set_errno(fp, ECTF_STRTAB));
+
+ if (idx > fp->ctf_nsyms)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + idx;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
+ return (ctf_set_errno(fp, ECTF_NOTFUNC));
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + idx;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
+ return (ctf_set_errno(fp, ECTF_NOTFUNC));
+ }
+
+ afp = fp;
+ if (ctf_lookup_by_id(&afp, fip->ctc_return) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ for (i = 0; i < fip->ctc_argc; i++) {
+ afp = fp;
+ if (ctf_lookup_by_id(&afp, argc[i]) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+ }
+
+ dsd = ctf_alloc(sizeof (ctf_dsdef_t));
+ if (dsd == NULL)
+ return (ctf_set_errno(fp, ENOMEM));
+ dsd->dsd_nargs = fip->ctc_argc;
+ if (fip->ctc_flags & CTF_FUNC_VARARG)
+ dsd->dsd_nargs++;
+ if (dsd->dsd_nargs != 0) {
+ dsd->dsd_argc = ctf_alloc(sizeof (ctf_id_t) * dsd->dsd_nargs);
+ if (dsd->dsd_argc == NULL) {
+ ctf_free(dsd, sizeof (ctf_dsdef_t));
+ return (ctf_set_errno(fp, ENOMEM));
+ }
+ bcopy(argc, dsd->dsd_argc, sizeof (ctf_id_t) * fip->ctc_argc);
+ if (fip->ctc_flags & CTF_FUNC_VARARG)
+ dsd->dsd_argc[fip->ctc_argc] = 0;
+ }
+ dsd->dsd_symidx = idx;
+ dsd->dsd_tid = fip->ctc_return;
+
+ ctf_dsd_insert(fp, dsd);
+ fp->ctf_flags |= LCTF_DIRTY;
+
+ return (0);
+}
+
+int
+ctf_add_object(ctf_file_t *fp, ulong_t idx, ctf_id_t type)
+{
+ ctf_dsdef_t *dsd;
+ ctf_file_t *afp;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (ctf_dsd_lookup(fp, idx) != NULL)
+ return (ctf_set_errno(fp, ECTF_CONFLICT));
+
+ if (symbase == NULL)
+ return (ctf_set_errno(fp, ECTF_STRTAB));
+
+ if (idx > fp->ctf_nsyms)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + idx;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + idx;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT)
+ return (ctf_set_errno(fp, ECTF_NOTDATA));
+ }
+
+ afp = fp;
+ if (ctf_lookup_by_id(&afp, type) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ dsd = ctf_alloc(sizeof (ctf_dsdef_t));
+ if (dsd == NULL)
+ return (ctf_set_errno(fp, ENOMEM));
+ dsd->dsd_symidx = idx;
+ dsd->dsd_tid = type;
+ dsd->dsd_argc = NULL;
+
+ ctf_dsd_insert(fp, dsd);
+ fp->ctf_flags |= LCTF_DIRTY;
+
+ return (0);
+}
+
+void
+ctf_dataptr(ctf_file_t *fp, const void **addrp, size_t *sizep)
+{
+ if (addrp != NULL)
+ *addrp = fp->ctf_base;
+ if (sizep != NULL)
+ *sizep = fp->ctf_size;
+}
+
+int
+ctf_add_label(ctf_file_t *fp, const char *name, ctf_id_t type, uint_t position)
+{
+ ctf_file_t *fpd;
+ ctf_dldef_t *dld;
+
+ if (name == NULL)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ fpd = fp;
+ if (type != 0 && ctf_lookup_by_id(&fpd, type) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (type != 0 && (fp->ctf_flags & LCTF_CHILD) &&
+ CTF_TYPE_ISPARENT(type))
+ return (ctf_set_errno(fp, ECTF_NOPARENT));
+
+ if (ctf_dld_lookup(fp, name) != NULL)
+ return (ctf_set_errno(fp, ECTF_LABELEXISTS));
+
+ if ((dld = ctf_alloc(sizeof (ctf_dldef_t))) == NULL)
+ return (ctf_set_errno(fp, EAGAIN));
+
+ if ((dld->dld_name = ctf_strdup(name)) == NULL) {
+ ctf_free(dld, sizeof (ctf_dldef_t));
+ return (ctf_set_errno(fp, EAGAIN));
+ }
+
+ dld->dld_type = type;
+ fp->ctf_dtstrlen += strlen(name) + 1;
+ ctf_dld_insert(fp, dld, position);
+ fp->ctf_flags |= LCTF_DIRTY;
+
+ return (0);
+}
+
+/*
+ * Update the size of a structure or union. Note that we don't allow this to
+ * shrink the size of a struct or union, only to increase it. This is useful for
+ * cases when you have a structure whose actual size is larger than the sum of
+ * its members due to padding for natural alignment.
+ */
+int
+ctf_set_size(ctf_file_t *fp, ctf_id_t id, const ulong_t newsz)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, id);
+ uint_t kind;
+ size_t oldsz;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (dtd == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (ctf_set_errno(fp, ECTF_NOTSOU));
+
+ if ((oldsz = dtd->dtd_data.ctt_size) == CTF_LSIZE_SENT)
+ oldsz = CTF_TYPE_LSIZE(&dtd->dtd_data);
+
+ if (newsz < oldsz)
+ return (ctf_set_errno(fp, EINVAL));
+
+ if (newsz > CTF_MAX_SIZE) {
+ dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+ dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(newsz);
+ dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(newsz);
+ } else {
+ dtd->dtd_data.ctt_size = (ushort_t)newsz;
+ }
+
+ fp->ctf_flags |= LCTF_DIRTY;
+ return (0);
+}
+
+int
+ctf_set_root(ctf_file_t *fp, ctf_id_t id, const boolean_t vis)
+{
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, id);
+ uint_t kind, vlen;
+
+ if (!(fp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(fp, ECTF_RDONLY));
+
+ if (dtd == NULL)
+ return (ctf_set_errno(fp, ECTF_BADID));
+
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
+
+ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, vis, vlen);
+ return (0);
+}
diff --git a/usr/src/common/ctf/ctf_error.c b/usr/src/common/ctf/ctf_error.c
index fe3d0de0cb..1765b77b54 100644
--- a/usr/src/common/ctf/ctf_error.c
+++ b/usr/src/common/ctf/ctf_error.c
@@ -24,7 +24,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2012, Joyent, Inc.
+ * Copyright (c) 2015, Joyent, Inc.
*/
#include <ctf_impl.h>
@@ -75,7 +75,15 @@ static const char *const _ctf_errlist[] = {
"Duplicate member name definition", /* ECTF_DUPMEMBER */
"Conflicting type is already defined", /* ECTF_CONFLICT */
"Type has outstanding references", /* ECTF_REFERENCED */
- "Type is not a dynamic type" /* ECTF_NOTDYN */
+ "Type is not a dynamic type", /* ECTF_NOTDYN */
+ "Elf library failure", /* ECTF_ELF */
+ "Cannot merge child container", /* ECTF_MCHILD */
+ "Label already exists", /* ECTF_LABEL */
+ "Merged labels conflict", /* ECTF_LCONFLICT */
+ "Zlib library failure", /* ECTF_ZLIB */
+ "CTF conversion backend error", /* ECTF_CONVBKERR */
+ "No C source to convert from", /* ECTF_CONVNOCSRC */
+ "No applicable conversion backend" /* ECTF_NOCONVBKEND */
};
static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);
diff --git a/usr/src/common/ctf/ctf_hash.c b/usr/src/common/ctf/ctf_hash.c
index b10a7618f6..0c5a71a5ac 100644
--- a/usr/src/common/ctf/ctf_hash.c
+++ b/usr/src/common/ctf/ctf_hash.c
@@ -25,9 +25,8 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <ctf_impl.h>
+#include <sys/debug.h>
static const ushort_t _CTF_EMPTY[1] = { 0 };
diff --git a/usr/src/common/ctf/ctf_impl.h b/usr/src/common/ctf/ctf_impl.h
index f56fa6a005..93a85a8b4f 100644
--- a/usr/src/common/ctf/ctf_impl.h
+++ b/usr/src/common/ctf/ctf_impl.h
@@ -25,7 +25,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
#ifndef _CTF_IMPL_H
@@ -41,6 +41,8 @@
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/varargs.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
#define isspace(c) \
((c) == ' ' || (c) == '\t' || (c) == '\n' || \
@@ -56,6 +58,7 @@
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
+#include <stddef.h>
#endif /* _KERNEL */
@@ -77,6 +80,10 @@ typedef struct ctf_hash {
uint_t h_free; /* index of next free hash element */
} ctf_hash_t;
+struct ctf_idhash_iter {
+ int cii_id; /* Current iteration id */
+};
+
typedef struct ctf_strs {
const char *cts_strs; /* base address of string table */
size_t cts_len; /* size of string table in bytes */
@@ -159,6 +166,20 @@ typedef struct ctf_dtdef {
} dtd_u;
} ctf_dtdef_t;
+typedef struct ctf_dsdef {
+ ctf_list_t dsd_list; /* list forward/back pointers */
+ ulong_t dsd_symidx; /* symbol id */
+ ctf_id_t dsd_tid; /* type for obj, 0 if function */
+ uint_t dsd_nargs;
+ ctf_id_t *dsd_argc; /* function argv */
+} ctf_dsdef_t;
+
+typedef struct ctf_dldef {
+ ctf_list_t dld_list; /* list forward/back pointers */
+ char *dld_name; /* name of the label */
+ ctf_id_t dld_type; /* type ID associated with the label */
+} ctf_dldef_t;
+
typedef struct ctf_bundle {
ctf_file_t *ctb_file; /* CTF container handle */
ctf_id_t ctb_type; /* CTF type identifier */
@@ -211,6 +232,9 @@ struct ctf_file {
ulong_t ctf_dtnextid; /* next dynamic type id to assign */
ulong_t ctf_dtoldid; /* oldest id that has been committed */
void *ctf_specific; /* data for ctf_get/setspecific */
+ ctf_list_t ctf_dsdefs; /* list of dynamic obj/func definitions */
+ ctf_list_t ctf_dldefs; /* list of dynamic labels */
+ uint_t ctf_hflags; /* original flags on the header */
};
#define LCTF_INDEX_TO_TYPEPTR(fp, i) \
@@ -225,62 +249,15 @@ struct ctf_file {
#define LCTF_RDWR 0x0004 /* CTF container is writable */
#define LCTF_DIRTY 0x0008 /* CTF container has been modified */
-#define ECTF_BASE 1000 /* base value for libctf errnos */
-
-enum {
- ECTF_FMT = ECTF_BASE, /* file is not in CTF or ELF format */
- ECTF_ELFVERS, /* ELF version is more recent than libctf */
- ECTF_CTFVERS, /* CTF version is more recent than libctf */
- ECTF_ENDIAN, /* data is different endian-ness than lib */
- ECTF_SYMTAB, /* symbol table uses invalid entry size */
- ECTF_SYMBAD, /* symbol table data buffer invalid */
- ECTF_STRBAD, /* string table data buffer invalid */
- ECTF_CORRUPT, /* file data corruption detected */
- ECTF_NOCTFDATA, /* ELF file does not contain CTF data */
- ECTF_NOCTFBUF, /* buffer does not contain CTF data */
- ECTF_NOSYMTAB, /* symbol table data is not available */
- ECTF_NOPARENT, /* parent CTF container is not available */
- ECTF_DMODEL, /* data model mismatch */
- ECTF_MMAP, /* failed to mmap a data section */
- ECTF_ZMISSING, /* decompression library not installed */
- ECTF_ZINIT, /* failed to initialize decompression library */
- ECTF_ZALLOC, /* failed to allocate decompression buffer */
- ECTF_DECOMPRESS, /* failed to decompress CTF data */
- ECTF_STRTAB, /* string table for this string is missing */
- ECTF_BADNAME, /* string offset is corrupt w.r.t. strtab */
- ECTF_BADID, /* invalid type ID number */
- ECTF_NOTSOU, /* type is not a struct or union */
- ECTF_NOTENUM, /* type is not an enum */
- ECTF_NOTSUE, /* type is not a struct, union, or enum */
- ECTF_NOTINTFP, /* type is not an integer or float */
- ECTF_NOTARRAY, /* type is not an array */
- ECTF_NOTREF, /* type does not reference another type */
- ECTF_NAMELEN, /* buffer is too small to hold type name */
- ECTF_NOTYPE, /* no type found corresponding to name */
- ECTF_SYNTAX, /* syntax error in type name */
- ECTF_NOTFUNC, /* symtab entry does not refer to a function */
- ECTF_NOFUNCDAT, /* no func info available for function */
- ECTF_NOTDATA, /* symtab entry does not refer to a data obj */
- ECTF_NOTYPEDAT, /* no type info available for object */
- ECTF_NOLABEL, /* no label found corresponding to name */
- ECTF_NOLABELDATA, /* file does not contain any labels */
- ECTF_NOTSUP, /* feature not supported */
- ECTF_NOENUMNAM, /* enum element name not found */
- ECTF_NOMEMBNAM, /* member name not found */
- ECTF_RDONLY, /* CTF container is read-only */
- ECTF_DTFULL, /* CTF type is full (no more members allowed) */
- ECTF_FULL, /* CTF container is full */
- ECTF_DUPMEMBER, /* duplicate member name definition */
- ECTF_CONFLICT, /* conflicting type definition present */
- ECTF_REFERENCED, /* type has outstanding references */
- ECTF_NOTDYN /* type is not a dynamic type */
-};
+#define CTF_ELF_SCN_NAME ".SUNW_ctf"
extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *,
ssize_t *, ssize_t *);
extern const ctf_type_t *ctf_lookup_by_id(ctf_file_t **, ctf_id_t);
+extern ctf_file_t *ctf_fdcreate_int(int, int *, ctf_sect_t *);
+
extern int ctf_hash_create(ctf_hash_t *, ulong_t);
extern int ctf_hash_insert(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t);
extern int ctf_hash_define(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t);
@@ -294,12 +271,16 @@ extern void ctf_hash_destroy(ctf_hash_t *);
extern void ctf_list_append(ctf_list_t *, void *);
extern void ctf_list_prepend(ctf_list_t *, void *);
+extern void ctf_list_insert_before(ctf_list_t *, void *, void *);
extern void ctf_list_delete(ctf_list_t *, void *);
extern void ctf_dtd_insert(ctf_file_t *, ctf_dtdef_t *);
extern void ctf_dtd_delete(ctf_file_t *, ctf_dtdef_t *);
extern ctf_dtdef_t *ctf_dtd_lookup(ctf_file_t *, ctf_id_t);
+extern void ctf_dsd_delete(ctf_file_t *, ctf_dsdef_t *);
+extern void ctf_dld_delete(ctf_file_t *, ctf_dldef_t *);
+
extern void ctf_decl_init(ctf_decl_t *, char *, size_t);
extern void ctf_decl_fini(ctf_decl_t *);
extern void ctf_decl_push(ctf_decl_t *, ctf_file_t *, ctf_id_t);
@@ -327,6 +308,13 @@ extern void ctf_dprintf(const char *, ...);
extern void *ctf_zopen(int *);
+extern ctf_id_t ctf_add_encoded(ctf_file_t *, uint_t, const char *,
+ const ctf_encoding_t *, uint_t);
+extern ctf_id_t ctf_add_reftype(ctf_file_t *, uint_t, const char *, ctf_id_t,
+ uint_t);
+extern boolean_t ctf_sym_valid(uintptr_t, int, uint16_t, uint64_t,
+ uint32_t);
+
extern const char _CTF_SECTION[]; /* name of CTF ELF section */
extern const char _CTF_NULLSTR[]; /* empty string */
diff --git a/usr/src/common/ctf/ctf_open.c b/usr/src/common/ctf/ctf_open.c
index 001cf5c591..82b396e825 100644
--- a/usr/src/common/ctf/ctf_open.c
+++ b/usr/src/common/ctf/ctf_open.c
@@ -25,7 +25,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
#include <ctf_impl.h>
@@ -550,6 +550,7 @@ ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
void *buf, *base;
size_t size, hdrsz;
int err;
+ uint_t hflags;
if (ctfsect == NULL || ((symsect == NULL) != (strsect == NULL)))
return (ctf_set_open_errno(errp, EINVAL));
@@ -631,6 +632,7 @@ ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
* the CTF data buffer if it is compressed. Otherwise we just put
* the data section's buffer pointer into ctf_buf, below.
*/
+ hflags = hp.cth_flags;
if (hp.cth_flags & CTF_F_COMPRESS) {
size_t srclen, dstlen;
const void *src;
@@ -680,6 +682,7 @@ ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
bzero(fp, sizeof (ctf_file_t));
fp->ctf_version = hp.cth_version;
fp->ctf_fileops = &ctf_fileops[hp.cth_version];
+ fp->ctf_hflags = hflags;
bcopy(ctfsect, &fp->ctf_data, sizeof (ctf_sect_t));
if (symsect != NULL) {
@@ -883,6 +886,8 @@ void
ctf_close(ctf_file_t *fp)
{
ctf_dtdef_t *dtd, *ntd;
+ ctf_dsdef_t *dsd, *nsd;
+ ctf_dldef_t *dld, *nld;
if (fp == NULL)
return; /* allow ctf_close(NULL) to simplify caller code */
@@ -906,10 +911,25 @@ ctf_close(ctf_file_t *fp)
ctf_dtd_delete(fp, dtd);
}
+ for (dsd = ctf_list_prev(&fp->ctf_dsdefs); dsd != NULL; dsd = nsd) {
+ nsd = ctf_list_prev(dsd);
+ ctf_dsd_delete(fp, dsd);
+ }
+
+ for (dld = ctf_list_prev(&fp->ctf_dldefs); dld != NULL; dld = nld) {
+ nld = ctf_list_prev(dld);
+ ctf_dld_delete(fp, dld);
+ }
+
ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *));
if (fp->ctf_flags & LCTF_MMAP) {
- if (fp->ctf_data.cts_data != NULL)
+ /*
+ * Writeable containers shouldn't necessairily have the CTF
+ * section freed.
+ */
+ if (fp->ctf_data.cts_data != NULL &&
+ !(fp->ctf_flags & LCTF_RDWR))
ctf_sect_munmap(&fp->ctf_data);
if (fp->ctf_symtab.cts_data != NULL)
ctf_sect_munmap(&fp->ctf_symtab);
@@ -980,6 +1000,16 @@ ctf_parent_name(ctf_file_t *fp)
}
/*
+ * Return the label of the parent CTF container, if one exists. Otherwise return
+ * NULL.
+ */
+const char *
+ctf_parent_label(ctf_file_t *fp)
+{
+ return (fp->ctf_parlabel);
+}
+
+/*
* Import the types from the specified parent container by storing a pointer
* to it in ctf_parent and incrementing its reference count. Only one parent
* is allowed: if a parent already exists, it is replaced by the new parent.
@@ -1043,3 +1073,9 @@ ctf_getspecific(ctf_file_t *fp)
{
return (fp->ctf_specific);
}
+
+uint_t
+ctf_flags(ctf_file_t *fp)
+{
+ return (fp->ctf_hflags);
+}
diff --git a/usr/src/common/ctf/ctf_types.c b/usr/src/common/ctf/ctf_types.c
index ab1b9ff14b..18d2d3d88a 100644
--- a/usr/src/common/ctf/ctf_types.c
+++ b/usr/src/common/ctf/ctf_types.c
@@ -24,8 +24,12 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
#include <ctf_impl.h>
+#include <sys/debug.h>
ssize_t
ctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
@@ -138,19 +142,21 @@ ctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
}
/*
- * Iterate over every root (user-visible) type in the given CTF container.
- * We pass the type ID of each type to the specified callback function.
+ * Iterate over every type in the given CTF container. If the user doesn't ask
+ * for all types, then we only give them the user visible, aka root, types. We
+ * pass the type ID of each type to the specified callback function.
*/
int
-ctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg)
+ctf_type_iter(ctf_file_t *fp, boolean_t nonroot, ctf_type_f *func, void *arg)
{
ctf_id_t id, max = fp->ctf_typemax;
int rc, child = (fp->ctf_flags & LCTF_CHILD);
for (id = 1; id <= max; id++) {
const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
- if (CTF_INFO_ISROOT(tp->ctt_info) &&
- (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0)
+ if ((nonroot || CTF_INFO_ISROOT(tp->ctt_info)) &&
+ (rc = func(CTF_INDEX_TO_TYPE(id, child),
+ CTF_INFO_ISROOT(tp->ctt_info), arg)) != 0)
return (rc);
}
@@ -194,13 +200,91 @@ ctf_type_resolve(ctf_file_t *fp, ctf_id_t type)
}
/*
- * Lookup the given type ID and print a string name for it into buf. Return
- * the actual number of bytes (not including \0) needed to format the name.
+ * Format an integer type; if a vname is specified, we need to insert it prior
+ * to any bitfield ":24" suffix. This works out far simpler than figuring it
+ * out from scratch.
+ */
+static const char *
+ctf_format_int(ctf_decl_t *cd, const char *vname, const char *qname,
+ const char *name)
+{
+ const char *c;
+
+ if (vname == NULL) {
+ if (qname != NULL)
+ ctf_decl_sprintf(cd, "%s`%s", qname, name);
+ else
+ ctf_decl_sprintf(cd, "%s", name);
+ return (NULL);
+ }
+
+ if ((c = strchr(name, ':')) == NULL) {
+ ctf_decl_sprintf(cd, "%s", name);
+ return (vname);
+ }
+
+ /* "unsigned int mybits:23" */
+ ctf_decl_sprintf(cd, "%.*s %s%s", c - name, name, vname, c);
+ return (NULL);
+}
+
+static void
+ctf_format_func(ctf_file_t *fp, ctf_decl_t *cd,
+ const char *vname, ctf_id_t id, int want_func_args)
+{
+ ctf_funcinfo_t fi;
+ /* We'll presume zone_create() is a bad example. */
+ ctf_id_t args[20];
+
+ ctf_decl_sprintf(cd, "%s(", vname == NULL ? "" : vname);
+
+ if (!want_func_args)
+ goto out;
+
+ if (ctf_func_info_by_id(fp, id, &fi) != 0)
+ goto out;
+
+ if (fi.ctc_argc > ARRAY_SIZE(args))
+ fi.ctc_argc = ARRAY_SIZE(args);
+
+ if (fi.ctc_argc == 0) {
+ ctf_decl_sprintf(cd, "void");
+ goto out;
+ }
+
+ if (ctf_func_args_by_id(fp, id, fi.ctc_argc, args) != 0)
+ goto out;
+
+ for (size_t i = 0; i < fi.ctc_argc; i++) {
+ char aname[512];
+
+ if (ctf_type_name(fp, args[i], aname, sizeof (aname)) == NULL)
+ (void) strlcpy(aname, "unknown_t", sizeof (aname));
+
+ ctf_decl_sprintf(cd, "%s%s", aname,
+ i + 1 == fi.ctc_argc ? "" : ", ");
+ }
+
+ if (fi.ctc_flags & CTF_FUNC_VARARG)
+ ctf_decl_sprintf(cd, "%s...", fi.ctc_argc == 0 ? "" : ", ");
+
+out:
+ ctf_decl_sprintf(cd, ")");
+}
+
+/*
+ * Lookup the given type ID and print a string name for it into buf. Return the
+ * actual number of bytes (not including \0) needed to format the name.
+ *
+ * "vname" is an optional variable name or similar, so array suffix formatting,
+ * bitfields, and functions are C-correct. (This is not perfect, as can be seen
+ * in kiconv_ops_t.)
*/
static ssize_t
ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
- const char *qname)
+ const char *vname, const char *qname)
{
+ int want_func_args = (vname != NULL);
ctf_decl_t cd;
ctf_decl_node_t *cdp;
ctf_decl_prec_t prec, lp, rp;
@@ -252,6 +336,8 @@ ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
switch (cdp->cd_kind) {
case CTF_K_INTEGER:
+ vname = ctf_format_int(&cd, vname, qname, name);
+ break;
case CTF_K_FLOAT:
case CTF_K_TYPEDEF:
if (qname != NULL)
@@ -262,10 +348,14 @@ ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
ctf_decl_sprintf(&cd, "*");
break;
case CTF_K_ARRAY:
- ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
+ ctf_decl_sprintf(&cd, "%s[%u]",
+ vname != NULL ? vname : "", cdp->cd_n);
+ vname = NULL;
break;
case CTF_K_FUNCTION:
- ctf_decl_sprintf(&cd, "()");
+ ctf_format_func(fp, &cd, vname,
+ cdp->cd_type, want_func_args);
+ vname = NULL;
break;
case CTF_K_STRUCT:
case CTF_K_FORWARD:
@@ -300,10 +390,29 @@ ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
k = cdp->cd_kind;
}
- if (rp == prec)
+ if (rp == prec) {
+ /*
+ * Peek ahead: if we're going to hit a function,
+ * we want to insert its name now before this closing
+ * bracket.
+ */
+ if (vname != NULL && prec < CTF_PREC_FUNCTION) {
+ cdp = ctf_list_next(
+ &cd.cd_nodes[CTF_PREC_FUNCTION]);
+
+ if (cdp != NULL) {
+ ctf_decl_sprintf(&cd, "%s", vname);
+ vname = NULL;
+ }
+ }
+
ctf_decl_sprintf(&cd, ")");
+ }
}
+ if (vname != NULL)
+ ctf_decl_sprintf(&cd, " %s", vname);
+
if (cd.cd_len >= len)
(void) ctf_set_errno(fp, ECTF_NAMELEN);
@@ -314,7 +423,7 @@ ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
ssize_t
ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
{
- return (ctf_type_qlname(fp, type, buf, len, NULL));
+ return (ctf_type_qlname(fp, type, buf, len, NULL, NULL));
}
/*
@@ -324,7 +433,7 @@ ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
char *
ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
{
- ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL);
+ ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL, NULL);
return (rv >= 0 && rv < len ? buf : NULL);
}
@@ -332,10 +441,17 @@ char *
ctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
const char *qname)
{
- ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname);
+ ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL, qname);
return (rv >= 0 && rv < len ? buf : NULL);
}
+char *
+ctf_type_cname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
+ const char *cname)
+{
+ ssize_t rv = ctf_type_qlname(fp, type, buf, len, cname, NULL);
+ return (rv >= 0 && rv < len ? buf : NULL);
+}
/*
* Resolve the type down to a base type node, and then return the size
@@ -361,6 +477,9 @@ ctf_type_size(ctf_file_t *fp, ctf_id_t type)
case CTF_K_FUNCTION:
return (0); /* function size is only known by symtab */
+ case CTF_K_FORWARD:
+ return (0);
+
case CTF_K_ENUM:
return (fp->ctf_dmodel->ctd_int);
@@ -380,7 +499,22 @@ ctf_type_size(ctf_file_t *fp, ctf_id_t type)
return (-1); /* errno is set for us */
return (size * ar.ctr_nelems);
-
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ /*
+ * If we have a zero size, we may be in the process of adding a
+ * structure or union but having not called ctf_update() to deal
+ * with the circular dependencies in such structures and unions.
+ * To handle that case, if we get a size of zero from the ctt,
+ * we look up the dtdef and use its size instead.
+ */
+ size = ctf_get_ctt_size(fp, tp, NULL, NULL);
+ if (size == 0) {
+ ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
+ if (dtd != NULL)
+ return (dtd->dtd_data.ctt_size);
+ }
+ return (size);
default:
return (ctf_get_ctt_size(fp, tp, NULL, NULL));
}
@@ -868,3 +1002,309 @@ ctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg)
{
return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0));
}
+
+int
+ctf_func_info_by_id(ctf_file_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ushort_t *dp;
+ int nargs;
+ ssize_t increment;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_FUNCTION)
+ return (ctf_set_errno(ofp, ECTF_NOTFUNC));
+
+ fip->ctc_return = tp->ctt_type;
+ nargs = LCTF_INFO_VLEN(fp, tp->ctt_info);
+ fip->ctc_argc = nargs;
+ fip->ctc_flags = 0;
+
+ /* dp should now point to the first argument */
+ if (nargs != 0) {
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+ dp = (ushort_t *)((uintptr_t)fp->ctf_buf +
+ fp->ctf_txlate[CTF_TYPE_TO_INDEX(type)] + increment);
+ if (dp[nargs - 1] == 0) {
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ fip->ctc_argc--;
+ }
+ }
+
+ return (0);
+}
+
+int
+ctf_func_args_by_id(ctf_file_t *fp, ctf_id_t type, uint_t argc, ctf_id_t *argv)
+{
+ ctf_file_t *ofp = fp;
+ const ctf_type_t *tp;
+ const ushort_t *dp;
+ int nargs;
+ ssize_t increment;
+
+ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
+ return (CTF_ERR); /* errno is set for us */
+
+ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_FUNCTION)
+ return (ctf_set_errno(ofp, ECTF_NOTFUNC));
+
+ nargs = LCTF_INFO_VLEN(fp, tp->ctt_info);
+ (void) ctf_get_ctt_size(fp, tp, NULL, &increment);
+ dp = (ushort_t *)((uintptr_t)fp->ctf_buf +
+ fp->ctf_txlate[CTF_TYPE_TO_INDEX(type)] +
+ increment);
+ if (nargs != 0 && dp[nargs - 1] == 0)
+ nargs--;
+
+ for (nargs = MIN(argc, nargs); nargs != 0; nargs--)
+ *argv++ = *dp++;
+
+ return (0);
+}
+
+int
+ctf_object_iter(ctf_file_t *fp, ctf_object_f *func, void *arg)
+{
+ int i, ret;
+ ctf_id_t id;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ if (fp->ctf_symtab.cts_data == NULL)
+ return (ctf_set_errno(fp, ECTF_NOSYMTAB));
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ char *name;
+ if (fp->ctf_sxlate[i] == -1u)
+ continue;
+ id = *(ushort_t *)((uintptr_t)fp->ctf_buf +
+ fp->ctf_sxlate[i]);
+
+ /*
+ * Validate whether or not we're looking at a data object as
+ * oposed to a function.
+ */
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT)
+ continue;
+ if (fp->ctf_strtab.cts_data != NULL &&
+ symp->st_name != 0)
+ name = (char *)(strbase + symp->st_name);
+ else
+ name = NULL;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT)
+ continue;
+ if (fp->ctf_strtab.cts_data != NULL &&
+ symp->st_name != 0)
+ name = (char *)(strbase + symp->st_name);
+ else
+ name = NULL;
+ }
+
+ if ((ret = func(name, id, i, arg)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+int
+ctf_function_iter(ctf_file_t *fp, ctf_function_f *func, void *arg)
+{
+ int i, ret;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ if (fp->ctf_symtab.cts_data == NULL)
+ return (ctf_set_errno(fp, ECTF_NOSYMTAB));
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ char *name;
+ ushort_t info, *dp;
+ ctf_funcinfo_t fi;
+ if (fp->ctf_sxlate[i] == -1u)
+ continue;
+
+ dp = (ushort_t *)((uintptr_t)fp->ctf_buf +
+ fp->ctf_sxlate[i]);
+ info = *dp;
+ if (info == 0)
+ continue;
+
+ /*
+ * This may be a function or it may be a data object. We have to
+ * consult the symbol table to be certain. Functions are encoded
+ * with their info, data objects with their actual type.
+ */
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
+ continue;
+ if (fp->ctf_strtab.cts_data != NULL)
+ name = (char *)(strbase + symp->st_name);
+ else
+ name = NULL;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
+ continue;
+ if (fp->ctf_strtab.cts_data != NULL)
+ name = (char *)(strbase + symp->st_name);
+ else
+ name = NULL;
+ }
+
+ if (LCTF_INFO_KIND(fp, info) != CTF_K_FUNCTION)
+ continue;
+ dp++;
+ fi.ctc_return = *dp;
+ dp++;
+ fi.ctc_argc = LCTF_INFO_VLEN(fp, info);
+ fi.ctc_flags = 0;
+
+ if (fi.ctc_argc != 0 && dp[fi.ctc_argc - 1] == 0) {
+ fi.ctc_flags |= CTF_FUNC_VARARG;
+ fi.ctc_argc--;
+ }
+
+ if ((ret = func(name, i, &fi, arg)) != 0)
+ return (ret);
+
+ }
+
+ return (0);
+}
+
+char *
+ctf_symbol_name(ctf_file_t *fp, ulong_t idx, char *buf, size_t len)
+{
+ const char *name;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ if (fp->ctf_symtab.cts_data == NULL) {
+ (void) ctf_set_errno(fp, ECTF_NOSYMTAB);
+ return (NULL);
+ }
+
+ if (fp->ctf_strtab.cts_data == NULL) {
+ (void) ctf_set_errno(fp, ECTF_STRTAB);
+ return (NULL);
+ }
+
+ if (idx > fp->ctf_nsyms) {
+ (void) ctf_set_errno(fp, ECTF_NOTDATA);
+ return (NULL);
+ }
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + idx;
+ if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT &&
+ ELF32_ST_TYPE(symp->st_info) != STT_FUNC) {
+ (void) ctf_set_errno(fp, ECTF_NOTDATA);
+ return (NULL);
+ }
+ if (symp->st_name == 0) {
+ (void) ctf_set_errno(fp, ENOENT);
+ return (NULL);
+ }
+ name = (const char *)(strbase + symp->st_name);
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + idx;
+ if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC &&
+ ELF64_ST_TYPE(symp->st_info) != STT_OBJECT) {
+ (void) ctf_set_errno(fp, ECTF_NOTDATA);
+ return (NULL);
+ }
+ if (symp->st_name == 0) {
+ (void) ctf_set_errno(fp, ENOENT);
+ return (NULL);
+ }
+ name = (const char *)(strbase + symp->st_name);
+ }
+
+ (void) strlcpy(buf, name, len);
+
+ return (buf);
+}
+
+int
+ctf_string_iter(ctf_file_t *fp, ctf_string_f *func, void *arg)
+{
+ int rc;
+ const char *strp = fp->ctf_str[CTF_STRTAB_0].cts_strs;
+ size_t strl = fp->ctf_str[CTF_STRTAB_0].cts_len;
+
+ while (strl > 0) {
+ size_t len;
+
+ if ((rc = func(strp, arg)) != 0)
+ return (rc);
+
+ len = strlen(strp) + 1;
+ strl -= len;
+ strp += len;
+ }
+
+ return (0);
+}
+
+/*
+ * fp isn't strictly necessary at the moment. However, if we ever rev the file
+ * format, the valid values for kind will change.
+ */
+const char *
+ctf_kind_name(ctf_file_t *fp, int kind)
+{
+ switch (kind) {
+ case CTF_K_INTEGER:
+ return ("integer");
+ case CTF_K_FLOAT:
+ return ("float");
+ case CTF_K_POINTER:
+ return ("pointer");
+ case CTF_K_ARRAY:
+ return ("array");
+ case CTF_K_FUNCTION:
+ return ("function");
+ case CTF_K_STRUCT:
+ return ("struct");
+ case CTF_K_UNION:
+ return ("union");
+ case CTF_K_ENUM:
+ return ("enum");
+ case CTF_K_FORWARD:
+ return ("forward");
+ case CTF_K_TYPEDEF:
+ return ("typedef");
+ case CTF_K_VOLATILE:
+ return ("volatile");
+ case CTF_K_CONST:
+ return ("const");
+ case CTF_K_RESTRICT:
+ return ("restrict");
+ case CTF_K_UNKNOWN:
+ default:
+ return ("unknown");
+ }
+}
+
+ctf_id_t
+ctf_max_id(ctf_file_t *fp)
+{
+ int child = (fp->ctf_flags & LCTF_CHILD);
+ return (fp->ctf_typemax + (child ? CTF_CHILD_START : 0));
+}
+
+ulong_t
+ctf_nr_syms(ctf_file_t *fp)
+{
+ return (fp->ctf_nsyms);
+}
diff --git a/usr/src/common/ctf/ctf_util.c b/usr/src/common/ctf/ctf_util.c
index 740d403e8c..550195b5e1 100644
--- a/usr/src/common/ctf/ctf_util.c
+++ b/usr/src/common/ctf/ctf_util.c
@@ -23,10 +23,12 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2015, Joyent, Inc.
+ */
#include <ctf_impl.h>
+#include <sys/debug.h>
/*
* Simple doubly-linked list append routine. This implementation assumes that
@@ -71,6 +73,24 @@ ctf_list_prepend(ctf_list_t *lp, void *new)
lp->l_prev = p;
}
+void
+ctf_list_insert_before(ctf_list_t *head, void *item, void *nitem)
+{
+ ctf_list_t *lp = item;
+ ctf_list_t *new = nitem;
+ ctf_list_t *prev = lp->l_prev;
+
+ lp->l_prev = new;
+ new->l_next = lp;
+ new->l_prev = prev;
+ if (prev != NULL) {
+ prev->l_next = new;
+ } else {
+ ASSERT(head->l_next == lp);
+ head->l_next = new;
+ }
+}
+
/*
* Delete the specified existing element from the given ctf_list_t. The
* existing pointer should be pointing at a struct with embedded ctf_list_t.
@@ -150,3 +170,22 @@ ctf_set_errno(ctf_file_t *fp, int err)
fp->ctf_errno = err;
return (CTF_ERR);
}
+
+boolean_t
+ctf_sym_valid(uintptr_t strbase, int type, uint16_t shndx, uint64_t val,
+ uint32_t noff)
+{
+ const char *name;
+
+ if (type != STT_OBJECT && type != STT_FUNC)
+ return (B_FALSE);
+ if (shndx == SHN_UNDEF || noff == 0)
+ return (B_FALSE);
+ if (type == STT_OBJECT && shndx == SHN_ABS && val == 0)
+ return (B_FALSE);
+ name = (char *)(strbase + noff);
+ if (strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}