git: bdf290cd3e1a - main - ctf: Add v3 support to CTF tools, ctf{convert,dump,merge}

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 07 Mar 2022 15:43:32 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=bdf290cd3e1a69d41c2f8bb60bd415cfa78adba2

commit bdf290cd3e1a69d41c2f8bb60bd415cfa78adba2
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2022-03-07 13:54:18 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-03-07 15:43:19 +0000

    ctf: Add v3 support to CTF tools, ctf{convert,dump,merge}
    
    ctfdump handles v2 and v3.  ctfconvert now emits only CTFv3, whereas
    ctfmerge can merge v2 and v3 containers into v3 containers.
    
    MFC after:      1 month
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D34364
---
 cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c      | 453 ++++++++++++++--------
 cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c |   4 +-
 cddl/contrib/opensolaris/tools/ctf/dump/dump.c    | 286 +++++++++-----
 sys/sys/ctf.h                                     |   2 +-
 4 files changed, 473 insertions(+), 272 deletions(-)

diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
index 5cd2de9f43ea..b3b4c1f7168f 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c
@@ -58,8 +58,7 @@ struct ctf_buf {
 	caddr_t ctb_end;	/* pointer to end of buffer */
 	caddr_t ctb_ptr;	/* pointer to empty buffer space */
 	size_t ctb_size;	/* size of buffer */
-	int nptent;		/* number of processed types */
-	int ntholes;		/* number of type holes */
+	uint_t nptent;		/* number of processed types */
 };
 
 /*
@@ -165,10 +164,10 @@ write_label(void *arg1, void *arg2)
 static void
 write_objects(iidesc_t *idp, ctf_buf_t *b)
 {
-	ushort_t id = (idp ? idp->ii_dtype->t_id : 0);
+	uint_t id = (idp ? idp->ii_dtype->t_id : 0);
 
 	if (target_requires_swap) {
-		SWAP_16(id);
+		SWAP_32(id);
 	}
 
 	ctf_buf_write(b, &id, sizeof (id));
@@ -179,8 +178,8 @@ write_objects(iidesc_t *idp, ctf_buf_t *b)
 static void
 write_functions(iidesc_t *idp, ctf_buf_t *b)
 {
-	ushort_t fdata[2];
-	ushort_t id;
+	uint_t fdata[2];
+	uint_t id;
 	int nargs;
 	int i;
 
@@ -194,17 +193,17 @@ write_functions(iidesc_t *idp, ctf_buf_t *b)
 
 	nargs = idp->ii_nargs + (idp->ii_vargs != 0);
 
-	if (nargs > CTF_MAX_VLEN) {
+	if (nargs > CTF_V3_MAX_VLEN) {
 		terminate("function %s has too many args: %d > %d\n",
-		    idp->ii_name, nargs, CTF_MAX_VLEN);
+		    idp->ii_name, nargs, CTF_V3_MAX_VLEN);
 	}
 
-	fdata[0] = CTF_TYPE_INFO(CTF_K_FUNCTION, 1, nargs);
+	fdata[0] = CTF_V3_TYPE_INFO(CTF_K_FUNCTION, 1, nargs);
 	fdata[1] = idp->ii_dtype->t_id;
 
 	if (target_requires_swap) {
-		SWAP_16(fdata[0]);
-		SWAP_16(fdata[1]);
+		SWAP_32(fdata[0]);
+		SWAP_32(fdata[1]);
 	}
 
 	ctf_buf_write(b, fdata, sizeof (fdata));
@@ -213,7 +212,7 @@ write_functions(iidesc_t *idp, ctf_buf_t *b)
 		id = idp->ii_args[i]->t_id;
 
 		if (target_requires_swap) {
-			SWAP_16(id);
+			SWAP_32(id);
 		}
 
 		ctf_buf_write(b, &id, sizeof (id));
@@ -234,29 +233,29 @@ write_functions(iidesc_t *idp, ctf_buf_t *b)
  * doesn't need to care.
  */
 static void
-write_sized_type_rec(ctf_buf_t *b, ctf_type_t *ctt, size_t size)
+write_sized_type_rec(ctf_buf_t *b, struct ctf_type_v3 *ctt, size_t size)
 {
-	if (size > CTF_MAX_SIZE) {
-		ctt->ctt_size = CTF_LSIZE_SENT;
+	if (size > CTF_V3_MAX_SIZE) {
+		ctt->ctt_size = CTF_V3_LSIZE_SENT;
 		ctt->ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
 		ctt->ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
 		if (target_requires_swap) {
 			SWAP_32(ctt->ctt_name);
-			SWAP_16(ctt->ctt_info);
-			SWAP_16(ctt->ctt_size);
+			SWAP_32(ctt->ctt_info);
+			SWAP_32(ctt->ctt_size);
 			SWAP_32(ctt->ctt_lsizehi);
 			SWAP_32(ctt->ctt_lsizelo);
 		}
 		ctf_buf_write(b, ctt, sizeof (*ctt));
 	} else {
-		ctf_stype_t *cts = (ctf_stype_t *)ctt;
+		struct ctf_stype_v3 *cts = (struct ctf_stype_v3 *)ctt;
 
-		cts->ctt_size = (ushort_t)size;
+		cts->ctt_size = size;
 
 		if (target_requires_swap) {
 			SWAP_32(cts->ctt_name);
-			SWAP_16(cts->ctt_info);
-			SWAP_16(cts->ctt_size);
+			SWAP_32(cts->ctt_info);
+			SWAP_32(cts->ctt_size);
 		}
 
 		ctf_buf_write(b, cts, sizeof (*cts));
@@ -264,14 +263,14 @@ write_sized_type_rec(ctf_buf_t *b, ctf_type_t *ctt, size_t size)
 }
 
 static void
-write_unsized_type_rec(ctf_buf_t *b, ctf_type_t *ctt)
+write_unsized_type_rec(ctf_buf_t *b, struct ctf_type_v3 *ctt)
 {
-	ctf_stype_t *cts = (ctf_stype_t *)ctt;
+	struct ctf_stype_v3 *cts = (struct ctf_stype_v3 *)ctt;
 
 	if (target_requires_swap) {
 		SWAP_32(cts->ctt_name);
-		SWAP_16(cts->ctt_info);
-		SWAP_16(cts->ctt_size);
+		SWAP_32(cts->ctt_info);
+		SWAP_32(cts->ctt_size);
 	}
 
 	ctf_buf_write(b, cts, sizeof (*cts));
@@ -292,14 +291,12 @@ write_type(void *arg1, void *arg2)
 	int isroot = tp->t_flags & TDESC_F_ISROOT;
 	int i;
 
-	ctf_type_t ctt;
-	ctf_array_t cta;
-	ctf_member_t ctm;
-	ctf_lmember_t ctlm;
-	ctf_enum_t cte;
-	ushort_t id;
-
-	ctlm.ctlm_pad = 0;
+	struct ctf_type_v3 ctt;
+	struct ctf_array_v3 cta;
+	struct ctf_member_v3 ctm;
+	struct ctf_lmember_v3 ctlm;
+	struct ctf_enum cte;
+	uint_t id;
 
 	/*
 	 * There shouldn't be any holes in the type list (where a hole is
@@ -308,13 +305,13 @@ write_type(void *arg1, void *arg2)
 	 * fake entries to fill the holes, or we won't be able to reconstruct
 	 * the tree from the written data.
 	 */
-	if (++b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) {
+	if (++b->nptent < CTF_V3_TYPE_TO_INDEX(tp->t_id)) {
 		debug(2, "genctf: type hole from %d < x < %d\n",
-		    b->nptent - 1, CTF_TYPE_TO_INDEX(tp->t_id));
+		    b->nptent - 1, CTF_V3_TYPE_TO_INDEX(tp->t_id));
 
 		ctt.ctt_name = CTF_TYPE_NAME(CTF_STRTAB_0, 0);
-		ctt.ctt_info = CTF_TYPE_INFO(0, 0, 0);
-		while (b->nptent < CTF_TYPE_TO_INDEX(tp->t_id)) {
+		ctt.ctt_info = CTF_V3_TYPE_INFO(0, 0, 0);
+		while (b->nptent < CTF_V3_TYPE_TO_INDEX(tp->t_id)) {
 			write_sized_type_rec(b, &ctt, 0);
 			b->nptent++;
 		}
@@ -327,10 +324,10 @@ write_type(void *arg1, void *arg2)
 	case INTRINSIC:
 		ip = tp->t_intr;
 		if (ip->intr_type == INTR_INT)
-			ctt.ctt_info = CTF_TYPE_INFO(CTF_K_INTEGER,
+			ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_INTEGER,
 			    isroot, 1);
 		else
-			ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FLOAT, isroot, 1);
+			ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FLOAT, isroot, 1);
 		write_sized_type_rec(b, &ctt, tp->t_size);
 
 		encoding = 0;
@@ -355,21 +352,21 @@ write_type(void *arg1, void *arg2)
 		break;
 
 	case POINTER:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_POINTER, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_POINTER, isroot, 0);
 		ctt.ctt_type = tp->t_tdesc->t_id;
 		write_unsized_type_rec(b, &ctt);
 		break;
 
 	case ARRAY:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, isroot, 1);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_ARRAY, isroot, 1);
 		write_sized_type_rec(b, &ctt, tp->t_size);
 
 		cta.cta_contents = tp->t_ardef->ad_contents->t_id;
 		cta.cta_index = tp->t_ardef->ad_idxtype->t_id;
 		cta.cta_nelems = tp->t_ardef->ad_nelems;
 		if (target_requires_swap) {
-			SWAP_16(cta.cta_contents);
-			SWAP_16(cta.cta_index);
+			SWAP_32(cta.cta_contents);
+			SWAP_32(cta.cta_index);
 			SWAP_32(cta.cta_nelems);
 		}
 		ctf_buf_write(b, &cta, sizeof (cta));
@@ -380,19 +377,19 @@ write_type(void *arg1, void *arg2)
 		for (i = 0, mp = tp->t_members; mp != NULL; mp = mp->ml_next)
 			i++; /* count up struct or union members */
 
-		if (i > CTF_MAX_VLEN) {
+		if (i > CTF_V3_MAX_VLEN) {
 			terminate("sou %s has too many members: %d > %d\n",
-			    tdesc_name(tp), i, CTF_MAX_VLEN);
+			    tdesc_name(tp), i, CTF_V3_MAX_VLEN);
 		}
 
 		if (tp->t_type == STRUCT)
-			ctt.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, isroot, i);
+			ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_STRUCT, isroot, i);
 		else
-			ctt.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, isroot, i);
+			ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_UNION, isroot, i);
 
 		write_sized_type_rec(b, &ctt, tp->t_size);
 
-		if (tp->t_size < CTF_LSTRUCT_THRESH) {
+		if (tp->t_size < CTF_V3_LSTRUCT_THRESH) {
 			for (mp = tp->t_members; mp != NULL; mp = mp->ml_next) {
 				offset = strtab_insert(&b->ctb_strtab,
 				    mp->ml_name);
@@ -403,8 +400,8 @@ write_type(void *arg1, void *arg2)
 				ctm.ctm_offset = mp->ml_offset;
 				if (target_requires_swap) {
 					SWAP_32(ctm.ctm_name);
-					SWAP_16(ctm.ctm_type);
-					SWAP_16(ctm.ctm_offset);
+					SWAP_32(ctm.ctm_type);
+					SWAP_32(ctm.ctm_offset);
 				}
 				ctf_buf_write(b, &ctm, sizeof (ctm));
 			}
@@ -423,7 +420,7 @@ write_type(void *arg1, void *arg2)
 
 				if (target_requires_swap) {
 					SWAP_32(ctlm.ctlm_name);
-					SWAP_16(ctlm.ctlm_type);
+					SWAP_32(ctlm.ctlm_type);
 					SWAP_32(ctlm.ctlm_offsethi);
 					SWAP_32(ctlm.ctlm_offsetlo);
 				}
@@ -437,11 +434,11 @@ write_type(void *arg1, void *arg2)
 		for (i = 0, ep = tp->t_emem; ep != NULL; ep = ep->el_next)
 			i++; /* count up enum members */
 
-		if (i > CTF_MAX_VLEN) {
-			i = CTF_MAX_VLEN;
+		if (i > CTF_V3_MAX_VLEN) {
+			i = CTF_V3_MAX_VLEN;
 		}
 
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, isroot, i);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_ENUM, isroot, i);
 		write_sized_type_rec(b, &ctt, tp->t_size);
 
 		for (ep = tp->t_emem; ep != NULL && i > 0; ep = ep->el_next) {
@@ -460,25 +457,25 @@ write_type(void *arg1, void *arg2)
 		break;
 
 	case FORWARD:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FORWARD, isroot, 0);
 		ctt.ctt_type = 0;
 		write_unsized_type_rec(b, &ctt);
 		break;
 
 	case TYPEDEF:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_TYPEDEF, isroot, 0);
 		ctt.ctt_type = tp->t_tdesc->t_id;
 		write_unsized_type_rec(b, &ctt);
 		break;
 
 	case VOLATILE:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_VOLATILE, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_VOLATILE, isroot, 0);
 		ctt.ctt_type = tp->t_tdesc->t_id;
 		write_unsized_type_rec(b, &ctt);
 		break;
 
 	case CONST:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_CONST, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_CONST, isroot, 0);
 		ctt.ctt_type = tp->t_tdesc->t_id;
 		write_unsized_type_rec(b, &ctt);
 		break;
@@ -486,12 +483,12 @@ write_type(void *arg1, void *arg2)
 	case FUNCTION:
 		i = tp->t_fndef->fn_nargs + tp->t_fndef->fn_vargs;
 
-		if (i > CTF_MAX_VLEN) {
+		if (i > CTF_V3_MAX_VLEN) {
 			terminate("function %s has too many args: %d > %d\n",
-			    tdesc_name(tp), i, CTF_MAX_VLEN);
+			    tdesc_name(tp), i, CTF_V3_MAX_VLEN);
 		}
 
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, isroot, i);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_FUNCTION, isroot, i);
 		ctt.ctt_type = tp->t_fndef->fn_ret->t_id;
 		write_unsized_type_rec(b, &ctt);
 
@@ -499,7 +496,7 @@ write_type(void *arg1, void *arg2)
 			id = tp->t_fndef->fn_args[i]->t_id;
 
 			if (target_requires_swap) {
-				SWAP_16(id);
+				SWAP_32(id);
 			}
 
 			ctf_buf_write(b, &id, sizeof (id));
@@ -511,14 +508,10 @@ write_type(void *arg1, void *arg2)
 			i++;
 		}
 
-		if (i & 1) {
-			id = 0;
-			ctf_buf_write(b, &id, sizeof (id));
-		}
 		break;
 
 	case RESTRICT:
-		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_RESTRICT, isroot, 0);
+		ctt.ctt_info = CTF_V3_TYPE_INFO(CTF_K_RESTRICT, isroot, 0);
 		ctt.ctt_type = tp->t_tdesc->t_id;
 		write_unsized_type_rec(b, &ctt);
 		break;
@@ -704,7 +697,7 @@ ctf_gen(iiburst_t *iiburst, size_t *resszp, int do_compress)
 	 * integers; we pad these out to the next 4-byte boundary if needed.
 	 */
 	h.cth_magic = CTF_MAGIC;
-	h.cth_version = CTF_VERSION;
+	h.cth_version = CTF_VERSION_3;
 	h.cth_flags = do_compress ? CTF_F_COMPRESS : 0;
 	h.cth_parlabel = strtab_insert(&buf->ctb_strtab,
 	    iiburst->iib_td->td_parlabel);
@@ -761,14 +754,46 @@ ctf_gen(iiburst_t *iiburst, size_t *resszp, int do_compress)
 }
 
 static void
-get_ctt_size(ctf_type_t *ctt, size_t *sizep, size_t *incrementp)
+get_ctt_info(ctf_header_t *h, void *v, uint_t *kind, uint_t *vlen, int *isroot)
+{
+	if (h->cth_version == CTF_VERSION_2) {
+		struct ctf_type_v2 *ctt = v;
+
+		*kind = CTF_V2_INFO_KIND(ctt->ctt_info);
+		*vlen = CTF_V2_INFO_VLEN(ctt->ctt_info);
+		*isroot = CTF_V2_INFO_ISROOT(ctt->ctt_info);
+	} else {
+		struct ctf_type_v3 *ctt = v;
+
+		*kind = CTF_V3_INFO_KIND(ctt->ctt_info);
+		*vlen = CTF_V3_INFO_VLEN(ctt->ctt_info);
+		*isroot = CTF_V3_INFO_ISROOT(ctt->ctt_info);
+	}
+}
+
+static void
+get_ctt_size(ctf_header_t *h, void *v, size_t *sizep, size_t *incrementp)
 {
-	if (ctt->ctt_size == CTF_LSIZE_SENT) {
-		*sizep = (size_t)CTF_TYPE_LSIZE(ctt);
-		*incrementp = sizeof (ctf_type_t);
+	if (h->cth_version == CTF_VERSION_2) {
+		struct ctf_type_v2 *ctt = v;
+
+		if (ctt->ctt_size == CTF_V2_LSIZE_SENT) {
+			*sizep = (size_t)CTF_TYPE_LSIZE(ctt);
+			*incrementp = sizeof (struct ctf_type_v2);
+		} else {
+			*sizep = ctt->ctt_size;
+			*incrementp = sizeof (struct ctf_stype_v2);
+		}
 	} else {
-		*sizep = ctt->ctt_size;
-		*incrementp = sizeof (ctf_stype_t);
+		struct ctf_type_v3 *ctt = v;
+
+		if (ctt->ctt_size == CTF_V3_LSIZE_SENT) {
+			*sizep = (size_t)CTF_TYPE_LSIZE(ctt);
+			*incrementp = sizeof (struct ctf_type_v3);
+		} else {
+			*sizep = ctt->ctt_size;
+			*incrementp = sizeof (struct ctf_stype_v3);
+		}
 	}
 }
 
@@ -776,18 +801,22 @@ static int
 count_types(ctf_header_t *h, caddr_t data)
 {
 	caddr_t dptr = data + h->cth_typeoff;
+	uint_t version = h->cth_version;
+	size_t idwidth;
 	int count = 0;
 
+	idwidth = version == CTF_VERSION_2 ? 2 : 4;
 	dptr = data + h->cth_typeoff;
 	while (dptr < data + h->cth_stroff) {
 		void *v = (void *) dptr;
-		ctf_type_t *ctt = v;
-		size_t vlen = CTF_INFO_VLEN(ctt->ctt_info);
 		size_t size, increment;
+		uint_t vlen, kind;
+		int isroot;
 
-		get_ctt_size(ctt, &size, &increment);
+		get_ctt_info(h, v, &kind, &vlen, &isroot);
+		get_ctt_size(h, v, &size, &increment);
 
-		switch (CTF_INFO_KIND(ctt->ctt_info)) {
+		switch (kind) {
 		case CTF_K_INTEGER:
 		case CTF_K_FLOAT:
 			dptr += 4;
@@ -799,17 +828,31 @@ count_types(ctf_header_t *h, caddr_t data)
 		case CTF_K_CONST:
 		case CTF_K_RESTRICT:
 		case CTF_K_FUNCTION:
-			dptr += sizeof (ushort_t) * (vlen + (vlen & 1));
+			dptr += idwidth * vlen;
 			break;
 		case CTF_K_ARRAY:
-			dptr += sizeof (ctf_array_t);
+			if (version == CTF_VERSION_2)
+				dptr += sizeof (struct ctf_array_v2);
+			else
+				dptr += sizeof (struct ctf_array_v3);
 			break;
 		case CTF_K_STRUCT:
 		case CTF_K_UNION:
-			if (size < CTF_LSTRUCT_THRESH)
-				dptr += sizeof (ctf_member_t) * vlen;
-			else
-				dptr += sizeof (ctf_lmember_t) * vlen;
+			if (version == CTF_VERSION_2) {
+				if (size < CTF_V2_LSTRUCT_THRESH)
+					dptr += sizeof (struct ctf_member_v2) *
+					    vlen;
+				else
+					dptr += sizeof (struct ctf_lmember_v2) *
+					    vlen;
+			} else {
+				if (size < CTF_V3_LSTRUCT_THRESH)
+					dptr += sizeof (struct ctf_member_v3) *
+					    vlen;
+				else
+					dptr += sizeof (struct ctf_lmember_v3) *
+					    vlen;
+			}
 			break;
 		case CTF_K_ENUM:
 			dptr += sizeof (ctf_enum_t) * vlen;
@@ -818,7 +861,7 @@ count_types(ctf_header_t *h, caddr_t data)
 			break;
 		default:
 			parseterminate("Unknown CTF type %d (#%d) at %#x",
-			    CTF_INFO_KIND(ctt->ctt_info), count, dptr - data);
+			    kind, count, dptr - data);
 		}
 
 		dptr += increment;
@@ -895,11 +938,15 @@ resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 	caddr_t buf = ctfdata + h->cth_objtoff;
 	size_t bufsz = h->cth_funcoff - h->cth_objtoff;
 	caddr_t dptr;
+	size_t idwidth;
+
+	idwidth = h->cth_version == CTF_VERSION_2 ? 2 : 4;
 
 	symit_reset(si);
-	for (dptr = buf; dptr < buf + bufsz; dptr += 2) {
-		void *v = (void *) dptr;
-		ushort_t id = *((ushort_t *)v);
+	for (dptr = buf; dptr < buf + bufsz; dptr += idwidth) {
+		uint32_t id = 0;
+
+		memcpy(&id, (void *) dptr, idwidth);
 		iidesc_t *ii;
 		GElf_Sym *sym;
 
@@ -912,7 +959,7 @@ resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 		if (id == 0) {
 			debug(3, "Skipping null object\n");
 			continue;
-		} else if (id >= tdsize) {
+		} else if (id >= (uint_t)tdsize) {
 			parseterminate("Reference to invalid type %d", id);
 		}
 
@@ -937,18 +984,21 @@ resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 {
 	caddr_t buf = ctfdata + h->cth_funcoff;
 	size_t bufsz = h->cth_typeoff - h->cth_funcoff;
+	size_t idwidth;
 	caddr_t dptr = buf;
 	iidesc_t *ii;
-	ushort_t info;
-	ushort_t retid;
 	GElf_Sym *sym;
 	int i;
 
+	idwidth = h->cth_version == CTF_VERSION_2 ? 2 : 4;
+
 	symit_reset(si);
 	while (dptr < buf + bufsz) {
-		void *v = (void *) dptr;
-		info = *((ushort_t *)v);
-		dptr += 2;
+		uint32_t id, info, retid;
+
+		info = 0;
+		memcpy(&info, (void *) dptr, idwidth);
+		dptr += idwidth;
 
 		if (!(sym = symit_next(si, STT_FUNC)) && info != 0)
 			parseterminate("Unexpected end of function symbols");
@@ -959,11 +1009,11 @@ resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 			continue;
 		}
 
-		v = (void *) dptr;
-		retid = *((ushort_t *)v);
-		dptr += 2;
+		retid = 0;
+		memcpy(&retid, (void *) dptr, idwidth);
+		dptr += idwidth;
 
-		if (retid >= tdsize)
+		if (retid >= (uint_t)tdsize)
 			parseterminate("Reference to invalid type %d", retid);
 
 		ii = iidesc_new(symit_name(si));
@@ -973,15 +1023,18 @@ resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 			ii->ii_owner = xstrdup(symit_curfile(si));
 		} else
 			ii->ii_type = II_GFUN;
-		ii->ii_nargs = CTF_INFO_VLEN(info);
+		if (h->cth_version == CTF_VERSION_2)
+			ii->ii_nargs = CTF_V2_INFO_VLEN(info);
+		else
+			ii->ii_nargs = CTF_V3_INFO_VLEN(info);
 		if (ii->ii_nargs)
 			ii->ii_args =
 			    xmalloc(sizeof (tdesc_t *) * ii->ii_nargs);
 
-		for (i = 0; i < ii->ii_nargs; i++, dptr += 2) {
-			v = (void *) dptr;
-			ushort_t id = *((ushort_t *)v);
-			if (id >= tdsize)
+		for (i = 0; i < ii->ii_nargs; i++, dptr += idwidth) {
+			id = 0;
+			memcpy(&id, (void *) dptr, idwidth);
+			if (id >= (uint_t)tdsize)
 				parseterminate("Reference to invalid type %d",
 				    id);
 			ii->ii_args[i] = tdarr[id];
@@ -1011,55 +1064,65 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 	tdesc_t *tdp;
 	uint_t data;
 	uint_t encoding;
-	size_t size, increment;
+	size_t idwidth, size, increment;
 	int tcnt;
 	int iicnt = 0;
 	tid_t tid, argid;
-	int kind, vlen;
-	int i;
+	int isroot, kind, vlen;
+	int i, version;
 
 	elist_t **epp;
 	mlist_t **mpp;
 	intr_t *ip;
 
-	ctf_type_t *ctt;
-	ctf_array_t *cta;
-	ctf_enum_t *cte;
+	version = h->cth_version;
+	idwidth = version == CTF_VERSION_2 ? 2 : 4;
 
 	/*
 	 * A maxid of zero indicates a request to resurrect all types, so reset
 	 * maxid to the maximum type id.
 	 */
-	if (maxid == 0)
-		maxid = CTF_MAX_TYPE;
+	if (maxid == 0) {
+		maxid = version == CTF_VERSION_2 ?
+		    CTF_V2_MAX_TYPE : CTF_V3_MAX_TYPE;
+	}
 
 	for (dptr = buf, tcnt = 0, tid = 1; dptr < buf + bufsz; tcnt++, tid++) {
+		ctf_enum_t *cte;
+		uint_t name, type;
+		void *v;
+
 		if (tid > maxid)
 			break;
 
 		if (tid >= tdsize)
 			parseterminate("Reference to invalid type %d", tid);
 
-		void *v = (void *) dptr;
-		ctt = v;
+		get_ctt_info(h, dptr, &kind, &vlen, &isroot);
+		get_ctt_size(h, dptr, &size, &increment);
+		if (version == CTF_VERSION_2) {
+			struct ctf_type_v2 *ctt = (void *) dptr;
 
-		get_ctt_size(ctt, &size, &increment);
+			name = ctt->ctt_name;
+			type = ctt->ctt_type;
+		} else {
+			struct ctf_type_v3 *ctt = (void *) dptr;
+
+			name = ctt->ctt_name;
+			type = ctt->ctt_type;
+		}
 		dptr += increment;
 
 		tdp = tdarr[tid];
 
-		if (CTF_NAME_STID(ctt->ctt_name) != CTF_STRTAB_0)
+		if (CTF_NAME_STID(name) != CTF_STRTAB_0)
 			parseterminate(
 			    "Unable to cope with non-zero strtab id");
-		if (CTF_NAME_OFFSET(ctt->ctt_name) != 0) {
-			tdp->t_name =
-			    xstrdup(sbuf + CTF_NAME_OFFSET(ctt->ctt_name));
+		if (CTF_NAME_OFFSET(name) != 0) {
+			tdp->t_name = xstrdup(sbuf + CTF_NAME_OFFSET(name));
 		} else
 			tdp->t_name = NULL;
 
-		kind = CTF_INFO_KIND(ctt->ctt_info);
-		vlen = CTF_INFO_VLEN(ctt->ctt_info);
-
 		switch (kind) {
 		case CTF_K_INTEGER:
 			tdp->t_type = INTRINSIC;
@@ -1106,62 +1169,110 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 
 		case CTF_K_POINTER:
 			tdp->t_type = POINTER;
-			tdp->t_tdesc = tdarr[ctt->ctt_type];
+			tdp->t_tdesc = tdarr[type];
 			break;
 
-		case CTF_K_ARRAY:
+		case CTF_K_ARRAY: {
+			uint_t contents, index, nelems;
+
 			tdp->t_type = ARRAY;
 			tdp->t_size = size;
 
-			v = (void *) dptr;
-			cta = v;
-			dptr += sizeof (ctf_array_t);
+			if (version == CTF_VERSION_2) {
+				struct ctf_array_v2 *cta = (void *) dptr;
+				contents = cta->cta_contents;
+				index = cta->cta_index;
+				nelems = cta->cta_nelems;
+				dptr += sizeof (*cta);
+			} else {
+				struct ctf_array_v3 *cta = (void *) dptr;
+				contents = cta->cta_contents;
+				index = cta->cta_index;
+				nelems = cta->cta_nelems;
+				dptr += sizeof (*cta);
+			}
 
 			tdp->t_ardef = xmalloc(sizeof (ardef_t));
-			tdp->t_ardef->ad_contents = tdarr[cta->cta_contents];
-			tdp->t_ardef->ad_idxtype = tdarr[cta->cta_index];
-			tdp->t_ardef->ad_nelems = cta->cta_nelems;
+			tdp->t_ardef->ad_contents = tdarr[contents];
+			tdp->t_ardef->ad_idxtype = tdarr[index];
+			tdp->t_ardef->ad_nelems = nelems;
 			break;
+		}
 
 		case CTF_K_STRUCT:
-		case CTF_K_UNION:
+		case CTF_K_UNION: {
 			tdp->t_type = (kind == CTF_K_STRUCT ? STRUCT : UNION);
 			tdp->t_size = size;
 
-			if (size < CTF_LSTRUCT_THRESH) {
-				for (i = 0, mpp = &tdp->t_members; i < vlen;
-				    i++, mpp = &((*mpp)->ml_next)) {
-					v = (void *) dptr;
-					ctf_member_t *ctm = v;
-					dptr += sizeof (ctf_member_t);
-
-					*mpp = xmalloc(sizeof (mlist_t));
-					(*mpp)->ml_name = xstrdup(sbuf +
-					    ctm->ctm_name);
-					(*mpp)->ml_type = tdarr[ctm->ctm_type];
-					(*mpp)->ml_offset = ctm->ctm_offset;
-					(*mpp)->ml_size = 0;
+			if (version == CTF_VERSION_2) {
+				if (size < CTF_V2_LSTRUCT_THRESH) {
+					for (i = 0, mpp = &tdp->t_members; i < vlen;
+					    i++, mpp = &((*mpp)->ml_next)) {
+						v = (void *) dptr;
+						struct ctf_member_v2 *ctm = v;
+						dptr += sizeof (struct ctf_member_v2);
+
+						*mpp = xmalloc(sizeof (mlist_t));
+						(*mpp)->ml_name = xstrdup(sbuf +
+						    ctm->ctm_name);
+						(*mpp)->ml_type = tdarr[ctm->ctm_type];
+						(*mpp)->ml_offset = ctm->ctm_offset;
+						(*mpp)->ml_size = 0;
+					}
+				} else {
+					for (i = 0, mpp = &tdp->t_members; i < vlen;
+					    i++, mpp = &((*mpp)->ml_next)) {
+						v = (void *) dptr;
+						struct ctf_lmember_v2 *ctlm = v;
+						dptr += sizeof (struct ctf_lmember_v2);
+
+						*mpp = xmalloc(sizeof (mlist_t));
+						(*mpp)->ml_name = xstrdup(sbuf +
+						    ctlm->ctlm_name);
+						(*mpp)->ml_type =
+						    tdarr[ctlm->ctlm_type];
+						(*mpp)->ml_offset =
+						    (int)CTF_LMEM_OFFSET(ctlm);
+						(*mpp)->ml_size = 0;
+					}
 				}
 			} else {
-				for (i = 0, mpp = &tdp->t_members; i < vlen;
-				    i++, mpp = &((*mpp)->ml_next)) {
-					v = (void *) dptr;
-					ctf_lmember_t *ctlm = v;
-					dptr += sizeof (ctf_lmember_t);
-
-					*mpp = xmalloc(sizeof (mlist_t));
-					(*mpp)->ml_name = xstrdup(sbuf +
-					    ctlm->ctlm_name);
-					(*mpp)->ml_type =
-					    tdarr[ctlm->ctlm_type];
-					(*mpp)->ml_offset =
-					    (int)CTF_LMEM_OFFSET(ctlm);
-					(*mpp)->ml_size = 0;
+				if (size < CTF_V3_LSTRUCT_THRESH) {
+					for (i = 0, mpp = &tdp->t_members; i < vlen;
+					    i++, mpp = &((*mpp)->ml_next)) {
+						v = (void *) dptr;
+						struct ctf_member_v3 *ctm = v;
+						dptr += sizeof (struct ctf_member_v3);
+
+						*mpp = xmalloc(sizeof (mlist_t));
+						(*mpp)->ml_name = xstrdup(sbuf +
+						    ctm->ctm_name);
+						(*mpp)->ml_type = tdarr[ctm->ctm_type];
+						(*mpp)->ml_offset = ctm->ctm_offset;
+						(*mpp)->ml_size = 0;
+					}
+				} else {
+					for (i = 0, mpp = &tdp->t_members; i < vlen;
+					    i++, mpp = &((*mpp)->ml_next)) {
+						v = (void *) dptr;
+						struct ctf_lmember_v3 *ctlm = v;
+						dptr += sizeof (struct ctf_lmember_v3);
+
+						*mpp = xmalloc(sizeof (mlist_t));
+						(*mpp)->ml_name = xstrdup(sbuf +
+						    ctlm->ctlm_name);
+						(*mpp)->ml_type =
+						    tdarr[ctlm->ctlm_type];
+						(*mpp)->ml_offset =
+						    (int)CTF_LMEM_OFFSET(ctlm);
+						(*mpp)->ml_size = 0;
+					}
 				}
 			}
 
 			*mpp = NULL;
 			break;
+		}
 
 		case CTF_K_ENUM:
 			tdp->t_type = ENUM;
@@ -1187,26 +1298,26 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 
 		case CTF_K_TYPEDEF:
 			tdp->t_type = TYPEDEF;
-			tdp->t_tdesc = tdarr[ctt->ctt_type];
+			tdp->t_tdesc = tdarr[type];
 			break;
 
 		case CTF_K_VOLATILE:
 			tdp->t_type = VOLATILE;
-			tdp->t_tdesc = tdarr[ctt->ctt_type];
+			tdp->t_tdesc = tdarr[type];
 			break;
 
 		case CTF_K_CONST:
 			tdp->t_type = CONST;
-			tdp->t_tdesc = tdarr[ctt->ctt_type];
+			tdp->t_tdesc = tdarr[type];
 			break;
 
 		case CTF_K_FUNCTION:
 			tdp->t_type = FUNCTION;
 			tdp->t_fndef = xcalloc(sizeof (fndef_t));
-			tdp->t_fndef->fn_ret = tdarr[ctt->ctt_type];
+			tdp->t_fndef->fn_ret = tdarr[type];
 
-			v = (void *) (dptr + (sizeof (ushort_t) * (vlen - 1)));
-			if (vlen > 0 && *(ushort_t *)v == 0)
+			v = (void *) (dptr + (idwidth * (vlen - 1)));
+			if (vlen > 0 && *(uint_t *)v == 0)
 				tdp->t_fndef->fn_vargs = 1;
 
 			tdp->t_fndef->fn_nargs = vlen - tdp->t_fndef->fn_vargs;
@@ -1215,20 +1326,19 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 
 			for (i = 0; i < vlen; i++) {
 				v = (void *) dptr;
-				argid = *(ushort_t *)v;
-				dptr += sizeof (ushort_t);
+				memcpy(&argid, v, idwidth);
+				dptr += idwidth;
 
 				if (argid != 0)
 					tdp->t_fndef->fn_args[i] = tdarr[argid];
 			}
 
-			if (vlen & 1)
-				dptr += sizeof (ushort_t);
+			dptr = roundup2(dptr, 4);
 			break;
 
 		case CTF_K_RESTRICT:
 			tdp->t_type = RESTRICT;
-			tdp->t_tdesc = tdarr[ctt->ctt_type];
+			tdp->t_tdesc = tdarr[type];
 			break;
 
 		case CTF_K_UNKNOWN:
@@ -1238,7 +1348,7 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 			warning("Can't parse unknown CTF type %d\n", kind);
 		}
 
-		if (CTF_INFO_ISROOT(ctt->ctt_info)) {
+		if (isroot) {
 			iidesc_t *ii = iidesc_new(tdp->t_name);
 			if (tdp->t_type == STRUCT || tdp->t_type == UNION ||
 			    tdp->t_type == ENUM)
@@ -1252,8 +1362,7 @@ resurrect_types(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
 		}
 
 		debug(3, "Resurrected %d %stype %s (%d)\n", tdp->t_type,
-		    (CTF_INFO_ISROOT(ctt->ctt_info) ? "root " : ""),
-		    tdesc_name(tdp), tdp->t_id);
+		    (isroot ? "root " : ""), tdesc_name(tdp), tdp->t_id);
 	}
 
 	debug(3, "Resurrected %d types (%d were roots)\n", tcnt, iicnt);
@@ -1353,7 +1462,7 @@ ctf_load(char *file, caddr_t buf, size_t bufsz, symit_data_t *si, char *label)
 	if (h->cth_magic != CTF_MAGIC)
 		parseterminate("Corrupt CTF - bad magic 0x%x", h->cth_magic);
 
-	if (h->cth_version != CTF_VERSION)
+	if (h->cth_version != CTF_VERSION_2 && h->cth_version != CTF_VERSION_3)
 		parseterminate("Unknown CTF version %d", h->cth_version);
 
 	ctfdatasz = h->cth_stroff + h->cth_strlen;
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c
index ddb5f388ca98..161927cf0663 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctfmerge.c
@@ -972,11 +972,11 @@ main(int argc, char **argv)
 
 		savetd = tdata_new();
 
-		if (CTF_TYPE_ISCHILD(reftd->td_nextid))
+		if (CTF_V3_TYPE_ISCHILD(reftd->td_nextid))
 			terminate("No room for additional types in master\n");
 
 		savetd->td_nextid = withfile ? reftd->td_nextid :
-		    CTF_INDEX_TO_TYPE(1, TRUE);
+		    CTF_V3_INDEX_TO_TYPE(1, TRUE);
 		merge_into_master(mstrtd, reftd, savetd, 0);
 
 		tdata_label_add(savetd, label, CTF_LABEL_LASTIDX);
diff --git a/cddl/contrib/opensolaris/tools/ctf/dump/dump.c b/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
index 740485ddff03..6da2c2cf8b26 100644
--- a/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
+++ b/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
@@ -97,6 +97,8 @@ typedef struct ctf_data {
 	caddr_t cd_ctfdata;	/* Pointer to the CTF data */
 	size_t cd_ctflen;	/* Length of CTF data */
 
+	size_t cd_idwidth;	/* Size of a type ID, in bytes */
+
 	/*
 	 * cd_symdata will be non-NULL if the CTF data is being retrieved from
 	 * an ELF file with a symbol table.  cd_strdata and cd_nsyms should be
@@ -266,9 +268,8 @@ next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
 static int
 read_data(const ctf_header_t *hp, const ctf_data_t *cd)
 {
-	void *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
-	const ushort_t *idp = v;
-	ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t);
+	const char *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
+	ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / cd->cd_idwidth;
 
 	if (flags != F_STATS)
 		print_line("- Data Objects ");
@@ -287,6 +288,7 @@ read_data(const ctf_header_t *hp, const ctf_data_t *cd)
 		char *name = NULL;
 
 		for (symidx = -1, i = 0; i < (int) n; i++) {
+			uint32_t id = 0;
 			int nextsym;
 
 			if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
@@ -295,7 +297,9 @@ read_data(const ctf_header_t *hp, const ctf_data_t *cd)
 			else
 				symidx = nextsym;
 
-			len = printf("  [%u] %u", i, *idp++);
+			memcpy(&id, v, cd->cd_idwidth);
+			v += cd->cd_idwidth;
+			len = printf("  [%u] %u", i, id);
 			if (name != NULL)
 				(void) printf("%*s%s (%u)", (15 - len), "",
 				    name, symidx);
@@ -310,11 +314,10 @@ read_data(const ctf_header_t *hp, const ctf_data_t *cd)
 static int
 read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
 {
-	void *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
-	const ushort_t *fp = v;
+	const char *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
+	uint_t f = 0, info;
 
-	v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
-	const ushort_t *end = v;
+	const char *end = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
 
 	ulong_t id;
 	int symidx;
*** 446 LINES SKIPPED ***