1/* Demangler for GNU C++
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
7This file is part of the libiberty library.
8Libiberty is free software; you can redistribute it and/or
9modify it under the terms of the GNU Library General Public
10License as published by the Free Software Foundation; either
11version 2 of the License, or (at your option) any later version.
12
13In addition to the permissions in the GNU Library General Public
14License, the Free Software Foundation gives you unlimited permission
15to link the compiled version of this file into combinations with other
16programs, and to distribute those combinations without any restriction
17coming from the use of this file.  (The Library Public License
18restrictions do apply in other respects; for example, they cover
19modification of the file, and distribution when not linked into a
20combined executable.)
21
22Libiberty is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25Library General Public License for more details.
26
27You should have received a copy of the GNU Library General Public
28License along with libiberty; see the file COPYING.LIB.  If
29not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
30Boston, MA 02110-1301, USA.  */
31
32/* This file lives in both GCC and libiberty.  When making changes, please
33   try not to break either.  */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "safe-ctype.h"
40
41#include <string.h>
42
43#ifdef HAVE_STDLIB_H
44#include <stdlib.h>
45#else
46void * malloc ();
47void * realloc ();
48#endif
49
50#include <demangle.h>
51#undef CURRENT_DEMANGLING_STYLE
52#define CURRENT_DEMANGLING_STYLE options
53
54#include "libiberty.h"
55
56enum demangling_styles current_demangling_style = auto_demangling;
57
58const struct demangler_engine libiberty_demanglers[] =
59{
60  {
61    NO_DEMANGLING_STYLE_STRING,
62    no_demangling,
63    "Demangling disabled"
64  }
65  ,
66  {
67    AUTO_DEMANGLING_STYLE_STRING,
68      auto_demangling,
69      "Automatic selection based on executable"
70  }
71  ,
72  {
73    GNU_V3_DEMANGLING_STYLE_STRING,
74    gnu_v3_demangling,
75    "GNU (g++) V3 (Itanium C++ ABI) style demangling"
76  }
77  ,
78  {
79    JAVA_DEMANGLING_STYLE_STRING,
80    java_demangling,
81    "Java style demangling"
82  }
83  ,
84  {
85    GNAT_DEMANGLING_STYLE_STRING,
86    gnat_demangling,
87    "GNAT style demangling"
88  }
89  ,
90  {
91    DLANG_DEMANGLING_STYLE_STRING,
92    dlang_demangling,
93    "DLANG style demangling"
94  }
95  ,
96  {
97    RUST_DEMANGLING_STYLE_STRING,
98    rust_demangling,
99    "Rust style demangling"
100  }
101  ,
102  {
103    NULL, unknown_demangling, NULL
104  }
105};
106
107/* Add a routine to set the demangling style to be sure it is valid and
108   allow for any demangler initialization that maybe necessary. */
109
110enum demangling_styles
111cplus_demangle_set_style (enum demangling_styles style)
112{
113  const struct demangler_engine *demangler = libiberty_demanglers;
114
115  for (; demangler->demangling_style != unknown_demangling; ++demangler)
116    if (style == demangler->demangling_style)
117      {
118	current_demangling_style = style;
119	return current_demangling_style;
120      }
121
122  return unknown_demangling;
123}
124
125/* Do string name to style translation */
126
127enum demangling_styles
128cplus_demangle_name_to_style (const char *name)
129{
130  const struct demangler_engine *demangler = libiberty_demanglers;
131
132  for (; demangler->demangling_style != unknown_demangling; ++demangler)
133    if (strcmp (name, demangler->demangling_style_name) == 0)
134      return demangler->demangling_style;
135
136  return unknown_demangling;
137}
138
139/* char *cplus_demangle (const char *mangled, int options)
140
141   If MANGLED is a mangled function name produced by GNU C++, then
142   a pointer to a @code{malloc}ed string giving a C++ representation
143   of the name will be returned; otherwise NULL will be returned.
144   It is the caller's responsibility to free the string which
145   is returned.
146
147   Note that any leading underscores, or other such characters prepended by
148   the compilation system, are presumed to have already been stripped from
149   MANGLED.  */
150
151char *
152cplus_demangle (const char *mangled, int options)
153{
154  char *ret;
155
156  if (current_demangling_style == no_demangling)
157    return xstrdup (mangled);
158
159  if ((options & DMGL_STYLE_MASK) == 0)
160    options |= (int) current_demangling_style & DMGL_STYLE_MASK;
161
162  /* The Rust demangling is implemented elsewhere.
163     Legacy Rust symbols overlap with GNU_V3, so try Rust first.  */
164  if (RUST_DEMANGLING || AUTO_DEMANGLING)
165    {
166      ret = rust_demangle (mangled, options);
167      if (ret || RUST_DEMANGLING)
168        return ret;
169    }
170
171  /* The V3 ABI demangling is implemented elsewhere.  */
172  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
173    {
174      ret = cplus_demangle_v3 (mangled, options);
175      if (ret || GNU_V3_DEMANGLING)
176	return ret;
177    }
178
179  if (JAVA_DEMANGLING)
180    {
181      ret = java_demangle_v3 (mangled);
182      if (ret)
183        return ret;
184    }
185
186  if (GNAT_DEMANGLING)
187    return ada_demangle (mangled, options);
188
189  if (DLANG_DEMANGLING)
190    {
191      ret = dlang_demangle (mangled, options);
192      if (ret)
193	return ret;
194    }
195
196  return (ret);
197}
198
199/* Demangle ada names.  The encoding is documented in gcc/ada/exp_dbug.ads.  */
200
201char *
202ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
203{
204  int len0;
205  const char* p;
206  char *d;
207  char *demangled = NULL;
208
209  /* Discard leading _ada_, which is used for library level subprograms.  */
210  if (strncmp (mangled, "_ada_", 5) == 0)
211    mangled += 5;
212
213  /* All ada unit names are lower-case.  */
214  if (!ISLOWER (mangled[0]))
215    goto unknown;
216
217  /* Most of the demangling will trivially remove chars.  Operator names
218     may add one char but because they are always preceeded by '__' which is
219     replaced by '.', they eventually never expand the size.
220     A few special names such as '___elabs' add a few chars (at most 7), but
221     they occur only once.  */
222  len0 = strlen (mangled) + 7 + 1;
223  demangled = XNEWVEC (char, len0);
224
225  d = demangled;
226  p = mangled;
227  while (1)
228    {
229      /* An entity names is expected.  */
230      if (ISLOWER (*p))
231        {
232          /* An identifier, which is always lower case.  */
233          do
234            *d++ = *p++;
235          while (ISLOWER(*p) || ISDIGIT (*p)
236                 || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1]))));
237        }
238      else if (p[0] == 'O')
239        {
240          /* An operator name.  */
241          static const char * const operators[][2] =
242            {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"},
243             {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"},
244             {"Oxor", "xor"},  {"Oeq", "="},       {"One", "/="},
245             {"Olt", "<"},     {"Ole", "<="},      {"Ogt", ">"},
246             {"Oge", ">="},    {"Oadd", "+"},      {"Osubtract", "-"},
247             {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"},
248             {"Oexpon", "**"}, {NULL, NULL}};
249          int k;
250
251          for (k = 0; operators[k][0] != NULL; k++)
252            {
253              size_t slen = strlen (operators[k][0]);
254              if (strncmp (p, operators[k][0], slen) == 0)
255                {
256                  p += slen;
257                  slen = strlen (operators[k][1]);
258                  *d++ = '"';
259                  memcpy (d, operators[k][1], slen);
260                  d += slen;
261                  *d++ = '"';
262                  break;
263                }
264            }
265          /* Operator not found.  */
266          if (operators[k][0] == NULL)
267            goto unknown;
268        }
269      else
270        {
271          /* Not a GNAT encoding.  */
272          goto unknown;
273        }
274
275      /* The name can be directly followed by some uppercase letters.  */
276      if (p[0] == 'T' && p[1] == 'K')
277        {
278          /* Task stuff.  */
279          if (p[2] == 'B' && p[3] == 0)
280            {
281              /* Subprogram for task body.  */
282              break;
283            }
284          else if (p[2] == '_' && p[3] == '_')
285            {
286              /* Inner declarations in a task.  */
287              p += 4;
288              *d++ = '.';
289              continue;
290            }
291          else
292            goto unknown;
293        }
294      if (p[0] == 'E' && p[1] == 0)
295        {
296          /* Exception name.  */
297          goto unknown;
298        }
299      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
300        {
301          /* Protected type subprogram.  */
302          break;
303        }
304      if ((*p == 'N' || *p == 'S') && p[1] == 0)
305        {
306          /* Enumerated type name table.  */
307          goto unknown;
308        }
309      if (p[0] == 'X')
310        {
311          /* Body nested.  */
312          p++;
313          while (p[0] == 'n' || p[0] == 'b')
314            p++;
315        }
316      if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0))
317        {
318          /* Stream operations.  */
319          const char *name;
320          switch (p[1])
321            {
322            case 'R':
323              name = "'Read";
324              break;
325            case 'W':
326              name = "'Write";
327              break;
328            case 'I':
329              name = "'Input";
330              break;
331            case 'O':
332              name = "'Output";
333              break;
334            default:
335              goto unknown;
336            }
337          p += 2;
338          strcpy (d, name);
339          d += strlen (name);
340        }
341      else if (p[0] == 'D')
342        {
343          /* Controlled type operation.  */
344          const char *name;
345          switch (p[1])
346            {
347            case 'F':
348              name = ".Finalize";
349              break;
350            case 'A':
351              name = ".Adjust";
352              break;
353            default:
354              goto unknown;
355            }
356          strcpy (d, name);
357          d += strlen (name);
358          break;
359        }
360
361      if (p[0] == '_')
362        {
363          /* Separator.  */
364          if (p[1] == '_')
365            {
366              /* Standard separator.  Handled first.  */
367              p += 2;
368
369              if (ISDIGIT (*p))
370                {
371                  /* Overloading number.  */
372                  do
373                    p++;
374                  while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
375                  if (*p == 'X')
376                    {
377                      p++;
378                      while (p[0] == 'n' || p[0] == 'b')
379                        p++;
380                    }
381                }
382              else if (p[0] == '_' && p[1] != '_')
383                {
384                  /* Special names.  */
385                  static const char * const special[][2] = {
386                    { "_elabb", "'Elab_Body" },
387                    { "_elabs", "'Elab_Spec" },
388                    { "_size", "'Size" },
389                    { "_alignment", "'Alignment" },
390                    { "_assign", ".\":=\"" },
391                    { NULL, NULL }
392                  };
393                  int k;
394
395                  for (k = 0; special[k][0] != NULL; k++)
396                    {
397                      size_t slen = strlen (special[k][0]);
398                      if (strncmp (p, special[k][0], slen) == 0)
399                        {
400                          p += slen;
401                          slen = strlen (special[k][1]);
402                          memcpy (d, special[k][1], slen);
403                          d += slen;
404                          break;
405                        }
406                    }
407                  if (special[k][0] != NULL)
408                    break;
409                  else
410                    goto unknown;
411                }
412              else
413                {
414                  *d++ = '.';
415                  continue;
416                }
417            }
418          else if (p[1] == 'B' || p[1] == 'E')
419            {
420              /* Entry Body or barrier Evaluation.  */
421              p += 2;
422              while (ISDIGIT (*p))
423                p++;
424              if (p[0] == 's' && p[1] == 0)
425                break;
426              else
427                goto unknown;
428            }
429          else
430            goto unknown;
431        }
432
433      if (p[0] == '.' && ISDIGIT (p[1]))
434        {
435          /* Nested subprogram.  */
436          p += 2;
437          while (ISDIGIT (*p))
438            p++;
439        }
440      if (*p == 0)
441        {
442          /* End of mangled name.  */
443          break;
444        }
445      else
446        goto unknown;
447    }
448  *d = 0;
449  return demangled;
450
451 unknown:
452  XDELETEVEC (demangled);
453  len0 = strlen (mangled);
454  demangled = XNEWVEC (char, len0 + 3);
455
456  if (mangled[0] == '<')
457     strcpy (demangled, mangled);
458  else
459    sprintf (demangled, "<%s>", mangled);
460
461  return demangled;
462}
463