358030 support direct socket calls on x86 32bit (new in linux 4.3)
358478 drd/tests/std_thread.cpp doesn't build with GCC6
359133 Assertion 'eltSzB <= ddpa->poolSzB' failed
+359181 Buffer Overflow during Demangling
359201 futex syscall "skips" argument 5 if op is FUTEX_WAIT_BITSET
359289 s390x: popcnt (B9E1) not implemented
359472 The Power PC vsubuqm instruction doesn't always give the correct result
#---------------------------------------------------------------------
# You need to modify these revision numbers for your update.
-old_gcc_revision=r181975 # the revision of the previous update
-new_gcc_revision=r212125 # the revision for this update
+old_gcc_revision=r212125 # the revision of the previous update
+new_gcc_revision=r240068 # the revision for this update
# Unless the organization of demangler related files has changed, no
# changes below this line should be necessary.
cp ../gcc-$old_gcc_revision/libiberty/cp-demangle.h .
cp ../gcc-$old_gcc_revision/libiberty/cplus-dem.c .
cp ../gcc-$old_gcc_revision/libiberty/dyn-string.c .
+cp ../gcc-$old_gcc_revision/libiberty/d-demangle.c .
cp ../gcc-$old_gcc_revision/libiberty/safe-ctype.c .
cd ..
cp ../gcc-$new_gcc_revision/libiberty/cp-demangle.h .
cp ../gcc-$new_gcc_revision/libiberty/cplus-dem.c .
cp ../gcc-$new_gcc_revision/libiberty/dyn-string.c .
+cp ../gcc-$new_gcc_revision/libiberty/d-demangle.c .
cp ../gcc-$new_gcc_revision/libiberty/safe-ctype.c .
cd ..
m_demangle/cplus-dem.c \
m_demangle/demangle.c \
m_demangle/dyn-string.c \
+ m_demangle/d-demangle.c \
m_demangle/safe-ctype.c \
m_dispatch/dispatch-x86-linux.S \
m_dispatch/dispatch-amd64-linux.S \
/* ANSI and traditional C compatability macros
- Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2013
- Free Software Foundation, Inc.
+ Copyright (C) 1991-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
# endif /* GNUC >= 4.3 */
#endif /* ATTRIBUTE_HOT */
+/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */
+#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
+# if (GCC_VERSION >= 4009)
+# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
+# else
+# define ATTRIBUTE_NO_SANITIZE_UNDEFINED
+# endif /* GNUC >= 4.9 */
+#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
+
/* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before
gcc 2.8. */
#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
#else
#define ENUM_BITFIELD(TYPE) unsigned int
+#endif
+
+ /* This is used to mark a class or virtual function as final. */
+#if __cplusplus >= 201103L
+#define GCC_FINAL final
+#elif GCC_VERSION >= 4007
+#define GCC_FINAL __final
+#else
+#define GCC_FINAL
#endif
#ifdef __cplusplus
CP_DEMANGLE_DEBUG
If defined, turns on debugging mode, which prints information on
stdout about the mangled string. This is not generally useful.
-*/
+
+ CHECK_DEMANGLER
+ If defined, additional sanity checks will be performed. It will
+ cause some slowdown, but will allow to catch out-of-bound access
+ errors earlier. This macro is intended for testing and debugging. */
#if 0 /* in valgrind */
#if defined (_AIX) && !defined (__GNUC__)
#endif /* HAVE_ALLOCA_H */
#endif /* ! in valgrind */
+#if 0 /* in valgrind */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#endif /* ! in valgrind */
+#ifndef INT_MAX
+# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */
+#endif
+
#if 0 /* in valgrind */
#include "ansidecl.h"
#include "libiberty.h"
/* Set to 1 if we saw a demangling error. */
int demangle_failure;
/* The current index into any template argument packs we are using
- for printing. */
+ for printing, or -1 to print the whole pack. */
int pack_index;
/* Number of d_print_flush calls so far. */
unsigned long int flush_count;
struct demangle_component *);
static struct demangle_component *
-d_make_template_param (struct d_info *, long);
+d_make_template_param (struct d_info *, int);
static struct demangle_component *
d_make_sub (struct d_info *, const char *, int);
static struct demangle_component *d_source_name (struct d_info *);
-static long d_number (struct d_info *);
+static int d_number (struct d_info *);
static struct demangle_component *d_identifier (struct d_info *, int);
d_template_param (struct d_info *);
static struct demangle_component *d_template_args (struct d_info *);
+static struct demangle_component *d_template_args_1 (struct d_info *);
static struct demangle_component *
d_template_arg (struct d_info *);
static void
d_print_expr_op (struct d_print_info *, int, const struct demangle_component *);
-static void
-d_print_cast (struct d_print_info *, int, const struct demangle_component *);
+static void d_print_cast (struct d_print_info *, int,
+ const struct demangle_component *);
+static void d_print_conversion (struct d_print_info *, int,
+ const struct demangle_component *);
static int d_demangle_callback (const char *, int,
demangle_callbackref, void *);
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
printf ("rvalue reference this\n");
break;
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ printf ("transaction_safe this\n");
+ break;
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
printf ("vendor type qualifier\n");
break;
printf ("pointer to member type\n");
break;
case DEMANGLE_COMPONENT_FIXED_TYPE:
- printf ("fixed-point type\n");
+ printf ("fixed-point type, accum? %d, sat? %d\n",
+ dc->u.s_fixed.accum, dc->u.s_fixed.sat);
+ d_dump (dc->u.s_fixed.length, indent + 2);
break;
case DEMANGLE_COMPONENT_ARGLIST:
printf ("argument list\n");
case DEMANGLE_COMPONENT_CAST:
printf ("cast\n");
break;
+ case DEMANGLE_COMPONENT_CONVERSION:
+ printf ("conversion operator\n");
+ break;
case DEMANGLE_COMPONENT_NULLARY:
printf ("nullary operator\n");
break;
case DEMANGLE_COMPONENT_IMAGINARY:
case DEMANGLE_COMPONENT_VENDOR_TYPE:
case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_CONVERSION:
case DEMANGLE_COMPONENT_JAVA_RESOURCE:
case DEMANGLE_COMPONENT_DECLTYPE:
case DEMANGLE_COMPONENT_PACK_EXPANSION:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_ARGLIST:
/* Add a new template parameter. */
static struct demangle_component *
-d_make_template_param (struct d_info *di, long i)
+d_make_template_param (struct d_info *di, int i)
{
struct demangle_component *p;
/* Add a new function parameter. */
static struct demangle_component *
-d_make_function_param (struct d_info *di, long i)
+d_make_function_param (struct d_info *di, int i)
{
struct demangle_component *p;
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
return has_return_type (d_left (dc));
}
}
return is_ctor_dtor_or_conversion (d_right (dc));
case DEMANGLE_COMPONENT_CTOR:
case DEMANGLE_COMPONENT_DTOR:
- case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_CONVERSION:
return 1;
}
}
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| dcr->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dcr->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|| dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dcr = d_left (dcr);
static struct demangle_component *
d_abi_tags (struct d_info *di, struct demangle_component *dc)
{
+ struct demangle_component *hold_last_name;
char peek;
+
+ /* Preserve the last name, so the ABI tag doesn't clobber it. */
+ hold_last_name = di->last_name;
+
while (peek = d_peek_char (di),
peek == 'B')
{
tag = d_source_name (di);
dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
}
+
+ di->last_name = hold_last_name;
+
return dc;
}
static struct demangle_component *
d_source_name (struct d_info *di)
{
- long len;
+ int len;
struct demangle_component *ret;
len = d_number (di);
/* number ::= [n] <(non-negative decimal integer)> */
-static long
+static int
d_number (struct d_info *di)
{
int negative;
char peek;
- long ret;
+ int ret;
negative = 0;
peek = d_peek_char (di);
{ "eO", NL ("^="), 2 },
{ "eo", NL ("^"), 2 },
{ "eq", NL ("=="), 2 },
+ { "fL", NL ("..."), 3 },
+ { "fR", NL ("..."), 3 },
+ { "fl", NL ("..."), 2 },
+ { "fr", NL ("..."), 2 },
{ "ge", NL (">="), 2 },
{ "gs", NL ("::"), 1 },
{ "gt", NL (">"), 2 },
{ "rc", NL ("reinterpret_cast"), 2 },
{ "rm", NL ("%"), 2 },
{ "rs", NL (">>"), 2 },
+ { "sP", NL ("sizeof..."), 1 },
+ { "sZ", NL ("sizeof..."), 1 },
{ "sc", NL ("static_cast"), 2 },
{ "st", NL ("sizeof "), 1 },
{ "sz", NL ("sizeof "), 1 },
{
struct demangle_component *type;
int was_conversion = di->is_conversion;
+ struct demangle_component *res;
di->is_conversion = ! di->is_expression;
type = cplus_demangle_type (di);
+ if (di->is_conversion)
+ res = d_make_comp (di, DEMANGLE_COMPONENT_CONVERSION, type, NULL);
+ else
+ res = d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL);
di->is_conversion = was_conversion;
- return d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL);
+ return res;
}
else
{
{
struct demangle_component *p = NULL;
struct demangle_component *next = NULL;
- long len, i;
+ int len, i;
char c;
const char *str;
case 'C':
{
struct demangle_component *derived_type;
- long offset;
+ int offset;
struct demangle_component *base_type;
derived_type = cplus_demangle_type (di);
names. */
peek = d_peek_char (di);
- if (peek == 'r' || peek == 'V' || peek == 'K')
+ if (peek == 'r' || peek == 'V' || peek == 'K'
+ || (peek == 'D' && d_peek_next_char (di) == 'x'))
{
struct demangle_component **pret;
case 'U':
d_advance (di, 1);
ret = d_source_name (di);
+ if (d_peek_char (di) == 'I')
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
cplus_demangle_type (di), ret);
break;
return ret;
}
-/* <CV-qualifiers> ::= [r] [V] [K] */
+/* <CV-qualifiers> ::= [r] [V] [K] [Dx] */
static struct demangle_component **
d_cv_qualifiers (struct d_info *di,
pstart = pret;
peek = d_peek_char (di);
- while (peek == 'r' || peek == 'V' || peek == 'K')
+ while (peek == 'r' || peek == 'V' || peek == 'K'
+ || (peek == 'D' && d_peek_next_char (di) == 'x'))
{
enum demangle_component_type t;
: DEMANGLE_COMPONENT_VOLATILE);
di->expansion += sizeof "volatile";
}
- else
+ else if (peek == 'K')
{
t = (member_fn
? DEMANGLE_COMPONENT_CONST_THIS
: DEMANGLE_COMPONENT_CONST);
di->expansion += sizeof "const";
}
+ else
+ {
+ t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
+ di->expansion += sizeof "transaction_safe";
+ d_advance (di, 1);
+ }
*pret = d_make_comp (di, t, NULL, NULL);
if (*pret == NULL)
return ret;
}
-/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
+/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] [T] E */
static struct demangle_component *
d_function_type (struct d_info *di)
/* <non-negative number> _ */
-static long
+static int
d_compact_number (struct d_info *di)
{
- long num;
+ int num;
if (d_peek_char (di) == '_')
num = 0;
else if (d_peek_char (di) == 'n')
else
num = d_number (di) + 1;
- if (! d_check_char (di, '_'))
+ if (num < 0 || ! d_check_char (di, '_'))
return -1;
return num;
}
static struct demangle_component *
d_template_param (struct d_info *di)
{
- long param;
+ int param;
if (! d_check_char (di, 'T'))
return NULL;
static struct demangle_component *
d_template_args (struct d_info *di)
+{
+ if (d_peek_char (di) != 'I'
+ && d_peek_char (di) != 'J')
+ return NULL;
+ d_advance (di, 1);
+
+ return d_template_args_1 (di);
+}
+
+/* <template-arg>* E */
+
+static struct demangle_component *
+d_template_args_1 (struct d_info *di)
{
struct demangle_component *hold_last_name;
struct demangle_component *al;
constructor or destructor. */
hold_last_name = di->last_name;
- if (d_peek_char (di) != 'I'
- && d_peek_char (di) != 'J')
- return NULL;
- d_advance (di, 1);
-
if (d_peek_char (di) == 'E')
{
/* An argument pack can be empty. */
}
else
{
- index = d_compact_number (di) + 1;
- if (index == 0)
+ index = d_compact_number (di);
+ if (index == INT_MAX || index == -1)
return NULL;
+ index++;
}
return d_make_function_param (di, index);
}
struct demangle_component *type = NULL;
if (peek == 't')
type = cplus_demangle_type (di);
+ if (!d_peek_next_char (di))
+ return NULL;
d_advance (di, 2);
return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
type, d_exprlist (di, 'E'));
if (op->type == DEMANGLE_COMPONENT_CAST
&& d_check_char (di, '_'))
operand = d_exprlist (di, 'E');
+ else if (code && !strcmp (code, "sP"))
+ operand = d_template_args_1 (di);
else
operand = d_expression_1 (di);
struct demangle_component *left;
struct demangle_component *right;
+ if (code == NULL)
+ return NULL;
if (op_is_new_cast (op))
left = cplus_demangle_type (di);
+ else if (code[0] == 'f')
+ /* fold-expression. */
+ left = d_operator_name (di);
else
left = d_expression_1 (di);
if (!strcmp (code, "cl"))
struct demangle_component *second;
struct demangle_component *third;
- if (!strcmp (code, "qu"))
+ if (code == NULL)
+ return NULL;
+ else if (!strcmp (code, "qu"))
{
/* ?: expression. */
first = d_expression_1 (di);
second = d_expression_1 (di);
third = d_expression_1 (di);
}
+ else if (code[0] == 'f')
+ {
+ /* fold-expression. */
+ first = d_operator_name (di);
+ second = d_expression_1 (di);
+ third = d_expression_1 (di);
+ }
else if (code[0] == 'n')
{
/* new-expression. */
static int
d_discriminator (struct d_info *di)
{
- long discrim;
+ int discrim;
if (d_peek_char (di) != '_')
return 1;
d_unnamed_type (struct d_info *di)
{
struct demangle_component *ret;
- long num;
+ int num;
if (! d_check_char (di, 'U'))
return NULL;
{
const char *s;
int len;
+ struct demangle_component *dc;
if (p->set_last_name != NULL)
di->last_name = d_make_sub (di, p->set_last_name,
len = p->simple_len;
}
di->expansion += len;
- return d_make_sub (di, s, len);
+ dc = d_make_sub (di, s, len);
+ if (d_peek_char (di) == 'B')
+ {
+ /* If there are ABI tags on the abbreviation, it becomes
+ a substitution candidate. */
+ dc = d_abi_tags (di, dc);
+ d_add_substitution (di, dc);
+ }
+ return dc;
}
}
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
case DEMANGLE_COMPONENT_ARRAY_TYPE:
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
- case DEMANGLE_COMPONENT_FIXED_TYPE:
case DEMANGLE_COMPONENT_VECTOR_TYPE:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
case DEMANGLE_COMPONENT_INITIALIZER_LIST:
case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_CONVERSION:
case DEMANGLE_COMPONENT_NULLARY:
case DEMANGLE_COMPONENT_UNARY:
case DEMANGLE_COMPONENT_BINARY:
dc->u.s_extended_operator.name);
break;
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_fixed.length);
+ break;
+
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
d_count_templates_scopes (num_templates, num_scopes,
}
static inline void
-d_append_num (struct d_print_info *dpi, long l)
+d_append_num (struct d_print_info *dpi, int l)
{
char buf[25];
- sprintf (buf,"%ld", l);
+ sprintf (buf,"%d", l);
d_append_string (dpi, buf);
}
{
#if 0 /* in valgrind */
#ifdef CP_DYNAMIC_ARRAYS
- __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes ?: 1];
- __extension__ struct d_print_template temps[dpi.num_copy_templates ?: 1];
+ /* Avoid zero-length VLAs, which are prohibited by the C99 standard
+ and flagged as errors by Address Sanitizer. */
+ __extension__ struct d_saved_scope scopes[(dpi.num_saved_scopes > 0)
+ ? dpi.num_saved_scopes : 1];
+ __extension__ struct d_print_template temps[(dpi.num_copy_templates > 0)
+ ? dpi.num_copy_templates : 1];
dpi.saved_scopes = scopes;
dpi.copy_templates = temps;
}
/* Returns the I'th element of the template arglist ARGS, or NULL on
- failure. */
+ failure. If I is negative, return the entire arglist. */
static struct demangle_component *
d_index_template_argument (struct demangle_component *args, int i)
{
struct demangle_component *a;
+ if (i < 0)
+ /* Print the whole argument pack. */
+ return args;
+
for (a = args;
a != NULL;
a = d_right (a))
case DEMANGLE_COMPONENT_CHARACTER:
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ case DEMANGLE_COMPONENT_NUMBER:
return NULL;
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
return count;
}
+/* Returns the number of template args in DC, expanding any pack expansions
+ found there. */
+
+static int
+d_args_length (struct d_print_info *dpi, const struct demangle_component *dc)
+{
+ int count = 0;
+ for (; dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST;
+ dc = d_right (dc))
+ {
+ struct demangle_component *elt = d_left (dc);
+ if (elt == NULL)
+ break;
+ if (elt->type == DEMANGLE_COMPONENT_PACK_EXPANSION)
+ {
+ struct demangle_component *a = d_find_pack (dpi, d_left (elt));
+ count += d_pack_length (a);
+ }
+ else
+ ++count;
+ }
+ return count;
+}
+
/* DC is a component of a mangled expression. Print it, wrapped in parens
if needed. */
return NULL;
}
+/* If DC is a C++17 fold-expression, print it and return true; otherwise
+ return false. */
+
+static int
+d_maybe_print_fold_expression (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+ const struct demangle_component *ops, *operator_, *op1, *op2;
+ int save_idx;
+
+ const char *fold_code = d_left (dc)->u.s_operator.op->code;
+ if (fold_code[0] != 'f')
+ return 0;
+
+ ops = d_right (dc);
+ operator_ = d_left (ops);
+ op1 = d_right (ops);
+ op2 = 0;
+ if (op1->type == DEMANGLE_COMPONENT_TRINARY_ARG2)
+ {
+ op2 = d_right (op1);
+ op1 = d_left (op1);
+ }
+
+ /* Print the whole pack. */
+ save_idx = dpi->pack_index;
+ dpi->pack_index = -1;
+
+ switch (fold_code[1])
+ {
+ /* Unary left fold, (... + X). */
+ case 'l':
+ d_append_string (dpi, "(...");
+ d_print_expr_op (dpi, options, operator_);
+ d_print_subexpr (dpi, options, op1);
+ d_append_char (dpi, ')');
+ break;
+
+ /* Unary right fold, (X + ...). */
+ case 'r':
+ d_append_char (dpi, '(');
+ d_print_subexpr (dpi, options, op1);
+ d_print_expr_op (dpi, options, operator_);
+ d_append_string (dpi, "...)");
+ break;
+
+ /* Binary left fold, (42 + ... + X). */
+ case 'L':
+ /* Binary right fold, (X + ... + 42). */
+ case 'R':
+ d_append_char (dpi, '(');
+ d_print_subexpr (dpi, options, op1);
+ d_print_expr_op (dpi, options, operator_);
+ d_append_string (dpi, "...");
+ d_print_expr_op (dpi, options, operator_);
+ d_print_subexpr (dpi, options, op2);
+ d_append_char (dpi, ')');
+ break;
+ }
+
+ dpi->pack_index = save_idx;
+ return 1;
+}
+
/* Subroutine to handle components. */
static void
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
&& typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
&& typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_TRANSACTION_SAFE
&& typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
break;
local_name = d_right (typed_name);
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
local_name = local_name->u.s_unary_num.sub;
+ if (local_name == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS
|| local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || local_name->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| (local_name->type
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
{
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
modifier:
{
/* We keep a list of modifiers on the stack. */
d_print_comp (dpi, options, dc->u.s_extended_operator.name);
return;
- case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_CONVERSION:
d_append_string (dpi, "operator ");
- d_print_cast (dpi, options, dc);
+ d_print_conversion (dpi, options, dc);
return;
case DEMANGLE_COMPONENT_NULLARY:
}
}
+ /* For sizeof..., just print the pack length. */
+ if (code && !strcmp (code, "sZ"))
+ {
+ struct demangle_component *a = d_find_pack (dpi, operand);
+ int len = d_pack_length (a);
+ d_append_num (dpi, len);
+ return;
+ }
+ else if (code && !strcmp (code, "sP"))
+ {
+ int len = d_args_length (dpi, operand);
+ d_append_num (dpi, len);
+ return;
+ }
+
if (op->type != DEMANGLE_COMPONENT_CAST)
d_print_expr_op (dpi, options, op);
else
return;
}
+ if (d_maybe_print_fold_expression (dpi, options, dc))
+ 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. */
d_print_error (dpi);
return;
}
+ if (d_maybe_print_fold_expression (dpi, options, dc))
+ return;
{
struct demangle_component *op = d_left (dc);
struct demangle_component *first = d_left (d_right (dc));
|| mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
|| mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| (mods->mod->type
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
{
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
case DEMANGLE_COMPONENT_CONST_THIS:
d_append_string (dpi, " const");
return;
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ d_append_string (dpi, " transaction_safe");
+ return;
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
d_append_char (dpi, ' ');
d_print_comp (dpi, options, d_right (mod));
case DEMANGLE_COMPONENT_REFERENCE_THIS:
/* For the ref-qualifier, put a space before the &. */
d_append_char (dpi, ' ');
+ /* FALLTHRU */
case DEMANGLE_COMPONENT_REFERENCE:
d_append_char (dpi, '&');
return;
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
d_append_char (dpi, ' ');
+ /* FALLTHRU */
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
d_append_string (dpi, "&&");
return;
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
break;
default:
break;
static void
d_print_cast (struct d_print_info *dpi, int options,
- const struct demangle_component *dc)
+ const struct demangle_component *dc)
+{
+ d_print_comp (dpi, options, d_left (dc));
+}
+
+/* Print a conversion operator. */
+
+static void
+d_print_conversion (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
{
struct d_print_template dpt;
- /* For a cast operator, we need the template parameters from
+ /* For a conversion operator, we need the template parameters from
the enclosing template in scope for processing the type. */
if (dpi->current_template != NULL)
{
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
default:
dc = NULL;
break;
- call d_check_char(di, '\0')
Everything else is safe. */
#define d_peek_char(di) (*((di)->n))
-#define d_peek_next_char(di) ((di)->n[1])
-#define d_advance(di, i) ((di)->n += (i))
+#ifndef CHECK_DEMANGLER
+# define d_peek_next_char(di) ((di)->n[1])
+# define d_advance(di, i) ((di)->n += (i))
+#endif
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
#define d_str(di) ((di)->n)
+#ifdef CHECK_DEMANGLER
+static inline char
+d_peek_next_char (const struct d_info *di)
+{
+ if (!di->n[0])
+ abort ();
+ return di->n[1];
+}
+
+static inline void
+d_advance (struct d_info *di, int i)
+{
+ if (i < 0)
+ abort ();
+ while (i--)
+ {
+ if (!di->n[0])
+ abort ();
+ di->n++;
+ }
+}
+#endif
+
/* Functions and arrays in cp-demangle.c which are referenced by
functions in cp-demint.c. */
#ifdef IN_GLIBCPP_V3
#endif
#endif /* ! in valgrind */
+#if 0 /* in valgrind */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#endif /* ! in valgrind */
+#ifndef INT_MAX
+# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */
+#endif
+
#if 0 /* in valgrind */
#include <demangle.h>
#undef CURRENT_DEMANGLING_STYLE
string* previous_argument; /* The last function argument demangled. */
int nrepeats; /* The number of times to repeat the previous
argument. */
+ int *proctypevec; /* Indices of currently processed remembered typevecs. */
+ int proctypevec_size;
+ int nproctypes;
};
#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
tk_none,
tk_pointer,
tk_reference,
+ tk_rvalue_reference,
tk_integral,
tk_bool,
tk_char,
"GNAT style demangling"
}
,
+ {
+ DLANG_DEMANGLING_STYLE_STRING,
+ dlang_demangling,
+ "DLANG style demangling"
+ }
+ ,
{
NULL, unknown_demangling, NULL
}
static void remember_type (struct work_stuff *, const char *, int);
+static void push_processed_type (struct work_stuff *, int);
+
+static void pop_processed_type (struct work_stuff *);
+
static void remember_Btype (struct work_stuff *, const char *, int, int);
static int register_Btype (struct work_stuff *);
if (GNAT_DEMANGLING)
return ada_demangle (mangled, options);
+ if (DLANG_DEMANGLING)
+ {
+ ret = dlang_demangle (mangled, options);
+ if (ret)
+ return ret;
+ }
+
ret = internal_cplus_demangle (work, mangled);
squangle_mop_up (work);
return (ret);
{
free ((char *) work -> btypevec);
work->btypevec = NULL;
+ work->bsize = 0;
}
if (work -> ktypevec != NULL)
{
free ((char *) work -> ktypevec);
work->ktypevec = NULL;
+ work->ksize = 0;
}
}
memcpy (to->btypevec[i], from->btypevec[i], len);
}
+ if (from->proctypevec)
+ to->proctypevec =
+ XDUPVEC (int, from->proctypevec, from->proctypevec_size);
+
if (from->ntmpl_args)
to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
/* Discard the remembered types, if any. */
forget_types (work);
- if (work -> typevec != NULL)
+ if (work->typevec != NULL)
{
- free ((char *) work -> typevec);
- work -> typevec = NULL;
- work -> typevec_size = 0;
+ free ((char *) work->typevec);
+ work->typevec = NULL;
+ work->typevec_size = 0;
+ }
+ if (work->proctypevec != NULL)
+ {
+ free (work->proctypevec);
+ work->proctypevec = NULL;
+ work->proctypevec_size = 0;
}
if (work->tmpl_argvec)
{
}
else if (tk == tk_real)
success = demangle_real_value (work, mangled, s);
- else if (tk == tk_pointer || tk == tk_reference)
+ else if (tk == tk_pointer || tk == tk_reference
+ || tk == tk_rvalue_reference)
{
if (**mangled == 'Q')
success = demangle_qualified (work, mangled, s,
else
{
int symbol_len = consume_count (mangled);
- if (symbol_len == -1)
+ if (symbol_len == -1
+ || symbol_len > (long) strlen (*mangled))
return -1;
if (symbol_len == 0)
string_appendn (s, "0", 1);
success = 1;
break;
}
+ else if (n == -1)
+ {
+ success = 0;
+ break;
+ }
}
else
{
do_type (struct work_stuff *work, const char **mangled, string *result)
{
int n;
+ int i;
+ int is_proctypevec;
int done;
int success;
string decl;
done = 0;
success = 1;
+ is_proctypevec = 0;
while (success && !done)
{
int member;
tk = tk_reference;
break;
+ /* An rvalue reference type */
+ case 'O':
+ (*mangled)++;
+ string_prepend (&decl, "&&");
+ if (tk == tk_none)
+ tk = tk_rvalue_reference;
+ break;
+
/* An array */
case 'A':
{
/* A back reference to a previously seen type */
case 'T':
(*mangled)++;
- if (!get_count (mangled, &n) || n >= work -> ntypes)
+ if (!get_count (mangled, &n) || n < 0 || n >= work -> ntypes)
{
success = 0;
}
else
- {
- remembered_type = work -> typevec[n];
+ for (i = 0; i < work->nproctypes; i++)
+ if (work -> proctypevec [i] == n)
+ success = 0;
+
+ if (success)
+ {
+ is_proctypevec = 1;
+ push_processed_type (work, n);
+ remembered_type = work->typevec[n];
mangled = &remembered_type;
}
break;
break;
case 'M':
- case 'O':
{
type_quals = TYPE_UNQUALIFIED;
/* A back reference to a previously seen squangled type */
case 'B':
(*mangled)++;
- if (!get_count (mangled, &n) || n >= work -> numb)
+ if (!get_count (mangled, &n) || n < 0 || n >= work -> numb)
success = 0;
else
string_append (result, work->btypevec[n]);
string_delete (result);
string_delete (&decl);
+ if (is_proctypevec)
+ pop_processed_type (work);
+
if (success)
/* Assume an integral type, if we're not sure. */
return (int) ((tk == tk_none) ? tk_integral : tk);
literal_len = consume_count (mangled);
- if (literal_len <= 0)
+ if (literal_len <= 0
+ || literal_len > (long) strlen (*mangled))
return 0;
/* Literal parameters are names of arrays, functions, etc. and the
return 1;
}
+static void
+push_processed_type (struct work_stuff *work, int typevec_index)
+{
+ if (work->nproctypes >= work->proctypevec_size)
+ {
+ if (!work->proctypevec_size)
+ {
+ work->proctypevec_size = 4;
+ work->proctypevec = XNEWVEC (int, work->proctypevec_size);
+ }
+ else
+ {
+ if (work->proctypevec_size < 16)
+ /* Double when small. */
+ work->proctypevec_size *= 2;
+ else
+ {
+ /* Grow slower when large. */
+ if (work->proctypevec_size > (INT_MAX / 3) * 2)
+ xmalloc_failed (INT_MAX);
+ work->proctypevec_size = (work->proctypevec_size * 3 / 2);
+ }
+ work->proctypevec
+ = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size);
+ }
+ }
+ work->proctypevec [work->nproctypes++] = typevec_index;
+}
+
+static void
+pop_processed_type (struct work_stuff *work)
+{
+ work->nproctypes--;
+}
+
static void
remember_type (struct work_stuff *work, const char *start, int len)
{
}
else
{
+ if (work -> typevec_size > INT_MAX / 2)
+ xmalloc_failed (INT_MAX);
work -> typevec_size *= 2;
work -> typevec
= XRESIZEVEC (char *, work->typevec, work->typevec_size);
}
else
{
+ if (work -> ksize > INT_MAX / 2)
+ xmalloc_failed (INT_MAX);
work -> ksize *= 2;
work -> ktypevec
= XRESIZEVEC (char *, work->ktypevec, work->ksize);
}
else
{
+ if (work -> bsize > INT_MAX / 2)
+ xmalloc_failed (INT_MAX);
work -> bsize *= 2;
work -> btypevec
= XRESIZEVEC (char *, work->btypevec, work->bsize);
{
string_append (declp, ", ");
}
+ push_processed_type (work, t);
if (!do_arg (work, &tem, &arg))
{
+ pop_processed_type (work);
return (0);
}
+ pop_processed_type (work);
if (PRINT_ARG_TYPES)
{
string_appends (declp, &arg);
else if (s->e - s->p < n)
{
tem = s->p - s->b;
+ if (n > INT_MAX / 2 - tem)
+ xmalloc_failed (INT_MAX);
n += tem;
n *= 2;
s->b = XRESIZEVEC (char, s->b, n);
--- /dev/null
+/* Demangler for the D programming language
+ Copyright 2014, 2015, 2016 Free Software Foundation, Inc.
+ Written by Iain Buclaw (ibuclaw@gdcproject.org)
+
+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, see <http://www.gnu.org/licenses/>. */
+
+/* This file exports one function; dlang_demangle.
+
+ This file imports strtol for decoding mangled literals. */
+
+#if 0 /* in valgrind */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif /* ! in valgrind */
+
+#if 0 /* in valgrind */
+#include "safe-ctype.h"
+#endif /* ! in valgrind */
+
+#if 0 /* in valgrind */
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#endif /* ! in valgrind */
+
+#if 0 /* in valgrind */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern long strtol (const char *nptr, char **endptr, int base);
+#endif
+#endif /* ! in valgrind */
+
+#if 0 /* in valgrind */
+#include <demangle.h>
+#include "libiberty.h"
+#endif /* ! in valgrind */
+
+#include "vg_libciface.h"
+
+#include "ansidecl.h"
+#include "demangle.h"
+#include "safe-ctype.h"
+
+/* A mini string-handling package */
+
+typedef struct string /* Beware: these aren't required to be */
+{ /* '\0' terminated. */
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+static void
+string_need (string *s, int n)
+{
+ int tem;
+
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ {
+ n = 32;
+ }
+ s->p = s->b = XNEWVEC (char, n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = XRESIZEVEC (char, s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (string *s)
+{
+ if (s->b != NULL)
+ {
+ XDELETEVEC (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (string *s)
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static int
+string_length (string *s)
+{
+ if (s->p == s->b)
+ {
+ return 0;
+ }
+ return s->p - s->b;
+}
+
+static void
+string_setlength (string *s, int n)
+{
+ if (n - string_length (s) < 0)
+ {
+ s->p = s->b + n;
+ }
+}
+
+static void
+string_append (string *p, const char *s)
+{
+ int n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appendn (string *p, const char *s, int n)
+{
+ if (n != 0)
+ {
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_prependn (string *p, const char *s, int n)
+{
+ char *q;
+
+ if (n != 0)
+ {
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ {
+ q[n] = q[0];
+ }
+ memcpy (p->b, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_prepend (string *p, const char *s)
+{
+ if (s != NULL && *s != '\0')
+ {
+ string_prependn (p, s, strlen (s));
+ }
+}
+
+/* What kinds of symbol we could be parsing. */
+enum dlang_symbol_kinds
+{
+ /* Top-level symbol, needs it's type checked. */
+ dlang_top_level,
+ /* Function symbol, needs it's type checked. */
+ dlang_function,
+ /* Strongly typed name, such as for classes, structs and enums. */
+ dlang_type_name,
+ /* Template identifier. */
+ dlang_template_ident,
+ /* Template symbol parameter. */
+ dlang_template_param
+};
+
+/* Prototypes for forward referenced functions */
+static const char *dlang_function_args (string *, const char *);
+
+static const char *dlang_type (string *, const char *);
+
+static const char *dlang_value (string *, const char *, const char *, char);
+
+static const char *dlang_parse_symbol (string *, const char *,
+ enum dlang_symbol_kinds);
+
+static const char *dlang_parse_tuple (string *, const char *);
+
+static const char *dlang_parse_template (string *, const char *, long);
+
+
+/* Demangle the calling convention from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_call_convention (string *decl, const char *mangled)
+{
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ switch (*mangled)
+ {
+ case 'F': /* (D) */
+ mangled++;
+ break;
+ case 'U': /* (C) */
+ mangled++;
+ string_append (decl, "extern(C) ");
+ break;
+ case 'W': /* (Windows) */
+ mangled++;
+ string_append (decl, "extern(Windows) ");
+ break;
+ case 'V': /* (Pascal) */
+ mangled++;
+ string_append (decl, "extern(Pascal) ");
+ break;
+ case 'R': /* (C++) */
+ mangled++;
+ string_append (decl, "extern(C++) ");
+ break;
+ case 'Y': /* (Objective-C) */
+ mangled++;
+ string_append (decl, "extern(Objective-C) ");
+ break;
+ default:
+ return NULL;
+ }
+
+ return mangled;
+}
+
+/* Extract the type modifiers from MANGLED and append them to DECL.
+ Returns the remaining signature on success or NULL on failure. */
+static const char *
+dlang_type_modifiers (string *decl, const char *mangled)
+{
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ switch (*mangled)
+ {
+ case 'x': /* const */
+ mangled++;
+ string_append (decl, " const");
+ return mangled;
+ case 'y': /* immutable */
+ mangled++;
+ string_append (decl, " immutable");
+ return mangled;
+ case 'O': /* shared */
+ mangled++;
+ string_append (decl, " shared");
+ return dlang_type_modifiers (decl, mangled);
+ case 'N':
+ mangled++;
+ if (*mangled == 'g') /* wild */
+ {
+ mangled++;
+ string_append (decl, " inout");
+ return dlang_type_modifiers (decl, mangled);
+ }
+ else
+ return NULL;
+
+ default:
+ return mangled;
+ }
+}
+
+/* Demangle the D function attributes from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_attributes (string *decl, const char *mangled)
+{
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ while (*mangled == 'N')
+ {
+ mangled++;
+ switch (*mangled)
+ {
+ case 'a': /* pure */
+ mangled++;
+ string_append (decl, "pure ");
+ continue;
+ case 'b': /* nothrow */
+ mangled++;
+ string_append (decl, "nothrow ");
+ continue;
+ case 'c': /* ref */
+ mangled++;
+ string_append (decl, "ref ");
+ continue;
+ case 'd': /* @property */
+ mangled++;
+ string_append (decl, "@property ");
+ continue;
+ case 'e': /* @trusted */
+ mangled++;
+ string_append (decl, "@trusted ");
+ continue;
+ case 'f': /* @safe */
+ mangled++;
+ string_append (decl, "@safe ");
+ continue;
+ case 'g':
+ case 'h':
+ case 'k':
+ /* inout parameter is represented as 'Ng'.
+ vector parameter is represented as 'Nh'.
+ return paramenter is represented as 'Nk'.
+ If we see this, then we know we're really in the
+ parameter list. Rewind and break. */
+ mangled--;
+ break;
+ case 'i': /* @nogc */
+ mangled++;
+ string_append (decl, "@nogc ");
+ continue;
+ case 'j': /* return */
+ mangled++;
+ string_append (decl, "return ");
+ continue;
+
+ default: /* unknown attribute */
+ return NULL;
+ }
+ break;
+ }
+
+ return mangled;
+}
+
+/* Demangle the function type from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_function_type (string *decl, const char *mangled)
+{
+ string attr, args, type;
+ size_t szattr, szargs, sztype;
+
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ /* The order of the mangled string is:
+ CallConvention FuncAttrs Arguments ArgClose Type
+
+ The demangled string is re-ordered as:
+ CallConvention Type Arguments FuncAttrs
+ */
+ string_init (&attr);
+ string_init (&args);
+ string_init (&type);
+
+ /* Function call convention. */
+ mangled = dlang_call_convention (decl, mangled);
+
+ /* Function attributes. */
+ mangled = dlang_attributes (&attr, mangled);
+ szattr = string_length (&attr);
+
+ /* Function arguments. */
+ mangled = dlang_function_args (&args, mangled);
+ szargs = string_length (&args);
+
+ /* Function return type. */
+ mangled = dlang_type (&type, mangled);
+ sztype = string_length (&type);
+
+ /* Append to decl in order. */
+ string_appendn (decl, type.b, sztype);
+ string_append (decl, "(");
+ string_appendn (decl, args.b, szargs);
+ string_append (decl, ") ");
+ string_appendn (decl, attr.b, szattr);
+
+ string_delete (&attr);
+ string_delete (&args);
+ string_delete (&type);
+ return mangled;
+}
+
+/* Demangle the argument list from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_function_args (string *decl, const char *mangled)
+{
+ size_t n = 0;
+
+ while (mangled && *mangled != '\0')
+ {
+ switch (*mangled)
+ {
+ case 'X': /* (variadic T t...) style. */
+ mangled++;
+ string_append (decl, "...");
+ return mangled;
+ case 'Y': /* (variadic T t, ...) style. */
+ mangled++;
+ if (n != 0)
+ string_append (decl, ", ");
+ string_append (decl, "...");
+ return mangled;
+ case 'Z': /* Normal function. */
+ mangled++;
+ return mangled;
+ }
+
+ if (n++)
+ string_append (decl, ", ");
+
+ if (*mangled == 'M') /* scope(T) */
+ {
+ mangled++;
+ string_append (decl, "scope ");
+ }
+
+ if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */
+ {
+ mangled += 2;
+ string_append (decl, "return ");
+ }
+
+ switch (*mangled)
+ {
+ case 'J': /* out(T) */
+ mangled++;
+ string_append (decl, "out ");
+ break;
+ case 'K': /* ref(T) */
+ mangled++;
+ string_append (decl, "ref ");
+ break;
+ case 'L': /* lazy(T) */
+ mangled++;
+ string_append (decl, "lazy ");
+ break;
+ }
+ mangled = dlang_type (decl, mangled);
+ }
+
+ return mangled;
+}
+
+/* Demangle the type from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_type (string *decl, const char *mangled)
+{
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ switch (*mangled)
+ {
+ case 'O': /* shared(T) */
+ mangled++;
+ string_append (decl, "shared(");
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, ")");
+ return mangled;
+ case 'x': /* const(T) */
+ mangled++;
+ string_append (decl, "const(");
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, ")");
+ return mangled;
+ case 'y': /* immutable(T) */
+ mangled++;
+ string_append (decl, "immutable(");
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, ")");
+ return mangled;
+ case 'N':
+ mangled++;
+ if (*mangled == 'g') /* wild(T) */
+ {
+ mangled++;
+ string_append (decl, "inout(");
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, ")");
+ return mangled;
+ }
+ else if (*mangled == 'h') /* vector(T) */
+ {
+ mangled++;
+ string_append (decl, "__vector(");
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, ")");
+ return mangled;
+ }
+ else
+ return NULL;
+ case 'A': /* dynamic array (T[]) */
+ mangled++;
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, "[]");
+ return mangled;
+ case 'G': /* static array (T[N]) */
+ {
+ const char *numptr;
+ size_t num = 0;
+ mangled++;
+
+ numptr = mangled;
+ while (ISDIGIT (*mangled))
+ {
+ num++;
+ mangled++;
+ }
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, "[");
+ string_appendn (decl, numptr, num);
+ string_append (decl, "]");
+ return mangled;
+ }
+ case 'H': /* associative array (T[T]) */
+ {
+ string type;
+ size_t sztype;
+ mangled++;
+
+ string_init (&type);
+ mangled = dlang_type (&type, mangled);
+ sztype = string_length (&type);
+
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, "[");
+ string_appendn (decl, type.b, sztype);
+ string_append (decl, "]");
+
+ string_delete (&type);
+ return mangled;
+ }
+ case 'P': /* pointer (T*) */
+ mangled++;
+ /* Function pointer types don't include the trailing asterisk. */
+ switch (*mangled)
+ {
+ case 'F': case 'U': case 'W':
+ case 'V': case 'R': case 'Y':
+ mangled = dlang_function_type (decl, mangled);
+ string_append (decl, "function");
+ return mangled;
+ }
+ mangled = dlang_type (decl, mangled);
+ string_append (decl, "*");
+ return mangled;
+ case 'I': /* ident T */
+ case 'C': /* class T */
+ case 'S': /* struct T */
+ case 'E': /* enum T */
+ case 'T': /* typedef T */
+ mangled++;
+ return dlang_parse_symbol (decl, mangled, dlang_type_name);
+ case 'D': /* delegate T */
+ {
+ string mods;
+ size_t szmods;
+ mangled++;
+
+ string_init (&mods);
+ mangled = dlang_type_modifiers (&mods, mangled);
+ szmods = string_length (&mods);
+
+ mangled = dlang_function_type (decl, mangled);
+ string_append (decl, "delegate");
+ string_appendn (decl, mods.b, szmods);
+
+ string_delete (&mods);
+ return mangled;
+ }
+ case 'B': /* tuple T */
+ mangled++;
+ return dlang_parse_tuple (decl, mangled);
+
+ /* Basic types */
+ case 'n':
+ mangled++;
+ string_append (decl, "none");
+ return mangled;
+ case 'v':
+ mangled++;
+ string_append (decl, "void");
+ return mangled;
+ case 'g':
+ mangled++;
+ string_append (decl, "byte");
+ return mangled;
+ case 'h':
+ mangled++;
+ string_append (decl, "ubyte");
+ return mangled;
+ case 's':
+ mangled++;
+ string_append (decl, "short");
+ return mangled;
+ case 't':
+ mangled++;
+ string_append (decl, "ushort");
+ return mangled;
+ case 'i':
+ mangled++;
+ string_append (decl, "int");
+ return mangled;
+ case 'k':
+ mangled++;
+ string_append (decl, "uint");
+ return mangled;
+ case 'l':
+ mangled++;
+ string_append (decl, "long");
+ return mangled;
+ case 'm':
+ mangled++;
+ string_append (decl, "ulong");
+ return mangled;
+ case 'f':
+ mangled++;
+ string_append (decl, "float");
+ return mangled;
+ case 'd':
+ mangled++;
+ string_append (decl, "double");
+ return mangled;
+ case 'e':
+ mangled++;
+ string_append (decl, "real");
+ return mangled;
+
+ /* Imaginary and Complex types */
+ case 'o':
+ mangled++;
+ string_append (decl, "ifloat");
+ return mangled;
+ case 'p':
+ mangled++;
+ string_append (decl, "idouble");
+ return mangled;
+ case 'j':
+ mangled++;
+ string_append (decl, "ireal");
+ return mangled;
+ case 'q':
+ mangled++;
+ string_append (decl, "cfloat");
+ return mangled;
+ case 'r':
+ mangled++;
+ string_append (decl, "cdouble");
+ return mangled;
+ case 'c':
+ mangled++;
+ string_append (decl, "creal");
+ return mangled;
+
+ /* Other types */
+ case 'b':
+ mangled++;
+ string_append (decl, "bool");
+ return mangled;
+ case 'a':
+ mangled++;
+ string_append (decl, "char");
+ return mangled;
+ case 'u':
+ mangled++;
+ string_append (decl, "wchar");
+ return mangled;
+ case 'w':
+ mangled++;
+ string_append (decl, "dchar");
+ return mangled;
+ case 'z':
+ mangled++;
+ switch (*mangled)
+ {
+ case 'i':
+ mangled++;
+ string_append (decl, "cent");
+ return mangled;
+ case 'k':
+ mangled++;
+ string_append (decl, "ucent");
+ return mangled;
+ }
+ return NULL;
+
+ default: /* unhandled */
+ return NULL;
+ }
+}
+
+/* Extract the identifier from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_identifier (string *decl, const char *mangled,
+ enum dlang_symbol_kinds kind)
+{
+ char *endptr;
+ long len;
+
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ len = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || len <= 0)
+ return NULL;
+
+ /* In template parameter symbols, the first character of the mangled
+ name can be a digit. This causes ambiguity issues because the
+ digits of the two numbers are adjacent. */
+ if (kind == dlang_template_param)
+ {
+ long psize = len;
+ char *pend;
+ int saved = string_length (decl);
+
+ /* Work backwards until a match is found. */
+ for (pend = endptr; endptr != NULL; pend--)
+ {
+ mangled = pend;
+
+ /* Reached the beginning of the pointer to the name length,
+ try parsing the entire symbol. */
+ if (psize == 0)
+ {
+ psize = len;
+ pend = endptr;
+ endptr = NULL;
+ }
+
+ /* Check whether template parameter is a function with a valid
+ return type or an untyped identifier. */
+ if (ISDIGIT (*mangled))
+ mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident);
+ else if (strncmp (mangled, "_D", 2) == 0)
+ {
+ mangled += 2;
+ mangled = dlang_parse_symbol (decl, mangled, dlang_function);
+ }
+
+ /* Check for name length mismatch. */
+ if (mangled && (mangled - pend) == psize)
+ return mangled;
+
+ psize /= 10;
+ string_setlength (decl, saved);
+ }
+
+ /* No match on any combinations. */
+ return NULL;
+ }
+ else
+ {
+ if (strlen (endptr) < (size_t) len)
+ return NULL;
+
+ mangled = endptr;
+
+ /* May be a template instance. */
+ if (len >= 5 && strncmp (mangled, "__T", 3) == 0)
+ {
+ /* Template symbol. */
+ if (ISDIGIT (mangled[3]) && mangled[3] != '0')
+ return dlang_parse_template (decl, mangled, len);
+
+ return NULL;
+ }
+
+ switch (len)
+ {
+ case 6:
+ if (strncmp (mangled, "__ctor", len) == 0)
+ {
+ /* Constructor symbol for a class/struct. */
+ string_append (decl, "this");
+ mangled += len;
+ return mangled;
+ }
+ else if (strncmp (mangled, "__dtor", len) == 0)
+ {
+ /* Destructor symbol for a class/struct. */
+ string_append (decl, "~this");
+ mangled += len;
+ return mangled;
+ }
+ else if (strncmp (mangled, "__initZ", len+1) == 0)
+ {
+ /* The static initialiser for a given symbol. */
+ string_append (decl, "init$");
+ mangled += len;
+ return mangled;
+ }
+ else if (strncmp (mangled, "__vtblZ", len+1) == 0)
+ {
+ /* The vtable symbol for a given class. */
+ string_prepend (decl, "vtable for ");
+ string_setlength (decl, string_length (decl) - 1);
+ mangled += len;
+ return mangled;
+ }
+ break;
+
+ case 7:
+ if (strncmp (mangled, "__ClassZ", len+1) == 0)
+ {
+ /* The classinfo symbol for a given class. */
+ string_prepend (decl, "ClassInfo for ");
+ string_setlength (decl, string_length (decl) - 1);
+ mangled += len;
+ return mangled;
+ }
+ break;
+
+ case 10:
+ if (strncmp (mangled, "__postblitMFZ", len+3) == 0)
+ {
+ /* Postblit symbol for a struct. */
+ string_append (decl, "this(this)");
+ mangled += len + 3;
+ return mangled;
+ }
+ break;
+
+ case 11:
+ if (strncmp (mangled, "__InterfaceZ", len+1) == 0)
+ {
+ /* The interface symbol for a given class. */
+ string_prepend (decl, "Interface for ");
+ string_setlength (decl, string_length (decl) - 1);
+ mangled += len;
+ return mangled;
+ }
+ break;
+
+ case 12:
+ if (strncmp (mangled, "__ModuleInfoZ", len+1) == 0)
+ {
+ /* The ModuleInfo symbol for a given module. */
+ string_prepend (decl, "ModuleInfo for ");
+ string_setlength (decl, string_length (decl) - 1);
+ mangled += len;
+ return mangled;
+ }
+ break;
+ }
+
+ string_appendn (decl, mangled, len);
+ mangled += len;
+ }
+
+ return mangled;
+}
+
+/* Extract the integer value from MANGLED and append it to DECL,
+ where TYPE is the type it should be represented as.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_integer (string *decl, const char *mangled, char type)
+{
+ if (type == 'a' || type == 'u' || type == 'w')
+ {
+ /* Parse character value. */
+ char value[10];
+ int pos = 10;
+ int width = 0;
+ char *endptr;
+ long val = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || val < 0)
+ return NULL;
+
+ string_append (decl, "'");
+
+ if (type == 'a' && val >= 0x20 && val < 0x7F)
+ {
+ /* Represent as a character literal. */
+ char c = (char) val;
+ string_appendn (decl, &c, 1);
+ }
+ else
+ {
+ /* Represent as a hexadecimal value. */
+ switch (type)
+ {
+ case 'a': /* char */
+ string_append (decl, "\\x");
+ width = 2;
+ break;
+ case 'u': /* wchar */
+ string_append (decl, "\\u");
+ width = 4;
+ break;
+ case 'w': /* dchar */
+ string_append (decl, "\\U");
+ width = 8;
+ break;
+ }
+
+ while (val > 0)
+ {
+ int digit = val % 16;
+
+ if (digit < 10)
+ value[--pos] = (char)(digit + '0');
+ else
+ value[--pos] = (char)((digit - 10) + 'a');
+
+ val /= 16;
+ width--;
+ }
+
+ for (; width > 0; width--)
+ value[--pos] = '0';
+
+ string_appendn (decl, &(value[pos]), 10 - pos);
+ }
+ string_append (decl, "'");
+ mangled = endptr;
+ }
+ else if (type == 'b')
+ {
+ /* Parse boolean value. */
+ char *endptr;
+ long val = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || val < 0)
+ return NULL;
+
+ string_append (decl, val ? "true" : "false");
+ mangled = endptr;
+ }
+ else
+ {
+ /* Parse integer value. */
+ const char *numptr = mangled;
+ size_t num = 0;
+
+ while (ISDIGIT (*mangled))
+ {
+ num++;
+ mangled++;
+ }
+ string_appendn (decl, numptr, num);
+
+ /* Append suffix. */
+ switch (type)
+ {
+ case 'h': /* ubyte */
+ case 't': /* ushort */
+ case 'k': /* uint */
+ string_append (decl, "u");
+ break;
+ case 'l': /* long */
+ string_append (decl, "L");
+ break;
+ case 'm': /* ulong */
+ string_append (decl, "uL");
+ break;
+ }
+ }
+
+ return mangled;
+}
+
+/* Extract the floating-point value from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_real (string *decl, const char *mangled)
+{
+ char buffer[64];
+ int len = 0;
+
+ /* Handle NAN and +-INF. */
+ if (strncmp (mangled, "NAN", 3) == 0)
+ {
+ string_append (decl, "NaN");
+ mangled += 3;
+ return mangled;
+ }
+ else if (strncmp (mangled, "INF", 3) == 0)
+ {
+ string_append (decl, "Inf");
+ mangled += 3;
+ return mangled;
+ }
+ else if (strncmp (mangled, "NINF", 4) == 0)
+ {
+ string_append (decl, "-Inf");
+ mangled += 4;
+ return mangled;
+ }
+
+ /* Hexadecimal prefix and leading bit. */
+ if (*mangled == 'N')
+ {
+ buffer[len++] = '-';
+ mangled++;
+ }
+
+ if (!ISXDIGIT (*mangled))
+ return NULL;
+
+ buffer[len++] = '0';
+ buffer[len++] = 'x';
+ buffer[len++] = *mangled;
+ buffer[len++] = '.';
+ mangled++;
+
+ /* Significand. */
+ while (ISXDIGIT (*mangled))
+ {
+ buffer[len++] = *mangled;
+ mangled++;
+ }
+
+ /* Exponent. */
+ if (*mangled != 'P')
+ return NULL;
+
+ buffer[len++] = 'p';
+ mangled++;
+
+ if (*mangled == 'N')
+ {
+ buffer[len++] = '-';
+ mangled++;
+ }
+
+ while (ISDIGIT (*mangled))
+ {
+ buffer[len++] = *mangled;
+ mangled++;
+ }
+
+ /* Write out the demangled hexadecimal, rather than trying to
+ convert the buffer into a floating-point value. */
+ buffer[len] = '\0';
+ len = strlen (buffer);
+ string_appendn (decl, buffer, len);
+ return mangled;
+}
+
+/* Convert VAL from an ascii hexdigit to value. */
+static char
+ascii2hex (char val)
+{
+ if (val >= 'a' && val <= 'f')
+ return (val - 'a' + 10);
+
+ if (val >= 'A' && val <= 'F')
+ return (val - 'A' + 10);
+
+ if (val >= '0' && val <= '9')
+ return (val - '0');
+
+ return 0;
+}
+
+/* Extract the string value from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_string (string *decl, const char *mangled)
+{
+ char type = *mangled;
+ char *endptr;
+ long len;
+
+ mangled++;
+ len = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || len < 0)
+ return NULL;
+
+ mangled = endptr;
+ if (*mangled != '_')
+ return NULL;
+
+ mangled++;
+ string_append (decl, "\"");
+ while (len--)
+ {
+ if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
+ {
+ char a = ascii2hex (mangled[0]);
+ char b = ascii2hex (mangled[1]);
+ char val = (a << 4) | b;
+
+ /* Sanitize white and non-printable characters. */
+ switch (val)
+ {
+ case ' ':
+ string_append (decl, " ");
+ break;
+ case '\t':
+ string_append (decl, "\\t");
+ break;
+ case '\n':
+ string_append (decl, "\\n");
+ break;
+ case '\r':
+ string_append (decl, "\\r");
+ break;
+ case '\f':
+ string_append (decl, "\\f");
+ break;
+ case '\v':
+ string_append (decl, "\\v");
+ break;
+
+ default:
+ if (ISPRINT (val))
+ string_appendn (decl, &val, 1);
+ else
+ {
+ string_append (decl, "\\x");
+ string_appendn (decl, mangled, 2);
+ }
+ }
+ }
+ else
+ return NULL;
+
+ mangled += 2;
+ }
+ string_append (decl, "\"");
+
+ if (type != 'a')
+ string_appendn (decl, &type, 1);
+
+ return mangled;
+}
+
+/* Extract the static array value from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_arrayliteral (string *decl, const char *mangled)
+{
+ char *endptr;
+ long elements = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || elements < 0)
+ return NULL;
+
+ mangled = endptr;
+ string_append (decl, "[");
+ while (elements--)
+ {
+ mangled = dlang_value (decl, mangled, NULL, '\0');
+ if (elements != 0)
+ string_append (decl, ", ");
+ }
+
+ string_append (decl, "]");
+ return mangled;
+}
+
+/* Extract the associative array value from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_assocarray (string *decl, const char *mangled)
+{
+ char *endptr;
+ long elements = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || elements < 0)
+ return NULL;
+
+ mangled = endptr;
+ string_append (decl, "[");
+ while (elements--)
+ {
+ mangled = dlang_value (decl, mangled, NULL, '\0');
+ string_append (decl, ":");
+ mangled = dlang_value (decl, mangled, NULL, '\0');
+
+ if (elements != 0)
+ string_append (decl, ", ");
+ }
+
+ string_append (decl, "]");
+ return mangled;
+}
+
+/* Extract the struct literal value for NAME from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_structlit (string *decl, const char *mangled, const char *name)
+{
+ char *endptr;
+ long args = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || args < 0)
+ return NULL;
+
+ mangled = endptr;
+ if (name != NULL)
+ string_append (decl, name);
+
+ string_append (decl, "(");
+ while (args--)
+ {
+ mangled = dlang_value (decl, mangled, NULL, '\0');
+ if (args != 0)
+ string_append (decl, ", ");
+ }
+
+ string_append (decl, ")");
+ return mangled;
+}
+
+/* Extract the value from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_value (string *decl, const char *mangled, const char *name, char type)
+{
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ switch (*mangled)
+ {
+ /* Null value. */
+ case 'n':
+ mangled++;
+ string_append (decl, "null");
+ break;
+
+ /* Integral values. */
+ case 'N':
+ mangled++;
+ string_append (decl, "-");
+ mangled = dlang_parse_integer (decl, mangled, type);
+ break;
+
+ case 'i':
+ mangled++;
+ if (*mangled < '0' || *mangled > '9')
+ return NULL;
+ /* Fall through */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ mangled = dlang_parse_integer (decl, mangled, type);
+ break;
+
+ /* Real value. */
+ case 'e':
+ mangled++;
+ mangled = dlang_parse_real (decl, mangled);
+ break;
+
+ /* Complex value. */
+ case 'c':
+ mangled++;
+ mangled = dlang_parse_real (decl, mangled);
+ string_append (decl, "+");
+ if (mangled == NULL || *mangled != 'c')
+ return NULL;
+ mangled++;
+ mangled = dlang_parse_real (decl, mangled);
+ string_append (decl, "i");
+ break;
+
+ /* String values. */
+ case 'a': /* UTF8 */
+ case 'w': /* UTF16 */
+ case 'd': /* UTF32 */
+ mangled = dlang_parse_string (decl, mangled);
+ break;
+
+ /* Array values. */
+ case 'A':
+ mangled++;
+ if (type == 'H')
+ mangled = dlang_parse_assocarray (decl, mangled);
+ else
+ mangled = dlang_parse_arrayliteral (decl, mangled);
+ break;
+
+ /* Struct values. */
+ case 'S':
+ mangled++;
+ mangled = dlang_parse_structlit (decl, mangled, name);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return mangled;
+}
+
+/* Extract the type modifiers from MANGLED and return the string
+ length that it consumes in MANGLED on success or 0 on failure. */
+static int
+dlang_type_modifier_p (const char *mangled)
+{
+ int i;
+
+ switch (*mangled)
+ {
+ case 'x': case 'y':
+ return 1;
+
+ case 'O':
+ mangled++;
+ i = dlang_type_modifier_p (mangled);
+ return i + 1;
+
+ case 'N':
+ mangled++;
+ if (*mangled == 'g')
+ {
+ mangled++;
+ i = dlang_type_modifier_p (mangled);
+ return i + 2;
+ }
+ }
+
+ return 0;
+}
+
+/* Extract the function calling convention from MANGLED and
+ return 1 on success or 0 on failure. */
+static int
+dlang_call_convention_p (const char *mangled)
+{
+ /* Prefix for functions needing 'this' */
+ if (*mangled == 'M')
+ {
+ mangled++;
+ /* Also skip over any type modifiers. */
+ mangled += dlang_type_modifier_p (mangled);
+ }
+
+ switch (*mangled)
+ {
+ case 'F': case 'U': case 'V':
+ case 'W': case 'R': case 'Y':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Extract and demangle the symbol in MANGLED and append it to DECL.
+ Returns the remaining signature on success or NULL on failure. */
+static const char *
+dlang_parse_symbol (string *decl, const char *mangled,
+ enum dlang_symbol_kinds kind)
+{
+ int saved;
+ size_t n = 0;
+ do
+ {
+ if (n++)
+ string_append (decl, ".");
+
+ mangled = dlang_identifier (decl, mangled, kind);
+
+ if (mangled && dlang_call_convention_p (mangled))
+ {
+ string mods;
+ const char *start = NULL;
+ int checkpoint = 0;
+
+ /* Skip over 'this' parameter. */
+ if (*mangled == 'M')
+ mangled++;
+
+ /* We have reached here because we expect an extern(Pascal) function.
+ However this is so rare, that it is more likely a template value
+ parameter. Since this can't be assumed, first attempt parsing
+ the symbol as a function, and then back out on failure. */
+ if (*mangled == 'V')
+ {
+ start = mangled;
+ checkpoint = string_length (decl);
+ }
+
+ /* Save the type modifiers for appending at the end. */
+ string_init (&mods);
+ mangled = dlang_type_modifiers (&mods, mangled);
+
+ /* Skip over calling convention and attributes in qualified name. */
+ saved = string_length (decl);
+ mangled = dlang_call_convention (decl, mangled);
+ mangled = dlang_attributes (decl, mangled);
+ string_setlength (decl, saved);
+
+ string_append (decl, "(");
+ mangled = dlang_function_args (decl, mangled);
+ string_append (decl, ")");
+
+ /* Add any const/immutable/shared modifier. */
+ string_appendn (decl, mods.b, string_length (&mods));
+ string_delete (&mods);
+
+ if (mangled == NULL && checkpoint != 0)
+ {
+ mangled = start;
+ string_setlength (decl, checkpoint);
+ }
+ }
+ }
+ while (mangled && ISDIGIT (*mangled));
+
+ /* Only top-level symbols or function template parameters have
+ a type that needs checking. */
+ if (kind == dlang_top_level || kind == dlang_function)
+ {
+ /* Artificial symbols end with 'Z' and have no type. */
+ if (mangled && *mangled == 'Z')
+ mangled++;
+ else
+ {
+ saved = string_length (decl);
+ mangled = dlang_type (decl, mangled);
+ string_setlength (decl, saved);
+ }
+
+ /* Check that the entire symbol was successfully demangled. */
+ if (kind == dlang_top_level)
+ {
+ if (mangled == NULL || *mangled != '\0')
+ return NULL;
+ }
+ }
+
+ return mangled;
+}
+
+/* Demangle the tuple from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_parse_tuple (string *decl, const char *mangled)
+{
+ char *endptr;
+ long elements = strtol (mangled, &endptr, 10);
+
+ if (endptr == NULL || elements < 0)
+ return NULL;
+
+ mangled = endptr;
+ string_append (decl, "Tuple!(");
+
+ while (elements--)
+ {
+ mangled = dlang_type (decl, mangled);
+ if (elements != 0)
+ string_append (decl, ", ");
+ }
+
+ string_append (decl, ")");
+ return mangled;
+}
+
+/* Demangle the argument list from MANGLED and append it to DECL.
+ Return the remaining string on success or NULL on failure. */
+static const char *
+dlang_template_args (string *decl, const char *mangled)
+{
+ size_t n = 0;
+
+ while (mangled && *mangled != '\0')
+ {
+ switch (*mangled)
+ {
+ case 'Z': /* End of parameter list. */
+ mangled++;
+ return mangled;
+ }
+
+ if (n++)
+ string_append (decl, ", ");
+
+ /* Skip over specialised template prefix. */
+ if (*mangled == 'H')
+ mangled++;
+
+ switch (*mangled)
+ {
+ case 'S': /* Symbol parameter. */
+ mangled++;
+ mangled = dlang_parse_symbol (decl, mangled, dlang_template_param);
+ break;
+ case 'T': /* Type parameter. */
+ mangled++;
+ mangled = dlang_type (decl, mangled);
+ break;
+ case 'V': /* Value parameter. */
+ {
+ string name;
+ char type;
+
+ /* Peek at the type. */
+ mangled++;
+ type = *mangled;
+
+ /* In the few instances where the type is actually desired in
+ the output, it should precede the value from dlang_value. */
+ string_init (&name);
+ mangled = dlang_type (&name, mangled);
+ string_need (&name, 1);
+ *(name.p) = '\0';
+
+ mangled = dlang_value (decl, mangled, name.b, type);
+ string_delete (&name);
+ break;
+ }
+
+ default:
+ return NULL;
+ }
+ }
+
+ return mangled;
+}
+
+/* Extract and demangle the template symbol in MANGLED, expected to
+ be made up of LEN characters, and append it to DECL.
+ Returns the remaining signature on success or NULL on failure. */
+static const char *
+dlang_parse_template (string *decl, const char *mangled, long len)
+{
+ const char *start = mangled;
+
+ /* Template instance names have the types and values of its parameters
+ encoded into it.
+
+ TemplateInstanceName:
+ Number __T LName TemplateArgs Z
+ ^
+ The start pointer should be at the above location, and LEN should be
+ the value of the decoded number.
+ */
+ if (strncmp (mangled, "__T", 3) != 0)
+ return NULL;
+
+ mangled += 3;
+
+ /* Template identifier. */
+ mangled = dlang_identifier (decl, mangled, dlang_template_ident);
+
+ /* Template arguments. */
+ string_append (decl, "!(");
+ mangled = dlang_template_args (decl, mangled);
+ string_append (decl, ")");
+
+ /* Check for template name length mismatch. */
+ if (mangled && (mangled - start) != len)
+ return NULL;
+
+ return mangled;
+}
+
+/* Extract and demangle the symbol in MANGLED. Returns the demangled
+ signature on success or NULL on failure. */
+
+char *
+dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
+{
+ string decl;
+ char *demangled = NULL;
+
+ if (mangled == NULL || *mangled == '\0')
+ return NULL;
+
+ if (strncmp (mangled, "_D", 2) != 0)
+ return NULL;
+
+ string_init (&decl);
+
+ if (strcmp (mangled, "_Dmain") == 0)
+ {
+ string_append (&decl, "D main");
+ }
+ else
+ {
+ mangled += 2;
+
+ if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL)
+ string_delete (&decl);
+ }
+
+ if (string_length (&decl) > 0)
+ {
+ string_need (&decl, 1);
+ *(decl.p) = '\0';
+ demangled = decl.b;
+ }
+
+ return demangled;
+}
+
/* Defs for interface to demanglers.
- Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
- 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
-
+ Copyright (C) 1992-2015 Free Software Foundation, Inc.
+
This program 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, or
#define DMGL_EDG (1 << 13)
#define DMGL_GNU_V3 (1 << 14)
#define DMGL_GNAT (1 << 15)
+#define DMGL_DLANG (1 << 16)
/* If none of these are set, use 'current_demangling_style' as the default. */
-#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG)
/* Enumeration of possible demangling styles.
edg_demangling = DMGL_EDG,
gnu_v3_demangling = DMGL_GNU_V3,
java_demangling = DMGL_JAVA,
- gnat_demangling = DMGL_GNAT
+ gnat_demangling = DMGL_GNAT,
+ dlang_demangling = DMGL_DLANG
} current_demangling_style;
/* Define string names for the various demangling styles. */
#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
#define JAVA_DEMANGLING_STYLE_STRING "java"
#define GNAT_DEMANGLING_STYLE_STRING "gnat"
+#define DLANG_DEMANGLING_STYLE_STRING "dlang"
/* Some macros to test what demangling style is active. */
#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
+#define DLANG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_DLANG)
/* Provide information about the available demangle styles. This code is
pulled from gdb into libiberty because it is useful to binutils also. */
extern void
set_cplus_marker_for_demangling (int ch);
-extern enum demangling_styles
+extern enum demangling_styles
cplus_demangle_set_style (enum demangling_styles style);
-extern enum demangling_styles
+extern enum demangling_styles
cplus_demangle_name_to_style (const char *name);
/* Callback typedef for allocation-less demangler interfaces. */
char *
ada_demangle (const char *mangled, int options);
+extern char *
+dlang_demangle (const char *mangled, int options);
+
enum gnu_v3_ctor_kinds {
gnu_v3_complete_object_ctor = 1,
gnu_v3_base_object_ctor,
/* A typecast, represented as a unary operator. The one subtree is
the type to which the argument should be cast. */
DEMANGLE_COMPONENT_CAST,
+ /* A conversion operator, represented as a unary operator. The one
+ subtree is the type to which the argument should be converted
+ to. */
+ DEMANGLE_COMPONENT_CONVERSION,
/* A nullary expression. The left subtree is the operator. */
DEMANGLE_COMPONENT_NULLARY,
/* A unary expression. The left subtree is the operator, and the
DEMANGLE_COMPONENT_PACK_EXPANSION,
/* A name with an ABI tag. */
DEMANGLE_COMPONENT_TAGGED_NAME,
+ /* A transaction-safe function type. */
+ DEMANGLE_COMPONENT_TRANSACTION_SAFE,
/* A cloned function. */
DEMANGLE_COMPONENT_CLONE
};
/* An abstract string datatype.
- Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GCC.
/* <ctype.h> replacement macros.
- Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 2000-2015 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library.
#define strpbrk(_ss,_aa) VG_(strpbrk)((_ss),(_aa))
#define strspn(_ss,_aa) VG_(strspn)((_ss),(_aa))
#define strstr(_hh,_nn) VG_(strstr)((_hh),(_nn))
+/* strtol supports base 16 or else assumes it is base 10 */
+#define strtol(s,r,b) ((b) == 16 ? \
+ VG_(strtoll16) ((s),(r)) \
+ : VG_(strtoll10) ((s),(r)))
+
#define size_t SizeT
#define xmalloc(_nn) \
VG_(arena_malloc)(VG_AR_DEMANGLE, "m_demangle.xmalloc", (_nn))
+#define xmalloc_failed(_sz) abort()
#define xrealloc(_pt,_sz) \
VG_(arena_realloc)(VG_AR_DEMANGLE,"m_demangle.xrealloc",(_pt),(_sz))
#define xstrdup(_str) \
VG_(arena_strdup)(VG_AR_DEMANGLE,"m_demangle.xstrdup",(_str))
+static inline void *xmemdup(const void *in, size_t c_size, size_t a_size) {
+ void *dst;
+ dst = VG_(arena_malloc)(VG_AR_DEMANGLE, "m_demangle.xmemdup", a_size);
+ if (a_size > c_size)
+ memset ((char *) dst + c_size, 0, a_size - c_size);
+ return memcpy (dst, in, c_size);
+}
+
/* Required by safe-ctype.h */
#undef EOF
#define XNEW(_Ty) \
((_Ty *) xmalloc(sizeof (_Ty)))
+#define XDELETEVEC(P) \
+ free ((void*) (P))
+
+#define XDUPVEC(T, P, N) \
+ ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N)))
/*--------------------------------------------------------------------*/
/*--- end vg_libciface.h ---*/