summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2019-11-09 01:17:22 -0600
committerJason King <jason.king@joyent.com>2020-03-28 13:09:21 -0500
commitd52aae2365749461c362fde5a4c1a26a620cfbd3 (patch)
tree25c0592411bdc4c433f1122675382cb68cd345cc
parenta61ed2ce7a86a4d6428f2a83eb4739fae945447e (diff)
downloadillumos-joyent-d52aae2365749461c362fde5a4c1a26a620cfbd3.tar.gz
12310 Add demangle(1) command
Reviewed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/cmd/Makefile3
-rw-r--r--usr/src/cmd/demangle/Makefile40
-rw-r--r--usr/src/cmd/demangle/demangle.c211
-rw-r--r--usr/src/lib/libdemangle/common/demangle-sys.h3
-rw-r--r--usr/src/lib/libdemangle/common/demangle.c40
-rw-r--r--usr/src/lib/libdemangle/common/mapfile-vers2
-rw-r--r--usr/src/man/man1/Makefile2
-rw-r--r--usr/src/man/man1/demangle.1119
-rw-r--r--usr/src/pkg/manifests/developer-object-file.mf3
9 files changed, 412 insertions, 11 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index cbfe2700e6..a4a744fe95 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -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>
@@ -119,6 +119,7 @@ COMMON_SUBDIRS= \
date \
dc \
dd \
+ demangle \
deroff \
devfsadm \
syseventd \
diff --git a/usr/src/cmd/demangle/Makefile b/usr/src/cmd/demangle/Makefile
new file mode 100644
index 0000000000..8366ac85f3
--- /dev/null
+++ b/usr/src/cmd/demangle/Makefile
@@ -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
diff --git a/usr/src/cmd/demangle/demangle.c b/usr/src/cmd/demangle/demangle.c
new file mode 100644
index 0000000000..33a68edc9e
--- /dev/null
+++ b/usr/src/cmd/demangle/demangle.c
@@ -0,0 +1,211 @@
+/*
+ * 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 int do_symbols(sysdem_lang_t, int, char * const *);
+static int do_input(sysdem_lang_t, FILE *restrict, FILE *restrict);
+static int do_demangle(const char *, sysdem_lang_t, FILE *);
+static void appendc(custr_t *, char);
+static void xputc(int, FILE *);
+
+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;
+ int ret;
+
+ (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)
+ ret = do_symbols(lang, argc, argv);
+ else
+ ret = do_input(lang, stdin, stdout);
+
+ return ((ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int
+do_symbols(sysdem_lang_t lang, int argc, char * const *argv)
+{
+ int ret = 0;
+
+ for (int i = 0; i < argc; i++) {
+ if (do_demangle(argv[i], lang, stdout) < 0)
+ ret = -1;
+ else
+ xputc('\n', stdout);
+ }
+
+ return (ret);
+}
+
+static int
+do_input(sysdem_lang_t lang, FILE *restrict in, FILE *restrict out)
+{
+ custr_t *word = NULL;
+ int c;
+ int ret = 0;
+ 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.
+ */
+ if (do_demangle(custr_cstr(word), lang, out) < 0)
+ ret = -1;
+
+ custr_reset(word);
+ in_symbol = B_FALSE;
+ }
+
+ if (c != '_') {
+ xputc(c, out);
+ } 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 && do_demangle(custr_cstr(word), lang, out) < 0)
+ ret = -1;
+
+ custr_free(word);
+ return (ret);
+}
+
+/*
+ * Attempt to demangle 'sym' as a symbol for 'lang' and write the result
+ * to 'out'. If 'sym' could not be demangled as 'lang' symbol, the original
+ * string is output instead.
+ *
+ * If an error other than 'not a mangled symbol' is encountered (e.g. ENOMEM),
+ * a warning is sent to stderr and -1 is returned. Otherwise, 0 is returned
+ * (including when 'sym' is merely not a mangled symbol of 'lang').
+ */
+static int
+do_demangle(const char *sym, sysdem_lang_t lang, FILE *out)
+{
+ char *demangled = sysdemangle(sym, lang, NULL);
+
+ if (demangled == NULL && errno != EINVAL) {
+ warn(_("error while demangling '%s'"), sym);
+ return (-1);
+ }
+
+ if (fprintf(out, "%s", (demangled != NULL) ? demangled : sym) < 0)
+ err(EXIT_FAILURE, _("failed to write to output"));
+
+ free(demangled);
+ return (0);
+}
+
+static void
+appendc(custr_t *cus, char c)
+{
+ if (custr_appendc(cus, c) == 0)
+ return;
+ err(EXIT_FAILURE, _("failed to save character from input"));
+}
+
+static void
+xputc(int c, FILE *out)
+{
+ if (fputc(c, out) < 0)
+ err(EXIT_FAILURE, _("failed to write output"));
+}
diff --git a/usr/src/lib/libdemangle/common/demangle-sys.h b/usr/src/lib/libdemangle/common/demangle-sys.h
index 05776ee5ee..3452d39667 100644
--- a/usr/src/lib/libdemangle/common/demangle-sys.h
+++ b/usr/src/lib/libdemangle/common/demangle-sys.h
@@ -11,7 +11,7 @@
/*
* Copyright 2017 Jason King
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _DEMANGLE_SYS_H
@@ -34,6 +34,7 @@ typedef struct sysdem_alloc_s {
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
diff --git a/usr/src/lib/libdemangle/common/demangle.c b/usr/src/lib/libdemangle/common/demangle.c
index 4f8e9ad678..b6db356416 100644
--- a/usr/src/lib/libdemangle/common/demangle.c
+++ b/usr/src/lib/libdemangle/common/demangle.c
@@ -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,19 +32,40 @@ static pthread_once_t debug_once = PTHREAD_ONCE_INIT;
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
diff --git a/usr/src/lib/libdemangle/common/mapfile-vers b/usr/src/lib/libdemangle/common/mapfile-vers
index 48c11ef0d7..2207547185 100644
--- a/usr/src/lib/libdemangle/common/mapfile-vers
+++ b/usr/src/lib/libdemangle/common/mapfile-vers
@@ -11,6 +11,7 @@
#
# Copyright 2017 Jason King
+# Copyright 2019 Joyent, Inc.
#
#
@@ -30,6 +31,7 @@ $mapfile_version 2
SYMBOL_VERSION ILLUMOSprivate {
global:
+ sysdem_parse_lang;
sysdemangle;
local:
*;
diff --git a/usr/src/man/man1/Makefile b/usr/src/man/man1/Makefile
index 069a50365e..2058046642 100644
--- a/usr/src/man/man1/Makefile
+++ b/usr/src/man/man1/Makefile
@@ -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 @@ MANFILES= acctcom.1 \
date.1 \
dc.1 \
deallocate.1 \
+ demangle.1 \
deroff.1 \
dhcpinfo.1 \
diff.1 \
diff --git a/usr/src/man/man1/demangle.1 b/usr/src/man/man1/demangle.1
new file mode 100644
index 0000000000..ca2dbef35a
--- /dev/null
+++ b/usr/src/man/man1/demangle.1
@@ -0,0 +1,119 @@
+.\" 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 March 3, 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.
+.Pp
+For either method, if an error other than attempting to demangle an non-mangled
+symbol (e.g. out of memory), that error will be written to standard error.
+.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
+.Sy Uncommitted .
+The output format is
+.Sy Not-an-Interface .
diff --git a/usr/src/pkg/manifests/developer-object-file.mf b/usr/src/pkg/manifests/developer-object-file.mf
index 5519e67d93..21d064fb9f 100644
--- a/usr/src/pkg/manifests/developer-object-file.mf
+++ b/usr/src/pkg/manifests/developer-object-file.mf
@@ -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)/mcs mode=0555
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/ncform
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