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