1130561Sobrien/* Demangler for GNU C++ - main program
2130561Sobrien   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
4130561Sobrien   Written by James Clark (jjc@jclark.uucp)
5130561Sobrien   Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
6130561Sobrien   Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
7130561Sobrien
8218822Sdim   This file is part of GCC.
9130561Sobrien
10218822Sdim   GCC is free software; you can redistribute it and/or modify it under
11218822Sdim   the terms of the GNU General Public License as published by the Free
12218822Sdim   Software Foundation; either version 2, or (at your option) any later
13218822Sdim   version.
14130561Sobrien
15218822Sdim   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16218822Sdim   WARRANTY; without even the implied warranty of MERCHANTABILITY or
17218822Sdim   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18218822Sdim   for more details.
19130561Sobrien
20218822Sdim   You should have received a copy of the GNU General Public License
21218822Sdim   along with GCC; see the file COPYING.  If not, write to the Free
22218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
23218822Sdim   02110-1301, USA.  */
24130561Sobrien
25218822Sdim#include "sysdep.h"
26130561Sobrien#include "bfd.h"
27130561Sobrien#include "libiberty.h"
28130561Sobrien#include "demangle.h"
29130561Sobrien#include "getopt.h"
30130561Sobrien#include "safe-ctype.h"
31218822Sdim#include "bucomm.h"
32130561Sobrien
33130561Sobrienstatic int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
34218822Sdimstatic int strip_underscore = TARGET_PREPENDS_UNDERSCORE;
35130561Sobrien
36218822Sdimstatic const struct option long_options[] =
37218822Sdim{
38218822Sdim  {"strip-underscore", no_argument, NULL, '_'},
39218822Sdim  {"format", required_argument, NULL, 's'},
40218822Sdim  {"help", no_argument, NULL, 'h'},
41218822Sdim  {"no-params", no_argument, NULL, 'p'},
42218822Sdim  {"no-strip-underscores", no_argument, NULL, 'n'},
43218822Sdim  {"no-verbose", no_argument, NULL, 'i'},
44218822Sdim  {"types", no_argument, NULL, 't'},
45218822Sdim  {"version", no_argument, NULL, 'v'},
46218822Sdim  {NULL, no_argument, NULL, 0}
47218822Sdim};
48130561Sobrien
49130561Sobrienstatic void
50130561Sobriendemangle_it (char *mangled_name)
51130561Sobrien{
52130561Sobrien  char *result;
53218822Sdim  unsigned int skip_first = 0;
54130561Sobrien
55218822Sdim  /* _ and $ are sometimes found at the start of function names
56218822Sdim     in assembler sources in order to distinguish them from other
57218822Sdim     names (eg register names).  So skip them here.  */
58218822Sdim  if (mangled_name[0] == '.' || mangled_name[0] == '$')
59218822Sdim    ++skip_first;
60218822Sdim  if (strip_underscore && mangled_name[skip_first] == '_')
61218822Sdim    ++skip_first;
62218822Sdim
63218822Sdim  result = cplus_demangle (mangled_name + skip_first, flags);
64218822Sdim
65130561Sobrien  if (result == NULL)
66259694Spfg    printf ("%s",mangled_name);
67130561Sobrien  else
68130561Sobrien    {
69218822Sdim      if (mangled_name[0] == '.')
70218822Sdim	putchar ('.');
71259694Spfg      printf ("%s",result);
72130561Sobrien      free (result);
73130561Sobrien    }
74130561Sobrien}
75130561Sobrien
76130561Sobrienstatic void
77130561Sobrienprint_demangler_list (FILE *stream)
78130561Sobrien{
79130561Sobrien  const struct demangler_engine *demangler;
80130561Sobrien
81130561Sobrien  fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
82130561Sobrien
83130561Sobrien  for (demangler = libiberty_demanglers + 1;
84130561Sobrien       demangler->demangling_style != unknown_demangling;
85130561Sobrien       ++demangler)
86130561Sobrien    fprintf (stream, ",%s", demangler->demangling_style_name);
87130561Sobrien
88130561Sobrien  fprintf (stream, "}");
89130561Sobrien}
90130561Sobrien
91130561Sobrienstatic void
92130561Sobrienusage (FILE *stream, int status)
93130561Sobrien{
94130561Sobrien  fprintf (stream, "\
95218822SdimUsage: %s [options] [mangled names]\n", program_name);
96130561Sobrien  fprintf (stream, "\
97218822SdimOptions are:\n\
98218822Sdim  [-_|--strip-underscore]     Ignore first leading underscore%s\n",
99218822Sdim	   TARGET_PREPENDS_UNDERSCORE ? " (default)" : "");
100130561Sobrien  fprintf (stream, "\
101218822Sdim  [-n|--no-strip-underscore]  Do not ignore a leading underscore%s\n",
102218822Sdim	   TARGET_PREPENDS_UNDERSCORE ? "" : " (default)");
103218822Sdim  fprintf (stream, "\
104218822Sdim  [-p|--no-params]            Do not display function arguments\n\
105218822Sdim  [-i|--no-verbose]           Do not show implementation details (if any)\n\
106218822Sdim  [-t|--types]                Also attempt to demangle type encodings\n\
107218822Sdim  [-s|--format ");
108130561Sobrien  print_demangler_list (stream);
109130561Sobrien  fprintf (stream, "]\n");
110130561Sobrien
111130561Sobrien  fprintf (stream, "\
112218822Sdim  [@<file>]                   Read extra options from <file>\n\
113218822Sdim  [-h|--help]                 Display this information\n\
114218822Sdim  [-v|--version]              Show the version information\n\
115218822SdimDemangled names are displayed to stdout.\n\
116218822SdimIf a name cannot be demangled it is just echoed to stdout.\n\
117218822SdimIf no names are provided on the command line, stdin is read.\n");
118218822Sdim  if (REPORT_BUGS_TO[0] && status == 0)
119218822Sdim    fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
120130561Sobrien  exit (status);
121130561Sobrien}
122130561Sobrien
123130561Sobrien/* Return the string of non-alnum characters that may occur
124130561Sobrien   as a valid symbol component, in the standard assembler symbol
125130561Sobrien   syntax.  */
126130561Sobrien
127130561Sobrienstatic const char *
128130561Sobrienstandard_symbol_characters (void)
129130561Sobrien{
130130561Sobrien  return "_$.";
131130561Sobrien}
132130561Sobrien
133130561Sobrien/* Return the string of non-alnum characters that may occur
134130561Sobrien   as a valid symbol name component in an HP object file.
135130561Sobrien
136130561Sobrien   Note that, since HP's compiler generates object code straight from
137130561Sobrien   C++ source, without going through an assembler, its mangled
138130561Sobrien   identifiers can use all sorts of characters that no assembler would
139130561Sobrien   tolerate, so the alphabet this function creates is a little odd.
140130561Sobrien   Here are some sample mangled identifiers offered by HP:
141130561Sobrien
142130561Sobrien	typeid*__XT24AddressIndExpClassMember_
143130561Sobrien	[Vftptr]key:__dt__32OrdinaryCompareIndExpClassMemberFv
144130561Sobrien	__ct__Q2_9Elf64_Dyn18{unnamed.union.#1}Fv
145130561Sobrien
146130561Sobrien   This still seems really weird to me, since nowhere else in this
147130561Sobrien   file is there anything to recognize curly brackets, parens, etc.
148130561Sobrien   I've talked with Srikanth <srikanth@cup.hp.com>, and he assures me
149130561Sobrien   this is right, but I still strongly suspect that there's a
150130561Sobrien   misunderstanding here.
151130561Sobrien
152130561Sobrien   If we decide it's better for c++filt to use HP's assembler syntax
153130561Sobrien   to scrape identifiers out of its input, here's the definition of
154130561Sobrien   the symbol name syntax from the HP assembler manual:
155130561Sobrien
156130561Sobrien       Symbols are composed of uppercase and lowercase letters, decimal
157130561Sobrien       digits, dollar symbol, period (.), ampersand (&), pound sign(#) and
158130561Sobrien       underscore (_). A symbol can begin with a letter, digit underscore or
159130561Sobrien       dollar sign. If a symbol begins with a digit, it must contain a
160130561Sobrien       non-digit character.
161130561Sobrien
162130561Sobrien   So have fun.  */
163130561Sobrienstatic const char *
164130561Sobrienhp_symbol_characters (void)
165130561Sobrien{
166130561Sobrien  return "_$.<>#,*&[]:(){}";
167130561Sobrien}
168130561Sobrien
169130561Sobrienextern int main (int, char **);
170130561Sobrien
171130561Sobrienint
172130561Sobrienmain (int argc, char **argv)
173130561Sobrien{
174130561Sobrien  int c;
175130561Sobrien  const char *valid_symbols;
176130561Sobrien  enum demangling_styles style = auto_demangling;
177130561Sobrien
178130561Sobrien  program_name = argv[0];
179130561Sobrien  xmalloc_set_program_name (program_name);
180130561Sobrien
181218822Sdim  expandargv (&argc, &argv);
182130561Sobrien
183218822Sdim  while ((c = getopt_long (argc, argv, "_hinps:tv", long_options, (int *) 0)) != EOF)
184130561Sobrien    {
185130561Sobrien      switch (c)
186130561Sobrien	{
187130561Sobrien	case '?':
188130561Sobrien	  usage (stderr, 1);
189130561Sobrien	  break;
190130561Sobrien	case 'h':
191130561Sobrien	  usage (stdout, 0);
192130561Sobrien	case 'n':
193130561Sobrien	  strip_underscore = 0;
194130561Sobrien	  break;
195130561Sobrien	case 'p':
196130561Sobrien	  flags &= ~ DMGL_PARAMS;
197130561Sobrien	  break;
198218822Sdim	case 't':
199218822Sdim	  flags |= DMGL_TYPES;
200218822Sdim	  break;
201218822Sdim	case 'i':
202218822Sdim	  flags &= ~ DMGL_VERBOSE;
203218822Sdim	  break;
204130561Sobrien	case 'v':
205130561Sobrien	  print_version ("c++filt");
206218822Sdim	  return 0;
207130561Sobrien	case '_':
208130561Sobrien	  strip_underscore = 1;
209130561Sobrien	  break;
210130561Sobrien	case 's':
211218822Sdim	  style = cplus_demangle_name_to_style (optarg);
212218822Sdim	  if (style == unknown_demangling)
213218822Sdim	    {
214218822Sdim	      fprintf (stderr, "%s: unknown demangling style `%s'\n",
215218822Sdim		       program_name, optarg);
216218822Sdim	      return 1;
217218822Sdim	    }
218218822Sdim	  cplus_demangle_set_style (style);
219130561Sobrien	  break;
220130561Sobrien	}
221130561Sobrien    }
222130561Sobrien
223130561Sobrien  if (optind < argc)
224130561Sobrien    {
225130561Sobrien      for ( ; optind < argc; optind++)
226130561Sobrien	{
227130561Sobrien	  demangle_it (argv[optind]);
228218822Sdim	  putchar ('\n');
229130561Sobrien	}
230218822Sdim
231218822Sdim      return 0;
232130561Sobrien    }
233218822Sdim
234218822Sdim  switch (current_demangling_style)
235130561Sobrien    {
236218822Sdim    case gnu_demangling:
237218822Sdim    case lucid_demangling:
238218822Sdim    case arm_demangling:
239218822Sdim    case java_demangling:
240218822Sdim    case edg_demangling:
241218822Sdim    case gnat_demangling:
242218822Sdim    case gnu_v3_demangling:
243218822Sdim    case auto_demangling:
244218822Sdim      valid_symbols = standard_symbol_characters ();
245218822Sdim      break;
246218822Sdim    case hp_demangling:
247218822Sdim      valid_symbols = hp_symbol_characters ();
248218822Sdim      break;
249218822Sdim    default:
250218822Sdim      /* Folks should explicitly indicate the appropriate alphabet for
251218822Sdim	 each demangling.  Providing a default would allow the
252218822Sdim	 question to go unconsidered.  */
253218822Sdim      fatal ("Internal error: no symbol alphabet for current style");
254218822Sdim    }
255218822Sdim
256218822Sdim  for (;;)
257218822Sdim    {
258218822Sdim      static char mbuffer[32767];
259218822Sdim      unsigned i = 0;
260218822Sdim
261218822Sdim      c = getchar ();
262218822Sdim      /* Try to read a mangled name.  */
263218822Sdim      while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
264130561Sobrien	{
265218822Sdim	  if (i >= sizeof (mbuffer) - 1)
266218822Sdim	    break;
267218822Sdim	  mbuffer[i++] = c;
268218822Sdim	  c = getchar ();
269130561Sobrien	}
270130561Sobrien
271218822Sdim      if (i > 0)
272130561Sobrien	{
273218822Sdim	  mbuffer[i] = 0;
274218822Sdim	  demangle_it (mbuffer);
275218822Sdim	}
276130561Sobrien
277218822Sdim      if (c == EOF)
278218822Sdim	break;
279130561Sobrien
280218822Sdim      /* Echo the whitespace characters so that the output looks
281218822Sdim	 like the input, only with the mangled names demangled.  */
282218822Sdim      putchar (c);
283218822Sdim      if (c == '\n')
284218822Sdim	fflush (stdout);
285130561Sobrien    }
286130561Sobrien
287218822Sdim  fflush (stdout);
288218822Sdim  return 0;
289130561Sobrien}
290