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/param.h> 28 #include <ctype.h> 29 #include <err.h> 30 #include <getopt.h> 31 #include <libelftc.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 36 #include "_elftc.h" 37 38 ELFTC_VCSID("$Id: cxxfilt.c 3174 2015-03-27 17:13:41Z emaste $"); 39 40 #define STRBUFSZ 8192 41 42 static int stripus = 0; 43 static int noparam = 0; 44 static int format = 0; 45 46 enum options 47 { 48 OPTION_HELP, 49 OPTION_VERSION 50 }; 51 52 static struct option longopts[] = 53 { 54 {"format", required_argument, NULL, 's'}, 55 {"help", no_argument, NULL, OPTION_HELP}, 56 {"no-params", no_argument, NULL, 'p'}, 57 {"no-strip-underscores", no_argument, NULL, 'n'}, 58 {"strip-underscores", no_argument, NULL, '_'}, 59 {"version", no_argument, NULL, 'V'}, 60 {NULL, 0, NULL, 0} 61 }; 62 63 static struct { 64 const char *fname; 65 int fvalue; 66 } flist[] = { 67 {"auto", 0}, 68 {"arm", ELFTC_DEM_ARM}, 69 {"gnu", ELFTC_DEM_GNU2}, 70 {"gnu-v3", ELFTC_DEM_GNU3} 71 }; 72 73 #define USAGE_MESSAGE "\ 74 Usage: %s [options] [encoded-names...]\n\ 75 Translate C++ symbol names to human-readable form.\n\n\ 76 Options:\n\ 77 -_ | --strip-underscores Remove leading underscores prior to decoding.\n\ 78 -n | --no-strip-underscores Do not remove leading underscores.\n\ 79 -p | --no-params (Accepted but ignored).\n\ 80 -s SCHEME | --format=SCHEME Select the encoding scheme to use.\n\ 81 Valid schemes are: 'arm', 'auto', 'gnu' and\n\ 82 'gnu-v3'.\n\ 83 --help Print a help message.\n\ 84 --version Print a version identifier and exit.\n" 85 86 static void 87 usage(void) 88 { 89 90 (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 91 exit(1); 92 } 93 94 static void 95 version(void) 96 { 97 fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 98 exit(0); 99 } 100 101 static int 102 find_format(const char *fstr) 103 { 104 int i; 105 106 for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) { 107 if (!strcmp(fstr, flist[i].fname)) 108 return (flist[i].fvalue); 109 } 110 111 return (-1); 112 } 113 114 static char * 115 demangle(char *name, int strict, int *pos) 116 { 117 static char dem[STRBUFSZ]; 118 char nb[STRBUFSZ]; 119 int p, t; 120 121 if (stripus && *name == '_') { 122 strncpy(nb, name + 1, sizeof(nb) - 1); 123 t = 1; 124 } else { 125 strncpy(nb, name, sizeof(nb) - 1); 126 t = 0; 127 } 128 nb[sizeof(nb) - 1] = '\0'; 129 130 p = strlen(nb); 131 if (p <= 0) 132 return NULL; 133 134 while (elftc_demangle(nb, dem, sizeof(dem), format) < 0) { 135 if (!strict && p > 1) { 136 nb[--p] = '\0'; 137 continue; 138 } else 139 return (NULL); 140 } 141 142 if (pos != NULL) 143 *pos = t ? p + 1 : p; 144 145 return (dem); 146 } 147 148 int 149 main(int argc, char **argv) 150 { 151 char *dem, buf[STRBUFSZ]; 152 int c, i, p, s, opt; 153 154 while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) != 155 -1) { 156 switch (opt) { 157 case '_': 158 stripus = 1; 159 break; 160 case 'n': 161 stripus = 0; 162 break; 163 case 'p': 164 noparam = 1; 165 break; 166 case 's': 167 if ((format = find_format(optarg)) < 0) 168 errx(EXIT_FAILURE, "unsupported format: %s", 169 optarg); 170 break; 171 case 'V': 172 version(); 173 /* NOT REACHED */ 174 case OPTION_HELP: 175 default: 176 usage(); 177 /* NOT REACHED */ 178 } 179 } 180 181 argv += optind; 182 argc -= optind; 183 184 if (*argv != NULL) { 185 for (i = 0; i < argc; i++) { 186 if ((dem = demangle(argv[i], 1, NULL)) == NULL) 187 fprintf(stderr, "Failed: %s\n", argv[i]); 188 else 189 printf("%s\n", dem); 190 } 191 } else { 192 p = 0; 193 for (;;) { 194 c = fgetc(stdin); 195 if (c == EOF || !isprint(c) || strchr(" \t\n", c)) { 196 if (p > 0) { 197 buf[p] = '\0'; 198 if ((dem = demangle(buf, 0, &s)) == 199 NULL) 200 printf("%s", buf); 201 else { 202 printf("%s", dem); 203 for (i = s; i < p; i++) 204 putchar(buf[i]); 205 } 206 p = 0; 207 } 208 if (c == EOF) 209 break; 210 if (isprint(c) || strchr(" \t\n", c)) 211 putchar(c); 212 } else { 213 if ((size_t) p >= sizeof(buf) - 1) 214 warnx("buffer overflowed"); 215 else 216 buf[p++] = c; 217 } 218 219 } 220 } 221 222 exit(0); 223 } 224