|  | /* Demangler for GNU C++ | 
|  | Copyright (C) 1989-2022 Free Software Foundation, Inc. | 
|  | Written by James Clark (jjc@jclark.uucp) | 
|  | Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling | 
|  | Modified by Satish Pai (pai@apollo.hp.com) for HP demangling | 
|  |  | 
|  | This file is part of the libiberty library. | 
|  | Libiberty is free software; you can redistribute it and/or | 
|  | modify it under the terms of the GNU Library General Public | 
|  | License as published by the Free Software Foundation; either | 
|  | version 2 of the License, or (at your option) any later version. | 
|  |  | 
|  | In addition to the permissions in the GNU Library General Public | 
|  | License, the Free Software Foundation gives you unlimited permission | 
|  | to link the compiled version of this file into combinations with other | 
|  | programs, and to distribute those combinations without any restriction | 
|  | coming from the use of this file.  (The Library Public License | 
|  | restrictions do apply in other respects; for example, they cover | 
|  | modification of the file, and distribution when not linked into a | 
|  | combined executable.) | 
|  |  | 
|  | Libiberty is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | Library General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU Library General Public | 
|  | License along with libiberty; see the file COPYING.LIB.  If | 
|  | not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, | 
|  | Boston, MA 02110-1301, USA.  */ | 
|  |  | 
|  | /* This file lives in both GCC and libiberty.  When making changes, please | 
|  | try not to break either.  */ | 
|  |  | 
|  | #ifdef HAVE_CONFIG_H | 
|  | #include "config.h" | 
|  | #endif | 
|  |  | 
|  | #include "safe-ctype.h" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | #ifdef HAVE_STDLIB_H | 
|  | #include <stdlib.h> | 
|  | #else | 
|  | void * malloc (); | 
|  | void * realloc (); | 
|  | #endif | 
|  |  | 
|  | #include <demangle.h> | 
|  | #undef CURRENT_DEMANGLING_STYLE | 
|  | #define CURRENT_DEMANGLING_STYLE options | 
|  |  | 
|  | #include "libiberty.h" | 
|  |  | 
|  | enum demangling_styles current_demangling_style = auto_demangling; | 
|  |  | 
|  | const struct demangler_engine libiberty_demanglers[] = | 
|  | { | 
|  | { | 
|  | NO_DEMANGLING_STYLE_STRING, | 
|  | no_demangling, | 
|  | "Demangling disabled" | 
|  | } | 
|  | , | 
|  | { | 
|  | AUTO_DEMANGLING_STYLE_STRING, | 
|  | auto_demangling, | 
|  | "Automatic selection based on executable" | 
|  | } | 
|  | , | 
|  | { | 
|  | GNU_V3_DEMANGLING_STYLE_STRING, | 
|  | gnu_v3_demangling, | 
|  | "GNU (g++) V3 (Itanium C++ ABI) style demangling" | 
|  | } | 
|  | , | 
|  | { | 
|  | JAVA_DEMANGLING_STYLE_STRING, | 
|  | java_demangling, | 
|  | "Java style demangling" | 
|  | } | 
|  | , | 
|  | { | 
|  | GNAT_DEMANGLING_STYLE_STRING, | 
|  | gnat_demangling, | 
|  | "GNAT style demangling" | 
|  | } | 
|  | , | 
|  | { | 
|  | DLANG_DEMANGLING_STYLE_STRING, | 
|  | dlang_demangling, | 
|  | "DLANG style demangling" | 
|  | } | 
|  | , | 
|  | { | 
|  | RUST_DEMANGLING_STYLE_STRING, | 
|  | rust_demangling, | 
|  | "Rust style demangling" | 
|  | } | 
|  | , | 
|  | { | 
|  | NULL, unknown_demangling, NULL | 
|  | } | 
|  | }; | 
|  |  | 
|  | /* Add a routine to set the demangling style to be sure it is valid and | 
|  | allow for any demangler initialization that maybe necessary. */ | 
|  |  | 
|  | enum demangling_styles | 
|  | cplus_demangle_set_style (enum demangling_styles style) | 
|  | { | 
|  | const struct demangler_engine *demangler = libiberty_demanglers; | 
|  |  | 
|  | for (; demangler->demangling_style != unknown_demangling; ++demangler) | 
|  | if (style == demangler->demangling_style) | 
|  | { | 
|  | current_demangling_style = style; | 
|  | return current_demangling_style; | 
|  | } | 
|  |  | 
|  | return unknown_demangling; | 
|  | } | 
|  |  | 
|  | /* Do string name to style translation */ | 
|  |  | 
|  | enum demangling_styles | 
|  | cplus_demangle_name_to_style (const char *name) | 
|  | { | 
|  | const struct demangler_engine *demangler = libiberty_demanglers; | 
|  |  | 
|  | for (; demangler->demangling_style != unknown_demangling; ++demangler) | 
|  | if (strcmp (name, demangler->demangling_style_name) == 0) | 
|  | return demangler->demangling_style; | 
|  |  | 
|  | return unknown_demangling; | 
|  | } | 
|  |  | 
|  | /* char *cplus_demangle (const char *mangled, int options) | 
|  |  | 
|  | If MANGLED is a mangled function name produced by GNU C++, then | 
|  | a pointer to a @code{malloc}ed string giving a C++ representation | 
|  | of the name will be returned; otherwise NULL will be returned. | 
|  | It is the caller's responsibility to free the string which | 
|  | is returned. | 
|  |  | 
|  | Note that any leading underscores, or other such characters prepended by | 
|  | the compilation system, are presumed to have already been stripped from | 
|  | MANGLED.  */ | 
|  |  | 
|  | char * | 
|  | cplus_demangle (const char *mangled, int options) | 
|  | { | 
|  | char *ret; | 
|  |  | 
|  | if (current_demangling_style == no_demangling) | 
|  | return xstrdup (mangled); | 
|  |  | 
|  | if ((options & DMGL_STYLE_MASK) == 0) | 
|  | options |= (int) current_demangling_style & DMGL_STYLE_MASK; | 
|  |  | 
|  | /* The Rust demangling is implemented elsewhere. | 
|  | Legacy Rust symbols overlap with GNU_V3, so try Rust first.  */ | 
|  | if (RUST_DEMANGLING || AUTO_DEMANGLING) | 
|  | { | 
|  | ret = rust_demangle (mangled, options); | 
|  | if (ret || RUST_DEMANGLING) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* The V3 ABI demangling is implemented elsewhere.  */ | 
|  | if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) | 
|  | { | 
|  | ret = cplus_demangle_v3 (mangled, options); | 
|  | if (ret || GNU_V3_DEMANGLING) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (JAVA_DEMANGLING) | 
|  | { | 
|  | ret = java_demangle_v3 (mangled); | 
|  | if (ret) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (GNAT_DEMANGLING) | 
|  | return ada_demangle (mangled, options); | 
|  |  | 
|  | if (DLANG_DEMANGLING) | 
|  | { | 
|  | ret = dlang_demangle (mangled, options); | 
|  | if (ret) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return (ret); | 
|  | } | 
|  |  | 
|  | /* Demangle ada names.  The encoding is documented in gcc/ada/exp_dbug.ads.  */ | 
|  |  | 
|  | char * | 
|  | ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) | 
|  | { | 
|  | int len0; | 
|  | const char* p; | 
|  | char *d; | 
|  | char *demangled = NULL; | 
|  |  | 
|  | /* Discard leading _ada_, which is used for library level subprograms.  */ | 
|  | if (strncmp (mangled, "_ada_", 5) == 0) | 
|  | mangled += 5; | 
|  |  | 
|  | /* All ada unit names are lower-case.  */ | 
|  | if (!ISLOWER (mangled[0])) | 
|  | goto unknown; | 
|  |  | 
|  | /* Most of the demangling will trivially remove chars.  Operator names | 
|  | may add one char but because they are always preceeded by '__' which is | 
|  | replaced by '.', they eventually never expand the size. | 
|  | A few special names such as '___elabs' add a few chars (at most 7), but | 
|  | they occur only once.  */ | 
|  | len0 = strlen (mangled) + 7 + 1; | 
|  | demangled = XNEWVEC (char, len0); | 
|  |  | 
|  | d = demangled; | 
|  | p = mangled; | 
|  | while (1) | 
|  | { | 
|  | /* An entity names is expected.  */ | 
|  | if (ISLOWER (*p)) | 
|  | { | 
|  | /* An identifier, which is always lower case.  */ | 
|  | do | 
|  | *d++ = *p++; | 
|  | while (ISLOWER(*p) || ISDIGIT (*p) | 
|  | || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1])))); | 
|  | } | 
|  | else if (p[0] == 'O') | 
|  | { | 
|  | /* An operator name.  */ | 
|  | static const char * const operators[][2] = | 
|  | {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"}, | 
|  | {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"}, | 
|  | {"Oxor", "xor"},  {"Oeq", "="},       {"One", "/="}, | 
|  | {"Olt", "<"},     {"Ole", "<="},      {"Ogt", ">"}, | 
|  | {"Oge", ">="},    {"Oadd", "+"},      {"Osubtract", "-"}, | 
|  | {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"}, | 
|  | {"Oexpon", "**"}, {NULL, NULL}}; | 
|  | int k; | 
|  |  | 
|  | for (k = 0; operators[k][0] != NULL; k++) | 
|  | { | 
|  | size_t slen = strlen (operators[k][0]); | 
|  | if (strncmp (p, operators[k][0], slen) == 0) | 
|  | { | 
|  | p += slen; | 
|  | slen = strlen (operators[k][1]); | 
|  | *d++ = '"'; | 
|  | memcpy (d, operators[k][1], slen); | 
|  | d += slen; | 
|  | *d++ = '"'; | 
|  | break; | 
|  | } | 
|  | } | 
|  | /* Operator not found.  */ | 
|  | if (operators[k][0] == NULL) | 
|  | goto unknown; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Not a GNAT encoding.  */ | 
|  | goto unknown; | 
|  | } | 
|  |  | 
|  | /* The name can be directly followed by some uppercase letters.  */ | 
|  | if (p[0] == 'T' && p[1] == 'K') | 
|  | { | 
|  | /* Task stuff.  */ | 
|  | if (p[2] == 'B' && p[3] == 0) | 
|  | { | 
|  | /* Subprogram for task body.  */ | 
|  | break; | 
|  | } | 
|  | else if (p[2] == '_' && p[3] == '_') | 
|  | { | 
|  | /* Inner declarations in a task.  */ | 
|  | p += 4; | 
|  | *d++ = '.'; | 
|  | continue; | 
|  | } | 
|  | else | 
|  | goto unknown; | 
|  | } | 
|  | if (p[0] == 'E' && p[1] == 0) | 
|  | { | 
|  | /* Exception name.  */ | 
|  | goto unknown; | 
|  | } | 
|  | if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0) | 
|  | { | 
|  | /* Protected type subprogram.  */ | 
|  | break; | 
|  | } | 
|  | if ((*p == 'N' || *p == 'S') && p[1] == 0) | 
|  | { | 
|  | /* Enumerated type name table.  */ | 
|  | goto unknown; | 
|  | } | 
|  | if (p[0] == 'X') | 
|  | { | 
|  | /* Body nested.  */ | 
|  | p++; | 
|  | while (p[0] == 'n' || p[0] == 'b') | 
|  | p++; | 
|  | } | 
|  | if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0)) | 
|  | { | 
|  | /* Stream operations.  */ | 
|  | const char *name; | 
|  | switch (p[1]) | 
|  | { | 
|  | case 'R': | 
|  | name = "'Read"; | 
|  | break; | 
|  | case 'W': | 
|  | name = "'Write"; | 
|  | break; | 
|  | case 'I': | 
|  | name = "'Input"; | 
|  | break; | 
|  | case 'O': | 
|  | name = "'Output"; | 
|  | break; | 
|  | default: | 
|  | goto unknown; | 
|  | } | 
|  | p += 2; | 
|  | strcpy (d, name); | 
|  | d += strlen (name); | 
|  | } | 
|  | else if (p[0] == 'D') | 
|  | { | 
|  | /* Controlled type operation.  */ | 
|  | const char *name; | 
|  | switch (p[1]) | 
|  | { | 
|  | case 'F': | 
|  | name = ".Finalize"; | 
|  | break; | 
|  | case 'A': | 
|  | name = ".Adjust"; | 
|  | break; | 
|  | default: | 
|  | goto unknown; | 
|  | } | 
|  | strcpy (d, name); | 
|  | d += strlen (name); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (p[0] == '_') | 
|  | { | 
|  | /* Separator.  */ | 
|  | if (p[1] == '_') | 
|  | { | 
|  | /* Standard separator.  Handled first.  */ | 
|  | p += 2; | 
|  |  | 
|  | if (ISDIGIT (*p)) | 
|  | { | 
|  | /* Overloading number.  */ | 
|  | do | 
|  | p++; | 
|  | while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1]))); | 
|  | if (*p == 'X') | 
|  | { | 
|  | p++; | 
|  | while (p[0] == 'n' || p[0] == 'b') | 
|  | p++; | 
|  | } | 
|  | } | 
|  | else if (p[0] == '_' && p[1] != '_') | 
|  | { | 
|  | /* Special names.  */ | 
|  | static const char * const special[][2] = { | 
|  | { "_elabb", "'Elab_Body" }, | 
|  | { "_elabs", "'Elab_Spec" }, | 
|  | { "_size", "'Size" }, | 
|  | { "_alignment", "'Alignment" }, | 
|  | { "_assign", ".\":=\"" }, | 
|  | { NULL, NULL } | 
|  | }; | 
|  | int k; | 
|  |  | 
|  | for (k = 0; special[k][0] != NULL; k++) | 
|  | { | 
|  | size_t slen = strlen (special[k][0]); | 
|  | if (strncmp (p, special[k][0], slen) == 0) | 
|  | { | 
|  | p += slen; | 
|  | slen = strlen (special[k][1]); | 
|  | memcpy (d, special[k][1], slen); | 
|  | d += slen; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (special[k][0] != NULL) | 
|  | break; | 
|  | else | 
|  | goto unknown; | 
|  | } | 
|  | else | 
|  | { | 
|  | *d++ = '.'; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | else if (p[1] == 'B' || p[1] == 'E') | 
|  | { | 
|  | /* Entry Body or barrier Evaluation.  */ | 
|  | p += 2; | 
|  | while (ISDIGIT (*p)) | 
|  | p++; | 
|  | if (p[0] == 's' && p[1] == 0) | 
|  | break; | 
|  | else | 
|  | goto unknown; | 
|  | } | 
|  | else | 
|  | goto unknown; | 
|  | } | 
|  |  | 
|  | if (p[0] == '.' && ISDIGIT (p[1])) | 
|  | { | 
|  | /* Nested subprogram.  */ | 
|  | p += 2; | 
|  | while (ISDIGIT (*p)) | 
|  | p++; | 
|  | } | 
|  | if (*p == 0) | 
|  | { | 
|  | /* End of mangled name.  */ | 
|  | break; | 
|  | } | 
|  | else | 
|  | goto unknown; | 
|  | } | 
|  | *d = 0; | 
|  | return demangled; | 
|  |  | 
|  | unknown: | 
|  | XDELETEVEC (demangled); | 
|  | len0 = strlen (mangled); | 
|  | demangled = XNEWVEC (char, len0 + 3); | 
|  |  | 
|  | if (mangled[0] == '<') | 
|  | strcpy (demangled, mangled); | 
|  | else | 
|  | sprintf (demangled, "<%s>", mangled); | 
|  |  | 
|  | return demangled; | 
|  | } |