freebsd-skq/cxxfilt/cxxfilt.c

224 lines
5.1 KiB
C

/*-
* 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/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 3174 2015-03-27 17:13:41Z emaste $");
#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);
}