1 | /* Demangler for GNU C++ |
2 | Copyright (C) 1989-2024 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 | |
56 | enum demangling_styles current_demangling_style = auto_demangling; |
57 | |
58 | const struct demangler_engine libiberty_demanglers[] = |
59 | { |
60 | { |
61 | NO_DEMANGLING_STYLE_STRING, |
62 | .demangling_style: no_demangling, |
63 | .demangling_style_doc: "Demangling disabled" |
64 | } |
65 | , |
66 | { |
67 | AUTO_DEMANGLING_STYLE_STRING, |
68 | .demangling_style: auto_demangling, |
69 | .demangling_style_doc: "Automatic selection based on executable" |
70 | } |
71 | , |
72 | { |
73 | GNU_V3_DEMANGLING_STYLE_STRING, |
74 | .demangling_style: gnu_v3_demangling, |
75 | .demangling_style_doc: "GNU (g++) V3 (Itanium C++ ABI) style demangling" |
76 | } |
77 | , |
78 | { |
79 | JAVA_DEMANGLING_STYLE_STRING, |
80 | .demangling_style: java_demangling, |
81 | .demangling_style_doc: "Java style demangling" |
82 | } |
83 | , |
84 | { |
85 | GNAT_DEMANGLING_STYLE_STRING, |
86 | .demangling_style: gnat_demangling, |
87 | .demangling_style_doc: "GNAT style demangling" |
88 | } |
89 | , |
90 | { |
91 | DLANG_DEMANGLING_STYLE_STRING, |
92 | .demangling_style: dlang_demangling, |
93 | .demangling_style_doc: "DLANG style demangling" |
94 | } |
95 | , |
96 | { |
97 | RUST_DEMANGLING_STYLE_STRING, |
98 | .demangling_style: rust_demangling, |
99 | .demangling_style_doc: "Rust style demangling" |
100 | } |
101 | , |
102 | { |
103 | NULL, .demangling_style: 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 | |
110 | enum demangling_styles |
111 | cplus_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 | |
127 | enum demangling_styles |
128 | cplus_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 (s1: name, s2: 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 | |
151 | char * |
152 | cplus_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 || AUTO_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 | |
201 | char * |
202 | ada_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 (s1: mangled, s2: "_ada_" , n: 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 (s: 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 (s: operators[k][0]); |
254 | if (strncmp (s1: p, s2: operators[k][0], n: slen) == 0) |
255 | { |
256 | p += slen; |
257 | slen = strlen (s: operators[k][1]); |
258 | *d++ = '"'; |
259 | memcpy (dest: d, src: operators[k][1], n: 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 (dest: d, src: name); |
339 | d += strlen (s: 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 (dest: d, src: name); |
357 | d += strlen (s: 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 (s: special[k][0]); |
398 | if (strncmp (s1: p, s2: special[k][0], n: slen) == 0) |
399 | { |
400 | p += slen; |
401 | slen = strlen (s: special[k][1]); |
402 | memcpy (dest: d, src: special[k][1], n: 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 (s: mangled); |
454 | demangled = XNEWVEC (char, len0 + 3); |
455 | |
456 | if (mangled[0] == '<') |
457 | strcpy (dest: demangled, src: mangled); |
458 | else |
459 | sprintf (s: demangled, format: "<%s>" , mangled); |
460 | |
461 | return demangled; |
462 | } |
463 | |