diff options
Diffstat (limited to 'cxxfilt/cxxfilt.c')
-rw-r--r-- | cxxfilt/cxxfilt.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/cxxfilt/cxxfilt.c b/cxxfilt/cxxfilt.c new file mode 100644 index 0000000000000..d30cfaeffdd77 --- /dev/null +++ b/cxxfilt/cxxfilt.c @@ -0,0 +1,224 @@ +/*- + * Copyright (c) 2009 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <ctype.h> +#include <err.h> +#include <getopt.h> +#include <libelftc.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "_elftc.h" + +ELFTC_VCSID("$Id: cxxfilt.c 2185 2011-11-19 16:07:16Z jkoshy $"); + +#define STRBUFSZ 8192 + +static int stripus = 0; +static int noparam = 0; +static int format = 0; + +enum options +{ + OPTION_HELP, + OPTION_VERSION +}; + +static struct option longopts[] = +{ + {"format", required_argument, NULL, 's'}, + {"help", no_argument, NULL, OPTION_HELP}, + {"no-params", no_argument, NULL, 'p'}, + {"no-strip-underscores", no_argument, NULL, 'n'}, + {"strip-underscores", no_argument, NULL, '_'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +static struct { + const char *fname; + int fvalue; +} flist[] = { + {"auto", 0}, + {"arm", ELFTC_DEM_ARM}, + {"gnu", ELFTC_DEM_GNU2}, + {"gnu-v3", ELFTC_DEM_GNU3} +}; + +#define USAGE_MESSAGE "\ +Usage: %s [options] [encoded-names...]\n\ + Translate C++ symbol names to human-readable form.\n\n\ + Options:\n\ + -_ | --strip-underscores Remove leading underscores prior to decoding.\n\ + -n | --no-strip-underscores Do not remove leading underscores.\n\ + -p | --no-params (Accepted but ignored).\n\ + -s SCHEME | --format=SCHEME Select the encoding scheme to use.\n\ + Valid schemes are: 'arm', 'auto', 'gnu' and\n\ + 'gnu-v3'.\n\ + --help Print a help message.\n\ + --version Print a version identifier and exit.\n" + +static void +usage(void) +{ + + (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); + exit(1); +} + +static void +version(void) +{ + fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); + exit(0); +} + +static int +find_format(const char *fstr) +{ + int i; + + for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) { + if (!strcmp(fstr, flist[i].fname)) + return (flist[i].fvalue); + } + + return (-1); +} + +static char * +demangle(char *name, int strict, int *pos) +{ + static char dem[STRBUFSZ]; + char nb[STRBUFSZ]; + int p, t; + + if (stripus && *name == '_') { + strncpy(nb, name + 1, sizeof(nb) - 1); + t = 1; + } else { + strncpy(nb, name, sizeof(nb) - 1); + t = 0; + } + nb[sizeof(nb) - 1] = '\0'; + + p = strlen(nb); + if (p <= 0) + return NULL; + + while (elftc_demangle(nb, dem, sizeof(dem), format) < 0) { + if (!strict && p > 1) { + nb[--p] = '\0'; + continue; + } else + return (NULL); + } + + if (pos != NULL) + *pos = t ? p + 1 : p; + + return (dem); +} + +int +main(int argc, char **argv) +{ + char *dem, buf[STRBUFSZ]; + int c, i, p, s, opt; + + while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) != + -1) { + switch (opt) { + case '_': + stripus = 1; + break; + case 'n': + stripus = 0; + break; + case 'p': + noparam = 1; + break; + case 's': + if ((format = find_format(optarg)) < 0) + errx(EXIT_FAILURE, "unsupported format: %s", + optarg); + break; + case 'V': + version(); + /* NOT REACHED */ + case OPTION_HELP: + default: + usage(); + /* NOT REACHED */ + } + } + + argv += optind; + argc -= optind; + + if (*argv != NULL) { + for (i = 0; i < argc; i++) { + if ((dem = demangle(argv[i], 1, NULL)) == NULL) + fprintf(stderr, "Failed: %s\n", argv[i]); + else + printf("%s\n", dem); + } + } else { + p = 0; + for (;;) { + c = fgetc(stdin); + if (c == EOF || !isprint(c) || strchr(" \t\n", c)) { + if (p > 0) { + buf[p] = '\0'; + if ((dem = demangle(buf, 0, &s)) == + NULL) + printf("%s", buf); + else { + printf("%s", dem); + for (i = s; i < p; i++) + putchar(buf[i]); + } + p = 0; + } + if (c == EOF) + break; + if (isprint(c) || strchr(" \t\n", c)) + putchar(c); + } else { + if ((size_t) p >= sizeof(buf) - 1) + warnx("buffer overflowed"); + else + buf[p++] = c; + } + + } + } + + exit(0); +} |