--- old/usr/src/cmd/Makefile	Mon Feb 17 13:23:04 2020
+++ new/usr/src/cmd/Makefile	Mon Feb 17 13:23:04 2020
@@ -21,7 +21,7 @@
 
 #
 # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2019, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 # Copyright (c) 2012, 2015 by Delphix. All rights reserved.
 # Copyright (c) 2013 DEY Storage Systems, Inc. All rights reserved.
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
@@ -118,6 +118,7 @@
 	date		\
 	dc		\
 	dd		\
+	demangle	\
 	deroff		\
 	devfsadm	\
 	syseventd	\
--- /dev/null	Mon Feb 17 13:23:04 2020
+++ new/usr/src/cmd/demangle/Makefile	Mon Feb 17 13:23:04 2020
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+PROG=		demangle
+OBJS=		demangle.o
+SRCS=		$(OBJS:%.o=%.c)
+
+include		$(SRC)/cmd/Makefile.cmd
+include		$(SRC)/cmd/Makefile.ctf
+
+CSTD=	$(CSTD_GNU99)
+
+LDLIBS +=	-ldemangle-sys -lcustr
+
+.KEEP_STATE:
+
+all:		$(PROG)
+
+$(PROG):	$(OBJS)
+		$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+		$(POST_PROCESS)
+
+clean:
+		$(RM) $(OBJS)
+
+install:	all $(ROOTPROG)
+
+include		$(SRC)/cmd/Makefile.targ
--- /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"));
+}
--- old/usr/src/lib/libdemangle/common/demangle-sys.h	Mon Feb 17 13:23:05 2020
+++ new/usr/src/lib/libdemangle/common/demangle-sys.h	Mon Feb 17 13:23:05 2020
@@ -11,7 +11,7 @@
 
 /*
  * Copyright 2017 Jason King
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #ifndef _DEMANGLE_SYS_H
@@ -34,6 +34,7 @@
 	void (*free)(void *, size_t);
 } sysdem_ops_t;
 
+boolean_t sysdem_parse_lang(const char *, sysdem_lang_t *);
 char *sysdemangle(const char *, sysdem_lang_t, sysdem_ops_t *);
 
 #ifdef __cplusplus
--- old/usr/src/lib/libdemangle/common/demangle.c	Mon Feb 17 13:23:05 2020
+++ new/usr/src/lib/libdemangle/common/demangle.c	Mon Feb 17 13:23:05 2020
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <sys/ctype.h>
 #include <sys/debug.h>
+#include <sys/sysmacros.h>
 #include <stdarg.h>
 #include "demangle-sys.h"
 #include "demangle_int.h"
@@ -31,21 +32,42 @@
 volatile boolean_t demangle_debug;
 FILE *debugf = stderr;
 
+static struct {
+	const char	*str;
+	sysdem_lang_t	lang;
+} lang_tbl[] = {
+	{ "auto", SYSDEM_LANG_AUTO },
+	{ "c++", SYSDEM_LANG_CPP },
+	{ "rust", SYSDEM_LANG_RUST },
+};
+
 static const char *
 langstr(sysdem_lang_t lang)
 {
-	switch (lang) {
-	case SYSDEM_LANG_AUTO:
-		return ("auto");
-	case SYSDEM_LANG_CPP:
-		return ("c++");
-	case SYSDEM_LANG_RUST:
-		return ("rust");
-	default:
-		return ("invalid");
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(lang_tbl); i++) {
+		if (lang == lang_tbl[i].lang)
+			return (lang_tbl[i].str);
 	}
+	return ("invalid");
 }
 
+boolean_t
+sysdem_parse_lang(const char *str, sysdem_lang_t *langp)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(lang_tbl); i++) {
+		if (strcmp(str, lang_tbl[i].str) == 0) {
+			*langp = lang_tbl[i].lang;
+			return (B_TRUE);
+		}
+	}
+
+	return (B_FALSE);
+}
+
 static sysdem_lang_t
 detect_lang(const char *str, size_t n)
 {
--- old/usr/src/lib/libdemangle/common/mapfile-vers	Mon Feb 17 13:23:06 2020
+++ new/usr/src/lib/libdemangle/common/mapfile-vers	Mon Feb 17 13:23:06 2020
@@ -11,6 +11,7 @@
 
 #
 # Copyright 2017 Jason King
+# Copyright 2019 Joyent, Inc.
 #
 
 #
@@ -30,6 +31,7 @@
 
 SYMBOL_VERSION ILLUMOSprivate {
     global:
+	sysdem_parse_lang;
 	sysdemangle;
     local:
         *;
--- old/usr/src/man/man1/Makefile	Mon Feb 17 13:23:06 2020
+++ new/usr/src/man/man1/Makefile	Mon Feb 17 13:23:06 2020
@@ -14,6 +14,7 @@
 # Copyright 2018 Nexenta Systems, Inc.
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 # Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2020 Joyent, Inc.
 #
 
 include		$(SRC)/Makefile.master
@@ -94,6 +95,7 @@
 		date.1				\
 		dc.1				\
 		deallocate.1			\
+		demangle.1			\
 		deroff.1			\
 		dhcpinfo.1			\
 		diff.1				\
--- /dev/null	Mon Feb 17 13:23:07 2020
+++ new/usr/src/man/man1/demangle.1	Mon Feb 17 13:23:07 2020
@@ -0,0 +1,114 @@
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" Copyright 2020 Joyent, Inc.
+.\"
+.Dd February 15, 2020
+.Dt DEMANGLE 1
+.Os
+.Sh NAME
+.Nm demangle
+.Nd demangle symbols
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl l
+.Ar lang
+.Oc
+.Op Ar symbol Ns ...
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to detect mangled symbols and transform them back into a
+more human friendly version of the symbol.
+.Pp
+Some languages allow the same identifier to refer to multiple things
+(functions, variables, etc\&.) where some additional context such as
+parameter types, return types, etc\&. are used to disambiguate between the
+symbols sharing the same name.
+When compiling such languages into an executable form, most binary formats
+do not allow for duplicate symbol names or provide a way to disambiguate
+between duplicate names.
+.Pp
+To solve this problem, many languages will use the additional context from
+the source code to transform the symbol name into a unique name.
+This process is called name mangling.
+While the resulting name is predictable, the mangled names are often difficult
+for humans to interpret.
+.Pp
+The
+.Nm
+utility can be invoked in one of two ways.
+In the first method,
+.Ar symbol
+is demangled and the result is written to standard out, one line per input
+.Ar symbol .
+If any input
+.Ar symbol
+cannot be demangled, the original value of
+.Ar symbol
+is output unchanged.
+In the second method,
+.Nm
+reads standard in, and whenever it encounters a potential symbol, it will
+attempt to replace the symbol in stdandard out with the demangled version.
+If the symbol cannot be demangled, it is output unchanged.
+.Sh OPTIONS
+.Bl -tag -width Fl
+.It Fl l Ar lang
+Treat all potential symbols as symbols from
+.Ar lang .
+By default,
+.Nm
+will attempt to detect the language and demangle symbols for all supported
+languages.
+Current supported values of
+.Ar lang
+are:
+.Bl -tag -width rust -offset indent
+.It c++
+The C++ mangling format defined by the Itanium ABI.
+While the mangling format was originally defined for the Itanium processor, g++
+and clang use this format for all their supported platforms (including x86 and
+SPARC).
+.It rust
+The legacy rust mangling format.
+.It auto
+Attempt to detect the language automatically (default).
+.El
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Sy Example 1
+Demangle symbols given as command line arguments.
+.Bd -literal
+% demangle '_ZGVN9__gnu_cxx16bitmap_allocatorIwE13_S_mem_blocksE'
+guard variable for __gnu_cxx::bitmap_allocator<wchar_t>::_S_mem_blocks
+%
+.Ed
+.Pp
+.Sy Example 2
+Demangle symbols from the output of another command.
+.Bd -literal
+% grep slice rust.c | head -1
+    T("__ZN4core5slice89_$LT$impl$u20$core..iter..traits..IntoIterator$u20$for$u20$$RF$$u27$a$u20$$u5b$T$u5d$$GT$9into_iter17h450e234d27262170E",
+% grep slice rust.c | head -1 | demangle
+    T("core::slice::<impl core::iter::traits::IntoIterator for &'a [T]>::into_iter::h450e234d27262170",
+%
+.Ed
+.Sh INTERFACE STABILITY
+The command line options are not stable.
+The output is uncommitted.
--- old/usr/src/pkg/manifests/developer-object-file.mf	Mon Feb 17 13:23:07 2020
+++ new/usr/src/pkg/manifests/developer-object-file.mf	Mon Feb 17 13:23:07 2020
@@ -22,6 +22,7 @@
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2020 Joyent, Inc.
 #
 
 set name=pkg.fmri value=pkg:/developer/object-file@$(PKGVERS)
@@ -53,6 +54,7 @@
 file path=usr/bin/$(ARCH64)/nm mode=0555
 file path=usr/bin/$(ARCH64)/size mode=0555
 file path=usr/bin/ar mode=0555
+file path=usr/bin/demangle mode=0555
 file path=usr/bin/dis mode=0555
 file path=usr/bin/dump mode=0555
 file path=usr/bin/elfdump mode=0555
@@ -95,6 +97,7 @@
 file path=usr/share/lib/ccs/nrform
 file path=usr/share/lib/ccs/yaccpar
 file path=usr/share/man/man1/ar.1
+file path=usr/share/man/man1/demangle.1
 file path=usr/share/man/man1/dis.1
 file path=usr/share/man/man1/dump.1
 file path=usr/share/man/man1/elfdump.1
