xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/cplus-dem.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
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