Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/* This code implements a demangler for the g++ V3 ABI. The ABI is
+ described on this web page:
+ http://www.codesourcery.com/cxx-abi/abi.html#mangling
+
+ This code was written while looking at the demangler written by
+ Alex Samuel <samuel@codesourcery.com>.
+
+ This code first pulls the mangled name apart into a list of
+ components, and then walks the list generating the demangled
+ name.
+
+ This file will normally define the following functions, q.v.:
+ char *cplus_demangle_v3(const char *mangled, int options)
+ char *java_demangle_v3(const char *mangled)
+ enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
+ enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
+
+ Preprocessor macros you can define while compiling this file:
+
+ IN_LIBGCC2
+ If defined, this file defines the following function, q.v.:
+ char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
+ int *status)
+ instead of cplus_demangle_v3() and java_demangle_v3().
+
+ IN_GLIBCPP_V3
+ If defined, this file defines only __cxa_demangle().
+
+ STANDALONE_DEMANGLER
+ If defined, this file defines a main() function which demangles
+ any arguments, or, if none, demangles stdin.
+
+ CP_DEMANGLE_DEBUG
+ If defined, turns on debugging mode, which prints information on
+ stdout about the mangled string. This is not generally useful.
+*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "libiberty.h"
#include "demangle.h"
-/* This code implements a demangler for the g++ V3 ABI. The ABI is
- described on this web page:
- http://www.codesourcery.com/cxx-abi/abi.html#mangling
-
- This code was written while looking at the demangler written by
- Alex Samuel <samuel@codesourcery.com>.
+/* We avoid pulling in the ctype tables, to prevent pulling in
+ additional unresolved symbols when this code is used in a library.
+ FIXME: Is this really a valid reason? This comes from the original
+ V3 demangler code.
- This code first pulls the mangled name apart into a list of
- components, and then walks the list generating the demangled
- name. */
+ As of this writing this file has the following undefined references
+ when compiled with -DIN_GLIBCPP_V3: malloc, realloc, free, memcpy,
+ strcpy, strcat, strlen. */
-/* Avoid pulling in the ctype tables for this simple usage. */
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
/* The prefix prepended by GCC to an identifier represnting the
anonymous namespace. */
D_COMP_VOLATILE,
/* The const qualifier. */
D_COMP_CONST,
+ /* The restrict qualifier modifying a member function. */
+ D_COMP_RESTRICT_THIS,
+ /* The volatile qualifier modifying a member function. */
+ D_COMP_VOLATILE_THIS,
+ /* The const qualifier modifying a member function. */
+ D_COMP_CONST_THIS,
/* A vendor qualifier. */
D_COMP_VENDOR_TYPE_QUAL,
/* A pointer. */
} \
while (0)
+#define d_last_char(dpi) \
+ ((dpi)->buf == NULL || (dpi)->len == 0 ? '\0' : (dpi)->buf[(dpi)->len - 1])
+
#ifdef CP_DEMANGLE_DEBUG
static void d_dump PARAMS ((struct d_comp *, int));
#endif
static struct d_comp *d_ctor_dtor_name PARAMS ((struct d_info *));
static struct d_comp *d_type PARAMS ((struct d_info *));
static struct d_comp **d_cv_qualifiers PARAMS ((struct d_info *,
- struct d_comp **));
+ struct d_comp **, int));
static struct d_comp *d_function_type PARAMS ((struct d_info *));
static struct d_comp *d_bare_function_type PARAMS ((struct d_info *, int));
static struct d_comp *d_class_enum_type PARAMS ((struct d_info *));
static void d_print_identifier PARAMS ((struct d_print_info *, const char *,
int));
static void d_print_mod_list PARAMS ((struct d_print_info *,
- struct d_print_mod *));
+ struct d_print_mod *, int));
static void d_print_mod PARAMS ((struct d_print_info *,
const struct d_comp *));
static void d_print_function_type PARAMS ((struct d_print_info *,
case D_COMP_CONST:
printf ("const\n");
break;
+ case D_COMP_RESTRICT_THIS:
+ printf ("restrict this\n");
+ break;
+ case D_COMP_VOLATILE_THIS:
+ printf ("volatile this\n");
+ break;
+ case D_COMP_CONST_THIS:
+ printf ("const this\n");
+ break;
case D_COMP_VENDOR_TYPE_QUAL:
printf ("vendor type qualifier\n");
break;
case D_COMP_RESTRICT:
case D_COMP_VOLATILE:
case D_COMP_CONST:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_CONST_THIS:
break;
/* Other types should not be seen here. */
{
struct d_comp *p;
+ if (s == NULL || len == 0)
+ return NULL;
p = d_make_empty (di, D_COMP_NAME);
if (p != NULL)
{
return 0;
case D_COMP_TEMPLATE:
return ! is_ctor_dtor_or_conversion (d_left (dc));
- case D_COMP_RESTRICT:
- case D_COMP_VOLATILE:
- case D_COMP_CONST:
- case D_COMP_VENDOR_TYPE_QUAL:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_CONST_THIS:
return has_return_type (d_left (dc));
}
}
/* Strip off any initial CV-qualifiers, as they really apply
to the `this' parameter, and they were not output by the
v2 demangler without DMGL_PARAMS. */
- while (dc->type == D_COMP_RESTRICT
- || dc->type == D_COMP_VOLATILE
- || dc->type == D_COMP_CONST)
+ while (dc->type == D_COMP_RESTRICT_THIS
+ || dc->type == D_COMP_VOLATILE_THIS
+ || dc->type == D_COMP_CONST_THIS)
dc = d_left (dc);
return dc;
}
if (d_next_char (di) != 'N')
return NULL;
- pret = d_cv_qualifiers (di, &ret);
+ pret = d_cv_qualifiers (di, &ret, 1);
if (pret == NULL)
return NULL;
comb_type = D_COMP_QUAL_NAME;
if (IS_DIGIT (peek)
- || (peek >= 'a' && peek <= 'z')
+ || IS_LOWER (peek)
|| peek == 'C'
|| peek == 'D')
dc = d_unqualified_name (di);
peek = d_peek_char (di);
if (IS_DIGIT (peek))
return d_source_name (di);
- else if (peek >= 'a' && peek <= 'z')
+ else if (IS_LOWER (peek))
return d_operator_name (di);
else if (peek == 'C' || peek == 'D')
return d_ctor_dtor_name (di);
{
struct d_comp **pret;
- pret = d_cv_qualifiers (di, &ret);
+ pret = d_cv_qualifiers (di, &ret, 0);
if (pret == NULL)
return NULL;
*pret = d_type (di);
peek_next = d_peek_next_char (di);
if (IS_DIGIT (peek_next)
|| peek_next == '_'
- || (peek_next >= 'A' && peek_next <= 'Z'))
+ || IS_UPPER (peek_next))
{
ret = d_substitution (di);
/* The substituted name may have been a template name and
/* <CV-qualifiers> ::= [r] [V] [K] */
static struct d_comp **
-d_cv_qualifiers (di, pret)
+d_cv_qualifiers (di, pret, member_fn)
struct d_info *di;
struct d_comp **pret;
+ int member_fn;
{
char peek;
d_advance (di, 1);
if (peek == 'r')
- t = D_COMP_RESTRICT;
+ t = member_fn ? D_COMP_RESTRICT_THIS: D_COMP_RESTRICT;
else if (peek == 'V')
- t = D_COMP_VOLATILE;
+ t = member_fn ? D_COMP_VOLATILE_THIS : D_COMP_VOLATILE;
else
- t = D_COMP_CONST;
+ t = member_fn ? D_COMP_CONST_THIS: D_COMP_CONST;
*pret = d_make_comp (di, t, NULL, NULL);
if (*pret == NULL)
with g++, we need to pull off the CV-qualifiers here, in order to
avoid calling add_substitution() in d_type(). */
- pmem = d_cv_qualifiers (di, &mem);
+ pmem = d_cv_qualifiers (di, &mem, 1);
if (pmem == NULL)
return NULL;
*pmem = d_type (di);
return NULL;
c = d_next_char (di);
- if (c == '_' || IS_DIGIT (c) || (c >= 'A' && c <= 'Z'))
+ if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
{
int id;
{
if (IS_DIGIT (c))
id = id * 36 + c - '0';
- else if (c >= 'A' && c <= 'Z')
+ else if (IS_UPPER (c))
id = id * 36 + c - 'A' + 10;
else
return NULL;
case D_COMP_TYPED_NAME:
{
- const struct d_comp *typed_name;
- struct d_print_mod dpm;
+ struct d_print_mod *hold_modifiers;
+ struct d_comp *typed_name;
+ struct d_print_mod adpm[4];
+ unsigned int i;
struct d_print_template dpt;
/* Pass the name down to the type so that it can be printed in
- the right place for the type. If the name has
- CV-qualifiers, they are really method qualifiers; pull them
- off now and print them after everything else. Note that we
- don't handle D_COMP_VENDOR_TYPE_QUAL here; it's not
- accepted by d_cv_qualifiers() either. */
+ the right place for the type. We also have to pass down
+ any CV-qualifiers, which apply to the this parameter. */
+ hold_modifiers = dpi->modifiers;
+ i = 0;
typed_name = d_left (dc);
- while (typed_name != NULL
- && (typed_name->type == D_COMP_RESTRICT
- || typed_name->type == D_COMP_VOLATILE
- || typed_name->type == D_COMP_CONST))
- typed_name = d_left (typed_name);
+ while (typed_name != NULL)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
- dpm.next = dpi->modifiers;
- dpi->modifiers = &dpm;
- dpm.mod = typed_name;
- dpm.printed = 0;
- dpm.templates = dpi->templates;
+ adpm[i].next = dpi->modifiers;
+ dpi->modifiers = &adpm[i];
+ adpm[i].mod = typed_name;
+ adpm[i].printed = 0;
+ adpm[i].templates = dpi->templates;
+ ++i;
+
+ if (typed_name->type != D_COMP_RESTRICT_THIS
+ && typed_name->type != D_COMP_VOLATILE_THIS
+ && typed_name->type != D_COMP_CONST_THIS)
+ break;
+
+ typed_name = d_left (typed_name);
+ }
/* If typed_name is a template, then it applies to the
function type as well. */
if (typed_name->type == D_COMP_TEMPLATE)
dpi->templates = dpt.next;
- /* If the modifier didn't get printed by the type, print it
+ /* If the modifiers didn't get printed by the type, print them
now. */
- if (! dpm.printed)
+ while (i > 0)
{
- d_append_char (dpi, ' ');
- d_print_comp (dpi, typed_name);
+ --i;
+ if (! adpm[i].printed)
+ {
+ d_append_char (dpi, ' ');
+ d_print_mod (dpi, adpm[i].mod);
+ }
}
- dpi->modifiers = dpm.next;
-
- /* Now print any CV-qualifiers on the type. */
- typed_name = d_left (dc);
- while (typed_name != NULL
- && (typed_name->type == D_COMP_RESTRICT
- || typed_name->type == D_COMP_VOLATILE
- || typed_name->type == D_COMP_CONST))
- {
- d_print_mod (dpi, typed_name);
- typed_name = d_left (typed_name);
- }
+ dpi->modifiers = hold_modifiers;
return;
}
dpi->modifiers = NULL;
d_print_comp (dpi, d_left (dc));
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
d_append_char (dpi, '<');
d_print_comp (dpi, d_right (dc));
/* Avoid generating two consecutive '>' characters, to avoid
the C++ syntactic ambiguity. */
- if (dpi->buf != NULL && dpi->buf[dpi->len - 1] == '>')
+ if (d_last_char (dpi) == '>')
d_append_char (dpi, ' ');
d_append_char (dpi, '>');
case D_COMP_RESTRICT:
case D_COMP_VOLATILE:
case D_COMP_CONST:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_CONST_THIS:
case D_COMP_VENDOR_TYPE_QUAL:
case D_COMP_POINTER:
case D_COMP_REFERENCE:
case D_COMP_PTRMEM_TYPE:
{
- const struct d_comp *target_type;
struct d_print_mod dpm;
- /* Pass the name down to the type so that it can be printed in
- the right place for the type. If the type has
- CV-qualifiers, they are really method qualifiers; pull them
- off now and print them after everything else. */
- target_type = d_right (dc);
- while (target_type != NULL
- && (target_type->type == D_COMP_RESTRICT
- || target_type->type == D_COMP_VOLATILE
- || target_type->type == D_COMP_CONST))
- target_type = d_left (target_type);
-
dpm.next = dpi->modifiers;
dpi->modifiers = &dpm;
dpm.mod = dc;
dpm.printed = 0;
dpm.templates = dpi->templates;
- d_print_comp (dpi, target_type);
+ d_print_comp (dpi, d_right (dc));
/* If the modifier didn't get printed by the type, print it
now. */
dpi->modifiers = dpm.next;
- /* Now print any CV-qualifiers on the type. */
- target_type = d_right (dc);
- while (target_type != NULL
- && (target_type->type == D_COMP_RESTRICT
- || target_type->type == D_COMP_VOLATILE
- || target_type->type == D_COMP_CONST))
- {
- d_print_mod (dpi, target_type);
- target_type = d_left (target_type);
- }
-
return;
}
d_append_string (dpi, "operator");
c = dc->u.s_operator.op->name[0];
- if (c >= 'a' && c <= 'z')
+ if (IS_LOWER (c))
d_append_char (dpi, ' ');
d_append_string (dpi, dc->u.s_operator.op->name);
return;
d_print_error (dpi);
return;
}
+
+ /* We wrap an expression which uses the greater-than operator in
+ an extra layer of parens so that it does not get confused
+ with the '>' which ends the template parameters. */
+ if (d_left (dc)->type == D_COMP_OPERATOR
+ && strcmp (d_left (dc)->u.s_operator.op->name, ">") == 0)
+ d_append_char (dpi, '(');
+
d_append_char (dpi, '(');
d_print_comp (dpi, d_left (d_right (dc)));
d_append_string (dpi, ") ");
d_append_string (dpi, " (");
d_print_comp (dpi, d_right (d_right (dc)));
d_append_char (dpi, ')');
+
+ if (d_left (dc)->type == D_COMP_OPERATOR
+ && strcmp (d_left (dc)->u.s_operator.op->name, ">") == 0)
+ d_append_char (dpi, ')');
+
return;
case D_COMP_BINARY_ARGS:
{
int dig;
- if (*q >= '0' && *q <= '9')
+ if (IS_DIGIT (*q))
dig = *q - '0';
else if (*q >= 'A' && *q <= 'F')
dig = *q - 'A' + 10;
}
}
-/* Print a list of modifiers. */
+/* Print a list of modifiers. SUFFIX is 1 if we are printing
+ qualifiers on this after printing a function. */
static void
-d_print_mod_list (dpi, mods)
+d_print_mod_list (dpi, mods, suffix)
struct d_print_info *dpi;
struct d_print_mod *mods;
+ int suffix;
{
struct d_print_template *hold_dpt;
- if (mods == NULL || mods->printed || d_print_saw_error (dpi))
+ if (mods == NULL || d_print_saw_error (dpi))
return;
+ if (mods->printed
+ || (! suffix
+ && (mods->mod->type == D_COMP_RESTRICT_THIS
+ || mods->mod->type == D_COMP_VOLATILE_THIS
+ || mods->mod->type == D_COMP_CONST_THIS)))
+ {
+ d_print_mod_list (dpi, mods->next, suffix);
+ return;
+ }
+
mods->printed = 1;
hold_dpt = dpi->templates;
dpi->templates = hold_dpt;
- d_print_mod_list (dpi, mods->next);
+ d_print_mod_list (dpi, mods->next, suffix);
}
/* Print a modifier. */
switch (mod->type)
{
case D_COMP_RESTRICT:
+ case D_COMP_RESTRICT_THIS:
d_append_string (dpi, " restrict");
return;
case D_COMP_VOLATILE:
+ case D_COMP_VOLATILE_THIS:
d_append_string (dpi, " volatile");
return;
case D_COMP_CONST:
+ case D_COMP_CONST_THIS:
d_append_string (dpi, " const");
return;
case D_COMP_VENDOR_TYPE_QUAL:
d_append_string (dpi, "imaginary ");
return;
case D_COMP_PTRMEM_TYPE:
- if (dpi->buf != NULL && dpi->buf[dpi->len - 1] != '(')
+ if (d_last_char (dpi) != '(')
d_append_char (dpi, ' ');
d_print_comp (dpi, d_left (mod));
d_append_string (dpi, "::*");
case D_COMP_PTRMEM_TYPE:
need_paren = 1;
break;
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_CONST_THIS:
+ break;
default:
break;
}
need_paren = 1;
if (need_paren)
- d_append_char (dpi, '(');
+ {
+ switch (d_last_char (dpi))
+ {
+ case ' ':
+ case '(':
+ case '*':
+ break;
- d_print_mod_list (dpi, mods);
+ default:
+ d_append_char (dpi, ' ');
+ break;
+ }
+
+ d_append_char (dpi, '(');
+ }
+
+ d_print_mod_list (dpi, mods, 0);
if (need_paren)
d_append_char (dpi, ')');
d_print_comp (dpi, d_right (dc));
d_append_char (dpi, ')');
+
+ d_print_mod_list (dpi, mods, 1);
}
/* Print an array type, except for the element type. */
if (need_paren)
d_append_string (dpi, " (");
- d_print_mod_list (dpi, mods);
+ d_print_mod_list (dpi, mods, 0);
if (need_paren)
d_append_char (dpi, ')');
dpi->templates = dpt.next;
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
d_append_char (dpi, '<');
d_print_comp (dpi, d_right (d_left (dc)));
/* Avoid generating two consecutive '>' characters, to avoid
the C++ syntactic ambiguity. */
- if (dpi->buf != NULL && dpi->buf[dpi->len - 1] == '>')
+ if (d_last_char (dpi) == '>')
d_append_char (dpi, ' ');
d_append_char (dpi, '>');
{
struct d_info di;
struct d_comp *dc;
+ int ret;
*ctor_kind = (enum gnu_v3_ctor_kinds) 0;
*dtor_kind = (enum gnu_v3_dtor_kinds) 0;
dc = d_mangled_name (&di, 1);
- if (dc == NULL || d_peek_char (&di) != '\0')
- return 0;
-
- while (dc != NULL)
+ ret = 0;
+ if (d_peek_char (&di) == '\0')
{
- switch (dc->type)
+ while (dc != NULL)
{
- default:
- return 0;
- case D_COMP_TYPED_NAME:
- case D_COMP_TEMPLATE:
- case D_COMP_RESTRICT:
- case D_COMP_VOLATILE:
- case D_COMP_CONST:
- case D_COMP_VENDOR_TYPE_QUAL:
- dc = d_left (dc);
- break;
- case D_COMP_QUAL_NAME:
- dc = d_right (dc);
- break;
- case D_COMP_CTOR:
- *ctor_kind = dc->u.s_ctor.kind;
- return 1;
- case D_COMP_DTOR:
- *dtor_kind = dc->u.s_dtor.kind;
- return 1;
+ switch (dc->type)
+ {
+ default:
+ dc = NULL;
+ break;
+ case D_COMP_TYPED_NAME:
+ case D_COMP_TEMPLATE:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_CONST_THIS:
+ dc = d_left (dc);
+ break;
+ case D_COMP_QUAL_NAME:
+ dc = d_right (dc);
+ break;
+ case D_COMP_CTOR:
+ *ctor_kind = dc->u.s_ctor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ case D_COMP_DTOR:
+ *dtor_kind = dc->u.s_dtor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ }
}
}
- return 0;
+ free (di.subs);
+ free (di.comps);
+
+ return ret;
}
/* Return whether NAME is the mangled form of a g++ V3 ABI constructor