--- /dev/null	Wed Sep 25 20:52:10 2019
+++ new/usr/src/test/util-tests/tests/demangle/main.c	Wed Sep 25 20:52:10 2019
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/sysmacros.h>
+#include <demangle-sys.h>
+#include "demangle_test.h"
+
+#define	ALL_TESTS ULONG_MAX
+
+SET_DECLARE(demangle_tests, demtest_group_t);
+SET_DECLARE(demangle_mtests, demtest_mgroup_t);
+
+static boolean_t
+check_failure(size_t i, demtest_case_t *tc, const char *dem, boolean_t res)
+{
+	int savederr = errno;
+
+	if (dem == NULL && (savederr == EINVAL || savederr == ENAMETOOLONG))
+		return (B_TRUE);
+
+	if (res)
+		(void) printf("FAILURE\n");
+
+	if (dem != NULL) {
+		(void) printf("  [%zu] Successfully demanged an invalid "
+		    "name\n", i);
+		(void) printf("         Name: '%s'\n", tc->dtc_mangled);
+		(void) printf("    Demangled: '%s'\n", dem);
+		return (B_FALSE);
+	}
+
+	(void) printf("  [%zu] demangle() returned an unexpected error\n", i);
+	(void) printf("     Name: '%s'\n", tc->dtc_mangled);
+	(void) printf("    Errno: %d %s\n", savederr, strerror(savederr));
+	return (B_FALSE);
+}
+
+static boolean_t
+check_success(size_t i, demtest_case_t *tc, const char *dem, boolean_t res)
+{
+	if (dem != NULL && strcmp(tc->dtc_demangled, dem) == 0)
+		return (B_TRUE);
+
+	if (res)
+		(void) printf("FAILURE\n");
+
+	if (dem == NULL) {
+		(void) printf("  [%zu] Failed to demangle '%s'\n", i,
+		    tc->dtc_mangled);
+		return (B_FALSE);
+	}
+
+	(void) printf("  [%zu] Demangled results do not match.\n", i);
+	(void) printf("       Mangled: %s\n", tc->dtc_mangled);
+	(void) printf("      Expected: %s\n", tc->dtc_demangled);
+	(void) printf("        Actual: %s\n", dem);
+	return (B_FALSE);
+}
+
+static boolean_t
+check_msuccess(size_t tcnum, demtest_mcase_t *tm, const char *dem,
+    boolean_t res)
+{
+	if (dem != NULL) {
+		for (size_t i = 0; tm->dtmc_demangled[i] != NULL; i++) {
+			if (strcmp(tm->dtmc_demangled[i], dem) == 0)
+				return (B_TRUE);
+		}
+	}
+
+	if (res)
+		(void) printf("FAILURE\n");
+
+	if (dem == NULL) {
+		(void) printf("  [%zu] Failed to demangle '%s'\n", tcnum,
+		    tm->dtmc_mangled);
+		return (B_FALSE);
+	}
+
+	(void) printf("  [%zu] Demangled results do not match.\n", tcnum);
+	(void) printf("       Mangled: %s\n", tm->dtmc_mangled);
+	(void) printf("      Expected: ");
+
+	for (size_t i = 0; tm->dtmc_demangled[i] != NULL; i++) {
+		if (i > 0) {
+			int indent = sizeof ("      Expected: ") - 1;
+			(void) printf("%*s", indent, "");
+		}
+
+		(void) printf("%s%s", tm->dtmc_demangled[i]);
+
+		if (tm->dtmc_demangled[i + 1] != NULL)
+			(void) printf(" or");
+
+		(void) fputc('\n', stdout);
+	}
+
+	(void) printf("        Actual: %s\n", dem);
+	return (B_FALSE);
+}
+
+static boolean_t
+run_test(demtest_group_t *test, unsigned long testnum)
+{
+	boolean_t res = B_TRUE;
+
+	(void) printf("Test %s: ", test->dtg_name);
+
+	for (size_t i = 0; test->dtg_tests[i].dtc_mangled != NULL; i++) {
+		char *dem;
+
+		if (testnum != ALL_TESTS && i != testnum)
+			continue;
+
+		dem = sysdemangle(test->dtg_tests[i].dtc_mangled,
+		    test->dtg_lang, NULL);
+
+		if (test->dtg_tests[i].dtc_demangled == NULL)
+			res &= check_failure(i, &test->dtg_tests[i], dem, res);
+		else
+			res &= check_success(i, &test->dtg_tests[i], dem, res);
+
+		free(dem);
+	}
+
+	if (res)
+		(void) printf("SUCCESS\n");
+
+	return (res);
+}
+
+static boolean_t
+run_mtest(demtest_mgroup_t *test, unsigned long testnum)
+{
+	boolean_t res = B_TRUE;
+
+	(void) printf("Test %s: ", test->dtmg_name);
+
+	for (size_t i = 0; test->dtmg_tests[i] != NULL; i++) {
+		char *dem;
+
+		if (testnum != ALL_TESTS && i != testnum)
+			continue;
+
+		dem = sysdemangle(test->dtmg_tests[i]->dtmc_mangled,
+		    test->dtmg_lang, NULL);
+		res &= check_msuccess(i, test->dtmg_tests[i], dem, res);
+		free(dem);
+	}
+
+	if (res)
+		(void) printf("SUCCESS\n");
+
+	return (res);
+}
+
+static void
+list_groups(void)
+{
+	size_t n;
+
+	n = SET_COUNT(demangle_tests);
+
+	if (n > 0)
+		(void) printf("Demangle tests:\n");
+
+	for (size_t i = 0; i < n; i++) {
+		demtest_group_t *grp = SET_ITEM(demangle_tests, n - i - 1);
+		size_t ntest = 0;
+
+		for (size_t j = 0; grp->dtg_tests[j].dtc_mangled != NULL; j++)
+			ntest++;
+
+		(void) printf("\t%s (%zu tests)\n", grp->dtg_name, ntest);
+	}
+
+
+	if (n > 0)
+		(void) fputc('\n', stdout);
+
+	n = SET_COUNT(demangle_mtests);
+
+	if (n > 0)
+		(void) printf("Demangle mtests:\n");
+
+	for (size_t i = 0; i < n; i++) {
+		demtest_mgroup_t *mgrp = SET_ITEM(demangle_mtests, n - i - 1);
+		size_t ntest = 0;
+
+		for (size_t j = 0; mgrp->dtmg_tests[j] != NULL; j++)
+			ntest++;
+
+		(void) printf("\t%s (%zu tests)\n", mgrp->dtmg_name, ntest);
+	}
+
+}
+
+__NORETURN static void
+usage(const char *name)
+{
+	(void) fprintf(stderr,
+	    "%s: [-hl] { [-g group] | [-m mgroup] } [-t test]\n", name);
+	(void) fprintf(stderr, "    -h        Display this help\n");
+	(void) fprintf(stderr, "    -l        List test groups\n");
+	(void) fprintf(stderr, "    -g group  Only run the specified group\n");
+	(void) fprintf(stderr, "    -m mgroup Only run the specified mgroup\n");
+	(void) fprintf(stderr, "    -t test  Only run the specified test "
+	    "(requires -g or -m)\n");
+	exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char **argv)
+{
+	const char *group = NULL;
+	const char *mgroup = NULL;
+	unsigned long testnum = ALL_TESTS;
+	size_t i, n;
+	int c;
+	boolean_t ok = B_TRUE;
+	boolean_t found;
+
+	while ((c = getopt(argc, argv, "hlg:m:t:")) > 0) {
+		switch (c) {
+		case 'h':
+			usage(argv[0]);
+		case 'l':
+			list_groups();
+			return (EXIT_SUCCESS);
+		case 'g':
+			if (mgroup != NULL) {
+				(void) fprintf(stderr, "-g and -m options are "
+				    "mutually exclusive\n");
+				return (EXIT_FAILURE);
+			}
+
+			group = optarg;
+			break;
+		case 'm':
+			if (group != NULL) {
+				(void) fprintf(stderr, "-g and -m options are "
+				    "mutually exclusive\n");
+				return (EXIT_FAILURE);
+			}
+
+			mgroup = optarg;
+			break;
+		case 't':
+			errno = 0;
+			testnum = strtoul(optarg, NULL, 10);
+			if (errno != 0) {
+				(void) fprintf(stderr,
+				    "Unable to parse '%s' as a number: %s\n",
+				    optarg, strerror(errno));
+				return (EXIT_FAILURE);
+			}
+			break;
+		case '?':
+			(void) fprintf(stderr, "Unknown option -%c\n", optopt);
+			usage(argv[0]);
+		}
+	}
+
+	if (testnum != ALL_TESTS && group == NULL && mgroup == NULL) {
+		(void) fprintf(stderr, "Error: -t requires -g or -m option\n");
+		return (EXIT_FAILURE);
+	}
+
+	/*
+	 * A downside to using linker sets is that the items get added in
+	 * the reverse order in which they're declared. To match the
+	 * declaration order, we iterate in reverse.
+	 */
+	n = SET_COUNT(demangle_tests);
+	found = (group == NULL) ? B_TRUE : B_FALSE;
+	for (i = 0; i < n; i++) {
+		demtest_group_t *grp = SET_ITEM(demangle_tests, n - i - 1);
+
+		if (group == NULL) {
+			ok &= run_test(grp, testnum);
+		} else if (strcmp(grp->dtg_name, group) == 0) {
+			found = B_TRUE;
+			ok &= run_test(grp, testnum);
+			break;
+		}
+	}
+	if (!found) {
+		(void) fprintf(stderr, "Test group %s does not exist\n", group);
+		return (EXIT_FAILURE);
+	}
+
+	n = SET_COUNT(demangle_mtests);
+	found = (mgroup == NULL) ? B_TRUE : B_FALSE;
+	for (i = 0; i < n; i++) {
+		demtest_mgroup_t *mgrp = SET_ITEM(demangle_mtests, n - i - 1);
+
+		if (mgroup == NULL) {
+			ok &= run_mtest(mgrp, testnum);
+		} else if (strcmp(mgrp->dtmg_name, mgroup) == 0) {
+			found = B_TRUE;
+			ok &= run_mtest(mgrp, testnum);
+			break;
+		}
+	}
+	if (!found) {
+		(void) fprintf(stderr,
+		    "Test mgroup %s does not exist\n", group);
+		return (EXIT_FAILURE);
+	}
+
+	return (ok ? 0 : 1);
+}
+
+const char *
+_umem_debug_init(void)
+{
+	return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+	return ("fail,contents");
+}
