198b9484cSchristos /* Demangler for GNU C++ 2*5173eb0aSchristos Copyright (C) 1989-2024 Free Software Foundation, Inc. 398b9484cSchristos Written by James Clark (jjc@jclark.uucp) 498b9484cSchristos Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling 598b9484cSchristos Modified by Satish Pai (pai@apollo.hp.com) for HP demangling 698b9484cSchristos 798b9484cSchristos This file is part of the libiberty library. 898b9484cSchristos Libiberty is free software; you can redistribute it and/or 998b9484cSchristos modify it under the terms of the GNU Library General Public 1098b9484cSchristos License as published by the Free Software Foundation; either 1198b9484cSchristos version 2 of the License, or (at your option) any later version. 1298b9484cSchristos 1398b9484cSchristos In addition to the permissions in the GNU Library General Public 1498b9484cSchristos License, the Free Software Foundation gives you unlimited permission 1598b9484cSchristos to link the compiled version of this file into combinations with other 1698b9484cSchristos programs, and to distribute those combinations without any restriction 1798b9484cSchristos coming from the use of this file. (The Library Public License 1898b9484cSchristos restrictions do apply in other respects; for example, they cover 1998b9484cSchristos modification of the file, and distribution when not linked into a 2098b9484cSchristos combined executable.) 2198b9484cSchristos 2298b9484cSchristos Libiberty is distributed in the hope that it will be useful, 2398b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 2498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2598b9484cSchristos Library General Public License for more details. 2698b9484cSchristos 2798b9484cSchristos You should have received a copy of the GNU Library General Public 2898b9484cSchristos License along with libiberty; see the file COPYING.LIB. If 2998b9484cSchristos not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 3098b9484cSchristos Boston, MA 02110-1301, USA. */ 3198b9484cSchristos 3298b9484cSchristos /* This file lives in both GCC and libiberty. When making changes, please 3398b9484cSchristos try not to break either. */ 3498b9484cSchristos 3598b9484cSchristos #ifdef HAVE_CONFIG_H 3698b9484cSchristos #include "config.h" 3798b9484cSchristos #endif 3898b9484cSchristos 3998b9484cSchristos #include "safe-ctype.h" 4098b9484cSchristos 4198b9484cSchristos #include <string.h> 4298b9484cSchristos 4398b9484cSchristos #ifdef HAVE_STDLIB_H 4498b9484cSchristos #include <stdlib.h> 4598b9484cSchristos #else 4698b9484cSchristos void * malloc (); 4798b9484cSchristos void * realloc (); 4898b9484cSchristos #endif 4998b9484cSchristos 5098b9484cSchristos #include <demangle.h> 5198b9484cSchristos #undef CURRENT_DEMANGLING_STYLE 524559860eSchristos #define CURRENT_DEMANGLING_STYLE options 5398b9484cSchristos 5498b9484cSchristos #include "libiberty.h" 5598b9484cSchristos 5698b9484cSchristos enum demangling_styles current_demangling_style = auto_demangling; 5798b9484cSchristos 5898b9484cSchristos const struct demangler_engine libiberty_demanglers[] = 5998b9484cSchristos { 6098b9484cSchristos { 6198b9484cSchristos NO_DEMANGLING_STYLE_STRING, 6298b9484cSchristos no_demangling, 6398b9484cSchristos "Demangling disabled" 6498b9484cSchristos } 6598b9484cSchristos , 6698b9484cSchristos { 6798b9484cSchristos AUTO_DEMANGLING_STYLE_STRING, 6898b9484cSchristos auto_demangling, 6998b9484cSchristos "Automatic selection based on executable" 7098b9484cSchristos } 7198b9484cSchristos , 7298b9484cSchristos { 7398b9484cSchristos GNU_V3_DEMANGLING_STYLE_STRING, 7498b9484cSchristos gnu_v3_demangling, 754559860eSchristos "GNU (g++) V3 (Itanium C++ ABI) style demangling" 7698b9484cSchristos } 7798b9484cSchristos , 7898b9484cSchristos { 7998b9484cSchristos JAVA_DEMANGLING_STYLE_STRING, 8098b9484cSchristos java_demangling, 8198b9484cSchristos "Java style demangling" 8298b9484cSchristos } 8398b9484cSchristos , 8498b9484cSchristos { 8598b9484cSchristos GNAT_DEMANGLING_STYLE_STRING, 8698b9484cSchristos gnat_demangling, 8798b9484cSchristos "GNAT style demangling" 8898b9484cSchristos } 8998b9484cSchristos , 9098b9484cSchristos { 91837edd6bSchristos DLANG_DEMANGLING_STYLE_STRING, 92837edd6bSchristos dlang_demangling, 93837edd6bSchristos "DLANG style demangling" 94837edd6bSchristos } 95837edd6bSchristos , 96837edd6bSchristos { 97796c32c9Schristos RUST_DEMANGLING_STYLE_STRING, 98796c32c9Schristos rust_demangling, 99796c32c9Schristos "Rust style demangling" 100796c32c9Schristos } 101796c32c9Schristos , 102796c32c9Schristos { 10398b9484cSchristos NULL, unknown_demangling, NULL 10498b9484cSchristos } 10598b9484cSchristos }; 10698b9484cSchristos 10798b9484cSchristos /* Add a routine to set the demangling style to be sure it is valid and 10898b9484cSchristos allow for any demangler initialization that maybe necessary. */ 10998b9484cSchristos 11098b9484cSchristos enum demangling_styles 11198b9484cSchristos cplus_demangle_set_style (enum demangling_styles style) 11298b9484cSchristos { 11398b9484cSchristos const struct demangler_engine *demangler = libiberty_demanglers; 11498b9484cSchristos 11598b9484cSchristos for (; demangler->demangling_style != unknown_demangling; ++demangler) 11698b9484cSchristos if (style == demangler->demangling_style) 11798b9484cSchristos { 11898b9484cSchristos current_demangling_style = style; 11998b9484cSchristos return current_demangling_style; 12098b9484cSchristos } 12198b9484cSchristos 12298b9484cSchristos return unknown_demangling; 12398b9484cSchristos } 12498b9484cSchristos 12598b9484cSchristos /* Do string name to style translation */ 12698b9484cSchristos 12798b9484cSchristos enum demangling_styles 12898b9484cSchristos cplus_demangle_name_to_style (const char *name) 12998b9484cSchristos { 13098b9484cSchristos const struct demangler_engine *demangler = libiberty_demanglers; 13198b9484cSchristos 13298b9484cSchristos for (; demangler->demangling_style != unknown_demangling; ++demangler) 13398b9484cSchristos if (strcmp (name, demangler->demangling_style_name) == 0) 13498b9484cSchristos return demangler->demangling_style; 13598b9484cSchristos 13698b9484cSchristos return unknown_demangling; 13798b9484cSchristos } 13898b9484cSchristos 13998b9484cSchristos /* char *cplus_demangle (const char *mangled, int options) 14098b9484cSchristos 14198b9484cSchristos If MANGLED is a mangled function name produced by GNU C++, then 14298b9484cSchristos a pointer to a @code{malloc}ed string giving a C++ representation 14398b9484cSchristos of the name will be returned; otherwise NULL will be returned. 14498b9484cSchristos It is the caller's responsibility to free the string which 14598b9484cSchristos is returned. 14698b9484cSchristos 14798b9484cSchristos Note that any leading underscores, or other such characters prepended by 14898b9484cSchristos the compilation system, are presumed to have already been stripped from 14998b9484cSchristos MANGLED. */ 15098b9484cSchristos 15198b9484cSchristos char * 15298b9484cSchristos cplus_demangle (const char *mangled, int options) 15398b9484cSchristos { 15498b9484cSchristos char *ret; 15598b9484cSchristos 15698b9484cSchristos if (current_demangling_style == no_demangling) 15798b9484cSchristos return xstrdup (mangled); 15898b9484cSchristos 1594559860eSchristos if ((options & DMGL_STYLE_MASK) == 0) 1604559860eSchristos options |= (int) current_demangling_style & DMGL_STYLE_MASK; 16198b9484cSchristos 1628dffb485Schristos /* The Rust demangling is implemented elsewhere. 1638dffb485Schristos Legacy Rust symbols overlap with GNU_V3, so try Rust first. */ 1648dffb485Schristos if (RUST_DEMANGLING || AUTO_DEMANGLING) 1658dffb485Schristos { 1668dffb485Schristos ret = rust_demangle (mangled, options); 1678dffb485Schristos if (ret || RUST_DEMANGLING) 1688dffb485Schristos return ret; 1698dffb485Schristos } 1708dffb485Schristos 17198b9484cSchristos /* The V3 ABI demangling is implemented elsewhere. */ 1728dffb485Schristos if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) 17398b9484cSchristos { 1744559860eSchristos ret = cplus_demangle_v3 (mangled, options); 1758dffb485Schristos if (ret || GNU_V3_DEMANGLING) 17698b9484cSchristos return ret; 17798b9484cSchristos } 17898b9484cSchristos 17998b9484cSchristos if (JAVA_DEMANGLING) 18098b9484cSchristos { 18198b9484cSchristos ret = java_demangle_v3 (mangled); 18298b9484cSchristos if (ret) 18398b9484cSchristos return ret; 18498b9484cSchristos } 18598b9484cSchristos 18698b9484cSchristos if (GNAT_DEMANGLING) 18798b9484cSchristos return ada_demangle (mangled, options); 18898b9484cSchristos 189*5173eb0aSchristos if (DLANG_DEMANGLING || AUTO_DEMANGLING) 190837edd6bSchristos { 191837edd6bSchristos ret = dlang_demangle (mangled, options); 192837edd6bSchristos if (ret) 193837edd6bSchristos return ret; 194837edd6bSchristos } 195837edd6bSchristos 19698b9484cSchristos return (ret); 19798b9484cSchristos } 19898b9484cSchristos 19998b9484cSchristos /* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */ 20098b9484cSchristos 20198b9484cSchristos char * 20298b9484cSchristos ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) 20398b9484cSchristos { 20498b9484cSchristos int len0; 20598b9484cSchristos const char* p; 20698b9484cSchristos char *d; 207796c32c9Schristos char *demangled = NULL; 20898b9484cSchristos 20998b9484cSchristos /* Discard leading _ada_, which is used for library level subprograms. */ 21098b9484cSchristos if (strncmp (mangled, "_ada_", 5) == 0) 21198b9484cSchristos mangled += 5; 21298b9484cSchristos 21398b9484cSchristos /* All ada unit names are lower-case. */ 21498b9484cSchristos if (!ISLOWER (mangled[0])) 21598b9484cSchristos goto unknown; 21698b9484cSchristos 21798b9484cSchristos /* Most of the demangling will trivially remove chars. Operator names 21898b9484cSchristos may add one char but because they are always preceeded by '__' which is 21998b9484cSchristos replaced by '.', they eventually never expand the size. 22098b9484cSchristos A few special names such as '___elabs' add a few chars (at most 7), but 22198b9484cSchristos they occur only once. */ 22298b9484cSchristos len0 = strlen (mangled) + 7 + 1; 22398b9484cSchristos demangled = XNEWVEC (char, len0); 22498b9484cSchristos 22598b9484cSchristos d = demangled; 22698b9484cSchristos p = mangled; 22798b9484cSchristos while (1) 22898b9484cSchristos { 22998b9484cSchristos /* An entity names is expected. */ 23098b9484cSchristos if (ISLOWER (*p)) 23198b9484cSchristos { 23298b9484cSchristos /* An identifier, which is always lower case. */ 23398b9484cSchristos do 23498b9484cSchristos *d++ = *p++; 23598b9484cSchristos while (ISLOWER(*p) || ISDIGIT (*p) 23698b9484cSchristos || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1])))); 23798b9484cSchristos } 23898b9484cSchristos else if (p[0] == 'O') 23998b9484cSchristos { 24098b9484cSchristos /* An operator name. */ 24198b9484cSchristos static const char * const operators[][2] = 24298b9484cSchristos {{"Oabs", "abs"}, {"Oand", "and"}, {"Omod", "mod"}, 24398b9484cSchristos {"Onot", "not"}, {"Oor", "or"}, {"Orem", "rem"}, 24498b9484cSchristos {"Oxor", "xor"}, {"Oeq", "="}, {"One", "/="}, 24598b9484cSchristos {"Olt", "<"}, {"Ole", "<="}, {"Ogt", ">"}, 24698b9484cSchristos {"Oge", ">="}, {"Oadd", "+"}, {"Osubtract", "-"}, 24798b9484cSchristos {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"}, 24898b9484cSchristos {"Oexpon", "**"}, {NULL, NULL}}; 24998b9484cSchristos int k; 25098b9484cSchristos 25198b9484cSchristos for (k = 0; operators[k][0] != NULL; k++) 25298b9484cSchristos { 25398b9484cSchristos size_t slen = strlen (operators[k][0]); 25498b9484cSchristos if (strncmp (p, operators[k][0], slen) == 0) 25598b9484cSchristos { 25698b9484cSchristos p += slen; 25798b9484cSchristos slen = strlen (operators[k][1]); 25898b9484cSchristos *d++ = '"'; 25998b9484cSchristos memcpy (d, operators[k][1], slen); 26098b9484cSchristos d += slen; 26198b9484cSchristos *d++ = '"'; 26298b9484cSchristos break; 26398b9484cSchristos } 26498b9484cSchristos } 26598b9484cSchristos /* Operator not found. */ 26698b9484cSchristos if (operators[k][0] == NULL) 26798b9484cSchristos goto unknown; 26898b9484cSchristos } 26998b9484cSchristos else 27098b9484cSchristos { 27198b9484cSchristos /* Not a GNAT encoding. */ 27298b9484cSchristos goto unknown; 27398b9484cSchristos } 27498b9484cSchristos 27598b9484cSchristos /* The name can be directly followed by some uppercase letters. */ 27698b9484cSchristos if (p[0] == 'T' && p[1] == 'K') 27798b9484cSchristos { 27898b9484cSchristos /* Task stuff. */ 27998b9484cSchristos if (p[2] == 'B' && p[3] == 0) 28098b9484cSchristos { 28198b9484cSchristos /* Subprogram for task body. */ 28298b9484cSchristos break; 28398b9484cSchristos } 28498b9484cSchristos else if (p[2] == '_' && p[3] == '_') 28598b9484cSchristos { 28698b9484cSchristos /* Inner declarations in a task. */ 28798b9484cSchristos p += 4; 28898b9484cSchristos *d++ = '.'; 28998b9484cSchristos continue; 29098b9484cSchristos } 29198b9484cSchristos else 29298b9484cSchristos goto unknown; 29398b9484cSchristos } 29498b9484cSchristos if (p[0] == 'E' && p[1] == 0) 29598b9484cSchristos { 29698b9484cSchristos /* Exception name. */ 29798b9484cSchristos goto unknown; 29898b9484cSchristos } 29998b9484cSchristos if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0) 30098b9484cSchristos { 30198b9484cSchristos /* Protected type subprogram. */ 30298b9484cSchristos break; 30398b9484cSchristos } 30498b9484cSchristos if ((*p == 'N' || *p == 'S') && p[1] == 0) 30598b9484cSchristos { 30698b9484cSchristos /* Enumerated type name table. */ 30798b9484cSchristos goto unknown; 30898b9484cSchristos } 30998b9484cSchristos if (p[0] == 'X') 31098b9484cSchristos { 31198b9484cSchristos /* Body nested. */ 31298b9484cSchristos p++; 31398b9484cSchristos while (p[0] == 'n' || p[0] == 'b') 31498b9484cSchristos p++; 31598b9484cSchristos } 31698b9484cSchristos if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0)) 31798b9484cSchristos { 31898b9484cSchristos /* Stream operations. */ 31998b9484cSchristos const char *name; 32098b9484cSchristos switch (p[1]) 32198b9484cSchristos { 32298b9484cSchristos case 'R': 32398b9484cSchristos name = "'Read"; 32498b9484cSchristos break; 32598b9484cSchristos case 'W': 32698b9484cSchristos name = "'Write"; 32798b9484cSchristos break; 32898b9484cSchristos case 'I': 32998b9484cSchristos name = "'Input"; 33098b9484cSchristos break; 33198b9484cSchristos case 'O': 33298b9484cSchristos name = "'Output"; 33398b9484cSchristos break; 33498b9484cSchristos default: 33598b9484cSchristos goto unknown; 33698b9484cSchristos } 33798b9484cSchristos p += 2; 33898b9484cSchristos strcpy (d, name); 33998b9484cSchristos d += strlen (name); 34098b9484cSchristos } 34198b9484cSchristos else if (p[0] == 'D') 34298b9484cSchristos { 34398b9484cSchristos /* Controlled type operation. */ 34498b9484cSchristos const char *name; 34598b9484cSchristos switch (p[1]) 34698b9484cSchristos { 34798b9484cSchristos case 'F': 34898b9484cSchristos name = ".Finalize"; 34998b9484cSchristos break; 35098b9484cSchristos case 'A': 35198b9484cSchristos name = ".Adjust"; 35298b9484cSchristos break; 35398b9484cSchristos default: 35498b9484cSchristos goto unknown; 35598b9484cSchristos } 35698b9484cSchristos strcpy (d, name); 35798b9484cSchristos d += strlen (name); 35898b9484cSchristos break; 35998b9484cSchristos } 36098b9484cSchristos 36198b9484cSchristos if (p[0] == '_') 36298b9484cSchristos { 36398b9484cSchristos /* Separator. */ 36498b9484cSchristos if (p[1] == '_') 36598b9484cSchristos { 36698b9484cSchristos /* Standard separator. Handled first. */ 36798b9484cSchristos p += 2; 36898b9484cSchristos 36998b9484cSchristos if (ISDIGIT (*p)) 37098b9484cSchristos { 37198b9484cSchristos /* Overloading number. */ 37298b9484cSchristos do 37398b9484cSchristos p++; 37498b9484cSchristos while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1]))); 37598b9484cSchristos if (*p == 'X') 37698b9484cSchristos { 37798b9484cSchristos p++; 37898b9484cSchristos while (p[0] == 'n' || p[0] == 'b') 37998b9484cSchristos p++; 38098b9484cSchristos } 38198b9484cSchristos } 38298b9484cSchristos else if (p[0] == '_' && p[1] != '_') 38398b9484cSchristos { 38498b9484cSchristos /* Special names. */ 38598b9484cSchristos static const char * const special[][2] = { 38698b9484cSchristos { "_elabb", "'Elab_Body" }, 38798b9484cSchristos { "_elabs", "'Elab_Spec" }, 38898b9484cSchristos { "_size", "'Size" }, 38998b9484cSchristos { "_alignment", "'Alignment" }, 39098b9484cSchristos { "_assign", ".\":=\"" }, 39198b9484cSchristos { NULL, NULL } 39298b9484cSchristos }; 39398b9484cSchristos int k; 39498b9484cSchristos 39598b9484cSchristos for (k = 0; special[k][0] != NULL; k++) 39698b9484cSchristos { 39798b9484cSchristos size_t slen = strlen (special[k][0]); 39898b9484cSchristos if (strncmp (p, special[k][0], slen) == 0) 39998b9484cSchristos { 40098b9484cSchristos p += slen; 40198b9484cSchristos slen = strlen (special[k][1]); 40298b9484cSchristos memcpy (d, special[k][1], slen); 40398b9484cSchristos d += slen; 40498b9484cSchristos break; 40598b9484cSchristos } 40698b9484cSchristos } 40798b9484cSchristos if (special[k][0] != NULL) 40898b9484cSchristos break; 40998b9484cSchristos else 41098b9484cSchristos goto unknown; 41198b9484cSchristos } 41298b9484cSchristos else 41398b9484cSchristos { 41498b9484cSchristos *d++ = '.'; 41598b9484cSchristos continue; 41698b9484cSchristos } 41798b9484cSchristos } 41898b9484cSchristos else if (p[1] == 'B' || p[1] == 'E') 41998b9484cSchristos { 42098b9484cSchristos /* Entry Body or barrier Evaluation. */ 42198b9484cSchristos p += 2; 42298b9484cSchristos while (ISDIGIT (*p)) 42398b9484cSchristos p++; 42498b9484cSchristos if (p[0] == 's' && p[1] == 0) 42598b9484cSchristos break; 42698b9484cSchristos else 42798b9484cSchristos goto unknown; 42898b9484cSchristos } 42998b9484cSchristos else 43098b9484cSchristos goto unknown; 43198b9484cSchristos } 43298b9484cSchristos 43398b9484cSchristos if (p[0] == '.' && ISDIGIT (p[1])) 43498b9484cSchristos { 43598b9484cSchristos /* Nested subprogram. */ 43698b9484cSchristos p += 2; 43798b9484cSchristos while (ISDIGIT (*p)) 43898b9484cSchristos p++; 43998b9484cSchristos } 44098b9484cSchristos if (*p == 0) 44198b9484cSchristos { 44298b9484cSchristos /* End of mangled name. */ 44398b9484cSchristos break; 44498b9484cSchristos } 44598b9484cSchristos else 44698b9484cSchristos goto unknown; 44798b9484cSchristos } 44898b9484cSchristos *d = 0; 44998b9484cSchristos return demangled; 45098b9484cSchristos 45198b9484cSchristos unknown: 452796c32c9Schristos XDELETEVEC (demangled); 45398b9484cSchristos len0 = strlen (mangled); 45498b9484cSchristos demangled = XNEWVEC (char, len0 + 3); 45598b9484cSchristos 45698b9484cSchristos if (mangled[0] == '<') 45798b9484cSchristos strcpy (demangled, mangled); 45898b9484cSchristos else 45998b9484cSchristos sprintf (demangled, "<%s>", mangled); 46098b9484cSchristos 46198b9484cSchristos return demangled; 46298b9484cSchristos } 463