cxxfilt.c revision 260684
1/*-
2 * Copyright (c) 2009 Kai Wang
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28#include <sys/param.h>
29#include <ctype.h>
30#include <err.h>
31#include <getopt.h>
32#include <libelftc.h>
33#include <stdlib.h>
34#include <stdio.h>
35#include <string.h>
36
37#include "_elftc.h"
38
39ELFTC_VCSID("$Id: cxxfilt.c 2185 2011-11-19 16:07:16Z jkoshy $");
40
41#define	STRBUFSZ	8192
42
43static int stripus = 0;
44static int noparam = 0;
45static int format = 0;
46
47enum options
48{
49	OPTION_HELP,
50	OPTION_VERSION
51};
52
53static struct option longopts[] =
54{
55	{"format", required_argument, NULL, 's'},
56	{"help", no_argument, NULL, OPTION_HELP},
57	{"no-params", no_argument, NULL, 'p'},
58	{"no-strip-underscores", no_argument, NULL, 'n'},
59	{"strip-underscores", no_argument, NULL, '_'},
60	{"version", no_argument, NULL, 'V'},
61	{NULL, 0, NULL, 0}
62};
63
64static struct {
65	const char *fname;
66	int fvalue;
67} flist[] = {
68	{"auto", 0},
69	{"arm", ELFTC_DEM_ARM},
70	{"gnu", ELFTC_DEM_GNU2},
71	{"gnu-v3", ELFTC_DEM_GNU3}
72};
73
74#define	USAGE_MESSAGE	"\
75Usage: %s [options] [encoded-names...]\n\
76  Translate C++ symbol names to human-readable form.\n\n\
77  Options:\n\
78  -_ | --strip-underscores     Remove leading underscores prior to decoding.\n\
79  -n | --no-strip-underscores  Do not remove leading underscores.\n\
80  -p | --no-params             (Accepted but ignored).\n\
81  -s SCHEME | --format=SCHEME  Select the encoding scheme to use.\n\
82                               Valid schemes are: 'arm', 'auto', 'gnu' and\n\
83                               'gnu-v3'.\n\
84  --help                       Print a help message.\n\
85  --version                    Print a version identifier and exit.\n"
86
87static void
88usage(void)
89{
90
91	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
92	exit(1);
93}
94
95static void
96version(void)
97{
98	fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
99	exit(0);
100}
101
102static int
103find_format(const char *fstr)
104{
105	int i;
106
107	for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) {
108		if (!strcmp(fstr, flist[i].fname))
109		    return (flist[i].fvalue);
110	}
111
112	return (-1);
113}
114
115static char *
116demangle(char *name, int strict, int *pos)
117{
118	static char dem[STRBUFSZ];
119	char nb[STRBUFSZ];
120	int p, t;
121
122	if (stripus && *name == '_') {
123		strncpy(nb, name + 1, sizeof(nb) - 1);
124		t = 1;
125	} else {
126		strncpy(nb, name, sizeof(nb) - 1);
127		t = 0;
128	}
129	nb[sizeof(nb) - 1] = '\0';
130
131	p = strlen(nb);
132	if (p <= 0)
133		return NULL;
134
135	while (elftc_demangle(nb, dem, sizeof(dem), format) < 0) {
136		if (!strict && p > 1) {
137			nb[--p] = '\0';
138			continue;
139		} else
140			return (NULL);
141	}
142
143	if (pos != NULL)
144		*pos = t ? p + 1 : p;
145
146	return (dem);
147}
148
149int
150main(int argc, char **argv)
151{
152	char *dem, buf[STRBUFSZ];
153	int c, i, p, s, opt;
154
155	while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) !=
156	    -1) {
157		switch (opt) {
158		case '_':
159			stripus = 1;
160			break;
161		case 'n':
162			stripus = 0;
163			break;
164		case 'p':
165			noparam = 1;
166			break;
167		case 's':
168			if ((format = find_format(optarg)) < 0)
169				errx(EXIT_FAILURE, "unsupported format: %s",
170				    optarg);
171			break;
172		case 'V':
173			version();
174			/* NOT REACHED */
175		case OPTION_HELP:
176		default:
177			usage();
178			/* NOT REACHED */
179		}
180	}
181
182	argv += optind;
183	argc -= optind;
184
185	if (*argv != NULL) {
186		for (i = 0; i < argc; i++) {
187			if ((dem = demangle(argv[i], 1, NULL)) == NULL)
188				fprintf(stderr, "Failed: %s\n", argv[i]);
189			else
190				printf("%s\n", dem);
191		}
192	} else {
193		p = 0;
194		for (;;) {
195			c = fgetc(stdin);
196			if (c == EOF || !isprint(c) || strchr(" \t\n", c)) {
197				if (p > 0) {
198					buf[p] = '\0';
199					if ((dem = demangle(buf, 0, &s)) ==
200					    NULL)
201						printf("%s", buf);
202					else {
203						printf("%s", dem);
204						for (i = s; i < p; i++)
205							putchar(buf[i]);
206					}
207					p = 0;
208				}
209				if (c == EOF)
210					break;
211				if (isprint(c) || strchr(" \t\n", c))
212					putchar(c);
213			} else {
214				if ((size_t) p >= sizeof(buf) - 1)
215					warnx("buffer overflowed");
216				else
217					buf[p++] = c;
218			}
219
220		}
221	}
222
223	exit(0);
224}
225