diff mbox

Sync libiberty with gcc

Message ID CABOHX+fvzPGoKSc6d_0xhQvhO5VHXUqM1ZSqmgSdAQzmPj-ZDA@mail.gmail.com
State New
Headers show

Commit Message

Iain Buclaw Sept. 29, 2014, 6:42 p.m. UTC
This patch to syncs libiberty with upstream gcc.

Largest change here is the addition of demangling dlang symbols, which
means following this will be the removal of dlang demangling on gdb's
side.

-- Iain.


libiberty/
2014-09-26  Jason Merrill  <jason@redhat.com>

       * cp-demangle.c (d_substitution): Handle abi tags on abbreviation.

2014-09-26  Max Ostapenko  <m.ostapenko@partner.samsung.com>

       * pex-common.h (struct pex_funcs): Add new parameter for
open_write field.
       * pex-unix.c (pex_unix_open_write): Add support for new parameter.
       * pex-djgpp.c (pex_djgpp_open_write): Likewise.
       * pex-win32.c (pex_win32_open_write): Likewise.
       * pex-common.c (pex_run_in_environment): Likewise.

2014-09-23  Iain Buclaw  <ibuclaw@gdcproject.org>

       * Makefile.in (CFILES): Add d-demangle.c.
       (REQUIRED_OFILES): Add d-demangle.o.
       * cplus-dem.c (libiberty_demanglers): Add dlang_demangling case.
       (cplus_demangle): Likewise.
       * d-demangle.c: New file.
       * testsuite/Makefile.in (really-check): Add check-d-demangle.
       * testsuite/d-demangle-expected: New file.

2014-09-19  Ian Lance Taylor  <iant@google.com>

       * simple-object-elf.c (simple_object_elf_write_ehdr): Correctly
       handle objects with more than SHN_LORESERVE sections.
       (simple_object_elf_write_shdr): Add sh_link parameter.
       (simple_object_elf_write_to_file): Correctly handle objects with
       more than SHN_LORESERVE sections.

2014-08-29  Andrew Burgess  <aburgess@broadcom.com>

       * cp-demangle.c (d_dump): Only access field from s_fixed part of
       the union for DEMANGLE_COMPONENT_FIXED_TYPE.
       (d_count_templates_scopes): Likewise.

2014-08-13  Gary Benson  <gbenson@redhat.com>

       * testsuite/demangler-fuzzer.c: New file.
       * testsuite/Makefile.in (fuzz-demangler): New rule.
       (demangler-fuzzer): Likewise.
       (mostlyclean): Clean up demangler fuzzer.
---

Comments

Pedro Alves Oct. 10, 2014, 2:54 p.m. UTC | #1
On 09/29/2014 07:42 PM, Iain Buclaw wrote:
> This patch to syncs libiberty with upstream gcc.
> 
> Largest change here is the addition of demangling dlang symbols, which
> means following this will be the removal of dlang demangling on gdb's
> side.

Thank Iain.  Please go ahead and push.

> 
> -- Iain.
> 
> 
> libiberty/
> 2014-09-26  Jason Merrill  <jason@redhat.com>
> 
>        * cp-demangle.c (d_substitution): Handle abi tags on abbreviation.
> 
> 2014-09-26  Max Ostapenko  <m.ostapenko@partner.samsung.com>
> 
>        * pex-common.h (struct pex_funcs): Add new parameter for
> open_write field.
>        * pex-unix.c (pex_unix_open_write): Add support for new parameter.
>        * pex-djgpp.c (pex_djgpp_open_write): Likewise.
>        * pex-win32.c (pex_win32_open_write): Likewise.
>        * pex-common.c (pex_run_in_environment): Likewise.
> 
> 2014-09-23  Iain Buclaw  <ibuclaw@gdcproject.org>
> 
>        * Makefile.in (CFILES): Add d-demangle.c.
>        (REQUIRED_OFILES): Add d-demangle.o.
>        * cplus-dem.c (libiberty_demanglers): Add dlang_demangling case.
>        (cplus_demangle): Likewise.
>        * d-demangle.c: New file.
>        * testsuite/Makefile.in (really-check): Add check-d-demangle.
>        * testsuite/d-demangle-expected: New file.
> 
> 2014-09-19  Ian Lance Taylor  <iant@google.com>
> 
>        * simple-object-elf.c (simple_object_elf_write_ehdr): Correctly
>        handle objects with more than SHN_LORESERVE sections.
>        (simple_object_elf_write_shdr): Add sh_link parameter.
>        (simple_object_elf_write_to_file): Correctly handle objects with
>        more than SHN_LORESERVE sections.
> 
> 2014-08-29  Andrew Burgess  <aburgess@broadcom.com>
> 
>        * cp-demangle.c (d_dump): Only access field from s_fixed part of
>        the union for DEMANGLE_COMPONENT_FIXED_TYPE.
>        (d_count_templates_scopes): Likewise.
> 
> 2014-08-13  Gary Benson  <gbenson@redhat.com>
> 
>        * testsuite/demangler-fuzzer.c: New file.
>        * testsuite/Makefile.in (fuzz-demangler): New rule.
>        (demangler-fuzzer): Likewise.
>        (mostlyclean): Clean up demangler fuzzer.
> ---
> 


Thanks,
Pedro Alves
Joel Brobecker Oct. 14, 2014, 1:38 p.m. UTC | #2
Hi Ian,

> 2014-09-23  Iain Buclaw  <ibuclaw@gdcproject.org>
> 
>        * Makefile.in (CFILES): Add d-demangle.c.
>        (REQUIRED_OFILES): Add d-demangle.o.
>        * cplus-dem.c (libiberty_demanglers): Add dlang_demangling case.
>        (cplus_demangle): Likewise.
>        * d-demangle.c: New file.
>        * testsuite/Makefile.in (really-check): Add check-d-demangle.
>        * testsuite/d-demangle-expected: New file.

Unfortunately, this part of the change breaks the build on Solaris 2.9.
And according to the gnulib documentation that function, it looks like
it'll break the build on the following hosts:

        NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, IRIX 6.5, OSF/1 4.0,
        Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS.

Not knowing D and whether you actually need long-double precision
or not, I didn't try to fix it. But it looks like the best option
would probably to add an strtold configure check, and then fallback
on strtod if strtold isn't available (and error out if strtod isn't)?


> 
> 2014-09-19  Ian Lance Taylor  <iant@google.com>
> 
>        * simple-object-elf.c (simple_object_elf_write_ehdr): Correctly
>        handle objects with more than SHN_LORESERVE sections.
>        (simple_object_elf_write_shdr): Add sh_link parameter.
>        (simple_object_elf_write_to_file): Correctly handle objects with
>        more than SHN_LORESERVE sections.
> 
> 2014-08-29  Andrew Burgess  <aburgess@broadcom.com>
> 
>        * cp-demangle.c (d_dump): Only access field from s_fixed part of
>        the union for DEMANGLE_COMPONENT_FIXED_TYPE.
>        (d_count_templates_scopes): Likewise.
> 
> 2014-08-13  Gary Benson  <gbenson@redhat.com>
> 
>        * testsuite/demangler-fuzzer.c: New file.
>        * testsuite/Makefile.in (fuzz-demangler): New rule.
>        (demangler-fuzzer): Likewise.
>        (mostlyclean): Clean up demangler fuzzer.
> ---

>  libiberty/Makefile.in                   |   12 +-
>  libiberty/cp-demangle.c                 |   21 +-
>  libiberty/cplus-dem.c                   |   13 +
>  libiberty/d-demangle.c                  | 1338 +++++++++++++++++++++++++++++++
>  libiberty/pex-common.c                  |    8 +-
>  libiberty/pex-common.h                  |    2 +-
>  libiberty/pex-djgpp.c                   |    6 +-
>  libiberty/pex-unix.c                    |    7 +-
>  libiberty/pex-win32.c                   |    6 +-
>  libiberty/simple-object-elf.c           |   38 +-
>  libiberty/testsuite/Makefile.in         |   14 +-
>  libiberty/testsuite/d-demangle-expected |  936 +++++++++++++++++++++
>  libiberty/testsuite/demangle-expected   |    8 +
>  libiberty/testsuite/demangler-fuzzer.c  |  108 +++
>  14 files changed, 2491 insertions(+), 26 deletions(-)
> 
> diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
> index 44e340f..9b87720 100644
> --- a/libiberty/Makefile.in
> +++ b/libiberty/Makefile.in
> @@ -127,7 +127,7 @@ CFILES = alloca.c argv.c asprintf.c atexit.c				\
>  	basename.c bcmp.c bcopy.c bsearch.c bzero.c			\
>  	calloc.c choose-temp.c clock.c concat.c cp-demangle.c		\
>  	 cp-demint.c cplus-dem.c crc32.c				\
> -	dwarfnames.c dyn-string.c					\
> +	d-demangle.c dwarfnames.c dyn-string.c				\
>  	fdmatch.c ffs.c fibheap.c filename_cmp.c floatformat.c		\
>  	fnmatch.c fopen_unlocked.c					\
>  	getcwd.c getopt.c getopt1.c getpagesize.c getpwd.c getruntime.c	\
> @@ -167,7 +167,7 @@ REQUIRED_OFILES =							\
>  	./md5.$(objext) ./sha1.$(objext) ./alloca.$(objext)		\
>  	./argv.$(objext)						\
>  	./choose-temp.$(objext) ./concat.$(objext)			\
> -	./cp-demint.$(objext) ./crc32.$(objext)				\
> +	./cp-demint.$(objext) ./crc32.$(objext) ./d-demangle.$(objext)	\
>  	./dwarfnames.$(objext) ./dyn-string.$(objext)			\
>  	./fdmatch.$(objext) ./fibheap.$(objext)				\
>  	./filename_cmp.$(objext) ./floatformat.$(objext)		\
> @@ -714,6 +714,14 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
>  	else true; fi
>  	$(COMPILE.c) $(srcdir)/dyn-string.c $(OUTPUT_OPTION)
>  
> +./d-demangle.$(objext): $(srcdir)/d-demangle.c config.h $(INCDIR)/ansidecl.h \
> +	$(srcdir)/cp-demangle.h $(INCDIR)/demangle.h \
> +	$(INCDIR)/dyn-string.h $(INCDIR)/getopt.h $(INCDIR)/libiberty.h
> +	if [ x"$(PICFLAG)" != x ]; then \
> +	  $(COMPILE.c) $(PICFLAG) $(srcdir)/d-demangle.c -o pic/$@; \
> +	else true; fi
> +	$(COMPILE.c) $(srcdir)/d-demangle.c $(OUTPUT_OPTION)
> +
>  ./fdmatch.$(objext): $(srcdir)/fdmatch.c config.h $(INCDIR)/ansidecl.h \
>  	$(INCDIR)/libiberty.h
>  	if [ x"$(PICFLAG)" != x ]; then \
> diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
> index c0d2ffe..77c2cee9 100644
> --- a/libiberty/cp-demangle.c
> +++ b/libiberty/cp-demangle.c
> @@ -713,7 +713,9 @@ d_dump (struct demangle_component *dc, int indent)
>        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");
> @@ -3685,6 +3687,7 @@ d_substitution (struct d_info *di, int prefix)
>  	    {
>  	      const char *s;
>  	      int len;
> +	      struct demangle_component *c;
>  
>  	      if (p->set_last_name != NULL)
>  		di->last_name = d_make_sub (di, p->set_last_name,
> @@ -3700,7 +3703,15 @@ d_substitution (struct d_info *di, int prefix)
>  		  len = p->simple_len;
>  		}
>  	      di->expansion += len;
> -	      return d_make_sub (di, s, len);
> +	      c = 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.  */
> +		  c = d_abi_tags (di, c);
> +		  d_add_substitution (di, c);
> +		}
> +	      return c;
>  	    }
>  	}
>  
> @@ -3875,7 +3886,6 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
>      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:
> @@ -3920,6 +3930,11 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
>  				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,
> diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
> index 52767cc..c68b981 100644
> --- a/libiberty/cplus-dem.c
> +++ b/libiberty/cplus-dem.c
> @@ -306,6 +306,12 @@ const struct demangler_engine libiberty_demanglers[] =
>    }
>    ,
>    {
> +    DLANG_DEMANGLING_STYLE_STRING,
> +    dlang_demangling,
> +    "DLANG style demangling"
> +  }
> +  ,
> +  {
>      NULL, unknown_demangling, NULL
>    }
>  };
> @@ -870,6 +876,13 @@ cplus_demangle (const char *mangled, int options)
>    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);
> diff --git a/libiberty/d-demangle.c b/libiberty/d-demangle.c
> new file mode 100644
> index 0000000..d31bf94
> --- /dev/null
> +++ b/libiberty/d-demangle.c
> @@ -0,0 +1,1338 @@
> +/* Demangler for the D programming language
> +   Copyright 2014 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 and strtold for decoding mangled literals.  */
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "safe-ctype.h"
> +
> +#include <sys/types.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +#ifdef HAVE_STDLIB_H
> +#include <stdlib.h>
> +#else
> +extern long strtol (const char *nptr, char **endptr, int base);
> +extern long double strtold (const char *nptr, char **endptr);
> +#endif
> +
> +#include <demangle.h>
> +#include "libiberty.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));
> +    }
> +}
> +
> +/* 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 *);
> +
> +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 mangled;
> +
> +  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;
> +    default:
> +      return NULL;
> +    }
> +
> +  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 mangled;
> +
> +  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':
> +	  /* inout parameter is represented as 'Ng'.
> +	     vector parameter is represented as 'Nh'.
> +	     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;
> +	}
> +      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 mangled;
> +
> +  /* 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++;
> +	  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 ");
> +	}
> +
> +      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 mangled;
> +
> +  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++;
> +      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);
> +    case 'D': /* delegate T */
> +      mangled++;
> +      mangled = dlang_function_type (decl, mangled);
> +      string_append (decl, "delegate");
> +      return mangled;
> +    case 'B': /* tuple T */
> +      mangled++;
> +      return dlang_parse_tuple (decl, mangled);
> +
> +    /* Function types */
> +    case 'F': case 'U': case 'W':
> +    case 'V': case 'R':
> +      mangled = dlang_function_type (decl, mangled);
> +      string_append (decl, "function");
> +      return 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;
> +
> +    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)
> +{
> +  if (mangled == NULL || *mangled == '\0')
> +    return mangled;
> +
> +  if (ISDIGIT (*mangled))
> +    {
> +      char *endptr;
> +      long i = strtol (mangled, &endptr, 10);
> +
> +      if (endptr == NULL || i <= 0 || strlen (endptr) < (size_t) i)
> +	return NULL;
> +
> +      mangled = endptr;
> +
> +      /* May be a template instance.  */
> +      if (i >= 5 && strncmp (mangled, "__T", 3) == 0)
> +	{
> +	  /* Template symbol.  */
> +	  if (ISDIGIT (mangled[3]) && mangled[3] != '0')
> +	    return dlang_parse_template (decl, mangled, i);
> +
> +	  return NULL;
> +	}
> +
> +      if (strncmp (mangled, "__ctor", i) == 0)
> +	{
> +	  /* Constructor symbol for a class/struct.  */
> +	  string_append (decl, "this");
> +	  mangled += i;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__dtor", i) == 0)
> +	{
> +	  /* Destructor symbol for a class/struct.  */
> +	  string_append (decl, "~this");
> +	  mangled += i;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__postblit", i) == 0)
> +	{
> +	  /* Postblit symbol for a struct.  */
> +	  string_append (decl, "this(this)");
> +	  mangled += i;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__initZ", i+1) == 0)
> +	{
> +	  /* The static initialiser for a given symbol.  */
> +	  string_append (decl, "init$");
> +	  mangled += i + 1;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__ClassZ", i+1) == 0)
> +	{
> +	  /* The classinfo symbol for a given class.  */
> +	  string_prepend (decl, "ClassInfo for ");
> +	  string_setlength (decl, string_length (decl) - 1);
> +	  mangled += i + 1;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__vtblZ", i+1) == 0)
> +	{
> +	  /* The vtable symbol for a given class.  */
> +	  string_prepend (decl, "vtable for ");
> +	  string_setlength (decl, string_length (decl) - 1);
> +	  mangled += i + 1;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__InterfaceZ", i+1) == 0)
> +	{
> +	  /* The interface symbol for a given class.  */
> +	  string_prepend (decl, "Interface for ");
> +	  string_setlength (decl, string_length (decl) - 1);
> +	  mangled += i + 1;
> +	  return mangled;
> +	}
> +      else if (strncmp (mangled, "__ModuleInfoZ", i+1) == 0)
> +	{
> +	  /* The ModuleInfo symbol for a given module.  */
> +	  string_prepend (decl, "ModuleInfo for ");
> +	  string_setlength (decl, string_length (decl) - 1);
> +	  mangled += i + 1;
> +	  return mangled;
> +	}
> +
> +      string_appendn (decl, mangled, i);
> +      mangled += i;
> +    }
> +  else
> +    return NULL;
> +
> +  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;
> +  long double value;
> +  char *endptr;
> +
> +  /* 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++;
> +    }
> +
> +  /* Convert buffer from hexadecimal to floating-point.  */
> +  buffer[len] = '\0';
> +  value = strtold (buffer, &endptr);
> +
> +  if (endptr == NULL || endptr != (buffer + len))
> +    return NULL;
> +
> +  len = snprintf (buffer, sizeof(buffer), "%#Lg", value);
> +  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;
> +	  string_appendn (decl, &val, 1);
> +	}
> +      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 mangled;
> +
> +  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;
> +}
> +
> +static int
> +dlang_call_convention_p (const char *mangled)
> +{
> +  size_t i;
> +
> +  switch (*mangled)
> +    {
> +    case 'F': case 'U': case 'V':
> +    case 'W': case 'R':
> +      return 1;
> +
> +    case 'M': /* Prefix for functions needing 'this' */
> +      i = 1;
> +      if (mangled[i] == 'x')
> +	i++;
> +
> +      switch (mangled[i])
> +	{
> +	case 'F': case 'U': case 'V':
> +	case 'W': case 'R':
> +	  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)
> +{
> +  size_t n = 0;
> +  do
> +    {
> +      if (n++)
> +	string_append (decl, ".");
> +
> +      mangled = dlang_identifier (decl, mangled);
> +
> +      if (mangled && dlang_call_convention_p (mangled))
> +	{
> +	  int saved;
> +
> +	  /* Skip over 'this' parameter.  */
> +	  if (*mangled == 'M')
> +	    mangled += (mangled[1] == 'x') ? 2 : 1;
> +
> +	  /* 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, ")");
> +
> +	  /* Demangle the function return type as a kind of sanity test.  */
> +	  if (mangled && !ISDIGIT (*mangled))
> +	    {
> +	      saved = string_length (decl);
> +	      mangled = dlang_type (decl, mangled);
> +	      string_setlength (decl, saved);
> +	    }
> +	}
> +    }
> +  while (mangled && ISDIGIT (*mangled));
> +
> +  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, ", ");
> +
> +      switch (*mangled)
> +	{
> +	case 'S': /* Symbol parameter.  */
> +	  mangled++;
> +	  mangled = dlang_parse_symbol (decl, mangled);
> +	  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);
> +
> +  /* 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) == NULL)
> +	string_delete (&decl);
> +    }
> +
> +  if (string_length (&decl) > 0)
> +    {
> +      string_need (&decl, 1);
> +      *(decl.p) = '\0';
> +      demangled = decl.b;
> +    }
> +
> +  return demangled;
> +}
> +
> diff --git a/libiberty/pex-common.c b/libiberty/pex-common.c
> index 6fd3fde..146010a 100644
> --- a/libiberty/pex-common.c
> +++ b/libiberty/pex-common.c
> @@ -267,7 +267,8 @@ pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
>    if (out < 0)
>      {
>        out = obj->funcs->open_write (obj, outname,
> -				    (flags & PEX_BINARY_OUTPUT) != 0);
> +				    (flags & PEX_BINARY_OUTPUT) != 0,
> +				    (flags & PEX_STDOUT_APPEND) != 0);
>        if (out < 0)
>  	{
>  	  *err = errno;
> @@ -319,8 +320,9 @@ pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
>      }
>    else
>      {
> -      errdes = obj->funcs->open_write (obj, errname, 
> -				       (flags & PEX_BINARY_ERROR) != 0);
> +      errdes = obj->funcs->open_write (obj, errname,
> +				       (flags & PEX_BINARY_ERROR) != 0,
> +				       (flags & PEX_STDERR_APPEND) != 0);
>        if (errdes < 0)
>  	{
>  	  *err = errno;
> diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h
> index af338e6..b6db248 100644
> --- a/libiberty/pex-common.h
> +++ b/libiberty/pex-common.h
> @@ -104,7 +104,7 @@ struct pex_funcs
>    /* Open file NAME for writing.  If BINARY is non-zero, open in
>       binary mode.  Return >= 0 on success, -1 on error.  */
>    int (*open_write) (struct pex_obj *, const char */* name */,
> -                     int /* binary */);
> +                     int /* binary */, int /* append */);
>    /* Execute a child process.  FLAGS, EXECUTABLE, ARGV, ERR are from
>       pex_run.  IN, OUT, ERRDES, TOCLOSE are all descriptors, from
>       open_read, open_write, or pipe, or they are one of STDIN_FILE_NO,
> diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c
> index 0721139..b014ffa 100644
> --- a/libiberty/pex-djgpp.c
> +++ b/libiberty/pex-djgpp.c
> @@ -43,7 +43,7 @@ extern int errno;
>  #endif
>  
>  static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
> -static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
> +static int pex_djgpp_open_write (struct pex_obj *, const char *, int, int);
>  static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *,
>  				  char * const *, char * const *,
>  				  int, int, int, int,
> @@ -90,10 +90,12 @@ pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
>  
>  static int
>  pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
> -		      const char *name, int binary)
> +		      const char *name, int binary, int append)
>  {
>    /* Note that we can't use O_EXCL here because gcc may have already
>       created the temporary file via make_temp_file.  */
> +  if (append)
> +    return -1;
>    return open (name,
>  	       (O_WRONLY | O_CREAT | O_TRUNC
>  		| (binary ? O_BINARY : O_TEXT)),
> diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c
> index addf8ee..0715115 100644
> --- a/libiberty/pex-unix.c
> +++ b/libiberty/pex-unix.c
> @@ -301,7 +301,7 @@ pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
>  static void pex_child_error (struct pex_obj *, const char *, const char *, int)
>       ATTRIBUTE_NORETURN;
>  static int pex_unix_open_read (struct pex_obj *, const char *, int);
> -static int pex_unix_open_write (struct pex_obj *, const char *, int);
> +static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
>  static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
>  				 char * const *, char * const *,
>  				 int, int, int, int,
> @@ -350,11 +350,12 @@ pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
>  
>  static int
>  pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
> -		     int binary ATTRIBUTE_UNUSED)
> +		     int binary ATTRIBUTE_UNUSED, int append)
>  {
>    /* Note that we can't use O_EXCL here because gcc may have already
>       created the temporary file via make_temp_file.  */
> -  return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
> +  return open (name, O_WRONLY | O_CREAT
> +		     | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
>  }
>  
>  /* Close a file.  */
> diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c
> index 8b9d4f0..66d2f11 100644
> --- a/libiberty/pex-win32.c
> +++ b/libiberty/pex-win32.c
> @@ -78,7 +78,7 @@ backslashify (char *s)
>  }
>  
>  static int pex_win32_open_read (struct pex_obj *, const char *, int);
> -static int pex_win32_open_write (struct pex_obj *, const char *, int);
> +static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
>  static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
>  				  char * const *, char * const *,
>                                    int, int, int, int,
> @@ -126,10 +126,12 @@ pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
>  
>  static int
>  pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
> -		      int binary)
> +		      int binary, int append)
>  {
>    /* Note that we can't use O_EXCL here because gcc may have already
>       created the temporary file via make_temp_file.  */
> +  if (append)
> +    return -1;
>    return _open (name,
>  		(_O_WRONLY | _O_CREAT | _O_TRUNC
>  		 | (binary ? _O_BINARY : _O_TEXT)),
> diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
> index 4196c53..8594cf9 100644
> --- a/libiberty/simple-object-elf.c
> +++ b/libiberty/simple-object-elf.c
> @@ -698,6 +698,7 @@ simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
>    unsigned char buf[sizeof (Elf64_External_Ehdr)];
>    simple_object_write_section *section;
>    unsigned int shnum;
> +  unsigned int shstrndx;
>  
>    fns = attrs->type_functions;
>    cl = attrs->ei_class;
> @@ -743,9 +744,17 @@ simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
>  		 (cl == ELFCLASS32
>  		  ? sizeof (Elf32_External_Shdr)
>  		  : sizeof (Elf64_External_Shdr)));
> -  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
> -  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
> -		 shnum == 0 ? 0 : shnum - 1);
> +  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
> +		 shnum >= SHN_LORESERVE ? 0 : shnum);
> +  if (shnum == 0)
> +    shstrndx = 0;
> +  else
> +    {
> +      shstrndx = shnum - 1;
> +      if (shstrndx >= SHN_LORESERVE)
> +	shstrndx = SHN_XINDEX;
> +    }
> +  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
>  
>    return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
>  				       errmsg, err);
> @@ -758,8 +767,8 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
>  			      off_t offset, unsigned int sh_name,
>  			      unsigned int sh_type, unsigned int sh_flags,
>  			      unsigned int sh_offset, unsigned int sh_size,
> -			      unsigned int sh_addralign, const char **errmsg,
> -			      int *err)
> +			      unsigned int sh_link, unsigned int sh_addralign,
> +			      const char **errmsg, int *err)
>  {
>    struct simple_object_elf_attributes *attrs =
>      (struct simple_object_elf_attributes *) sobj->data;
> @@ -781,7 +790,7 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
> -  /* sh_link left as zero.  */
> +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
>    /* sh_info left as zero.  */
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
>    /* sh_entsize left as zero.  */
> @@ -812,6 +821,8 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>    unsigned int shnum;
>    size_t shdr_offset;
>    size_t sh_offset;
> +  unsigned int first_sh_size;
> +  unsigned int first_sh_link;
>    size_t sh_name;
>    unsigned char zero;
>  
> @@ -842,8 +853,17 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>    shdr_offset = ehdr_size;
>    sh_offset = shdr_offset + shnum * shdr_size;
>  
> +  if (shnum < SHN_LORESERVE)
> +    first_sh_size = 0;
> +  else
> +    first_sh_size = shnum;
> +  if (shnum - 1 < SHN_LORESERVE)
> +    first_sh_link = 0;
> +  else
> +    first_sh_link = shnum - 1;
>    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> -				     0, 0, 0, 0, 0, 0, &errmsg, err))
> +				     0, 0, 0, 0, first_sh_size, first_sh_link,
> +				     0, &errmsg, err))
>      return errmsg;
>  
>    shdr_offset += shdr_size;
> @@ -887,7 +907,7 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>  
>        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
>  					 sh_name, SHT_PROGBITS, 0, sh_offset,
> -					 sh_size, 1U << section->align,
> +					 sh_size, 0, 1U << section->align,
>  					 &errmsg, err))
>  	return errmsg;
>  
> @@ -898,7 +918,7 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>  
>    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
>  				     sh_name, SHT_STRTAB, 0, sh_offset,
> -				     sh_name + strlen (".shstrtab") + 1,
> +				     sh_name + strlen (".shstrtab") + 1, 0,
>  				     1, &errmsg, err))
>      return errmsg;
>  
> diff --git a/libiberty/testsuite/Makefile.in b/libiberty/testsuite/Makefile.in
> index 69ac1f5..bb2db67 100644
> --- a/libiberty/testsuite/Makefile.in
> +++ b/libiberty/testsuite/Makefile.in
> @@ -45,12 +45,15 @@ all:
>  # CHECK is set to "really_check" or the empty string by configure.
>  check: @CHECK@
>  
> -really-check: check-cplus-dem check-pexecute check-expandargv
> +really-check: check-cplus-dem check-d-demangle check-pexecute check-expandargv
>  
>  # Run some tests of the demangler.
>  check-cplus-dem: test-demangle $(srcdir)/demangle-expected
>  	./test-demangle < $(srcdir)/demangle-expected
>  
> +check-d-demangle: test-demangle $(srcdir)/d-demangle-expected
> +	./test-demangle < $(srcdir)/d-demangle-expected
> +
>  # Check the pexecute code.
>  check-pexecute: test-pexecute
>  	./test-pexecute
> @@ -59,6 +62,10 @@ check-pexecute: test-pexecute
>  check-expandargv: test-expandargv
>  	./test-expandargv
>  
> +# Run the demangler fuzzer
> +fuzz-demangler: demangler-fuzzer
> +	./demangler-fuzzer
> +
>  TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES)
>  test-demangle: $(srcdir)/test-demangle.c ../libiberty.a
>  	$(TEST_COMPILE) -o test-demangle \
> @@ -72,6 +79,10 @@ test-expandargv: $(srcdir)/test-expandargv.c ../libiberty.a
>  	$(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-expandargv \
>  		$(srcdir)/test-expandargv.c ../libiberty.a
>  
> +demangler-fuzzer: $(srcdir)/demangler-fuzzer.c ../libiberty.a
> +	$(TEST_COMPILE) -o demangler-fuzzer \
> +		$(srcdir)/demangler-fuzzer.c ../libiberty.a
> +
>  # Standard (either GNU or Cygnus) rules we don't use.
>  html install-html info install-info clean-info dvi pdf install-pdf \
>  install etags tags installcheck:
> @@ -81,6 +92,7 @@ mostlyclean:
>  	rm -f test-demangle
>  	rm -f test-pexecute
>  	rm -f test-expandargv
> +	rm -f demangler-fuzzer
>  	rm -f core
>  clean: mostlyclean
>  distclean: clean
> diff --git a/libiberty/testsuite/d-demangle-expected b/libiberty/testsuite/d-demangle-expected
> new file mode 100644
> index 0000000..2aeacb8
> --- /dev/null
> +++ b/libiberty/testsuite/d-demangle-expected
> @@ -0,0 +1,936 @@
> +# This file holds test cases for the D demangler.
> +# Each test case looks like this:
> +#  options
> +#  input to be demangled
> +#  expected output
> +#
> +# See demangle-expected for documentation of supported options.
> +#
> +# A line starting with `#' is ignored.
> +# However, blank lines in this file are NOT ignored.
> +#
> +############
> +#
> +# Coverage Tests
> +#
> +--format=dlang
> +_Dmain
> +D main
> +#
> +--format=dlang
> +_D8demangle4testPFLAiYi
> +demangle.test
> +#
> +--format=dlang
> +_D8demangle4testFaZv
> +demangle.test(char)
> +#
> +--format=dlang
> +_D8demangle4testFbZv
> +demangle.test(bool)
> +#
> +--format=dlang
> +_D8demangle4testFcZv
> +demangle.test(creal)
> +#
> +--format=dlang
> +_D8demangle4testFdZv
> +demangle.test(double)
> +#
> +--format=dlang
> +_D8demangle4testFeZv
> +demangle.test(real)
> +#
> +--format=dlang
> +_D8demangle4testFfZv
> +demangle.test(float)
> +#
> +--format=dlang
> +_D8demangle4testFgZv
> +demangle.test(byte)
> +#
> +--format=dlang
> +_D8demangle4testFhZv
> +demangle.test(ubyte)
> +#
> +--format=dlang
> +_D8demangle4testFiZv
> +demangle.test(int)
> +#
> +--format=dlang
> +_D8demangle4testFjZv
> +demangle.test(ireal)
> +#
> +--format=dlang
> +_D8demangle4testFkZv
> +demangle.test(uint)
> +#
> +--format=dlang
> +_D8demangle4testFlZv
> +demangle.test(long)
> +#
> +--format=dlang
> +_D8demangle4testFmZv
> +demangle.test(ulong)
> +#
> +--format=dlang
> +_D8demangle4testFnZv
> +demangle.test(none)
> +#
> +--format=dlang
> +_D8demangle4testFoZv
> +demangle.test(ifloat)
> +#
> +--format=dlang
> +_D8demangle4testFpZv
> +demangle.test(idouble)
> +#
> +--format=dlang
> +_D8demangle4testFqZv
> +demangle.test(cfloat)
> +#
> +--format=dlang
> +_D8demangle4testFrZv
> +demangle.test(cdouble)
> +#
> +--format=dlang
> +_D8demangle4testFsZv
> +demangle.test(short)
> +#
> +--format=dlang
> +_D8demangle4testFtZv
> +demangle.test(ushort)
> +#
> +--format=dlang
> +_D8demangle4testFuZv
> +demangle.test(wchar)
> +#
> +--format=dlang
> +_D8demangle4testFvZv
> +demangle.test(void)
> +#
> +--format=dlang
> +_D8demangle4testFwZv
> +demangle.test(dchar)
> +#
> +--format=dlang
> +_D8demangle4testFOaZv
> +demangle.test(shared(char))
> +#
> +--format=dlang
> +_D8demangle4testFxaZv
> +demangle.test(const(char))
> +#
> +--format=dlang
> +_D8demangle4testFyaZv
> +demangle.test(immutable(char))
> +#
> +--format=dlang
> +_D8demangle4testFNgaZv
> +demangle.test(inout(char))
> +#
> +--format=dlang
> +_D8demangle4testFOxaZv
> +demangle.test(shared(const(char)))
> +#
> +--format=dlang
> +_D8demangle4testFONgaZv
> +demangle.test(shared(inout(char)))
> +#
> +--format=dlang
> +_D8demangle4testFAaZv
> +demangle.test(char[])
> +#
> +--format=dlang
> +_D8demangle4testFAAaZv
> +demangle.test(char[][])
> +#
> +--format=dlang
> +_D8demangle4testFAAAaZv
> +demangle.test(char[][][])
> +#
> +--format=dlang
> +_D8demangle4testFG42aZv
> +demangle.test(char[42])
> +#
> +--format=dlang
> +_D8demangle4testFG42G42aZv
> +demangle.test(char[42][42])
> +#
> +--format=dlang
> +_D8demangle4testFG42G42G42aZv
> +demangle.test(char[42][42][42])
> +#
> +--format=dlang
> +_D8demangle4testFG1234567890aZv
> +demangle.test(char[1234567890])
> +#
> +--format=dlang
> +_D8demangle4testFHaaZv
> +demangle.test(char[char])
> +#
> +--format=dlang
> +_D8demangle4testFHHaaaZv
> +demangle.test(char[char[char]])
> +#
> +--format=dlang
> +_D8demangle4testFPaZv
> +demangle.test(char*)
> +#
> +--format=dlang
> +_D8demangle4testFPPaZv
> +demangle.test(char**)
> +#
> +--format=dlang
> +_D8demangle4testFPPPaZv
> +demangle.test(char***)
> +#
> +--format=dlang
> +_D8demangle4testFNhG8gZv
> +demangle.test(__vector(byte[8]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG16gZv
> +demangle.test(__vector(byte[16]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG32gZv
> +demangle.test(__vector(byte[32]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG4sZv
> +demangle.test(__vector(short[4]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG8sZv
> +demangle.test(__vector(short[8]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG16sZv
> +demangle.test(__vector(short[16]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG2iZv
> +demangle.test(__vector(int[2]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG4iZv
> +demangle.test(__vector(int[4]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG8iZv
> +demangle.test(__vector(int[8]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG1lZv
> +demangle.test(__vector(long[1]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG2lZv
> +demangle.test(__vector(long[2]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG4lZv
> +demangle.test(__vector(long[4]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG2fZv
> +demangle.test(__vector(float[2]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG4fZv
> +demangle.test(__vector(float[4]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG8fZv
> +demangle.test(__vector(float[8]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG1dZv
> +demangle.test(__vector(double[1]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG2dZv
> +demangle.test(__vector(double[2]))
> +#
> +--format=dlang
> +_D8demangle4testFNhG4dZv
> +demangle.test(__vector(double[4]))
> +#
> +--format=dlang
> +_D8demangle4testFI5identZv
> +demangle.test(ident)
> +#
> +--format=dlang
> +_D8demangle4testFI5ident4testZv
> +demangle.test(ident.test)
> +#
> +--format=dlang
> +_D8demangle4testFC5classZv
> +demangle.test(class)
> +#
> +--format=dlang
> +_D8demangle4testFC5class4testZv
> +demangle.test(class.test)
> +#
> +--format=dlang
> +_D8demangle4testFS6structZv
> +demangle.test(struct)
> +#
> +--format=dlang
> +_D8demangle4testFS6struct4testZv
> +demangle.test(struct.test)
> +#
> +--format=dlang
> +_D8demangle4testFE4enumZv
> +demangle.test(enum)
> +#
> +--format=dlang
> +_D8demangle4testFE4enum4testZv
> +demangle.test(enum.test)
> +#
> +--format=dlang
> +_D8demangle4testFT7typedefZv
> +demangle.test(typedef)
> +#
> +--format=dlang
> +_D8demangle4testFT7typedef4testZv
> +demangle.test(typedef.test)
> +#
> +--format=dlang
> +_D8demangle4testFJaZv
> +demangle.test(out char)
> +#
> +--format=dlang
> +_D8demangle4testFKaZv
> +demangle.test(ref char)
> +#
> +--format=dlang
> +_D8demangle4testFLaZv
> +demangle.test(lazy char)
> +#
> +--format=dlang
> +_D8demangle4testFMaZv
> +demangle.test(scope char)
> +#
> +--format=dlang
> +_D8demangle4testFaXv
> +demangle.test(char...)
> +#
> +--format=dlang
> +_D8demangle4testFaYv
> +demangle.test(char, ...)
> +#
> +--format=dlang
> +_D8demangle4testFaaYv
> +demangle.test(char, char, ...)
> +#
> +--format=dlang
> +_D8demangle4testFaaZv
> +demangle.test(char, char)
> +#
> +--format=dlang
> +_D8demangle4testFB0Zv
> +demangle.test(Tuple!())
> +#
> +--format=dlang
> +_D8demangle4testFB1aZv
> +demangle.test(Tuple!(char))
> +#
> +--format=dlang
> +_D8demangle4testFB2aaZv
> +demangle.test(Tuple!(char, char))
> +#
> +--format=dlang
> +_D8demangle4testFB3aaaZv
> +demangle.test(Tuple!(char, char, char))
> +#
> +--format=dlang
> +_D8demangle4testFB2OaaZv
> +demangle.test(Tuple!(shared(char), char))
> +#
> +--format=dlang
> +_D8demangle4testFB3aDFZaaZv
> +demangle.test(Tuple!(char, char() delegate, char))
> +#
> +--format=dlang
> +_D8demangle4testFDFZaZv
> +demangle.test(char() delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDUZaZv
> +demangle.test(extern(C) char() delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDWZaZv
> +demangle.test(extern(Windows) char() delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDVZaZv
> +demangle.test(extern(Pascal) char() delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDRZaZv
> +demangle.test(extern(C++) char() delegate)
> +#
> +--format=dlang
> +_D8demangle4testFFZaZv
> +demangle.test(char() function)
> +#
> +--format=dlang
> +_D8demangle4testFUZaZv
> +demangle.test(extern(C) char() function)
> +#
> +--format=dlang
> +_D8demangle4testFWZaZv
> +demangle.test(extern(Windows) char() function)
> +#
> +--format=dlang
> +_D8demangle4testFVZaZv
> +demangle.test(extern(Pascal) char() function)
> +#
> +--format=dlang
> +_D8demangle4testFRZaZv
> +demangle.test(extern(C++) char() function)
> +#
> +--format=dlang
> +_D8demangle4testFDFNaZaZv
> +demangle.test(char() pure delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNbZaZv
> +demangle.test(char() nothrow delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNcZaZv
> +demangle.test(char() ref delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNdZaZv
> +demangle.test(char() @property delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNeZaZv
> +demangle.test(char() @trusted delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNfZaZv
> +demangle.test(char() @safe delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNiZaZv
> +demangle.test(char() @nogc delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNaNbZaZv
> +demangle.test(char() pure nothrow delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNbNaZaZv
> +demangle.test(char() nothrow pure delegate)
> +#
> +--format=dlang
> +_D8demangle4testFDFNdNfNaZaZv
> +demangle.test(char() @property @safe pure delegate)
> +#
> +--format=dlang
> +_D8demangle4testFFNaZaZv
> +demangle.test(char() pure function)
> +#
> +--format=dlang
> +_D8demangle4testFFNbZaZv
> +demangle.test(char() nothrow function)
> +#
> +--format=dlang
> +_D8demangle4testFFNcZaZv
> +demangle.test(char() ref function)
> +#
> +--format=dlang
> +_D8demangle4testFFNdZaZv
> +demangle.test(char() @property function)
> +#
> +--format=dlang
> +_D8demangle4testFFNeZaZv
> +demangle.test(char() @trusted function)
> +#
> +--format=dlang
> +_D8demangle4testFFNfZaZv
> +demangle.test(char() @safe function)
> +#
> +--format=dlang
> +_D8demangle4testFFNiZaZv
> +demangle.test(char() @nogc function)
> +#
> +--format=dlang
> +_D8demangle4testFFNaNbZaZv
> +demangle.test(char() pure nothrow function)
> +#
> +--format=dlang
> +_D8demangle4testFFNbNaZaZv
> +demangle.test(char() nothrow pure function)
> +#
> +--format=dlang
> +_D8demangle4testFFNdNfNaZaZv
> +demangle.test(char() @property @safe pure function)
> +#
> +--format=dlang
> +_D8demangle4test6__initZ
> +demangle.test.init$
> +#
> +--format=dlang
> +_D8demangle4test6__vtblZ
> +vtable for demangle.test
> +#
> +--format=dlang
> +_D8demangle4test7__ClassZ
> +ClassInfo for demangle.test
> +#
> +--format=dlang
> +_D8demangle4test11__InterfaceZ
> +Interface for demangle.test
> +#
> +--format=dlang
> +_D8demangle4test12__ModuleInfoZ
> +ModuleInfo for demangle.test
> +#
> +--format=dlang
> +_D8demangle4test6__ctorMFZv
> +demangle.test.this()
> +#
> +--format=dlang
> +_D8demangle4test6__dtorMFZv
> +demangle.test.~this()
> +#
> +--format=dlang
> +_D8demangle4test6__postblitMFZv
> +demangle.test.this(this)
> +#
> +--format=dlang
> +_D8demangle4testFHAbaZv
> +demangle.test(char[bool[]])
> +#
> +--format=dlang
> +_D8demangle4testFHG42caZv
> +demangle.test(char[creal[42]])
> +#
> +--format=dlang
> +_D8demangle4testFAiXv
> +demangle.test(int[]...)
> +#
> +--format=dlang
> +_D8demangle4testFLAiXv
> +demangle.test(lazy int[]...)
> +#
> +--format=dlang
> +_D8demangle4testFAiYv
> +demangle.test(int[], ...)
> +#
> +--format=dlang
> +_D8demangle4testFLAiYv
> +demangle.test(lazy int[], ...)
> +#
> +--format=dlang
> +_D8demangle4testFLilZv
> +demangle.test(lazy int, long)
> +#
> +--format=dlang
> +_D8demangle4testFLliZv
> +demangle.test(lazy long, int)
> +#
> +--format=dlang
> +_D8demangle4testFLC6ObjectLDFLiZiZi
> +demangle.test(lazy Object, lazy int(lazy int) delegate)
> +#
> +--format=dlang
> +_D8demangle9__T4testZv
> +demangle.test!()
> +#
> +--format=dlang
> +_D8demangle11__T4testTaZv
> +demangle.test!(char)
> +#
> +--format=dlang
> +_D8demangle13__T4testTaTaZv
> +demangle.test!(char, char)
> +#
> +--format=dlang
> +_D8demangle15__T4testTaTaTaZv
> +demangle.test!(char, char, char)
> +#
> +--format=dlang
> +_D8demangle16__T4testTaTOiTaZv
> +demangle.test!(char, shared(int), char)
> +#
> +--format=dlang
> +_D8demangle17__T4testS6symbolZv
> +demangle.test!(symbol)
> +#
> +--format=dlang
> +_D8demangle21__T4testS6symbol3fooZv
> +demangle.test!(symbol.foo)
> +#
> +--format=dlang
> +_D8demangle25__T4testS6symbol3foo3barZv
> +demangle.test!(symbol.foo.bar)
> +#
> +--format=dlang
> +_D8demangle19__T4testTaS6symbolZv
> +demangle.test!(char, symbol)
> +#
> +--format=dlang
> +_D8demangle19__T4testS6symbolTaZv
> +demangle.test!(symbol, char)
> +#
> +--format=dlang
> +_D8demangle13__T4testVPinZv
> +demangle.test!(null)
> +#
> +--format=dlang
> +_D8demangle14__T4testVg123Zv
> +demangle.test!(123)
> +#
> +--format=dlang
> +_D8demangle14__T4testVi123Zv
> +demangle.test!(123)
> +#
> +--format=dlang
> +_D8demangle14__T4testVs123Zv
> +demangle.test!(123)
> +#
> +--format=dlang
> +_D8demangle14__T4testVh123Zv
> +demangle.test!(123u)
> +#
> +--format=dlang
> +_D8demangle14__T4testVk123Zv
> +demangle.test!(123u)
> +#
> +--format=dlang
> +_D8demangle14__T4testVt123Zv
> +demangle.test!(123u)
> +#
> +--format=dlang
> +_D8demangle14__T4testVl123Zv
> +demangle.test!(123L)
> +#
> +--format=dlang
> +_D8demangle14__T4testVm123Zv
> +demangle.test!(123uL)
> +#
> +--format=dlang
> +_D8demangle15__T4testViN123Zv
> +demangle.test!(-123)
> +#
> +--format=dlang
> +_D8demangle15__T4testVkN123Zv
> +demangle.test!(-123u)
> +#
> +--format=dlang
> +_D8demangle15__T4testVlN123Zv
> +demangle.test!(-123L)
> +#
> +--format=dlang
> +_D8demangle15__T4testVmN123Zv
> +demangle.test!(-123uL)
> +#
> +--format=dlang
> +_D8demangle12__T4testVb1Zv
> +demangle.test!(true)
> +#
> +--format=dlang
> +_D8demangle12__T4testVb0Zv
> +demangle.test!(false)
> +#
> +--format=dlang
> +_D8demangle13__T4testVa10Zv
> +demangle.test!('\x0a')
> +#
> +--format=dlang
> +_D8demangle13__T4testVa32Zv
> +demangle.test!(' ')
> +#
> +--format=dlang
> +_D8demangle13__T4testVa65Zv
> +demangle.test!('A')
> +#
> +--format=dlang
> +_D8demangle14__T4testVa126Zv
> +demangle.test!('~')
> +#
> +--format=dlang
> +_D8demangle15__T4testVu1000Zv
> +demangle.test!('\u03e8')
> +#
> +--format=dlang
> +_D8demangle17__T4testVw100000Zv
> +demangle.test!('\U000186a0')
> +#
> +--format=dlang
> +_D8demangle17__T4testVde0A8P6Zv
> +demangle.test!(42.0000)
> +#
> +--format=dlang
> +_D8demangle16__T4testVdeA8P2Zv
> +demangle.test!(42.0000)
> +#
> +--format=dlang
> +_D8demangle18__T4testVdeN0A8P6Zv
> +demangle.test!(-42.0000)
> +#
> +--format=dlang
> +_D8demangle31__T4testVde0F6E978D4FDF3B646P7Zv
> +demangle.test!(123.456)
> +#
> +--format=dlang
> +_D8demangle15__T4testVdeNANZv
> +demangle.test!(NaN)
> +#
> +--format=dlang
> +_D8demangle15__T4testVdeINFZv
> +demangle.test!(Inf)
> +#
> +--format=dlang
> +_D8demangle16__T4testVdeNINFZv
> +demangle.test!(-Inf)
> +#
> +--format=dlang
> +_D8demangle23__T4testVfe0FFFFFFP128Zv
> +demangle.test!(3.40282e+38)
> +#
> +--format=dlang
> +_D8demangle32__T4testVde0FFFFFFFFFFFFF8P1024Zv
> +demangle.test!(1.79769e+308)
> +#
> +--format=dlang
> +_D8demangle19__T4testVfe08PN125Zv
> +demangle.test!(1.17549e-38)
> +#
> +--format=dlang
> +_D8demangle20__T4testVde08PN1021Zv
> +demangle.test!(2.22507e-308)
> +#
> +--format=dlang
> +_D8demangle51__T4testVrc0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv
> +demangle.test!(12.3000+45.6000i)
> +#
> +--format=dlang
> +_D8demangle52__T4testVrcN0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv
> +demangle.test!(-12.3000+45.6000i)
> +#
> +--format=dlang
> +_D8demangle22__T4testVG3ua3_616263Zv
> +demangle.test!("abc")
> +#
> +--format=dlang
> +_D8demangle22__T4testVG3ud3_616263Zv
> +demangle.test!("abc"d)
> +#
> +--format=dlang
> +_D8demangle22__T4testVG3uw3_616263Zv
> +demangle.test!("abc"w)
> +#
> +--format=dlang
> +_D8demangle22__T4testVAiA4i1i2i3i4Zv
> +demangle.test!([1, 2, 3, 4])
> +#
> +--format=dlang
> +_D8demangle25__T4testVAdA2e08P1eN08P1Zv
> +demangle.test!([1.00000, -1.00000])
> +#
> +--format=dlang
> +_D8demangle23__T4testVHiiA2i1i2i3i4Zv
> +demangle.test!([1:2, 3:4])
> +#
> +--format=dlang
> +_D8demangle39__T4testVHAxaiA2a3_616263i1a3_646566i2Zv
> +demangle.test!(["abc":1, "def":2])
> +#
> +--format=dlang
> +_D8demangle28__T4testVS8demangle1SS2i1i2Zv
> +demangle.test!(demangle.S(1, 2))
> +#
> +--format=dlang
> +_D8demangle35__T4testVS8demangle1SS2i1a3_616263Zv
> +demangle.test!(demangle.S(1, "abc"))
> +#
> +# Unittests
> +#
> +--format=dlang
> +printf
> +printf
> +#
> +--format=dlang
> +_foo
> +_foo
> +#
> +--format=dlang
> +_D88
> +_D88
> +#
> +--format=dlang
> +_D5__T1aZv
> +_D5__T1aZv
> +#
> +--format=dlang
> +_D4test3fooAa
> +test.foo
> +#
> +--format=dlang
> +_D8demangle8demangleFAaZAa
> +demangle.demangle(char[])
> +#
> +--format=dlang
> +_D6object6Object8opEqualsFC6ObjectZi
> +object.Object.opEquals(Object)
> +#
> +--format=dlang
> +_D6object6Object8opAssignFC6ObjectZi
> +object.Object.opAssign(Object)
> +#
> +--format=dlang
> +_D4test2dgDFiYd
> +test.dg
> +#
> +--format=dlang
> +_D1a1bi
> +a.b
> +#
> +--format=dlang
> +_D1a1bPFiZi
> +a.b
> +#
> +--format=dlang
> +_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi
> +test.bar!("abc"w, "def"d).x
> +#
> +--format=dlang
> +_D6plugin8generateFiiZAya
> +plugin.generate(int, int)
> +#
> +--format=dlang
> +_D6plugin8generateFiiZAxa
> +plugin.generate(int, int)
> +#
> +--format=dlang
> +_D6plugin8generateFiiZAOa
> +plugin.generate(int, int)
> +#
> +--format=dlang
> +_D8demangle3fnAFZv3fnBMFZv
> +demangle.fnA().fnB()
> +#
> +--format=dlang
> +_D8demangle4mainFZv1S3fnCFZv
> +demangle.main().S.fnC()
> +#
> +--format=dlang
> +_D8demangle4mainFZv1S3fnDMFZv
> +demangle.main().S.fnD()
> +#
> +--format=dlang
> +_D8demangle4mainFZv5localMFZi
> +demangle.main().local()
> +#
> +--format=dlang
> +_D3std5ascii9uppercaseyAa
> +std.ascii.uppercase
> +#
> +--format=dlang
> +_D3std6stream9BOMEndianyG5E3std6system6Endian
> +std.stream.BOMEndian
> +#
> +--format=dlang
> +_D3std8internal7uni_tab10unicodeNkoyS3std8internal3uni12CodepointSet
> +std.internal.uni_tab.unicodeNko
> +#
> +--format=dlang
> +_D2gc2gc2GC6addrOfMFPvZPv
> +gc.gc.GC.addrOf(void*)
> +#
> +--format=dlang
> +_D3std7process10setCLOEXECFibZv
> +std.process.setCLOEXEC(int, bool)
> +#
> +--format=dlang
> +_D3std6digest2md3MD53putMFNaNbNeMAxhXv
> +std.digest.md.MD5.put(scope const(ubyte)[]...)
> +#
> +--format=dlang
> +_D3std6mmfile6MmFile13opIndexAssignMFhmZh
> +std.mmfile.MmFile.opIndexAssign(ubyte, ulong)
> +#
> +--format=dlang
> +_D3std7process18escapeShellCommandFxAAaXAya
> +std.process.escapeShellCommand(const(char[][])...)
> +#
> +--format=dlang
> +_D4core4sync5mutex5Mutex6__ctorMFC6ObjectZC4core4sync5mutex5Mutex
> +core.sync.mutex.Mutex.this(Object)
> +#
> +--format=dlang
> +_D6object14TypeInfo_Array8argTypesMFNbNfJC8TypeInfoJC8TypeInfoZi
> +object.TypeInfo_Array.argTypes(out TypeInfo, out TypeInfo)
> +#
> +--format=dlang
> +_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7tryExecMFMDFZvZv
> +rt.dmain2._d_run_main(int, char**, extern(C) int(char[][]) function*).tryExec(scope void() delegate)
> +#
> +--format=dlang
> +_D6object9Exception6__ctorMFNaNbNfAyaAyamC6object9ThrowableZC9Exception
> +object.Exception.this(immutable(char)[], immutable(char)[], ulong, object.Throwable)
> +#
> +--format=dlang
> +_D3gcc3deh17parse_lsda_headerFPS3gcc6unwind7generic15_Unwind_ContextPhPS3gcc3deh16lsda_header_infoZPh
> +gcc.deh.parse_lsda_header(gcc.unwind.generic._Unwind_Context*, ubyte*, gcc.deh.lsda_header_info*)
> +#
> +--format=dlang
> +_D3std6socket23UnknownAddressReference6__ctorMFPS4core3sys5posix3sys6socket8sockaddrkZC3std6socket23UnknownAddressReference
> +std.socket.UnknownAddressReference.this(core.sys.posix.sys.socket.sockaddr*, uint)
> +#
> +--format=dlang
> +_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv
> +demangle.fn!([1, 2, 3, 4]).fn()
> +#
> +--format=dlang
> +_D8demangle10__T2fnVi1Z2fnFZv
> +demangle.fn!(1).fn()
> +#
> +--format=dlang
> +_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv
> +demangle.fn!(demangle.S(1, 2)).fn()
> +#
> +--format=dlang
> +_D8demangle13__T2fnVeeNANZ2fnFZv
> +demangle.fn!(NaN).fn()
> +#
> +--format=dlang
> +_D8demangle14__T2fnVeeNINFZ2fnFZv
> +demangle.fn!(-Inf).fn()
> +#
> +--format=dlang
> +_D8demangle13__T2fnVeeINFZ2fnFZv
> +demangle.fn!(Inf).fn()
> +#
> +--format=dlang
> +_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv
> +demangle.fn!([1:2, 3:4]).fn()
> +#
> +--format=dlang
> +_D8demangle2fnFNgiZNgi
> +demangle.fn(inout(int))
> +#
> +--format=dlang
> +_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv
> +demangle.fn!('a', '\x09', '\x00', '\u0101', '\U00010001').fn()
> +#
> +--format=dlang
> +_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv
> +gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)
> +#
> +--format=dlang
> +_D8serenity9persister6Sqlite70__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZv4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZv4Test
> +serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)
> +#
> +--format=dlang
> +_D4test4mainFZv5localMFZi
> +test.main().local()
> diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
> index 864ee7e..a030685 100644
> --- a/libiberty/testsuite/demangle-expected
> +++ b/libiberty/testsuite/demangle-expected
> @@ -4343,8 +4343,16 @@ cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::p
>  --format=gnu-v3
>  _ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v
>  void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<void post<std::function<void ()> >(void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
> +#
> +--format=auto --no-params
> +_Z3xxxDFyuVb
> +xxx(unsigned long long _Fract, bool volatile)
> +xxx
>  # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
>  --format=auto --no-params
>  _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
>  _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
>  _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
> +--format=gnu-v3
> +_Z1fSsB3fooS_
> +f(std::string[abi:foo], std::string[abi:foo])
> diff --git a/libiberty/testsuite/demangler-fuzzer.c b/libiberty/testsuite/demangler-fuzzer.c
> new file mode 100644
> index 0000000..aff7024
> --- /dev/null
> +++ b/libiberty/testsuite/demangler-fuzzer.c
> @@ -0,0 +1,108 @@
> +/* Demangler fuzzer.
> +
> +   Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +   This file is part of GNU libiberty.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program 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 General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <time.h>
> +#include "demangle.h"
> +
> +#define MAXLEN 253
> +#define ALPMIN 33
> +#define ALPMAX 127
> +
> +static char *program_name;
> +
> +#define DEFAULT_MAXCOUNT 7500000
> +
> +static void
> +print_usage (FILE *fp, int exit_value)
> +{
> +  fprintf (fp, "Usage: %s [OPTION]...\n", program_name);
> +  fprintf (fp, "Options:\n");
> +  fprintf (fp, "  -h           Display this message.\n");
> +  fprintf (fp, "  -s SEED      Select the random seed to be used.\n");
> +  fprintf (fp, "               The default is to base one on the");
> +  fprintf (fp, " current time.\n");
> +  fprintf (fp, "  -m MAXCOUNT  Exit after MAXCOUNT symbols.\n");
> +  fprintf (fp, "               The default is %d.", DEFAULT_MAXCOUNT);
> +  fprintf (fp, " Set to `-1' for no limit.\n");
> +
> +  exit (exit_value);
> +}
> +
> +int
> +main (int argc, char *argv[])
> +{
> +  char symbol[2 + MAXLEN + 1] = "_Z";
> +  int seed = -1, seed_set = 0;
> +  int count = 0, maxcount = DEFAULT_MAXCOUNT;
> +  int optchr;
> +
> +  program_name = argv[0];
> +
> +  do
> +    {
> +      optchr = getopt (argc, argv, "hs:m:t:");
> +      switch (optchr)
> +	{
> +	case '?':  /* Unrecognized option.  */
> +	  print_usage (stderr, 1);
> +	  break;
> +
> +	case 'h':
> +	  print_usage (stdout, 0);
> +	  break;
> +
> +	case 's':
> +	  seed = atoi (optarg);
> +	  seed_set = 1;
> +	  break;
> +
> +	case 'm':
> +	  maxcount = atoi (optarg);
> +	  break;
> +	}
> +    }
> +  while (optchr != -1);
> +
> +  if (!seed_set)
> +    seed = time (NULL);
> +  srand (seed);
> +  printf ("%s: seed = %d\n", program_name, seed);
> +
> +  while (maxcount < 0 || count < maxcount)
> +    {
> +      char *buffer = symbol + 2;
> +      int length, i;
> +
> +      length = rand () % MAXLEN;
> +      for (i = 0; i < length; i++)
> +	*buffer++ = (rand () % (ALPMAX - ALPMIN)) + ALPMIN;
> +
> +      *buffer++ = '\0';
> +
> +      cplus_demangle (symbol, DMGL_AUTO | DMGL_ANSI | DMGL_PARAMS);
> +
> +      count++;
> +    }
> +
> +  printf ("%s: successfully demangled %d symbols\n", program_name, count);
> +  exit (0);
> +}
Joel Brobecker Oct. 14, 2014, 1:58 p.m. UTC | #3
> Unfortunately, this part of the change breaks the build on Solaris 2.9.
> And according to the gnulib documentation that function, it looks like
> it'll break the build on the following hosts:
> 
>         NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, IRIX 6.5, OSF/1 4.0,
>         Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS.
> 
> Not knowing D and whether you actually need long-double precision
> or not, I didn't try to fix it. But it looks like the best option
> would probably to add an strtold configure check, and then fallback
> on strtod if strtold isn't available (and error out if strtod isn't)?

Just a quick note to say that I am working on a patch that I'll apply
internally, so I might as well send it to gcc-patches as well.
If it is actually the best way to fix this, then it'll save you
the trouble.
Iain Buclaw Oct. 14, 2014, 4:15 p.m. UTC | #4
On 14 October 2014 14:38, Joel Brobecker <brobecker@adacore.com> wrote:
> Hi Ian,
>
>> 2014-09-23  Iain Buclaw  <ibuclaw@gdcproject.org>
>>
>>        * Makefile.in (CFILES): Add d-demangle.c.
>>        (REQUIRED_OFILES): Add d-demangle.o.
>>        * cplus-dem.c (libiberty_demanglers): Add dlang_demangling case.
>>        (cplus_demangle): Likewise.
>>        * d-demangle.c: New file.
>>        * testsuite/Makefile.in (really-check): Add check-d-demangle.
>>        * testsuite/d-demangle-expected: New file.
>
> Unfortunately, this part of the change breaks the build on Solaris 2.9.
> And according to the gnulib documentation that function, it looks like
> it'll break the build on the following hosts:
>
>         NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, IRIX 6.5, OSF/1 4.0,
>         Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS.
>

Hi Joel,

The call to strtold is only needed to decode templates which have a
floating point value encoded inside. This value may or may not have a
greater than double precision.


> Not knowing D and whether you actually need long-double precision
> or not, I didn't try to fix it. But it looks like the best option
> would probably to add an strtold configure check, and then fallback
> on strtod if strtold isn't available (and error out if strtod isn't)?
>

This seems reasonable.  Though replacing long double with double will
be fine with me too.  I'll accept that I didn't consider legacy in
hindsight, and in reality it would be rather rare to stumble upon the
need for strtold.

-- Iain.
Joseph Myers Oct. 14, 2014, 10:49 p.m. UTC | #5
On Tue, 14 Oct 2014, Iain Buclaw wrote:

> The call to strtold is only needed to decode templates which have a
> floating point value encoded inside. This value may or may not have a
> greater than double precision.

But its precision may also be greater than that of long double on the 
host, if long double on the target has greater precision than long double 
on the host.  Likewise, its range may be greater than that of long double 
on the host.  So it would seem a lot more sensible just to produce a hex 
float value in your output without going through any decoding process at 
all (but if you do decode, host floating-point types should not be 
involved).
diff mbox

Patch

 libiberty/Makefile.in                   |   12 +-
 libiberty/cp-demangle.c                 |   21 +-
 libiberty/cplus-dem.c                   |   13 +
 libiberty/d-demangle.c                  | 1338 +++++++++++++++++++++++++++++++
 libiberty/pex-common.c                  |    8 +-
 libiberty/pex-common.h                  |    2 +-
 libiberty/pex-djgpp.c                   |    6 +-
 libiberty/pex-unix.c                    |    7 +-
 libiberty/pex-win32.c                   |    6 +-
 libiberty/simple-object-elf.c           |   38 +-
 libiberty/testsuite/Makefile.in         |   14 +-
 libiberty/testsuite/d-demangle-expected |  936 +++++++++++++++++++++
 libiberty/testsuite/demangle-expected   |    8 +
 libiberty/testsuite/demangler-fuzzer.c  |  108 +++
 14 files changed, 2491 insertions(+), 26 deletions(-)

diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
index 44e340f..9b87720 100644
--- a/libiberty/Makefile.in
+++ b/libiberty/Makefile.in
@@ -127,7 +127,7 @@  CFILES = alloca.c argv.c asprintf.c atexit.c				\
 	basename.c bcmp.c bcopy.c bsearch.c bzero.c			\
 	calloc.c choose-temp.c clock.c concat.c cp-demangle.c		\
 	 cp-demint.c cplus-dem.c crc32.c				\
-	dwarfnames.c dyn-string.c					\
+	d-demangle.c dwarfnames.c dyn-string.c				\
 	fdmatch.c ffs.c fibheap.c filename_cmp.c floatformat.c		\
 	fnmatch.c fopen_unlocked.c					\
 	getcwd.c getopt.c getopt1.c getpagesize.c getpwd.c getruntime.c	\
@@ -167,7 +167,7 @@  REQUIRED_OFILES =							\
 	./md5.$(objext) ./sha1.$(objext) ./alloca.$(objext)		\
 	./argv.$(objext)						\
 	./choose-temp.$(objext) ./concat.$(objext)			\
-	./cp-demint.$(objext) ./crc32.$(objext)				\
+	./cp-demint.$(objext) ./crc32.$(objext) ./d-demangle.$(objext)	\
 	./dwarfnames.$(objext) ./dyn-string.$(objext)			\
 	./fdmatch.$(objext) ./fibheap.$(objext)				\
 	./filename_cmp.$(objext) ./floatformat.$(objext)		\
@@ -714,6 +714,14 @@  $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/dyn-string.c $(OUTPUT_OPTION)
 
+./d-demangle.$(objext): $(srcdir)/d-demangle.c config.h $(INCDIR)/ansidecl.h \
+	$(srcdir)/cp-demangle.h $(INCDIR)/demangle.h \
+	$(INCDIR)/dyn-string.h $(INCDIR)/getopt.h $(INCDIR)/libiberty.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/d-demangle.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/d-demangle.c $(OUTPUT_OPTION)
+
 ./fdmatch.$(objext): $(srcdir)/fdmatch.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/libiberty.h
 	if [ x"$(PICFLAG)" != x ]; then \
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index c0d2ffe..77c2cee9 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -713,7 +713,9 @@  d_dump (struct demangle_component *dc, int indent)
       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");
@@ -3685,6 +3687,7 @@  d_substitution (struct d_info *di, int prefix)
 	    {
 	      const char *s;
 	      int len;
+	      struct demangle_component *c;
 
 	      if (p->set_last_name != NULL)
 		di->last_name = d_make_sub (di, p->set_last_name,
@@ -3700,7 +3703,15 @@  d_substitution (struct d_info *di, int prefix)
 		  len = p->simple_len;
 		}
 	      di->expansion += len;
-	      return d_make_sub (di, s, len);
+	      c = 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.  */
+		  c = d_abi_tags (di, c);
+		  d_add_substitution (di, c);
+		}
+	      return c;
 	    }
 	}
 
@@ -3875,7 +3886,6 @@  d_count_templates_scopes (int *num_templates, int *num_scopes,
     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:
@@ -3920,6 +3930,11 @@  d_count_templates_scopes (int *num_templates, int *num_scopes,
 				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,
diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
index 52767cc..c68b981 100644
--- a/libiberty/cplus-dem.c
+++ b/libiberty/cplus-dem.c
@@ -306,6 +306,12 @@  const struct demangler_engine libiberty_demanglers[] =
   }
   ,
   {
+    DLANG_DEMANGLING_STYLE_STRING,
+    dlang_demangling,
+    "DLANG style demangling"
+  }
+  ,
+  {
     NULL, unknown_demangling, NULL
   }
 };
@@ -870,6 +876,13 @@  cplus_demangle (const char *mangled, int options)
   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);
diff --git a/libiberty/d-demangle.c b/libiberty/d-demangle.c
new file mode 100644
index 0000000..d31bf94
--- /dev/null
+++ b/libiberty/d-demangle.c
@@ -0,0 +1,1338 @@ 
+/* Demangler for the D programming language
+   Copyright 2014 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 and strtold for decoding mangled literals.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "safe-ctype.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern long strtol (const char *nptr, char **endptr, int base);
+extern long double strtold (const char *nptr, char **endptr);
+#endif
+
+#include <demangle.h>
+#include "libiberty.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));
+    }
+}
+
+/* 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 *);
+
+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 mangled;
+
+  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;
+    default:
+      return NULL;
+    }
+
+  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 mangled;
+
+  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':
+	  /* inout parameter is represented as 'Ng'.
+	     vector parameter is represented as 'Nh'.
+	     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;
+	}
+      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 mangled;
+
+  /* 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++;
+	  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 ");
+	}
+
+      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 mangled;
+
+  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++;
+      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);
+    case 'D': /* delegate T */
+      mangled++;
+      mangled = dlang_function_type (decl, mangled);
+      string_append (decl, "delegate");
+      return mangled;
+    case 'B': /* tuple T */
+      mangled++;
+      return dlang_parse_tuple (decl, mangled);
+
+    /* Function types */
+    case 'F': case 'U': case 'W':
+    case 'V': case 'R':
+      mangled = dlang_function_type (decl, mangled);
+      string_append (decl, "function");
+      return 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;
+
+    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)
+{
+  if (mangled == NULL || *mangled == '\0')
+    return mangled;
+
+  if (ISDIGIT (*mangled))
+    {
+      char *endptr;
+      long i = strtol (mangled, &endptr, 10);
+
+      if (endptr == NULL || i <= 0 || strlen (endptr) < (size_t) i)
+	return NULL;
+
+      mangled = endptr;
+
+      /* May be a template instance.  */
+      if (i >= 5 && strncmp (mangled, "__T", 3) == 0)
+	{
+	  /* Template symbol.  */
+	  if (ISDIGIT (mangled[3]) && mangled[3] != '0')
+	    return dlang_parse_template (decl, mangled, i);
+
+	  return NULL;
+	}
+
+      if (strncmp (mangled, "__ctor", i) == 0)
+	{
+	  /* Constructor symbol for a class/struct.  */
+	  string_append (decl, "this");
+	  mangled += i;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__dtor", i) == 0)
+	{
+	  /* Destructor symbol for a class/struct.  */
+	  string_append (decl, "~this");
+	  mangled += i;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__postblit", i) == 0)
+	{
+	  /* Postblit symbol for a struct.  */
+	  string_append (decl, "this(this)");
+	  mangled += i;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__initZ", i+1) == 0)
+	{
+	  /* The static initialiser for a given symbol.  */
+	  string_append (decl, "init$");
+	  mangled += i + 1;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__ClassZ", i+1) == 0)
+	{
+	  /* The classinfo symbol for a given class.  */
+	  string_prepend (decl, "ClassInfo for ");
+	  string_setlength (decl, string_length (decl) - 1);
+	  mangled += i + 1;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__vtblZ", i+1) == 0)
+	{
+	  /* The vtable symbol for a given class.  */
+	  string_prepend (decl, "vtable for ");
+	  string_setlength (decl, string_length (decl) - 1);
+	  mangled += i + 1;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__InterfaceZ", i+1) == 0)
+	{
+	  /* The interface symbol for a given class.  */
+	  string_prepend (decl, "Interface for ");
+	  string_setlength (decl, string_length (decl) - 1);
+	  mangled += i + 1;
+	  return mangled;
+	}
+      else if (strncmp (mangled, "__ModuleInfoZ", i+1) == 0)
+	{
+	  /* The ModuleInfo symbol for a given module.  */
+	  string_prepend (decl, "ModuleInfo for ");
+	  string_setlength (decl, string_length (decl) - 1);
+	  mangled += i + 1;
+	  return mangled;
+	}
+
+      string_appendn (decl, mangled, i);
+      mangled += i;
+    }
+  else
+    return NULL;
+
+  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;
+  long double value;
+  char *endptr;
+
+  /* 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++;
+    }
+
+  /* Convert buffer from hexadecimal to floating-point.  */
+  buffer[len] = '\0';
+  value = strtold (buffer, &endptr);
+
+  if (endptr == NULL || endptr != (buffer + len))
+    return NULL;
+
+  len = snprintf (buffer, sizeof(buffer), "%#Lg", value);
+  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;
+	  string_appendn (decl, &val, 1);
+	}
+      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 mangled;
+
+  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;
+}
+
+static int
+dlang_call_convention_p (const char *mangled)
+{
+  size_t i;
+
+  switch (*mangled)
+    {
+    case 'F': case 'U': case 'V':
+    case 'W': case 'R':
+      return 1;
+
+    case 'M': /* Prefix for functions needing 'this' */
+      i = 1;
+      if (mangled[i] == 'x')
+	i++;
+
+      switch (mangled[i])
+	{
+	case 'F': case 'U': case 'V':
+	case 'W': case 'R':
+	  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)
+{
+  size_t n = 0;
+  do
+    {
+      if (n++)
+	string_append (decl, ".");
+
+      mangled = dlang_identifier (decl, mangled);
+
+      if (mangled && dlang_call_convention_p (mangled))
+	{
+	  int saved;
+
+	  /* Skip over 'this' parameter.  */
+	  if (*mangled == 'M')
+	    mangled += (mangled[1] == 'x') ? 2 : 1;
+
+	  /* 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, ")");
+
+	  /* Demangle the function return type as a kind of sanity test.  */
+	  if (mangled && !ISDIGIT (*mangled))
+	    {
+	      saved = string_length (decl);
+	      mangled = dlang_type (decl, mangled);
+	      string_setlength (decl, saved);
+	    }
+	}
+    }
+  while (mangled && ISDIGIT (*mangled));
+
+  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, ", ");
+
+      switch (*mangled)
+	{
+	case 'S': /* Symbol parameter.  */
+	  mangled++;
+	  mangled = dlang_parse_symbol (decl, mangled);
+	  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);
+
+  /* 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) == NULL)
+	string_delete (&decl);
+    }
+
+  if (string_length (&decl) > 0)
+    {
+      string_need (&decl, 1);
+      *(decl.p) = '\0';
+      demangled = decl.b;
+    }
+
+  return demangled;
+}
+
diff --git a/libiberty/pex-common.c b/libiberty/pex-common.c
index 6fd3fde..146010a 100644
--- a/libiberty/pex-common.c
+++ b/libiberty/pex-common.c
@@ -267,7 +267,8 @@  pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
   if (out < 0)
     {
       out = obj->funcs->open_write (obj, outname,
-				    (flags & PEX_BINARY_OUTPUT) != 0);
+				    (flags & PEX_BINARY_OUTPUT) != 0,
+				    (flags & PEX_STDOUT_APPEND) != 0);
       if (out < 0)
 	{
 	  *err = errno;
@@ -319,8 +320,9 @@  pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
     }
   else
     {
-      errdes = obj->funcs->open_write (obj, errname, 
-				       (flags & PEX_BINARY_ERROR) != 0);
+      errdes = obj->funcs->open_write (obj, errname,
+				       (flags & PEX_BINARY_ERROR) != 0,
+				       (flags & PEX_STDERR_APPEND) != 0);
       if (errdes < 0)
 	{
 	  *err = errno;
diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h
index af338e6..b6db248 100644
--- a/libiberty/pex-common.h
+++ b/libiberty/pex-common.h
@@ -104,7 +104,7 @@  struct pex_funcs
   /* Open file NAME for writing.  If BINARY is non-zero, open in
      binary mode.  Return >= 0 on success, -1 on error.  */
   int (*open_write) (struct pex_obj *, const char */* name */,
-                     int /* binary */);
+                     int /* binary */, int /* append */);
   /* Execute a child process.  FLAGS, EXECUTABLE, ARGV, ERR are from
      pex_run.  IN, OUT, ERRDES, TOCLOSE are all descriptors, from
      open_read, open_write, or pipe, or they are one of STDIN_FILE_NO,
diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c
index 0721139..b014ffa 100644
--- a/libiberty/pex-djgpp.c
+++ b/libiberty/pex-djgpp.c
@@ -43,7 +43,7 @@  extern int errno;
 #endif
 
 static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
-static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
+static int pex_djgpp_open_write (struct pex_obj *, const char *, int, int);
 static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *,
 				  char * const *, char * const *,
 				  int, int, int, int,
@@ -90,10 +90,12 @@  pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
 
 static int
 pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
-		      const char *name, int binary)
+		      const char *name, int binary, int append)
 {
   /* Note that we can't use O_EXCL here because gcc may have already
      created the temporary file via make_temp_file.  */
+  if (append)
+    return -1;
   return open (name,
 	       (O_WRONLY | O_CREAT | O_TRUNC
 		| (binary ? O_BINARY : O_TEXT)),
diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c
index addf8ee..0715115 100644
--- a/libiberty/pex-unix.c
+++ b/libiberty/pex-unix.c
@@ -301,7 +301,7 @@  pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
 static void pex_child_error (struct pex_obj *, const char *, const char *, int)
      ATTRIBUTE_NORETURN;
 static int pex_unix_open_read (struct pex_obj *, const char *, int);
-static int pex_unix_open_write (struct pex_obj *, const char *, int);
+static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
 static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
 				 char * const *, char * const *,
 				 int, int, int, int,
@@ -350,11 +350,12 @@  pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
 
 static int
 pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
-		     int binary ATTRIBUTE_UNUSED)
+		     int binary ATTRIBUTE_UNUSED, int append)
 {
   /* Note that we can't use O_EXCL here because gcc may have already
      created the temporary file via make_temp_file.  */
-  return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
+  return open (name, O_WRONLY | O_CREAT
+		     | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
 }
 
 /* Close a file.  */
diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c
index 8b9d4f0..66d2f11 100644
--- a/libiberty/pex-win32.c
+++ b/libiberty/pex-win32.c
@@ -78,7 +78,7 @@  backslashify (char *s)
 }
 
 static int pex_win32_open_read (struct pex_obj *, const char *, int);
-static int pex_win32_open_write (struct pex_obj *, const char *, int);
+static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
 static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
 				  char * const *, char * const *,
                                   int, int, int, int,
@@ -126,10 +126,12 @@  pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
 
 static int
 pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
-		      int binary)
+		      int binary, int append)
 {
   /* Note that we can't use O_EXCL here because gcc may have already
      created the temporary file via make_temp_file.  */
+  if (append)
+    return -1;
   return _open (name,
 		(_O_WRONLY | _O_CREAT | _O_TRUNC
 		 | (binary ? _O_BINARY : _O_TEXT)),
diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
index 4196c53..8594cf9 100644
--- a/libiberty/simple-object-elf.c
+++ b/libiberty/simple-object-elf.c
@@ -698,6 +698,7 @@  simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
   unsigned char buf[sizeof (Elf64_External_Ehdr)];
   simple_object_write_section *section;
   unsigned int shnum;
+  unsigned int shstrndx;
 
   fns = attrs->type_functions;
   cl = attrs->ei_class;
@@ -743,9 +744,17 @@  simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
 		 (cl == ELFCLASS32
 		  ? sizeof (Elf32_External_Shdr)
 		  : sizeof (Elf64_External_Shdr)));
-  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
-  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
-		 shnum == 0 ? 0 : shnum - 1);
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
+		 shnum >= SHN_LORESERVE ? 0 : shnum);
+  if (shnum == 0)
+    shstrndx = 0;
+  else
+    {
+      shstrndx = shnum - 1;
+      if (shstrndx >= SHN_LORESERVE)
+	shstrndx = SHN_XINDEX;
+    }
+  ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
 
   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
 				       errmsg, err);
@@ -758,8 +767,8 @@  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
 			      off_t offset, unsigned int sh_name,
 			      unsigned int sh_type, unsigned int sh_flags,
 			      unsigned int sh_offset, unsigned int sh_size,
-			      unsigned int sh_addralign, const char **errmsg,
-			      int *err)
+			      unsigned int sh_link, unsigned int sh_addralign,
+			      const char **errmsg, int *err)
 {
   struct simple_object_elf_attributes *attrs =
     (struct simple_object_elf_attributes *) sobj->data;
@@ -781,7 +790,7 @@  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
-  /* sh_link left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
   /* sh_info left as zero.  */
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
   /* sh_entsize left as zero.  */
@@ -812,6 +821,8 @@  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
   unsigned int shnum;
   size_t shdr_offset;
   size_t sh_offset;
+  unsigned int first_sh_size;
+  unsigned int first_sh_link;
   size_t sh_name;
   unsigned char zero;
 
@@ -842,8 +853,17 @@  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
   shdr_offset = ehdr_size;
   sh_offset = shdr_offset + shnum * shdr_size;
 
+  if (shnum < SHN_LORESERVE)
+    first_sh_size = 0;
+  else
+    first_sh_size = shnum;
+  if (shnum - 1 < SHN_LORESERVE)
+    first_sh_link = 0;
+  else
+    first_sh_link = shnum - 1;
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-				     0, 0, 0, 0, 0, 0, &errmsg, err))
+				     0, 0, 0, 0, first_sh_size, first_sh_link,
+				     0, &errmsg, err))
     return errmsg;
 
   shdr_offset += shdr_size;
@@ -887,7 +907,7 @@  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
 
       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
 					 sh_name, SHT_PROGBITS, 0, sh_offset,
-					 sh_size, 1U << section->align,
+					 sh_size, 0, 1U << section->align,
 					 &errmsg, err))
 	return errmsg;
 
@@ -898,7 +918,7 @@  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
 
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
 				     sh_name, SHT_STRTAB, 0, sh_offset,
-				     sh_name + strlen (".shstrtab") + 1,
+				     sh_name + strlen (".shstrtab") + 1, 0,
 				     1, &errmsg, err))
     return errmsg;
 
diff --git a/libiberty/testsuite/Makefile.in b/libiberty/testsuite/Makefile.in
index 69ac1f5..bb2db67 100644
--- a/libiberty/testsuite/Makefile.in
+++ b/libiberty/testsuite/Makefile.in
@@ -45,12 +45,15 @@  all:
 # CHECK is set to "really_check" or the empty string by configure.
 check: @CHECK@
 
-really-check: check-cplus-dem check-pexecute check-expandargv
+really-check: check-cplus-dem check-d-demangle check-pexecute check-expandargv
 
 # Run some tests of the demangler.
 check-cplus-dem: test-demangle $(srcdir)/demangle-expected
 	./test-demangle < $(srcdir)/demangle-expected
 
+check-d-demangle: test-demangle $(srcdir)/d-demangle-expected
+	./test-demangle < $(srcdir)/d-demangle-expected
+
 # Check the pexecute code.
 check-pexecute: test-pexecute
 	./test-pexecute
@@ -59,6 +62,10 @@  check-pexecute: test-pexecute
 check-expandargv: test-expandargv
 	./test-expandargv
 
+# Run the demangler fuzzer
+fuzz-demangler: demangler-fuzzer
+	./demangler-fuzzer
+
 TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES)
 test-demangle: $(srcdir)/test-demangle.c ../libiberty.a
 	$(TEST_COMPILE) -o test-demangle \
@@ -72,6 +79,10 @@  test-expandargv: $(srcdir)/test-expandargv.c ../libiberty.a
 	$(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-expandargv \
 		$(srcdir)/test-expandargv.c ../libiberty.a
 
+demangler-fuzzer: $(srcdir)/demangler-fuzzer.c ../libiberty.a
+	$(TEST_COMPILE) -o demangler-fuzzer \
+		$(srcdir)/demangler-fuzzer.c ../libiberty.a
+
 # Standard (either GNU or Cygnus) rules we don't use.
 html install-html info install-info clean-info dvi pdf install-pdf \
 install etags tags installcheck:
@@ -81,6 +92,7 @@  mostlyclean:
 	rm -f test-demangle
 	rm -f test-pexecute
 	rm -f test-expandargv
+	rm -f demangler-fuzzer
 	rm -f core
 clean: mostlyclean
 distclean: clean
diff --git a/libiberty/testsuite/d-demangle-expected b/libiberty/testsuite/d-demangle-expected
new file mode 100644
index 0000000..2aeacb8
--- /dev/null
+++ b/libiberty/testsuite/d-demangle-expected
@@ -0,0 +1,936 @@ 
+# This file holds test cases for the D demangler.
+# Each test case looks like this:
+#  options
+#  input to be demangled
+#  expected output
+#
+# See demangle-expected for documentation of supported options.
+#
+# A line starting with `#' is ignored.
+# However, blank lines in this file are NOT ignored.
+#
+############
+#
+# Coverage Tests
+#
+--format=dlang
+_Dmain
+D main
+#
+--format=dlang
+_D8demangle4testPFLAiYi
+demangle.test
+#
+--format=dlang
+_D8demangle4testFaZv
+demangle.test(char)
+#
+--format=dlang
+_D8demangle4testFbZv
+demangle.test(bool)
+#
+--format=dlang
+_D8demangle4testFcZv
+demangle.test(creal)
+#
+--format=dlang
+_D8demangle4testFdZv
+demangle.test(double)
+#
+--format=dlang
+_D8demangle4testFeZv
+demangle.test(real)
+#
+--format=dlang
+_D8demangle4testFfZv
+demangle.test(float)
+#
+--format=dlang
+_D8demangle4testFgZv
+demangle.test(byte)
+#
+--format=dlang
+_D8demangle4testFhZv
+demangle.test(ubyte)
+#
+--format=dlang
+_D8demangle4testFiZv
+demangle.test(int)
+#
+--format=dlang
+_D8demangle4testFjZv
+demangle.test(ireal)
+#
+--format=dlang
+_D8demangle4testFkZv
+demangle.test(uint)
+#
+--format=dlang
+_D8demangle4testFlZv
+demangle.test(long)
+#
+--format=dlang
+_D8demangle4testFmZv
+demangle.test(ulong)
+#
+--format=dlang
+_D8demangle4testFnZv
+demangle.test(none)
+#
+--format=dlang
+_D8demangle4testFoZv
+demangle.test(ifloat)
+#
+--format=dlang
+_D8demangle4testFpZv
+demangle.test(idouble)
+#
+--format=dlang
+_D8demangle4testFqZv
+demangle.test(cfloat)
+#
+--format=dlang
+_D8demangle4testFrZv
+demangle.test(cdouble)
+#
+--format=dlang
+_D8demangle4testFsZv
+demangle.test(short)
+#
+--format=dlang
+_D8demangle4testFtZv
+demangle.test(ushort)
+#
+--format=dlang
+_D8demangle4testFuZv
+demangle.test(wchar)
+#
+--format=dlang
+_D8demangle4testFvZv
+demangle.test(void)
+#
+--format=dlang
+_D8demangle4testFwZv
+demangle.test(dchar)
+#
+--format=dlang
+_D8demangle4testFOaZv
+demangle.test(shared(char))
+#
+--format=dlang
+_D8demangle4testFxaZv
+demangle.test(const(char))
+#
+--format=dlang
+_D8demangle4testFyaZv
+demangle.test(immutable(char))
+#
+--format=dlang
+_D8demangle4testFNgaZv
+demangle.test(inout(char))
+#
+--format=dlang
+_D8demangle4testFOxaZv
+demangle.test(shared(const(char)))
+#
+--format=dlang
+_D8demangle4testFONgaZv
+demangle.test(shared(inout(char)))
+#
+--format=dlang
+_D8demangle4testFAaZv
+demangle.test(char[])
+#
+--format=dlang
+_D8demangle4testFAAaZv
+demangle.test(char[][])
+#
+--format=dlang
+_D8demangle4testFAAAaZv
+demangle.test(char[][][])
+#
+--format=dlang
+_D8demangle4testFG42aZv
+demangle.test(char[42])
+#
+--format=dlang
+_D8demangle4testFG42G42aZv
+demangle.test(char[42][42])
+#
+--format=dlang
+_D8demangle4testFG42G42G42aZv
+demangle.test(char[42][42][42])
+#
+--format=dlang
+_D8demangle4testFG1234567890aZv
+demangle.test(char[1234567890])
+#
+--format=dlang
+_D8demangle4testFHaaZv
+demangle.test(char[char])
+#
+--format=dlang
+_D8demangle4testFHHaaaZv
+demangle.test(char[char[char]])
+#
+--format=dlang
+_D8demangle4testFPaZv
+demangle.test(char*)
+#
+--format=dlang
+_D8demangle4testFPPaZv
+demangle.test(char**)
+#
+--format=dlang
+_D8demangle4testFPPPaZv
+demangle.test(char***)
+#
+--format=dlang
+_D8demangle4testFNhG8gZv
+demangle.test(__vector(byte[8]))
+#
+--format=dlang
+_D8demangle4testFNhG16gZv
+demangle.test(__vector(byte[16]))
+#
+--format=dlang
+_D8demangle4testFNhG32gZv
+demangle.test(__vector(byte[32]))
+#
+--format=dlang
+_D8demangle4testFNhG4sZv
+demangle.test(__vector(short[4]))
+#
+--format=dlang
+_D8demangle4testFNhG8sZv
+demangle.test(__vector(short[8]))
+#
+--format=dlang
+_D8demangle4testFNhG16sZv
+demangle.test(__vector(short[16]))
+#
+--format=dlang
+_D8demangle4testFNhG2iZv
+demangle.test(__vector(int[2]))
+#
+--format=dlang
+_D8demangle4testFNhG4iZv
+demangle.test(__vector(int[4]))
+#
+--format=dlang
+_D8demangle4testFNhG8iZv
+demangle.test(__vector(int[8]))
+#
+--format=dlang
+_D8demangle4testFNhG1lZv
+demangle.test(__vector(long[1]))
+#
+--format=dlang
+_D8demangle4testFNhG2lZv
+demangle.test(__vector(long[2]))
+#
+--format=dlang
+_D8demangle4testFNhG4lZv
+demangle.test(__vector(long[4]))
+#
+--format=dlang
+_D8demangle4testFNhG2fZv
+demangle.test(__vector(float[2]))
+#
+--format=dlang
+_D8demangle4testFNhG4fZv
+demangle.test(__vector(float[4]))
+#
+--format=dlang
+_D8demangle4testFNhG8fZv
+demangle.test(__vector(float[8]))
+#
+--format=dlang
+_D8demangle4testFNhG1dZv
+demangle.test(__vector(double[1]))
+#
+--format=dlang
+_D8demangle4testFNhG2dZv
+demangle.test(__vector(double[2]))
+#
+--format=dlang
+_D8demangle4testFNhG4dZv
+demangle.test(__vector(double[4]))
+#
+--format=dlang
+_D8demangle4testFI5identZv
+demangle.test(ident)
+#
+--format=dlang
+_D8demangle4testFI5ident4testZv
+demangle.test(ident.test)
+#
+--format=dlang
+_D8demangle4testFC5classZv
+demangle.test(class)
+#
+--format=dlang
+_D8demangle4testFC5class4testZv
+demangle.test(class.test)
+#
+--format=dlang
+_D8demangle4testFS6structZv
+demangle.test(struct)
+#
+--format=dlang
+_D8demangle4testFS6struct4testZv
+demangle.test(struct.test)
+#
+--format=dlang
+_D8demangle4testFE4enumZv
+demangle.test(enum)
+#
+--format=dlang
+_D8demangle4testFE4enum4testZv
+demangle.test(enum.test)
+#
+--format=dlang
+_D8demangle4testFT7typedefZv
+demangle.test(typedef)
+#
+--format=dlang
+_D8demangle4testFT7typedef4testZv
+demangle.test(typedef.test)
+#
+--format=dlang
+_D8demangle4testFJaZv
+demangle.test(out char)
+#
+--format=dlang
+_D8demangle4testFKaZv
+demangle.test(ref char)
+#
+--format=dlang
+_D8demangle4testFLaZv
+demangle.test(lazy char)
+#
+--format=dlang
+_D8demangle4testFMaZv
+demangle.test(scope char)
+#
+--format=dlang
+_D8demangle4testFaXv
+demangle.test(char...)
+#
+--format=dlang
+_D8demangle4testFaYv
+demangle.test(char, ...)
+#
+--format=dlang
+_D8demangle4testFaaYv
+demangle.test(char, char, ...)
+#
+--format=dlang
+_D8demangle4testFaaZv
+demangle.test(char, char)
+#
+--format=dlang
+_D8demangle4testFB0Zv
+demangle.test(Tuple!())
+#
+--format=dlang
+_D8demangle4testFB1aZv
+demangle.test(Tuple!(char))
+#
+--format=dlang
+_D8demangle4testFB2aaZv
+demangle.test(Tuple!(char, char))
+#
+--format=dlang
+_D8demangle4testFB3aaaZv
+demangle.test(Tuple!(char, char, char))
+#
+--format=dlang
+_D8demangle4testFB2OaaZv
+demangle.test(Tuple!(shared(char), char))
+#
+--format=dlang
+_D8demangle4testFB3aDFZaaZv
+demangle.test(Tuple!(char, char() delegate, char))
+#
+--format=dlang
+_D8demangle4testFDFZaZv
+demangle.test(char() delegate)
+#
+--format=dlang
+_D8demangle4testFDUZaZv
+demangle.test(extern(C) char() delegate)
+#
+--format=dlang
+_D8demangle4testFDWZaZv
+demangle.test(extern(Windows) char() delegate)
+#
+--format=dlang
+_D8demangle4testFDVZaZv
+demangle.test(extern(Pascal) char() delegate)
+#
+--format=dlang
+_D8demangle4testFDRZaZv
+demangle.test(extern(C++) char() delegate)
+#
+--format=dlang
+_D8demangle4testFFZaZv
+demangle.test(char() function)
+#
+--format=dlang
+_D8demangle4testFUZaZv
+demangle.test(extern(C) char() function)
+#
+--format=dlang
+_D8demangle4testFWZaZv
+demangle.test(extern(Windows) char() function)
+#
+--format=dlang
+_D8demangle4testFVZaZv
+demangle.test(extern(Pascal) char() function)
+#
+--format=dlang
+_D8demangle4testFRZaZv
+demangle.test(extern(C++) char() function)
+#
+--format=dlang
+_D8demangle4testFDFNaZaZv
+demangle.test(char() pure delegate)
+#
+--format=dlang
+_D8demangle4testFDFNbZaZv
+demangle.test(char() nothrow delegate)
+#
+--format=dlang
+_D8demangle4testFDFNcZaZv
+demangle.test(char() ref delegate)
+#
+--format=dlang
+_D8demangle4testFDFNdZaZv
+demangle.test(char() @property delegate)
+#
+--format=dlang
+_D8demangle4testFDFNeZaZv
+demangle.test(char() @trusted delegate)
+#
+--format=dlang
+_D8demangle4testFDFNfZaZv
+demangle.test(char() @safe delegate)
+#
+--format=dlang
+_D8demangle4testFDFNiZaZv
+demangle.test(char() @nogc delegate)
+#
+--format=dlang
+_D8demangle4testFDFNaNbZaZv
+demangle.test(char() pure nothrow delegate)
+#
+--format=dlang
+_D8demangle4testFDFNbNaZaZv
+demangle.test(char() nothrow pure delegate)
+#
+--format=dlang
+_D8demangle4testFDFNdNfNaZaZv
+demangle.test(char() @property @safe pure delegate)
+#
+--format=dlang
+_D8demangle4testFFNaZaZv
+demangle.test(char() pure function)
+#
+--format=dlang
+_D8demangle4testFFNbZaZv
+demangle.test(char() nothrow function)
+#
+--format=dlang
+_D8demangle4testFFNcZaZv
+demangle.test(char() ref function)
+#
+--format=dlang
+_D8demangle4testFFNdZaZv
+demangle.test(char() @property function)
+#
+--format=dlang
+_D8demangle4testFFNeZaZv
+demangle.test(char() @trusted function)
+#
+--format=dlang
+_D8demangle4testFFNfZaZv
+demangle.test(char() @safe function)
+#
+--format=dlang
+_D8demangle4testFFNiZaZv
+demangle.test(char() @nogc function)
+#
+--format=dlang
+_D8demangle4testFFNaNbZaZv
+demangle.test(char() pure nothrow function)
+#
+--format=dlang
+_D8demangle4testFFNbNaZaZv
+demangle.test(char() nothrow pure function)
+#
+--format=dlang
+_D8demangle4testFFNdNfNaZaZv
+demangle.test(char() @property @safe pure function)
+#
+--format=dlang
+_D8demangle4test6__initZ
+demangle.test.init$
+#
+--format=dlang
+_D8demangle4test6__vtblZ
+vtable for demangle.test
+#
+--format=dlang
+_D8demangle4test7__ClassZ
+ClassInfo for demangle.test
+#
+--format=dlang
+_D8demangle4test11__InterfaceZ
+Interface for demangle.test
+#
+--format=dlang
+_D8demangle4test12__ModuleInfoZ
+ModuleInfo for demangle.test
+#
+--format=dlang
+_D8demangle4test6__ctorMFZv
+demangle.test.this()
+#
+--format=dlang
+_D8demangle4test6__dtorMFZv
+demangle.test.~this()
+#
+--format=dlang
+_D8demangle4test6__postblitMFZv
+demangle.test.this(this)
+#
+--format=dlang
+_D8demangle4testFHAbaZv
+demangle.test(char[bool[]])
+#
+--format=dlang
+_D8demangle4testFHG42caZv
+demangle.test(char[creal[42]])
+#
+--format=dlang
+_D8demangle4testFAiXv
+demangle.test(int[]...)
+#
+--format=dlang
+_D8demangle4testFLAiXv
+demangle.test(lazy int[]...)
+#
+--format=dlang
+_D8demangle4testFAiYv
+demangle.test(int[], ...)
+#
+--format=dlang
+_D8demangle4testFLAiYv
+demangle.test(lazy int[], ...)
+#
+--format=dlang
+_D8demangle4testFLilZv
+demangle.test(lazy int, long)
+#
+--format=dlang
+_D8demangle4testFLliZv
+demangle.test(lazy long, int)
+#
+--format=dlang
+_D8demangle4testFLC6ObjectLDFLiZiZi
+demangle.test(lazy Object, lazy int(lazy int) delegate)
+#
+--format=dlang
+_D8demangle9__T4testZv
+demangle.test!()
+#
+--format=dlang
+_D8demangle11__T4testTaZv
+demangle.test!(char)
+#
+--format=dlang
+_D8demangle13__T4testTaTaZv
+demangle.test!(char, char)
+#
+--format=dlang
+_D8demangle15__T4testTaTaTaZv
+demangle.test!(char, char, char)
+#
+--format=dlang
+_D8demangle16__T4testTaTOiTaZv
+demangle.test!(char, shared(int), char)
+#
+--format=dlang
+_D8demangle17__T4testS6symbolZv
+demangle.test!(symbol)
+#
+--format=dlang
+_D8demangle21__T4testS6symbol3fooZv
+demangle.test!(symbol.foo)
+#
+--format=dlang
+_D8demangle25__T4testS6symbol3foo3barZv
+demangle.test!(symbol.foo.bar)
+#
+--format=dlang
+_D8demangle19__T4testTaS6symbolZv
+demangle.test!(char, symbol)
+#
+--format=dlang
+_D8demangle19__T4testS6symbolTaZv
+demangle.test!(symbol, char)
+#
+--format=dlang
+_D8demangle13__T4testVPinZv
+demangle.test!(null)
+#
+--format=dlang
+_D8demangle14__T4testVg123Zv
+demangle.test!(123)
+#
+--format=dlang
+_D8demangle14__T4testVi123Zv
+demangle.test!(123)
+#
+--format=dlang
+_D8demangle14__T4testVs123Zv
+demangle.test!(123)
+#
+--format=dlang
+_D8demangle14__T4testVh123Zv
+demangle.test!(123u)
+#
+--format=dlang
+_D8demangle14__T4testVk123Zv
+demangle.test!(123u)
+#
+--format=dlang
+_D8demangle14__T4testVt123Zv
+demangle.test!(123u)
+#
+--format=dlang
+_D8demangle14__T4testVl123Zv
+demangle.test!(123L)
+#
+--format=dlang
+_D8demangle14__T4testVm123Zv
+demangle.test!(123uL)
+#
+--format=dlang
+_D8demangle15__T4testViN123Zv
+demangle.test!(-123)
+#
+--format=dlang
+_D8demangle15__T4testVkN123Zv
+demangle.test!(-123u)
+#
+--format=dlang
+_D8demangle15__T4testVlN123Zv
+demangle.test!(-123L)
+#
+--format=dlang
+_D8demangle15__T4testVmN123Zv
+demangle.test!(-123uL)
+#
+--format=dlang
+_D8demangle12__T4testVb1Zv
+demangle.test!(true)
+#
+--format=dlang
+_D8demangle12__T4testVb0Zv
+demangle.test!(false)
+#
+--format=dlang
+_D8demangle13__T4testVa10Zv
+demangle.test!('\x0a')
+#
+--format=dlang
+_D8demangle13__T4testVa32Zv
+demangle.test!(' ')
+#
+--format=dlang
+_D8demangle13__T4testVa65Zv
+demangle.test!('A')
+#
+--format=dlang
+_D8demangle14__T4testVa126Zv
+demangle.test!('~')
+#
+--format=dlang
+_D8demangle15__T4testVu1000Zv
+demangle.test!('\u03e8')
+#
+--format=dlang
+_D8demangle17__T4testVw100000Zv
+demangle.test!('\U000186a0')
+#
+--format=dlang
+_D8demangle17__T4testVde0A8P6Zv
+demangle.test!(42.0000)
+#
+--format=dlang
+_D8demangle16__T4testVdeA8P2Zv
+demangle.test!(42.0000)
+#
+--format=dlang
+_D8demangle18__T4testVdeN0A8P6Zv
+demangle.test!(-42.0000)
+#
+--format=dlang
+_D8demangle31__T4testVde0F6E978D4FDF3B646P7Zv
+demangle.test!(123.456)
+#
+--format=dlang
+_D8demangle15__T4testVdeNANZv
+demangle.test!(NaN)
+#
+--format=dlang
+_D8demangle15__T4testVdeINFZv
+demangle.test!(Inf)
+#
+--format=dlang
+_D8demangle16__T4testVdeNINFZv
+demangle.test!(-Inf)
+#
+--format=dlang
+_D8demangle23__T4testVfe0FFFFFFP128Zv
+demangle.test!(3.40282e+38)
+#
+--format=dlang
+_D8demangle32__T4testVde0FFFFFFFFFFFFF8P1024Zv
+demangle.test!(1.79769e+308)
+#
+--format=dlang
+_D8demangle19__T4testVfe08PN125Zv
+demangle.test!(1.17549e-38)
+#
+--format=dlang
+_D8demangle20__T4testVde08PN1021Zv
+demangle.test!(2.22507e-308)
+#
+--format=dlang
+_D8demangle51__T4testVrc0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv
+demangle.test!(12.3000+45.6000i)
+#
+--format=dlang
+_D8demangle52__T4testVrcN0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv
+demangle.test!(-12.3000+45.6000i)
+#
+--format=dlang
+_D8demangle22__T4testVG3ua3_616263Zv
+demangle.test!("abc")
+#
+--format=dlang
+_D8demangle22__T4testVG3ud3_616263Zv
+demangle.test!("abc"d)
+#
+--format=dlang
+_D8demangle22__T4testVG3uw3_616263Zv
+demangle.test!("abc"w)
+#
+--format=dlang
+_D8demangle22__T4testVAiA4i1i2i3i4Zv
+demangle.test!([1, 2, 3, 4])
+#
+--format=dlang
+_D8demangle25__T4testVAdA2e08P1eN08P1Zv
+demangle.test!([1.00000, -1.00000])
+#
+--format=dlang
+_D8demangle23__T4testVHiiA2i1i2i3i4Zv
+demangle.test!([1:2, 3:4])
+#
+--format=dlang
+_D8demangle39__T4testVHAxaiA2a3_616263i1a3_646566i2Zv
+demangle.test!(["abc":1, "def":2])
+#
+--format=dlang
+_D8demangle28__T4testVS8demangle1SS2i1i2Zv
+demangle.test!(demangle.S(1, 2))
+#
+--format=dlang
+_D8demangle35__T4testVS8demangle1SS2i1a3_616263Zv
+demangle.test!(demangle.S(1, "abc"))
+#
+# Unittests
+#
+--format=dlang
+printf
+printf
+#
+--format=dlang
+_foo
+_foo
+#
+--format=dlang
+_D88
+_D88
+#
+--format=dlang
+_D5__T1aZv
+_D5__T1aZv
+#
+--format=dlang
+_D4test3fooAa
+test.foo
+#
+--format=dlang
+_D8demangle8demangleFAaZAa
+demangle.demangle(char[])
+#
+--format=dlang
+_D6object6Object8opEqualsFC6ObjectZi
+object.Object.opEquals(Object)
+#
+--format=dlang
+_D6object6Object8opAssignFC6ObjectZi
+object.Object.opAssign(Object)
+#
+--format=dlang
+_D4test2dgDFiYd
+test.dg
+#
+--format=dlang
+_D1a1bi
+a.b
+#
+--format=dlang
+_D1a1bPFiZi
+a.b
+#
+--format=dlang
+_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi
+test.bar!("abc"w, "def"d).x
+#
+--format=dlang
+_D6plugin8generateFiiZAya
+plugin.generate(int, int)
+#
+--format=dlang
+_D6plugin8generateFiiZAxa
+plugin.generate(int, int)
+#
+--format=dlang
+_D6plugin8generateFiiZAOa
+plugin.generate(int, int)
+#
+--format=dlang
+_D8demangle3fnAFZv3fnBMFZv
+demangle.fnA().fnB()
+#
+--format=dlang
+_D8demangle4mainFZv1S3fnCFZv
+demangle.main().S.fnC()
+#
+--format=dlang
+_D8demangle4mainFZv1S3fnDMFZv
+demangle.main().S.fnD()
+#
+--format=dlang
+_D8demangle4mainFZv5localMFZi
+demangle.main().local()
+#
+--format=dlang
+_D3std5ascii9uppercaseyAa
+std.ascii.uppercase
+#
+--format=dlang
+_D3std6stream9BOMEndianyG5E3std6system6Endian
+std.stream.BOMEndian
+#
+--format=dlang
+_D3std8internal7uni_tab10unicodeNkoyS3std8internal3uni12CodepointSet
+std.internal.uni_tab.unicodeNko
+#
+--format=dlang
+_D2gc2gc2GC6addrOfMFPvZPv
+gc.gc.GC.addrOf(void*)
+#
+--format=dlang
+_D3std7process10setCLOEXECFibZv
+std.process.setCLOEXEC(int, bool)
+#
+--format=dlang
+_D3std6digest2md3MD53putMFNaNbNeMAxhXv
+std.digest.md.MD5.put(scope const(ubyte)[]...)
+#
+--format=dlang
+_D3std6mmfile6MmFile13opIndexAssignMFhmZh
+std.mmfile.MmFile.opIndexAssign(ubyte, ulong)
+#
+--format=dlang
+_D3std7process18escapeShellCommandFxAAaXAya
+std.process.escapeShellCommand(const(char[][])...)
+#
+--format=dlang
+_D4core4sync5mutex5Mutex6__ctorMFC6ObjectZC4core4sync5mutex5Mutex
+core.sync.mutex.Mutex.this(Object)
+#
+--format=dlang
+_D6object14TypeInfo_Array8argTypesMFNbNfJC8TypeInfoJC8TypeInfoZi
+object.TypeInfo_Array.argTypes(out TypeInfo, out TypeInfo)
+#
+--format=dlang
+_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7tryExecMFMDFZvZv
+rt.dmain2._d_run_main(int, char**, extern(C) int(char[][]) function*).tryExec(scope void() delegate)
+#
+--format=dlang
+_D6object9Exception6__ctorMFNaNbNfAyaAyamC6object9ThrowableZC9Exception
+object.Exception.this(immutable(char)[], immutable(char)[], ulong, object.Throwable)
+#
+--format=dlang
+_D3gcc3deh17parse_lsda_headerFPS3gcc6unwind7generic15_Unwind_ContextPhPS3gcc3deh16lsda_header_infoZPh
+gcc.deh.parse_lsda_header(gcc.unwind.generic._Unwind_Context*, ubyte*, gcc.deh.lsda_header_info*)
+#
+--format=dlang
+_D3std6socket23UnknownAddressReference6__ctorMFPS4core3sys5posix3sys6socket8sockaddrkZC3std6socket23UnknownAddressReference
+std.socket.UnknownAddressReference.this(core.sys.posix.sys.socket.sockaddr*, uint)
+#
+--format=dlang
+_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv
+demangle.fn!([1, 2, 3, 4]).fn()
+#
+--format=dlang
+_D8demangle10__T2fnVi1Z2fnFZv
+demangle.fn!(1).fn()
+#
+--format=dlang
+_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv
+demangle.fn!(demangle.S(1, 2)).fn()
+#
+--format=dlang
+_D8demangle13__T2fnVeeNANZ2fnFZv
+demangle.fn!(NaN).fn()
+#
+--format=dlang
+_D8demangle14__T2fnVeeNINFZ2fnFZv
+demangle.fn!(-Inf).fn()
+#
+--format=dlang
+_D8demangle13__T2fnVeeINFZ2fnFZv
+demangle.fn!(Inf).fn()
+#
+--format=dlang
+_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv
+demangle.fn!([1:2, 3:4]).fn()
+#
+--format=dlang
+_D8demangle2fnFNgiZNgi
+demangle.fn(inout(int))
+#
+--format=dlang
+_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv
+demangle.fn!('a', '\x09', '\x00', '\u0101', '\U00010001').fn()
+#
+--format=dlang
+_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv
+gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)
+#
+--format=dlang
+_D8serenity9persister6Sqlite70__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZv4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZv4Test
+serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)
+#
+--format=dlang
+_D4test4mainFZv5localMFZi
+test.main().local()
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 864ee7e..a030685 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4343,8 +4343,16 @@  cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::p
 --format=gnu-v3
 _ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v
 void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<void post<std::function<void ()> >(void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
+#
+--format=auto --no-params
+_Z3xxxDFyuVb
+xxx(unsigned long long _Fract, bool volatile)
+xxx
 # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
 --format=auto --no-params
 _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
 _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
 _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
+--format=gnu-v3
+_Z1fSsB3fooS_
+f(std::string[abi:foo], std::string[abi:foo])
diff --git a/libiberty/testsuite/demangler-fuzzer.c b/libiberty/testsuite/demangler-fuzzer.c
new file mode 100644
index 0000000..aff7024
--- /dev/null
+++ b/libiberty/testsuite/demangler-fuzzer.c
@@ -0,0 +1,108 @@ 
+/* Demangler fuzzer.
+
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   This file is part of GNU libiberty.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include "demangle.h"
+
+#define MAXLEN 253
+#define ALPMIN 33
+#define ALPMAX 127
+
+static char *program_name;
+
+#define DEFAULT_MAXCOUNT 7500000
+
+static void
+print_usage (FILE *fp, int exit_value)
+{
+  fprintf (fp, "Usage: %s [OPTION]...\n", program_name);
+  fprintf (fp, "Options:\n");
+  fprintf (fp, "  -h           Display this message.\n");
+  fprintf (fp, "  -s SEED      Select the random seed to be used.\n");
+  fprintf (fp, "               The default is to base one on the");
+  fprintf (fp, " current time.\n");
+  fprintf (fp, "  -m MAXCOUNT  Exit after MAXCOUNT symbols.\n");
+  fprintf (fp, "               The default is %d.", DEFAULT_MAXCOUNT);
+  fprintf (fp, " Set to `-1' for no limit.\n");
+
+  exit (exit_value);
+}
+
+int
+main (int argc, char *argv[])
+{
+  char symbol[2 + MAXLEN + 1] = "_Z";
+  int seed = -1, seed_set = 0;
+  int count = 0, maxcount = DEFAULT_MAXCOUNT;
+  int optchr;
+
+  program_name = argv[0];
+
+  do
+    {
+      optchr = getopt (argc, argv, "hs:m:t:");
+      switch (optchr)
+	{
+	case '?':  /* Unrecognized option.  */
+	  print_usage (stderr, 1);
+	  break;
+
+	case 'h':
+	  print_usage (stdout, 0);
+	  break;
+
+	case 's':
+	  seed = atoi (optarg);
+	  seed_set = 1;
+	  break;
+
+	case 'm':
+	  maxcount = atoi (optarg);
+	  break;
+	}
+    }
+  while (optchr != -1);
+
+  if (!seed_set)
+    seed = time (NULL);
+  srand (seed);
+  printf ("%s: seed = %d\n", program_name, seed);
+
+  while (maxcount < 0 || count < maxcount)
+    {
+      char *buffer = symbol + 2;
+      int length, i;
+
+      length = rand () % MAXLEN;
+      for (i = 0; i < length; i++)
+	*buffer++ = (rand () % (ALPMAX - ALPMIN)) + ALPMIN;
+
+      *buffer++ = '\0';
+
+      cplus_demangle (symbol, DMGL_AUTO | DMGL_ANSI | DMGL_PARAMS);
+
+      count++;
+    }
+
+  printf ("%s: successfully demangled %d symbols\n", program_name, count);
+  exit (0);
+}