1 /* Demangler for GNU C++ - main program
2    Copyright (C) 1989-2020 Free Software Foundation, Inc.
3    Written by James Clark (jjc@jclark.uucp)
4    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
5    Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
6 
7    This file is part of GNU Binutils.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or (at
12    your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with GCC; see the file COPYING.  If not, write to the Free
21    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
22    02110-1301, USA.  */
23 
24 #include "sysdep.h"
25 #include "bfd.h"
26 #include "libiberty.h"
27 #include "demangle.h"
28 #include "getopt.h"
29 #include "safe-ctype.h"
30 #include "bucomm.h"
31 
32 static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
33 static int strip_underscore = TARGET_PREPENDS_UNDERSCORE;
34 
35 static const struct option long_options[] =
36 {
37   {"strip-underscore", no_argument, NULL, '_'},
38   {"format", required_argument, NULL, 's'},
39   {"help", no_argument, NULL, 'h'},
40   {"no-params", no_argument, NULL, 'p'},
41   {"no-strip-underscores", no_argument, NULL, 'n'},
42   {"no-verbose", no_argument, NULL, 'i'},
43   {"types", no_argument, NULL, 't'},
44   {"version", no_argument, NULL, 'v'},
45   {"recurse-limit", no_argument, NULL, 'R'},
46   {"recursion-limit", no_argument, NULL, 'R'},
47   {"no-recurse-limit", no_argument, NULL, 'r'},
48   {"no-recursion-limit", no_argument, NULL, 'r'},
49   {NULL, no_argument, NULL, 0}
50 };
51 
52 static void
53 demangle_it (char *mangled_name)
54 {
55   char *result;
56   unsigned int skip_first = 0;
57 
58   /* _ and $ are sometimes found at the start of function names
59      in assembler sources in order to distinguish them from other
60      names (eg register names).  So skip them here.  */
61   if (mangled_name[0] == '.' || mangled_name[0] == '$')
62     ++skip_first;
63   if (strip_underscore && mangled_name[skip_first] == '_')
64     ++skip_first;
65 
66   result = cplus_demangle (mangled_name + skip_first, flags);
67 
68   if (result == NULL)
69     printf ("%s", mangled_name);
70   else
71     {
72       if (mangled_name[0] == '.')
73 	putchar ('.');
74       printf ("%s", result);
75       free (result);
76     }
77 }
78 
79 static void
80 print_demangler_list (FILE *stream)
81 {
82   const struct demangler_engine *demangler;
83 
84   fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
85 
86   for (demangler = libiberty_demanglers + 1;
87        demangler->demangling_style != unknown_demangling;
88        ++demangler)
89     fprintf (stream, ",%s", demangler->demangling_style_name);
90 
91   fprintf (stream, "}");
92 }
93 
94 ATTRIBUTE_NORETURN static void
95 usage (FILE *stream, int status)
96 {
97   fprintf (stream, "\
98 Usage: %s [options] [mangled names]\n", program_name);
99   fprintf (stream, "\
100 Options are:\n\
101   [-_|--strip-underscore]     Ignore first leading underscore%s\n",
102 	   TARGET_PREPENDS_UNDERSCORE ? " (default)" : "");
103   fprintf (stream, "\
104   [-n|--no-strip-underscore]  Do not ignore a leading underscore%s\n",
105 	   TARGET_PREPENDS_UNDERSCORE ? "" : " (default)");
106   fprintf (stream, "\
107   [-p|--no-params]            Do not display function arguments\n\
108   [-i|--no-verbose]           Do not show implementation details (if any)\n\
109   [-R|--recurse-limit]        Enable a limit on recursion whilst demangling.  [Default]\n\
110   ]-r|--no-recurse-limit]     Disable a limit on recursion whilst demangling\n\
111   [-t|--types]                Also attempt to demangle type encodings\n\
112   [-s|--format ");
113   print_demangler_list (stream);
114   fprintf (stream, "]\n");
115 
116   fprintf (stream, "\
117   [@<file>]                   Read extra options from <file>\n\
118   [-h|--help]                 Display this information\n\
119   [-v|--version]              Show the version information\n\
120 Demangled names are displayed to stdout.\n\
121 If a name cannot be demangled it is just echoed to stdout.\n\
122 If no names are provided on the command line, stdin is read.\n");
123   if (REPORT_BUGS_TO[0] && status == 0)
124     fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
125   exit (status);
126 }
127 
128 /* Return the string of non-alnum characters that may occur
129    as a valid symbol component, in the standard assembler symbol
130    syntax.  */
131 
132 static const char *
133 standard_symbol_characters (void)
134 {
135   return "_$.";
136 }
137 
138 extern int main (int, char **);
139 
140 int
141 main (int argc, char **argv)
142 {
143   int c;
144   const char *valid_symbols;
145   enum demangling_styles style = auto_demangling;
146 
147   program_name = argv[0];
148   xmalloc_set_program_name (program_name);
149   bfd_set_error_program_name (program_name);
150 
151   expandargv (&argc, &argv);
152 
153   while ((c = getopt_long (argc, argv, "_hinprRs:tv", long_options, (int *) 0)) != EOF)
154     {
155       switch (c)
156 	{
157 	case '?':
158 	  usage (stderr, 1);
159 	  break;
160 	case 'h':
161 	  usage (stdout, 0);
162 	case 'n':
163 	  strip_underscore = 0;
164 	  break;
165 	case 'p':
166 	  flags &= ~ DMGL_PARAMS;
167 	  break;
168 	case 'r':
169 	  flags |= DMGL_NO_RECURSE_LIMIT;
170 	  break;
171 	case 'R':
172 	  flags &= ~ DMGL_NO_RECURSE_LIMIT;
173 	  break;
174 	case 't':
175 	  flags |= DMGL_TYPES;
176 	  break;
177 	case 'i':
178 	  flags &= ~ DMGL_VERBOSE;
179 	  break;
180 	case 'v':
181 	  print_version ("c++filt");
182 	  return 0;
183 	case '_':
184 	  strip_underscore = 1;
185 	  break;
186 	case 's':
187 	  style = cplus_demangle_name_to_style (optarg);
188 	  if (style == unknown_demangling)
189 	    {
190 	      fprintf (stderr, "%s: unknown demangling style `%s'\n",
191 		       program_name, optarg);
192 	      return 1;
193 	    }
194 	  cplus_demangle_set_style (style);
195 	  break;
196 	}
197     }
198 
199   if (optind < argc)
200     {
201       for ( ; optind < argc; optind++)
202 	{
203 	  demangle_it (argv[optind]);
204 	  putchar ('\n');
205 	}
206 
207       return 0;
208     }
209 
210   switch (current_demangling_style)
211     {
212     case auto_demangling:
213     case gnu_v3_demangling:
214     case java_demangling:
215     case gnat_demangling:
216     case dlang_demangling:
217     case rust_demangling:
218        valid_symbols = standard_symbol_characters ();
219       break;
220     default:
221       /* Folks should explicitly indicate the appropriate alphabet for
222 	 each demangling.  Providing a default would allow the
223 	 question to go unconsidered.  */
224       fatal ("Internal error: no symbol alphabet for current style");
225     }
226 
227   for (;;)
228     {
229       static char mbuffer[32767];
230       unsigned i = 0;
231 
232       c = getchar ();
233       /* Try to read a mangled name.  */
234       while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
235 	{
236 	  if (i >= sizeof (mbuffer) - 1)
237 	    break;
238 	  mbuffer[i++] = c;
239 	  c = getchar ();
240 	}
241 
242       if (i > 0)
243 	{
244 	  mbuffer[i] = 0;
245 	  demangle_it (mbuffer);
246 	}
247 
248       if (c == EOF)
249 	break;
250 
251       /* Echo the whitespace characters so that the output looks
252 	 like the input, only with the mangled names demangled.  */
253       putchar (c);
254       if (c == '\n')
255 	fflush (stdout);
256     }
257 
258   fflush (stdout);
259   return 0;
260 }
261