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