From 4226f635096bf9d814aa9fb335518c4855bbe3a3 Mon Sep 17 00:00:00 2001 From: Jason King Date: Sat, 27 May 2017 18:46:17 -0500 Subject: 6375 Add native name demangling support Reviewed by: Robert Mustacchi Reviewed by: Richard Lowe Approved by: Dan McDonald --- usr/src/cmd/dis/Makefile | 6 +- usr/src/cmd/dis/dis_util.c | 60 +- usr/src/cmd/mdb/Makefile.mdb | 2 + usr/src/cmd/mdb/common/kmdb/kmdb_demangle.c | 6 +- usr/src/cmd/mdb/common/mdb/mdb_demangle.c | 146 +- usr/src/cmd/mdb/common/mdb/mdb_demangle.h | 11 +- usr/src/cmd/sgs/dump/common/dump.c | 29 +- usr/src/cmd/sgs/gprof/common/printgprof.c | 99 +- usr/src/cmd/sgs/libconv/Makefile.com | 45 +- usr/src/cmd/sgs/libconv/common/demangle.c | 48 +- usr/src/cmd/sgs/libconv/common/demangle.msg | 6 +- usr/src/cmd/sgs/libconv/common/lintsup.c | 2 +- usr/src/cmd/sgs/liblddbg/common/util.c | 29 +- usr/src/cmd/sgs/nm/common/nm.c | 56 +- usr/src/cmd/sgs/prof/common/prof.c | 12 +- usr/src/cmd/sgs/prof/common/profv.c | 8 +- usr/src/lib/Makefile | 3 + usr/src/lib/libdemangle/Makefile | 41 + usr/src/lib/libdemangle/Makefile.com | 43 + usr/src/lib/libdemangle/THIRDPARTYLICENSE | 76 + usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip | 1 + usr/src/lib/libdemangle/amd64/Makefile | 30 + usr/src/lib/libdemangle/common/cxx.c | 4217 +++ usr/src/lib/libdemangle/common/cxx.h | 87 + usr/src/lib/libdemangle/common/cxx_util.c | 600 + usr/src/lib/libdemangle/common/demangle-sys.h | 41 + usr/src/lib/libdemangle/common/demangle.c | 87 + usr/src/lib/libdemangle/common/demangle_int.h | 39 + usr/src/lib/libdemangle/common/llib-ldemangle-sys | 29 + usr/src/lib/libdemangle/common/mapfile-vers | 36 + usr/src/lib/libdemangle/common/str.c | 313 + usr/src/lib/libdemangle/common/str.h | 63 + usr/src/lib/libdemangle/common/util.c | 85 + usr/src/lib/libdemangle/i386/Makefile | 30 + usr/src/lib/libdemangle/sparc/Makefile | 30 + usr/src/lib/libdemangle/sparcv9/Makefile | 29 + usr/src/pkg/manifests/system-library-demangle.mf | 43 + usr/src/pkg/manifests/system-test-utiltest.mf | 7 + usr/src/test/util-tests/runfiles/default.run | 3 + usr/src/test/util-tests/tests/Makefile | 2 + usr/src/test/util-tests/tests/demangle/Makefile | 73 + usr/src/test/util-tests/tests/demangle/afl-fast.c | 2955 ++ .../test/util-tests/tests/demangle/gcc-libstdc++.c | 8670 ++++++ .../util-tests/tests/demangle/llvm-stdcxxabi.c | 29733 +++++++++++++++++++ 44 files changed, 47641 insertions(+), 290 deletions(-) create mode 100644 usr/src/lib/libdemangle/Makefile create mode 100644 usr/src/lib/libdemangle/Makefile.com create mode 100644 usr/src/lib/libdemangle/THIRDPARTYLICENSE create mode 100644 usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip create mode 100644 usr/src/lib/libdemangle/amd64/Makefile create mode 100644 usr/src/lib/libdemangle/common/cxx.c create mode 100644 usr/src/lib/libdemangle/common/cxx.h create mode 100644 usr/src/lib/libdemangle/common/cxx_util.c create mode 100644 usr/src/lib/libdemangle/common/demangle-sys.h create mode 100644 usr/src/lib/libdemangle/common/demangle.c create mode 100644 usr/src/lib/libdemangle/common/demangle_int.h create mode 100644 usr/src/lib/libdemangle/common/llib-ldemangle-sys create mode 100644 usr/src/lib/libdemangle/common/mapfile-vers create mode 100644 usr/src/lib/libdemangle/common/str.c create mode 100644 usr/src/lib/libdemangle/common/str.h create mode 100644 usr/src/lib/libdemangle/common/util.c create mode 100644 usr/src/lib/libdemangle/i386/Makefile create mode 100644 usr/src/lib/libdemangle/sparc/Makefile create mode 100644 usr/src/lib/libdemangle/sparcv9/Makefile create mode 100644 usr/src/pkg/manifests/system-library-demangle.mf create mode 100644 usr/src/test/util-tests/tests/demangle/Makefile create mode 100644 usr/src/test/util-tests/tests/demangle/afl-fast.c create mode 100644 usr/src/test/util-tests/tests/demangle/gcc-libstdc++.c create mode 100644 usr/src/test/util-tests/tests/demangle/llvm-stdcxxabi.c (limited to 'usr/src') diff --git a/usr/src/cmd/dis/Makefile b/usr/src/cmd/dis/Makefile index f17298c92b..c35932248f 100644 --- a/usr/src/cmd/dis/Makefile +++ b/usr/src/cmd/dis/Makefile @@ -22,14 +22,16 @@ # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2018 Jason King +# PROG= dis OBJS= dis_target.o dis_main.o dis_util.o dis_list.o SRCS= $(OBJS:%.o=%.c) -include ../Makefile.cmd +include ../Makefile.cmd -LDLIBS += -ldisasm -luutil -lelf +LDLIBS += -ldisasm -luutil -lelf -ldemangle-sys CERRWARN += -_gcc=-Wno-uninitialized .KEEP_STATE: diff --git a/usr/src/cmd/dis/dis_util.c b/usr/src/cmd/dis/dis_util.c index 816c41394c..f74e7cef67 100644 --- a/usr/src/cmd/dis/dis_util.c +++ b/usr/src/cmd/dis/dis_util.c @@ -22,15 +22,15 @@ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Jason King. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include #include -#include +#include #include "dis_util.h" @@ -92,56 +92,20 @@ safe_malloc(size_t size) /* - * Generic interface to demangle C++ names. Calls cplus_demangle to do the - * necessary translation. If the translation fails, the argument is returned - * unchanged. The memory returned is only valid until the next call to - * demangle(). - * - * We dlopen() libdemangle.so rather than linking directly against it in case it - * is not installed on the system. + * Since the -C flag explicitly says C++, for now at least, force language to + * C++ */ const char * dis_demangle(const char *name) { - static char *demangled_name; - static int (*demangle_func)() = NULL; - static int size = BUFSIZE; - static int first_flag = 0; - int ret; + static char *demangled_name = NULL; /* - * If this is the first call, allocate storage - * for the buffer. + * Since demangled_name is static, it may be preserved across + * invocations. As such, make sure any memory that might be present + * from previous invocations is freed. */ - if (first_flag == 0) { - void *demangle_hand; - - demangle_hand = dlopen("libdemangle.so.1", RTLD_LAZY); - if (demangle_hand != NULL) - demangle_func = (int (*)(int))dlsym( - demangle_hand, "cplus_demangle"); - - demangled_name = safe_malloc(size); - first_flag = 1; - } - - /* - * If libdemangle is not present, pass through unchanged. - */ - if (demangle_func == NULL) - return (name); - - /* - * The function returns -1 when the buffer size is not sufficient. - */ - while ((ret = (*demangle_func)(name, demangled_name, size)) == -1) { - free(demangled_name); - size = size + BUFSIZE; - demangled_name = safe_malloc(size); - } - - if (ret != 0) - return (name); - - return (demangled_name); + free(demangled_name); + demangled_name = sysdemangle(name, SYSDEM_LANG_CPP, NULL); + return ((demangled_name != NULL) ? demangled_name : name); } diff --git a/usr/src/cmd/mdb/Makefile.mdb b/usr/src/cmd/mdb/Makefile.mdb index 852ce281ac..529f3a9a12 100644 --- a/usr/src/cmd/mdb/Makefile.mdb +++ b/usr/src/cmd/mdb/Makefile.mdb @@ -27,6 +27,7 @@ # Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright (c) 2012 Joyent, Inc. All rights reserved. +# Copyright 2018 Jason King # .KEEP_STATE: @@ -99,6 +100,7 @@ CSTD= $(CSTD_GNU99) C99LMODE= -Xc99=%all LDLIBS += -lcurses -lkvm -lproc -lrtld_db -lctf -lumem -ldisasm -lscf +LDLIBS += -ldemangle-sys CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-char-subscripts diff --git a/usr/src/cmd/mdb/common/kmdb/kmdb_demangle.c b/usr/src/cmd/mdb/common/kmdb/kmdb_demangle.c index efa73d023c..2027b2f186 100644 --- a/usr/src/cmd/mdb/common/kmdb/kmdb_demangle.c +++ b/usr/src/cmd/mdb/common/kmdb/kmdb_demangle.c @@ -22,17 +22,17 @@ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2017 Jason King. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include /*ARGSUSED*/ mdb_demangler_t * -mdb_dem_load(const char *path) +mdb_dem_load(void) { (void) set_errno(ENOTSUP); return (NULL); diff --git a/usr/src/cmd/mdb/common/mdb/mdb_demangle.c b/usr/src/cmd/mdb/common/mdb/mdb_demangle.c index 7ab7d19716..ad7555dcc0 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_demangle.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_demangle.c @@ -22,55 +22,48 @@ /* * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Jason King */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include #include -#include #include #include #include #include -#ifdef _LP64 -static const char LIB_DEMANGLE[] = "/usr/lib/64/libdemangle.so.1"; -#else -static const char LIB_DEMANGLE[] = "/usr/lib/libdemangle.so.1"; -#endif - -mdb_demangler_t * -mdb_dem_load(const char *path) +static void * +mdb_dem_alloc(size_t len) { - mdb_demangler_t *dmp; - void *hdl, *func; + return (mdb_alloc(len, UM_SLEEP)); +} - if (access(path, F_OK) == -1) - return (NULL); +static void +mdb_dem_free(void *p, size_t len) +{ + mdb_free(p, len); +} - if ((hdl = dlmopen(LM_ID_BASE, path, RTLD_LAZY | RTLD_LOCAL)) == NULL) { - (void) set_errno(EMDB_RTLD); - return (NULL); - } +static sysdem_ops_t mdb_dem_demops = { + .alloc = mdb_dem_alloc, + .free = mdb_dem_free +}; - if ((func = dlsym(hdl, "cplus_demangle")) == NULL) { - (void) dlclose(hdl); - (void) set_errno(EMDB_NODEM); - return (NULL); - } +mdb_demangler_t * +mdb_dem_load(void) +{ + mdb_demangler_t *dmp; dmp = mdb_alloc(sizeof (mdb_demangler_t), UM_SLEEP); - (void) strncpy(dmp->dm_pathname, path, MAXPATHLEN); - dmp->dm_pathname[MAXPATHLEN - 1] = '\0'; - dmp->dm_handle = hdl; - dmp->dm_convert = (int (*)())func; - dmp->dm_len = MDB_SYM_NAMLEN * 2; - dmp->dm_buf = mdb_alloc(dmp->dm_len, UM_SLEEP); + dmp->dm_len = 0; + dmp->dm_buf = NULL; dmp->dm_flags = MDB_DM_SCOPE; + /* stick with C++ for now to match old behavior */ + dmp->dm_lang = SYSDEM_LANG_CPP; return (dmp); } @@ -78,7 +71,6 @@ mdb_dem_load(const char *path) void mdb_dem_unload(mdb_demangler_t *dmp) { - (void) dlclose(dmp->dm_handle); mdb_free(dmp->dm_buf, dmp->dm_len); mdb_free(dmp, sizeof (mdb_demangler_t)); } @@ -202,58 +194,65 @@ mdb_dem_filter(mdb_demangler_t *dmp, const char *name) static int mdb_dem_process(mdb_demangler_t *dmp, const char *name) { - char *buf = dmp->dm_buf; - size_t len = dmp->dm_len; + char *res = NULL; + size_t reslen = 0; char *prefix = strrchr(name, '`'); - size_t prefixlen; + size_t prefixlen = 0; if (prefix) { prefix++; /* the ` is part of the prefix */ prefixlen = prefix - name; + } - if (prefixlen >= len) - return (DEMANGLE_ESPACE); + res = sysdemangle(name + prefixlen, dmp->dm_lang, &mdb_dem_demops); + if (res == NULL) { + if (errno != EINVAL) + mdb_warn("Error while demangling"); + return (-1); + } - (void) strncpy(buf, name, prefixlen); + reslen = (res != NULL) ? strlen(res) : 0; + reslen += prefixlen; + reslen += 1; - /* - * Fix up the arguments to dmp->dm_convert() - */ - name += prefixlen; - buf += prefixlen; - len -= prefixlen; + if (reslen > dmp->dm_len) { + mdb_free(dmp->dm_buf, dmp->dm_len); + + dmp->dm_buf = mdb_zalloc(reslen, UM_SLEEP); + if (dmp->dm_buf == NULL) { + dmp->dm_len = 0; + mdb_warn("Unable to allocate memory for demangling"); + return (-1); + } + dmp->dm_len = reslen; + } + + if (prefixlen > 0) + (void) strlcpy(dmp->dm_buf, name, prefixlen + 1); + else + *dmp->dm_buf = '\0'; + + if (res != NULL) { + (void) strlcat(dmp->dm_buf, res, dmp->dm_len); + mdb_dem_free(res, strlen(res) + 1); } /* * Save the position of the demangled string for mdb_dem_filter() */ - dmp->dm_dem = buf; + dmp->dm_dem = dmp->dm_buf + prefixlen; - return (dmp->dm_convert(name, buf, len)); + return (0); } +/* used by mdb_io.c:iob_addr2str */ const char * mdb_dem_convert(mdb_demangler_t *dmp, const char *name) { - int err; - - while ((err = mdb_dem_process(dmp, name)) == DEMANGLE_ESPACE) { - size_t len = dmp->dm_len * 2; - char *buf = mdb_alloc(len, UM_NOSLEEP); - - if (buf == NULL) { - mdb_warn("failed to allocate memory for demangling"); - return (name); /* just return original name */ - } - - mdb_free(dmp->dm_buf, dmp->dm_len); - dmp->dm_buf = buf; - dmp->dm_len = len; - } - - if (err != 0 || strcmp(dmp->dm_buf, name) == 0) - return (name); /* return original name if not mangled */ + if (mdb_dem_process(dmp, name) != 0 || + strcmp(dmp->dm_buf, name) == 0) + return (name); return (mdb_dem_filter(dmp, name)); } @@ -263,27 +262,20 @@ int cmd_demangle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { mdb_demangler_t *dmp = mdb.m_demangler; - const char *path = LIB_DEMANGLE; - if (argc > 1 || (argc > 0 && argv->a_type != MDB_TYPE_STRING)) + if (argc > 0) return (DCMD_USAGE); - if (argc > 0) { - if (dmp != NULL) - mdb_dem_unload(mdb.m_demangler); - path = argv->a_un.a_str; - } - - if (dmp != NULL && argc == 0 && !(mdb.m_flags & MDB_FL_DEMANGLE)) { + if (dmp != NULL && !(mdb.m_flags & MDB_FL_DEMANGLE)) { mdb_printf("C++ symbol demangling enabled\n"); mdb.m_flags |= MDB_FL_DEMANGLE; - } else if (dmp == NULL || argc > 0) { - if ((mdb.m_demangler = mdb_dem_load(path)) != NULL) { + } else if (dmp == NULL) { + if ((mdb.m_demangler = mdb_dem_load()) != NULL) { mdb_printf("C++ symbol demangling enabled\n"); mdb.m_flags |= MDB_FL_DEMANGLE; } else { - mdb_warn("failed to load C++ demangler %s", path); + mdb_warn("no memory to load C++ demangler"); mdb.m_flags &= ~MDB_FL_DEMANGLE; } @@ -338,8 +330,8 @@ cmd_demstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_USAGE); if (mdb.m_demangler == NULL && (mdb.m_demangler = - mdb_dem_load(LIB_DEMANGLE)) == NULL) { - mdb_warn("failed to load C++ demangler %s", LIB_DEMANGLE); + mdb_dem_load()) == NULL) { + mdb_warn("failed to load demangler"); return (DCMD_ERR); } diff --git a/usr/src/cmd/mdb/common/mdb/mdb_demangle.h b/usr/src/cmd/mdb/common/mdb/mdb_demangle.h index 7c9e99fd22..a92d64a349 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_demangle.h +++ b/usr/src/cmd/mdb/common/mdb/mdb_demangle.h @@ -22,13 +22,13 @@ /* * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Jason King. */ #ifndef _MDB_DEMANGLE_H #define _MDB_DEMANGLE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -38,11 +38,10 @@ extern "C" { #include #include #include +#include typedef struct mdb_demangler { - char dm_pathname[MAXPATHLEN]; /* pathname of demangling library */ - void *dm_handle; /* rtld handle to demangling library */ - int (*dm_convert)(const char *, char *, size_t); /* demangler */ + sysdem_lang_t dm_lang; /* language to demangle */ char *dm_buf; /* demangling buffer */ size_t dm_len; /* size of dm_buf in bytes */ char *dm_dem; /* start of demangled string (in buf) */ @@ -55,7 +54,7 @@ typedef struct mdb_demangler { #define MDB_DM_MANGLED 0x8 /* show mangled name */ #define MDB_DM_ALL 0xf /* mask of all valid flags */ -extern mdb_demangler_t *mdb_dem_load(const char *); +extern mdb_demangler_t *mdb_dem_load(void); extern void mdb_dem_unload(mdb_demangler_t *); extern const char *mdb_dem_convert(mdb_demangler_t *, const char *); diff --git a/usr/src/cmd/sgs/dump/common/dump.c b/usr/src/cmd/sgs/dump/common/dump.c index 016f045dc1..10c10c5b19 100644 --- a/usr/src/cmd/sgs/dump/common/dump.c +++ b/usr/src/cmd/sgs/dump/common/dump.c @@ -24,6 +24,7 @@ * All Rights Reserved * * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018, Joyent, Inc. */ /* Get definitions for the relocation types supported. */ @@ -477,28 +478,32 @@ static char * demangled_name(char *s) { static char *buf = NULL; - const char *dn; + size_t buflen = 0; + char *dn; size_t len; - dn = conv_demangle_name(s); + dn = (char *)conv_demangle_name(s); /* * If not demangled, just return the symbol name */ - if (strcmp(s, dn) == 0) + if (dn == s) return (s); + len = strlen(dn) + strlen(s) + 4; + + if (buflen < len) { + free(buf); + if ((buf = malloc(len)) == NULL) + return (s); + buflen = len; + } + /* * Demangled. Format it */ - if (buf != NULL) - free(buf); - - len = strlen(dn) + strlen(s) + 4; - if ((buf = malloc(len)) == NULL) - return (s); - - (void) snprintf(buf, len, "%s\t[%s]", dn, s); + (void) snprintf(buf, buflen, "%s\t[%s]", dn, s); + free(dn); return (buf); } @@ -526,7 +531,7 @@ print_symtab(Elf *elf_file, SCNTAB *p_symtab, Elf_Data *sym_data, adj = 8; while (range > 0) { - char *sym_name = (char *)0; + char *sym_name = NULL; int type, bind; int specsec; unsigned int shndx; diff --git a/usr/src/cmd/sgs/gprof/common/printgprof.c b/usr/src/cmd/sgs/gprof/common/printgprof.c index d02e9a3d9a..acabccaedd 100644 --- a/usr/src/cmd/sgs/gprof/common/printgprof.c +++ b/usr/src/cmd/sgs/gprof/common/printgprof.c @@ -22,10 +22,11 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Jason King + * Copyright 2018, Joyent, Inc. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -34,7 +35,7 @@ #include "gprof.h" void print_demangled_name(int, nltype *); -void striped_name(char *, nltype **); +static void stripped_name(char **, size_t *, nltype **); extern long hz; @@ -65,7 +66,7 @@ printprof(void) nltype *np; nltype **sortednlp; int i, index; - int print_count = number_funcs_toprint; + int print_count = number_funcs_toprint; bool print_flag = TRUE; mod_info_t *mi; @@ -293,7 +294,7 @@ printgprof(nltype **timesortnlp) { int index; nltype *parentp; - int print_count = number_funcs_toprint; + int print_count = number_funcs_toprint; bool count_flag = TRUE; /* @@ -500,10 +501,7 @@ printname(nltype *selfp) c = demangled_name(selfp); if (selfp->name != 0) { - if (!Cflag) - (void) printf("%s", selfp->name); - else - (void) printf("%s", c); + (void) printf("%s", c); #ifdef DEBUG if (debug & DFNDEBUG) @@ -523,24 +521,26 @@ printname(nltype *selfp) else (void) printf(" (%d)", selfp->index); } + + if (c != selfp->name) + free((void *)c); } void print_demangled_name(int n, nltype *selfp) { - char *c; + char *c = (char *)demangled_name(selfp); int i; - c = selfp->name; - - if (strcmp(c, demangled_name(selfp)) == 0) + if (c == selfp->name) return; - else { - (void) printf("\n"); - for (i = 1; i < n; i++) - (void) printf(" "); - (void) printf("[%s]", selfp->name); - } + + (void) printf("\n"); + for (i = 1; i < n; i++) + (void) printf(" "); + (void) printf("[%s]", selfp->name); + + free(c); } void @@ -862,8 +862,6 @@ printblurb(char *blurbname) (void) fclose(blurbfile); } -char *s1, *s2; - static int namecmp(const void *arg1, const void *arg2) { @@ -873,20 +871,50 @@ namecmp(const void *arg1, const void *arg2) if (!Cflag) return (strcmp((*npp1)->name, (*npp2)->name)); else { - striped_name(s1, npp1); - striped_name(s2, npp2); + static char *s1 = NULL, *s2 = NULL; + static size_t s1len = 0, s2len = 0; + + stripped_name(&s1, &s1len, npp1); + stripped_name(&s2, &s2len, npp2); return (strcmp(s1, s2)); } } -void -striped_name(char *s, nltype **npp) +#define NAME_CHUNK 512 +#define ROUNDLEN(x) (((x) + NAME_CHUNK - 1) / NAME_CHUNK * NAME_CHUNK) +static void +adjust_size(char **pp, size_t *lenp, const char *name) { - const char *d; + void *newp; + size_t nlen = strlen(name); + size_t buflen; + + if (*lenp > nlen) { + (void) memset(*pp, '\0', *lenp); + return; + } + + buflen = ROUNDLEN(nlen + 1); + if ((newp = realloc(*pp, buflen)) == NULL) { + (void) fprintf(stderr, + "gprof: out of memory comparing names\n"); + exit(EXIT_FAILURE); + } + (void) memset(newp, '\0', buflen); + + *lenp = buflen; + *pp = newp; +} + +static void +stripped_name(char **sp, size_t *slenp, nltype **npp) +{ + const char *name, *d; char *c; - c = (char *)s; - d = demangled_name(*npp); + name = d = demangled_name(*npp); + adjust_size(sp, slenp, name); + c = *sp; while ((*d != '(') && (*d != '\0')) { if (*d != ':') @@ -895,6 +923,9 @@ striped_name(char *s, nltype **npp) d++; } *c = '\0'; + + if ((*npp)->name != name) + free((void *)name); } /* @@ -972,11 +1003,6 @@ printindex() } } - if (Cflag) { - s1 = malloc(500 * sizeof (char)); - s2 = malloc(500 * sizeof (char)); - } - qsort(namesortnlp, nnames, sizeof (nltype *), namecmp); for (index = 1, todo = nnames; index <= ncycle; index++) @@ -1038,13 +1064,16 @@ printindex() if (does_clash(namesortnlp, i, nnames)) { (void) printf("%6.6s %d:%s\n", peterbuffer, nlp->module->id, d); - } else + } else { (void) printf("%6.6s %s\n", peterbuffer, d); + } - if (d != nlp->name) + if (d != nlp->name) { (void) printf("%6.6s [%s]", "", nlp->name); + free((void *)d); + } } else { (void) printf("%6.6s ", peterbuffer); (void) sprintf(peterbuffer, "", diff --git a/usr/src/cmd/sgs/libconv/Makefile.com b/usr/src/cmd/sgs/libconv/Makefile.com index d95213e586..c6287c433c 100644 --- a/usr/src/cmd/sgs/libconv/Makefile.com +++ b/usr/src/cmd/sgs/libconv/Makefile.com @@ -21,12 +21,13 @@ # # Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2018, Joyent, Inc. # LIBRARY = libconv.a COMOBJS32 = cap_machelf32.o dynamic_machelf32.o \ - globals_machelf32.o sections_machelf32.o \ + globals_machelf32.o sections_machelf32.o \ symbols_machelf32.o symbols_sparc_machelf32.o COMOBJS64 = cap_machelf64.o dynamic_machelf64.o \ @@ -36,19 +37,19 @@ COMOBJS64 = cap_machelf64.o dynamic_machelf64.o \ COMOBJS= arch.o audit.o \ c_literal.o \ cap.o config.o \ - corenote.o data.o \ - deftag.o demangle.o \ + corenote.o data.o \ + deftag.o demangle.o \ dl.o dwarf.o \ - dwarf_ehe.o dynamic.o \ + dwarf_ehe.o dynamic.o \ elf.o entry.o \ globals.o group.o \ - lddstub.o map.o \ + lddstub.o map.o \ phdr.o relocate.o \ - relocate_i386.o relocate_amd64.o \ + relocate_i386.o relocate_amd64.o \ relocate_sparc.o sections.o \ - segments.o strproc.o \ - symbols.o syminfo.o \ - tokens.o time.o \ + segments.o strproc.o \ + symbols.o syminfo.o \ + tokens.o time.o \ version.o ELFCAP_OBJS= elfcap.o @@ -61,15 +62,15 @@ BLTOBJS= arch_msg.o audit_msg.o \ corenote_msg.o data_msg.o \ deftag_msg.o demangle_msg.o \ dl_msg.o dwarf_msg.o \ - dwarf_ehe_msg.o dynamic_msg.o \ - elf_msg.o entry_msg.o \ + dwarf_ehe_msg.o dynamic_msg.o \ + elf_msg.o entry_msg.o \ globals_msg.o group_msg.o \ - map_msg.o lddstub_msg.o \ - phdr_msg.o relocate_amd64_msg.o \ + map_msg.o lddstub_msg.o \ + phdr_msg.o relocate_amd64_msg.o \ relocate_i386_msg.o relocate_sparc_msg.o \ - sections_msg.o segments_msg.o \ - symbols_msg.o symbols_sparc_msg.o \ - syminfo_msg.o time_msg.o \ + sections_msg.o segments_msg.o \ + symbols_msg.o symbols_sparc_msg.o \ + syminfo_msg.o time_msg.o \ version_msg.o @@ -84,8 +85,8 @@ OBJECTS = $(COMOBJS) $(COMOBJS32) $(COMOBJS64) $(ELFCAP_OBJS) \ NOCTFOBJS = $(OBJECTS) CTFMERGE_LIB = : -include $(SRC)/lib/Makefile.lib -include $(SRC)/cmd/sgs/Makefile.com +include $(SRC)/lib/Makefile.lib +include $(SRC)/cmd/sgs/Makefile.com CERRWARN += -_gcc=-Wno-type-limits CERRWARN += -_gcc=-Wno-switch @@ -113,6 +114,14 @@ LINTSRCS= $(COMOBJS:%.o=../common/%.c) \ LINTSRCS32 = $(COMOBJS32:%32.o=../common/%.c) LINTSRCS64 = $(COMOBJS64:%64.o=../common/%.c) +# Since libconv uses dlopen(3C) to load libdemangle-sys.so (much like it did +# for the old Sun Studio libdemangle.so) in order to avoid messy bootstrapping +# problems, but it also needs the definitions from demangle-sys.h for +# SYSDEM_LANG_AUTO, lint will complain about sysdemangle() being defined but not +# used unless it is explicitly included during the lint pass +$(LINTOUT32) := LDLIBS += -ldemangle-sys +$(LINTOUT64) := LDLIBS += -ldemangle-sys + SGSMSGTARG= $(BLTOBJS:%_msg.o=../common/%.msg) LINTFLAGS += -u diff --git a/usr/src/cmd/sgs/libconv/common/demangle.c b/usr/src/cmd/sgs/libconv/common/demangle.c index 8b590d87e0..eb2961ea3a 100644 --- a/usr/src/cmd/sgs/libconv/common/demangle.c +++ b/usr/src/cmd/sgs/libconv/common/demangle.c @@ -21,10 +21,11 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018, Joyent, Inc. */ #include -#include +#include #include "_conv.h" #include "demangle_msg.h" @@ -59,13 +60,11 @@ const char * conv_demangle_name(const char *name) { - static char _str[SYM_MAX], *str = _str; - static size_t size = SYM_MAX; - static int again = 1; - static int (*fptr)() = 0; - int error; + static char *(*fptr)() = 0; + static volatile int loading = 0; + char *d; - if (str == 0) + if (loading) return (name); /* @@ -78,38 +77,15 @@ conv_demangle_name(const char *name) if (fptr == 0) { void *hdl; - str = 0; + loading = 1; if (!(hdl = dlopen(MSG_ORIG(MSG_DEM_LIB), RTLD_LAZY)) || - !(fptr = (int (*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM)))) + !(fptr = (char *(*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM)))) return (name); - str = _str; + loading = 0; } - if ((error = (*fptr)(name, str, size)) == 0) - return ((const char *)str); - - while ((error == DEMANGLE_ESPACE) && again) { - char *_str; - size_t _size = size; - - /* - * If we haven't allocated our maximum try incrementing the - * present buffer size. Use malloc() rather than realloc() so - * that we at least have the old buffer on failure. - */ - if (((_size += SYM_MAX) > (SYM_MAX * 4)) || - ((_str = malloc(_size)) == 0)) { - again = 0; - break; - } - if (size != SYM_MAX) { - free(str); - } - str = _str; - size = _size; + if ((d = fptr(name, SYSDEM_LANG_AUTO, NULL)) == NULL) + return (name); - if ((error = (*fptr)(name, str, size)) == 0) - return ((const char *)str); - } - return (name); + return (d); } diff --git a/usr/src/cmd/sgs/libconv/common/demangle.msg b/usr/src/cmd/sgs/libconv/common/demangle.msg index c7cbeaf921..4a69427057 100644 --- a/usr/src/cmd/sgs/libconv/common/demangle.msg +++ b/usr/src/cmd/sgs/libconv/common/demangle.msg @@ -23,8 +23,8 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" +# Copyright 2018 Jason King # -@ MSG_DEM_SYM "cplus_demangle" -@ MSG_DEM_LIB "libdemangle.so.1" +@ MSG_DEM_SYM "sysdemangle" +@ MSG_DEM_LIB "libdemangle-sys.so.1" diff --git a/usr/src/cmd/sgs/libconv/common/lintsup.c b/usr/src/cmd/sgs/libconv/common/lintsup.c index 4c0d6e4fdd..6f1dfc4125 100644 --- a/usr/src/cmd/sgs/libconv/common/lintsup.c +++ b/usr/src/cmd/sgs/libconv/common/lintsup.c @@ -21,6 +21,7 @@ /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018, Joyent, Inc. */ /* LINTLIBRARY */ /* PROTOLIB1 */ @@ -39,7 +40,6 @@ #include #include #include -#include #include #include #include "sgs.h" diff --git a/usr/src/cmd/sgs/liblddbg/common/util.c b/usr/src/cmd/sgs/liblddbg/common/util.c index 575a9bd15f..09bcd437e9 100644 --- a/usr/src/cmd/sgs/liblddbg/common/util.c +++ b/usr/src/cmd/sgs/liblddbg/common/util.c @@ -22,6 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Jason King */ #include "msg.h" @@ -342,16 +344,35 @@ Dbg_util_nl(Lm_list *lml, int flag) const char * Dbg_demangle_name(const char *name) { + static char *buf = NULL; + if (DBG_NOTCLASS(DBG_C_DEMANGLE)) return (name); - return (conv_demangle_name(name)); + free(buf); + buf = (char *)conv_demangle_name(name); + if (buf == name) { + buf = NULL; + return (name); + } + + return (buf); } const char * Elf_demangle_name(const char *name) { - if (DBG_ISDEMANGLE()) - return (conv_demangle_name(name)); - return (name); + static char *buf = NULL; + + if (!DBG_ISDEMANGLE()) + return (name); + + free(buf); + buf = (char *)conv_demangle_name(name); + if (buf == name) { + buf = NULL; + return (name); + } + + return (buf); } diff --git a/usr/src/cmd/sgs/nm/common/nm.c b/usr/src/cmd/sgs/nm/common/nm.c index 258bd9fd67..fc3ded721e 100644 --- a/usr/src/cmd/sgs/nm/common/nm.c +++ b/usr/src/cmd/sgs/nm/common/nm.c @@ -25,6 +25,7 @@ * All Rights Reserved * * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Jason King */ #include @@ -260,7 +261,7 @@ main(int argc, char *argv[], char *envp[]) "%s: -u or -e set, -g ignored\n"), prog_name); break; - case 'r': if (R_flag) { + case 'r': if (R_flag) { R_flag = 0; (void) fprintf(stderr, gettext( "%s: -r set, -R ignored\n"), @@ -666,7 +667,7 @@ static void print_with_otherflags(int, Elf *, unsigned int, */ static void print_symtab(Elf *elf_file, unsigned int shstrndx, - Elf_Scn *p_sd, GElf_Shdr *shdr, char *filename) + Elf_Scn *p_sd, GElf_Shdr *shdr, char *filename) { Elf_Data * sd; @@ -781,7 +782,7 @@ is_bss_section(unsigned int shndx, Elf * elf_file, unsigned int shstrndx) */ static SYM * readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf, - unsigned int link, unsigned int symscnndx) + unsigned int link, unsigned int symscnndx) { SYM *s, *buf; GElf_Sym sym; @@ -805,15 +806,15 @@ readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf, if (sym.st_name == 0) buf->name = ""; else if (C_flag) { - const char *dn; + const char *dn = NULL; char *name = (char *)elf_strptr(elf, link, sym.st_name); + dn = conv_demangle_name(name); - if (strcmp(dn, name) == 0) { /* Not demangled */ - if (exotic(name)) { - name = FormatName(name, d_buf); - } - } else { /* name demangled */ + if (dn != name) { name = FormatName(name, dn); + free((void *)dn); + } else if (exotic(name)) { + name = FormatName(name, d_buf); } buf->name = name; } @@ -1014,10 +1015,7 @@ is_sym_print(SYM *sym_data) * -u flag specified */ static void -print_with_uflag( - SYM *sym_data, - char *filename -) +print_with_uflag(SYM *sym_data, char *filename) { if ((sym_data->shndx == SHN_UNDEF) && (strlen(sym_data->name))) { if (!r_flag) { @@ -1094,18 +1092,13 @@ print_brief_sym_type(Elf *elf_file, unsigned int shstrndx, SYM *sym_data) * -p flag specified */ static void -print_with_pflag( - int ndigits, - Elf *elf_file, - unsigned int shstrndx, - SYM *sym_data, - char *filename -) +print_with_pflag(int ndigits, Elf *elf_file, unsigned int shstrndx, + SYM *sym_data, char *filename) { const char * const fmt[] = { - "%.*llu ", /* FMT_T_DEC */ - "0x%.*llx ", /* FMT_T_HEX */ - "0%.*llo " /* FMT_T_OCT */ + "%.*llu ", /* FMT_T_DEC */ + "0x%.*llx ", /* FMT_T_HEX */ + "0%.*llo " /* FMT_T_OCT */ }; if (is_sym_print(sym_data) != 1) @@ -1148,12 +1141,8 @@ print_with_pflag( * -P flag specified */ static void -print_with_Pflag( - int ndigits, - Elf *elf_file, - unsigned int shstrndx, - SYM *sym_data -) +print_with_Pflag(int ndigits, Elf *elf_file, unsigned int shstrndx, + SYM *sym_data) { #define SYM_LEN 10 char sym_name[SYM_LEN+1]; @@ -1200,13 +1189,8 @@ print_with_Pflag( * other flags specified */ static void -print_with_otherflags( - int ndigits, - Elf *elf_file, - unsigned int shstrndx, - SYM *sym_data, - char *filename -) +print_with_otherflags(int ndigits, Elf *elf_file, unsigned int shstrndx, + SYM *sym_data, char *filename) { const char * const fmt_value_size[] = { "%*llu|%*lld|", /* FMT_T_DEC */ diff --git a/usr/src/cmd/sgs/prof/common/prof.c b/usr/src/cmd/sgs/prof/common/prof.c index 38a0aa0a9f..4b6086040c 100644 --- a/usr/src/cmd/sgs/prof/common/prof.c +++ b/usr/src/cmd/sgs/prof/common/prof.c @@ -22,6 +22,7 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2018 Jason King */ /* Copyright (c) 1988 AT&T */ @@ -32,7 +33,7 @@ * * Usage: * - * prof [-ChsVz] [-a | c | n | t] [-o | x] [-g | l] + * prof [-ChsVz] [-a | c | n | t] [-o | x] [-g | l] * [-m mdata] [prog] * * Where "prog" is the program that was profiled; "a.out" by default. @@ -136,7 +137,7 @@ char *aformat = "%8o "; int gflag = 0; /* replaces gmatch and gmask */ int Cflag = 0; -PROF_FILE *ldptr; /* For program ("a.out") file. */ +PROF_FILE *ldptr; /* For program ("a.out") file. */ FILE *mon_iop; /* For profile (MON_OUT) file. */ char *sym_fn = "a.out"; /* Default program file name. */ @@ -197,7 +198,7 @@ struct snymEntry { char *sym_addr; /* address which has a synonym */ int howMany; /* # of synonyms for this symbol */ int snymReported; /* 'was printed in a report line already' */ - /* flag, */ + /* flag, */ /* > 0 report line printed for these syns. */ /* == 0 not printed yet. */ long tot_sl_count; /* total subr calls for these snyms */ @@ -1311,9 +1312,7 @@ demangled_name(char *s) const char *name; size_t len; - name = conv_demangle_name(s); - - if (strcmp(name, s) == 0) + if ((name = conv_demangle_name(s)) == s) return (s); if (format_buf != NULL) @@ -1324,6 +1323,7 @@ demangled_name(char *s) if (format_buf == NULL) return (s); (void) snprintf(format_buf, len, FORMAT_BUF, name, s); + free((void *)name); return (format_buf); } diff --git a/usr/src/cmd/sgs/prof/common/profv.c b/usr/src/cmd/sgs/prof/common/profv.c index 4f9b72596e..887b36bba5 100644 --- a/usr/src/cmd/sgs/prof/common/profv.c +++ b/usr/src/cmd/sgs/prof/common/profv.c @@ -22,10 +22,10 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018, Joyent, Inc. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * All routines in this file are for processing new-style, *versioned* * mon.out format. Together with rdelf.c, lookup.c and profv.h, these @@ -74,7 +74,8 @@ setup_demangled_names(void) nbe = namebuf + namebuf_sz; for (i = 0; i < total_funcs; i++) { - if ((p = conv_demangle_name(profsym[i].name)) == NULL) + p = conv_demangle_name(profsym[i].name); + if (p == profsym[i].name) continue; namelen = strlen(p); @@ -97,6 +98,7 @@ setup_demangled_names(void) nbp += namelen + 1; cur_len += namelen + 1; + free((void *)p); } } diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 60b086a16c..07c8f13474 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -30,6 +30,7 @@ # Copyright 2018 Nexenta Systems, Inc. # Copyright (c) 2016, Chris Fraire . # Copyright 2017 RackTop Systems. +# Copyirght 2018 Jason King # include ../Makefile.master @@ -106,6 +107,7 @@ SUBDIRS += \ libctf \ libcurses \ libcustr \ + libdemangle \ libdevice \ libdevid \ libdevinfo \ @@ -379,6 +381,7 @@ HDRSUBDIRS= \ libctf \ libcurses \ libcustr \ + libdemangle \ libdevice \ libdevid \ libdevinfo \ diff --git a/usr/src/lib/libdemangle/Makefile b/usr/src/lib/libdemangle/Makefile new file mode 100644 index 0000000000..2d17d76e7f --- /dev/null +++ b/usr/src/lib/libdemangle/Makefile @@ -0,0 +1,41 @@ +# +# 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 2018 Jason King. +# Copyright 2017, Joyent. Inc. +# + +include ../Makefile.lib + +HDRS = demangle-sys.h +HDRDIR = common +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libdemangle/Makefile.com b/usr/src/lib/libdemangle/Makefile.com new file mode 100644 index 0000000000..0b0d495df7 --- /dev/null +++ b/usr/src/lib/libdemangle/Makefile.com @@ -0,0 +1,43 @@ +# +# 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 2018 Jason King +# Copyright 2018, Joyent, Inc. +# + +LIBRARY = libdemangle-sys.a +VERS = .1 +OBJECTS = str.o util.o cxx_util.o cxx.o demangle.o + +include ../../Makefile.lib + +LIBS = $(DYNLIB) $(LINTLIB) +LDLIBS += -lc + +SRCDIR = ../common +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +CSTD = $(CSTD_GNU99) +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -I$(SRCDIR) -D_REENTRANT -D__EXTENSIONS__ + +LINTFLAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 +LINTFLAGS64 += -erroff=E_BAD_FORMAT_ARG_TYPE2 +C99LMODE = -Xc99=%all + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libdemangle/THIRDPARTYLICENSE b/usr/src/lib/libdemangle/THIRDPARTYLICENSE new file mode 100644 index 0000000000..7381b74c4d --- /dev/null +++ b/usr/src/lib/libdemangle/THIRDPARTYLICENSE @@ -0,0 +1,76 @@ +============================================================================== +libc++abi License +============================================================================== + +The libc++abi library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip b/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip new file mode 100644 index 0000000000..ee4e5590cf --- /dev/null +++ b/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip @@ -0,0 +1 @@ +PORTIONS OF LIBSYSDEMANGLE FUNCTIONALITY diff --git a/usr/src/lib/libdemangle/amd64/Makefile b/usr/src/lib/libdemangle/amd64/Makefile new file mode 100644 index 0000000000..137dd0cf23 --- /dev/null +++ b/usr/src/lib/libdemangle/amd64/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/libdemangle/common/cxx.c b/usr/src/lib/libdemangle/common/cxx.c new file mode 100644 index 0000000000..66d7170544 --- /dev/null +++ b/usr/src/lib/libdemangle/common/cxx.c @@ -0,0 +1,4217 @@ +/* + * Ported from LLVM's libcxxabi trunk/src/cxa_demangle.cpp + * LICENSE.TXT contents is available as ../THIRDPARTYLICENSE + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + */ + +/* + * Copyright 2018 Jason King. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "demangle-sys.h" +#include "demangle_int.h" +#include "cxx.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) +#endif + +#define CPP_QUAL_CONST (1U) +#define CPP_QUAL_VOLATILE (2U) +#define CPP_QUAL_RESTRICT (4U) + +typedef struct cpp_db_s { + sysdem_ops_t *cpp_ops; + jmp_buf cpp_jmp; + name_t cpp_name; + sub_t cpp_subs; + templ_t cpp_templ; + unsigned cpp_cv; + unsigned cpp_ref; + unsigned cpp_depth; + boolean_t cpp_parsed_ctor_dtor_cv; + boolean_t cpp_tag_templates; + boolean_t cpp_fix_forward_references; + boolean_t cpp_try_to_parse_template_args; + locale_t cpp_loc; +} cpp_db_t; + +#define CK(x) \ + do { \ + if (!(x)) { \ + longjmp(db->cpp_jmp, 1); \ + } \ + NOTE(CONSTCOND) \ + } while (0) + +#define TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l)) +#define RLEN(f, l) ((size_t)((l) - (f))) +#define NAMT(db, n) (nlen(db) - n) + +static inline boolean_t is_xdigit(int); + +static boolean_t nempty(cpp_db_t *); +static size_t nlen(cpp_db_t *); +static void nadd_l(cpp_db_t *, const char *, size_t); +static void njoin(cpp_db_t *, size_t, const char *); +static void nfmt(cpp_db_t *, const char *, const char *); + +static void save_top(cpp_db_t *, size_t); +static void sub(cpp_db_t *, size_t); + +static boolean_t tempty(const cpp_db_t *); +static size_t ttlen(const cpp_db_t *); + +static void tsub(cpp_db_t *, size_t); +static void tpush(cpp_db_t *); +static void tpop(cpp_db_t *); +static void tsave(cpp_db_t *, size_t); + +static boolean_t db_init(cpp_db_t *, sysdem_ops_t *); +static void db_fini(cpp_db_t *); +static void dump(cpp_db_t *, FILE *); + +static void demangle(const char *, const char *, cpp_db_t *); + +static const char *parse_type(const char *, const char *, cpp_db_t *); +static const char *parse_builtin_type(const char *, const char *, cpp_db_t *); +static const char *parse_qual_type(const char *, const char *, cpp_db_t *); +static const char *parse_encoding(const char *, const char *, cpp_db_t *); +static const char *parse_dot_suffix(const char *, const char *, cpp_db_t *); +static const char *parse_block_invoke(const char *, const char *, cpp_db_t *); +static const char *parse_special_name(const char *, const char *, cpp_db_t *); +static const char *parse_name(const char *, const char *, boolean_t *, + cpp_db_t *); +static const char *parse_call_offset(const char *, const char *, locale_t); +static const char *parse_number(const char *, const char *, locale_t); +static const char *parse_nested_name(const char *, const char *, boolean_t *, + cpp_db_t *); +static const char *parse_local_name(const char *, const char *, boolean_t *, + cpp_db_t *); +static const char *parse_unscoped_name(const char *, const char *, cpp_db_t *); +static const char *parse_template_args(const char *, const char *, cpp_db_t *); +static const char *parse_substitution(const char *, const char *, cpp_db_t *); +static const char *parse_discriminator(const char *, const char *, locale_t); +static const char *parse_cv_qualifiers(const char *, const char *, unsigned *); +static const char *parse_template_param(const char *, const char *, cpp_db_t *); +static const char *parse_decltype(const char *, const char *, cpp_db_t *); +static const char *parse_template_args(const char *, const char *, cpp_db_t *); +static const char *parse_unqualified_name(const char *, const char *, + cpp_db_t *); +static const char *parse_template_arg(const char *, const char *, cpp_db_t *); +static const char *parse_expression(const char *, const char *, cpp_db_t *); +static const char *parse_expr_primary(const char *, const char *, cpp_db_t *); +static const char *parse_binary_expr(const char *, const char *, + const char *, cpp_db_t *); +static const char *parse_prefix_expr(const char *, const char *, + const char *, cpp_db_t *); +static const char *parse_gs(const char *, const char *, cpp_db_t *); +static const char *parse_idx_expr(const char *, const char *, cpp_db_t *); +static const char *parse_mm_expr(const char *, const char *, cpp_db_t *); +static const char *parse_pp_expr(const char *, const char *, cpp_db_t *); +static const char *parse_trinary_expr(const char *, const char *, cpp_db_t *); +static const char *parse_new_expr(const char *, const char *, cpp_db_t *); +static const char *parse_del_expr(const char *, const char *, cpp_db_t *); +static const char *parse_cast_expr(const char *, const char *, cpp_db_t *); +static const char *parse_sizeof_param_pack_expr(const char *, const char *, + cpp_db_t *); +static const char *parse_typeid_expr(const char *, const char *, cpp_db_t *); +static const char *parse_throw_expr(const char *, const char *, cpp_db_t *); +static const char *parse_dot_star_expr(const char *, const char *, cpp_db_t *); +static const char *parse_dot_expr(const char *, const char *, cpp_db_t *); +static const char *parse_call_expr(const char *, const char *, cpp_db_t *); +static const char *parse_arrow_expr(const char *, const char *, cpp_db_t *); +static const char *parse_conv_expr(const char *, const char *, cpp_db_t *); +static const char *parse_function_param(const char *, const char *, cpp_db_t *); +static const char *parse_base_unresolved_name(const char *, const char *, + cpp_db_t *); +static const char *parse_unresolved_name(const char *, const char *, + cpp_db_t *); +static const char *parse_noexcept_expr(const char *, const char *, cpp_db_t *); +static const char *parse_alignof(const char *, const char *, cpp_db_t *); +static const char *parse_sizeof(const char *, const char *, cpp_db_t *); +static const char *parse_unnamed_type_name(const char *, const char *, + cpp_db_t *); +static const char *parse_ctor_dtor_name(const char *, const char *, cpp_db_t *); +static const char *parse_source_name(const char *, const char *, cpp_db_t *); +static const char *parse_operator_name(const char *, const char *, cpp_db_t *); +static const char *parse_pack_expansion(const char *, const char *, cpp_db_t *); +static const char *parse_unresolved_type(const char *, const char *, + cpp_db_t *); +static const char *parse_unresolved_qualifier_level(const char *, const char *, + cpp_db_t *); +static const char *parse_destructor_name(const char *, const char *, + cpp_db_t *); +static const char *parse_function_type(const char *, const char *, cpp_db_t *); +static const char *parse_array_type(const char *, const char *, cpp_db_t *); +static const char *parse_pointer_to_member_type(const char *, const char *, + cpp_db_t *); +static const char *parse_vector_type(const char *, const char *, cpp_db_t *); + +size_t cpp_name_max_depth = 1024; /* max depth of name stack */ + +char * +cpp_demangle(const char *src, sysdem_ops_t *ops) +{ + char *result = NULL; + cpp_db_t db; + size_t srclen = strlen(src); + + if (!db_init(&db, ops)) + goto done; + if (setjmp(db.cpp_jmp) != 0) + goto done; + + errno = 0; + demangle(src, src + srclen, &db); + + if (errno == 0 && db.cpp_fix_forward_references && + !templ_empty(&db.cpp_templ) && + !sub_empty(&db.cpp_templ.tpl_items[0])) { + db.cpp_fix_forward_references = B_FALSE; + db.cpp_tag_templates = B_FALSE; + name_clear(&db.cpp_name); + sub_clear(&db.cpp_subs); + + if (setjmp(db.cpp_jmp) != 0) + goto done; + + demangle(src, src + srclen, &db); + + if (db.cpp_fix_forward_references) { + errno = EINVAL; + goto done; + } + } + + if (errno != 0) + goto done; + + if (nempty(&db)) { + errno = EINVAL; + goto done; + } + + njoin(&db, 1, ""); + + if (nlen(&db) > 0) { + str_t *s = TOP_L(&db); + result = zalloc(ops, s->str_len + 1); + if (result == NULL) + goto done; + + (void) memcpy(result, s->str_s, s->str_len); + } + +done: + if (demangle_debug) + dump(&db, stdout); + + db_fini(&db); + return (result); +} + +static void +demangle(const char *first, const char *last, cpp_db_t *db) +{ + const char *t = NULL; + + if (first >= last) { + errno = EINVAL; + return; + } + + if (first[0] != '_') { + t = parse_type(first, last, db); + if (t == first) { + errno = EINVAL; + return; + } + goto done; + } + + if (last - first < 4) { + errno = EINVAL; + return; + } + + if (first[1] == 'Z') { + t = parse_encoding(first + 2, last, db); + + if (t != first + 2 && t != last && t[0] == '.') { + t = parse_dot_suffix(t, last, db); + if (nlen(db) > 1) + njoin(db, 2, ""); + } + + goto done; + } + + if (first[1] != '_' || first[2] != '_' || first[3] != 'Z') + goto done; + + t = parse_encoding(first + 4, last, db); + if (t != first + 4 && t != last) + t = parse_block_invoke(t, last, db); + +done: + if (t != last) + errno = EINVAL; +} + +static const char * +parse_dot_suffix(const char *first, const char *last, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + if (first == last || first[0] != '.') + return (first); + + if (nempty(db)) + return (first); + + nadd_l(db, first, RLEN(first, last)); + nfmt(db, " ({0})", NULL); + + return (last); +} + +/* + * _block_invoke + * _block_invoke* + * _block_invoke_+ + */ +static const char * +parse_block_invoke(const char *first, const char *last, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + if (last - first < 13) + return (first); + + const char test[] = "_block_invoke"; + const char *t = first; + + if (strncmp(first, test, sizeof (test) - 1) != 0) + return (first); + + t += sizeof (test); + if (t == last) + goto done; + + if (t[0] == '_') { + /* need at least one digit */ + if (t + 1 == last || !isdigit_l(t[1], db->cpp_loc)) + return (first); + t += 2; + } + + while (t < last && isdigit_l(t[0], db->cpp_loc)) + t++; + +done: + if (nempty(db)) + return (first); + + nfmt(db, "invocation function for block in {0}", NULL); + return (t); +} + +/* + * ::= + * ::= + * ::= + */ +static const char * +parse_encoding(const char *first, const char *last, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + if (first == last) + return (first); + + const char *t = NULL; + const char *t2 = NULL; + unsigned cv = 0; + unsigned ref = 0; + boolean_t tag_templ_save = db->cpp_tag_templates; + + if (++db->cpp_depth > 1) + db->cpp_tag_templates = B_TRUE; + + if (first[0] == 'G' || first[0] == 'T') { + t = parse_special_name(first, last, db); + goto done; + } + + boolean_t ends_with_template_args = B_FALSE; + t = parse_name(first, last, &ends_with_template_args, db); + if (t == first) + goto fail; + + cv = db->cpp_cv; + ref = db->cpp_ref; + + if (t == last || t[0] == 'E' || t[0] == '.') + goto done; + + db->cpp_tag_templates = B_FALSE; + if (nempty(db) || str_length(TOP_L(db)) == 0) + goto fail; + + if (!db->cpp_parsed_ctor_dtor_cv && ends_with_template_args) { + t2 = parse_type(t, last, db); + if (t2 == t || nlen(db) < 2) + goto fail; + + str_pair_t *sp = name_top(&db->cpp_name); + + if (str_length(&sp->strp_r) == 0) + (void) str_append(&sp->strp_l, " ", 1); + + nfmt(db, "{0:L}{1:L}", "{1:R}{0:R}"); + t = t2; + } + + if (t == last || nempty(db)) + goto fail; + + size_t n = nlen(db); + + if (t[0] == 'v') { + t++; + } else { + for (;;) { + t2 = parse_type(t, last, db); + if (t2 == t || t == last) + break; + + t = t2; + } + } + + /* + * a bit of a hack, but a template substitution can apparently be + * an empty string at the end of an argument list, so avoid + * <...., > + */ + if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0) + name_pop(&db->cpp_name, NULL); + + njoin(db, NAMT(db, n), ", "); + nfmt(db, "({0})", NULL); + + str_t *s = TOP_L(db); + + if (cv & CPP_QUAL_CONST) { + CK(str_append(s, " const", 0)); + } + if (cv & CPP_QUAL_VOLATILE) { + CK(str_append(s, " volatile", 0)); + } + if (cv & CPP_QUAL_RESTRICT) { + CK(str_append(s, " restrict", 0)); + } + if (ref == 1) { + CK(str_append(s, " &", 0)); + } + if (ref == 2) { + CK(str_append(s, " &&", 0)); + } + + nfmt(db, "{1:L}{0}{1:R}", NULL); + +done: + db->cpp_tag_templates = tag_templ_save; + db->cpp_depth--; + return (t); + +fail: + db->cpp_tag_templates = tag_templ_save; + db->cpp_depth--; + return (first); +} + +/* + * ::= TV # virtual table + * ::= TT # VTT structure (construction vtable index) + * ::= TI # typeinfo structure + * ::= TS # typeinfo name (null-terminated byte string) + * ::= Tc + * # base is the nominal target function of thunk + * # first call-offset is 'this' adjustment + * # second call-offset is result adjustment + * ::= T + * # base is the nominal target function of thunk + * ::= GV # Guard variable for one-time init + * # No + * ::= TW # Thread-local wrapper + * ::= TH # Thread-local initialization + * extension ::= TC _ + * # construction vtable for second-in-first + * extension ::= GR # reference temporary for object + */ +static const char * +parse_special_name(const char *first, const char *last, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + const char *t = first; + const char *t1 = NULL; + size_t n = nlen(db); + + if (last - first < 2) + return (first); + + switch (t[0]) { + case 'T': + switch (t[1]) { + case 'V': + nadd_l(db, "vtable for", 0); + t = parse_type(first + 2, last, db); + break; + case 'T': + nadd_l(db, "VTT for", 0); + t = parse_type(first + 2, last, db); + break; + case 'I': + nadd_l(db, "typeinfo for", 0); + t = parse_type(first + 2, last, db); + break; + case 'S': + nadd_l(db, "typeinfo name for", 0); + t = parse_type(first + 2, last, db); + break; + case 'c': + nadd_l(db, "covariant return thunk to", 0); + t1 = parse_call_offset(first + 2, last, db->cpp_loc); + if (t1 == t) + return (first); + t = parse_call_offset(t1, last, db->cpp_loc); + if (t == t1) + return (first); + t1 = parse_encoding(t, last, db); + if (t1 == t) + return (first); + break; + case 'C': + t = parse_type(first + 2, last, db); + if (t == first + 2) + return (first); + t1 = parse_number(t, last, db->cpp_loc); + if (*t1 != '_') + return (first); + t = parse_type(t1 + 1, last, db); + if (t == t1 + 1 || nlen(db) < 2) + return (first); + nfmt(db, "construction vtable for {0}-in-{1}", NULL); + return (t); + case 'W': + nadd_l(db, "thread-local wrapper routine for", 0); + t = parse_name(first + 2, last, NULL, db); + break; + case 'H': + nadd_l(db, "thread-local initialization routine for", + 0); + t = parse_name(first + 2, last, NULL, db); + break; + default: + if (first[1] == 'v') { + nadd_l(db, "virtual thunk to", 0); + } else { + nadd_l(db, "non-virtual thunk to", 0); + } + + t = parse_call_offset(first + 1, last, db->cpp_loc); + if (t == first + 1) + return (first); + t1 = parse_encoding(t, last, db); + if (t == t1) + return (first); + t = t1; + break; + } + break; + case 'G': + switch (first[1]) { + case 'V': + nadd_l(db, "guard variable for", 0); + t = parse_name(first + 2, last, NULL, db); + break; + case 'R': + nadd_l(db, "reference temporary for", 0); + t = parse_name(first + 2, last, NULL, db); + break; + default: + return (first); + } + break; + default: + return (first); + } + + size_t amt = NAMT(db, n); + if (t == first + 2 || amt < 2) + return (first); + + njoin(db, amt, " "); + return (t); +} + +/* + * ::= h _ + * ::= v _ + * + * ::= + * # non-virtual base override + * + * ::= _ + * # virtual base override, with vcall offset + */ +static const char * +parse_call_offset(const char *first, const char *last, locale_t loc) +{ + VERIFY3P(first, <=, last); + + const char *t = NULL; + const char *t1 = NULL; + + if (first == last) + return (first); + + if (first[0] != 'h' && first[0] != 'v') + return (first); + + t = parse_number(first + 1, last, loc); + if (t == first + 1 || t == last || t[0] != '_') + return (first); + + /* skip _ */ + t++; + + if (first[0] == 'h') + return (t); + + t1 = parse_number(t, last, loc); + if (t == t1 || t1 == last || t1[0] != '_') + return (first); + + /* skip _ */ + t1++; + + return (t1); +} + +/* + * ::= // N + * ::= # See Scope Encoding below // Z + * ::= + * ::= + * + * ::= + * ::= + */ +static const char * +parse_name(const char *first, const char *last, + boolean_t *ends_with_template_args, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + const char *t = first; + const char *t1 = NULL; + + if (last - first < 2) + return (first); + + /* extension: ignore L here */ + if (t[0] == 'L') + t++; + + switch (t[0]) { + case 'N': + t1 = parse_nested_name(t, last, ends_with_template_args, db); + return ((t == t1) ? first : t1); + case 'Z': + t1 = parse_local_name(t, last, ends_with_template_args, db); + return ((t == t1) ? first : t1); + } + + /* + * + * + * + */ + t1 = parse_unscoped_name(t, last, db); + + /* */ + if (t != t1 && t1[0] != 'I') + return (t1); + + if (t == t1) { + t1 = parse_substitution(t, last, db); + if (t == t1 || t1 == last || t1[0] != 'I') + return (first); + } else { + save_top(db, 1); + } + + t = parse_template_args(t1, last, db); + if (t1 == t || nlen(db) < 2) + return (first); + + nfmt(db, "{1:L}{0}", "{1:R}"); + + if (ends_with_template_args != NULL) + *ends_with_template_args = B_TRUE; + + return (t); +} + +/* BEGIN CSTYLED */ +/* + * := Z E [] + * := Z E s [] + * := Z Ed [ ] _ + */ +/* END CSTYLED */ +const char * +parse_local_name(const char *first, const char *last, + boolean_t *ends_with_template_args, cpp_db_t *db) +{ + VERIFY3P(first, <=, last); + + const char *t = NULL; + const char *t1 = NULL; + const char *t2 = NULL; + + if (first == last || first[0] != 'Z') + return (first); + + t = parse_encoding(first + 1, last, db); + if (t == first + 1 || t == last || t[0] != 'E') + return (first); + + VERIFY(!nempty(db)); + + /* skip E */ + t++; + + if (t[0] == 's') { + nfmt(db, "{0:L}::string literal", "{0:R}"); + return (parse_discriminator(t, last, db->cpp_loc)); + } + + if (t[0] == 'd') { + t1 = parse_number(t + 1, last, db->cpp_loc); + if (t1[0] != '_') + return (first); + t1++; + } else { + t1 = t; + } + + t2 = parse_name(t1, last, ends_with_template_args, db); + if (t2 == t1) + return (first); + + nfmt(db, "{1:L}::{0}", "{1:R}"); + + /* parsed, but ignored */ + if (t[0] != 'd') + t2 = parse_discriminator(t2, last, db->cpp_loc); + + return (t2); +} + +/* BEGIN CSTYLED */ +/* + * ::= N [] [] E + * ::= N [] [] E + * + * ::= + * ::= + * ::= + * ::= + * ::= # empty + * ::= + * ::= + * extension ::= L + * + * ::=