diff options
author | Jason King <jason.king@joyent.com> | 2019-11-09 01:17:22 -0600 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2020-03-28 13:09:21 -0500 |
commit | d52aae2365749461c362fde5a4c1a26a620cfbd3 (patch) | |
tree | 25c0592411bdc4c433f1122675382cb68cd345cc | |
parent | a61ed2ce7a86a4d6428f2a83eb4739fae945447e (diff) | |
download | illumos-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/Makefile | 3 | ||||
-rw-r--r-- | usr/src/cmd/demangle/Makefile | 40 | ||||
-rw-r--r-- | usr/src/cmd/demangle/demangle.c | 211 | ||||
-rw-r--r-- | usr/src/lib/libdemangle/common/demangle-sys.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libdemangle/common/demangle.c | 40 | ||||
-rw-r--r-- | usr/src/lib/libdemangle/common/mapfile-vers | 2 | ||||
-rw-r--r-- | usr/src/man/man1/Makefile | 2 | ||||
-rw-r--r-- | usr/src/man/man1/demangle.1 | 119 | ||||
-rw-r--r-- | usr/src/pkg/manifests/developer-object-file.mf | 3 |
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 |