summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2018-09-09 19:56:37 +0000
committerRobert Mustacchi <rm@joyent.com>2019-03-21 17:15:41 +0000
commitd8fc647be2c6caf34bbf0e0b6990d1d798f0c108 (patch)
tree3ab49b134f07eaf55721406851ffedc2a3107d26
parent554f80e97289e58da5f8cd5d6334edd78d1f0461 (diff)
downloadillumos-joyent-d8fc647be2c6caf34bbf0e0b6990d1d798f0c108.tar.gz
OS-7386 Want primordial CTF test suite
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: John Levon <john.levon@joyent.com> Approved by: John Levon <john.levon@joyent.com>
-rw-r--r--usr/src/test/util-tests/tests/Makefile4
-rw-r--r--usr/src/test/util-tests/tests/ctf/Makefile149
-rw-r--r--usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com92
-rw-r--r--usr/src/test/util-tests/tests/ctf/README54
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-array.c116
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-common.c802
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-common.h141
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-enum.c143
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-float.c80
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-forward.c130
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-function.c88
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-int.c88
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-dedup.c82
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-forward.c132
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-reduction.c72
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-static.c290
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-weak.c70
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-reference.c197
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-sou.c405
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-weak.c70
-rw-r--r--usr/src/test/util-tests/tests/ctf/ctftest.ksh257
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-array.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-enum.c74
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-float.c28
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-forward.c34
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-function.c71
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-int.c34
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest39
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c33
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest30
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c32
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest92
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers37
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c25
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest42
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c28
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest23
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c33
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-reference.c44
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-sou.c246
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-weak.c25
50 files changed, 4694 insertions, 2 deletions
diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile
index 936f7c920a..cb2d3028da 100644
--- a/usr/src/test/util-tests/tests/Makefile
+++ b/usr/src/test/util-tests/tests/Makefile
@@ -14,11 +14,11 @@
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
# Copyright 2017 Jason King
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4
SUBDIRS += demangle mergeq workq chown
-SUBDIRS += bunyan awk smbios libjedec
+SUBDIRS += bunyan awk smbios libjedec ctf
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/util-tests/tests/ctf/Makefile b/usr/src/test/util-tests/tests/ctf/Makefile
new file mode 100644
index 0000000000..007d6c1c2f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/Makefile
@@ -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)
diff --git a/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com
new file mode 100644
index 0000000000..f3f754dbf9
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com
@@ -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)
diff --git a/usr/src/test/util-tests/tests/ctf/README b/usr/src/test/util-tests/tests/ctf/README
new file mode 100644
index 0000000000..0f9aeb9e3a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/README
@@ -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.
diff --git a/usr/src/test/util-tests/tests/ctf/check-array.c b/usr/src/test/util-tests/tests/ctf/check-array.c
new file mode 100644
index 0000000000..c694726a3f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-array.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-common.c b/usr/src/test/util-tests/tests/ctf/check-common.c
new file mode 100644
index 0000000000..8aa5449cac
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-common.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-common.h b/usr/src/test/util-tests/tests/ctf/check-common.h
new file mode 100644
index 0000000000..f78fb2f00c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-common.h
@@ -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 */
diff --git a/usr/src/test/util-tests/tests/ctf/check-enum.c b/usr/src/test/util-tests/tests/ctf/check-enum.c
new file mode 100644
index 0000000000..79d6f795ed
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-enum.c
@@ -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);
+
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-float.c b/usr/src/test/util-tests/tests/ctf/check-float.c
new file mode 100644
index 0000000000..948c467446
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-float.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-forward.c b/usr/src/test/util-tests/tests/ctf/check-forward.c
new file mode 100644
index 0000000000..2b00209fce
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-forward.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-function.c b/usr/src/test/util-tests/tests/ctf/check-function.c
new file mode 100644
index 0000000000..fdb60ce290
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-function.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-int.c b/usr/src/test/util-tests/tests/ctf/check-int.c
new file mode 100644
index 0000000000..ac34f27e85
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-int.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c
new file mode 100644
index 0000000000..06db2ad1f0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-forward.c b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c
new file mode 100644
index 0000000000..e396beb133
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c
new file mode 100644
index 0000000000..86b688bc0b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-static.c b/usr/src/test/util-tests/tests/ctf/check-merge-static.c
new file mode 100644
index 0000000000..3ca40eb5aa
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-static.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-weak.c b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c
new file mode 100644
index 0000000000..da6d37def8
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-reference.c b/usr/src/test/util-tests/tests/ctf/check-reference.c
new file mode 100644
index 0000000000..05c0469c15
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-reference.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-sou.c b/usr/src/test/util-tests/tests/ctf/check-sou.c
new file mode 100644
index 0000000000..32bcc20b6d
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-sou.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-weak.c b/usr/src/test/util-tests/tests/ctf/check-weak.c
new file mode 100644
index 0000000000..13e69e87de
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-weak.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/ctftest.ksh b/usr/src/test/util-tests/tests/ctf/ctftest.ksh
new file mode 100644
index 0000000000..62f5cc5dd7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/ctftest.ksh
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-array.c b/usr/src/test/util-tests/tests/ctf/test-array.c
new file mode 100644
index 0000000000..9c15771caf
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-array.c
@@ -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];
diff --git a/usr/src/test/util-tests/tests/ctf/test-enum.c b/usr/src/test/util-tests/tests/ctf/test-enum.c
new file mode 100644
index 0000000000..f6bfbfccb0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-enum.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-float.c b/usr/src/test/util-tests/tests/ctf/test-float.c
new file mode 100644
index 0000000000..ddec7a7167
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-float.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-forward.c b/usr/src/test/util-tests/tests/ctf/test-forward.c
new file mode 100644
index 0000000000..4aa0fa2486
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-forward.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-function.c b/usr/src/test/util-tests/tests/ctf/test-function.c
new file mode 100644
index 0000000000..af999b5c78
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-function.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-int.c b/usr/src/test/util-tests/tests/ctf/test-int.c
new file mode 100644
index 0000000000..d7cca69956
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-int.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest
new file mode 100644
index 0000000000..e19e461a1a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c
new file mode 100644
index 0000000000..7119026d83
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c
new file mode 100644
index 0000000000..5d3da5b082
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c
new file mode 100644
index 0000000000..81ed216743
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c
new file mode 100644
index 0000000000..798457bd05
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest
new file mode 100644
index 0000000000..270264370e
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c
new file mode 100644
index 0000000000..c4319032a0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c
@@ -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--;
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c
new file mode 100644
index 0000000000..ab986d920b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest
new file mode 100644
index 0000000000..3cf1fd647f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers
new file mode 100644
index 0000000000..c1e47627ad
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers
@@ -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:
+ *;
+};
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c
new file mode 100644
index 0000000000..09f2914c12
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c
@@ -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()));
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c
new file mode 100644
index 0000000000..a30fe7a7b7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest
new file mode 100644
index 0000000000..7d5a875bce
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c
new file mode 100644
index 0000000000..749e9fbd22
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c
new file mode 100644
index 0000000000..7fca620966
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c
new file mode 100644
index 0000000000..2627cec22c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c
new file mode 100644
index 0000000000..516b6c2fa2
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c
new file mode 100644
index 0000000000..e645302f8b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c
@@ -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);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest
new file mode 100644
index 0000000000..35b3ecf69c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest
@@ -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
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c
new file mode 100644
index 0000000000..7d47c02fea
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c
@@ -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());
+};
diff --git a/usr/src/test/util-tests/tests/ctf/test-reference.c b/usr/src/test/util-tests/tests/ctf/test-reference.c
new file mode 100644
index 0000000000..b738a2e429
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-reference.c
@@ -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;
diff --git a/usr/src/test/util-tests/tests/ctf/test-sou.c b/usr/src/test/util-tests/tests/ctf/test-sou.c
new file mode 100644
index 0000000000..8194248df5
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-sou.c
@@ -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];
diff --git a/usr/src/test/util-tests/tests/ctf/test-weak.c b/usr/src/test/util-tests/tests/ctf/test-weak.c
new file mode 100644
index 0000000000..d07981f369
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-weak.c
@@ -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);
+}