--- old/usr/src/test/util-tests/tests/Makefile	Tue Apr 23 05:35:48 2019
+++ new/usr/src/test/util-tests/tests/Makefile	Tue Apr 23 05:35:48 2019
@@ -14,9 +14,10 @@
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 # Copyright 2014 Nexenta Systems, Inc. All rights reserved.
 # Copyright 2017 Jason King
+# Copyright 2019 Joyent, Inc.
 #
 
 SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4
-SUBDIRS += demangle mergeq workq chown
+SUBDIRS += demangle mergeq workq chown ctf
 
 include $(SRC)/test/Makefile.com
--- /dev/null	Tue Apr 23 05:35:48 2019
+++ new/usr/src/test/util-tests/tests/ctf/Makefile	Tue Apr 23 05:35:48 2019
@@ -0,0 +1,149 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2019, Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/ctf
+
+SCRIPTS =	ctftest.ksh
+
+TESTS =		test-float.c \
+		test-reference.c \
+		test-int.c \
+		test-array.c \
+		test-enum.c \
+		test-forward.c \
+		test-sou.c \
+		test-function.c \
+		test-merge-static/Makefile.ctftest \
+		test-merge-static/test-a.c \
+		test-merge-static/test-b.c \
+		test-merge-static/test-c.c \
+		test-merge-static/test-d.c \
+		test-merge-static/test-main.c \
+		test-merge-forward/Makefile.ctftest \
+		test-merge-forward/test-impl.c \
+		test-merge-forward/test-merge.c \
+		test-merge-dedup/Makefile.ctftest \
+		test-merge-dedup/test-merge-1.c \
+		test-merge-dedup/test-merge-2.c \
+		test-merge-dedup/test-merge-3.c \
+		test-merge-dedup/test-merge-dedup.c \
+		test-merge-reduction/Makefile.ctftest \
+		test-merge-reduction/mapfile-vers \
+		test-merge-reduction/test-global.c \
+		test-merge-reduction/test-scoped.c \
+		test-merge-weak/Makefile.ctftest \
+		test-merge-weak/test-merge-weak.c \
+		test-weak.c \
+		Makefile.ctftest.com
+
+MAKEDIRS =	test-merge-static \
+		test-merge-forward \
+		test-merge-dedup \
+		test-merge-reduction \
+		test-merge-weak
+
+CHECKS =	check-float-32 \
+		check-float-64 \
+		check-int-32 \
+		check-int-64 \
+		check-reference \
+		check-array \
+		check-enum \
+		check-sou-32 \
+		check-sou-64 \
+		check-forward-32 \
+		check-forward-64 \
+		check-function \
+		check-merge-static \
+		check-merge-forward-32 \
+		check-merge-forward-64 \
+		check-merge-dedup \
+		check-merge-reduction \
+		check-merge-weak \
+		check-weak
+
+COMMON_OBJS =	check-common.o
+ALL_OBJS =	$(CHECKS:%=%.o) $(CHECKS:%-32=%.32.o) $(CHECKS:%-64=%.64.o) $(COMMON_OBJS)
+
+ROOTTESTS =	$(TESTS:%=$(TESTDIR)/%)
+ROOTMAKEDIRS =	$(MAKEDIRS:%=$(TESTDIR)/%)
+ROOTCHECKS =	$(CHECKS:%=$(TESTDIR)/%)
+ROOTSCRIPTS =	$(SCRIPTS:%.ksh=$(TESTDIR)/%)
+
+ROOTTESTS	:= FILEMODE =	0444
+ROOTCHECKS	:= FILEMODE =	0555
+ROOTSCRIPTS	:= FILEMODE =	0555
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+LDLIBS +=	-lctf
+
+check-merge-static :=	LDLIBS += -lelf
+
+all: $(CHECKS)
+
+install: all $(ROOTTESTS) $(ROOTCHECKS) $(ROOTSCRIPTS)
+
+$(CHECKS): $(COMMON_OBJS)
+
+clean:
+	$(RM) $(ALL_OBJS)
+
+clobber: clean
+	$(RM) $(CHECKS)
+
+$(ROOTTESTS): $(TESTDIR) $(ROOTMAKEDIRS) $(TESTS)
+$(ROOTCHECKS): $(TESTDIR) $(CHECKS)
+$(ROOTSCRIPTS): $(TESTDIR) $(SCRIPTS)
+
+$(TESTDIR):
+	$(INS.dir)
+
+$(ROOTMAKEDIRS):
+	$(INS.dir)
+
+$(TESTDIR)/%: %
+	$(INS.file)
+
+$(TESTDIR)/%: %.ksh
+	$(INS.rename)
+
+%.o: %.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+%.32.o: %.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+%.64.o: %.c
+	$(COMPILE.c) -DTARGET_LP64 -o $@ $<
+	$(POST_PROCESS_O)
+
+%-32: %.32.o
+	$(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+%-64: %.64.o
+	$(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+%: %.o
+	$(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+	$(POST_PROCESS)
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,92 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+#
+# This Makefile is installed onto the target system and is used as part
+# of the running tests. It is not used as part of the build.
+#
+# This makefile could be simplified substantially. However, it does
+# everything explicitly to try and work with a wide variety of different
+# makes.
+#
+# The following values should be passed in by the invoker of the
+# Makefile:
+#
+#	CC		C Compiler to use
+#	CFLAGS32	32-bit CFLAGS
+#	CFLAGS64	64-bit CFLAGS
+#	CTFCONVERT	Path to ctfconvert
+#	CTFMERGE	Path to ctfmerge
+#	DEBUGFLAGS	The set of debug flags to use
+#	BUILDDIR	Directory things should be built in
+#	CHECK32		Program to check 32-bit output
+#	CHECK64		Program to check 64-bit output
+#
+# The following values should be set before building this:
+#
+#	TEST		The name of the test program
+#	OBJS_C_32	32-bit convert objects
+#	OBJS_C_64	64-bit convert objects
+#	OBJS_M_32	32-bit merge objects
+#	OBJS_M_64	64-bit merge objects
+#
+
+CONV32 =	$(BUILDDIR)/$(TEST)-32c
+CONV64 =	$(BUILDDIR)/$(TEST)-64c
+MERGE32 =	$(BUILDDIR)/$(TEST)-32m
+MERGE64 =	$(BUILDDIR)/$(TEST)-64m
+
+BINS =		$(CONV32) \
+		$(CONV64) \
+		$(MERGE32) \
+		$(MERGE64)
+
+build: $(BINS)
+
+$(BUILDDIR)/%.32.c.o: %.c
+	$(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.64.c.o: %.c
+	$(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.32.m.o: %.c
+	$(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+	$(CTFCONVERT) $@
+
+$(BUILDDIR)/%.64.m.o: %.c
+	$(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+	$(CTFCONVERT) $@
+
+$(CONV32): $(OBJS_C_32)
+	$(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_C_32)
+	$(CTFCONVERT) $@
+
+$(CONV64): $(OBJS_C_64)
+	$(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_C_64)
+	$(CTFCONVERT) $@
+
+$(MERGE32): $(OBJS_M_32)
+	$(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_M_32)
+	$(CTFMERGE) -t -o $@ $(OBJS_M_32)
+
+$(MERGE64): $(OBJS_M_64)
+	$(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_M_64)
+	$(CTFMERGE) -t -o $@ $(OBJS_M_64)
+
+run-test:
+	$(CHECK32) $(CONV32)
+	$(CHECK64) $(CONV64)
+	$(CHECK32) $(MERGE32)
+	$(CHECK64) $(MERGE64)
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/README	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,54 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2019, Joyent, Inc.
+#
+
+CTF Tests
+---------
+
+This directory contains a series of tests for the Compact C Type Format
+(CTF). For each test program, there is a corresponding C program that
+goes through and checks the CTF for various aspects. Due to the fact
+that the CTF generated by compilers can change slightly, the tests have
+been designed this way to try and make it work with as wide a variety of
+programs as possible.
+
+The test suite requires the following:
+
+1. make
+2. C Compiler (defaults to gcc)
+3. A copy of ctfconvert
+
+The source for a given program will be compiled on the target system and
+then converted. This allows us to try the CTF tools against a wide
+variety of different compilers or DWARF standards.
+
+Caveats
+-------
+
+Right now the tests only pass when using gcc 4.x. The following are
+known issues with the tests:
+
+1. gcc7+ generates some different DWARF ordering, which causes some
+tests to spuriously fail. These tests should be improved.
+
+2. There are cases where gcc7+ appears to attribute things as being const
+twice in DWARF which throw off the tests. The CTF tools likely should
+work around this if we confirm that this is intentional.
+
+3. Many tests will cause clang not to emit DWARF information because
+clang infers that they cannot be used. The tests should be cleaned up in
+these cases.
+
+4. clang generated DWARF can confuse the CTF tools. The tools should be
+fixed and additional regression tests should be added.
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-array.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,116 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly generate basic nested arrays.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_base[] = {
+	{ "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+	{ "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+	{ "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "a", "int [3]" },
+	{ "b", "double [42]" },
+	{ "c", "const char *[2]" },
+	{ "d", "int [4][5]" },
+	{ "e", "int [4][5][6]" },
+	{ "f", "int [4][5][6][7]" },
+	{ "g", "int [4][5][6][7][8]" },
+	{ "h", "int [4][5][6][7][8][9]" },
+	{ "i", "int [4][5][6][7][8][9][10]" },
+	{ NULL }
+};
+
+static check_descent_t check_array_a[] = {
+	{ "int [3]", CTF_K_ARRAY, "int", 3 },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_array_b[] = {
+	{ "double [42]", CTF_K_ARRAY, "double", 42 },
+	{ "double", CTF_K_FLOAT },
+	{ NULL }
+};
+
+static check_descent_t check_array_c[] = {
+	{ "const char *[2]", CTF_K_ARRAY, "const char *", 2 },
+	{ "const char *", CTF_K_POINTER },
+	{ "const char", CTF_K_CONST },
+	{ "char", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_array_i[] = {
+	{ "int [4][5][6][7][8][9][10]", CTF_K_ARRAY,
+	    "int [5][6][7][8][9][10]", 4 },
+	{ "int [5][6][7][8][9][10]", CTF_K_ARRAY, "int [6][7][8][9][10]", 5 },
+	{ "int [6][7][8][9][10]", CTF_K_ARRAY, "int [7][8][9][10]", 6 },
+	{ "int [7][8][9][10]", CTF_K_ARRAY, "int [8][9][10]", 7 },
+	{ "int [8][9][10]", CTF_K_ARRAY, "int [9][10]", 8 },
+	{ "int [9][10]", CTF_K_ARRAY, "int [10]", 9 },
+	{ "int [10]", CTF_K_ARRAY, "int", 10 },
+	{ "int", CTF_K_INTEGER },
+	{ NULL },
+};
+
+static check_descent_test_t descents[] = {
+	{ "a", check_array_a },
+	{ "b", check_array_b },
+	{ "c", check_array_c },
+	{ "i", check_array_i },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t d;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+		if (!ctftest_check_numbers(fp, check_base))
+			ret = EXIT_FAILURE;
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		for (d = 0; descents[d].cdt_sym != NULL; d++) {
+			if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+			    descents[d].cdt_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-common.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,802 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Collection of common utilities for CTF testing.
+ */
+
+#include <strings.h>
+#include <libctf.h>
+#include "check-common.h"
+
+typedef struct ctftests_lookup_cb {
+	ctf_file_t *clc_fp;
+	ctf_id_t clc_id;
+	const char *clc_name;
+} ctftests_lookup_cb_t;
+
+typedef struct ctftest_member_cb {
+	ctf_file_t *cmc_fp;
+	const check_member_t *cmc_members;
+	const char *cmc_name;
+} ctftest_member_cb_t;
+
+static int
+ctftest_lookup_type_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+	char buf[2048];
+	ctftests_lookup_cb_t *clc = arg;
+
+	if (ctf_type_name(clc->clc_fp, id, buf, sizeof (buf)) == NULL)
+		return (0);
+
+	if (strcmp(buf, clc->clc_name) != 0)
+		return (0);
+
+	clc->clc_id = id;
+	return (1);
+}
+
+/*
+ * This is a variant on the classic ctf_lookup_by_name(). ctf_lookup_by_name()
+ * skips qualifiers, which makes sense given what the consumers of it are trying
+ * to do. However, that's not what we want here. So instead we basically have to
+ * walk the type table.
+ */
+static ctf_id_t
+ctftest_lookup_type(ctf_file_t *fp, const char *name)
+{
+	ctftests_lookup_cb_t clc;
+
+	clc.clc_fp = fp;
+	clc.clc_id = CTF_ERR;
+	clc.clc_name = name;
+
+	(void) ctf_type_iter(fp, B_TRUE, ctftest_lookup_type_cb, &clc);
+	return (clc.clc_id);
+}
+
+static int
+ctftest_lookup_object_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
+{
+	ctftests_lookup_cb_t *clc = arg;
+
+	if (strcmp(obj, clc->clc_name) == 0) {
+		clc->clc_id = type;
+		return (1);
+	}
+
+	return (0);
+}
+
+static ctf_id_t
+ctftest_lookup_symbol(ctf_file_t *fp, const char *name)
+{
+	ctftests_lookup_cb_t clc;
+
+	clc.clc_fp = fp;
+	clc.clc_id = CTF_ERR;
+	clc.clc_name = name;
+
+	(void) ctf_object_iter(fp, ctftest_lookup_object_cb, &clc);
+	return (clc.clc_id);
+}
+
+typedef struct ctf_function_cb {
+	const char *cfc_name;
+	ulong_t *cfc_symp;
+	ctf_funcinfo_t *cfc_fip;
+} ctf_function_cb_t;
+
+static int
+ctftest_lookup_function_cb(const char *name, ulong_t symidx,
+    ctf_funcinfo_t *fip, void *arg)
+{
+	ctf_function_cb_t *cfc = arg;
+	if (strcmp(name, cfc->cfc_name) != 0)
+		return (0);
+
+	*cfc->cfc_symp = symidx;
+	*cfc->cfc_fip = *fip;
+
+	return (1);
+}
+
+/*
+ * Note, this function finds the first one with a matching name. This must not
+ * be used when performing searches where a given name may occur more than once.
+ */
+static boolean_t
+ctftest_lookup_function(ctf_file_t *fp, const char *name, ulong_t *symp,
+    ctf_funcinfo_t *fip)
+{
+	ctf_function_cb_t cfc;
+
+	*symp = 0;
+	cfc.cfc_name = name;
+	cfc.cfc_symp = symp;
+	cfc.cfc_fip = fip;
+	(void) ctf_function_iter(fp, ctftest_lookup_function_cb, &cfc);
+	return (*symp == 0 ? B_FALSE : B_TRUE);
+}
+
+boolean_t
+ctftest_check_numbers(ctf_file_t *fp, const check_number_t *tests)
+{
+	uint_t i;
+	boolean_t ret = B_TRUE;
+
+	for (i = 0; tests[i].cn_tname != NULL; i++) {
+		ctf_id_t id;
+		ctf_encoding_t enc;
+
+		id = ctftest_lookup_type(fp, tests[i].cn_tname);
+		if (id == CTF_ERR) {
+			warnx("failed to look up %s", tests[i].cn_tname);
+			ret = B_FALSE;
+			continue;
+		}
+
+		if (ctf_type_kind(fp, id) != tests[i].cn_kind) {
+			warnx("type kind mismatch for %s: got %u, expected %u",
+			    tests[i].cn_tname, ctf_type_kind(fp, id),
+			    tests[i].cn_kind);
+			ret = B_FALSE;
+			continue;
+		}
+
+		if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) {
+			warnx("failed to get type encoding for %s: %s",
+			    tests[i].cn_tname, ctf_errmsg(ctf_errno(fp)));
+			ret = B_FALSE;
+			continue;
+		}
+
+		if (enc.cte_format != tests[i].cn_flags) {
+			warnx("encoding flags mismatch for %s: got 0x%x, "
+			    "expected 0x%x", tests[i].cn_tname, enc.cte_format,
+			    tests[i].cn_flags);
+			ret = B_FALSE;
+			continue;
+		}
+
+		if (enc.cte_offset != tests[i].cn_offset) {
+			warnx("encoding offset mismatch for %s: got 0x%x, "
+			    "expected 0x%x", tests[i].cn_tname, enc.cte_offset,
+			    tests[i].cn_offset);
+			ret = B_FALSE;
+			continue;
+		}
+
+		if (enc.cte_bits != tests[i].cn_size) {
+			warnx("encoding size mismatch for %s: got 0x%x, "
+			    "expected 0x%x", tests[i].cn_tname, enc.cte_bits,
+			    tests[i].cn_size);
+			ret = B_FALSE;
+			continue;
+		}
+	}
+
+	return (ret);
+}
+
+typedef struct ctftests_symbol_cb {
+	ctf_file_t	*csc_fp;
+	boolean_t	csc_ret;
+	const check_symbol_t *csc_tests;
+} ctftest_symbol_cb_t;
+
+static int
+ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
+{
+	ctftest_symbol_cb_t *cb = arg;
+	const check_symbol_t *tests = cb->csc_tests;
+	ctf_file_t *fp = cb->csc_fp;
+	uint_t i;
+
+	for (i = 0; tests[i].cs_symbol != NULL; i++) {
+		ctf_id_t id;
+
+		if (strcmp(obj, tests[i].cs_symbol) != 0)
+			continue;
+
+		id = ctftest_lookup_type(fp, tests[i].cs_type);
+		if (id == CTF_ERR) {
+			warnx("failed to lookup type %s for symbol %s",
+			    tests[i].cs_type, tests[i].cs_symbol);
+			cb->csc_ret = B_FALSE;
+			return (0);
+		}
+
+		if (id != type) {
+			warnx("type mismatch for symbol %s, has type id %u, "
+			    "but specified type %s has id %u",
+			    tests[i].cs_symbol, type, tests[i].cs_type, id);
+			cb->csc_ret = B_FALSE;
+			return (0);
+		}
+	}
+
+	return (0);
+}
+
+boolean_t
+ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests)
+{
+	ctftest_symbol_cb_t cb;
+
+	cb.csc_fp = fp;
+	cb.csc_ret = B_TRUE;
+	cb.csc_tests = tests;
+	if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0)
+		return (B_FALSE);
+	return (cb.csc_ret);
+}
+
+
+boolean_t
+ctftest_check_descent(const char *symbol, ctf_file_t *fp,
+    const check_descent_t *tests)
+{
+	ctf_id_t base;
+	uint_t layer = 0;
+
+	/*
+	 * First, find the initial type of the symbol.
+	 */
+	base = ctftest_lookup_symbol(fp, symbol);
+	if (base == CTF_ERR) {
+		warnx("failed to lookup type for symbol %s", symbol);
+		return (B_FALSE);
+	}
+
+	while (tests->cd_tname != NULL) {
+		ctf_id_t tid;
+		int kind;
+		ctf_arinfo_t ari;
+
+		if (base == CTF_ERR) {
+			warnx("encountered non-reference type at layer %u "
+			    "while still expecting type %s for symbol %s",
+			    layer, tests->cd_tname, symbol);
+			return (B_FALSE);
+		}
+
+		tid = ctftest_lookup_type(fp, tests->cd_tname);
+		if (tid == CTF_ERR) {
+			warnx("failed to lookup type %s", tests->cd_tname);
+			return (B_FALSE);
+		}
+
+		if (tid != base) {
+			warnx("type mismatch at layer %u: found id %u, but "
+			    "expecting type id %u for type %s, symbol %s",
+			    layer, base, tid, tests->cd_tname, symbol);
+			return (B_FALSE);
+		}
+
+		kind = ctf_type_kind(fp, base);
+		if (kind != tests->cd_kind) {
+			warnx("type kind mismatch at layer %u: found kind %u, "
+			    "but expected kind %u for %s, symbol %s", layer,
+			    kind, tests->cd_kind, tests->cd_tname, symbol);
+			return (B_FALSE);
+		}
+
+		switch (kind) {
+		case CTF_K_ARRAY:
+			if (ctf_array_info(fp, base, &ari) == CTF_ERR) {
+				warnx("failed to lookup array info at layer "
+				    "%u for type %s, symbol %s: %s", base,
+				    tests->cd_tname, symbol,
+				    ctf_errmsg(ctf_errno(fp)));
+				return (B_FALSE);
+			}
+
+			if (tests->cd_nents != ari.ctr_nelems) {
+				warnx("array element mismatch at layer %u "
+				    "for type %s, symbol %s: found %u, "
+				    "expected %u", layer, tests->cd_tname,
+				    symbol, ari.ctr_nelems, tests->cd_nents);
+				return (B_FALSE);
+			}
+
+			tid = ctftest_lookup_type(fp, tests->cd_contents);
+			if (tid == CTF_ERR) {
+				warnx("failed to look up type %s",
+				    tests->cd_contents);
+				return (B_FALSE);
+			}
+
+			if (ari.ctr_contents != tid) {
+				warnx("array contents mismatch at layer %u "
+				    "for type %s, symbol %s: found %u, "
+				    "expected %s/%u", layer, tests->cd_tname,
+				    symbol, ari.ctr_contents,
+				    tests->cd_contents, tid);
+
+				return (B_FALSE);
+			}
+			base = ari.ctr_contents;
+			break;
+		default:
+			base = ctf_type_reference(fp, base);
+			break;
+		}
+
+		tests++;
+		layer++;
+	}
+
+	if (base != CTF_ERR) {
+		warnx("found additional type %u in chain, but expected no more",
+		    base);
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+int
+ctftest_check_enum_count(const char *name, int value, void *arg)
+{
+	uint_t *u = arg;
+	*u = *u + 1;
+	return (0);
+}
+
+int
+ctftest_check_enum_value(const char *name, int value, void *arg)
+{
+	uint_t i;
+	const check_enum_t *enums = arg;
+
+	for (i = 0; enums[i].ce_name != NULL; i++) {
+		if (strcmp(enums[i].ce_name, name) != 0)
+			continue;
+		if (enums[i].ce_value == (int64_t)value)
+			return (0);
+		warnx("enum %s value mismatch: found %d, expected %" PRId64,
+		    name, value, enums[i].ce_value);
+		return (1);
+	}
+
+	warnx("found no matching entry for enum member %s", name);
+	return (1);
+}
+
+boolean_t
+ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums)
+{
+	int ret;
+	uint_t tcount, ecount;
+	ctf_id_t base;
+
+	if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
+		warnx("Failed to look up type %s", type);
+		return (B_FALSE);
+	}
+
+	if (ctf_type_kind(fp, base) != CTF_K_ENUM) {
+		warnx("%s is not an enum", type);
+		return (B_FALSE);
+	}
+
+	/*
+	 * First count how many entries we have.
+	 */
+	tcount = 0;
+	while (enums[tcount].ce_name != NULL) {
+		tcount++;
+	}
+
+	ecount = 0;
+	if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) {
+		warnx("failed to walk enum %s: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	if (tcount != ecount) {
+		warnx("enum value mismatch: expected %u values, but found %u",
+		    tcount, ecount);
+		return (B_FALSE);
+	}
+
+	if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value,
+	    (void *)enums)) != 0) {
+		if (ret == -1) {
+			warnx("failed to walk enum %s: %s", type,
+			    ctf_errmsg(ctf_errno(fp)));
+		}
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+int
+ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff,
+    void *arg)
+{
+	uint_t *countp = arg;
+	*countp = *countp + 1;
+	return (0);
+}
+
+int
+ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff,
+    void *arg)
+{
+	uint_t i;
+	const ctftest_member_cb_t *cmc = arg;
+	const check_member_t *members = cmc->cmc_members;
+	ctf_file_t *fp = cmc->cmc_fp;
+
+	for (i = 0; members[i].cm_name != NULL; i++) {
+		boolean_t bad = B_FALSE;
+		char buf[2048];
+
+		if (strcmp(mname, members[i].cm_name) != 0)
+			continue;
+
+		if (bitoff != members[i].cm_offset) {
+			warnx("member %s of type %s has mismatched bit offset: "
+			    "found %lu, expected %lu", mname, cmc->cmc_name,
+			    bitoff, members[i].cm_offset);
+			bad = B_TRUE;
+		}
+
+		if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) {
+			warnx("failed to obtain type name for member %s",
+			    mname, ctf_errmsg(ctf_errno(fp)));
+			bad = B_TRUE;
+		} else if (strcmp(buf, members[i].cm_type) != 0) {
+			warnx("member %s has bad type, found %s, expected %s",
+			    mname, buf, members[i].cm_type);
+			bad = B_TRUE;
+		}
+
+		return (bad ? 1 : 0);
+	}
+
+	warnx("found no matching entry for member %s of type %s", mname,
+	    cmc->cmc_name);
+	return (1);
+}
+
+boolean_t
+ctftest_check_members(const char *type, ctf_file_t *fp, int kind,
+    size_t size, const check_member_t *members)
+{
+	int ret;
+	uint_t tcount, mcount;
+	ctf_id_t base;
+	ctftest_member_cb_t cmc;
+
+	if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
+		warnx("failed to look up type %s", type);
+		return (B_FALSE);
+	}
+
+	if (ctf_type_kind(fp, base) != kind) {
+		warnx("%s has kind %s, expected %s", type,
+		    ctf_kind_name(fp, ctf_type_kind(fp, base)),
+		    ctf_kind_name(fp, kind));
+		return (B_FALSE);
+	}
+
+	if (size != ctf_type_size(fp, base)) {
+		warnx("%s has bad size, expected %lu, found %lu",
+		    type, size, ctf_type_size(fp, base));
+		return (B_FALSE);
+	}
+
+	/*
+	 * First count how many entries we have.
+	 */
+	tcount = 0;
+	while (members[tcount].cm_name != NULL) {
+		tcount++;
+	}
+
+	mcount = 0;
+	if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) !=
+	    0) {
+		warnx("failed to walk members of %s: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	if (tcount != mcount) {
+		warnx("type member mismatch: expected %u values, but found %u",
+		    tcount, mcount);
+		return (B_FALSE);
+	}
+
+	cmc.cmc_fp = fp;
+	cmc.cmc_members = members;
+	cmc.cmc_name = type;
+	if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb,
+	    &cmc)) != 0) {
+		if (ret == -1) {
+			warnx("failed to walk type %s: %s", type,
+			    ctf_errmsg(ctf_errno(fp)));
+		}
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+boolean_t
+ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype,
+    uint_t nargs, uint_t flags, const char **argv)
+{
+	ulong_t sym;
+	ctf_funcinfo_t fi;
+	uint_t i;
+	boolean_t ret = B_TRUE;
+	ctf_id_t *args;
+	char buf[2048];
+
+
+	if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) {
+		warnx("failed to look up function %s", symbol);
+		return (B_FALSE);
+	}
+
+	if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
+		warnx("failed to lookup return type name for function %s",
+		    symbol);
+		ret = B_FALSE;
+	} else if (strcmp(rtype, buf) != 0) {
+		warnx("return type has wrong type: found %s, expected %s",
+		    buf, rtype);
+		ret = B_FALSE;
+	}
+
+	if (nargs != fi.ctc_argc) {
+		warnx("function argument mismatch: found %u, expected %u",
+		    fi.ctc_argc, nargs);
+		ret = B_FALSE;
+	}
+
+	if (flags != fi.ctc_flags) {
+		warnx("function flags mismatch, found 0x%x, expected 0x%x",
+		    fi.ctc_flags, flags);
+		ret = B_FALSE;
+	}
+
+	if (!ret || fi.ctc_argc == 0) {
+		return (ret);
+	}
+
+	if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
+		warnx("failed to allocate memory for function arguments");
+		return (B_FALSE);
+	}
+
+	if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) {
+		warnx("failed to get function information: %s",
+		    ctf_errmsg(ctf_errno(fp)));
+		free(args);
+		return (B_FALSE);
+	}
+
+	for (i = 0; i < fi.ctc_argc; i++) {
+		if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
+			warnx("failed to obtain type name for argument %u",
+			    i, ctf_errmsg(ctf_errno(fp)));
+			ret = B_FALSE;
+			break;
+		}
+
+		if (strcmp(buf, argv[i]) != 0) {
+			warnx("argument %u has wrong type: found %s, "
+			    "expected %s", i, buf, argv[i]);
+			ret = B_FALSE;
+			break;
+		}
+	}
+
+	free(args);
+	return (ret);
+}
+
+boolean_t
+ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype,
+    uint_t nargs, uint_t flags, const char **argv)
+{
+	ctf_id_t tid;
+	ctf_funcinfo_t fi;
+	uint_t i;
+	boolean_t ret = B_TRUE;
+	ctf_id_t *args;
+	char buf[2048];
+
+
+	if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
+		warnx("failed to look up type %s: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	/*
+	 * Perform two CTF type resolves, one for the function pointer and one
+	 * for the typedef that gets passed in.
+	 */
+	if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) {
+		warnx("failed to convert type %s to base type: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	if (ctf_type_kind(fp, tid) == CTF_K_POINTER &&
+	    (tid = ctf_type_reference(fp, tid)) == CTF_ERR) {
+		warnx("failed to convert type %s to base type: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	if (ctf_func_info_by_id(fp, tid, &fi) != 0) {
+		warnx("failed to get function information for type %s: %s",
+		    type, ctf_errmsg(ctf_errno(fp)));
+		return (B_FALSE);
+	}
+
+	if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
+		warnx("failed to lookup return type name for function %s",
+		    type);
+		ret = B_FALSE;
+	} else if (strcmp(rtype, buf) != 0) {
+		warnx("return type has wrong type: found %s, expected %s",
+		    buf, rtype);
+		ret = B_FALSE;
+	}
+
+	if (nargs != fi.ctc_argc) {
+		warnx("function argument mismatch: found %u, expected %u",
+		    fi.ctc_argc, nargs);
+		ret = B_FALSE;
+	}
+
+	if (flags != fi.ctc_flags) {
+		warnx("function flags mismatch, found 0x%x, expected 0x%x",
+		    fi.ctc_flags, flags);
+		ret = B_FALSE;
+	}
+
+	if (!ret || fi.ctc_argc == 0) {
+		return (ret);
+	}
+
+	if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
+		warnx("failed to allocate memory for function arguments");
+		return (B_FALSE);
+	}
+
+	if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) {
+		warnx("failed to get function information: %s",
+		    ctf_errmsg(ctf_errno(fp)));
+		free(args);
+		return (B_FALSE);
+	}
+
+	for (i = 0; i < fi.ctc_argc; i++) {
+		if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
+			warnx("failed to obtain type name for argument %u",
+			    i, ctf_errmsg(ctf_errno(fp)));
+			ret = B_FALSE;
+			break;
+		}
+
+		if (strcmp(buf, argv[i]) != 0) {
+			warnx("argument %u has wrong type: found %s, "
+			    "expected %s", i, buf, argv[i]);
+			ret = B_FALSE;
+			break;
+		}
+	}
+
+	free(args);
+	return (ret);
+}
+
+typedef struct ctftest_duplicates {
+	ctf_file_t *ctd_fp;
+	char **ctd_names;
+	size_t ctd_len;
+	size_t ctd_curent;
+	boolean_t ctd_ret;
+} ctftest_duplicates_t;
+
+static int
+ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+	char buf[2048];
+	ctftest_duplicates_t *dup = arg;
+	size_t i;
+
+	if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) {
+		warnx("failed to lookup name for id %ld", id);
+		dup->ctd_ret = B_FALSE;
+		return (1);
+	}
+
+	for (i = 0; i < dup->ctd_curent; i++) {
+		if (strcmp(buf, dup->ctd_names[i]) == 0) {
+			warnx("encountered duplicate type '%s'", buf);
+			dup->ctd_ret = B_FALSE;
+			/*
+			 * Don't break out of the loop and keep going in case we
+			 * find another duplicate.
+			 */
+			return (0);
+		}
+	}
+
+	if (dup->ctd_curent == dup->ctd_len) {
+		char **n;
+		size_t newlen = dup->ctd_len * 2;
+
+		n = recallocarray(dup->ctd_names, dup->ctd_len, newlen,
+		    sizeof (char *));
+		if (n == NULL) {
+			warnx("failed to resize type name array");
+			dup->ctd_ret = B_FALSE;
+			return (1);
+		}
+
+		dup->ctd_names = n;
+		dup->ctd_len = newlen;
+	}
+
+	dup->ctd_names[dup->ctd_curent] = strdup(buf);
+	if (dup->ctd_names[dup->ctd_curent] == NULL) {
+		warn("failed to duplicate type name");
+		dup->ctd_ret = B_FALSE;
+		return (1);
+	}
+	dup->ctd_curent++;
+
+	return (0);
+}
+
+boolean_t
+ctftest_duplicates(ctf_file_t *fp)
+{
+	size_t i;
+	ctftest_duplicates_t d;
+
+	bzero(&d, sizeof (d));
+	d.ctd_fp = fp;
+	d.ctd_len = 4;
+	d.ctd_ret = B_TRUE;
+	d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *));
+	if (d.ctd_names == NULL) {
+		warnx("failed to allocate duplicate name storage");
+		return (B_FALSE);
+	}
+
+	(void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d);
+
+	for (i = 0; i < d.ctd_curent; i++) {
+		free(d.ctd_names[i]);
+	}
+	free(d.ctd_names);
+
+	return (d.ctd_ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-common.h	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,141 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#ifndef _CHECK_COMMON_H
+#define	_CHECK_COMMON_H
+
+/*
+ * Common definitions for the CTF tests
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <libctf.h>
+#include <err.h>
+#include <strings.h>
+#include <sys/param.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct check_number {
+	const char *cn_tname;
+	uint_t cn_kind;
+	uint_t cn_flags;
+	uint_t cn_offset;
+	uint_t cn_size;
+} check_number_t;
+
+typedef struct check_symbol {
+	const char *cs_symbol;
+	const char *cs_type;
+} check_symbol_t;
+
+typedef struct check_descent {
+	const char *cd_tname;
+	uint_t cd_kind;
+	const char *cd_contents;
+	uint_t cd_nents;
+} check_descent_t;
+
+typedef struct check_descent_test {
+	const char *cdt_sym;
+	const check_descent_t *cdt_tests;
+} check_descent_test_t;
+
+typedef struct check_enum {
+	const char *ce_name;
+	int64_t ce_value;
+} check_enum_t;
+
+typedef struct check_enum_test {
+	const char *cet_type;
+	const check_enum_t *cet_tests;
+} check_enum_test_t;
+
+typedef struct check_member {
+	const char *cm_name;
+	const char *cm_type;
+	ulong_t cm_offset;
+} check_member_t;
+
+typedef struct check_member_test {
+	const char *cmt_type;
+	int cmt_kind;
+	size_t cmt_size;
+	const check_member_t *cmt_members;
+} check_member_test_t;
+
+typedef struct check_function_test {
+	const char *cft_name;
+	const char *cft_rtype;
+	uint_t cft_nargs;
+	uint_t cft_flags;
+	const char **cft_args;
+} check_function_test_t;
+
+/*
+ * Looks up each type and verifies that it matches the expected type.
+ */
+extern boolean_t ctftest_check_numbers(ctf_file_t *, const check_number_t *);
+
+/*
+ * Looks at each symbol specified and verifies that it matches the expected
+ * type.
+ */
+extern boolean_t ctftest_check_symbols(ctf_file_t *, const check_symbol_t *);
+
+/*
+ * Given a symbol name which refers to a type, walks all the references of that
+ * type and checks against it with each subsequent entry.
+ */
+extern boolean_t ctftest_check_descent(const char *, ctf_file_t *,
+    const check_descent_t *);
+
+/*
+ * Checks that all of the listed members of an enum are present and have the
+ * right values.
+ */
+extern boolean_t ctftest_check_enum(const char *, ctf_file_t *,
+    const check_enum_t *);
+
+/*
+ * Checks that all of the members of a structure or union are present and have
+ * the right types and byte offsets. This can be used for either structures or
+ * unions.
+ */
+extern boolean_t ctftest_check_members(const char *, ctf_file_t *, int, size_t,
+    const check_member_t *);
+
+/*
+ * Check that the named function or function pointer has the correct return
+ * type, arguments, and function flags.
+ */
+extern boolean_t ctftest_check_function(const char *, ctf_file_t *,
+    const char *, uint_t, uint_t, const char **);
+extern boolean_t ctftest_check_fptr(const char *, ctf_file_t *,
+    const char *, uint_t, uint_t, const char **);
+
+/*
+ * Determine whether or not we have a duplicate type or not based on its name.
+ */
+extern boolean_t ctftest_duplicates(ctf_file_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHECK_COMMON_H */
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-enum.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,143 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle enums.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+	{ "ff6", "enum ff6" },
+	{ "ff10", "ff10_t" },
+	{ NULL }
+};
+
+static check_descent_t check_descent_ff6[] = {
+	{ "enum ff6", CTF_K_ENUM },
+	{ NULL }
+};
+
+static check_descent_t check_descent_ff10[] = {
+	{ "ff10_t", CTF_K_TYPEDEF },
+	{ "enum ff10", CTF_K_ENUM },
+	{ NULL }
+};
+
+static check_descent_t check_descent_chrono[] = {
+	{ "chrono_t", CTF_K_TYPEDEF },
+	{ "enum chrono", CTF_K_ENUM },
+	{ NULL }
+};
+
+static check_descent_test_t descents[] = {
+	{ "ff10", check_descent_ff10 },
+	{ "ff6", check_descent_ff6 },
+	{ "trigger", check_descent_chrono },
+	{ NULL }
+};
+
+static check_enum_t check_enum_ff6[] = {
+	{ "TERRA", 0 },
+	{ "LOCKE", 1 },
+	{ "EDGAR", 2 },
+	{ "SABIN", 3 },
+	{ "CELES", 4 },
+	{ "CYAN", 5 },
+	{ "SHADOW", 6 },
+	{ "GAU", 7 },
+	{ "SETZER", 8 },
+	{ "STRAGO", 9 },
+	{ "RELM", 10 },
+	{ "MOG", 11 },
+	{ "GOGO", 12 },
+	{ "UMARO", 13 },
+	{ "LEO", 14 },
+	{ "KEFKA", 15 },
+	{ NULL }
+};
+
+static check_enum_t check_enum_ff10[] = {
+	{ "TIDUS", -10 },
+	{ "YUNA", 23 },
+	{ "AURON", -34 },
+	{ "WAKA", 52 },
+	{ "LULU", INT32_MAX },
+	{ "RIKKU", INT32_MIN },
+	{ "KHIMARI", 0 },
+	{ NULL }
+};
+
+static check_enum_t check_enum_chrono[] = {
+	{ "CRONO", 0x1000 },
+	{ "LUCCA", 0x2000 },
+	{ "MARLE", 0x3000 },
+	{ "FROG", 0x4000 },
+	{ "ROBO", 0x5000 },
+	{ "AYLA", 0x6000 },
+	{ "MAGUS", 0x7000 },
+	{ "SCHALA", 0x8000 },
+	{ "LAVOS", 0x9000 },
+	{ "BALTHAZAR", 0xa000 },
+	{ NULL }
+};
+
+static check_enum_test_t enums[] = {
+	{ "enum ff6", check_enum_ff6 },
+	{ "enum ff10", check_enum_ff10 },
+	{ "enum chrono", check_enum_chrono },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t d;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		for (d = 0; descents[d].cdt_sym != NULL; d++) {
+			if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+			    descents[d].cdt_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		for (d = 0; enums[d].cet_type != NULL; d++) {
+			if (!ctftest_check_enum(enums[d].cet_type, fp,
+			    enums[d].cet_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+		ctf_close(fp);
+	}
+
+	return (ret);
+
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-float.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,80 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check for basic float types.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "check-common.h"
+
+static check_number_t check_floats[] = {
+	{ "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 },
+	{ "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 },
+#ifdef	TARGET_LP64
+	{ "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 128 },
+#else
+	{ "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 96 },
+#endif
+	{ "complex float", CTF_K_FLOAT, CTF_FP_CPLX, 0, 64 },
+	{ "complex double", CTF_K_FLOAT, CTF_FP_DCPLX, 0, 128 },
+#ifdef	TARGET_LP64
+	{ "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 256 },
+#else
+	{ "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 192 },
+#endif
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "a", "float" },
+	{ "b", "double" },
+	{ "c", "long double" },
+	{ "d", "complex float" },
+	{ "e", "complex double" },
+	{ "f", "complex long double" },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_numbers(fp, check_floats))
+			ret = EXIT_FAILURE;
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-forward.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,130 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Verify that we can properly handle forward declarations.
+ *
+ * In test-forward.c barp is declared as a union, not a struct. However, today
+ * the CTF tooling does not contain enough information to know whether a forward
+ * declaration was for a struct or a union, only that it was a forward.
+ * Therefore, the type printing information assumes at the moment that the type
+ * is a struct. In a future revision of the CTF type data, we should encode this
+ * information in the equivalent of ctt_info so we can properly distinguish
+ * between these.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+	{ "forward", "struct forward" },
+	{ "foop", "struct foo *" },
+	{ "barp", "struct bar *" },
+	{ "bazp", "enum baz *" },
+	{ NULL }
+};
+
+static check_member_t check_member_forward[] = {
+#ifdef	TARGET_LP64
+	{ "prev", "struct foo *", 0 },
+	{ "next", "struct foo *", 8 * NBBY },
+	{ "data", "struct bar *", 16 * NBBY },
+	{ "tag", "enum baz *", 24 * NBBY },
+#else
+	{ "prev", "struct foo *", 0 },
+	{ "next", "struct foo *", 4 * NBBY },
+	{ "data", "struct bar *", 8 * NBBY },
+	{ "tag", "enum baz *", 12 * NBBY },
+#endif
+	{ NULL }
+};
+
+
+static check_member_test_t members[] = {
+#ifdef	TARGET_LP64
+	{ "struct forward", CTF_K_STRUCT, 32, check_member_forward },
+#else
+	{ "struct forward", CTF_K_STRUCT, 16, check_member_forward },
+#endif
+	{ NULL }
+};
+
+static check_descent_t check_descent_foo[] = {
+	{ "struct foo *", CTF_K_POINTER },
+	{ "struct foo", CTF_K_FORWARD },
+	{ NULL }
+};
+
+static check_descent_t check_descent_bar[] = {
+	{ "struct bar *", CTF_K_POINTER },
+	{ "struct bar", CTF_K_FORWARD },
+	{ NULL }
+};
+
+static check_descent_t check_descent_baz[] = {
+	{ "enum baz *", CTF_K_POINTER },
+	{ "enum baz", CTF_K_ENUM },
+	{ NULL }
+};
+
+static check_descent_test_t descents[] = {
+	{ "foop", check_descent_foo },
+	{ "barp", check_descent_bar },
+	{ "bazp", check_descent_baz },
+	{ NULL }
+};
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+
+		for (j = 0; descents[j].cdt_sym != NULL; j++) {
+			if (!ctftest_check_descent(descents[j].cdt_sym, fp,
+			    descents[j].cdt_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+
+		for (j = 0; members[j].cmt_type != NULL; j++) {
+			if (!ctftest_check_members(members[j].cmt_type, fp,
+			    members[j].cmt_kind, members[j].cmt_size,
+			    members[j].cmt_members)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-function.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,88 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle functions and function pointers.
+ */
+
+#include "check-common.h"
+
+static const char *one_args[] = { "int" };
+static const char *two_args[] = { "int", "const char *" };
+static const char *three_args[] = { "int", "const char *", "float" };
+static const char *argument_args[] = { "uintptr_t" };
+static const char *vararg_args[] = { "const char *" };
+
+static check_function_test_t functions[] = {
+	{ "simple_func", "void", 0, 0, NULL },
+	{ "one", "void", 1, 0, one_args },
+	{ "two", "void", 2, 0, two_args },
+	{ "three", "void", 3, 0, three_args },
+	{ "noarg", "const char *", 0, 0, NULL },
+	{ "argument", "const char *", 1, 0, argument_args },
+	{ "vararg", "void", 1, CTF_FUNC_VARARG, vararg_args },
+	{ "vararg_ret", "uintptr_t", 1, CTF_FUNC_VARARG, vararg_args },
+	{ NULL }
+};
+
+static const char *strfunc_args[] = { "const char *", "const char *" };
+
+static check_function_test_t fptrs[] = {
+	{ "strfunc_t", "int", 2, 0, strfunc_args },
+	{ "vararg_t", "void", 1, CTF_FUNC_VARARG, vararg_args },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		for (j = 0; functions[j].cft_name != NULL; j++) {
+			if (!ctftest_check_function(functions[j].cft_name, fp,
+			    functions[j].cft_rtype, functions[j].cft_nargs,
+			    functions[j].cft_flags, functions[j].cft_args)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		for (j = 0; fptrs[j].cft_name != NULL; j++) {
+			if (!ctftest_check_fptr(fptrs[j].cft_name, fp,
+			    fptrs[j].cft_rtype, fptrs[j].cft_nargs,
+			    fptrs[j].cft_flags, fptrs[j].cft_args)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-int.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,88 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check for basic integer types.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "check-common.h"
+
+static check_number_t check_ints[] = {
+	{ "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+	{ "short", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 16 },
+	{ "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+#ifdef	TARGET_LP64
+	{ "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 },
+#else
+	{ "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+#endif
+	{ "long long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 },
+	{ "unsigned char", CTF_K_INTEGER, CTF_INT_CHAR, 0, 8 },
+	{ "unsigned short", CTF_K_INTEGER, 0, 0, 16 },
+	{ "unsigned int", CTF_K_INTEGER, 0, 0, 32 },
+#ifdef	TARGET_LP64
+	{ "unsigned long", CTF_K_INTEGER, 0, 0, 64 },
+#else
+	{ "unsigned long", CTF_K_INTEGER, 0, 0, 32 },
+#endif
+	{ "unsigned long long", CTF_K_INTEGER, 0, 0, 64 },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "a", "char" },
+	{ "b", "unsigned char" },
+	{ "d", "short" },
+	{ "e", "unsigned short" },
+	{ "g", "int" },
+	{ "h", "unsigned int" },
+	{ "j", "long" },
+	{ "k", "unsigned long" },
+	{ "m", "long long" },
+	{ "n", "unsigned long long" },
+	{ NULL },
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_numbers(fp, check_ints))
+			ret = EXIT_FAILURE;
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:49 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c	Tue Apr 23 05:35:49 2019
@@ -0,0 +1,82 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that we don't end up with several copies of the same type.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+	{ "int", "a" },
+	{ "short", "b" },
+	{ "const char *", "c" },
+	{ "float", "d" },
+	{ "double" "e" },
+	{ "int", "f" },
+	{ "short", "g" },
+	{ "const char *", "h" },
+	{ "float", "i" },
+	{ "double" "j" },
+	{ "int", "k" },
+	{ "short", "l" },
+	{ "const char *", "m" },
+	{ "float", "n" },
+	{ "double" "o" },
+	{ "int", "p" },
+	{ "short", "q" },
+	{ "const char *", "r" },
+	{ "float", "s" },
+	{ "double" "t" },
+	{ "struct dup" "dupmain" },
+	{ "struct dup" "dup1" },
+	{ "struct dup" "dup2" },
+	{ "struct dup" "dup3" },
+	{ NULL }
+};
+
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms)) {
+			ret = EXIT_FAILURE;
+		}
+
+		if (!ctftest_duplicates(fp)) {
+			ret = EXIT_FAILURE;
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-merge-forward.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,132 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that a forward declared in one object file that is defined in
+ * another doesn't end up in the final one.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+	{ "list", "foo_list_t" },
+	{ NULL }
+};
+
+static check_member_t check_member_foo_list[] = {
+	{ "count", "int", 0 },
+#ifdef	TARGET_LP64
+	{ "head", "struct foo *", 8 * NBBY },
+	{ "tail", "struct foo *", 16 * NBBY },
+#else
+	{ "head", "struct foo *", 4 * NBBY },
+	{ "tail", "struct foo *", 8 * NBBY },
+#endif
+	{ NULL }
+};
+
+static check_member_t check_member_foo[] = {
+	{ "next", "struct foo *", 0 * NBBY },
+#ifdef	TARGET_LP64
+	{ "left", "int", 8 * NBBY },
+	{ "right", "int", 12 * NBBY },
+	{ "count", "int", 16 * NBBY },
+#else
+	{ "left", "int", 4 * NBBY },
+	{ "right", "int", 8 * NBBY },
+	{ "count", "int", 12 * NBBY },
+#endif
+	{ NULL }
+};
+
+static check_member_test_t members[] = {
+#ifdef	TARGET_LP64
+	{ "struct foo_list", CTF_K_STRUCT, 24, check_member_foo_list },
+	{ "struct foo", CTF_K_STRUCT, 24, check_member_foo },
+#else
+	{ "struct foo_list", CTF_K_STRUCT, 12, check_member_foo_list },
+	{ "struct foo", CTF_K_STRUCT, 16, check_member_foo },
+#endif
+	{ NULL }
+};
+
+static int
+ctf_merge_forward_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+	ctf_file_t *fp = arg;
+	char buf[2048];
+
+	if (ctf_type_kind(fp, id) != CTF_K_FORWARD)
+		return (0);
+
+	if (ctf_type_name(fp, id, buf, sizeof (buf)) == NULL) {
+		warnx("failed to lookup the name of type %ld: %s", id,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (1);
+	}
+
+	/*
+	 * If a forward shows up, that's OK. It's only bad if it's the name of
+	 * the one we created.
+	 */
+	if (strcmp("struct foo", buf) == 0) {
+		warnx("encountered forward type for struct foo that "
+		    "shouldn't exist");
+		return (1);
+	}
+
+	return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+
+		for (j = 0; members[j].cmt_type != NULL; j++) {
+			if (!ctftest_check_members(members[j].cmt_type, fp,
+			    members[j].cmt_kind, members[j].cmt_size,
+			    members[j].cmt_members)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		if (ctf_type_iter(fp, B_TRUE, ctf_merge_forward_cb, fp) != 0) {
+			ret = EXIT_FAILURE;
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,72 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that a global that has been scoped to local scope through symbol
+ * reduction of a mapfile can still be detected.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+	{ "data", "int" },
+	{ NULL }
+};
+
+static const char *scoped_args[] = { "uint32_t" };
+
+static check_function_test_t functions[] = {
+	{ "global", "int", 0, 0, NULL },
+	{ "scoped", "int", 1, 0, scoped_args },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+
+		for (j = 0; functions[j].cft_name != NULL; j++) {
+			if (!ctftest_check_function(functions[j].cft_name, fp,
+			    functions[j].cft_rtype, functions[j].cft_nargs,
+			    functions[j].cft_flags, functions[j].cft_args)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-merge-static.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,290 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Verify that various type information for static symbols is accurate for the
+ * file in question. To run this test, there's a global and static version of a
+ * symbol and function that exists on a per-file basis. These will all have been
+ * reproduced in the output file. As such, we need to iterate the symbol table
+ * to know which version should be which and use that to drive things.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <limits.h>
+#include <strings.h>
+
+#include "check-common.h"
+
+typedef struct check_map {
+	const char *map_file;
+	const char *map_type;
+} check_map_t;
+
+static const char *global_type = "int";
+static check_map_t map[] = {
+	{ "test-a.c", "uint8_t" },
+	{ "test-b.c", "uint16_t" },
+	{ "test-c.c", "uint32_t" },
+	{ "test-d.c", "uint64_t" },
+	{ NULL }
+};
+
+static const char *
+check_file_to_type(GElf_Sym *symp, const char *file, const char *name)
+{
+	uint_t i;
+
+	if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL) {
+		return (global_type);
+	}
+
+	if (file == NULL) {
+		warnx("encountered non-global symbol without STT_FILE info: %s",
+		    name);
+		return (NULL);
+	}
+
+	for (i = 0; map[i].map_file != NULL; i++) {
+		if (strcmp(map[i].map_file, file) == 0) {
+			return (map[i].map_type);
+		}
+	}
+
+	warnx("failed to find type mapping for symbol %s, file %s", name, file);
+	return (NULL);
+}
+
+static int
+check_global(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
+    const char *name)
+{
+	const char *type;
+	ctf_id_t tid;
+	char buf[2048];
+
+	if ((type = check_file_to_type(symp, file, name)) == NULL) {
+		return (EXIT_FAILURE);
+	}
+
+	if ((tid = ctf_lookup_by_symbol(fp, symid)) == CTF_ERR) {
+		warnx("failed to get type for symbol %s (%d): %s", name, symid,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (EXIT_FAILURE);
+	}
+
+	if (ctf_type_name(fp, tid, buf, sizeof (buf)) == NULL) {
+		warnx("failed to get type name for symbol %s (%d): %s",
+		    name, symid, ctf_errmsg(ctf_errno(fp)));
+		return (EXIT_FAILURE);
+	}
+
+	if (strcmp(buf, type) != 0) {
+		warnx("type mismatch for symbol %s (%d): found %s, expected %s",
+		    name, symid, buf, type);
+		return (EXIT_FAILURE);
+	}
+
+	return (0);
+}
+
+static int
+check_mumble(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
+    const char *name)
+{
+	const char *type;
+	ctf_funcinfo_t fi;
+	ctf_id_t id, args;
+
+	if ((type = check_file_to_type(symp, file, name)) == NULL) {
+		return (EXIT_FAILURE);
+	}
+
+	if ((id = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
+		warnx("failed to lookup type id for %s: %s", type,
+		    ctf_errmsg(ctf_errno(fp)));
+		return (EXIT_FAILURE);
+	}
+
+	if (ctf_func_info(fp, symid, &fi) != 0) {
+		warnx("failed to get function information for %s (%d): %s",
+		    name, symid, ctf_errmsg(ctf_errno(fp)));
+		return (EXIT_FAILURE);
+	}
+
+	if (fi.ctc_argc != 1) {
+		warnx("argument count mismatch for symbol %s (%d): found %u, "
+		    "expected %d", name, symid, fi.ctc_argc, 1);
+		return (EXIT_FAILURE);
+	}
+
+	if (fi.ctc_flags != 0) {
+		warnx("function flags mismatch for symbol %s (%d): found %u, "
+		    "expected %d", name, symid, fi.ctc_flags, 0);
+		return (EXIT_FAILURE);
+	}
+
+	if (fi.ctc_return != id) {
+		warnx("return value mismatch for symbol %s (%d): found %ld, "
+		    "expected %ld", name, symid, fi.ctc_return, id);
+		return (EXIT_FAILURE);
+	}
+
+	if (ctf_func_args(fp, symid, 1, &args) != 0) {
+		warnx("failed to get function arguments for symbol %s (%d): %s",
+		    name, symid, ctf_errmsg(ctf_errno(fp)));
+		return (EXIT_FAILURE);
+	}
+
+	if (args != id) {
+		warnx("argument mismatch for symbol %s (%d): found %ld, "
+		    "expected %ld", name, symid, args, id);
+		return (EXIT_FAILURE);
+	}
+
+	return (0);
+}
+
+static int
+check_merge_static(const char *file, ctf_file_t *fp, Elf *elf)
+{
+	Elf_Scn *scn = NULL, *symscn = NULL;
+	Elf_Data *symdata = NULL;
+	GElf_Shdr symhdr;
+	ulong_t nsyms;
+	int i;
+	const char *curfile = NULL;
+	int ret = 0;
+
+	while ((scn = elf_nextscn(elf, scn)) != NULL) {
+		if (gelf_getshdr(scn, &symhdr) == NULL) {
+			warnx("failed to get section header: %s",
+			    elf_errmsg(elf_errno()));
+			return (EXIT_FAILURE);
+		}
+
+		if (symhdr.sh_type == SHT_SYMTAB) {
+			symscn = scn;
+			break;
+		}
+	}
+
+	if (symscn == NULL) {
+		warnx("failed to find symbol table for %s", file);
+		return (EXIT_FAILURE);
+	}
+
+	if ((symdata = elf_getdata(symscn, NULL)) == NULL) {
+		warnx("failed to get data for symbol table %s: %s", file,
+		    elf_errmsg(elf_errno()));
+		return (EXIT_FAILURE);
+	}
+
+	if (symhdr.sh_link == SHN_XINDEX) {
+		warnx("test does not support extended ELF sections!");
+		return (EXIT_FAILURE);
+	}
+	nsyms = symhdr.sh_size / symhdr.sh_entsize;
+	if (nsyms > INT_MAX) {
+		warnx("file contains more symbols than libelf can iterate");
+		return (EXIT_FAILURE);
+	}
+
+	for (i = 1; i < (int)nsyms; i++) {
+		GElf_Sym sym;
+		const char *name;
+		uint_t type;
+
+		if (gelf_getsym(symdata, i, &sym) == NULL) {
+			warnx("failed to get data about symbol %d", i);
+			return (EXIT_FAILURE);
+		}
+
+		if ((name = elf_strptr(elf, symhdr.sh_link, sym.st_name)) ==
+		    NULL) {
+			warnx("failed to get name for symbol %d", i);
+			return (EXIT_FAILURE);
+		}
+
+		type = GELF_ST_TYPE(sym.st_info);
+		if (type == STT_FILE) {
+			curfile = name;
+			continue;
+		}
+
+		if (strcmp(name, "global") == 0) {
+			ret |= check_global(fp, &sym, i, curfile, name);
+		} else if (strcmp(name, "mumble") == 0) {
+			ret |= check_mumble(fp, &sym, i, curfile, name);
+		}
+	}
+
+	return (ret);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	if (elf_version(EV_CURRENT) == EV_NONE) {
+		errx(EXIT_FAILURE, "failed to initialize libelf");
+	}
+
+	for (i = 1; i < argc; i++) {
+		int fd;
+		ctf_file_t *fp;
+		Elf *elf;
+
+		if ((fd = open(argv[i], O_RDONLY)) < 0) {
+			warn("failed to open %s", argv[i]);
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+			warnx("failed to open libelf handle to %s", argv[i]);
+			ret = EXIT_FAILURE;
+			(void) close(fd);
+			continue;
+		}
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			(void) close(fd);
+			(void) elf_end(elf);
+			continue;
+		}
+
+		if (check_merge_static(argv[i], fp, elf) != 0) {
+			ret = EXIT_FAILURE;
+		}
+
+		ctf_close(fp);
+		(void) close(fd);
+		(void) elf_end(elf);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-merge-weak.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,70 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle weak symbols.
+ */
+
+#include "check-common.h"
+
+
+static check_function_test_t functions[] = {
+	{ "mumble", "int", 0, 0, NULL },
+	{ "_mumble", "int", 0, 0, NULL },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "foo", "int" },
+	{ "_foo", "int" },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+
+		for (j = 0; functions[j].cft_name != NULL; j++) {
+			if (!ctftest_check_function(functions[j].cft_name, fp,
+			    functions[j].cft_rtype, functions[j].cft_nargs,
+			    functions[j].cft_flags, functions[j].cft_args)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-reference.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,197 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly understand reference types and can walk through them
+ * as well as generate them.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_base[] = {
+	{ "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+	{ "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+	{ "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "a", "int" },
+	{ "aa", "test_int_t" },
+	{ "b", "const short" },
+	{ "c", "volatile float" },
+	{ "d", "int *" },
+	{ "dd", "int **" },
+	{ "ddd", "int ***" },
+	{ "e", "test_int_t *" },
+	{ "ce", "const test_int_t *" },
+	{ "ve", "volatile test_int_t *" },
+	{ "cve", "const volatile test_int_t *" },
+	{ "f", "int *const *" },
+	{ "g", "const char *const" },
+	{ NULL },
+};
+
+static check_descent_t check_descent_aa[] = {
+	{ "test_int_t", CTF_K_TYPEDEF },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_b[] = {
+	{ "const short", CTF_K_CONST },
+	{ "short", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_c[] = {
+	{ "volatile float", CTF_K_VOLATILE },
+	{ "float", CTF_K_FLOAT },
+	{ NULL }
+};
+
+static check_descent_t check_descent_d[] = {
+	{ "int *", CTF_K_POINTER },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_dd[] = {
+	{ "int **", CTF_K_POINTER },
+	{ "int *", CTF_K_POINTER },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_ddd[] = {
+	{ "int ***", CTF_K_POINTER },
+	{ "int **", CTF_K_POINTER },
+	{ "int *", CTF_K_POINTER },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_e[] = {
+	{ "test_int_t *", CTF_K_POINTER },
+	{ "test_int_t", CTF_K_TYPEDEF },
+	{ "int", CTF_K_INTEGER },
+	{ NULL },
+};
+
+static check_descent_t check_descent_ce[] = {
+	{ "const test_int_t *", CTF_K_POINTER },
+	{ "const test_int_t", CTF_K_CONST },
+	{ "test_int_t", CTF_K_TYPEDEF },
+	{ "int", CTF_K_INTEGER },
+	{ NULL },
+};
+
+static check_descent_t check_descent_ve[] = {
+	{ "volatile test_int_t *", CTF_K_POINTER},
+	{ "volatile test_int_t", CTF_K_VOLATILE },
+	{ "test_int_t", CTF_K_TYPEDEF },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_cve[] = {
+	{ "const volatile test_int_t *", CTF_K_POINTER },
+	{ "const volatile test_int_t", CTF_K_CONST },
+	{ "volatile test_int_t", CTF_K_VOLATILE },
+	{ "test_int_t", CTF_K_TYPEDEF },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_f[] = {
+	{ "int *const *", CTF_K_POINTER },
+	{ "int *const", CTF_K_CONST },
+	{ "int *", CTF_K_POINTER },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_g[] = {
+	{ "const char *const", CTF_K_CONST },
+	{ "const char *", CTF_K_POINTER },
+	{ "const char", CTF_K_CONST },
+	{ "char", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_t check_descent_cvh[] = {
+	{ "const volatile foo_t *", CTF_K_POINTER },
+	{ "const volatile foo_t", CTF_K_CONST },
+	{ "volatile foo_t", CTF_K_VOLATILE },
+	{ "foo_t", CTF_K_TYPEDEF },
+	{ "int *const *", CTF_K_POINTER },
+	{ "int *const", CTF_K_CONST },
+	{ "int *", CTF_K_POINTER },
+	{ "int", CTF_K_INTEGER },
+	{ NULL }
+};
+
+static check_descent_test_t descents[] = {
+	{ "aa", check_descent_aa },
+	{ "b", check_descent_b },
+	{ "c", check_descent_c },
+	{ "d", check_descent_d },
+	{ "dd", check_descent_dd },
+	{ "ddd", check_descent_ddd },
+	{ "e", check_descent_e },
+	{ "ce", check_descent_ce },
+	{ "ve", check_descent_ve },
+	{ "cve", check_descent_cve },
+	{ "f", check_descent_f },
+	{ "g", check_descent_g },
+	{ "cvh", check_descent_cvh },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t d;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_numbers(fp, check_base))
+			ret = EXIT_FAILURE;
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		for (d = 0; descents[d].cdt_sym != NULL; d++) {
+			if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+			    descents[d].cdt_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-sou.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,405 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle structures and unions.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_bitfields[] = {
+#ifdef	TARGET_LP64
+	{ "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 },
+	{ "unsigned long:2", CTF_K_INTEGER,  0, 0, 2 },
+	{ "unsigned long:4", CTF_K_INTEGER,  0, 0, 4 },
+	{ "unsigned long:5", CTF_K_INTEGER,  0, 0, 5 },
+	{ "unsigned long:8", CTF_K_INTEGER,  0, 0, 8 },
+	{ "unsigned long:16", CTF_K_INTEGER,  0, 0, 16 },
+	{ "unsigned long:19", CTF_K_INTEGER,  0, 0, 19 },
+	{ "unsigned long:32", CTF_K_INTEGER,  0, 0, 32 },
+#else
+	{ "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 },
+	{ "unsigned long long:2", CTF_K_INTEGER,  0, 0, 2 },
+	{ "unsigned long long:4", CTF_K_INTEGER,  0, 0, 4 },
+	{ "unsigned long long:5", CTF_K_INTEGER,  0, 0, 5 },
+	{ "unsigned long long:8", CTF_K_INTEGER,  0, 0, 8 },
+	{ "unsigned long long:16", CTF_K_INTEGER,  0, 0, 16 },
+	{ "unsigned long long:19", CTF_K_INTEGER,  0, 0, 19 },
+	{ "unsigned long long:32", CTF_K_INTEGER,  0, 0, 32 },
+#endif
+	{ "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 },
+	{ "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 },
+	{ "unsigned int:32", CTF_K_INTEGER, 0, 0, 32 },
+	{ "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "foo", "struct foo" },
+	{ "head", "nlist_t" },
+	{ "forward", "const forward_t" },
+	{ "oot", "struct round_up" },
+	{ "botw", "struct fixed_up" },
+	{ "sophie", "struct mysterious_barrel" },
+	{ "ayesha", "struct dusk_barrel" },
+	{ "stats", "struct stats" },
+	{ "ring", "struct fellowship" },
+	{ "rings", "struct rings" },
+	{ "nvme", "struct csts" },
+	{ "games", "union jrpg" },
+	{ "nier", "union nier" },
+	{ "kh", "union kh" },
+	{ "ct", "struct trigger" },
+	{ "regress", "const union regress [9]" },
+	{ NULL }
+};
+
+static check_member_t check_member_foo[] = {
+	{ "a", "int", 0 },
+	{ "b", "float", 4 * NBBY },
+	{ "c", "const char *", 8 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_node[] = {
+	{ "prev", "struct node *", 0 },
+#ifdef	TARGET_LP64
+	{ "next", "struct node *", 8 * NBBY },
+#else
+	{ "next", "struct node *", 4 * NBBY },
+#endif
+	{ NULL }
+};
+
+static check_member_t check_member_nlist[] = {
+	{ "size", "size_t", 0 },
+#ifdef	TARGET_LP64
+	{ "off", "size_t", 8 * NBBY },
+	{ "head", "struct node", 16 * NBBY },
+#else
+	{ "off", "size_t", 4 * NBBY },
+	{ "head", "struct node", 8 * NBBY },
+#endif
+	{ NULL }
+};
+
+static check_member_t check_member_forward[] = {
+	{ "past", "void *", 0 },
+#ifdef	TARGET_LP64
+	{ "present", "void *", 8 * NBBY },
+	{ "future", "void *", 16 * NBBY },
+#else
+	{ "present", "void *", 4 * NBBY },
+	{ "future", "void *", 8 * NBBY },
+#endif
+	{ NULL }
+};
+
+static check_member_t check_member_round_up[] = {
+	{ "triforce", "uint8_t", 0 },
+	{ "link", "uint32_t", 4 * NBBY },
+	{ "zelda", "uint8_t", 8 * NBBY },
+	{ "ganon", "uint8_t", 9 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_fixed_up[] = {
+	{ "triforce", "uint8_t", 0 },
+	{ "link", "uint32_t", 1 * NBBY },
+	{ "zelda", "uint8_t", 5 * NBBY },
+	{ "ganon", "uint8_t", 6 * NBBY },
+	{ NULL }
+};
+
+#ifdef	TARGET_LP64
+static check_member_t check_member_component[] = {
+	{ "m", "enum material", 0 },
+	{ "grade", "uint64_t", 8 * NBBY },
+	{ "count", "uint64_t", 16 * NBBY },
+	{ "locations", "const char *[4]", 24 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_mysterious[] = {
+	{ "name", "const char *", 0 },
+	{ "capacity", "size_t", 8 * NBBY },
+	{ "optional", "struct component [0]", 16 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_dusk[] = {
+	{ "name", "const char *", 0 },
+	{ "opacity", "size_t", 8 * NBBY },
+	{ "optional", "struct component [0]", 16 * NBBY },
+	{ NULL }
+};
+
+
+static check_member_t check_member_stats[] = {
+	{ "hp", "unsigned long:16", 0 },
+	{ "mp", "unsigned long:16", 16 },
+	{ "str", "unsigned long:8", 32 },
+	{ "dex", "unsigned long:4", 40 },
+	{ "con", "unsigned long:1", 44 },
+	{ "inte", "unsigned long:2", 45 },
+	{ "wis", "unsigned long:1", 47 },
+	{ "cha", "unsigned long:4", 48 },
+	{ "sanity", "unsigned long:1", 52 },
+	{ "attack", "unsigned long:2", 53 },
+	{ "mattack", "unsigned long:1", 55 },
+	{ "defense", "unsigned long:8", 56 },
+	{ "mdefense", "unsigned long:32", 64 },
+	{ "evasion", "unsigned long:8", 96 },
+	{ "crit", "unsigned long:5", 104 },
+	{ "luck", "unsigned long:19", 109 },
+	{ NULL }
+};
+#else
+static check_member_t check_member_component[] = {
+	{ "m", "enum material", 0 },
+	{ "grade", "uint64_t", 4 * NBBY },
+	{ "count", "uint64_t", 12 * NBBY },
+	{ "locations", "const char *[4]", 20 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_mysterious[] = {
+	{ "name", "const char *", 0 },
+	{ "capacity", "size_t", 4 * NBBY },
+	{ "optional", "struct component [0]", 8 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_dusk[] = {
+	{ "name", "const char *", 0 },
+	{ "opacity", "size_t", 4 * NBBY },
+	{ "optional", "struct component [0]", 8 * NBBY },
+	{ NULL }
+};
+
+
+static check_member_t check_member_stats[] = {
+	{ "hp", "unsigned long long:16", 0 },
+	{ "mp", "unsigned long long:16", 16 },
+	{ "str", "unsigned long long:8", 32 },
+	{ "dex", "unsigned long long:4", 40 },
+	{ "con", "unsigned long long:1", 44 },
+	{ "inte", "unsigned long long:2", 45 },
+	{ "wis", "unsigned long long:1", 47 },
+	{ "cha", "unsigned long long:4", 48 },
+	{ "sanity", "unsigned long long:1", 52 },
+	{ "attack", "unsigned long long:2", 53 },
+	{ "mattack", "unsigned long long:1", 55 },
+	{ "defense", "unsigned long long:8", 56 },
+	{ "mdefense", "unsigned long long:32", 64 },
+	{ "evasion", "unsigned long long:8", 96 },
+	{ "crit", "unsigned long long:5", 104 },
+	{ "luck", "unsigned long long:19", 109 },
+	{ NULL }
+};
+#endif
+
+static check_member_t check_member_fellowship[] = {
+	{ "frodo", "unsigned short:1", 0 },
+	{ "sam", "unsigned short:1", 1 },
+	{ "merry", "unsigned short:1", 2 },
+	{ "pippin", "unsigned short:1", 3 },
+	{ "aragorn", "unsigned short:1", 4 },
+	{ "boromir", "unsigned short:1", 5 },
+	{ "legolas", "unsigned short:1", 6 },
+	{ "gimli", "unsigned short:1", 7 },
+	{ "gandalf", "unsigned short:1", 8 },
+	{ NULL }
+};
+
+static check_member_t check_member_rings[] = {
+	{ "elves", "unsigned int:3", 0 },
+	{ "dwarves", "unsigned int:7", 3 },
+	{ "men", "unsigned int:9", 10 },
+	{ "one", "uint8_t", 3 * NBBY },
+	{ "silmarils", "uint8_t [3]", 4 * NBBY },
+	{ NULL }
+};
+
+static check_member_t check_member_csts[] = {
+	{ "rdy", "unsigned int:7", 0 },
+	{ "csts", "unsigned int:32", 7 },
+	{ NULL }
+};
+
+static check_member_t check_member_jrpg[] = {
+	{ "ff", "int", 0 },
+	{ "atelier", "double [4]", 0 },
+	{ "tales", "const char *", 0 },
+	{ "chrono", "int (*)()", 0 },
+	{ "xeno", "struct rings", 0 },
+	{ NULL }
+};
+
+static check_member_t check_member_android[] = {
+	{ "_2b", "unsigned int:16", 0 },
+	{ "_9s", "unsigned int:16", 16 },
+	{ NULL }
+};
+
+static check_member_t check_member_nier[] = {
+	{ "automata", "uint32_t", 0 },
+	{ "android", "struct android", 0 },
+	{ NULL }
+};
+
+static check_member_t check_member_kh[] = {
+	{ "sora", "int:3", 0 },
+	{ "riku", "char:7", 0 },
+	{ "kairi", "double", 0 },
+	{ "namine", "complex double", 0 },
+	{ NULL }
+};
+
+static check_member_t check_member_trigger[] = {
+	{ "chrono", "uint8_t", 0 },
+	{ "cross", "uint8_t", 8 },
+	/*
+	 * This test has an anonymous union. Unfortunately, there's not a great
+	 * way to distinguish between various anonymous unions in this form.
+	 */
+#ifdef	TARGET_LP64
+	{ "", "union ", 64 },
+#else
+	{ "", "union ", 32 },
+#endif
+	{ NULL }
+};
+
+static check_member_t check_member_regress[] = {
+	{ "i", "unsigned int [3]", 0 },
+	{ "e", "long double", 0 },
+	{ NULL }
+};
+
+static check_member_test_t members[] = {
+#ifdef	TARGET_LP64
+	{ "struct foo", CTF_K_STRUCT, 16, check_member_foo },
+	{ "struct node", CTF_K_STRUCT, 16, check_member_node },
+	{ "struct nlist", CTF_K_STRUCT, 32, check_member_nlist },
+	{ "struct forward", CTF_K_STRUCT, 24, check_member_forward },
+#else
+	{ "struct foo", CTF_K_STRUCT, 12, check_member_foo },
+	{ "struct node", CTF_K_STRUCT, 8, check_member_node },
+	{ "struct nlist", CTF_K_STRUCT, 16, check_member_nlist },
+	{ "struct forward", CTF_K_STRUCT, 12, check_member_forward },
+#endif
+	{ "struct round_up", CTF_K_STRUCT, 12, check_member_round_up },
+	{ "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up },
+#ifdef	TARGET_LP64
+	{ "struct component", CTF_K_STRUCT, 56, check_member_component },
+	{ "struct mysterious_barrel", CTF_K_STRUCT, 16,
+	    check_member_mysterious },
+	{ "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk },
+#else
+	{ "struct component", CTF_K_STRUCT, 36, check_member_component },
+	{ "struct mysterious_barrel", CTF_K_STRUCT, 8,
+	    check_member_mysterious },
+	{ "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk },
+#endif
+	{ "struct stats", CTF_K_STRUCT, 16, check_member_stats },
+	{ "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship },
+	{ "struct rings", CTF_K_STRUCT, 8, check_member_rings },
+	{ "struct csts", CTF_K_STRUCT, 5, check_member_csts },
+	{ "union jrpg", CTF_K_UNION, 32, check_member_jrpg },
+	{ "struct android", CTF_K_STRUCT, 4, check_member_android },
+	{ "union nier", CTF_K_UNION, 4, check_member_nier },
+	{ "union kh", CTF_K_UNION, 16, check_member_kh },
+#ifdef	TARGET_LP64
+	{ "struct trigger", CTF_K_STRUCT, 32, check_member_trigger },
+	{ "union regress", CTF_K_UNION, 16, check_member_regress },
+#else
+	{ "struct trigger", CTF_K_STRUCT, 28, check_member_trigger },
+	{ "union regress", CTF_K_UNION, 12, check_member_regress },
+#endif
+	{ NULL }
+};
+
+static check_descent_t check_descent_head[] = {
+	{ "nlist_t", CTF_K_TYPEDEF },
+	{ "struct nlist", CTF_K_STRUCT },
+	{ NULL }
+};
+
+static check_descent_t check_descent_forward[] = {
+	{ "const forward_t", CTF_K_CONST },
+	{ "forward_t", CTF_K_TYPEDEF },
+	{ "struct forward", CTF_K_STRUCT },
+	{ NULL }
+};
+
+static check_descent_t check_descent_regress[] = {
+	{ "const union regress [9]", CTF_K_CONST },
+	{ "union regress [9]", CTF_K_ARRAY, "union regress", 9 },
+	{ "union regress", CTF_K_UNION },
+	{ NULL }
+};
+
+static check_descent_test_t descents[] = {
+	{ "head", check_descent_head },
+	{ "forward", check_descent_forward },
+	{ "regress", check_descent_regress },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_numbers(fp, check_bitfields))
+			ret = EXIT_FAILURE;
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+		for (j = 0; descents[j].cdt_sym != NULL; j++) {
+			if (!ctftest_check_descent(descents[j].cdt_sym, fp,
+			    descents[j].cdt_tests)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		for (j = 0; members[j].cmt_type != NULL; j++) {
+			if (!ctftest_check_members(members[j].cmt_type, fp,
+			    members[j].cmt_kind, members[j].cmt_size,
+			    members[j].cmt_members)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/check-weak.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,70 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle weak symbols.
+ */
+
+#include "check-common.h"
+
+
+static check_function_test_t functions[] = {
+	{ "mumble", "int", 0, 0, NULL },
+	{ "_mumble", "int", 0, 0, NULL },
+	{ NULL }
+};
+
+static check_symbol_t check_syms[] = {
+	{ "strong", "int" },
+	{ "_strong", "int" },
+	{ NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	if (argc < 2) {
+		errx(EXIT_FAILURE, "missing test files");
+	}
+
+	for (i = 1; i < argc; i++) {
+		ctf_file_t *fp;
+		uint_t j;
+
+		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+			warnx("failed to open %s: %s", argv[i],
+			    ctf_errmsg(ret));
+			ret = EXIT_FAILURE;
+			continue;
+		}
+
+		if (!ctftest_check_symbols(fp, check_syms))
+			ret = EXIT_FAILURE;
+
+		for (j = 0; functions[j].cft_name != NULL; j++) {
+			if (!ctftest_check_function(functions[j].cft_name, fp,
+			    functions[j].cft_rtype, functions[j].cft_nargs,
+			    functions[j].cft_flags, functions[j].cft_args)) {
+				ret = EXIT_FAILURE;
+			}
+		}
+
+		ctf_close(fp);
+	}
+
+	return (ret);
+}
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/ctftest.ksh	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,257 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2019, Joyent, Inc.
+#
+
+#
+# Run all of the various CTF tests
+#
+
+unalias -a
+#set -o xtrace
+
+if [[ -z "$TMPDIR" ]]; then
+	TMPDIR="/tmp"
+fi
+
+ctf_arg0=$(basename $0)
+ctf_root=$(cd $(dirname $0) && echo $PWD)
+ctf_tests=
+ctf_compiler="gcc"
+ctf_convert="ctfconvert"
+ctf_merge="ctfmerge"
+ctf_debugflags="-gdwarf-2 "
+ctf_mach32="-m32"
+ctf_mach64="-m64"
+ctf_32cflags="$ctf_mach32 $ctf_debugflags"
+ctf_64cflags="$ctf_mach64 $ctf_debugflags"
+ctf_temp="$TMPDIR/ctftest.$$.o"
+ctf_makefile="Makefile.ctftest"
+ctf_nerrs=0
+
+usage()
+{
+	typeset msg="$*"
+	[[ -z "$msg" ]] || echo "$msg" >&2
+	cat <<USAGE >&2
+Usage: $ctf_arg0  [-c compiler] [-g flags] [-m ctfmerge] [-t ctfconvert]
+
+	Runs the CTF test suite
+
+	-c compiler		Use the specified compiler, defaults to 'gcc'
+				on path.
+	-g flags		Use flags to generate debug info. Defaults to
+				"-gdwarf-2".
+	-m ctfmerge		Use the specified ctfmerge, defaults to
+				'ctfmerge' on path.
+	-t ctfconvert		Use the specified ctfconvert, defaults to
+				'ctfconvert' on path.
+USAGE
+	exit 2
+}
+
+
+test_fail()
+{
+	typeset msg="$*"
+	[[ -z "$msg" ]] && msg="failed"
+	echo "TEST FAILED: $msg" >&2
+	((ctf_nerrs++))
+}
+
+fatal()
+{
+	typeset msg="$*"
+	[[ -z "$msg" ]] && msg="failed"
+	echo "$ctf_arg0: $msg" >&2
+	rm -f "$ctf_tmp32" "$ctf_temp64"
+	exit 1
+}
+
+check_env()
+{
+	if which "$1" 2>/dev/null >/dev/null; then
+		return
+	fi
+
+	[[ -f "$1" ]] || fatal "failed to find tool $1"
+}
+
+announce()
+{
+	cat << EOF
+Beginning CTF tests with the following settings:
+COMPILER:	$(which $ctf_compiler)
+CTFCONVERT:	$(which $ctf_convert)
+CTFMERGE:	$(which $ctf_merge)
+32-bit CFLAGS:	$ctf_32cflags
+64-bit CFLAGS:	$ctf_64cflags
+
+EOF
+}
+
+run_one()
+{
+	typeset source=$1 checker=$2 flags=$3
+
+	if ! "$ctf_compiler" $flags -o "$ctf_temp" -c "$source"; then
+		test_fail "failed to compile $source with flags: $flags"
+		return
+	fi
+
+	if ! "$ctf_convert" "$ctf_temp"; then
+		test_fail "failed to convert CTF in $source"
+		return
+	fi
+
+	if ! "$checker" "$ctf_temp"; then
+		test_fail "check for $source, $checker, failed"
+		return
+	fi
+
+	echo "TEST PASSED: $source $flags"
+}
+
+#
+# Perform a more complex build. The Makefile present will drive the
+# building of the artifacts and the running of the tests based on the
+# variables that we pass to it.
+#
+run_dir()
+{
+	typeset dir outdir check32 check64 flags32 flags64
+
+	dir=$1
+	outdir="$TMPDIR/ctftest.$$-$(basename $d)"
+	check32=$2
+	flags32=$3
+	check64=$4
+	flags64=$5
+
+	if ! mkdir $outdir; then
+		fatal "failed to make temporary directory '$outdir'"
+	fi
+
+	if ! make -C $dir -f Makefile.ctftest \
+	    BUILDDIR="$outdir" \
+	    CC="$ctf_compiler" \
+	    CFLAGS32="$ctf_mach32" \
+	    CFLAGS64="$ctf_mach64" \
+	    DEBUGFLAGS="$ctf_debugflags" \
+	    CTFCONVERT="$ctf_convert" \
+	    CTFMERGE="$ctf_merge" \
+	    build 1>/dev/null; then
+		rm -rf $outdir
+		test_fail "failed to build $dir"
+		return
+	fi
+
+	if ! make -C $dir -f Makefile.ctftest \
+	    BUILDDIR="$outdir" \
+	    CHECK32="$check32" \
+	    CHECK64="$check64" \
+	    run-test 1>/dev/null; then
+		rm -rf $outdir
+		test_fail "failed to run tests for $dir"
+		return
+	fi
+
+	rm -rf $outdir
+	echo "TEST PASSED: $dir (dir)"
+}
+
+#
+# Find all of the tests that exist and then try to run them all. Tests
+# may either be a single file or a directory.
+#
+run_tests()
+{
+	typeset t base check
+	ctf_tests=$(ls "$ctf_root"/*.c)
+	for t in $ctf_tests; do
+		base=$(basename "$t" .c)
+		check=$(echo "$base" | sed s/test-/check-/)
+		if [[ -f "$ctf_root/$check" ]]; then
+			run_one $t "$ctf_root/$check" "$ctf_32cflags"
+			run_one $t "$ctf_root/$check" "$ctf_64cflags"
+		elif [[ -f "$ctf_root/$check-32" && \
+		    -f "$ctf_root/$check-64" ]]; then
+			run_one $t "$ctf_root/$check-32" "$ctf_32cflags"
+			run_one $t "$ctf_root/$check-64" "$ctf_64cflags"
+		else
+			test_fail "missing checker for $t"
+		fi
+	done
+
+	for d in $(find "$ctf_root" -maxdepth 1 -type d -name 'test-*'); do
+		[[ ! -f "$d/$ctf_makefile" ]] && continue
+		base=$(basename "$d")
+		check=$(echo "$base" | sed s/test-/check-/)
+		if [[ -f "$ctf_root/$check" ]]; then
+			run_dir $d "$ctf_root/$check" "$ctf_32cflags" \
+			    "$ctf_root/$check" "$ctf_64cflags"
+		elif [[ -f "$ctf_root/$check-32" && \
+		    -f "$ctf_root/$check-64" ]]; then
+			run_dir $d "$ctf_root/$check-32" "$ctf_32cflags" \
+			    "$ctf_root/$check-64" "$ctf_64cflags"
+		else
+			test_fail "missing checker for $t"
+		fi
+	done
+}
+
+while getopts ":c:g:m:t:" c $@; do
+	case "$c" in
+	c)
+		ctf_compiler=$OPTARG
+		;;
+	g)
+		ctf_debugflags=$OPTARG
+		;;
+	m)
+		ctf_merge=$OPTARG
+		;;
+	t)
+		ctf_convert=$OPTARG
+		;;
+	:)
+		usage "option requires an argument -- $OPTARG"
+		;;
+	*)
+		usage "invalid option -- $OPTARG"
+		;;
+	esac
+done
+
+ctf_32cflags="$ctf_mach32 $ctf_debugflags"
+ctf_64cflags="$ctf_mach64 $ctf_debugflags"
+
+check_env "$ctf_compiler"
+check_env "$ctf_convert"
+check_env "$ctf_merge"
+announce
+
+run_tests
+
+if [[ $ctf_nerrs -ne 0 ]]; then
+	if [[ $ctf_nerrs -eq 1 ]]; then
+		printf "\n%s: %u test failed\n" "$ctf_arg0" "$ctf_nerrs"
+	else
+		printf "\n%s: %u tests failed\n" "$ctf_arg0" "$ctf_nerrs"
+	fi
+else
+	printf "\n%s: All tests passed successfully\n" "$ctf_arg0"
+	exit 0
+fi
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-array.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * A series of basic array tests with simple base types.
+ */
+
+int a[3];
+double b[42];
+const char *c[] = { "17" "31", "169" };
+
+int d[4][5];
+int e[4][5][6];
+int f[4][5][6][7];
+int g[4][5][6][7][8];
+int h[4][5][6][7][8][9];
+int i[4][5][6][7][8][9][10];
--- /dev/null	Tue Apr 23 05:35:50 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-enum.c	Tue Apr 23 05:35:50 2019
@@ -0,0 +1,74 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <stdint.h>
+
+/*
+ * Basic sanity checking of enumerations, using specific numbers and arbitrary
+ * numbers.
+ */
+
+enum ff6 {
+	TERRA,
+	LOCKE,
+	EDGAR,
+	SABIN,
+	CELES,
+	CYAN,
+	SHADOW,
+	GAU,
+	SETZER,
+	STRAGO,
+	RELM,
+	MOG,
+	GOGO,
+	UMARO,
+	LEO,
+	KEFKA
+};
+
+typedef enum ff10 {
+	TIDUS = -10,
+	YUNA = 23,
+	AURON = -34,
+	WAKA = 52,
+	LULU = INT32_MAX,
+	RIKKU = INT32_MIN,
+	KHIMARI = 0
+} ff10_t;
+
+/*
+ * The following enum is copy of the ddi_hp_cn_state_t enumeration which was
+ * previously incorrectly converted by the tools. Notably, we always assumed
+ * that the DWARF enum values were signed; however, in this case we needed to
+ * check for an unsigned version before a signed version, otherwise some of the
+ * entries below will have the wrong values.
+ */
+typedef enum chrono {
+	CRONO = 0x1000,
+	LUCCA = 0x2000,
+	MARLE = 0x3000,
+	FROG = 0x4000,
+	ROBO = 0x5000,
+	AYLA = 0x6000,
+	MAGUS = 0x7000,
+	SCHALA = 0x8000,
+	LAVOS = 0x9000,
+	BALTHAZAR = 0xa000
+} chrono_t;
+
+enum ff6 ff6;
+ff10_t ff10;
+chrono_t trigger;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-float.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,28 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <complex.h>
+
+/*
+ * Test floating point types. Unfortunately neither gcc nor clang support the
+ * imaginary keyword which means that we cannot test it.
+ */
+
+float a;
+double b;
+long double c;
+float complex d;
+double complex e;
+long double complex f;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-forward.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,34 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests the use of forward declarations of unknown types.
+ */
+
+struct foo;
+union bar;
+enum baz;
+
+struct forward {
+	struct foo *prev;
+	struct foo *next;
+	union bar *data;
+	enum baz *tag;
+};
+
+struct foo *foop;
+union bar *barp;
+enum baz *bazp;
+struct forward forward;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-function.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,71 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Test various function and function pointer cases.
+ */
+
+static void
+simple_func(void)
+{
+}
+
+static void
+one(int v)
+{
+}
+
+static void
+two(int v, const char *a)
+{
+}
+
+static void
+three(int v, const char *a, float b)
+{
+}
+
+static const char *
+noarg(void)
+{
+	return ("hello, world");
+}
+
+static const char *
+argument(uintptr_t base)
+{
+	return ((const char *)(base + 1));
+}
+
+static void
+vararg(const char *foo, ...)
+{
+
+}
+
+static uintptr_t
+vararg_ret(const char *foo, ...)
+{
+	return ((uintptr_t)foo);
+}
+
+typedef int (*strfunc_t)(const char *, const char *);
+typedef void (*vararg_t)(const char *, ...);
+
+strfunc_t s = strcmp;
+vararg_t v = vararg;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-int.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,34 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Test basic integer types. Note that signed types are considered the same as
+ * the base type.
+ */
+
+char a;
+unsigned char b;
+
+short d;
+unsigned short e;
+
+int g;
+unsigned int h;
+
+long j;
+unsigned long k;
+
+long long m;
+unsigned long long n;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST =		test-merge-dedup
+
+OBJS_C_32 =	$(BUILDDIR)/test-merge-1.32.c.o \
+		$(BUILDDIR)/test-merge-2.32.c.o \
+		$(BUILDDIR)/test-merge-3.32.c.o \
+		$(BUILDDIR)/test-merge-dedup.32.c.o
+
+OBJS_C_64 =	$(BUILDDIR)/test-merge-1.64.c.o \
+		$(BUILDDIR)/test-merge-2.64.c.o \
+		$(BUILDDIR)/test-merge-3.64.c.o \
+		$(BUILDDIR)/test-merge-dedup.64.c.o
+
+OBJS_M_32 =	$(BUILDDIR)/test-merge-1.32.m.o \
+		$(BUILDDIR)/test-merge-2.32.m.o \
+		$(BUILDDIR)/test-merge-3.32.m.o \
+		$(BUILDDIR)/test-merge-dedup.32.m.o
+
+OBJS_M_64 =	$(BUILDDIR)/test-merge-1.64.m.o \
+		$(BUILDDIR)/test-merge-2.64.m.o \
+		$(BUILDDIR)/test-merge-3.64.m.o \
+		$(BUILDDIR)/test-merge-dedup.64.m.o
+
+
+include		../Makefile.ctftest.com
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,27 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+int f;
+short g;
+const char *h;
+float i;
+double j;
+
+struct dup {
+	int dup;
+	int dup2;
+};
+
+struct dup dup1;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,27 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+int k;
+short l;
+const char *m;
+float n;
+double o;
+
+struct dup {
+	int dup;
+	int dup2;
+};
+
+struct dup dup2;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,27 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+int p;
+short q;
+const char *r;
+float s;
+double t;
+
+struct dup {
+	int dup;
+	int dup2;
+};
+
+struct dup dup3;
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,33 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+int a;
+short b;
+const char *c;
+float d;
+double e;
+
+struct dup {
+	int dup;
+	int dup2;
+};
+
+struct dup dupmain;
+
+int
+main(int argc, const char *argv[])
+{
+	return (0);
+}
--- /dev/null	Tue Apr 23 05:35:51 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest	Tue Apr 23 05:35:51 2019
@@ -0,0 +1,30 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.c.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST =		test-merge-forward
+
+OBJS_C_32 =	$(BUILDDIR)/test-merge.32.c.o \
+		$(BUILDDIR)/test-impl.32.c.o
+
+OBJS_C_64 =	$(BUILDDIR)/test-merge.64.c.o \
+		$(BUILDDIR)/test-impl.64.c.o
+
+OBJS_M_32 =	$(BUILDDIR)/test-merge.32.m.o \
+		$(BUILDDIR)/test-impl.32.m.o
+
+OBJS_M_64 =	$(BUILDDIR)/test-merge.64.m.o \
+		$(BUILDDIR)/test-impl.64.m.o
+
+include ../Makefile.ctftest.com
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+struct foo {
+	struct foo *next;
+	int left;
+	int right;
+	int count;
+};
+
+void
+mumble(struct foo *foo)
+{
+	foo->left = foo->right - foo->count;
+	foo->count += foo->right;
+	foo->right--;
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <stdio.h>
+
+struct foo;
+
+typedef struct foo_list {
+	int count;
+	struct foo *head;
+	struct foo *tail;
+} foo_list_t;
+
+foo_list_t list;
+
+int
+main(void)
+{
+	(void) printf("%p", &list);
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,92 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+#
+# This makefile could be simplified substantially. However, it does
+# everything explicitly to try and work with a wide variety of different
+# makes.
+#
+# The following values should be passed in by the invoker of the
+# Makefile:
+#
+#	CC		C Compiler to use
+#	CFLAGS32	32-bit CFLAGS
+#	CFLAGS64	64-bit CFLAGS
+#	CTFCONVERT	Path to ctfconvert
+#	CTFMERGE	Path to ctfmerge
+#	DEBUGFLAGS	The set of debug flags to use
+#	BUILDDIR	Directory things should be built in
+#	CHECK32		Program to check 32-bit output
+#	CHECK64		Program to check 64-bit output
+#
+
+OBJS_C_32 =	$(BUILDDIR)/test-global.32.c.o \
+		$(BUILDDIR)/test-scoped.32.c.o
+
+OBJS_C_64 =	$(BUILDDIR)/test-global.64.c.o \
+		$(BUILDDIR)/test-scoped.64.c.o
+
+OBJS_M_32 =	$(BUILDDIR)/test-global.32.m.o \
+		$(BUILDDIR)/test-scoped.32.m.o
+
+OBJS_M_64 =	$(BUILDDIR)/test-global.64.m.o \
+		$(BUILDDIR)/test-scoped.64.m.o
+
+BINS =		$(BUILDDIR)/test-merge-reduction-32c.so.1 \
+		$(BUILDDIR)/test-merge-reduction-32m.so.1 \
+		$(BUILDDIR)/test-merge-reduction-64c.so.1 \
+		$(BUILDDIR)/test-merge-reduction-64m.so.1 \
+
+CFLAGS = -fPIC
+LDFLAGS = -shared -Wl,-Mmapfile-vers -Wl,-ztext -Wl,-zdefs \
+	  -htest-merge-reduction.so.1
+
+build: $(BINS)
+
+$(BUILDDIR)/%.32.c.o: %.c
+	$(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.64.c.o: %.c
+	$(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.32.m.o: %.c
+	$(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+	$(CTFCONVERT) $@
+
+$(BUILDDIR)/%.64.m.o: %.c
+	$(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+	$(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-32c.so.1: $(OBJS_C_32)
+	$(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_32)
+	$(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-64c.so.1: $(OBJS_C_64)
+	$(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_64)
+	$(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-32m.so.1: $(OBJS_M_32)
+	$(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_32)
+	$(CTFMERGE) -t -o $@ $(OBJS_M_32)
+
+$(BUILDDIR)/test-merge-reduction-64m.so.1: $(OBJS_M_64)
+	$(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_64)
+	$(CTFMERGE) -t -o $@ $(OBJS_M_64)
+
+run-test:
+	$(CHECK32) $(BUILDDIR)/test-merge-reduction-32c.so.1
+	$(CHECK64) $(BUILDDIR)/test-merge-reduction-64c.so.1
+	$(CHECK32) $(BUILDDIR)/test-merge-reduction-32m.so.1
+	$(CHECK64) $(BUILDDIR)/test-merge-reduction-64m.so.1
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,37 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION CTFTEST {
+    global:
+	global;
+    local:
+	*;
+};
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,25 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+
+#include <stdlib.h>
+
+extern int scoped(uint32_t);
+
+int
+global(void)
+{
+	return (scoped(arc4random()));
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,29 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+
+int data;
+
+int
+scoped(uint32_t a)
+{
+	if (a >= INT32_MAX) {
+		data = a - INT32_MAX;
+	}
+
+	return (data);
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST =		test-merge-static
+
+OBJS_C_32 =	$(BUILDDIR)/test-a.32.c.o \
+		$(BUILDDIR)/test-b.32.c.o \
+		$(BUILDDIR)/test-c.32.c.o \
+		$(BUILDDIR)/test-d.32.c.o \
+		$(BUILDDIR)/test-main.32.c.o
+
+OBJS_C_64 =	$(BUILDDIR)/test-a.64.c.o \
+		$(BUILDDIR)/test-b.64.c.o \
+		$(BUILDDIR)/test-c.64.c.o \
+		$(BUILDDIR)/test-d.64.c.o \
+		$(BUILDDIR)/test-main.64.c.o
+
+OBJS_M_32 =	$(BUILDDIR)/test-a.32.m.o \
+		$(BUILDDIR)/test-b.32.m.o \
+		$(BUILDDIR)/test-c.32.m.o \
+		$(BUILDDIR)/test-d.32.m.o \
+		$(BUILDDIR)/test-main.32.m.o
+
+OBJS_M_64 =	$(BUILDDIR)/test-a.64.m.o \
+		$(BUILDDIR)/test-b.64.m.o \
+		$(BUILDDIR)/test-c.64.m.o \
+		$(BUILDDIR)/test-d.64.m.o \
+		$(BUILDDIR)/test-main.64.m.o
+
+include		../Makefile.ctftest.com
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,24 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint8_t global;
+
+static uint8_t
+mumble(uint8_t a)
+{
+	return (a);
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,24 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint16_t global;
+
+static uint16_t
+mumble(uint16_t a)
+{
+	return (a);
+}
--- /dev/null	Tue Apr 23 05:35:52 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c	Tue Apr 23 05:35:52 2019
@@ -0,0 +1,24 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint32_t global;
+
+static uint32_t
+mumble(uint32_t a)
+{
+	return (a);
+}
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,24 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint64_t global;
+
+static uint64_t
+mumble(uint64_t a)
+{
+	return (a);
+}
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,28 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+int global;
+
+int
+mumble(int a)
+{
+	return (a);
+}
+
+int
+main(void)
+{
+	return (0);
+}
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.c.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST =		test-merge-weak
+
+OBJS_C_32 =	$(BUILDDIR)/test-merge-weak.32.c.o
+OBJS_C_64 =	$(BUILDDIR)/test-merge-weak.64.c.o
+OBJS_M_32 =	$(BUILDDIR)/test-merge-weak.32.m.o
+OBJS_M_64 =	$(BUILDDIR)/test-merge-weak.64.m.o
+
+include ../Makefile.ctftest.com
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,33 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <stdlib.h>
+
+#pragma weak mumble = _mumble
+#pragma weak foo = _foo
+
+int _foo = 5;
+
+int
+_mumble(void)
+{
+	return ((int)arc4random());
+}
+
+int
+main(void)
+{
+	return (mumble());
+};
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-reference.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,44 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Test the encoding of references to another type. Specifically the references
+ * that we generally care about are things like:
+ *
+ * o pointers
+ * o typedefs
+ * o const
+ * o volatile
+ * o restrict
+ */
+
+int a;
+typedef int test_int_t;
+test_int_t aa;
+const short b;
+volatile float c;
+
+int *d;
+int **dd;
+int ***ddd;
+test_int_t *e;
+const test_int_t *ce;
+volatile test_int_t *ve;
+volatile const test_int_t *cve;
+int *const *f;
+const char *const g;
+
+typedef int *const * foo_t;
+const volatile foo_t *cvh;
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-sou.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,246 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <complex.h>
+
+/*
+ * Test various structure and union constructs, including various things that
+ * have caused regressions in the past.
+ */
+
+/*
+ * Basic, simple struct.
+ */
+struct foo {
+	int a;
+	float b;
+	const char *c;
+};
+
+struct foo foo;
+
+/*
+ * Self-referential structs
+ */
+struct node {
+	struct node *prev;
+	struct node *next;
+};
+
+typedef struct nlist {
+	size_t size;
+	size_t off;
+	struct node head;
+} nlist_t;
+
+nlist_t head;
+
+/*
+ * Struct that has a forward declaration.
+ */
+typedef struct forward forward_t;
+struct forward {
+	void *past;
+	void *present;
+	void *future;
+};
+
+const forward_t forward;
+
+/*
+ * Here, we have a pair of structures that basically round up to different
+ * sizes. As in, the size of the structure is somewhat compiler dependent.
+ */
+struct round_up {
+	uint8_t triforce;
+	uint32_t link;
+	uint8_t zelda;
+	uint8_t ganon;
+};
+
+#pragma pack(1)
+struct fixed_up {
+	uint8_t triforce;
+	uint32_t link;
+	uint8_t zelda;
+	uint8_t ganon;
+};
+#pragma pack()
+
+struct round_up oot;
+struct fixed_up botw;
+
+/*
+ * Various GNU and c99 style arrays
+ */
+enum material {
+	COPPER,
+	IRON,
+	STEEL,
+	ADAMANTIUM,
+	MYTHRIL,
+	ORIHALCUM
+};
+
+struct component {
+	enum material m;
+	uint64_t grade;
+	uint64_t count;
+	const char *locations[4];
+};
+
+struct mysterious_barrel {
+	const char *name;
+	size_t capacity;
+	struct component optional[];
+};
+
+struct dusk_barrel {
+	const char *name;
+	size_t opacity;
+	struct component optional[0];
+};
+
+struct mysterious_barrel sophie;
+struct dusk_barrel ayesha;
+
+/*
+ * Various bitfield forms.
+ */
+
+/*
+ * Variant of the Intel system_desc.
+ */
+struct stats {
+	uint64_t hp:16;
+	uint64_t mp:16;
+	uint64_t str:8;
+	uint64_t dex:4;
+	uint64_t con:1;
+	uint64_t inte:2;
+	uint64_t wis:1;
+	uint64_t cha:4;
+	uint64_t sanity:1;
+	uint64_t attack:2;
+	uint64_t mattack:1;
+	uint64_t defense:8;
+	uint64_t mdefense:32;
+	uint64_t evasion:8;
+	uint64_t crit:5;
+	uint64_t luck:19;
+};
+
+struct stats stats;
+
+/*
+ * More odd length structures due to bitfields
+ */
+struct fellowship {
+	uint16_t frodo:1;
+	uint16_t sam:1;
+	uint16_t merry:1;
+	uint16_t pippin:1;
+	uint16_t aragorn:1;
+	uint16_t boromir:1;
+	uint16_t legolas:1;
+	uint16_t gimli:1;
+	uint16_t gandalf:1;
+};
+
+struct fellowship ring;
+
+struct rings {
+	uint32_t elves:3;
+	uint32_t dwarves:7;
+	uint32_t men:9;
+	uint8_t one;
+	uint8_t silmarils[3];
+};
+
+struct rings rings;
+
+/*
+ * Regression, we didn't handle receiving a negative offset from DWARF with
+ * this.
+ */
+#pragma pack(1)
+struct csts {
+	unsigned int rdy:7;
+	unsigned int csts:32;
+};
+
+struct csts nvme;
+#pragma pack()
+
+/*
+ * Onto unions
+ */
+union jrpg {
+	int ff;
+	double atelier[4];
+	const char *tales;
+	int (*chrono)(void);
+	struct rings xeno;
+};
+
+union jrpg games;
+
+#pragma pack(1)
+struct android {
+	uint32_t _2b:16;
+	uint32_t _9s:16;
+};
+
+union nier {
+	uint32_t automata;
+	struct android android;
+};
+#pragma pack()
+
+union nier nier;
+
+union kh {
+	int sora:3;
+	char riku:7;
+	double kairi;
+	complex double namine;
+};
+
+union kh kh;
+
+/*
+ * Anonymous union in a struct, GNU extension / C11
+ */
+
+struct trigger {
+	uint8_t chrono;
+	uint8_t cross;
+	union {
+		void *lavos;
+		int *crono;
+		uint64_t schala[3];
+	};
+};
+
+struct trigger ct;
+
+/*
+ * This is an array/union combo that failed conversion previously.
+ */
+static const union regress {
+	unsigned int i[3];
+	long double e;
+} regress[9];
--- /dev/null	Tue Apr 23 05:35:53 2019
+++ new/usr/src/test/util-tests/tests/ctf/test-weak.c	Tue Apr 23 05:35:53 2019
@@ -0,0 +1,25 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#pragma weak  _strong = strong
+#pragma weak _mumble = mumble
+
+int strong = 3;
+
+int
+mumble(void)
+{
+	return (42);
+}
