--- /dev/null	Mon Feb 17 13:23:04 2020
+++ new/usr/src/cmd/demangle/demangle.c	Mon Feb 17 13:23:04 2020
@@ -0,0 +1,206 @@
+/*
+ * 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 2020 Joyent, Inc.
+ */
+
+#include <ctype.h>
+#include <demangle-sys.h>
+#include <err.h>
+#include <errno.h>
+#include <libcustr.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define	_(x) gettext(x)
+
+locale_t c_locale;
+
+static void do_symbols(sysdem_lang_t, int, char * const *);
+static void do_input(sysdem_lang_t, FILE *restrict, FILE *restrict);
+static void demangle_custr(custr_t *, sysdem_lang_t, FILE *);
+static void appendc(custr_t *, char);
+
+static void
+usage(void)
+{
+	(void) fprintf(stderr, _("Usage: %s [-l lang] [sym...]\n"),
+	    getprogname());
+	exit(2);
+}
+
+int
+main(int argc, char * const *argv)
+{
+	sysdem_lang_t lang = SYSDEM_LANG_AUTO;
+	int c;
+
+	(void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN "SYS_TEST"
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+
+	/*
+	 * For detecting symbol boundaries, we want to use the C locale
+	 * definitions for use in isalnum_l().
+	 */
+	if ((c_locale = newlocale(LC_CTYPE_MASK, "C", NULL)) == NULL)
+		err(EXIT_FAILURE, _("failed to construct C locale"));
+
+	while ((c = getopt(argc, argv, "hl:")) != -1) {
+		switch (c) {
+		case 'l':
+			if (sysdem_parse_lang(optarg, &lang))
+				break;
+
+			errx(EXIT_FAILURE, _("Unsupported language '%s'\n"),
+			    optarg);
+		case 'h':
+		case '?':
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc > 0)
+		do_symbols(lang, argc, argv);
+	else
+		do_input(lang, stdin, stdout);
+
+	return (0);
+}
+
+static void
+do_symbols(sysdem_lang_t lang, int argc, char * const *argv)
+{
+	for (int i = 0; i < argc; i++) {
+		char *demangled = NULL;
+
+		demangled = sysdemangle(argv[i], lang, NULL);
+
+		if (demangled == NULL) {
+			/*
+			 * If we failed to demangle for any reason other than
+			 * 'not a mangled name' (EINVAL), we print the error.
+			 * For EINVAL, we just print the original value like
+			 * c++filt does.
+			 */
+			if (errno != EINVAL)
+				warnx(_("failed to demangle '%s'"), argv[i]);
+			else
+				(void) printf("%s\n", argv[i]);
+		} else {
+			(void) printf("%s\n", demangled);
+			free(demangled);
+		}
+	}
+}
+
+static void
+do_input(sysdem_lang_t lang, FILE *restrict in, FILE *restrict out)
+{
+	custr_t *word = NULL;
+	int c;
+	boolean_t in_symbol = B_FALSE;
+
+	if (custr_alloc(&word) != 0)
+		err(EXIT_FAILURE, _("failed to allocate memory"));
+
+	while ((c = fgetc(in)) != EOF) {
+		if (in_symbol) {
+			/*
+			 * All currently supported mangling formats only use
+			 * alphanumeric characters, '.', '_', or '$' in
+			 * mangled names. Once we've seen the potential start
+			 * of a symbol ('_'), we accumulate subsequent
+			 * charaters into 'word'. If we encounter a character
+			 * that is not a part of that set ([A-Za-z0-9._$]), we
+			 * treat it as a delimiter, we stop accumulating
+			 * characters into word, and we attempt to demangle the
+			 * accumulated string in 'word' by calling
+			 * demangle_custr().
+			 *
+			 * Similar utilities like c++filt behave in a similar
+			 * fashion when reading from stdin to allow for
+			 * demangling of symbols embedded in surrounding text.
+			 */
+			if (isalnum_l(c, c_locale) || c == '.' || c == '_' ||
+			    c == '$') {
+				appendc(word, c);
+				continue;
+			}
+
+			/*
+			 * Hit a symbol boundary, attempt to demangle what
+			 * we've accumulated in word and reset word.
+			 */
+			demangle_custr(word, lang, out);
+			in_symbol = B_FALSE;
+		}
+
+		if (c != '_') {
+			if (fputc(c, out) != c) {
+				err(EXIT_FAILURE,
+				    _("failed to write to output"));
+			}
+		} else {
+			in_symbol = B_TRUE;
+			appendc(word, c);
+		}
+	}
+
+	if (ferror(in))
+		err(EXIT_FAILURE, _("error reading input"));
+
+	/*
+	 * If we were accumulating characters for a symbol and hit EOF,
+	 * attempt to demangle what we accumulated.
+	 */
+	if (custr_len(word) > 0)
+		demangle_custr(word, lang, out);
+
+	custr_free(word);
+}
+
+/*
+ * Attempt to demangle the string in 'word' and write to out, otherwise
+ * write out the contents of word. In either case, 'word' is reset (contents
+ * cleared) prior to returning.
+ */
+static void
+demangle_custr(custr_t *word, sysdem_lang_t lang, FILE *out)
+{
+	char *demangled = NULL;
+
+	demangled = sysdemangle(custr_cstr(word), lang, NULL);
+
+	if (fprintf(out, "%s",
+	    (demangled != NULL) ? demangled : custr_cstr(word)) < 0) {
+		err(EXIT_FAILURE, _("failed to write to output"));
+	}
+
+	free(demangled);
+	custr_reset(word);
+}
+
+static void
+appendc(custr_t *cus, char c)
+{
+	if (custr_appendc(cus, c) == 0)
+		return;
+	err(EXIT_FAILURE, _("failed to save character from input"));
+}
