Home | History | Annotate | Line # | Download | only in libiberty
      1 /* Demangler for GNU C++
      2    Copyright (C) 1989-2026 Free Software Foundation, Inc.
      3    Written by James Clark (jjc (at) jclark.uucp)
      4    Rewritten by Fred Fish (fnf (at) cygnus.com) for ARM and Lucid demangling
      5    Modified by Satish Pai (pai (at) 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     no_demangling,
     63     "Demangling disabled"
     64   }
     65   ,
     66   {
     67     AUTO_DEMANGLING_STYLE_STRING,
     68       auto_demangling,
     69       "Automatic selection based on executable"
     70   }
     71   ,
     72   {
     73     GNU_V3_DEMANGLING_STYLE_STRING,
     74     gnu_v3_demangling,
     75     "GNU (g++) V3 (Itanium C++ ABI) style demangling"
     76   }
     77   ,
     78   {
     79     JAVA_DEMANGLING_STYLE_STRING,
     80     java_demangling,
     81     "Java style demangling"
     82   }
     83   ,
     84   {
     85     GNAT_DEMANGLING_STYLE_STRING,
     86     gnat_demangling,
     87     "GNAT style demangling"
     88   }
     89   ,
     90   {
     91     DLANG_DEMANGLING_STYLE_STRING,
     92     dlang_demangling,
     93     "DLANG style demangling"
     94   }
     95   ,
     96   {
     97     RUST_DEMANGLING_STYLE_STRING,
     98     rust_demangling,
     99     "Rust style demangling"
    100   }
    101   ,
    102   {
    103     NULL, 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 (name, 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 (mangled, "_ada_", 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 preceded 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 (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 (operators[k][0]);
    254               if (strncmp (p, operators[k][0], slen) == 0)
    255                 {
    256                   p += slen;
    257                   slen = strlen (operators[k][1]);
    258                   *d++ = '"';
    259                   memcpy (d, operators[k][1], 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 (d, name);
    339           d += strlen (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 (d, name);
    357           d += strlen (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 (special[k][0]);
    398                       if (strncmp (p, special[k][0], slen) == 0)
    399                         {
    400                           p += slen;
    401                           slen = strlen (special[k][1]);
    402                           memcpy (d, special[k][1], 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 (mangled);
    454   demangled = XNEWVEC (char, len0 + 3);
    455 
    456   if (mangled[0] == '<')
    457      strcpy (demangled, mangled);
    458   else
    459     sprintf (demangled, "<%s>", mangled);
    460 
    461   return demangled;
    462 }
    463