[PATCH 2/2] Add demangle option to Symbols_Load() command

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


---
 src/configuration.c          | 2 ++
 src/debug/symbols.c          | 2 +-
 src/includes/configuration.h | 2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/configuration.c b/src/configuration.c
index 468ad6ec..1be23fdd 100644
--- a/src/configuration.c
+++ b/src/configuration.c
@@ -70,6 +70,7 @@ static const struct Config_Tag configs_Debugger[] =
 	{ "bDisasmUAE", Bool_Tag, &ConfigureParams.Debugger.bDisasmUAE },
 	{ "bSymbolsAutoLoad", Bool_Tag, &ConfigureParams.Debugger.bSymbolsAutoLoad },
 	{ "bMatchAllSymbols", Bool_Tag, &ConfigureParams.Debugger.bMatchAllSymbols },
+	{ "bDemangle", Bool_Tag, &ConfigureParams.Debugger.bDemangle },
 	{ NULL , Error_Tag, NULL }
 };
 
@@ -538,6 +539,7 @@ void Configuration_SetDefault(void)
 	ConfigureParams.Debugger.bDisasmUAE = true;
 	ConfigureParams.Debugger.bSymbolsAutoLoad = true;
 	ConfigureParams.Debugger.bMatchAllSymbols = false;
+	ConfigureParams.Debugger.bDemangle = false;
 	ConfigureParams.Debugger.nDisasmOptions = Disasm_GetOptions();
 	Disasm_Init();
 
diff --git a/src/debug/symbols.c b/src/debug/symbols.c
index ba3afb3f..2d148dcf 100644
--- a/src/debug/symbols.c
+++ b/src/debug/symbols.c
@@ -295,7 +295,7 @@ static symbol_list_t* Symbols_Load(const char *filename, uint32_t *offsets, uint
 		opts.notypes = 0;
 		opts.no_obj = true;
 		opts.no_local = true;
-		opts.demangle = false;
+		opts.demangle = ConfigureParams.Debugger.bDemangle;
 		list = symbols_load_binary(fp, &opts, update_sections);
 		SymbolsAreForProgram = true;
 	} else {
diff --git a/src/includes/configuration.h b/src/includes/configuration.h
index 86e26c37..f38f9103 100644
--- a/src/includes/configuration.h
+++ b/src/includes/configuration.h
@@ -39,6 +39,8 @@ typedef struct
   bool bSymbolsAutoLoad;
   /* whether to match all symbols or just types relevant for given command */
   bool bMatchAllSymbols;
+  /* whether to demangle c++ style symbol names */
+  bool bDemangle;
 } CNF_DEBUGGER;
 
 
-- 
2.39.0


--nextPart1937259.O6WyjCxUj0
Content-Disposition: attachment;
 filename="0001-Add-demangle-option-to-gst2ascii.patch"
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; charset="unicode-2-0-utf-8";
 name="0001-Add-demangle-option-to-gst2ascii.patch"

=46rom 7e0771e4c833311d077894bccaf2cd1685d80b52 Mon Sep 17 00:00:00 2001
=46rom: Thorsten Otto <admin@xxxxxxxxxxx>
Date: Mon, 27 Feb 2023 09:21:07 +0100
Subject: [PATCH 1/2] Add demangle option to gst2ascii

=2D--
 src/debug/cp-dem.c         | 6694 ++++++++++++++++++++++++++++++++++++
 src/debug/demangle.h       |  630 ++++
 src/debug/symbols-common.c |   45 +
 src/debug/symbols.c        |    1 +
 tools/debugger/gst2ascii.c |    4 +
 5 files changed, 7374 insertions(+)
 create mode 100644 src/debug/cp-dem.c
 create mode 100644 src/debug/demangle.h

diff --git a/src/debug/cp-dem.c b/src/debug/cp-dem.c
new file mode 100644
index 00000000..ec0edf76
=2D-- /dev/null
+++ b/src/debug/cp-dem.c
@@ -0,0 +1,6694 @@
+/* Demangler for g++ V3 ABI.
+   Copyright (C) 2003-2022 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor <ian@xxxxxxxxxxxxxxxxx>.
+
+   This file is part of the libiberty library, which is part of GCC.
+
+   This file 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 2 of the License, or
+   (at your option) any later version.
+
+   In addition to the permissions in the GNU 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 General 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.)
+
+   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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-13=
01, USA.=20
+*/
+
+/* This code implements a demangler for the g++ V3 ABI.  The ABI is
+   described on this web page:
+       https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
+
+   This code was written while looking at the demangler written by
+   Alex Samuel <samuel@xxxxxxxxxxxxxxxx>.
+
+   This code first pulls the mangled name apart into a list of
+   components, and then walks the list generating the demangled
+   name.
+
+   This file will normally define the following functions, q.v.:
+      char *cplus_demangle_v3(const char *mangled, int options)
+      char *java_demangle_v3(const char *mangled)
+      int cplus_demangle_v3_callback(const char *mangled, int options,
+                                     demangle_callbackref callback)
+      int java_demangle_v3_callback(const char *mangled,
+                                    demangle_callbackref callback)
+      enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
+      enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
+
+   Also, the interface to the component list is public, and defined in
+   demangle.h.  The interface consists of these types, which are
+   defined in demangle.h:
+      enum demangle_component_type
+      struct demangle_component
+      demangle_callbackref
+   and these functions defined in this file:
+      cplus_demangle_fill_name
+      cplus_demangle_fill_extended_operator
+      cplus_demangle_fill_ctor
+      cplus_demangle_fill_dtor
+      cplus_demangle_print
+      cplus_demangle_print_callback
+   and other functions defined in the file cp-demint.c.
+
+   This file also defines some other functions and variables which are
+   only to be used by the file cp-demint.c.
+
+   Preprocessor macros you can define while compiling this file:
+
+   IN_LIBGCC2
+      If defined, this file defines the following functions, q.v.:
+         char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
+                               int *status)
+         int __gcclibcxx_demangle_callback (const char *,
+                                            void (*)
+                                              (const char *, size_t, void =
*),
+                                            void *)
+      instead of cplus_demangle_v3[_callback]() and
+      java_demangle_v3[_callback]().
+
+   IN_GLIBCPP_V3
+      If defined, this file defines only __cxa_demangle() and
+      __gcclibcxx_demangle_callback(), and no other publically visible
+      functions or variables.
+
+   STANDALONE_DEMANGLER
+      If defined, this file defines a main() function which demangles
+      any arguments, or, if none, demangles stdin.
+
+   CP_DEMANGLE_DEBUG
+      If defined, turns on debugging mode, which prints information on
+      stdout about the mangled string.  This is not generally useful.
+
+   CHECK_DEMANGLER
+      If defined, additional sanity checks will be performed.  It will
+      cause some slowdown, but will allow to catch out-of-bound access
+      errors earlier.  This macro is intended for testing and debugging.  =
*/
+
+#if defined (_AIX) && !defined (__GNUC__)
+#pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+extern char *alloca();
+#endif /* __GNUC__ */
+#endif /* alloca */
+#endif /* HAVE_ALLOCA_H */
+
+#include <limits.h>
+
+#include "demangle.h"
+
+/* Information we keep for operators.  */
+
+struct demangle_operator_info
+{
+  /* Mangled name.  */
+  const char *code;
+  /* Real name.  */
+  const char *name;
+  /* Length of real name.  */
+  int len;
+  /* Number of arguments.  */
+  int args;
+};
+
+/* How to print the value of a builtin type.  */
+
+enum d_builtin_type_print
+{
+  /* Print as (type)val.  */
+  D_PRINT_DEFAULT,
+  /* Print as integer.  */
+  D_PRINT_INT,
+  /* Print as unsigned integer, with trailing "u".  */
+  D_PRINT_UNSIGNED,
+  /* Print as long, with trailing "l".  */
+  D_PRINT_LONG,
+  /* Print as unsigned long, with trailing "ul".  */
+  D_PRINT_UNSIGNED_LONG,
+  /* Print as long long, with trailing "ll".  */
+  D_PRINT_LONG_LONG,
+  /* Print as unsigned long long, with trailing "ull".  */
+  D_PRINT_UNSIGNED_LONG_LONG,
+  /* Print as bool.  */
+  D_PRINT_BOOL,
+  /* Print as float--put value in square brackets.  */
+  D_PRINT_FLOAT,
+  /* Print in usual way, but here to detect void.  */
+  D_PRINT_VOID
+};
+
+/* Information we keep for a builtin type.  */
+
+struct demangle_builtin_type_info
+{
+  /* Type name.  */
+  const char *name;
+  /* Length of type name.  */
+  int len;
+  /* Type name when using Java.  */
+  const char *java_name;
+  /* Length of java name.  */
+  int java_len;
+  /* How to print a value of this type.  */
+  enum d_builtin_type_print print;
+};
+
+/* The information structure we pass around.  */
+
+struct d_info
+{
+  /* The string we are demangling.  */
+  const char *s;
+  /* The end of the string we are demangling.  */
+  const char *send;
+  /* The options passed to the demangler.  */
+  int options;
+  /* The next character in the string to consider.  */
+  const char *n;
+  /* The array of components.  */
+  struct demangle_component *comps;
+  /* The index of the next available component.  */
+  int next_comp;
+  /* The number of available component structures.  */
+  int num_comps;
+  /* The array of substitutions.  */
+  struct demangle_component **subs;
+  /* The index of the next substitution.  */
+  int next_sub;
+  /* The number of available entries in the subs array.  */
+  int num_subs;
+  /* The last name we saw, for constructors and destructors.  */
+  struct demangle_component *last_name;
+  /* A running total of the length of large expansions from the
+     mangled name to the demangled name, such as standard
+     substitutions and builtin types.  */
+  int expansion;
+  /* Non-zero if we are parsing an expression.  */
+  int is_expression;
+  /* Non-zero if we are parsing the type operand of a conversion
+     operator, but not when in an expression.  */
+  int is_conversion;
+  /*  1: using new unresolved-name grammar.
+     -1: using new unresolved-name grammar and saw an unresolved-name.
+      0: using old unresolved-name grammar.  */
+  int unresolved_name_state;
+  /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
+     the current recursion level.  */
+  unsigned int recursion_level;
+};
+
+/* To avoid running past the ending '\0', don't:
+   - call d_peek_next_char if d_peek_char returned '\0'
+   - call d_advance with an 'i' that is too large
+   - call d_check_char(di, '\0')
+   Everything else is safe.  */
+#define d_peek_char(di) (*((di)->n))
+#ifndef CHECK_DEMANGLER
+#  define d_peek_next_char(di) ((di)->n[1])
+#  define d_advance(di, i) ((di)->n +=3D (i))
+#endif
+#define d_check_char(di, c) (d_peek_char(di) =3D=3D c ? ((di)->n++, 1) : 0)
+#define d_next_char(di) (d_peek_char(di) =3D=3D '\0' ? '\0' : *((di)->n++))
+#define d_str(di) ((di)->n)
+
+#ifdef CHECK_DEMANGLER
+static inline char
+d_peek_next_char (const struct d_info *di)
+{
+  if (!di->n[0])
+    abort ();
+  return di->n[1];
+}
+
+static inline void
+d_advance (struct d_info *di, int i)
+{
+  if (i < 0)
+    abort ();
+  while (i--)
+    {
+      if (!di->n[0])
+	abort ();
+      di->n++;
+    }
+}
+#endif
+
+/* Functions and arrays in cp-demangle.c which are referenced by
+   functions in cp-demint.c.  */
+#ifdef IN_GLIBCPP_V3
+#define CP_STATIC_IF_GLIBCPP_V3 static
+#else
+#define CP_STATIC_IF_GLIBCPP_V3 extern
+#endif
+
+#ifndef IN_GLIBCPP_V3
+extern const struct demangle_operator_info cplus_demangle_operators[];
+#endif
+
+#define D_BUILTIN_TYPE_COUNT (34)
+
+CP_STATIC_IF_GLIBCPP_V3 const struct demangle_builtin_type_info cplus_dema=
ngle_builtin_types[D_BUILTIN_TYPE_COUNT];
+
+CP_STATIC_IF_GLIBCPP_V3 struct demangle_component *cplus_demangle_mangled_=
name (struct d_info *, int);
+
+CP_STATIC_IF_GLIBCPP_V3 struct demangle_component *cplus_demangle_type (st=
ruct d_info *);
+
+extern void cplus_demangle_init_info (const char *, int, size_t, struct d_=
info *);
+
+/* cp-demangle.c needs to define this a little differently */
+#undef CP_STATIC_IF_GLIBCPP_V3
+
+
+/* If IN_GLIBCPP_V3 is defined, some functions are made static.  We
+   also rename them via #define to avoid compiler errors when the
+   static definition conflicts with the extern declaration in a header
+   file.  */
+#ifdef IN_GLIBCPP_V3
+
+#define CP_STATIC_IF_GLIBCPP_V3 static
+
+#define cplus_demangle_fill_name d_fill_name
+static int d_fill_name(struct demangle_component *, const char *, int);
+
+#define cplus_demangle_fill_extended_operator d_fill_extended_operator
+static int d_fill_extended_operator(struct demangle_component *, int, stru=
ct demangle_component *);
+
+#define cplus_demangle_fill_ctor d_fill_ctor
+static int d_fill_ctor(struct demangle_component *, enum gnu_v3_ctor_kinds=
, struct demangle_component *);
+
+#define cplus_demangle_fill_dtor d_fill_dtor
+static int d_fill_dtor(struct demangle_component *, enum gnu_v3_dtor_kinds=
, struct demangle_component *);
+
+#define cplus_demangle_mangled_name d_mangled_name
+static struct demangle_component *d_mangled_name(struct d_info *, int);
+
+#define cplus_demangle_type d_type
+static struct demangle_component *d_type(struct d_info *);
+
+#define cplus_demangle_print d_print
+static char *d_print(int, struct demangle_component *, int, size_t *);
+
+#define cplus_demangle_print_callback d_print_callback
+static int d_print_callback(int, struct demangle_component *, demangle_cal=
lbackref, void *);
+
+#define cplus_demangle_init_info d_init_info
+static void d_init_info(const char *, int, size_t, struct d_info *);
+
+#else /* ! defined(IN_GLIBCPP_V3) */
+#define CP_STATIC_IF_GLIBCPP_V3
+#endif /* ! defined(IN_GLIBCPP_V3) */
+
+/* See if the compiler supports dynamic arrays.  */
+
+#ifdef __GNUC__
+#define CP_DYNAMIC_ARRAYS
+#else
+#ifdef __STDC__
+#ifdef __STDC_VERSION__
+#if __STDC_VERSION__ >=3D 199901L && !__STDC_NO_VLA__
+#define CP_DYNAMIC_ARRAYS
+#endif /* __STDC_VERSION__ >=3D 199901L && !__STDC_NO_VLA__ */
+#endif /* defined (__STDC_VERSION__) */
+#endif /* defined (__STDC__) */
+#endif /* ! defined (__GNUC__) */
+
+/* We avoid pulling in the ctype tables, to prevent pulling in
+   additional unresolved symbols when this code is used in a library.
+   FIXME: Is this really a valid reason?  This comes from the original
+   V3 demangler code.
+
+   As of this writing this file has the following undefined references
+   when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy,
+   strcat, strlen.  */
+
+#define IS_DIGIT(c) ((c) >=3D '0' && (c) <=3D '9')
+#define IS_UPPER(c) ((c) >=3D 'A' && (c) <=3D 'Z')
+#define IS_LOWER(c) ((c) >=3D 'a' && (c) <=3D 'z')
+
+/* The prefix prepended by GCC to an identifier represnting the
+   anonymous namespace.  */
+#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
+#define ANONYMOUS_NAMESPACE_PREFIX_LEN (sizeof (ANONYMOUS_NAMESPACE_PREFIX=
) - 1)
+
+/* Information we keep for the standard substitutions.  */
+
+struct d_standard_sub_info
+{
+	/* The code for this substitution.  */
+	char code;
+	/* The simple string it expands to.  */
+	const char *simple_expansion;
+	/* The length of the simple expansion.  */
+	int simple_len;
+	/* The results of a full, verbose, expansion.  This is used when
+	   qualifying a constructor/destructor, or when in verbose mode.  */
+	const char *full_expansion;
+	/* The length of the full expansion.  */
+	int full_len;
+	/* What to set the last_name field of d_info to; NULL if we should
+	   not set it.  This is only relevant when qualifying a
+	   constructor/destructor.  */
+	const char *set_last_name;
+	/* The length of set_last_name.  */
+	int set_last_name_len;
+};
+
+/* Accessors for subtrees of struct demangle_component.  */
+
+#define d_left(dc) ((dc)->u.s_binary.left)
+#define d_right(dc) ((dc)->u.s_binary.right)
+
+/* A list of templates.  This is used while printing.  */
+
+struct d_print_template
+{
+	/* Next template on the list.  */
+	struct d_print_template *next;
+	/* This template.  */
+	const struct demangle_component *template_decl;
+};
+
+/* A list of type modifiers.  This is used while printing.  */
+
+struct d_print_mod
+{
+	/* Next modifier on the list.  These are in the reverse of the order
+	   in which they appeared in the mangled string.  */
+	struct d_print_mod *next;
+	/* The modifier.  */
+	struct demangle_component *mod;
+	/* Whether this modifier was printed.  */
+	int printed;
+	/* The list of templates which applies to this modifier.  */
+	struct d_print_template *templates;
+};
+
+/* We use these structures to hold information during printing.  */
+
+struct d_growable_string
+{
+	/* Buffer holding the result.  */
+	char *buf;
+	/* Current length of data in buffer.  */
+	size_t len;
+	/* Allocated size of buffer.  */
+	size_t alc;
+	/* Set to 1 if we had a memory allocation failure.  */
+	int allocation_failure;
+};
+
+/* Stack of components, innermost first, used to avoid loops.  */
+
+struct d_component_stack
+{
+	/* This component.  */
+	const struct demangle_component *dc;
+	/* This component's parent.  */
+	const struct d_component_stack *parent;
+};
+
+/* A demangle component and some scope captured when it was first
+   traversed.  */
+
+struct d_saved_scope
+{
+	/* The component whose scope this is.  */
+	const struct demangle_component *container;
+	/* The list of templates, if any, that was current when this
+	   scope was captured.  */
+	struct d_print_template *templates;
+};
+
+/* Checkpoint structure to allow backtracking.  This holds copies
+   of the fields of struct d_info that need to be restored
+   if a trial parse needs to be backtracked over.  */
+
+struct d_info_checkpoint
+{
+	const char *n;
+	int next_comp;
+	int next_sub;
+	int expansion;
+};
+
+/* Maximum number of times d_print_comp may be called recursively.  */
+#define MAX_RECURSION_COUNT 1024
+
+enum
+{ D_PRINT_BUFFER_LENGTH =3D 256 };
+struct d_print_info
+{
+	/* Fixed-length allocated buffer for demangled data, flushed to the
+	   callback with a NUL termination once full.  */
+	char buf[D_PRINT_BUFFER_LENGTH];
+	/* Current length of data in buffer.  */
+	size_t len;
+	/* The last character printed, saved individually so that it survives
+	   any buffer flush.  */
+	char last_char;
+	/* Callback function to handle demangled buffer flush.  */
+	demangle_callbackref callback;
+	/* Opaque callback argument.  */
+	void *opaque;
+	/* The current list of templates, if any.  */
+	struct d_print_template *templates;
+	/* The current list of modifiers (e.g., pointer, reference, etc.),
+	   if any.  */
+	struct d_print_mod *modifiers;
+	/* Set to 1 if we saw a demangling error.  */
+	int demangle_failure;
+	/* Number of times d_print_comp was recursively called.  Should not
+	   be bigger than MAX_RECURSION_COUNT.  */
+	int recursion;
+	/* Non-zero if we're printing a lambda argument.  A template
+	   parameter reference actually means 'auto'.  */
+	int is_lambda_arg;
+	/* The current index into any template argument packs we are using
+	   for printing, or -1 to print the whole pack.  */
+	int pack_index;
+	/* Number of d_print_flush calls so far.  */
+	unsigned long int flush_count;
+	/* Stack of components, innermost first, used to avoid loops.  */
+	const struct d_component_stack *component_stack;
+	/* Array of saved scopes for evaluating substitutions.  */
+	struct d_saved_scope *saved_scopes;
+	/* Index of the next unused saved scope in the above array.  */
+	int next_saved_scope;
+	/* Number of saved scopes in the above array.  */
+	int num_saved_scopes;
+	/* Array of templates for saving into scopes.  */
+	struct d_print_template *copy_templates;
+	/* Index of the next unused copy template in the above array.  */
+	int next_copy_template;
+	/* Number of copy templates in the above array.  */
+	int num_copy_templates;
+	/* The nearest enclosing template, if any.  */
+	const struct demangle_component *current_template;
+};
+
+#ifdef CP_DEMANGLE_DEBUG
+static void d_dump(struct demangle_component *, int);
+#endif
+
+static struct demangle_component *d_make_empty(struct d_info *);
+
+static struct demangle_component *d_make_comp(struct d_info *, enum demang=
le_component_type,
+											  struct demangle_component *, struct demangle_component *);
+
+static struct demangle_component *d_make_name(struct d_info *, const char =
*, int);
+
+static struct demangle_component *d_make_demangle_mangled_name(struct d_in=
fo *, const char *);
+
+static struct demangle_component *d_make_builtin_type(struct d_info *, con=
st struct demangle_builtin_type_info *);
+
+static struct demangle_component *d_make_operator(struct d_info *, const s=
truct demangle_operator_info *);
+
+static struct demangle_component *d_make_extended_operator(struct d_info *=
, int, struct demangle_component *);
+
+static struct demangle_component *d_make_ctor(struct d_info *, enum gnu_v3=
_ctor_kinds, struct demangle_component *);
+
+static struct demangle_component *d_make_dtor(struct d_info *, enum gnu_v3=
_dtor_kinds, struct demangle_component *);
+
+static struct demangle_component *d_make_template_param(struct d_info *, i=
nt);
+
+static struct demangle_component *d_make_sub(struct d_info *, const char *=
, int);
+
+static int has_return_type(struct demangle_component *);
+
+static int is_ctor_dtor_or_conversion(struct demangle_component *);
+
+static struct demangle_component *d_encoding(struct d_info *, int);
+
+static struct demangle_component *d_name(struct d_info *, int substable);
+
+static struct demangle_component *d_nested_name(struct d_info *);
+
+static int d_maybe_module_name(struct d_info *, struct demangle_component =
**);
+
+static struct demangle_component *d_prefix(struct d_info *, int);
+
+static struct demangle_component *d_unqualified_name(struct d_info *,
+													 struct demangle_component *scope,
+													 struct demangle_component *module);
+
+static struct demangle_component *d_source_name(struct d_info *);
+
+static int d_number(struct d_info *);
+
+static struct demangle_component *d_identifier(struct d_info *, int);
+
+static struct demangle_component *d_operator_name(struct d_info *);
+
+static struct demangle_component *d_special_name(struct d_info *);
+
+static struct demangle_component *d_parmlist(struct d_info *);
+
+static int d_call_offset(struct d_info *, int);
+
+static struct demangle_component *d_ctor_dtor_name(struct d_info *);
+
+static struct demangle_component **d_cv_qualifiers(struct d_info *, struct=
 demangle_component **, int);
+
+static struct demangle_component *d_ref_qualifier(struct d_info *, struct =
demangle_component *);
+
+static struct demangle_component *d_function_type(struct d_info *);
+
+static struct demangle_component *d_bare_function_type(struct d_info *, in=
t);
+
+static struct demangle_component *d_class_enum_type(struct d_info *, int);
+
+static struct demangle_component *d_array_type(struct d_info *);
+
+static struct demangle_component *d_vector_type(struct d_info *);
+
+static struct demangle_component *d_pointer_to_member_type(struct d_info *=
);
+
+static struct demangle_component *d_template_param(struct d_info *);
+
+static struct demangle_component *d_template_args(struct d_info *);
+static struct demangle_component *d_template_args_1(struct d_info *);
+
+static struct demangle_component *d_template_arg(struct d_info *);
+
+static struct demangle_component *d_expression(struct d_info *);
+
+static struct demangle_component *d_expr_primary(struct d_info *);
+
+static struct demangle_component *d_local_name(struct d_info *);
+
+static int d_discriminator(struct d_info *);
+
+static struct demangle_component *d_lambda(struct d_info *);
+
+static struct demangle_component *d_unnamed_type(struct d_info *);
+
+static struct demangle_component *d_clone_suffix(struct d_info *, struct d=
emangle_component *);
+
+static int d_add_substitution(struct d_info *, struct demangle_component *=
);
+
+static struct demangle_component *d_substitution(struct d_info *, int);
+
+static void d_checkpoint(struct d_info *, struct d_info_checkpoint *);
+
+static void d_backtrack(struct d_info *, struct d_info_checkpoint *);
+
+static void d_growable_string_init(struct d_growable_string *, size_t);
+
+static inline void d_growable_string_resize(struct d_growable_string *, si=
ze_t);
+
+static inline void d_growable_string_append_buffer(struct d_growable_strin=
g *, const char *, size_t);
+static void d_growable_string_callback_adapter(const char *, size_t, void =
*);
+
+static void d_print_init(struct d_print_info *, demangle_callbackref, void=
 *, struct demangle_component *);
+
+static inline void d_print_error(struct d_print_info *);
+
+static inline int d_print_saw_error(struct d_print_info *);
+
+static inline void d_print_flush(struct d_print_info *);
+
+static inline void d_append_char(struct d_print_info *, char);
+
+static inline void d_append_buffer(struct d_print_info *, const char *, si=
ze_t);
+
+static inline void d_append_string(struct d_print_info *, const char *);
+
+static inline char d_last_char(struct d_print_info *);
+
+static void d_print_comp(struct d_print_info *, int, struct demangle_compo=
nent *);
+
+static void d_print_java_identifier(struct d_print_info *, const char *, i=
nt);
+
+static void d_print_mod_list(struct d_print_info *, int, struct d_print_mo=
d *, int);
+
+static void d_print_mod(struct d_print_info *, int, struct demangle_compon=
ent *);
+
+static void d_print_function_type(struct d_print_info *, int, struct deman=
gle_component *, struct d_print_mod *);
+
+static void d_print_array_type(struct d_print_info *, int, struct demangle=
_component *, struct d_print_mod *);
+
+static void d_print_expr_op(struct d_print_info *, int, struct demangle_co=
mponent *);
+
+static void d_print_cast(struct d_print_info *, int, struct demangle_compo=
nent *);
+static void d_print_conversion(struct d_print_info *, int, struct demangle=
_component *);
+
+static int d_demangle_callback(const char *, int, demangle_callbackref, vo=
id *);
+static char *d_demangle(const char *, int, size_t *);
+
+#define FNQUAL_COMPONENT_CASE				\
+    case DEMANGLE_COMPONENT_RESTRICT_THIS:		\
+    case DEMANGLE_COMPONENT_VOLATILE_THIS:		\
+    case DEMANGLE_COMPONENT_CONST_THIS:			\
+    case DEMANGLE_COMPONENT_REFERENCE_THIS:		\
+    case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:	\
+    case DEMANGLE_COMPONENT_TRANSACTION_SAFE:		\
+    case DEMANGLE_COMPONENT_NOEXCEPT:			\
+    case DEMANGLE_COMPONENT_THROW_SPEC
+
+/* True iff TYPE is a demangling component representing a
+   function-type-qualifier.  */
+
+static int is_fnqual_component_type(enum demangle_component_type type)
+{
+	switch (type)
+	{
+	  FNQUAL_COMPONENT_CASE:
+		return 1;
+	default:
+		break;
+	}
+	return 0;
+}
+
+
+#ifdef CP_DEMANGLE_DEBUG
+
+static void d_dump(struct demangle_component *dc, int indent)
+{
+	int i;
+
+	if (dc =3D=3D NULL)
+	{
+		if (indent =3D=3D 0)
+			printf("failed demangling\n");
+		return;
+	}
+
+	for (i =3D 0; i < indent; ++i)
+		putchar(' ');
+
+	switch (dc->type)
+	{
+	case DEMANGLE_COMPONENT_NAME:
+		printf("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
+		return;
+	case DEMANGLE_COMPONENT_TAGGED_NAME:
+		printf("tagged name\n");
+		d_dump(dc->u.s_binary.left, indent + 2);
+		d_dump(dc->u.s_binary.right, indent + 2);
+		return;
+	case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+		printf("template parameter %ld\n", dc->u.s_number.number);
+		return;
+	case DEMANGLE_COMPONENT_TPARM_OBJ:
+		printf("template parameter object\n");
+		break;
+	case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+		printf("function parameter %ld\n", dc->u.s_number.number);
+		return;
+	case DEMANGLE_COMPONENT_CTOR:
+		printf("constructor %d\n", (int) dc->u.s_ctor.kind);
+		d_dump(dc->u.s_ctor.name, indent + 2);
+		return;
+	case DEMANGLE_COMPONENT_DTOR:
+		printf("destructor %d\n", (int) dc->u.s_dtor.kind);
+		d_dump(dc->u.s_dtor.name, indent + 2);
+		return;
+	case DEMANGLE_COMPONENT_SUB_STD:
+		printf("standard substitution %s\n", dc->u.s_string.string);
+		return;
+	case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+		printf("builtin type %s\n", dc->u.s_builtin.type->name);
+		return;
+	case DEMANGLE_COMPONENT_OPERATOR:
+		printf("operator %s\n", dc->u.s_operator.op->name);
+		return;
+	case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+		printf("extended operator with %d args\n", dc->u.s_extended_operator.arg=
s);
+		d_dump(dc->u.s_extended_operator.name, indent + 2);
+		return;
+
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+		printf("qualified name\n");
+		break;
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+		printf("local name\n");
+		break;
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+		printf("typed name\n");
+		break;
+	case DEMANGLE_COMPONENT_TEMPLATE:
+		printf("template\n");
+		break;
+	case DEMANGLE_COMPONENT_VTABLE:
+		printf("vtable\n");
+		break;
+	case DEMANGLE_COMPONENT_VTT:
+		printf("VTT\n");
+		break;
+	case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+		printf("construction vtable\n");
+		break;
+	case DEMANGLE_COMPONENT_TYPEINFO:
+		printf("typeinfo\n");
+		break;
+	case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+		printf("typeinfo name\n");
+		break;
+	case DEMANGLE_COMPONENT_TYPEINFO_FN:
+		printf("typeinfo function\n");
+		break;
+	case DEMANGLE_COMPONENT_THUNK:
+		printf("thunk\n");
+		break;
+	case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+		printf("virtual thunk\n");
+		break;
+	case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+		printf("covariant thunk\n");
+		break;
+	case DEMANGLE_COMPONENT_JAVA_CLASS:
+		printf("java class\n");
+		break;
+	case DEMANGLE_COMPONENT_GUARD:
+		printf("guard\n");
+		break;
+	case DEMANGLE_COMPONENT_REFTEMP:
+		printf("reference temporary\n");
+		break;
+	case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+		printf("hidden alias\n");
+		break;
+	case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+		printf("transaction clone\n");
+		break;
+	case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+		printf("non-transaction clone\n");
+		break;
+	case DEMANGLE_COMPONENT_RESTRICT:
+		printf("restrict\n");
+		break;
+	case DEMANGLE_COMPONENT_VOLATILE:
+		printf("volatile\n");
+		break;
+	case DEMANGLE_COMPONENT_CONST:
+		printf("const\n");
+		break;
+	case DEMANGLE_COMPONENT_RESTRICT_THIS:
+		printf("restrict this\n");
+		break;
+	case DEMANGLE_COMPONENT_VOLATILE_THIS:
+		printf("volatile this\n");
+		break;
+	case DEMANGLE_COMPONENT_CONST_THIS:
+		printf("const this\n");
+		break;
+	case DEMANGLE_COMPONENT_REFERENCE_THIS:
+		printf("reference this\n");
+		break;
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+		printf("rvalue reference this\n");
+		break;
+	case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+		printf("transaction_safe this\n");
+		break;
+	case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+		printf("vendor type qualifier\n");
+		break;
+	case DEMANGLE_COMPONENT_POINTER:
+		printf("pointer\n");
+		break;
+	case DEMANGLE_COMPONENT_REFERENCE:
+		printf("reference\n");
+		break;
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+		printf("rvalue reference\n");
+		break;
+	case DEMANGLE_COMPONENT_COMPLEX:
+		printf("complex\n");
+		break;
+	case DEMANGLE_COMPONENT_IMAGINARY:
+		printf("imaginary\n");
+		break;
+	case DEMANGLE_COMPONENT_VENDOR_TYPE:
+		printf("vendor type\n");
+		break;
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+		printf("function type\n");
+		break;
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+		printf("array type\n");
+		break;
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+		printf("pointer to member type\n");
+		break;
+	case DEMANGLE_COMPONENT_FIXED_TYPE:
+		printf("fixed-point type, accum? %d, sat? %d\n", dc->u.s_fixed.accum, dc=
=2D>u.s_fixed.sat);
+		d_dump(dc->u.s_fixed.length, indent + 2);
+		break;
+	case DEMANGLE_COMPONENT_ARGLIST:
+		printf("argument list\n");
+		break;
+	case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+		printf("template argument list\n");
+		break;
+	case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+		printf("initializer list\n");
+		break;
+	case DEMANGLE_COMPONENT_CAST:
+		printf("cast\n");
+		break;
+	case DEMANGLE_COMPONENT_CONVERSION:
+		printf("conversion operator\n");
+		break;
+	case DEMANGLE_COMPONENT_NULLARY:
+		printf("nullary operator\n");
+		break;
+	case DEMANGLE_COMPONENT_UNARY:
+		printf("unary operator\n");
+		break;
+	case DEMANGLE_COMPONENT_BINARY:
+		printf("binary operator\n");
+		break;
+	case DEMANGLE_COMPONENT_BINARY_ARGS:
+		printf("binary operator arguments\n");
+		break;
+	case DEMANGLE_COMPONENT_TRINARY:
+		printf("trinary operator\n");
+		break;
+	case DEMANGLE_COMPONENT_TRINARY_ARG1:
+		printf("trinary operator arguments 1\n");
+		break;
+	case DEMANGLE_COMPONENT_TRINARY_ARG2:
+		printf("trinary operator arguments 1\n");
+		break;
+	case DEMANGLE_COMPONENT_LITERAL:
+		printf("literal\n");
+		break;
+	case DEMANGLE_COMPONENT_LITERAL_NEG:
+		printf("negative literal\n");
+		break;
+	case DEMANGLE_COMPONENT_VENDOR_EXPR:
+		printf("vendor expression\n");
+		break;
+	case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+		printf("java resource\n");
+		break;
+	case DEMANGLE_COMPONENT_COMPOUND_NAME:
+		printf("compound name\n");
+		break;
+	case DEMANGLE_COMPONENT_CHARACTER:
+		printf("character '%c'\n", dc->u.s_character.character);
+		return;
+	case DEMANGLE_COMPONENT_NUMBER:
+		printf("number %ld\n", dc->u.s_number.number);
+		return;
+	case DEMANGLE_COMPONENT_DECLTYPE:
+		printf("decltype\n");
+		break;
+	case DEMANGLE_COMPONENT_PACK_EXPANSION:
+		printf("pack expansion\n");
+		break;
+	case DEMANGLE_COMPONENT_TLS_INIT:
+		printf("tls init function\n");
+		break;
+	case DEMANGLE_COMPONENT_TLS_WRAPPER:
+		printf("tls wrapper function\n");
+		break;
+	case DEMANGLE_COMPONENT_DEFAULT_ARG:
+		printf("default argument %d\n", dc->u.s_unary_num.num);
+		d_dump(dc->u.s_unary_num.sub, indent + 2);
+		return;
+	case DEMANGLE_COMPONENT_LAMBDA:
+		printf("lambda %d\n", dc->u.s_unary_num.num);
+		d_dump(dc->u.s_unary_num.sub, indent + 2);
+		return;
+	}
+
+	d_dump(d_left(dc), indent + 2);
+	d_dump(d_right(dc), indent + 2);
+}
+
+#endif /* CP_DEMANGLE_DEBUG */
+
+/* Fill in a DEMANGLE_COMPONENT_NAME.  */
+
+CP_STATIC_IF_GLIBCPP_V3 int cplus_demangle_fill_name(struct demangle_compo=
nent *p, const char *s, int len)
+{
+	if (p =3D=3D NULL || s =3D=3D NULL || len <=3D 0)
+		return 0;
+	p->d_printing =3D 0;
+	p->d_counting =3D 0;
+	p->type =3D DEMANGLE_COMPONENT_NAME;
+	p->u.s_name.s =3D s;
+	p->u.s_name.len =3D len;
+	return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR.  */
+
+CP_STATIC_IF_GLIBCPP_V3	int cplus_demangle_fill_extended_operator(struct d=
emangle_component *p, int args, struct demangle_component *name)
+{
+	if (p =3D=3D NULL || args < 0 || name =3D=3D NULL)
+		return 0;
+	p->d_printing =3D 0;
+	p->d_counting =3D 0;
+	p->type =3D DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
+	p->u.s_extended_operator.args =3D args;
+	p->u.s_extended_operator.name =3D name;
+	return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR.  */
+
+CP_STATIC_IF_GLIBCPP_V3	int cplus_demangle_fill_ctor(struct demangle_compo=
nent *p, enum gnu_v3_ctor_kinds kind, struct demangle_component *name)
+{
+	if (p =3D=3D NULL || name =3D=3D NULL || (int) kind < gnu_v3_complete_obj=
ect_ctor || (int) kind > gnu_v3_object_ctor_group)
+		return 0;
+	p->d_printing =3D 0;
+	p->d_counting =3D 0;
+	p->type =3D DEMANGLE_COMPONENT_CTOR;
+	p->u.s_ctor.kind =3D kind;
+	p->u.s_ctor.name =3D name;
+	return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR.  */
+
+CP_STATIC_IF_GLIBCPP_V3 int cplus_demangle_fill_dtor(struct demangle_compo=
nent *p, enum gnu_v3_dtor_kinds kind, struct demangle_component *name)
+{
+	if (p =3D=3D NULL || name =3D=3D NULL || (int) kind < gnu_v3_deleting_dto=
r || (int) kind > gnu_v3_object_dtor_group)
+		return 0;
+	p->d_printing =3D 0;
+	p->d_counting =3D 0;
+	p->type =3D DEMANGLE_COMPONENT_DTOR;
+	p->u.s_dtor.kind =3D kind;
+	p->u.s_dtor.name =3D name;
+	return 1;
+}
+
+/* Add a new component.  */
+
+static struct demangle_component *d_make_empty(struct d_info *di)
+{
+	struct demangle_component *p;
+
+	if (di->next_comp >=3D di->num_comps)
+		return NULL;
+	p =3D &di->comps[di->next_comp];
+	p->d_printing =3D 0;
+	p->d_counting =3D 0;
+	++di->next_comp;
+	return p;
+}
+
+/* Add a new generic component.  */
+
+static struct demangle_component *d_make_comp(struct d_info *di, enum dema=
ngle_component_type type,
+											  struct demangle_component *left, struct demangle_component *r=
ight)
+{
+	struct demangle_component *p;
+
+	/* We check for errors here.  A typical error would be a NULL return
+	   from a subroutine.  We catch those here, and return NULL
+	   upward.  */
+	switch (type)
+	{
+		/* These types require two parameters.  */
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+	case DEMANGLE_COMPONENT_TAGGED_NAME:
+	case DEMANGLE_COMPONENT_TEMPLATE:
+	case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+	case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+	case DEMANGLE_COMPONENT_UNARY:
+	case DEMANGLE_COMPONENT_BINARY:
+	case DEMANGLE_COMPONENT_BINARY_ARGS:
+	case DEMANGLE_COMPONENT_TRINARY:
+	case DEMANGLE_COMPONENT_TRINARY_ARG1:
+	case DEMANGLE_COMPONENT_LITERAL:
+	case DEMANGLE_COMPONENT_LITERAL_NEG:
+	case DEMANGLE_COMPONENT_VENDOR_EXPR:
+	case DEMANGLE_COMPONENT_COMPOUND_NAME:
+	case DEMANGLE_COMPONENT_VECTOR_TYPE:
+	case DEMANGLE_COMPONENT_CLONE:
+	case DEMANGLE_COMPONENT_MODULE_ENTITY:
+		if (left =3D=3D NULL || right =3D=3D NULL)
+			return NULL;
+		break;
+
+		/* These types only require one parameter.  */
+	case DEMANGLE_COMPONENT_VTABLE:
+	case DEMANGLE_COMPONENT_VTT:
+	case DEMANGLE_COMPONENT_TYPEINFO:
+	case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+	case DEMANGLE_COMPONENT_TYPEINFO_FN:
+	case DEMANGLE_COMPONENT_THUNK:
+	case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+	case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+	case DEMANGLE_COMPONENT_JAVA_CLASS:
+	case DEMANGLE_COMPONENT_GUARD:
+	case DEMANGLE_COMPONENT_TLS_INIT:
+	case DEMANGLE_COMPONENT_TLS_WRAPPER:
+	case DEMANGLE_COMPONENT_REFTEMP:
+	case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+	case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+	case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+	case DEMANGLE_COMPONENT_POINTER:
+	case DEMANGLE_COMPONENT_REFERENCE:
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+	case DEMANGLE_COMPONENT_COMPLEX:
+	case DEMANGLE_COMPONENT_IMAGINARY:
+	case DEMANGLE_COMPONENT_VENDOR_TYPE:
+	case DEMANGLE_COMPONENT_CAST:
+	case DEMANGLE_COMPONENT_CONVERSION:
+	case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+	case DEMANGLE_COMPONENT_DECLTYPE:
+	case DEMANGLE_COMPONENT_PACK_EXPANSION:
+	case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+	case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+	case DEMANGLE_COMPONENT_NULLARY:
+	case DEMANGLE_COMPONENT_TRINARY_ARG2:
+	case DEMANGLE_COMPONENT_TPARM_OBJ:
+	case DEMANGLE_COMPONENT_STRUCTURED_BINDING:
+	case DEMANGLE_COMPONENT_MODULE_INIT:
+		if (left =3D=3D NULL)
+			return NULL;
+		break;
+
+		/* This needs a right parameter, but the left parameter can be
+		   empty.  */
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+	case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+	case DEMANGLE_COMPONENT_MODULE_NAME:
+	case DEMANGLE_COMPONENT_MODULE_PARTITION:
+		if (right =3D=3D NULL)
+			return NULL;
+		break;
+
+		/* These are allowed to have no parameters--in some cases they
+		   will be filled in later.  */
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+	case DEMANGLE_COMPONENT_RESTRICT:
+	case DEMANGLE_COMPONENT_VOLATILE:
+	case DEMANGLE_COMPONENT_CONST:
+	case DEMANGLE_COMPONENT_ARGLIST:
+	case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+	  FNQUAL_COMPONENT_CASE:
+		break;
+
+		/* Other types should not be seen here.  */
+	default:
+		return NULL;
+	}
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D type;
+		p->u.s_binary.left =3D left;
+		p->u.s_binary.right =3D right;
+	}
+	return p;
+}
+
+/* Add a new demangle mangled name component.  */
+
+static struct demangle_component *d_make_demangle_mangled_name(struct d_in=
fo *di, const char *s)
+{
+	if (d_peek_char(di) !=3D '_' || d_peek_next_char(di) !=3D 'Z')
+		return d_make_name(di, s, strlen(s));
+	d_advance(di, 2);
+	return d_encoding(di, 0);
+}
+
+/* Add a new name component.  */
+
+static struct demangle_component *d_make_name(struct d_info *di, const cha=
r *s, int len)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (!cplus_demangle_fill_name(p, s, len))
+		return NULL;
+	return p;
+}
+
+/* Add a new builtin type component.  */
+
+static struct demangle_component *d_make_builtin_type(struct d_info *di, c=
onst struct demangle_builtin_type_info *type)
+{
+	struct demangle_component *p;
+
+	if (type =3D=3D NULL)
+		return NULL;
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_BUILTIN_TYPE;
+		p->u.s_builtin.type =3D type;
+	}
+	return p;
+}
+
+/* Add a new operator component.  */
+
+static struct demangle_component *d_make_operator(struct d_info *di, const=
 struct demangle_operator_info *op)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_OPERATOR;
+		p->u.s_operator.op =3D op;
+	}
+	return p;
+}
+
+/* Add a new extended operator component.  */
+
+static struct demangle_component *d_make_extended_operator(struct d_info *=
di, int args, struct demangle_component *name)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (!cplus_demangle_fill_extended_operator(p, args, name))
+		return NULL;
+	return p;
+}
+
+static struct demangle_component *d_make_default_arg(struct d_info *di, in=
t num, struct demangle_component *sub)
+{
+	struct demangle_component *p =3D d_make_empty(di);
+
+	if (p)
+	{
+		p->type =3D DEMANGLE_COMPONENT_DEFAULT_ARG;
+		p->u.s_unary_num.num =3D num;
+		p->u.s_unary_num.sub =3D sub;
+	}
+	return p;
+}
+
+/* Add a new constructor component.  */
+
+static struct demangle_component *d_make_ctor(struct d_info *di, enum gnu_=
v3_ctor_kinds kind,
+											  struct demangle_component *name)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (!cplus_demangle_fill_ctor(p, kind, name))
+		return NULL;
+	return p;
+}
+
+/* Add a new destructor component.  */
+
+static struct demangle_component *d_make_dtor(struct d_info *di, enum gnu_=
v3_dtor_kinds kind,
+											  struct demangle_component *name)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (!cplus_demangle_fill_dtor(p, kind, name))
+		return NULL;
+	return p;
+}
+
+/* Add a new template parameter.  */
+
+static struct demangle_component *d_make_template_param(struct d_info *di,=
 int i)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_TEMPLATE_PARAM;
+		p->u.s_number.number =3D i;
+	}
+	return p;
+}
+
+/* Add a new function parameter.  */
+
+static struct demangle_component *d_make_function_param(struct d_info *di,=
 int i)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_FUNCTION_PARAM;
+		p->u.s_number.number =3D i;
+	}
+	return p;
+}
+
+/* Add a new standard substitution component.  */
+
+static struct demangle_component *d_make_sub(struct d_info *di, const char=
 *name, int len)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_SUB_STD;
+		p->u.s_string.string =3D name;
+		p->u.s_string.len =3D len;
+	}
+	return p;
+}
+
+/* <mangled-name> ::=3D _Z <encoding> [<clone-suffix>]*
+
+   TOP_LEVEL is non-zero when called at the top level.  */
+
+CP_STATIC_IF_GLIBCPP_V3 struct demangle_component *cplus_demangle_mangled_=
name(struct d_info *di, int top_level)
+{
+	struct demangle_component *p;
+
+	if (!d_check_char(di, '_')
+		/* Allow missing _ if not at toplevel to work around a
+		   bug in G++ abi-version=3D2 mangling; see the comment in
+		   write_template_arg.  */
+		&& top_level)
+		return NULL;
+	if (!d_check_char(di, 'Z'))
+		return NULL;
+	p =3D d_encoding(di, top_level);
+
+	/* If at top level and parsing parameters, check for a clone
+	   suffix.  */
+	if (top_level && (di->options & DMGL_PARAMS) !=3D 0)
+		while (d_peek_char(di) =3D=3D '.'
+			   && (IS_LOWER(d_peek_next_char(di)) || d_peek_next_char(di) =3D=3D '_=
' || IS_DIGIT(d_peek_next_char(di))))
+			p =3D d_clone_suffix(di, p);
+
+	return p;
+}
+
+/* Return whether a function should have a return type.  The argument
+   is the function name, which may be qualified in various ways.  The
+   rules are that template functions have return types with some
+   exceptions, function types which are not part of a function name
+   mangling have return types with some exceptions, and non-template
+   function names do not have return types.  The exceptions are that
+   constructors, destructors, and conversion operators do not have
+   return types.  */
+
+static int has_return_type(struct demangle_component *dc)
+{
+	if (dc =3D=3D NULL)
+		return 0;
+	switch (dc->type)
+	{
+	default:
+		return 0;
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+		return has_return_type(d_right(dc));
+	case DEMANGLE_COMPONENT_TEMPLATE:
+		return !is_ctor_dtor_or_conversion(d_left(dc));
+	  FNQUAL_COMPONENT_CASE:
+		return has_return_type(d_left(dc));
+	}
+}
+
+/* Return whether a name is a constructor, a destructor, or a
+   conversion operator.  */
+
+static int is_ctor_dtor_or_conversion(struct demangle_component *dc)
+{
+	if (dc =3D=3D NULL)
+		return 0;
+	switch (dc->type)
+	{
+	default:
+		return 0;
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+		return is_ctor_dtor_or_conversion(d_right(dc));
+	case DEMANGLE_COMPONENT_CTOR:
+	case DEMANGLE_COMPONENT_DTOR:
+	case DEMANGLE_COMPONENT_CONVERSION:
+		return 1;
+	}
+}
+
+/* <encoding> ::=3D <(function) name> <bare-function-type>
+              ::=3D <(data) name>
+              ::=3D <special-name>
+
+   TOP_LEVEL is non-zero when called at the top level, in which case
+   if DMGL_PARAMS is not set we do not demangle the function
+   parameters.  We only set this at the top level, because otherwise
+   we would not correctly demangle names in local scopes.  */
+
+static struct demangle_component *d_encoding(struct d_info *di, int top_le=
vel)
+{
+	char peek =3D d_peek_char(di);
+	struct demangle_component *dc;
+
+	if (peek =3D=3D 'G' || peek =3D=3D 'T')
+		dc =3D d_special_name(di);
+	else
+	{
+		dc =3D d_name(di, 0);
+
+		if (!dc)
+			/* Failed already.  */ ;
+		else if (top_level && (di->options & DMGL_PARAMS) =3D=3D 0)
+		{
+			/* Strip off any initial CV-qualifiers, as they really apply
+			   to the `this' parameter, and they were not output by the
+			   v2 demangler without DMGL_PARAMS.  */
+			while (is_fnqual_component_type(dc->type))
+				dc =3D d_left(dc);
+
+			/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+			   there may be function-qualifiers on its right argument which
+			   really apply here; this happens when parsing a class
+			   which is local to a function.  */
+			if (dc->type =3D=3D DEMANGLE_COMPONENT_LOCAL_NAME)
+			{
+				while (d_right(dc) !=3D NULL && is_fnqual_component_type(d_right(dc)->=
type))
+					d_right(dc) =3D d_left(d_right(dc));
+
+				if (d_right(dc) =3D=3D NULL)
+					dc =3D NULL;
+			}
+		} else
+		{
+			peek =3D d_peek_char(di);
+			if (peek !=3D '\0' && peek !=3D 'E')
+			{
+				struct demangle_component *ftype;
+
+				ftype =3D d_bare_function_type(di, has_return_type(dc));
+				if (ftype)
+				{
+					/* If this is a non-top-level local-name, clear the
+					   return type, so it doesn't confuse the user by
+					   being confused with the return type of whaever
+					   this is nested within.  */
+					if (!top_level && dc->type =3D=3D DEMANGLE_COMPONENT_LOCAL_NAME
+						&& ftype->type =3D=3D DEMANGLE_COMPONENT_FUNCTION_TYPE)
+						d_left(ftype) =3D NULL;
+
+					dc =3D d_make_comp(di, DEMANGLE_COMPONENT_TYPED_NAME, dc, ftype);
+				} else
+					dc =3D NULL;
+			}
+		}
+	}
+
+	return dc;
+}
+
+/* <tagged-name> ::=3D <name> B <source-name> */
+
+static struct demangle_component *d_abi_tags(struct d_info *di, struct dem=
angle_component *dc)
+{
+	struct demangle_component *hold_last_name;
+	char peek;
+
+	/* Preserve the last name, so the ABI tag doesn't clobber it.  */
+	hold_last_name =3D di->last_name;
+
+	while (peek =3D d_peek_char(di), peek =3D=3D 'B')
+	{
+		struct demangle_component *tag;
+
+		d_advance(di, 1);
+		tag =3D d_source_name(di);
+		dc =3D d_make_comp(di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
+	}
+
+	di->last_name =3D hold_last_name;
+
+	return dc;
+}
+
+/* <name> ::=3D <nested-name>
+          ::=3D <unscoped-name>
+          ::=3D <unscoped-template-name> <template-args>
+          ::=3D <local-name>
+
+   <unscoped-name> ::=3D <unqualified-name>
+                   ::=3D St <unqualified-name>
+
+   <unscoped-template-name> ::=3D <unscoped-name>
+                            ::=3D <substitution>
+*/
+
+static struct demangle_component *d_name(struct d_info *di, int substable)
+{
+	char peek =3D d_peek_char(di);
+	struct demangle_component *dc =3D NULL;
+	struct demangle_component *module =3D NULL;
+	int subst =3D 0;
+
+	switch (peek)
+	{
+	case 'N':
+		dc =3D d_nested_name(di);
+		break;
+
+	case 'Z':
+		dc =3D d_local_name(di);
+		break;
+
+	case 'U':
+		dc =3D d_unqualified_name(di, NULL, NULL);
+		break;
+
+	case 'S':
+		{
+			if (d_peek_next_char(di) =3D=3D 't')
+			{
+				d_advance(di, 2);
+				dc =3D d_make_name(di, "std", 3);
+				di->expansion +=3D 3;
+			}
+
+			if (d_peek_char(di) =3D=3D 'S')
+			{
+				module =3D d_substitution(di, 0);
+				if (!module)
+					return NULL;
+				if (!(module->type =3D=3D DEMANGLE_COMPONENT_MODULE_NAME
+					  || module->type =3D=3D DEMANGLE_COMPONENT_MODULE_PARTITION))
+				{
+					if (dc)
+						return NULL;
+					subst =3D 1;
+					dc =3D module;
+					module =3D NULL;
+				}
+			}
+		}
+		/* FALLTHROUGH */
+
+	case 'L':
+	default:
+		if (!subst)
+			dc =3D d_unqualified_name(di, dc, module);
+		if (d_peek_char(di) =3D=3D 'I')
+		{
+			/* This is <template-args>, which means that we just saw
+			   <unscoped-template-name>, which is a substitution
+			   candidate.  */
+			if (!subst && !d_add_substitution(di, dc))
+				return NULL;
+			dc =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, dc, d_template_args=
(di));
+			subst =3D 0;
+		}
+		break;
+	}
+	if (substable && !subst && !d_add_substitution(di, dc))
+		return NULL;
+	return dc;
+}
+
+/* <nested-name> ::=3D N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unq=
ualified-name> E
+                 ::=3D N [<CV-qualifiers>] [<ref-qualifier>] <template-pre=
fix> <template-args> E
+*/
+
+static struct demangle_component *d_nested_name(struct d_info *di)
+{
+	struct demangle_component *ret;
+	struct demangle_component **pret;
+	struct demangle_component *rqual;
+
+	if (!d_check_char(di, 'N'))
+		return NULL;
+
+	pret =3D d_cv_qualifiers(di, &ret, 1);
+	if (pret =3D=3D NULL)
+		return NULL;
+
+	/* Parse the ref-qualifier now and then attach it
+	   once we have something to attach it to.  */
+	rqual =3D d_ref_qualifier(di, NULL);
+
+	*pret =3D d_prefix(di, 1);
+	if (*pret =3D=3D NULL)
+		return NULL;
+
+	if (rqual)
+	{
+		d_left(rqual) =3D ret;
+		ret =3D rqual;
+	}
+
+	if (!d_check_char(di, 'E'))
+		return NULL;
+
+	return ret;
+}
+
+/* <prefix> ::=3D <prefix> <unqualified-name>
+            ::=3D <template-prefix> <template-args>
+            ::=3D <template-param>
+            ::=3D <decltype>
+            ::=3D
+            ::=3D <substitution>
+
+   <template-prefix> ::=3D <prefix> <(template) unqualified-name>
+                     ::=3D <template-param>
+                     ::=3D <substitution>
+
+   SUBST is true if we should add substitutions (as normal), false
+   if not (in an unresolved-name).  */
+
+static struct demangle_component *d_prefix(struct d_info *di, int substabl=
e)
+{
+	struct demangle_component *ret =3D NULL;
+
+	for (;;)
+	{
+		char peek =3D d_peek_char(di);
+
+		/* The older code accepts a <local-name> here, but I don't see
+		   that in the grammar.  The older code does not accept a
+		   <template-param> here.  */
+
+		if (peek =3D=3D 'D' && (d_peek_next_char(di) =3D=3D 'T' || d_peek_next_c=
har(di) =3D=3D 't'))
+		{
+			/* Decltype.  */
+			if (ret)
+				return NULL;
+			ret =3D cplus_demangle_type(di);
+		} else if (peek =3D=3D 'I')
+		{
+			if (ret =3D=3D NULL)
+				return NULL;
+			struct demangle_component *dc =3D d_template_args(di);
+
+			if (!dc)
+				return NULL;
+			ret =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, ret, dc);
+		} else if (peek =3D=3D 'T')
+		{
+			if (ret)
+				return NULL;
+			ret =3D d_template_param(di);
+		} else if (peek =3D=3D 'M')
+		{
+			/* Initializer scope for a lambda.  We don't need to represent
+			   this; the normal code will just treat the variable as a type
+			   scope, which gives appropriate output.  */
+			if (ret =3D=3D NULL)
+				return NULL;
+			d_advance(di, 1);
+		} else
+		{
+			struct demangle_component *module =3D NULL;
+
+			if (peek =3D=3D 'S')
+			{
+				module =3D d_substitution(di, 1);
+				if (!module)
+					return NULL;
+				if (!(module->type =3D=3D DEMANGLE_COMPONENT_MODULE_NAME
+					  || module->type =3D=3D DEMANGLE_COMPONENT_MODULE_PARTITION))
+				{
+					if (ret)
+						return NULL;
+					ret =3D module;
+					continue;
+				}
+			}
+			ret =3D d_unqualified_name(di, ret, module);
+		}
+
+		if (!ret)
+			break;
+
+		if (d_peek_char(di) =3D=3D 'E')
+			break;
+
+		if (substable && !d_add_substitution(di, ret))
+			return NULL;
+	}
+
+	return ret;
+}
+
+static int d_maybe_module_name(struct d_info *di, struct demangle_componen=
t **name)
+{
+	while (d_peek_char(di) =3D=3D 'W')
+	{
+		d_advance(di, 1);
+		enum demangle_component_type code =3D DEMANGLE_COMPONENT_MODULE_NAME;
+
+		if (d_peek_char(di) =3D=3D 'P')
+		{
+			code =3D DEMANGLE_COMPONENT_MODULE_PARTITION;
+			d_advance(di, 1);
+		}
+
+		*name =3D d_make_comp(di, code, *name, d_source_name(di));
+		if (!*name)
+			return 0;
+		if (!d_add_substitution(di, *name))
+			return 0;
+	}
+	return 1;
+}
+
+/* <unqualified-name> ::=3D [<module-name>] <operator-name> [<abi-tags>]
+                      ::=3D [<module-name>] <ctor-dtor-name> [<abi-tags>]
+                      ::=3D [<module-name>] <source-name> [<abi-tags>]
+		      ::=3D [<module-name>] <local-source-name>  [<abi-tags>]
+                      ::=3D [<module-name>] DC <source-name>+ E [<abi-tags=
>]
+    <local-source-name>	::=3D L <source-name> <discriminator> [<abi-tags>]
+*/
+
+static struct demangle_component *d_unqualified_name(struct d_info *di, st=
ruct demangle_component *scope,
+													 struct demangle_component *module)
+{
+	struct demangle_component *ret;
+	char peek;
+
+	if (!d_maybe_module_name(di, &module))
+		return NULL;
+
+	peek =3D d_peek_char(di);
+	if (IS_DIGIT(peek))
+		ret =3D d_source_name(di);
+	else if (IS_LOWER(peek))
+	{
+		int was_expr =3D di->is_expression;
+
+		if (peek =3D=3D 'o' && d_peek_next_char(di) =3D=3D 'n')
+		{
+			d_advance(di, 2);
+			/* Treat cv as naming a conversion operator.  */
+			di->is_expression =3D 0;
+		}
+		ret =3D d_operator_name(di);
+		di->is_expression =3D was_expr;
+		if (ret !=3D NULL && ret->type =3D=3D DEMANGLE_COMPONENT_OPERATOR)
+		{
+			di->expansion +=3D sizeof "operator" + ret->u.s_operator.op->len - 2;
+			if (!strcmp(ret->u.s_operator.op->code, "li"))
+				ret =3D d_make_comp(di, DEMANGLE_COMPONENT_UNARY, ret, d_source_name(d=
i));
+		}
+	} else if (peek =3D=3D 'D' && d_peek_next_char(di) =3D=3D 'C')
+	{
+		// structured binding
+		d_advance(di, 2);
+		struct demangle_component *prev =3D NULL;
+
+		do
+		{
+			struct demangle_component *next =3D d_make_comp(di, DEMANGLE_COMPONENT_=
STRUCTURED_BINDING,
+														  d_source_name(di), NULL);
+
+			if (prev)
+				d_right(prev) =3D next;
+			else
+				ret =3D next;
+			prev =3D next;
+		}
+		while (prev && d_peek_char(di) !=3D 'E');
+		if (prev)
+			d_advance(di, 1);
+		else
+			ret =3D NULL;
+	} else if (peek =3D=3D 'C' || peek =3D=3D 'D')
+		ret =3D d_ctor_dtor_name(di);
+	else if (peek =3D=3D 'L')
+	{
+		d_advance(di, 1);
+
+		ret =3D d_source_name(di);
+		if (ret =3D=3D NULL)
+			return NULL;
+		if (!d_discriminator(di))
+			return NULL;
+	} else if (peek =3D=3D 'U')
+	{
+		switch (d_peek_next_char(di))
+		{
+		case 'l':
+			ret =3D d_lambda(di);
+			break;
+		case 't':
+			ret =3D d_unnamed_type(di);
+			break;
+		default:
+			return NULL;
+		}
+	} else
+		return NULL;
+
+	if (module)
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_MODULE_ENTITY, ret, module);
+	if (d_peek_char(di) =3D=3D 'B')
+		ret =3D d_abi_tags(di, ret);
+	if (scope)
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_QUAL_NAME, scope, ret);
+
+	return ret;
+}
+
+/* <source-name> ::=3D <(positive length) number> <identifier>  */
+
+static struct demangle_component *d_source_name(struct d_info *di)
+{
+	int len;
+	struct demangle_component *ret;
+
+	len =3D d_number(di);
+	if (len <=3D 0)
+		return NULL;
+	ret =3D d_identifier(di, len);
+	di->last_name =3D ret;
+	return ret;
+}
+
+/* number ::=3D [n] <(non-negative decimal integer)>  */
+
+static int d_number(struct d_info *di)
+{
+	int negative;
+	char peek;
+	int ret;
+
+	negative =3D 0;
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D 'n')
+	{
+		negative =3D 1;
+		d_advance(di, 1);
+		peek =3D d_peek_char(di);
+	}
+
+	ret =3D 0;
+	while (1)
+	{
+		if (!IS_DIGIT(peek))
+		{
+			if (negative)
+				ret =3D -ret;
+			return ret;
+		}
+		if (ret > ((INT_MAX - (peek - '0')) / 10))
+			return -1;
+		ret =3D ret * 10 + (peek - '0');
+		d_advance(di, 1);
+		peek =3D d_peek_char(di);
+	}
+}
+
+/* Like d_number, but returns a demangle_component.  */
+
+static struct demangle_component *d_number_component(struct d_info *di)
+{
+	struct demangle_component *ret =3D d_make_empty(di);
+
+	if (ret)
+	{
+		ret->type =3D DEMANGLE_COMPONENT_NUMBER;
+		ret->u.s_number.number =3D d_number(di);
+	}
+	return ret;
+}
+
+/* identifier ::=3D <(unqualified source code identifier)>  */
+
+static struct demangle_component *d_identifier(struct d_info *di, int len)
+{
+	const char *name;
+
+	name =3D d_str(di);
+
+	if (di->send - name < len)
+		return NULL;
+
+	d_advance(di, len);
+
+	/* A Java mangled name may have a trailing '$' if it is a C++
+	   keyword.  This '$' is not included in the length count.  We just
+	   ignore the '$'.  */
+	if ((di->options & DMGL_JAVA) !=3D 0 && d_peek_char(di) =3D=3D '$')
+		d_advance(di, 1);
+
+	/* Look for something which looks like a gcc encoding of an
+	   anonymous namespace, and replace it with a more user friendly
+	   name.  */
+	if (len >=3D (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
+		&& memcmp(name, ANONYMOUS_NAMESPACE_PREFIX, ANONYMOUS_NAMESPACE_PREFIX_L=
EN) =3D=3D 0)
+	{
+		const char *s;
+
+		s =3D name + ANONYMOUS_NAMESPACE_PREFIX_LEN;
+		if ((*s =3D=3D '.' || *s =3D=3D '_' || *s =3D=3D '$') && s[1] =3D=3D 'N')
+		{
+			di->expansion -=3D len - sizeof "(anonymous namespace)";
+			return d_make_name(di, "(anonymous namespace)", sizeof "(anonymous name=
space)" - 1);
+		}
+	}
+
+	return d_make_name(di, name, len);
+}
+
+/* operator_name ::=3D many different two character encodings.
+                 ::=3D cv <type>
+                 ::=3D v <digit> <source-name>
+
+   This list is sorted for binary search.  */
+
+#define NL(s) s, (sizeof s) - 1
+
+CP_STATIC_IF_GLIBCPP_V3 const struct demangle_operator_info cplus_demangle=
_operators[] =3D {
+	{"aN", NL("&=3D"), 2},
+	{"aS", NL("=3D"), 2},
+	{"aa", NL("&&"), 2},
+	{"ad", NL("&"), 1},
+	{"an", NL("&"), 2},
+	{"at", NL("alignof "), 1},
+	{"aw", NL("co_await "), 1},
+	{"az", NL("alignof "), 1},
+	{"cc", NL("const_cast"), 2},
+	{"cl", NL("()"), 2},
+	{"cm", NL(","), 2},
+	{"co", NL("~"), 1},
+	{"dV", NL("/=3D"), 2},
+	{"dX", NL("[...]=3D"), 3},			/* [expr...expr] =3D expr */
+	{"da", NL("delete[] "), 1},
+	{"dc", NL("dynamic_cast"), 2},
+	{"de", NL("*"), 1},
+	{"di", NL("=3D"), 2},					/* .name =3D expr */
+	{"dl", NL("delete "), 1},
+	{"ds", NL(".*"), 2},
+	{"dt", NL("."), 2},
+	{"dv", NL("/"), 2},
+	{"dx", NL("]=3D"), 2},				/* [expr] =3D expr */
+	{"eO", NL("^=3D"), 2},
+	{"eo", NL("^"), 2},
+	{"eq", NL("=3D=3D"), 2},
+	{"fL", NL("..."), 3},
+	{"fR", NL("..."), 3},
+	{"fl", NL("..."), 2},
+	{"fr", NL("..."), 2},
+	{"ge", NL(">=3D"), 2},
+	{"gs", NL("::"), 1},
+	{"gt", NL(">"), 2},
+	{"ix", NL("[]"), 2},
+	{"lS", NL("<<=3D"), 2},
+	{"le", NL("<=3D"), 2},
+	{"li", NL("operator\"\" "), 1},
+	{"ls", NL("<<"), 2},
+	{"lt", NL("<"), 2},
+	{"mI", NL("-=3D"), 2},
+	{"mL", NL("*=3D"), 2},
+	{"mi", NL("-"), 2},
+	{"ml", NL("*"), 2},
+	{"mm", NL("--"), 1},
+	{"na", NL("new[]"), 3},
+	{"ne", NL("!=3D"), 2},
+	{"ng", NL("-"), 1},
+	{"nt", NL("!"), 1},
+	{"nw", NL("new"), 3},
+	{"oR", NL("|=3D"), 2},
+	{"oo", NL("||"), 2},
+	{"or", NL("|"), 2},
+	{"pL", NL("+=3D"), 2},
+	{"pl", NL("+"), 2},
+	{"pm", NL("->*"), 2},
+	{"pp", NL("++"), 1},
+	{"ps", NL("+"), 1},
+	{"pt", NL("->"), 2},
+	{"qu", NL("?"), 3},
+	{"rM", NL("%=3D"), 2},
+	{"rS", NL(">>=3D"), 2},
+	{"rc", NL("reinterpret_cast"), 2},
+	{"rm", NL("%"), 2},
+	{"rs", NL(">>"), 2},
+	{"sP", NL("sizeof..."), 1},
+	{"sZ", NL("sizeof..."), 1},
+	{"sc", NL("static_cast"), 2},
+	{"ss", NL("<=3D>"), 2},
+	{"st", NL("sizeof "), 1},
+	{"sz", NL("sizeof "), 1},
+	{"tr", NL("throw"), 0},
+	{"tw", NL("throw "), 1},
+	{NULL, NULL, 0, 0}
+};
+
+static struct demangle_component *d_operator_name(struct d_info *di)
+{
+	char c1;
+	char c2;
+
+	c1 =3D d_next_char(di);
+	c2 =3D d_next_char(di);
+	if (c1 =3D=3D 'v' && IS_DIGIT(c2))
+		return d_make_extended_operator(di, c2 - '0', d_source_name(di));
+	else if (c1 =3D=3D 'c' && c2 =3D=3D 'v')
+	{
+		struct demangle_component *type;
+		int was_conversion =3D di->is_conversion;
+		struct demangle_component *res;
+
+		di->is_conversion =3D !di->is_expression;
+		type =3D cplus_demangle_type(di);
+		if (di->is_conversion)
+			res =3D d_make_comp(di, DEMANGLE_COMPONENT_CONVERSION, type, NULL);
+		else
+			res =3D d_make_comp(di, DEMANGLE_COMPONENT_CAST, type, NULL);
+		di->is_conversion =3D was_conversion;
+		return res;
+	} else
+	{
+		/* LOW is the inclusive lower bound.  */
+		int low =3D 0;
+
+		/* HIGH is the exclusive upper bound.  We subtract one to ignore
+		   the sentinel at the end of the array.  */
+		int high =3D ((sizeof(cplus_demangle_operators) / sizeof(cplus_demangle_=
operators[0])) - 1);
+
+		while (1)
+		{
+			int i;
+			const struct demangle_operator_info *p;
+
+			i =3D low + (high - low) / 2;
+			p =3D cplus_demangle_operators + i;
+
+			if (c1 =3D=3D p->code[0] && c2 =3D=3D p->code[1])
+				return d_make_operator(di, p);
+
+			if (c1 < p->code[0] || (c1 =3D=3D p->code[0] && c2 < p->code[1]))
+				high =3D i;
+			else
+				low =3D i + 1;
+			if (low =3D=3D high)
+				return NULL;
+		}
+	}
+}
+
+static struct demangle_component *d_make_character(struct d_info *di, int =
c)
+{
+	struct demangle_component *p;
+
+	p =3D d_make_empty(di);
+	if (p !=3D NULL)
+	{
+		p->type =3D DEMANGLE_COMPONENT_CHARACTER;
+		p->u.s_character.character =3D c;
+	}
+	return p;
+}
+
+static struct demangle_component *d_java_resource(struct d_info *di)
+{
+	struct demangle_component *p =3D NULL;
+	struct demangle_component *next =3D NULL;
+	int len,
+	 i;
+	char c;
+	const char *str;
+
+	len =3D d_number(di);
+	if (len <=3D 1)
+		return NULL;
+
+	/* Eat the leading '_'.  */
+	if (d_next_char(di) !=3D '_')
+		return NULL;
+	len--;
+
+	str =3D d_str(di);
+	i =3D 0;
+
+	while (len > 0)
+	{
+		c =3D str[i];
+		if (!c)
+			return NULL;
+
+		/* Each chunk is either a '$' escape...  */
+		if (c =3D=3D '$')
+		{
+			i++;
+			switch (str[i++])
+			{
+			case 'S':
+				c =3D '/';
+				break;
+			case '_':
+				c =3D '.';
+				break;
+			case '$':
+				c =3D '$';
+				break;
+			default:
+				return NULL;
+			}
+			next =3D d_make_character(di, c);
+			d_advance(di, i);
+			str =3D d_str(di);
+			len -=3D i;
+			i =3D 0;
+			if (next =3D=3D NULL)
+				return NULL;
+		}
+		/* ... or a sequence of characters.  */
+		else
+		{
+			while (i < len && str[i] && str[i] !=3D '$')
+				i++;
+
+			next =3D d_make_name(di, str, i);
+			d_advance(di, i);
+			str =3D d_str(di);
+			len -=3D i;
+			i =3D 0;
+			if (next =3D=3D NULL)
+				return NULL;
+		}
+
+		if (p =3D=3D NULL)
+			p =3D next;
+		else
+		{
+			p =3D d_make_comp(di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
+			if (p =3D=3D NULL)
+				return NULL;
+		}
+	}
+
+	p =3D d_make_comp(di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
+
+	return p;
+}
+
+/* <special-name> ::=3D TV <type>
+                  ::=3D TT <type>
+                  ::=3D TI <type>
+                  ::=3D TS <type>
+		  ::=3D TA <template-arg>
+                  ::=3D GV <(object) name>
+                  ::=3D T <call-offset> <(base) encoding>
+                  ::=3D Tc <call-offset> <call-offset> <(base) encoding>
+   Also g++ extensions:
+                  ::=3D TC <type> <(offset) number> _ <(base) type>
+                  ::=3D TF <type>
+                  ::=3D TJ <type>
+                  ::=3D GR <name>
+		  ::=3D GA <encoding>
+		  ::=3D Gr <resource name>
+		  ::=3D GTt <encoding>
+		  ::=3D GTn <encoding>
+*/
+
+static struct demangle_component *d_special_name(struct d_info *di)
+{
+	di->expansion +=3D 20;
+	if (d_check_char(di, 'T'))
+	{
+		switch (d_next_char(di))
+		{
+		case 'V':
+			di->expansion -=3D 5;
+			return d_make_comp(di, DEMANGLE_COMPONENT_VTABLE, cplus_demangle_type(d=
i), NULL);
+		case 'T':
+			di->expansion -=3D 10;
+			return d_make_comp(di, DEMANGLE_COMPONENT_VTT, cplus_demangle_type(di),=
 NULL);
+		case 'I':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TYPEINFO, cplus_demangle_type=
(di), NULL);
+		case 'S':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TYPEINFO_NAME, cplus_demangle=
_type(di), NULL);
+
+		case 'h':
+			if (!d_call_offset(di, 'h'))
+				return NULL;
+			return d_make_comp(di, DEMANGLE_COMPONENT_THUNK, d_encoding(di, 0), NUL=
L);
+
+		case 'v':
+			if (!d_call_offset(di, 'v'))
+				return NULL;
+			return d_make_comp(di, DEMANGLE_COMPONENT_VIRTUAL_THUNK, d_encoding(di,=
 0), NULL);
+
+		case 'c':
+			if (!d_call_offset(di, '\0'))
+				return NULL;
+			if (!d_call_offset(di, '\0'))
+				return NULL;
+			return d_make_comp(di, DEMANGLE_COMPONENT_COVARIANT_THUNK, d_encoding(d=
i, 0), NULL);
+
+		case 'C':
+			{
+				struct demangle_component *derived_type;
+				int offset;
+				struct demangle_component *base_type;
+
+				derived_type =3D cplus_demangle_type(di);
+				offset =3D d_number(di);
+				if (offset < 0)
+					return NULL;
+				if (!d_check_char(di, '_'))
+					return NULL;
+				base_type =3D cplus_demangle_type(di);
+				/* We don't display the offset.  FIXME: We should display
+				   it in verbose mode.  */
+				di->expansion +=3D 5;
+				return d_make_comp(di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, base_ty=
pe, derived_type);
+			}
+
+		case 'F':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TYPEINFO_FN, cplus_demangle_t=
ype(di), NULL);
+		case 'J':
+			return d_make_comp(di, DEMANGLE_COMPONENT_JAVA_CLASS, cplus_demangle_ty=
pe(di), NULL);
+
+		case 'H':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TLS_INIT, d_name(di, 0), NULL=
);
+
+		case 'W':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TLS_WRAPPER, d_name(di, 0), N=
ULL);
+
+		case 'A':
+			return d_make_comp(di, DEMANGLE_COMPONENT_TPARM_OBJ, d_template_arg(di)=
, NULL);
+
+		default:
+			return NULL;
+		}
+	} else if (d_check_char(di, 'G'))
+	{
+		switch (d_next_char(di))
+		{
+		case 'V':
+			return d_make_comp(di, DEMANGLE_COMPONENT_GUARD, d_name(di, 0), NULL);
+
+		case 'R':
+			{
+				struct demangle_component *name =3D d_name(di, 0);
+
+				return d_make_comp(di, DEMANGLE_COMPONENT_REFTEMP, name, d_number_comp=
onent(di));
+			}
+
+		case 'A':
+			return d_make_comp(di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, d_encoding(di, =
0), NULL);
+
+		case 'I':
+			{
+				struct demangle_component *module =3D NULL;
+
+				if (!d_maybe_module_name(di, &module) || !module)
+					return NULL;
+				return d_make_comp(di, DEMANGLE_COMPONENT_MODULE_INIT, module, NULL);
+			}
+		case 'T':
+			switch (d_next_char(di))
+			{
+			case 'n':
+				return d_make_comp(di, DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, d_enco=
ding(di, 0), NULL);
+			default:
+				/* ??? The proposal is that other letters (such as 'h') stand
+				   for different variants of transaction cloning, such as
+				   compiling directly for hardware transaction support.  But
+				   they still should all be transactional clones of some sort
+				   so go ahead and call them that.  */
+			case 't':
+				return d_make_comp(di, DEMANGLE_COMPONENT_TRANSACTION_CLONE, d_encodin=
g(di, 0), NULL);
+			}
+
+		case 'r':
+			return d_java_resource(di);
+
+		default:
+			return NULL;
+		}
+	} else
+		return NULL;
+}
+
+/* <call-offset> ::=3D h <nv-offset> _
+                 ::=3D v <v-offset> _
+
+   <nv-offset> ::=3D <(offset) number>
+
+   <v-offset> ::=3D <(offset) number> _ <(virtual offset) number>
+
+   The C parameter, if not '\0', is a character we just read which is
+   the start of the <call-offset>.
+
+   We don't display the offset information anywhere.  FIXME: We should
+   display it in verbose mode.  */
+
+static int d_call_offset(struct d_info *di, int c)
+{
+	if (c =3D=3D '\0')
+		c =3D d_next_char(di);
+
+	if (c =3D=3D 'h')
+		d_number(di);
+	else if (c =3D=3D 'v')
+	{
+		d_number(di);
+		if (!d_check_char(di, '_'))
+			return 0;
+		d_number(di);
+	} else
+		return 0;
+
+	if (!d_check_char(di, '_'))
+		return 0;
+
+	return 1;
+}
+
+/* <ctor-dtor-name> ::=3D C1
+                    ::=3D C2
+                    ::=3D C3
+                    ::=3D D0
+                    ::=3D D1
+                    ::=3D D2
+*/
+
+static struct demangle_component *d_ctor_dtor_name(struct d_info *di)
+{
+	if (di->last_name !=3D NULL)
+	{
+		if (di->last_name->type =3D=3D DEMANGLE_COMPONENT_NAME)
+			di->expansion +=3D di->last_name->u.s_name.len;
+		else if (di->last_name->type =3D=3D DEMANGLE_COMPONENT_SUB_STD)
+			di->expansion +=3D di->last_name->u.s_string.len;
+	}
+	switch (d_peek_char(di))
+	{
+	case 'C':
+		{
+			enum gnu_v3_ctor_kinds kind;
+			int inheriting =3D 0;
+
+			if (d_peek_next_char(di) =3D=3D 'I')
+			{
+				inheriting =3D 1;
+				d_advance(di, 1);
+			}
+
+			switch (d_peek_next_char(di))
+			{
+			case '1':
+				kind =3D gnu_v3_complete_object_ctor;
+				break;
+			case '2':
+				kind =3D gnu_v3_base_object_ctor;
+				break;
+			case '3':
+				kind =3D gnu_v3_complete_object_allocating_ctor;
+				break;
+			case '4':
+				kind =3D gnu_v3_unified_ctor;
+				break;
+			case '5':
+				kind =3D gnu_v3_object_ctor_group;
+				break;
+			default:
+				return NULL;
+			}
+
+			d_advance(di, 2);
+
+			if (inheriting)
+				cplus_demangle_type(di);
+
+			return d_make_ctor(di, kind, di->last_name);
+		}
+
+	case 'D':
+		{
+			enum gnu_v3_dtor_kinds kind;
+
+			switch (d_peek_next_char(di))
+			{
+			case '0':
+				kind =3D gnu_v3_deleting_dtor;
+				break;
+			case '1':
+				kind =3D gnu_v3_complete_object_dtor;
+				break;
+			case '2':
+				kind =3D gnu_v3_base_object_dtor;
+				break;
+				/*  digit '3' is not used */
+			case '4':
+				kind =3D gnu_v3_unified_dtor;
+				break;
+			case '5':
+				kind =3D gnu_v3_object_dtor_group;
+				break;
+			default:
+				return NULL;
+			}
+			d_advance(di, 2);
+			return d_make_dtor(di, kind, di->last_name);
+		}
+
+	default:
+		return NULL;
+	}
+}
+
+/* True iff we're looking at an order-insensitive type-qualifier, including
+   function-type-qualifiers.  */
+
+static int next_is_type_qual(struct d_info *di)
+{
+	char peek =3D d_peek_char(di);
+
+	if (peek =3D=3D 'r' || peek =3D=3D 'V' || peek =3D=3D 'K')
+		return 1;
+	if (peek =3D=3D 'D')
+	{
+		peek =3D d_peek_next_char(di);
+		if (peek =3D=3D 'x' || peek =3D=3D 'o' || peek =3D=3D 'O' || peek =3D=3D=
 'w')
+			return 1;
+	}
+	return 0;
+}
+
+/* <type> ::=3D <builtin-type>
+          ::=3D <function-type>
+          ::=3D <class-enum-type>
+          ::=3D <array-type>
+          ::=3D <pointer-to-member-type>
+          ::=3D <template-param>
+          ::=3D <template-template-param> <template-args>
+          ::=3D <substitution>
+          ::=3D <CV-qualifiers> <type>
+          ::=3D P <type>
+          ::=3D R <type>
+          ::=3D O <type> (C++0x)
+          ::=3D C <type>
+          ::=3D G <type>
+          ::=3D U <source-name> <type>
+
+   <builtin-type> ::=3D various one letter codes
+                  ::=3D u <source-name>
+*/
+
+CP_STATIC_IF_GLIBCPP_V3 const struct demangle_builtin_type_info cplus_dema=
ngle_builtin_types[D_BUILTIN_TYPE_COUNT] =3D {
+	/* a */ {NL("signed char"), NL("signed char"), D_PRINT_DEFAULT},
+	/* b */ {NL("bool"), NL("boolean"), D_PRINT_BOOL},
+	/* c */ {NL("char"), NL("byte"), D_PRINT_DEFAULT},
+	/* d */ {NL("double"), NL("double"), D_PRINT_FLOAT},
+	/* e */ {NL("long double"), NL("long double"), D_PRINT_FLOAT},
+	/* f */ {NL("float"), NL("float"), D_PRINT_FLOAT},
+	/* g */ {NL("__float128"), NL("__float128"), D_PRINT_FLOAT},
+	/* h */ {NL("unsigned char"), NL("unsigned char"), D_PRINT_DEFAULT},
+	/* i */ {NL("int"), NL("int"), D_PRINT_INT},
+	/* j */ {NL("unsigned int"), NL("unsigned"), D_PRINT_UNSIGNED},
+	/* k */ {NULL, 0, NULL, 0, D_PRINT_DEFAULT},
+	/* l */ {NL("long"), NL("long"), D_PRINT_LONG},
+	/* m */ {NL("unsigned long"), NL("unsigned long"), D_PRINT_UNSIGNED_LONG},
+	/* n */ {NL("__int128"), NL("__int128"), D_PRINT_DEFAULT},
+	/* o */ {NL("unsigned __int128"), NL("unsigned __int128"),
+			 D_PRINT_DEFAULT},
+	/* p */ {NULL, 0, NULL, 0, D_PRINT_DEFAULT},
+	/* q */ {NULL, 0, NULL, 0, D_PRINT_DEFAULT},
+	/* r */ {NULL, 0, NULL, 0, D_PRINT_DEFAULT},
+	/* s */ {NL("short"), NL("short"), D_PRINT_DEFAULT},
+	/* t */ {NL("unsigned short"), NL("unsigned short"), D_PRINT_DEFAULT},
+	/* u */ {NULL, 0, NULL, 0, D_PRINT_DEFAULT},
+	/* v */ {NL("void"), NL("void"), D_PRINT_VOID},
+	/* w */ {NL("wchar_t"), NL("char"), D_PRINT_DEFAULT},
+	/* x */ {NL("long long"), NL("long"), D_PRINT_LONG_LONG},
+	/* y */ {NL("unsigned long long"), NL("unsigned long long"),
+			 D_PRINT_UNSIGNED_LONG_LONG},
+	/* z */ {NL("..."), NL("..."), D_PRINT_DEFAULT},
+	/* 26 */ {NL("decimal32"), NL("decimal32"), D_PRINT_DEFAULT},
+	/* 27 */ {NL("decimal64"), NL("decimal64"), D_PRINT_DEFAULT},
+	/* 28 */ {NL("decimal128"), NL("decimal128"), D_PRINT_DEFAULT},
+	/* 29 */ {NL("half"), NL("half"), D_PRINT_FLOAT},
+	/* 30 */ {NL("char8_t"), NL("char8_t"), D_PRINT_DEFAULT},
+	/* 31 */ {NL("char16_t"), NL("char16_t"), D_PRINT_DEFAULT},
+	/* 32 */ {NL("char32_t"), NL("char32_t"), D_PRINT_DEFAULT},
+	/* 33 */ {NL("decltype(nullptr)"), NL("decltype(nullptr)"),
+			  D_PRINT_DEFAULT},
+};
+
+CP_STATIC_IF_GLIBCPP_V3 struct demangle_component *cplus_demangle_type(str=
uct d_info *di)
+{
+	char peek;
+	struct demangle_component *ret;
+	int can_subst;
+
+	/* The ABI specifies that when CV-qualifiers are used, the base type
+	   is substitutable, and the fully qualified type is substitutable,
+	   but the base type with a strict subset of the CV-qualifiers is
+	   not substitutable.  The natural recursive implementation of the
+	   CV-qualifiers would cause subsets to be substitutable, so instead
+	   we pull them all off now.
+
+	   FIXME: The ABI says that order-insensitive vendor qualifiers
+	   should be handled in the same way, but we have no way to tell
+	   which vendor qualifiers are order-insensitive and which are
+	   order-sensitive.  So we just assume that they are all
+	   order-sensitive.  g++ 3.4 supports only one vendor qualifier,
+	   __vector, and it treats it as order-sensitive when mangling
+	   names.  */
+
+	if (next_is_type_qual(di))
+	{
+		struct demangle_component **pret;
+
+		pret =3D d_cv_qualifiers(di, &ret, 0);
+		if (pret =3D=3D NULL)
+			return NULL;
+		if (d_peek_char(di) =3D=3D 'F')
+		{
+			/* cv-qualifiers before a function type apply to 'this',
+			   so avoid adding the unqualified function type to
+			   the substitution list.  */
+			*pret =3D d_function_type(di);
+		} else
+			*pret =3D cplus_demangle_type(di);
+		if (!*pret)
+			return NULL;
+		if ((*pret)->type =3D=3D DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+			|| (*pret)->type =3D=3D DEMANGLE_COMPONENT_REFERENCE_THIS)
+		{
+			/* Move the ref-qualifier outside the cv-qualifiers so that
+			   they are printed in the right order.  */
+			struct demangle_component *fn =3D d_left(*pret);
+
+			d_left(*pret) =3D ret;
+			ret =3D *pret;
+			*pret =3D fn;
+		}
+		if (!d_add_substitution(di, ret))
+			return NULL;
+		return ret;
+	}
+
+	can_subst =3D 1;
+
+	peek =3D d_peek_char(di);
+	switch (peek)
+	{
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+	case 'e':
+	case 'f':
+	case 'g':
+	case 'h':
+	case 'i':
+	case 'j':
+	case 'l':
+	case 'm':
+	case 'n':
+	case 'o':
+	case 's':
+	case 't':
+	case 'v':
+	case 'w':
+	case 'x':
+	case 'y':
+	case 'z':
+		ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[peek - 'a'=
]);
+		di->expansion +=3D ret->u.s_builtin.type->len;
+		can_subst =3D 0;
+		d_advance(di, 1);
+		break;
+
+	case 'u':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_VENDOR_TYPE, d_source_name(di=
), NULL);
+		break;
+
+	case 'F':
+		ret =3D d_function_type(di);
+		break;
+
+	case 'A':
+		ret =3D d_array_type(di);
+		break;
+
+	case 'M':
+		ret =3D d_pointer_to_member_type(di);
+		break;
+
+	case 'T':
+		ret =3D d_template_param(di);
+		if (d_peek_char(di) =3D=3D 'I')
+		{
+			/* This may be <template-template-param> <template-args>.
+			   If this is the type for a conversion operator, we can
+			   have a <template-template-param> here only by following
+			   a derivation like this:
+
+			   <nested-name>
+			   -> <template-prefix> <template-args>
+			   -> <prefix> <template-unqualified-name> <template-args>
+			   -> <unqualified-name> <template-unqualified-name> <template-args>
+			   -> <source-name> <template-unqualified-name> <template-args>
+			   -> <source-name> <operator-name> <template-args>
+			   -> <source-name> cv <type> <template-args>
+			   -> <source-name> cv <template-template-param> <template-args> <templ=
ate-args>
+
+			   where the <template-args> is followed by another.
+			   Otherwise, we must have a derivation like this:
+
+			   <nested-name>
+			   -> <template-prefix> <template-args>
+			   -> <prefix> <template-unqualified-name> <template-args>
+			   -> <unqualified-name> <template-unqualified-name> <template-args>
+			   -> <source-name> <template-unqualified-name> <template-args>
+			   -> <source-name> <operator-name> <template-args>
+			   -> <source-name> cv <type> <template-args>
+			   -> <source-name> cv <template-param> <template-args>
+
+			   where we need to leave the <template-args> to be processed
+			   by d_prefix (following the <template-prefix>).
+
+			   The <template-template-param> part is a substitution
+			   candidate.  */
+			if (!di->is_conversion)
+			{
+				if (!d_add_substitution(di, ret))
+					return NULL;
+				ret =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, ret, d_template_a=
rgs(di));
+			} else
+			{
+				struct demangle_component *args;
+				struct d_info_checkpoint checkpoint;
+
+				d_checkpoint(di, &checkpoint);
+				args =3D d_template_args(di);
+				if (d_peek_char(di) =3D=3D 'I')
+				{
+					if (!d_add_substitution(di, ret))
+						return NULL;
+					ret =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, ret, args);
+				} else
+					d_backtrack(di, &checkpoint);
+			}
+		}
+		break;
+
+	case 'O':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, cplus_deman=
gle_type(di), NULL);
+		break;
+
+	case 'P':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_POINTER, cplus_demangle_type(=
di), NULL);
+		break;
+
+	case 'R':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_REFERENCE, cplus_demangle_typ=
e(di), NULL);
+		break;
+
+	case 'C':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_COMPLEX, cplus_demangle_type(=
di), NULL);
+		break;
+
+	case 'G':
+		d_advance(di, 1);
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_IMAGINARY, cplus_demangle_typ=
e(di), NULL);
+		break;
+
+	case 'U':
+		d_advance(di, 1);
+		ret =3D d_source_name(di);
+		if (d_peek_char(di) =3D=3D 'I')
+			ret =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, ret, d_template_ar=
gs(di));
+		ret =3D d_make_comp(di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, cplus_deman=
gle_type(di), ret);
+		break;
+
+	case 'D':
+		can_subst =3D 0;
+		d_advance(di, 1);
+		peek =3D d_next_char(di);
+		switch (peek)
+		{
+		case 'T':
+		case 't':
+			/* decltype (expression) */
+			ret =3D d_make_comp(di, DEMANGLE_COMPONENT_DECLTYPE, d_expression(di), =
NULL);
+			if (ret && d_next_char(di) !=3D 'E')
+				ret =3D NULL;
+			can_subst =3D 1;
+			break;
+
+		case 'p':
+			/* Pack expansion.  */
+			ret =3D d_make_comp(di, DEMANGLE_COMPONENT_PACK_EXPANSION, cplus_demang=
le_type(di), NULL);
+			can_subst =3D 1;
+			break;
+
+		case 'a':
+			/* auto */
+			ret =3D d_make_name(di, "auto", 4);
+			break;
+		case 'c':
+			/* decltype(auto) */
+			ret =3D d_make_name(di, "decltype(auto)", 14);
+			break;
+
+		case 'f':
+			/* 32-bit decimal floating point */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[26]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 'd':
+			/* 64-bit DFP */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[27]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 'e':
+			/* 128-bit DFP */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[28]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 'h':
+			/* 16-bit half-precision FP */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[29]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 'u':
+			/* char8_t */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[30]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 's':
+			/* char16_t */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[31]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+		case 'i':
+			/* char32_t */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[32]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+
+		case 'F':
+			/* Fixed point types. DF<int bits><length><fract bits><sat>  */
+			ret =3D d_make_empty(di);
+			ret->type =3D DEMANGLE_COMPONENT_FIXED_TYPE;
+			if ((ret->u.s_fixed.accum =3D IS_DIGIT(d_peek_char(di))))
+				/* For demangling we don't care about the bits.  */
+				d_number(di);
+			ret->u.s_fixed.length =3D cplus_demangle_type(di);
+			if (ret->u.s_fixed.length =3D=3D NULL)
+				return NULL;
+			d_number(di);
+			peek =3D d_next_char(di);
+			ret->u.s_fixed.sat =3D (peek =3D=3D 's');
+			break;
+
+		case 'v':
+			ret =3D d_vector_type(di);
+			can_subst =3D 1;
+			break;
+
+		case 'n':
+			/* decltype(nullptr) */
+			ret =3D d_make_builtin_type(di, &cplus_demangle_builtin_types[33]);
+			di->expansion +=3D ret->u.s_builtin.type->len;
+			break;
+
+		default:
+			return NULL;
+		}
+		break;
+
+	default:
+		return d_class_enum_type(di, 1);
+	}
+
+	if (can_subst)
+	{
+		if (!d_add_substitution(di, ret))
+			return NULL;
+	}
+
+	return ret;
+}
+
+/* <CV-qualifiers> ::=3D [r] [V] [K] [Dx] */
+
+static struct demangle_component **d_cv_qualifiers(struct d_info *di, stru=
ct demangle_component **pret, int member_fn)
+{
+	struct demangle_component **pstart;
+	char peek;
+
+	pstart =3D pret;
+	peek =3D d_peek_char(di);
+	while (next_is_type_qual(di))
+	{
+		enum demangle_component_type t;
+		struct demangle_component *right =3D NULL;
+
+		d_advance(di, 1);
+		if (peek =3D=3D 'r')
+		{
+			t =3D (member_fn ? DEMANGLE_COMPONENT_RESTRICT_THIS : DEMANGLE_COMPONEN=
T_RESTRICT);
+			di->expansion +=3D sizeof "restrict";
+		} else if (peek =3D=3D 'V')
+		{
+			t =3D (member_fn ? DEMANGLE_COMPONENT_VOLATILE_THIS : DEMANGLE_COMPONEN=
T_VOLATILE);
+			di->expansion +=3D sizeof "volatile";
+		} else if (peek =3D=3D 'K')
+		{
+			t =3D (member_fn ? DEMANGLE_COMPONENT_CONST_THIS : DEMANGLE_COMPONENT_C=
ONST);
+			di->expansion +=3D sizeof "const";
+		} else
+		{
+			peek =3D d_next_char(di);
+			if (peek =3D=3D 'x')
+			{
+				t =3D DEMANGLE_COMPONENT_TRANSACTION_SAFE;
+				di->expansion +=3D sizeof "transaction_safe";
+			} else if (peek =3D=3D 'o' || peek =3D=3D 'O')
+			{
+				t =3D DEMANGLE_COMPONENT_NOEXCEPT;
+				di->expansion +=3D sizeof "noexcept";
+				if (peek =3D=3D 'O')
+				{
+					right =3D d_expression(di);
+					if (right =3D=3D NULL)
+						return NULL;
+					if (!d_check_char(di, 'E'))
+						return NULL;
+				}
+			} else if (peek =3D=3D 'w')
+			{
+				t =3D DEMANGLE_COMPONENT_THROW_SPEC;
+				di->expansion +=3D sizeof "throw";
+				right =3D d_parmlist(di);
+				if (right =3D=3D NULL)
+					return NULL;
+				if (!d_check_char(di, 'E'))
+					return NULL;
+			} else
+				return NULL;
+		}
+
+		*pret =3D d_make_comp(di, t, NULL, right);
+		if (*pret =3D=3D NULL)
+			return NULL;
+		pret =3D &d_left(*pret);
+
+		peek =3D d_peek_char(di);
+	}
+
+	if (!member_fn && peek =3D=3D 'F')
+	{
+		while (pstart !=3D pret)
+		{
+			switch ((*pstart)->type)
+			{
+			case DEMANGLE_COMPONENT_RESTRICT:
+				(*pstart)->type =3D DEMANGLE_COMPONENT_RESTRICT_THIS;
+				break;
+			case DEMANGLE_COMPONENT_VOLATILE:
+				(*pstart)->type =3D DEMANGLE_COMPONENT_VOLATILE_THIS;
+				break;
+			case DEMANGLE_COMPONENT_CONST:
+				(*pstart)->type =3D DEMANGLE_COMPONENT_CONST_THIS;
+				break;
+			default:
+				break;
+			}
+			pstart =3D &d_left(*pstart);
+		}
+	}
+
+	return pret;
+}
+
+/* <ref-qualifier> ::=3D R
+                   ::=3D O */
+
+static struct demangle_component *d_ref_qualifier(struct d_info *di, struc=
t demangle_component *sub)
+{
+	struct demangle_component *ret =3D sub;
+	char peek;
+
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D 'R' || peek =3D=3D 'O')
+	{
+		enum demangle_component_type t;
+
+		if (peek =3D=3D 'R')
+		{
+			t =3D DEMANGLE_COMPONENT_REFERENCE_THIS;
+			di->expansion +=3D sizeof "&";
+		} else
+		{
+			t =3D DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS;
+			di->expansion +=3D sizeof "&&";
+		}
+		d_advance(di, 1);
+
+		ret =3D d_make_comp(di, t, ret, NULL);
+	}
+
+	return ret;
+}
+
+/* <function-type> ::=3D F [Y] <bare-function-type> [<ref-qualifier>] [T] =
E  */
+
+static struct demangle_component *d_function_type(struct d_info *di)
+{
+	struct demangle_component *ret =3D NULL;
+
+	if ((di->options & DMGL_NO_RECURSE_LIMIT) =3D=3D 0)
+	{
+		if (di->recursion_level > DEMANGLE_RECURSION_LIMIT)
+			/* FIXME: There ought to be a way to report
+			   that the recursion limit has been reached.  */
+			return NULL;
+
+		di->recursion_level++;
+	}
+
+	if (d_check_char(di, 'F'))
+	{
+		if (d_peek_char(di) =3D=3D 'Y')
+		{
+			/* Function has C linkage.  We don't print this information.
+			   FIXME: We should print it in verbose mode.  */
+			d_advance(di, 1);
+		}
+		ret =3D d_bare_function_type(di, 1);
+		ret =3D d_ref_qualifier(di, ret);
+
+		if (!d_check_char(di, 'E'))
+			ret =3D NULL;
+	}
+
+	if ((di->options & DMGL_NO_RECURSE_LIMIT) =3D=3D 0)
+		di->recursion_level--;
+	return ret;
+}
+
+/* <type>+ */
+
+static struct demangle_component *d_parmlist(struct d_info *di)
+{
+	struct demangle_component *tl;
+	struct demangle_component **ptl;
+
+	tl =3D NULL;
+	ptl =3D &tl;
+	while (1)
+	{
+		struct demangle_component *type;
+
+		char peek =3D d_peek_char(di);
+
+		if (peek =3D=3D '\0' || peek =3D=3D 'E' || peek =3D=3D '.')
+			break;
+		if ((peek =3D=3D 'R' || peek =3D=3D 'O') && d_peek_next_char(di) =3D=3D =
'E')
+			/* Function ref-qualifier, not a ref prefix for a parameter type.  */
+			break;
+		type =3D cplus_demangle_type(di);
+		if (type =3D=3D NULL)
+			return NULL;
+		*ptl =3D d_make_comp(di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
+		if (*ptl =3D=3D NULL)
+			return NULL;
+		ptl =3D &d_right(*ptl);
+	}
+
+	/* There should be at least one parameter type besides the optional
+	   return type.  A function which takes no arguments will have a
+	   single parameter type void.  */
+	if (tl =3D=3D NULL)
+		return NULL;
+
+	/* If we have a single parameter type void, omit it.  */
+	if (d_right(tl) =3D=3D NULL
+		&& d_left(tl)->type =3D=3D DEMANGLE_COMPONENT_BUILTIN_TYPE && d_left(tl)=
=2D>u.s_builtin.type->print =3D=3D D_PRINT_VOID)
+	{
+		di->expansion -=3D d_left(tl)->u.s_builtin.type->len;
+		d_left(tl) =3D NULL;
+	}
+
+	return tl;
+}
+
+/* <bare-function-type> ::=3D [J]<type>+  */
+
+static struct demangle_component *d_bare_function_type(struct d_info *di, =
int has_return_type)
+{
+	struct demangle_component *return_type;
+	struct demangle_component *tl;
+	char peek;
+
+	/* Detect special qualifier indicating that the first argument
+	   is the return type.  */
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D 'J')
+	{
+		d_advance(di, 1);
+		has_return_type =3D 1;
+	}
+
+	if (has_return_type)
+	{
+		return_type =3D cplus_demangle_type(di);
+		if (return_type =3D=3D NULL)
+			return NULL;
+	} else
+		return_type =3D NULL;
+
+	tl =3D d_parmlist(di);
+	if (tl =3D=3D NULL)
+		return NULL;
+
+	return d_make_comp(di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl);
+}
+
+/* <class-enum-type> ::=3D <name>  */
+
+static struct demangle_component *d_class_enum_type(struct d_info *di, int=
 substable)
+{
+	return d_name(di, substable);
+}
+
+/* <array-type> ::=3D A <(positive dimension) number> _ <(element) type>
+                ::=3D A [<(dimension) expression>] _ <(element) type>
+*/
+
+static struct demangle_component *d_array_type(struct d_info *di)
+{
+	char peek;
+	struct demangle_component *dim;
+
+	if (!d_check_char(di, 'A'))
+		return NULL;
+
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D '_')
+		dim =3D NULL;
+	else if (IS_DIGIT(peek))
+	{
+		const char *s;
+
+		s =3D d_str(di);
+		do
+		{
+			d_advance(di, 1);
+			peek =3D d_peek_char(di);
+		}
+		while (IS_DIGIT(peek));
+		dim =3D d_make_name(di, s, d_str(di) - s);
+		if (dim =3D=3D NULL)
+			return NULL;
+	} else
+	{
+		dim =3D d_expression(di);
+		if (dim =3D=3D NULL)
+			return NULL;
+	}
+
+	if (!d_check_char(di, '_'))
+		return NULL;
+
+	return d_make_comp(di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim, cplus_demangle=
_type(di));
+}
+
+/* <vector-type> ::=3D Dv <number> _ <type>
+                 ::=3D Dv _ <expression> _ <type> */
+
+static struct demangle_component *d_vector_type(struct d_info *di)
+{
+	char peek;
+	struct demangle_component *dim;
+
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D '_')
+	{
+		d_advance(di, 1);
+		dim =3D d_expression(di);
+	} else
+		dim =3D d_number_component(di);
+
+	if (dim =3D=3D NULL)
+		return NULL;
+
+	if (!d_check_char(di, '_'))
+		return NULL;
+
+	return d_make_comp(di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim, cplus_demangl=
e_type(di));
+}
+
+/* <pointer-to-member-type> ::=3D M <(class) type> <(member) type>  */
+
+static struct demangle_component *d_pointer_to_member_type(struct d_info *=
di)
+{
+	struct demangle_component *cl;
+	struct demangle_component *mem;
+
+	if (!d_check_char(di, 'M'))
+		return NULL;
+
+	cl =3D cplus_demangle_type(di);
+	if (cl =3D=3D NULL)
+		return NULL;
+
+	/* The ABI says, "The type of a non-static member function is considered
+	   to be different, for the purposes of substitution, from the type of a
+	   namespace-scope or static member function whose type appears
+	   similar. The types of two non-static member functions are considered
+	   to be different, for the purposes of substitution, if the functions
+	   are members of different classes. In other words, for the purposes of
+	   substitution, the class of which the function is a member is
+	   considered part of the type of function."
+
+	   For a pointer to member function, this call to cplus_demangle_type
+	   will end up adding a (possibly qualified) non-member function type to
+	   the substitution table, which is not correct; however, the member
+	   function type will never be used in a substitution, so putting the
+	   wrong type in the substitution table is harmless.  */
+
+	mem =3D cplus_demangle_type(di);
+	if (mem =3D=3D NULL)
+		return NULL;
+
+	return d_make_comp(di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
+}
+
+/* <non-negative number> _ */
+
+static int d_compact_number(struct d_info *di)
+{
+	int num;
+
+	if (d_peek_char(di) =3D=3D '_')
+		num =3D 0;
+	else if (d_peek_char(di) =3D=3D 'n')
+		return -1;
+	else
+		num =3D d_number(di) + 1;
+
+	if (num < 0 || !d_check_char(di, '_'))
+		return -1;
+	return num;
+}
+
+/* <template-param> ::=3D T_
+                    ::=3D T <(parameter-2 non-negative) number> _
+*/
+
+static struct demangle_component *d_template_param(struct d_info *di)
+{
+	int param;
+
+	if (!d_check_char(di, 'T'))
+		return NULL;
+
+	param =3D d_compact_number(di);
+	if (param < 0)
+		return NULL;
+
+	return d_make_template_param(di, param);
+}
+
+/* <template-args> ::=3D I <template-arg>+ E  */
+
+static struct demangle_component *d_template_args(struct d_info *di)
+{
+	if (d_peek_char(di) !=3D 'I' && d_peek_char(di) !=3D 'J')
+		return NULL;
+	d_advance(di, 1);
+
+	return d_template_args_1(di);
+}
+
+/* <template-arg>* E  */
+
+static struct demangle_component *d_template_args_1(struct d_info *di)
+{
+	struct demangle_component *hold_last_name;
+	struct demangle_component *al;
+	struct demangle_component **pal;
+
+	/* Preserve the last name we saw--don't let the template arguments
+	   clobber it, as that would give us the wrong name for a subsequent
+	   constructor or destructor.  */
+	hold_last_name =3D di->last_name;
+
+	if (d_peek_char(di) =3D=3D 'E')
+	{
+		/* An argument pack can be empty.  */
+		d_advance(di, 1);
+		return d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
+	}
+
+	al =3D NULL;
+	pal =3D &al;
+	while (1)
+	{
+		struct demangle_component *a;
+
+		a =3D d_template_arg(di);
+		if (a =3D=3D NULL)
+			return NULL;
+
+		*pal =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
+		if (*pal =3D=3D NULL)
+			return NULL;
+		pal =3D &d_right(*pal);
+
+		if (d_peek_char(di) =3D=3D 'E')
+		{
+			d_advance(di, 1);
+			break;
+		}
+	}
+
+	di->last_name =3D hold_last_name;
+
+	return al;
+}
+
+/* <template-arg> ::=3D <type>
+                  ::=3D X <expression> E
+                  ::=3D <expr-primary>
+*/
+
+static struct demangle_component *d_template_arg(struct d_info *di)
+{
+	struct demangle_component *ret;
+
+	switch (d_peek_char(di))
+	{
+	case 'X':
+		d_advance(di, 1);
+		ret =3D d_expression(di);
+		if (!d_check_char(di, 'E'))
+			return NULL;
+		return ret;
+
+	case 'L':
+		return d_expr_primary(di);
+
+	case 'I':
+	case 'J':
+		/* An argument pack.  */
+		return d_template_args(di);
+
+	default:
+		return cplus_demangle_type(di);
+	}
+}
+
+/* Parse a sequence of expressions until we hit the terminator
+   character.  */
+
+static struct demangle_component *d_exprlist(struct d_info *di, char termi=
nator)
+{
+	struct demangle_component *list =3D NULL;
+	struct demangle_component **p =3D &list;
+
+	if (d_peek_char(di) =3D=3D terminator)
+	{
+		d_advance(di, 1);
+		return d_make_comp(di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
+	}
+
+	while (1)
+	{
+		struct demangle_component *arg =3D d_expression(di);
+
+		if (arg =3D=3D NULL)
+			return NULL;
+
+		*p =3D d_make_comp(di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
+		if (*p =3D=3D NULL)
+			return NULL;
+		p =3D &d_right(*p);
+
+		if (d_peek_char(di) =3D=3D terminator)
+		{
+			d_advance(di, 1);
+			break;
+		}
+	}
+
+	return list;
+}
+
+/* Returns nonzero iff OP is an operator for a C++ cast: const_cast,
+   dynamic_cast, static_cast or reinterpret_cast.  */
+
+static int op_is_new_cast(struct demangle_component *op)
+{
+	const char *code =3D op->u.s_operator.op->code;
+
+	return (code[1] =3D=3D 'c' && (code[0] =3D=3D 's' || code[0] =3D=3D 'd' |=
| code[0] =3D=3D 'c' || code[0] =3D=3D 'r'));
+}
+
+/*   <unresolved-name> ::=3D [gs] <base-unresolved-name> # x or (with "gs"=
) ::x
+       ::=3D sr <unresolved-type> <base-unresolved-name> # T::x / decltype=
(p)::x
+       # T::N::x /decltype(p)::N::x
+       ::=3D srN <unresolved-type> <unresolved-qualifier-level>+ E <base-u=
nresolved-name>
+       # A::x, N::y, A<T>::z; "gs" means leading "::"
+       ::=3D [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+     "gs" is handled elsewhere, as a unary operator.  */
+
+static struct demangle_component *d_unresolved_name(struct d_info *di)
+{
+	struct demangle_component *type;
+	struct demangle_component *name;
+	char peek;
+
+	/* Consume the "sr".  */
+	d_advance(di, 2);
+
+	peek =3D d_peek_char(di);
+	if (di->unresolved_name_state && (IS_DIGIT(peek) || IS_LOWER(peek) || pee=
k =3D=3D 'C' || peek =3D=3D 'U' || peek =3D=3D 'L'))
+	{
+		/* The third production is ambiguous with the old unresolved-name syntax
+		   of <type> <base-unresolved-name>; in the old mangling, A::x was mangl=
ed
+		   as sr1A1x, now sr1AE1x.  So we first try to demangle using the new
+		   mangling, then with the old if that fails.  */
+		di->unresolved_name_state =3D -1;
+		type =3D d_prefix(di, 0);
+		if (d_peek_char(di) =3D=3D 'E')
+			d_advance(di, 1);
+	} else
+		type =3D cplus_demangle_type(di);
+	name =3D d_unqualified_name(di, type, NULL);
+	if (d_peek_char(di) =3D=3D 'I')
+		name =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, name, d_template_a=
rgs(di));
+	return name;
+}
+
+/* <expression> ::=3D <(unary) operator-name> <expression>
+                ::=3D <(binary) operator-name> <expression> <expression>
+                ::=3D <(trinary) operator-name> <expression> <expression> =
<expression>
+		::=3D cl <expression>+ E
+                ::=3D st <type>
+                ::=3D <template-param>
+		::=3D u <source-name> <template-arg>* E # vendor extended expression
+		::=3D <unresolved-name>
+                ::=3D <expr-primary>
+
+  <braced-expression> ::=3D <expression>
+		      ::=3D di <field source-name> <braced-expression>	# .name =3D expr
+		      ::=3D dx <index expression> <braced-expression>	# [expr] =3D expr
+		      ::=3D dX <range begin expression> <range end expression> <braced-e=
xpression>
+									# [expr ... expr] =3D expr
+*/
+
+static struct demangle_component *d_expression_1(struct d_info *di)
+{
+	char peek;
+
+	peek =3D d_peek_char(di);
+	if (peek =3D=3D 'L')
+		return d_expr_primary(di);
+	else if (peek =3D=3D 'T')
+		return d_template_param(di);
+	else if (peek =3D=3D 's' && d_peek_next_char(di) =3D=3D 'r')
+		return d_unresolved_name(di);
+	else if (peek =3D=3D 's' && d_peek_next_char(di) =3D=3D 'p')
+	{
+		d_advance(di, 2);
+		return d_make_comp(di, DEMANGLE_COMPONENT_PACK_EXPANSION, d_expression_1=
(di), NULL);
+	} else if (peek =3D=3D 'f' && d_peek_next_char(di) =3D=3D 'p')
+	{
+		/* Function parameter used in a late-specified return type.  */
+		int index;
+
+		d_advance(di, 2);
+		if (d_peek_char(di) =3D=3D 'T')
+		{
+			/* 'this' parameter.  */
+			d_advance(di, 1);
+			index =3D 0;
+		} else
+		{
+			index =3D d_compact_number(di);
+			if (index =3D=3D INT_MAX || index =3D=3D -1)
+				return NULL;
+			index++;
+		}
+		return d_make_function_param(di, index);
+	} else if (IS_DIGIT(peek) || (peek =3D=3D 'o' && d_peek_next_char(di) =3D=
=3D 'n'))
+	{
+		/* We can get an unqualified name as an expression in the case of
+		   a dependent function call, i.e. decltype(f(t)).  */
+		struct demangle_component *name;
+
+		if (peek =3D=3D 'o')
+			/* operator-function-id, i.e. operator+(t).  */
+			d_advance(di, 2);
+
+		name =3D d_unqualified_name(di, NULL, NULL);
+		if (name =3D=3D NULL)
+			return NULL;
+		if (d_peek_char(di) =3D=3D 'I')
+			return d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, name, d_template_ar=
gs(di));
+		else
+			return name;
+	} else if ((peek =3D=3D 'i' || peek =3D=3D 't') && d_peek_next_char(di) =
=3D=3D 'l')
+	{
+		/* Brace-enclosed initializer list, untyped or typed.  */
+		struct demangle_component *type =3D NULL;
+
+		d_advance(di, 2);
+		if (peek =3D=3D 't')
+			type =3D cplus_demangle_type(di);
+		if (!d_peek_char(di) || !d_peek_next_char(di))
+			return NULL;
+		return d_make_comp(di, DEMANGLE_COMPONENT_INITIALIZER_LIST, type, d_expr=
list(di, 'E'));
+	} else if (peek =3D=3D 'u')
+	{
+		/* A vendor extended expression.  */
+		struct demangle_component *name,
+		*args;
+
+		d_advance(di, 1);
+		name =3D d_source_name(di);
+		args =3D d_template_args_1(di);
+		return d_make_comp(di, DEMANGLE_COMPONENT_VENDOR_EXPR, name, args);
+	} else
+	{
+		struct demangle_component *op;
+		const char *code =3D NULL;
+		int args;
+
+		op =3D d_operator_name(di);
+		if (op =3D=3D NULL)
+			return NULL;
+
+		if (op->type =3D=3D DEMANGLE_COMPONENT_OPERATOR)
+		{
+			code =3D op->u.s_operator.op->code;
+			di->expansion +=3D op->u.s_operator.op->len - 2;
+			if (strcmp(code, "st") =3D=3D 0)
+				return d_make_comp(di, DEMANGLE_COMPONENT_UNARY, op, cplus_demangle_ty=
pe(di));
+		}
+
+		switch (op->type)
+		{
+		default:
+			return NULL;
+		case DEMANGLE_COMPONENT_OPERATOR:
+			args =3D op->u.s_operator.op->args;
+			break;
+		case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+			args =3D op->u.s_extended_operator.args;
+			break;
+		case DEMANGLE_COMPONENT_CAST:
+			args =3D 1;
+			break;
+		}
+
+		switch (args)
+		{
+		case 0:
+			return d_make_comp(di, DEMANGLE_COMPONENT_NULLARY, op, NULL);
+
+		case 1:
+			{
+				struct demangle_component *operand;
+				int suffix =3D 0;
+
+				if (code && (code[0] =3D=3D 'p' || code[0] =3D=3D 'm') && code[1] =3D=
=3D code[0])
+					/* pp_ and mm_ are the prefix variants.  */
+					suffix =3D !d_check_char(di, '_');
+
+				if (op->type =3D=3D DEMANGLE_COMPONENT_CAST && d_check_char(di, '_'))
+					operand =3D d_exprlist(di, 'E');
+				else if (code && !strcmp(code, "sP"))
+					operand =3D d_template_args_1(di);
+				else
+					operand =3D d_expression_1(di);
+
+				if (suffix)
+					/* Indicate the suffix variant for d_print_comp.  */
+					operand =3D d_make_comp(di, DEMANGLE_COMPONENT_BINARY_ARGS, operand, =
operand);
+
+				return d_make_comp(di, DEMANGLE_COMPONENT_UNARY, op, operand);
+			}
+		case 2:
+			{
+				struct demangle_component *left;
+				struct demangle_component *right;
+
+				if (code =3D=3D NULL)
+					return NULL;
+				if (op_is_new_cast(op))
+					left =3D cplus_demangle_type(di);
+				else if (code[0] =3D=3D 'f')
+					/* fold-expression.  */
+					left =3D d_operator_name(di);
+				else if (!strcmp(code, "di"))
+					left =3D d_unqualified_name(di, NULL, NULL);
+				else
+					left =3D d_expression_1(di);
+				if (!strcmp(code, "cl"))
+					right =3D d_exprlist(di, 'E');
+				else if (!strcmp(code, "dt") || !strcmp(code, "pt"))
+				{
+					peek =3D d_peek_char(di);
+					/* These codes start a qualified name.  */
+					if ((peek =3D=3D 'g' && d_peek_next_char(di) =3D=3D 's') || (peek =3D=
=3D 's' && d_peek_next_char(di) =3D=3D 'r'))
+						right =3D d_expression_1(di);
+					else
+					{
+						/* Otherwise it's an unqualified name.  We use
+						   d_unqualified_name rather than d_expression_1 here for
+						   old mangled names that didn't add 'on' before operator
+						   names.  */
+						right =3D d_unqualified_name(di, NULL, NULL);
+						if (d_peek_char(di) =3D=3D 'I')
+							right =3D d_make_comp(di, DEMANGLE_COMPONENT_TEMPLATE, right, d_tem=
plate_args(di));
+					}
+				} else
+					right =3D d_expression_1(di);
+
+				return d_make_comp(di, DEMANGLE_COMPONENT_BINARY, op,
+								   d_make_comp(di, DEMANGLE_COMPONENT_BINARY_ARGS, left, right));
+			}
+		case 3:
+			{
+				struct demangle_component *first;
+				struct demangle_component *second;
+				struct demangle_component *third;
+
+				if (code =3D=3D NULL)
+					return NULL;
+				else if (!strcmp(code, "qu") || !strcmp(code, "dX"))
+				{
+					/* ?: expression.  */
+					first =3D d_expression_1(di);
+					second =3D d_expression_1(di);
+					third =3D d_expression_1(di);
+					if (third =3D=3D NULL)
+						return NULL;
+				} else if (code[0] =3D=3D 'f')
+				{
+					/* fold-expression.  */
+					first =3D d_operator_name(di);
+					second =3D d_expression_1(di);
+					third =3D d_expression_1(di);
+					if (third =3D=3D NULL)
+						return NULL;
+				} else if (code[0] =3D=3D 'n')
+				{
+					/* new-expression.  */
+					if (code[1] !=3D 'w' && code[1] !=3D 'a')
+						return NULL;
+					first =3D d_exprlist(di, '_');
+					second =3D cplus_demangle_type(di);
+					if (d_peek_char(di) =3D=3D 'E')
+					{
+						d_advance(di, 1);
+						third =3D NULL;
+					} else if (d_peek_char(di) =3D=3D 'p' && d_peek_next_char(di) =3D=3D =
'i')
+					{
+						/* Parenthesized initializer.  */
+						d_advance(di, 2);
+						third =3D d_exprlist(di, 'E');
+					} else if (d_peek_char(di) =3D=3D 'i' && d_peek_next_char(di) =3D=3D =
'l')
+						/* initializer-list.  */
+						third =3D d_expression_1(di);
+					else
+						return NULL;
+				} else
+					return NULL;
+				return d_make_comp(di, DEMANGLE_COMPONENT_TRINARY, op,
+								   d_make_comp(di,
+											   DEMANGLE_COMPONENT_TRINARY_ARG1,
+											   first, d_make_comp(di, DEMANGLE_COMPONENT_TRINARY_ARG2, seco=
nd, third)));
+			}
+		default:
+			return NULL;
+		}
+	}
+}
+
+static struct demangle_component *d_expression(struct d_info *di)
+{
+	struct demangle_component *ret;
+	int was_expression =3D di->is_expression;
+
+	di->is_expression =3D 1;
+	ret =3D d_expression_1(di);
+	di->is_expression =3D was_expression;
+	return ret;
+}
+
+/* <expr-primary> ::=3D L <type> <(value) number> E
+                  ::=3D L <type> <(value) float> E
+                  ::=3D L <mangled-name> E
+*/
+
+static struct demangle_component *d_expr_primary(struct d_info *di)
+{
+	struct demangle_component *ret;
+
+	if (!d_check_char(di, 'L'))
+		return NULL;
+	if (d_peek_char(di) =3D=3D '_'
+		/* Workaround for G++ bug; see comment in write_template_arg.  */
+		|| d_peek_char(di) =3D=3D 'Z')
+		ret =3D cplus_demangle_mangled_name(di, 0);
+	else
+	{
+		struct demangle_component *type;
+		enum demangle_component_type t;
+		const char *s;
+
+		type =3D cplus_demangle_type(di);
+		if (type =3D=3D NULL)
+			return NULL;
+
+		/* If we have a type we know how to print, we aren't going to
+		   print the type name itself.  */
+		if (type->type =3D=3D DEMANGLE_COMPONENT_BUILTIN_TYPE && type->u.s_built=
in.type->print !=3D D_PRINT_DEFAULT)
+			di->expansion -=3D type->u.s_builtin.type->len;
+
+		if (type->type =3D=3D DEMANGLE_COMPONENT_BUILTIN_TYPE
+			&& strcmp(type->u.s_builtin.type->name, cplus_demangle_builtin_types[33=
].name) =3D=3D 0)
+		{
+			if (d_peek_char(di) =3D=3D 'E')
+			{
+				d_advance(di, 1);
+				return type;
+			}
+		}
+
+		/* Rather than try to interpret the literal value, we just
+		   collect it as a string.  Note that it's possible to have a
+		   floating point literal here.  The ABI specifies that the
+		   format of such literals is machine independent.  That's fine,
+		   but what's not fine is that versions of g++ up to 3.2 with
+		   -fabi-version=3D1 used upper case letters in the hex constant,
+		   and dumped out gcc's internal representation.  That makes it
+		   hard to tell where the constant ends, and hard to dump the
+		   constant in any readable form anyhow.  We don't attempt to
+		   handle these cases.  */
+
+		t =3D DEMANGLE_COMPONENT_LITERAL;
+		if (d_peek_char(di) =3D=3D 'n')
+		{
+			t =3D DEMANGLE_COMPONENT_LITERAL_NEG;
+			d_advance(di, 1);
+		}
+		s =3D d_str(di);
+		while (d_peek_char(di) !=3D 'E')
+		{
+			if (d_peek_char(di) =3D=3D '\0')
+				return NULL;
+			d_advance(di, 1);
+		}
+		ret =3D d_make_comp(di, t, type, d_make_name(di, s, d_str(di) - s));
+	}
+	if (!d_check_char(di, 'E'))
+		return NULL;
+	return ret;
+}
+
+/* <local-name> ::=3D Z <(function) encoding> E <(entity) name> [<discrimi=
nator>]
+                ::=3D Z <(function) encoding> E s [<discriminator>]
+                ::=3D Z <(function) encoding> E d [<parameter> number>] _ =
<entity name>
+*/
+
+static struct demangle_component *d_local_name(struct d_info *di)
+{
+	struct demangle_component *function;
+	struct demangle_component *name;
+
+	if (!d_check_char(di, 'Z'))
+		return NULL;
+
+	function =3D d_encoding(di, 0);
+	if (!function)
+		return NULL;
+
+	if (!d_check_char(di, 'E'))
+		return NULL;
+
+	if (d_peek_char(di) =3D=3D 's')
+	{
+		d_advance(di, 1);
+		if (!d_discriminator(di))
+			return NULL;
+		name =3D d_make_name(di, "string literal", sizeof "string literal" - 1);
+	} else
+	{
+		int num =3D -1;
+
+		if (d_peek_char(di) =3D=3D 'd')
+		{
+			/* Default argument scope: d <number> _.  */
+			d_advance(di, 1);
+			num =3D d_compact_number(di);
+			if (num < 0)
+				return NULL;
+		}
+
+		name =3D d_name(di, 0);
+
+		if (name
+			/* Lambdas and unnamed types have internal discriminators
+			   and are not functions.  */
+			&& name->type !=3D DEMANGLE_COMPONENT_LAMBDA && name->type !=3D DEMANGL=
E_COMPONENT_UNNAMED_TYPE)
+		{
+			/* Read and ignore an optional discriminator.  */
+			if (!d_discriminator(di))
+				return NULL;
+		}
+
+		if (num >=3D 0)
+			name =3D d_make_default_arg(di, num, name);
+	}
+
+	/* Elide the return type of the containing function so as to not
+	   confuse the user thinking it is the return type of whatever local
+	   function we might be containing.  */
+	if (function->type =3D=3D DEMANGLE_COMPONENT_TYPED_NAME && d_right(functi=
on)->type =3D=3D DEMANGLE_COMPONENT_FUNCTION_TYPE)
+		d_left(d_right(function)) =3D NULL;
+
+	return d_make_comp(di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
+}
+
+/* <discriminator> ::=3D _ <number>    # when number < 10
+                   ::=3D __ <number> _ # when number >=3D 10
+
+   <discriminator> ::=3D _ <number>    # when number >=3D10
+   is also accepted to support gcc versions that wrongly mangled that way.
+
+   We demangle the discriminator, but we don't print it out.  FIXME:
+   We should print it out in verbose mode.  */
+
+static int d_discriminator(struct d_info *di)
+{
+	int discrim,
+	 num_underscores =3D 1;
+
+	if (d_peek_char(di) !=3D '_')
+		return 1;
+	d_advance(di, 1);
+	if (d_peek_char(di) =3D=3D '_')
+	{
+		++num_underscores;
+		d_advance(di, 1);
+	}
+
+	discrim =3D d_number(di);
+	if (discrim < 0)
+		return 0;
+	if (num_underscores > 1 && discrim >=3D 10)
+	{
+		if (d_peek_char(di) =3D=3D '_')
+			d_advance(di, 1);
+		else
+			return 0;
+	}
+
+	return 1;
+}
+
+/* <closure-type-name> ::=3D Ul <lambda-sig> E [ <nonnegative number> ] _ =
*/
+
+static struct demangle_component *d_lambda(struct d_info *di)
+{
+	struct demangle_component *tl;
+	struct demangle_component *ret;
+	int num;
+
+	if (!d_check_char(di, 'U'))
+		return NULL;
+	if (!d_check_char(di, 'l'))
+		return NULL;
+
+	tl =3D d_parmlist(di);
+	if (tl =3D=3D NULL)
+		return NULL;
+
+	if (!d_check_char(di, 'E'))
+		return NULL;
+
+	num =3D d_compact_number(di);
+	if (num < 0)
+		return NULL;
+
+	ret =3D d_make_empty(di);
+	if (ret)
+	{
+		ret->type =3D DEMANGLE_COMPONENT_LAMBDA;
+		ret->u.s_unary_num.sub =3D tl;
+		ret->u.s_unary_num.num =3D num;
+	}
+
+	return ret;
+}
+
+/* <unnamed-type-name> ::=3D Ut [ <nonnegative number> ] _ */
+
+static struct demangle_component *d_unnamed_type(struct d_info *di)
+{
+	struct demangle_component *ret;
+	int num;
+
+	if (!d_check_char(di, 'U'))
+		return NULL;
+	if (!d_check_char(di, 't'))
+		return NULL;
+
+	num =3D d_compact_number(di);
+	if (num < 0)
+		return NULL;
+
+	ret =3D d_make_empty(di);
+	if (ret)
+	{
+		ret->type =3D DEMANGLE_COMPONENT_UNNAMED_TYPE;
+		ret->u.s_number.number =3D num;
+	}
+
+	if (!d_add_substitution(di, ret))
+		return NULL;
+
+	return ret;
+}
+
+/* <clone-suffix> ::=3D [ . <clone-type-identifier> ] [ . <nonnegative num=
ber> ]*
+*/
+
+static struct demangle_component *d_clone_suffix(struct d_info *di, struct=
 demangle_component *encoding)
+{
+	const char *suffix =3D d_str(di);
+	const char *pend =3D suffix;
+	struct demangle_component *n;
+
+	if (*pend =3D=3D '.' && (IS_LOWER(pend[1]) || IS_DIGIT(pend[1]) || pend[1=
] =3D=3D '_'))
+	{
+		pend +=3D 2;
+		while (IS_LOWER(*pend) || IS_DIGIT(*pend) || *pend =3D=3D '_')
+			++pend;
+	}
+	while (*pend =3D=3D '.' && IS_DIGIT(pend[1]))
+	{
+		pend +=3D 2;
+		while (IS_DIGIT(*pend))
+			++pend;
+	}
+	d_advance(di, pend - suffix);
+	n =3D d_make_name(di, suffix, pend - suffix);
+	return d_make_comp(di, DEMANGLE_COMPONENT_CLONE, encoding, n);
+}
+
+/* Add a new substitution.  */
+
+static int d_add_substitution(struct d_info *di, struct demangle_component=
 *dc)
+{
+	if (dc =3D=3D NULL)
+		return 0;
+	if (di->next_sub >=3D di->num_subs)
+		return 0;
+	di->subs[di->next_sub] =3D dc;
+	++di->next_sub;
+	return 1;
+}
+
+/* <substitution> ::=3D S <seq-id> _
+                  ::=3D S_
+                  ::=3D St
+                  ::=3D Sa
+                  ::=3D Sb
+                  ::=3D Ss
+                  ::=3D Si
+                  ::=3D So
+                  ::=3D Sd
+
+   If PREFIX is non-zero, then this type is being used as a prefix in
+   a qualified name.  In this case, for the standard substitutions, we
+   need to check whether we are being used as a prefix for a
+   constructor or destructor, and return a full template name.
+   Otherwise we will get something like std::iostream::~iostream()
+   which does not correspond particularly well to any function which
+   actually appears in the source.
+*/
+
+static const struct d_standard_sub_info standard_subs[] =3D {
+	{'t', NL("std"),
+	 NL("std"),
+	 NULL, 0},
+	{'a', NL("std::allocator"),
+	 NL("std::allocator"),
+	 NL("allocator")},
+	{'b', NL("std::basic_string"),
+	 NL("std::basic_string"),
+	 NL("basic_string")},
+	{'s', NL("std::string"),
+	 NL("std::basic_string<char, std::char_traits<char>, std::allocator<char>=
 >"),
+	 NL("basic_string")},
+	{'i', NL("std::istream"),
+	 NL("std::basic_istream<char, std::char_traits<char> >"),
+	 NL("basic_istream")},
+	{'o', NL("std::ostream"),
+	 NL("std::basic_ostream<char, std::char_traits<char> >"),
+	 NL("basic_ostream")},
+	{'d', NL("std::iostream"),
+	 NL("std::basic_iostream<char, std::char_traits<char> >"),
+	 NL("basic_iostream")}
+};
+
+static struct demangle_component *d_substitution(struct d_info *di, int pr=
efix)
+{
+	char c;
+
+	if (!d_check_char(di, 'S'))
+		return NULL;
+
+	c =3D d_next_char(di);
+	if (c =3D=3D '_' || IS_DIGIT(c) || IS_UPPER(c))
+	{
+		unsigned int id;
+
+		id =3D 0;
+		if (c !=3D '_')
+		{
+			do
+			{
+				unsigned int new_id;
+
+				if (IS_DIGIT(c))
+					new_id =3D id * 36 + c - '0';
+				else if (IS_UPPER(c))
+					new_id =3D id * 36 + c - 'A' + 10;
+				else
+					return NULL;
+				if (new_id < id)
+					return NULL;
+				id =3D new_id;
+				c =3D d_next_char(di);
+			}
+			while (c !=3D '_');
+
+			++id;
+		}
+
+		if (id >=3D (unsigned int) di->next_sub)
+			return NULL;
+
+		return di->subs[id];
+	} else
+	{
+		int verbose;
+		const struct d_standard_sub_info *p;
+		const struct d_standard_sub_info *pend;
+
+		verbose =3D (di->options & DMGL_VERBOSE) !=3D 0;
+		if (!verbose && prefix)
+		{
+			char peek;
+
+			peek =3D d_peek_char(di);
+			if (peek =3D=3D 'C' || peek =3D=3D 'D')
+				verbose =3D 1;
+		}
+
+		pend =3D (&standard_subs[0] + sizeof standard_subs / sizeof standard_sub=
s[0]);
+		for (p =3D &standard_subs[0]; p < pend; ++p)
+		{
+			if (c =3D=3D p->code)
+			{
+				const char *s;
+				int len;
+				struct demangle_component *dc;
+
+				if (p->set_last_name !=3D NULL)
+					di->last_name =3D d_make_sub(di, p->set_last_name, p->set_last_name_l=
en);
+				if (verbose)
+				{
+					s =3D p->full_expansion;
+					len =3D p->full_len;
+				} else
+				{
+					s =3D p->simple_expansion;
+					len =3D p->simple_len;
+				}
+				di->expansion +=3D len;
+				dc =3D d_make_sub(di, s, len);
+				if (d_peek_char(di) =3D=3D 'B')
+				{
+					/* If there are ABI tags on the abbreviation, it becomes
+					   a substitution candidate.  */
+					dc =3D d_abi_tags(di, dc);
+					if (!d_add_substitution(di, dc))
+						return NULL;
+				}
+				return dc;
+			}
+		}
+
+		return NULL;
+	}
+}
+
+static void d_checkpoint(struct d_info *di, struct d_info_checkpoint *chec=
kpoint)
+{
+	checkpoint->n =3D di->n;
+	checkpoint->next_comp =3D di->next_comp;
+	checkpoint->next_sub =3D di->next_sub;
+	checkpoint->expansion =3D di->expansion;
+}
+
+static void d_backtrack(struct d_info *di, struct d_info_checkpoint *check=
point)
+{
+	di->n =3D checkpoint->n;
+	di->next_comp =3D checkpoint->next_comp;
+	di->next_sub =3D checkpoint->next_sub;
+	di->expansion =3D checkpoint->expansion;
+}
+
+/* Initialize a growable string.  */
+
+static void d_growable_string_init(struct d_growable_string *dgs, size_t e=
stimate)
+{
+	dgs->buf =3D NULL;
+	dgs->len =3D 0;
+	dgs->alc =3D 0;
+	dgs->allocation_failure =3D 0;
+
+	if (estimate > 0)
+		d_growable_string_resize(dgs, estimate);
+}
+
+/* Grow a growable string to a given size.  */
+
+static inline void d_growable_string_resize(struct d_growable_string *dgs,=
 size_t need)
+{
+	size_t newalc;
+	char *newbuf;
+
+	if (dgs->allocation_failure)
+		return;
+
+	/* Start allocation at two bytes to avoid any possibility of confusion
+	   with the special value of 1 used as a return in *palc to indicate
+	   allocation failures.  */
+	newalc =3D dgs->alc > 0 ? dgs->alc : 2;
+	while (newalc < need)
+		newalc <<=3D 1;
+
+	newbuf =3D (char *) realloc(dgs->buf, newalc);
+	if (newbuf =3D=3D NULL)
+	{
+		free(dgs->buf);
+		dgs->buf =3D NULL;
+		dgs->len =3D 0;
+		dgs->alc =3D 0;
+		dgs->allocation_failure =3D 1;
+		return;
+	}
+	dgs->buf =3D newbuf;
+	dgs->alc =3D newalc;
+}
+
+/* Append a buffer to a growable string.  */
+
+static inline void d_growable_string_append_buffer(struct d_growable_strin=
g *dgs, const char *s, size_t l)
+{
+	size_t need;
+
+	need =3D dgs->len + l + 1;
+	if (need > dgs->alc)
+		d_growable_string_resize(dgs, need);
+
+	if (dgs->allocation_failure)
+		return;
+
+	memcpy(dgs->buf + dgs->len, s, l);
+	dgs->buf[dgs->len + l] =3D '\0';
+	dgs->len +=3D l;
+}
+
+/* Bridge growable strings to the callback mechanism.  */
+
+static void d_growable_string_callback_adapter(const char *s, size_t l, vo=
id *opaque)
+{
+	struct d_growable_string *dgs =3D (struct d_growable_string *) opaque;
+
+	d_growable_string_append_buffer(dgs, s, l);
+}
+
+/* Walk the tree, counting the number of templates encountered, and
+   the number of times a scope might be saved.  These counts will be
+   used to allocate data structures for d_print_comp, so the logic
+   here must mirror the logic d_print_comp will use.  It is not
+   important that the resulting numbers are exact, so long as they
+   are larger than the actual numbers encountered.  */
+
+static void d_count_templates_scopes(struct d_print_info *dpi, struct dema=
ngle_component *dc)
+{
+	if (dc =3D=3D NULL || dc->d_counting > 1 || dpi->recursion > MAX_RECURSIO=
N_COUNT)
+		return;
+
+	++dc->d_counting;
+
+	switch (dc->type)
+	{
+	case DEMANGLE_COMPONENT_NAME:
+	case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+	case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+	case DEMANGLE_COMPONENT_SUB_STD:
+	case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+	case DEMANGLE_COMPONENT_OPERATOR:
+	case DEMANGLE_COMPONENT_CHARACTER:
+	case DEMANGLE_COMPONENT_NUMBER:
+	case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+	case DEMANGLE_COMPONENT_STRUCTURED_BINDING:
+	case DEMANGLE_COMPONENT_MODULE_NAME:
+	case DEMANGLE_COMPONENT_MODULE_PARTITION:
+	case DEMANGLE_COMPONENT_MODULE_INIT:
+		break;
+
+	case DEMANGLE_COMPONENT_TEMPLATE:
+		dpi->num_copy_templates++;
+		goto recurse_left_right;
+
+	case DEMANGLE_COMPONENT_REFERENCE:
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+		if (d_left(dc)->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_PARAM)
+			dpi->num_saved_scopes++;
+		goto recurse_left_right;
+
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+	case DEMANGLE_COMPONENT_VTABLE:
+	case DEMANGLE_COMPONENT_VTT:
+	case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+	case DEMANGLE_COMPONENT_TYPEINFO:
+	case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+	case DEMANGLE_COMPONENT_TYPEINFO_FN:
+	case DEMANGLE_COMPONENT_THUNK:
+	case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+	case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+	case DEMANGLE_COMPONENT_JAVA_CLASS:
+	case DEMANGLE_COMPONENT_GUARD:
+	case DEMANGLE_COMPONENT_TLS_INIT:
+	case DEMANGLE_COMPONENT_TLS_WRAPPER:
+	case DEMANGLE_COMPONENT_REFTEMP:
+	case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+	case DEMANGLE_COMPONENT_RESTRICT:
+	case DEMANGLE_COMPONENT_VOLATILE:
+	case DEMANGLE_COMPONENT_CONST:
+	case DEMANGLE_COMPONENT_RESTRICT_THIS:
+	case DEMANGLE_COMPONENT_VOLATILE_THIS:
+	case DEMANGLE_COMPONENT_CONST_THIS:
+	case DEMANGLE_COMPONENT_REFERENCE_THIS:
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+	case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+	case DEMANGLE_COMPONENT_NOEXCEPT:
+	case DEMANGLE_COMPONENT_THROW_SPEC:
+	case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+	case DEMANGLE_COMPONENT_POINTER:
+	case DEMANGLE_COMPONENT_COMPLEX:
+	case DEMANGLE_COMPONENT_IMAGINARY:
+	case DEMANGLE_COMPONENT_VENDOR_TYPE:
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+	case DEMANGLE_COMPONENT_VECTOR_TYPE:
+	case DEMANGLE_COMPONENT_ARGLIST:
+	case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+	case DEMANGLE_COMPONENT_TPARM_OBJ:
+	case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+	case DEMANGLE_COMPONENT_CAST:
+	case DEMANGLE_COMPONENT_CONVERSION:
+	case DEMANGLE_COMPONENT_NULLARY:
+	case DEMANGLE_COMPONENT_UNARY:
+	case DEMANGLE_COMPONENT_BINARY:
+	case DEMANGLE_COMPONENT_BINARY_ARGS:
+	case DEMANGLE_COMPONENT_TRINARY:
+	case DEMANGLE_COMPONENT_TRINARY_ARG1:
+	case DEMANGLE_COMPONENT_TRINARY_ARG2:
+	case DEMANGLE_COMPONENT_LITERAL:
+	case DEMANGLE_COMPONENT_LITERAL_NEG:
+	case DEMANGLE_COMPONENT_VENDOR_EXPR:
+	case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+	case DEMANGLE_COMPONENT_COMPOUND_NAME:
+	case DEMANGLE_COMPONENT_DECLTYPE:
+	case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+	case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+	case DEMANGLE_COMPONENT_PACK_EXPANSION:
+	case DEMANGLE_COMPONENT_TAGGED_NAME:
+	case DEMANGLE_COMPONENT_CLONE:
+	  recurse_left_right:
+		/* PR 89394 - Check for too much recursion.  */
+		if (dpi->recursion > DEMANGLE_RECURSION_LIMIT)
+			/* FIXME: There ought to be a way to report to the
+			   user that the recursion limit has been reached.  */
+			return;
+
+		++dpi->recursion;
+		d_count_templates_scopes(dpi, d_left(dc));
+		d_count_templates_scopes(dpi, d_right(dc));
+		--dpi->recursion;
+		break;
+
+	case DEMANGLE_COMPONENT_CTOR:
+		d_count_templates_scopes(dpi, dc->u.s_ctor.name);
+		break;
+
+	case DEMANGLE_COMPONENT_DTOR:
+		d_count_templates_scopes(dpi, dc->u.s_dtor.name);
+		break;
+
+	case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+		d_count_templates_scopes(dpi, dc->u.s_extended_operator.name);
+		break;
+
+	case DEMANGLE_COMPONENT_FIXED_TYPE:
+		d_count_templates_scopes(dpi, dc->u.s_fixed.length);
+		break;
+
+	case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+	case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+	case DEMANGLE_COMPONENT_MODULE_ENTITY:
+		d_count_templates_scopes(dpi, d_left(dc));
+		break;
+
+	case DEMANGLE_COMPONENT_LAMBDA:
+	case DEMANGLE_COMPONENT_DEFAULT_ARG:
+		d_count_templates_scopes(dpi, dc->u.s_unary_num.sub);
+		break;
+	}
+}
+
+/* Initialize a print information structure.  */
+
+static void
+d_print_init(struct d_print_info *dpi, demangle_callbackref callback, void=
 *opaque, struct demangle_component *dc)
+{
+	dpi->len =3D 0;
+	dpi->last_char =3D '\0';
+	dpi->templates =3D NULL;
+	dpi->modifiers =3D NULL;
+	dpi->pack_index =3D 0;
+	dpi->flush_count =3D 0;
+
+	dpi->callback =3D callback;
+	dpi->opaque =3D opaque;
+
+	dpi->demangle_failure =3D 0;
+	dpi->recursion =3D 0;
+	dpi->is_lambda_arg =3D 0;
+
+	dpi->component_stack =3D NULL;
+
+	dpi->saved_scopes =3D NULL;
+	dpi->next_saved_scope =3D 0;
+	dpi->num_saved_scopes =3D 0;
+
+	dpi->copy_templates =3D NULL;
+	dpi->next_copy_template =3D 0;
+	dpi->num_copy_templates =3D 0;
+
+	d_count_templates_scopes(dpi, dc);
+	/* If we did not reach the recursion limit, then reset the
+	   current recursion value back to 0, so that we can print
+	   the templates.  */
+	if (dpi->recursion < DEMANGLE_RECURSION_LIMIT)
+		dpi->recursion =3D 0;
+	dpi->num_copy_templates *=3D dpi->num_saved_scopes;
+
+	dpi->current_template =3D NULL;
+}
+
+/* Indicate that an error occurred during printing, and test for error.  */
+
+static inline void d_print_error(struct d_print_info *dpi)
+{
+	dpi->demangle_failure =3D 1;
+}
+
+static inline int d_print_saw_error(struct d_print_info *dpi)
+{
+	return dpi->demangle_failure !=3D 0;
+}
+
+/* Flush buffered characters to the callback.  */
+
+static inline void d_print_flush(struct d_print_info *dpi)
+{
+	dpi->buf[dpi->len] =3D '\0';
+	dpi->callback(dpi->buf, dpi->len, dpi->opaque);
+	dpi->len =3D 0;
+	dpi->flush_count++;
+}
+
+/* Append characters and buffers for printing.  */
+
+static inline void d_append_char(struct d_print_info *dpi, char c)
+{
+	if (dpi->len =3D=3D sizeof(dpi->buf) - 1)
+		d_print_flush(dpi);
+
+	dpi->buf[dpi->len++] =3D c;
+	dpi->last_char =3D c;
+}
+
+static inline void d_append_buffer(struct d_print_info *dpi, const char *s=
, size_t l)
+{
+	size_t i;
+
+	for (i =3D 0; i < l; i++)
+		d_append_char(dpi, s[i]);
+}
+
+static inline void d_append_string(struct d_print_info *dpi, const char *s)
+{
+	d_append_buffer(dpi, s, strlen(s));
+}
+
+static inline void d_append_num(struct d_print_info *dpi, int l)
+{
+	char buf[25];
+
+	sprintf(buf, "%d", l);
+	d_append_string(dpi, buf);
+}
+
+static inline char d_last_char(struct d_print_info *dpi)
+{
+	return dpi->last_char;
+}
+
+/* Turn components into a human readable string.  OPTIONS is the
+   options bits passed to the demangler.  DC is the tree to print.
+   CALLBACK is a function to call to flush demangled string segments
+   as they fill the intermediate buffer, and OPAQUE is a generalized
+   callback argument.  On success, this returns 1.  On failure,
+   it returns 0, indicating a bad parse.  It does not use heap
+   memory to build an output string, so cannot encounter memory
+   allocation failure.  */
+
+CP_STATIC_IF_GLIBCPP_V3
+	int
+cplus_demangle_print_callback(int options, struct demangle_component *dc, =
demangle_callbackref callback, void *opaque)
+{
+	struct d_print_info dpi;
+
+	d_print_init(&dpi, callback, opaque, dc);
+
+	{
+#ifdef CP_DYNAMIC_ARRAYS
+		/* Avoid zero-length VLAs, which are prohibited by the C99 standard
+		   and flagged as errors by Address Sanitizer.  */
+		__extension__ struct d_saved_scope scopes[(dpi.num_saved_scopes > 0) ? d=
pi.num_saved_scopes : 1];
+		__extension__ struct d_print_template temps[(dpi.num_copy_templates > 0)=
 ? dpi.num_copy_templates : 1];
+
+		dpi.saved_scopes =3D scopes;
+		dpi.copy_templates =3D temps;
+#else
+		dpi.saved_scopes =3D alloca(dpi.num_saved_scopes * sizeof(*dpi.saved_sco=
pes));
+		dpi.copy_templates =3D alloca(dpi.num_copy_templates * sizeof(*dpi.copy_=
templates));
+#endif
+
+		d_print_comp(&dpi, options, dc);
+	}
+
+	d_print_flush(&dpi);
+
+	return !d_print_saw_error(&dpi);
+}
+
+/* Turn components into a human readable string.  OPTIONS is the
+   options bits passed to the demangler.  DC is the tree to print.
+   ESTIMATE is a guess at the length of the result.  This returns a
+   string allocated by malloc, or NULL on error.  On success, this
+   sets *PALC to the size of the allocated buffer.  On failure, this
+   sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
+   failure.  */
+
+CP_STATIC_IF_GLIBCPP_V3
+	char *cplus_demangle_print(int options, struct demangle_component *dc, in=
t estimate, size_t *palc)
+{
+	struct d_growable_string dgs;
+
+	d_growable_string_init(&dgs, estimate);
+
+	if (!cplus_demangle_print_callback(options, dc, d_growable_string_callbac=
k_adapter, &dgs))
+	{
+		free(dgs.buf);
+		*palc =3D 0;
+		return NULL;
+	}
+
+	*palc =3D dgs.allocation_failure ? 1 : dgs.alc;
+	return dgs.buf;
+}
+
+/* Returns the I'th element of the template arglist ARGS, or NULL on
+   failure.  If I is negative, return the entire arglist.  */
+
+static struct demangle_component *d_index_template_argument(struct demangl=
e_component *args, int i)
+{
+	struct demangle_component *a;
+
+	if (i < 0)
+		/* Print the whole argument pack.  */
+		return args;
+
+	for (a =3D args; a !=3D NULL; a =3D d_right(a))
+	{
+		if (a->type !=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+			return NULL;
+		if (i <=3D 0)
+			break;
+		--i;
+	}
+	if (i !=3D 0 || a =3D=3D NULL)
+		return NULL;
+
+	return d_left(a);
+}
+
+/* Returns the template argument from the current context indicated by DC,
+   which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL.  */
+
+static struct demangle_component *d_lookup_template_argument(struct d_prin=
t_info *dpi,
+															 const struct demangle_component *dc)
+{
+	if (dpi->templates =3D=3D NULL)
+	{
+		d_print_error(dpi);
+		return NULL;
+	}
+
+	return d_index_template_argument(d_right(dpi->templates->template_decl), =
dc->u.s_number.number);
+}
+
+/* Returns a template argument pack used in DC (any will do), or NULL.  */
+
+static struct demangle_component *d_find_pack(struct d_print_info *dpi, co=
nst struct demangle_component *dc)
+{
+	struct demangle_component *a;
+
+	if (dc =3D=3D NULL)
+		return NULL;
+
+	switch (dc->type)
+	{
+	case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+		a =3D d_lookup_template_argument(dpi, dc);
+		if (a && a->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+			return a;
+		return NULL;
+
+	case DEMANGLE_COMPONENT_PACK_EXPANSION:
+		return NULL;
+
+	case DEMANGLE_COMPONENT_LAMBDA:
+	case DEMANGLE_COMPONENT_NAME:
+	case DEMANGLE_COMPONENT_TAGGED_NAME:
+	case DEMANGLE_COMPONENT_OPERATOR:
+	case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+	case DEMANGLE_COMPONENT_SUB_STD:
+	case DEMANGLE_COMPONENT_CHARACTER:
+	case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+	case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+	case DEMANGLE_COMPONENT_FIXED_TYPE:
+	case DEMANGLE_COMPONENT_DEFAULT_ARG:
+	case DEMANGLE_COMPONENT_NUMBER:
+		return NULL;
+
+	case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+		return d_find_pack(dpi, dc->u.s_extended_operator.name);
+	case DEMANGLE_COMPONENT_CTOR:
+		return d_find_pack(dpi, dc->u.s_ctor.name);
+	case DEMANGLE_COMPONENT_DTOR:
+		return d_find_pack(dpi, dc->u.s_dtor.name);
+
+	default:
+		a =3D d_find_pack(dpi, d_left(dc));
+		if (a)
+			return a;
+		return d_find_pack(dpi, d_right(dc));
+	}
+}
+
+/* Returns the length of the template argument pack DC.  */
+
+static int d_pack_length(const struct demangle_component *dc)
+{
+	int count =3D 0;
+
+	while (dc && dc->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST && d_lef=
t(dc) !=3D NULL)
+	{
+		++count;
+		dc =3D d_right(dc);
+	}
+	return count;
+}
+
+/* Returns the number of template args in DC, expanding any pack expansions
+   found there.  */
+
+static int d_args_length(struct d_print_info *dpi, const struct demangle_c=
omponent *dc)
+{
+	int count =3D 0;
+
+	for (; dc && dc->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST; dc =3D =
d_right(dc))
+	{
+		struct demangle_component *elt =3D d_left(dc);
+
+		if (elt =3D=3D NULL)
+			break;
+		if (elt->type =3D=3D DEMANGLE_COMPONENT_PACK_EXPANSION)
+		{
+			struct demangle_component *a =3D d_find_pack(dpi, d_left(elt));
+
+			count +=3D d_pack_length(a);
+		} else
+			++count;
+	}
+	return count;
+}
+
+/* DC is a component of a mangled expression.  Print it, wrapped in parens
+   if needed.  */
+
+static void d_print_subexpr(struct d_print_info *dpi, int options, struct =
demangle_component *dc)
+{
+	int simple =3D 0;
+
+	if (dc->type =3D=3D DEMANGLE_COMPONENT_NAME
+		|| dc->type =3D=3D DEMANGLE_COMPONENT_QUAL_NAME
+		|| dc->type =3D=3D DEMANGLE_COMPONENT_INITIALIZER_LIST || dc->type =3D=
=3D DEMANGLE_COMPONENT_FUNCTION_PARAM)
+		simple =3D 1;
+	if (!simple)
+		d_append_char(dpi, '(');
+	d_print_comp(dpi, options, dc);
+	if (!simple)
+		d_append_char(dpi, ')');
+}
+
+/* Save the current scope.  */
+
+static void d_save_scope(struct d_print_info *dpi, const struct demangle_c=
omponent *container)
+{
+	struct d_saved_scope *scope;
+	struct d_print_template *src,
+	**link;
+
+	if (dpi->next_saved_scope >=3D dpi->num_saved_scopes)
+	{
+		d_print_error(dpi);
+		return;
+	}
+	scope =3D &dpi->saved_scopes[dpi->next_saved_scope];
+	dpi->next_saved_scope++;
+
+	scope->container =3D container;
+	link =3D &scope->templates;
+
+	for (src =3D dpi->templates; src !=3D NULL; src =3D src->next)
+	{
+		struct d_print_template *dst;
+
+		if (dpi->next_copy_template >=3D dpi->num_copy_templates)
+		{
+			d_print_error(dpi);
+			return;
+		}
+		dst =3D &dpi->copy_templates[dpi->next_copy_template];
+		dpi->next_copy_template++;
+
+		dst->template_decl =3D src->template_decl;
+		*link =3D dst;
+		link =3D &dst->next;
+	}
+
+	*link =3D NULL;
+}
+
+/* Attempt to locate a previously saved scope.  Returns NULL if no
+   corresponding saved scope was found.  */
+
+static struct d_saved_scope *d_get_saved_scope(struct d_print_info *dpi, c=
onst struct demangle_component *container)
+{
+	int i;
+
+	for (i =3D 0; i < dpi->next_saved_scope; i++)
+		if (dpi->saved_scopes[i].container =3D=3D container)
+			return &dpi->saved_scopes[i];
+
+	return NULL;
+}
+
+/* If DC is a C++17 fold-expression, print it and return true; otherwise
+   return false.  */
+
+static int d_maybe_print_fold_expression(struct d_print_info *dpi, int opt=
ions, struct demangle_component *dc)
+{
+	struct demangle_component *ops,
+	*operator_,
+	*op1,
+	*op2;
+	int save_idx;
+
+	const char *fold_code =3D d_left(dc)->u.s_operator.op->code;
+
+	if (fold_code[0] !=3D 'f')
+		return 0;
+
+	ops =3D d_right(dc);
+	operator_ =3D d_left(ops);
+	op1 =3D d_right(ops);
+	op2 =3D 0;
+	if (op1->type =3D=3D DEMANGLE_COMPONENT_TRINARY_ARG2)
+	{
+		op2 =3D d_right(op1);
+		op1 =3D d_left(op1);
+	}
+
+	/* Print the whole pack.  */
+	save_idx =3D dpi->pack_index;
+	dpi->pack_index =3D -1;
+
+	switch (fold_code[1])
+	{
+		/* Unary left fold, (... + X).  */
+	case 'l':
+		d_append_string(dpi, "(...");
+		d_print_expr_op(dpi, options, operator_);
+		d_print_subexpr(dpi, options, op1);
+		d_append_char(dpi, ')');
+		break;
+
+		/* Unary right fold, (X + ...).  */
+	case 'r':
+		d_append_char(dpi, '(');
+		d_print_subexpr(dpi, options, op1);
+		d_print_expr_op(dpi, options, operator_);
+		d_append_string(dpi, "...)");
+		break;
+
+		/* Binary left fold, (42 + ... + X).  */
+	case 'L':
+		/* Binary right fold, (X + ... + 42).  */
+	case 'R':
+		d_append_char(dpi, '(');
+		d_print_subexpr(dpi, options, op1);
+		d_print_expr_op(dpi, options, operator_);
+		d_append_string(dpi, "...");
+		d_print_expr_op(dpi, options, operator_);
+		d_print_subexpr(dpi, options, op2);
+		d_append_char(dpi, ')');
+		break;
+	}
+
+	dpi->pack_index =3D save_idx;
+	return 1;
+}
+
+/* True iff DC represents a C99-style designated initializer.  */
+
+static int is_designated_init(struct demangle_component *dc)
+{
+	if (dc->type !=3D DEMANGLE_COMPONENT_BINARY && dc->type !=3D DEMANGLE_COM=
PONENT_TRINARY)
+		return 0;
+
+	struct demangle_component *op =3D d_left(dc);
+	const char *code =3D op->u.s_operator.op->code;
+
+	return (code[0] =3D=3D 'd' && (code[1] =3D=3D 'i' || code[1] =3D=3D 'x' |=
| code[1] =3D=3D 'X'));
+}
+
+/* If DC represents a C99-style designated initializer, print it and return
+   true; otherwise, return false.  */
+
+static int d_maybe_print_designated_init(struct d_print_info *dpi, int opt=
ions, struct demangle_component *dc)
+{
+	if (!is_designated_init(dc))
+		return 0;
+
+	const char *code =3D d_left(dc)->u.s_operator.op->code;
+
+	struct demangle_component *operands =3D d_right(dc);
+	struct demangle_component *op1 =3D d_left(operands);
+	struct demangle_component *op2 =3D d_right(operands);
+
+	if (code[1] =3D=3D 'i')
+		d_append_char(dpi, '.');
+	else
+		d_append_char(dpi, '[');
+
+	d_print_comp(dpi, options, op1);
+	if (code[1] =3D=3D 'X')
+	{
+		d_append_string(dpi, " ... ");
+		d_print_comp(dpi, options, d_left(op2));
+		op2 =3D d_right(op2);
+	}
+	if (code[1] !=3D 'i')
+		d_append_char(dpi, ']');
+	if (is_designated_init(op2))
+	{
+		/* Don't put '=3D' or '(' between chained designators.  */
+		d_print_comp(dpi, options, op2);
+	} else
+	{
+		d_append_char(dpi, '=3D');
+		d_print_subexpr(dpi, options, op2);
+	}
+	return 1;
+}
+
+/* Subroutine to handle components.  */
+
+static void d_print_comp_inner(struct d_print_info *dpi, int options, stru=
ct demangle_component *dc)
+{
+	/* Magic variable to let reference smashing skip over the next modifier
+	   without needing to modify *dc.  */
+	struct demangle_component *mod_inner =3D NULL;
+
+	/* Variable used to store the current templates while a previously
+	   captured scope is used.  */
+	struct d_print_template *saved_templates;
+
+	/* Nonzero if templates have been stored in the above variable.  */
+	int need_template_restore =3D 0;
+
+	if (dc =3D=3D NULL)
+	{
+		d_print_error(dpi);
+		return;
+	}
+	if (d_print_saw_error(dpi))
+		return;
+
+	switch (dc->type)
+	{
+	case DEMANGLE_COMPONENT_NAME:
+		if ((options & DMGL_JAVA) =3D=3D 0)
+			d_append_buffer(dpi, dc->u.s_name.s, dc->u.s_name.len);
+		else
+			d_print_java_identifier(dpi, dc->u.s_name.s, dc->u.s_name.len);
+		return;
+
+	case DEMANGLE_COMPONENT_TAGGED_NAME:
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_string(dpi, "[abi:");
+		d_print_comp(dpi, options, d_right(dc));
+		d_append_char(dpi, ']');
+		return;
+
+	case DEMANGLE_COMPONENT_STRUCTURED_BINDING:
+		d_append_char(dpi, '[');
+		for (;;)
+		{
+			d_print_comp(dpi, options, d_left(dc));
+			dc =3D d_right(dc);
+			if (!dc)
+				break;
+			d_append_string(dpi, ", ");
+		}
+		d_append_char(dpi, ']');
+		return;
+
+	case DEMANGLE_COMPONENT_MODULE_ENTITY:
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_char(dpi, '@');
+		d_print_comp(dpi, options, d_right(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_MODULE_NAME:
+	case DEMANGLE_COMPONENT_MODULE_PARTITION:
+		{
+			if (d_left(dc))
+				d_print_comp(dpi, options, d_left(dc));
+			char c =3D dc->type =3D=3D DEMANGLE_COMPONENT_MODULE_PARTITION ? ':' : =
d_left(dc) ? '.' : 0;
+
+			if (c)
+				d_append_char(dpi, c);
+			d_print_comp(dpi, options, d_right(dc));
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+		d_print_comp(dpi, options, d_left(dc));
+		if ((options & DMGL_JAVA) =3D=3D 0)
+			d_append_string(dpi, "::");
+		else
+			d_append_char(dpi, '.');
+		{
+			struct demangle_component *local_name =3D d_right(dc);
+
+			if (local_name->type =3D=3D DEMANGLE_COMPONENT_DEFAULT_ARG)
+			{
+				d_append_string(dpi, "{default arg#");
+				d_append_num(dpi, local_name->u.s_unary_num.num + 1);
+				d_append_string(dpi, "}::");
+				local_name =3D local_name->u.s_unary_num.sub;
+			}
+			d_print_comp(dpi, options, local_name);
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+		{
+			struct d_print_mod *hold_modifiers;
+			struct demangle_component *typed_name;
+			struct d_print_mod adpm[4];
+			unsigned int i;
+			struct d_print_template dpt;
+
+			/* Pass the name down to the type so that it can be printed in
+			   the right place for the type.  We also have to pass down
+			   any CV-qualifiers, which apply to the this parameter.  */
+			hold_modifiers =3D dpi->modifiers;
+			dpi->modifiers =3D 0;
+			i =3D 0;
+			typed_name =3D d_left(dc);
+			while (typed_name !=3D NULL)
+			{
+				if (i >=3D sizeof adpm / sizeof adpm[0])
+				{
+					d_print_error(dpi);
+					return;
+				}
+
+				adpm[i].next =3D dpi->modifiers;
+				dpi->modifiers =3D &adpm[i];
+				adpm[i].mod =3D typed_name;
+				adpm[i].printed =3D 0;
+				adpm[i].templates =3D dpi->templates;
+				++i;
+
+				if (!is_fnqual_component_type(typed_name->type))
+					break;
+
+				typed_name =3D d_left(typed_name);
+			}
+
+			if (typed_name =3D=3D NULL)
+			{
+				d_print_error(dpi);
+				return;
+			}
+
+			/* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+			   there may be CV-qualifiers on its right argument which
+			   really apply here; this happens when parsing a class that
+			   is local to a function.  */
+			if (typed_name->type =3D=3D DEMANGLE_COMPONENT_LOCAL_NAME)
+			{
+				typed_name =3D d_right(typed_name);
+				if (typed_name->type =3D=3D DEMANGLE_COMPONENT_DEFAULT_ARG)
+					typed_name =3D typed_name->u.s_unary_num.sub;
+				while (typed_name !=3D NULL && is_fnqual_component_type(typed_name->ty=
pe))
+				{
+					if (i >=3D sizeof adpm / sizeof adpm[0])
+					{
+						d_print_error(dpi);
+						return;
+					}
+
+					adpm[i] =3D adpm[i - 1];
+					adpm[i].next =3D &adpm[i - 1];
+					dpi->modifiers =3D &adpm[i];
+
+					adpm[i - 1].mod =3D typed_name;
+					adpm[i - 1].printed =3D 0;
+					adpm[i - 1].templates =3D dpi->templates;
+					++i;
+
+					typed_name =3D d_left(typed_name);
+				}
+				if (typed_name =3D=3D NULL)
+				{
+					d_print_error(dpi);
+					return;
+				}
+			}
+
+			/* If typed_name is a template, then it applies to the
+			   function type as well.  */
+			if (typed_name->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE)
+			{
+				dpt.next =3D dpi->templates;
+				dpi->templates =3D &dpt;
+				dpt.template_decl =3D typed_name;
+			}
+
+			d_print_comp(dpi, options, d_right(dc));
+
+			if (typed_name->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE)
+				dpi->templates =3D dpt.next;
+
+			/* If the modifiers didn't get printed by the type, print them
+			   now.  */
+			while (i > 0)
+			{
+				--i;
+				if (!adpm[i].printed)
+				{
+					d_append_char(dpi, ' ');
+					d_print_mod(dpi, options, adpm[i].mod);
+				}
+			}
+
+			dpi->modifiers =3D hold_modifiers;
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_TEMPLATE:
+		{
+			struct d_print_mod *hold_dpm;
+			struct demangle_component *dcl;
+			const struct demangle_component *hold_current;
+
+			/* This template may need to be referenced by a cast operator
+			   contained in its subtree.  */
+			hold_current =3D dpi->current_template;
+			dpi->current_template =3D dc;
+
+			/* Don't push modifiers into a template definition.  Doing so
+			   could give the wrong definition for a template argument.
+			   Instead, treat the template essentially as a name.  */
+
+			hold_dpm =3D dpi->modifiers;
+			dpi->modifiers =3D NULL;
+
+			dcl =3D d_left(dc);
+
+			if ((options & DMGL_JAVA) !=3D 0
+				&& dcl->type =3D=3D DEMANGLE_COMPONENT_NAME
+				&& dcl->u.s_name.len =3D=3D 6 && strncmp(dcl->u.s_name.s, "JArray", 6)=
 =3D=3D 0)
+			{
+				/* Special-case Java arrays, so that JArray<TYPE> appears
+				   instead as TYPE[].  */
+
+				d_print_comp(dpi, options, d_right(dc));
+				d_append_string(dpi, "[]");
+			} else
+			{
+				d_print_comp(dpi, options, dcl);
+				if (d_last_char(dpi) =3D=3D '<')
+					d_append_char(dpi, ' ');
+				d_append_char(dpi, '<');
+				d_print_comp(dpi, options, d_right(dc));
+				/* Avoid generating two consecutive '>' characters, to avoid
+				   the C++ syntactic ambiguity.  */
+				if (d_last_char(dpi) =3D=3D '>')
+					d_append_char(dpi, ' ');
+				d_append_char(dpi, '>');
+			}
+
+			dpi->modifiers =3D hold_dpm;
+			dpi->current_template =3D hold_current;
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+		if (dpi->is_lambda_arg)
+		{
+			/* Show the template parm index, as that's how g++ displays
+			   these, and future proofs us against potential
+			   '[]<typename T> (T *a, T *b) {...}'.  */
+			d_append_buffer(dpi, "auto:", 5);
+			d_append_num(dpi, dc->u.s_number.number + 1);
+		} else
+		{
+			struct d_print_template *hold_dpt;
+			struct demangle_component *a =3D d_lookup_template_argument(dpi, dc);
+
+			if (a && a->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+				a =3D d_index_template_argument(a, dpi->pack_index);
+
+			if (a =3D=3D NULL)
+			{
+				d_print_error(dpi);
+				return;
+			}
+
+			/* While processing this parameter, we need to pop the list
+			   of templates.  This is because the template parameter may
+			   itself be a reference to a parameter of an outer
+			   template.  */
+
+			hold_dpt =3D dpi->templates;
+			dpi->templates =3D hold_dpt->next;
+
+			d_print_comp(dpi, options, a);
+
+			dpi->templates =3D hold_dpt;
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_TPARM_OBJ:
+		d_append_string(dpi, "template parameter object for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_CTOR:
+		d_print_comp(dpi, options, dc->u.s_ctor.name);
+		return;
+
+	case DEMANGLE_COMPONENT_DTOR:
+		d_append_char(dpi, '~');
+		d_print_comp(dpi, options, dc->u.s_dtor.name);
+		return;
+
+	case DEMANGLE_COMPONENT_MODULE_INIT:
+		d_append_string(dpi, "initializer for module ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_VTABLE:
+		d_append_string(dpi, "vtable for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_VTT:
+		d_append_string(dpi, "VTT for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+		d_append_string(dpi, "construction vtable for ");
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_string(dpi, "-in-");
+		d_print_comp(dpi, options, d_right(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TYPEINFO:
+		d_append_string(dpi, "typeinfo for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+		d_append_string(dpi, "typeinfo name for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TYPEINFO_FN:
+		d_append_string(dpi, "typeinfo fn for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_THUNK:
+		d_append_string(dpi, "non-virtual thunk to ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+		d_append_string(dpi, "virtual thunk to ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+		d_append_string(dpi, "covariant return thunk to ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_JAVA_CLASS:
+		d_append_string(dpi, "java Class for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_GUARD:
+		d_append_string(dpi, "guard variable for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TLS_INIT:
+		d_append_string(dpi, "TLS init function for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TLS_WRAPPER:
+		d_append_string(dpi, "TLS wrapper function for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_REFTEMP:
+		d_append_string(dpi, "reference temporary #");
+		d_print_comp(dpi, options, d_right(dc));
+		d_append_string(dpi, " for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+		d_append_string(dpi, "hidden alias for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+		d_append_string(dpi, "transaction clone for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+		d_append_string(dpi, "non-transaction clone for ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_SUB_STD:
+		d_append_buffer(dpi, dc->u.s_string.string, dc->u.s_string.len);
+		return;
+
+	case DEMANGLE_COMPONENT_RESTRICT:
+	case DEMANGLE_COMPONENT_VOLATILE:
+	case DEMANGLE_COMPONENT_CONST:
+		{
+			struct d_print_mod *pdpm;
+
+			/* When printing arrays, it's possible to have cases where the
+			   same CV-qualifier gets pushed on the stack multiple times.
+			   We only need to print it once.  */
+
+			for (pdpm =3D dpi->modifiers; pdpm !=3D NULL; pdpm =3D pdpm->next)
+			{
+				if (!pdpm->printed)
+				{
+					if (pdpm->mod->type !=3D DEMANGLE_COMPONENT_RESTRICT
+						&& pdpm->mod->type !=3D DEMANGLE_COMPONENT_VOLATILE
+						&& pdpm->mod->type !=3D DEMANGLE_COMPONENT_CONST)
+						break;
+					if (pdpm->mod->type =3D=3D dc->type)
+					{
+						d_print_comp(dpi, options, d_left(dc));
+						return;
+					}
+				}
+			}
+		}
+		goto modifier;
+
+	case DEMANGLE_COMPONENT_REFERENCE:
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+		{
+			/* Handle reference smashing: & + && =3D &.  */
+			struct demangle_component *sub =3D d_left(dc);
+
+			if (!dpi->is_lambda_arg && sub->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE=
_PARAM)
+			{
+				struct d_saved_scope *scope =3D d_get_saved_scope(dpi, sub);
+				struct demangle_component *a;
+
+				if (scope =3D=3D NULL)
+				{
+					/* This is the first time SUB has been traversed.
+					   We need to capture the current templates so
+					   they can be restored if SUB is reentered as a
+					   substitution.  */
+					d_save_scope(dpi, sub);
+					if (d_print_saw_error(dpi))
+						return;
+				} else
+				{
+					const struct d_component_stack *dcse;
+					int found_self_or_parent =3D 0;
+
+					/* This traversal is reentering SUB as a substition.
+					   If we are not beneath SUB or DC in the tree then we
+					   need to restore SUB's template stack temporarily.  */
+					for (dcse =3D dpi->component_stack; dcse !=3D NULL; dcse =3D dcse->pa=
rent)
+					{
+						if (dcse->dc =3D=3D sub || (dcse->dc =3D=3D dc && dcse !=3D dpi->com=
ponent_stack))
+						{
+							found_self_or_parent =3D 1;
+							break;
+						}
+					}
+
+					if (!found_self_or_parent)
+					{
+						saved_templates =3D dpi->templates;
+						dpi->templates =3D scope->templates;
+						need_template_restore =3D 1;
+					}
+				}
+
+				a =3D d_lookup_template_argument(dpi, sub);
+				if (a && a->type =3D=3D DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+					a =3D d_index_template_argument(a, dpi->pack_index);
+
+				if (a =3D=3D NULL)
+				{
+					if (need_template_restore)
+						dpi->templates =3D saved_templates;
+
+					d_print_error(dpi);
+					return;
+				}
+
+				sub =3D a;
+			}
+
+			if (sub->type =3D=3D DEMANGLE_COMPONENT_REFERENCE || sub->type =3D=3D d=
c->type)
+				dc =3D sub;
+			else if (sub->type =3D=3D DEMANGLE_COMPONENT_RVALUE_REFERENCE)
+				mod_inner =3D d_left(sub);
+		}
+		/* Fall through.  */
+
+	case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+	case DEMANGLE_COMPONENT_POINTER:
+	case DEMANGLE_COMPONENT_COMPLEX:
+	case DEMANGLE_COMPONENT_IMAGINARY:
+	  FNQUAL_COMPONENT_CASE:
+	  modifier:
+		{
+			/* We keep a list of modifiers on the stack.  */
+			struct d_print_mod dpm;
+
+			dpm.next =3D dpi->modifiers;
+			dpi->modifiers =3D &dpm;
+			dpm.mod =3D dc;
+			dpm.printed =3D 0;
+			dpm.templates =3D dpi->templates;
+
+			if (!mod_inner)
+				mod_inner =3D d_left(dc);
+
+			d_print_comp(dpi, options, mod_inner);
+
+			/* If the modifier didn't get printed by the type, print it
+			   now.  */
+			if (!dpm.printed)
+				d_print_mod(dpi, options, dc);
+
+			dpi->modifiers =3D dpm.next;
+
+			if (need_template_restore)
+				dpi->templates =3D saved_templates;
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+		if ((options & DMGL_JAVA) =3D=3D 0)
+			d_append_buffer(dpi, dc->u.s_builtin.type->name, dc->u.s_builtin.type->=
len);
+		else
+			d_append_buffer(dpi, dc->u.s_builtin.type->java_name, dc->u.s_builtin.t=
ype->java_len);
+		return;
+
+	case DEMANGLE_COMPONENT_VENDOR_TYPE:
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+		{
+			if ((options & DMGL_RET_POSTFIX) !=3D 0)
+				d_print_function_type(dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DRO=
P), dc, dpi->modifiers);
+
+			/* Print return type if present */
+			if (d_left(dc) !=3D NULL && (options & DMGL_RET_POSTFIX) !=3D 0)
+				d_print_comp(dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), d_lef=
t(dc));
+			else if (d_left(dc) !=3D NULL && (options & DMGL_RET_DROP) =3D=3D 0)
+			{
+				struct d_print_mod dpm;
+
+				/* We must pass this type down as a modifier in order to
+				   print it in the right location.  */
+				dpm.next =3D dpi->modifiers;
+				dpi->modifiers =3D &dpm;
+				dpm.mod =3D dc;
+				dpm.printed =3D 0;
+				dpm.templates =3D dpi->templates;
+
+				d_print_comp(dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), d_lef=
t(dc));
+
+				dpi->modifiers =3D dpm.next;
+
+				if (dpm.printed)
+					return;
+
+				/* In standard prefix notation, there is a space between the
+				   return type and the function signature.  */
+				if ((options & DMGL_RET_POSTFIX) =3D=3D 0)
+					d_append_char(dpi, ' ');
+			}
+
+			if ((options & DMGL_RET_POSTFIX) =3D=3D 0)
+				d_print_function_type(dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DRO=
P), dc, dpi->modifiers);
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+		{
+			struct d_print_mod *hold_modifiers;
+			struct d_print_mod adpm[4];
+			unsigned int i;
+			struct d_print_mod *pdpm;
+
+			/* We must pass this type down as a modifier in order to print
+			   multi-dimensional arrays correctly.  If the array itself is
+			   CV-qualified, we act as though the element type were
+			   CV-qualified.  We do this by copying the modifiers down
+			   rather than fiddling pointers, so that we don't wind up
+			   with a d_print_mod higher on the stack pointing into our
+			   stack frame after we return.  */
+
+			hold_modifiers =3D dpi->modifiers;
+
+			adpm[0].next =3D hold_modifiers;
+			dpi->modifiers =3D &adpm[0];
+			adpm[0].mod =3D dc;
+			adpm[0].printed =3D 0;
+			adpm[0].templates =3D dpi->templates;
+
+			i =3D 1;
+			pdpm =3D hold_modifiers;
+			while (pdpm !=3D NULL
+				   && (pdpm->mod->type =3D=3D DEMANGLE_COMPONENT_RESTRICT
+					   || pdpm->mod->type =3D=3D DEMANGLE_COMPONENT_VOLATILE
+					   || pdpm->mod->type =3D=3D DEMANGLE_COMPONENT_CONST))
+			{
+				if (!pdpm->printed)
+				{
+					if (i >=3D sizeof adpm / sizeof adpm[0])
+					{
+						d_print_error(dpi);
+						return;
+					}
+
+					adpm[i] =3D *pdpm;
+					adpm[i].next =3D dpi->modifiers;
+					dpi->modifiers =3D &adpm[i];
+					pdpm->printed =3D 1;
+					++i;
+				}
+
+				pdpm =3D pdpm->next;
+			}
+
+			d_print_comp(dpi, options, d_right(dc));
+
+			dpi->modifiers =3D hold_modifiers;
+
+			if (adpm[0].printed)
+				return;
+
+			while (i > 1)
+			{
+				--i;
+				d_print_mod(dpi, options, adpm[i].mod);
+			}
+
+			d_print_array_type(dpi, options, dc, dpi->modifiers);
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+	case DEMANGLE_COMPONENT_VECTOR_TYPE:
+		{
+			struct d_print_mod dpm;
+
+			dpm.next =3D dpi->modifiers;
+			dpi->modifiers =3D &dpm;
+			dpm.mod =3D dc;
+			dpm.printed =3D 0;
+			dpm.templates =3D dpi->templates;
+
+			d_print_comp(dpi, options, d_right(dc));
+
+			/* If the modifier didn't get printed by the type, print it
+			   now.  */
+			if (!dpm.printed)
+				d_print_mod(dpi, options, dc);
+
+			dpi->modifiers =3D dpm.next;
+
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_FIXED_TYPE:
+		if (dc->u.s_fixed.sat)
+			d_append_string(dpi, "_Sat ");
+		/* Don't print "int _Accum".  */
+		if (dc->u.s_fixed.length->u.s_builtin.type !=3D &cplus_demangle_builtin_=
types['i' - 'a'])
+		{
+			d_print_comp(dpi, options, dc->u.s_fixed.length);
+			d_append_char(dpi, ' ');
+		}
+		if (dc->u.s_fixed.accum)
+			d_append_string(dpi, "_Accum");
+		else
+			d_append_string(dpi, "_Fract");
+		return;
+
+	case DEMANGLE_COMPONENT_ARGLIST:
+	case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+		if (d_left(dc) !=3D NULL)
+			d_print_comp(dpi, options, d_left(dc));
+		if (d_right(dc) !=3D NULL)
+		{
+			size_t len;
+			unsigned long int flush_count;
+
+			/* Make sure ", " isn't flushed by d_append_string, otherwise
+			   dpi->len -=3D 2 wouldn't work.  */
+			if (dpi->len >=3D sizeof(dpi->buf) - 2)
+				d_print_flush(dpi);
+			d_append_string(dpi, ", ");
+			len =3D dpi->len;
+			flush_count =3D dpi->flush_count;
+			d_print_comp(dpi, options, d_right(dc));
+			/* If that didn't print anything (which can happen with empty
+			   template argument packs), remove the comma and space.  */
+			if (dpi->flush_count =3D=3D flush_count && dpi->len =3D=3D len)
+				dpi->len -=3D 2;
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+		{
+			struct demangle_component *type =3D d_left(dc);
+			struct demangle_component *list =3D d_right(dc);
+
+			if (type)
+				d_print_comp(dpi, options, type);
+			d_append_char(dpi, '{');
+			d_print_comp(dpi, options, list);
+			d_append_char(dpi, '}');
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_OPERATOR:
+		{
+			const struct demangle_operator_info *op =3D dc->u.s_operator.op;
+			int len =3D op->len;
+
+			d_append_string(dpi, "operator");
+			/* Add a space before new/delete.  */
+			if (IS_LOWER(op->name[0]))
+				d_append_char(dpi, ' ');
+			/* Omit a trailing space.  */
+			if (op->name[len - 1] =3D=3D ' ')
+				--len;
+			d_append_buffer(dpi, op->name, len);
+			return;
+		}
+
+	case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+		d_append_string(dpi, "operator ");
+		d_print_comp(dpi, options, dc->u.s_extended_operator.name);
+		return;
+
+	case DEMANGLE_COMPONENT_CONVERSION:
+		d_append_string(dpi, "operator ");
+		d_print_conversion(dpi, options, dc);
+		return;
+
+	case DEMANGLE_COMPONENT_NULLARY:
+		d_print_expr_op(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_UNARY:
+		{
+			struct demangle_component *op =3D d_left(dc);
+			struct demangle_component *operand =3D d_right(dc);
+			const char *code =3D NULL;
+
+			if (op->type =3D=3D DEMANGLE_COMPONENT_OPERATOR)
+			{
+				code =3D op->u.s_operator.op->code;
+				if (!strcmp(code, "ad"))
+				{
+					/* Don't print the argument list for the address of a
+					   function.  */
+					if (operand->type =3D=3D DEMANGLE_COMPONENT_TYPED_NAME
+						&& d_left(operand)->type =3D=3D DEMANGLE_COMPONENT_QUAL_NAME
+						&& d_right(operand)->type =3D=3D DEMANGLE_COMPONENT_FUNCTION_TYPE)
+						operand =3D d_left(operand);
+				}
+				if (operand->type =3D=3D DEMANGLE_COMPONENT_BINARY_ARGS)
+				{
+					/* This indicates a suffix operator.  */
+					operand =3D d_left(operand);
+					d_print_subexpr(dpi, options, operand);
+					d_print_expr_op(dpi, options, op);
+					return;
+				}
+			}
+
+			/* For sizeof..., just print the pack length.  */
+			if (code && !strcmp(code, "sZ"))
+			{
+				struct demangle_component *a =3D d_find_pack(dpi, operand);
+				int len =3D d_pack_length(a);
+
+				d_append_num(dpi, len);
+				return;
+			} else if (code && !strcmp(code, "sP"))
+			{
+				int len =3D d_args_length(dpi, operand);
+
+				d_append_num(dpi, len);
+				return;
+			}
+
+			if (op->type !=3D DEMANGLE_COMPONENT_CAST)
+				d_print_expr_op(dpi, options, op);
+			else
+			{
+				d_append_char(dpi, '(');
+				d_print_cast(dpi, options, op);
+				d_append_char(dpi, ')');
+			}
+			if (code && !strcmp(code, "gs"))
+				/* Avoid parens after '::'.  */
+				d_print_comp(dpi, options, operand);
+			else if (code && !strcmp(code, "st"))
+				/* Always print parens for sizeof (type).  */
+			{
+				d_append_char(dpi, '(');
+				d_print_comp(dpi, options, operand);
+				d_append_char(dpi, ')');
+			} else
+				d_print_subexpr(dpi, options, operand);
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_BINARY:
+		if (d_right(dc)->type !=3D DEMANGLE_COMPONENT_BINARY_ARGS)
+		{
+			d_print_error(dpi);
+			return;
+		}
+
+		if (op_is_new_cast(d_left(dc)))
+		{
+			d_print_expr_op(dpi, options, d_left(dc));
+			d_append_char(dpi, '<');
+			d_print_comp(dpi, options, d_left(d_right(dc)));
+			d_append_string(dpi, ">(");
+			d_print_comp(dpi, options, d_right(d_right(dc)));
+			d_append_char(dpi, ')');
+			return;
+		}
+
+		if (d_maybe_print_fold_expression(dpi, options, dc))
+			return;
+
+		if (d_maybe_print_designated_init(dpi, options, dc))
+			return;
+
+		/* We wrap an expression which uses the greater-than operator in
+		   an extra layer of parens so that it does not get confused
+		   with the '>' which ends the template parameters.  */
+		if (d_left(dc)->type =3D=3D DEMANGLE_COMPONENT_OPERATOR
+			&& d_left(dc)->u.s_operator.op->len =3D=3D 1 && d_left(dc)->u.s_operato=
r.op->name[0] =3D=3D '>')
+			d_append_char(dpi, '(');
+
+		if (strcmp(d_left(dc)->u.s_operator.op->code, "cl") =3D=3D 0
+			&& d_left(d_right(dc))->type =3D=3D DEMANGLE_COMPONENT_TYPED_NAME)
+		{
+			/* Function call used in an expression should not have printed types
+			   of the function arguments.  Values of the function arguments still
+			   get printed below.  */
+
+			const struct demangle_component *func =3D d_left(d_right(dc));
+
+			if (d_right(func)->type !=3D DEMANGLE_COMPONENT_FUNCTION_TYPE)
+				d_print_error(dpi);
+			d_print_subexpr(dpi, options, d_left(func));
+		} else
+			d_print_subexpr(dpi, options, d_left(d_right(dc)));
+		if (strcmp(d_left(dc)->u.s_operator.op->code, "ix") =3D=3D 0)
+		{
+			d_append_char(dpi, '[');
+			d_print_comp(dpi, options, d_right(d_right(dc)));
+			d_append_char(dpi, ']');
+		} else
+		{
+			if (strcmp(d_left(dc)->u.s_operator.op->code, "cl") !=3D 0)
+				d_print_expr_op(dpi, options, d_left(dc));
+			d_print_subexpr(dpi, options, d_right(d_right(dc)));
+		}
+
+		if (d_left(dc)->type =3D=3D DEMANGLE_COMPONENT_OPERATOR
+			&& d_left(dc)->u.s_operator.op->len =3D=3D 1 && d_left(dc)->u.s_operato=
r.op->name[0] =3D=3D '>')
+			d_append_char(dpi, ')');
+
+		return;
+
+	case DEMANGLE_COMPONENT_BINARY_ARGS:
+		/* We should only see this as part of DEMANGLE_COMPONENT_BINARY.  */
+		d_print_error(dpi);
+		return;
+
+	case DEMANGLE_COMPONENT_TRINARY:
+		if (d_right(dc)->type !=3D DEMANGLE_COMPONENT_TRINARY_ARG1
+			|| d_right(d_right(dc))->type !=3D DEMANGLE_COMPONENT_TRINARY_ARG2)
+		{
+			d_print_error(dpi);
+			return;
+		}
+		if (d_maybe_print_fold_expression(dpi, options, dc))
+			return;
+		if (d_maybe_print_designated_init(dpi, options, dc))
+			return;
+		{
+			struct demangle_component *op =3D d_left(dc);
+			struct demangle_component *first =3D d_left(d_right(dc));
+			struct demangle_component *second =3D d_left(d_right(d_right(dc)));
+			struct demangle_component *third =3D d_right(d_right(d_right(dc)));
+
+			if (!strcmp(op->u.s_operator.op->code, "qu"))
+			{
+				d_print_subexpr(dpi, options, first);
+				d_print_expr_op(dpi, options, op);
+				d_print_subexpr(dpi, options, second);
+				d_append_string(dpi, " : ");
+				d_print_subexpr(dpi, options, third);
+			} else
+			{
+				d_append_string(dpi, "new ");
+				if (d_left(first) !=3D NULL)
+				{
+					d_print_subexpr(dpi, options, first);
+					d_append_char(dpi, ' ');
+				}
+				d_print_comp(dpi, options, second);
+				if (third)
+					d_print_subexpr(dpi, options, third);
+			}
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_TRINARY_ARG1:
+	case DEMANGLE_COMPONENT_TRINARY_ARG2:
+		/* We should only see these are part of DEMANGLE_COMPONENT_TRINARY.  */
+		d_print_error(dpi);
+		return;
+
+	case DEMANGLE_COMPONENT_LITERAL:
+	case DEMANGLE_COMPONENT_LITERAL_NEG:
+		{
+			enum d_builtin_type_print tp;
+
+			/* For some builtin types, produce simpler output.  */
+			tp =3D D_PRINT_DEFAULT;
+			if (d_left(dc)->type =3D=3D DEMANGLE_COMPONENT_BUILTIN_TYPE)
+			{
+				tp =3D d_left(dc)->u.s_builtin.type->print;
+				switch (tp)
+				{
+				case D_PRINT_INT:
+				case D_PRINT_UNSIGNED:
+				case D_PRINT_LONG:
+				case D_PRINT_UNSIGNED_LONG:
+				case D_PRINT_LONG_LONG:
+				case D_PRINT_UNSIGNED_LONG_LONG:
+					if (d_right(dc)->type =3D=3D DEMANGLE_COMPONENT_NAME)
+					{
+						if (dc->type =3D=3D DEMANGLE_COMPONENT_LITERAL_NEG)
+							d_append_char(dpi, '-');
+						d_print_comp(dpi, options, d_right(dc));
+						switch (tp)
+						{
+						default:
+							break;
+						case D_PRINT_UNSIGNED:
+							d_append_char(dpi, 'u');
+							break;
+						case D_PRINT_LONG:
+							d_append_char(dpi, 'l');
+							break;
+						case D_PRINT_UNSIGNED_LONG:
+							d_append_string(dpi, "ul");
+							break;
+						case D_PRINT_LONG_LONG:
+							d_append_string(dpi, "ll");
+							break;
+						case D_PRINT_UNSIGNED_LONG_LONG:
+							d_append_string(dpi, "ull");
+							break;
+						}
+						return;
+					}
+					break;
+
+				case D_PRINT_BOOL:
+					if (d_right(dc)->type =3D=3D DEMANGLE_COMPONENT_NAME
+						&& d_right(dc)->u.s_name.len =3D=3D 1 && dc->type =3D=3D DEMANGLE_CO=
MPONENT_LITERAL)
+					{
+						switch (d_right(dc)->u.s_name.s[0])
+						{
+						case '0':
+							d_append_string(dpi, "false");
+							return;
+						case '1':
+							d_append_string(dpi, "true");
+							return;
+						default:
+							break;
+						}
+					}
+					break;
+
+				default:
+					break;
+				}
+			}
+
+			d_append_char(dpi, '(');
+			d_print_comp(dpi, options, d_left(dc));
+			d_append_char(dpi, ')');
+			if (dc->type =3D=3D DEMANGLE_COMPONENT_LITERAL_NEG)
+				d_append_char(dpi, '-');
+			if (tp =3D=3D D_PRINT_FLOAT)
+				d_append_char(dpi, '[');
+			d_print_comp(dpi, options, d_right(dc));
+			if (tp =3D=3D D_PRINT_FLOAT)
+				d_append_char(dpi, ']');
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_VENDOR_EXPR:
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_char(dpi, '(');
+		d_print_comp(dpi, options, d_right(dc));
+		d_append_char(dpi, ')');
+		return;
+
+	case DEMANGLE_COMPONENT_NUMBER:
+		d_append_num(dpi, dc->u.s_number.number);
+		return;
+
+	case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+		d_append_string(dpi, "java resource ");
+		d_print_comp(dpi, options, d_left(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_COMPOUND_NAME:
+		d_print_comp(dpi, options, d_left(dc));
+		d_print_comp(dpi, options, d_right(dc));
+		return;
+
+	case DEMANGLE_COMPONENT_CHARACTER:
+		d_append_char(dpi, dc->u.s_character.character);
+		return;
+
+	case DEMANGLE_COMPONENT_DECLTYPE:
+		d_append_string(dpi, "decltype (");
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_char(dpi, ')');
+		return;
+
+	case DEMANGLE_COMPONENT_PACK_EXPANSION:
+		{
+			int len;
+			int i;
+			struct demangle_component *a =3D d_find_pack(dpi, d_left(dc));
+
+			if (a =3D=3D NULL)
+			{
+				/* d_find_pack won't find anything if the only packs involved
+				   in this expansion are function parameter packs; in that
+				   case, just print the pattern and "...".  */
+				d_print_subexpr(dpi, options, d_left(dc));
+				d_append_string(dpi, "...");
+				return;
+			}
+
+			len =3D d_pack_length(a);
+			dc =3D d_left(dc);
+			for (i =3D 0; i < len; ++i)
+			{
+				dpi->pack_index =3D i;
+				d_print_comp(dpi, options, dc);
+				if (i < len - 1)
+					d_append_string(dpi, ", ");
+			}
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+		{
+			long num =3D dc->u.s_number.number;
+
+			if (num =3D=3D 0)
+				d_append_string(dpi, "this");
+			else
+			{
+				d_append_string(dpi, "{parm#");
+				d_append_num(dpi, num);
+				d_append_char(dpi, '}');
+			}
+		}
+		return;
+
+	case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+		d_append_string(dpi, "global constructors keyed to ");
+		d_print_comp(dpi, options, dc->u.s_binary.left);
+		return;
+
+	case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+		d_append_string(dpi, "global destructors keyed to ");
+		d_print_comp(dpi, options, dc->u.s_binary.left);
+		return;
+
+	case DEMANGLE_COMPONENT_LAMBDA:
+		d_append_string(dpi, "{lambda(");
+		/* Generic lambda auto parms are mangled as the template type
+		   parm they are.  */
+		dpi->is_lambda_arg++;
+		d_print_comp(dpi, options, dc->u.s_unary_num.sub);
+		dpi->is_lambda_arg--;
+		d_append_string(dpi, ")#");
+		d_append_num(dpi, dc->u.s_unary_num.num + 1);
+		d_append_char(dpi, '}');
+		return;
+
+	case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+		d_append_string(dpi, "{unnamed type#");
+		d_append_num(dpi, dc->u.s_number.number + 1);
+		d_append_char(dpi, '}');
+		return;
+
+	case DEMANGLE_COMPONENT_CLONE:
+		d_print_comp(dpi, options, d_left(dc));
+		d_append_string(dpi, " [clone ");
+		d_print_comp(dpi, options, d_right(dc));
+		d_append_char(dpi, ']');
+		return;
+
+	default:
+		d_print_error(dpi);
+		return;
+	}
+}
+
+static void d_print_comp(struct d_print_info *dpi, int options, struct dem=
angle_component *dc)
+{
+	struct d_component_stack self;
+
+	if (dc =3D=3D NULL || dc->d_printing > 1 || dpi->recursion > MAX_RECURSIO=
N_COUNT)
+	{
+		d_print_error(dpi);
+		return;
+	}
+
+	dc->d_printing++;
+	dpi->recursion++;
+
+	self.dc =3D dc;
+	self.parent =3D dpi->component_stack;
+	dpi->component_stack =3D &self;
+
+	d_print_comp_inner(dpi, options, dc);
+
+	dpi->component_stack =3D self.parent;
+	dc->d_printing--;
+	dpi->recursion--;
+}
+
+/* Print a Java dentifier.  For Java we try to handle encoded extended
+   Unicode characters.  The C++ ABI doesn't mention Unicode encoding,
+   so we don't it for C++.  Characters are encoded as
+   __U<hex-char>+_.  */
+
+static void d_print_java_identifier(struct d_print_info *dpi, const char *=
name, int len)
+{
+	const char *p;
+	const char *end;
+
+	end =3D name + len;
+	for (p =3D name; p < end; ++p)
+	{
+		if (end - p > 3 && p[0] =3D=3D '_' && p[1] =3D=3D '_' && p[2] =3D=3D 'U')
+		{
+			unsigned long c;
+			const char *q;
+
+			c =3D 0;
+			for (q =3D p + 3; q < end; ++q)
+			{
+				int dig;
+
+				if (IS_DIGIT(*q))
+					dig =3D *q - '0';
+				else if (*q >=3D 'A' && *q <=3D 'F')
+					dig =3D *q - 'A' + 10;
+				else if (*q >=3D 'a' && *q <=3D 'f')
+					dig =3D *q - 'a' + 10;
+				else
+					break;
+
+				c =3D c * 16 + dig;
+			}
+			/* If the Unicode character is larger than 256, we don't try
+			   to deal with it here.  FIXME.  */
+			if (q < end && *q =3D=3D '_' && c < 256)
+			{
+				d_append_char(dpi, c);
+				p =3D q;
+				continue;
+			}
+		}
+
+		d_append_char(dpi, *p);
+	}
+}
+
+/* Print a list of modifiers.  SUFFIX is 1 if we are printing
+   qualifiers on this after printing a function.  */
+
+static void d_print_mod_list(struct d_print_info *dpi, int options, struct=
 d_print_mod *mods, int suffix)
+{
+	struct d_print_template *hold_dpt;
+
+	if (mods =3D=3D NULL || d_print_saw_error(dpi))
+		return;
+
+	if (mods->printed || (!suffix && (is_fnqual_component_type(mods->mod->typ=
e))))
+	{
+		d_print_mod_list(dpi, options, mods->next, suffix);
+		return;
+	}
+
+	mods->printed =3D 1;
+
+	hold_dpt =3D dpi->templates;
+	dpi->templates =3D mods->templates;
+
+	if (mods->mod->type =3D=3D DEMANGLE_COMPONENT_FUNCTION_TYPE)
+	{
+		d_print_function_type(dpi, options, mods->mod, mods->next);
+		dpi->templates =3D hold_dpt;
+		return;
+	} else if (mods->mod->type =3D=3D DEMANGLE_COMPONENT_ARRAY_TYPE)
+	{
+		d_print_array_type(dpi, options, mods->mod, mods->next);
+		dpi->templates =3D hold_dpt;
+		return;
+	} else if (mods->mod->type =3D=3D DEMANGLE_COMPONENT_LOCAL_NAME)
+	{
+		struct d_print_mod *hold_modifiers;
+		struct demangle_component *dc;
+
+		/* When this is on the modifier stack, we have pulled any
+		   qualifiers off the right argument already.  Otherwise, we
+		   print it as usual, but don't let the left argument see any
+		   modifiers.  */
+
+		hold_modifiers =3D dpi->modifiers;
+		dpi->modifiers =3D NULL;
+		d_print_comp(dpi, options, d_left(mods->mod));
+		dpi->modifiers =3D hold_modifiers;
+
+		if ((options & DMGL_JAVA) =3D=3D 0)
+			d_append_string(dpi, "::");
+		else
+			d_append_char(dpi, '.');
+
+		dc =3D d_right(mods->mod);
+
+		if (dc->type =3D=3D DEMANGLE_COMPONENT_DEFAULT_ARG)
+		{
+			d_append_string(dpi, "{default arg#");
+			d_append_num(dpi, dc->u.s_unary_num.num + 1);
+			d_append_string(dpi, "}::");
+			dc =3D dc->u.s_unary_num.sub;
+		}
+
+		while (is_fnqual_component_type(dc->type))
+			dc =3D d_left(dc);
+
+		d_print_comp(dpi, options, dc);
+
+		dpi->templates =3D hold_dpt;
+		return;
+	}
+
+	d_print_mod(dpi, options, mods->mod);
+
+	dpi->templates =3D hold_dpt;
+
+	d_print_mod_list(dpi, options, mods->next, suffix);
+}
+
+/* Print a modifier.  */
+
+static void d_print_mod(struct d_print_info *dpi, int options, struct dema=
ngle_component *mod)
+{
+	switch (mod->type)
+	{
+	case DEMANGLE_COMPONENT_RESTRICT:
+	case DEMANGLE_COMPONENT_RESTRICT_THIS:
+		d_append_string(dpi, " restrict");
+		return;
+	case DEMANGLE_COMPONENT_VOLATILE:
+	case DEMANGLE_COMPONENT_VOLATILE_THIS:
+		d_append_string(dpi, " volatile");
+		return;
+	case DEMANGLE_COMPONENT_CONST:
+	case DEMANGLE_COMPONENT_CONST_THIS:
+		d_append_string(dpi, " const");
+		return;
+	case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+		d_append_string(dpi, " transaction_safe");
+		return;
+	case DEMANGLE_COMPONENT_NOEXCEPT:
+		d_append_string(dpi, " noexcept");
+		if (d_right(mod))
+		{
+			d_append_char(dpi, '(');
+			d_print_comp(dpi, options, d_right(mod));
+			d_append_char(dpi, ')');
+		}
+		return;
+	case DEMANGLE_COMPONENT_THROW_SPEC:
+		d_append_string(dpi, " throw");
+		if (d_right(mod))
+		{
+			d_append_char(dpi, '(');
+			d_print_comp(dpi, options, d_right(mod));
+			d_append_char(dpi, ')');
+		}
+		return;
+	case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+		d_append_char(dpi, ' ');
+		d_print_comp(dpi, options, d_right(mod));
+		return;
+	case DEMANGLE_COMPONENT_POINTER:
+		/* There is no pointer symbol in Java.  */
+		if ((options & DMGL_JAVA) =3D=3D 0)
+			d_append_char(dpi, '*');
+		return;
+	case DEMANGLE_COMPONENT_REFERENCE_THIS:
+		/* For the ref-qualifier, put a space before the &.  */
+		d_append_char(dpi, ' ');
+		/* FALLTHRU */
+	case DEMANGLE_COMPONENT_REFERENCE:
+		d_append_char(dpi, '&');
+		return;
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+		d_append_char(dpi, ' ');
+		/* FALLTHRU */
+	case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+		d_append_string(dpi, "&&");
+		return;
+	case DEMANGLE_COMPONENT_COMPLEX:
+		d_append_string(dpi, " _Complex");
+		return;
+	case DEMANGLE_COMPONENT_IMAGINARY:
+		d_append_string(dpi, " _Imaginary");
+		return;
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+		if (d_last_char(dpi) !=3D '(')
+			d_append_char(dpi, ' ');
+		d_print_comp(dpi, options, d_left(mod));
+		d_append_string(dpi, "::*");
+		return;
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+		d_print_comp(dpi, options, d_left(mod));
+		return;
+	case DEMANGLE_COMPONENT_VECTOR_TYPE:
+		d_append_string(dpi, " __vector(");
+		d_print_comp(dpi, options, d_left(mod));
+		d_append_char(dpi, ')');
+		return;
+
+	default:
+		/* Otherwise, we have something that won't go back on the
+		   modifier stack, so we can just print it.  */
+		d_print_comp(dpi, options, mod);
+		return;
+	}
+}
+
+/* Print a function type, except for the return type.  */
+
+static void d_print_function_type(struct d_print_info *dpi, int options, s=
truct demangle_component *dc, struct d_print_mod *mods)
+{
+	int need_paren;
+	int need_space;
+	struct d_print_mod *p;
+	struct d_print_mod *hold_modifiers;
+
+	need_paren =3D 0;
+	need_space =3D 0;
+	for (p =3D mods; p !=3D NULL; p =3D p->next)
+	{
+		if (p->printed)
+			break;
+
+		switch (p->mod->type)
+		{
+		case DEMANGLE_COMPONENT_POINTER:
+		case DEMANGLE_COMPONENT_REFERENCE:
+		case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+			need_paren =3D 1;
+			break;
+		case DEMANGLE_COMPONENT_RESTRICT:
+		case DEMANGLE_COMPONENT_VOLATILE:
+		case DEMANGLE_COMPONENT_CONST:
+		case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+		case DEMANGLE_COMPONENT_COMPLEX:
+		case DEMANGLE_COMPONENT_IMAGINARY:
+		case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+			need_space =3D 1;
+			need_paren =3D 1;
+			break;
+		  FNQUAL_COMPONENT_CASE:
+			break;
+		default:
+			break;
+		}
+		if (need_paren)
+			break;
+	}
+
+	if (need_paren)
+	{
+		if (!need_space)
+		{
+			if (d_last_char(dpi) !=3D '(' && d_last_char(dpi) !=3D '*')
+				need_space =3D 1;
+		}
+		if (need_space && d_last_char(dpi) !=3D ' ')
+			d_append_char(dpi, ' ');
+		d_append_char(dpi, '(');
+	}
+
+	hold_modifiers =3D dpi->modifiers;
+	dpi->modifiers =3D NULL;
+
+	d_print_mod_list(dpi, options, mods, 0);
+
+	if (need_paren)
+		d_append_char(dpi, ')');
+
+	d_append_char(dpi, '(');
+
+	if (d_right(dc) !=3D NULL)
+		d_print_comp(dpi, options, d_right(dc));
+
+	d_append_char(dpi, ')');
+
+	d_print_mod_list(dpi, options, mods, 1);
+
+	dpi->modifiers =3D hold_modifiers;
+}
+
+/* Print an array type, except for the element type.  */
+
+static void
+d_print_array_type(struct d_print_info *dpi, int options, struct demangle_=
component *dc, struct d_print_mod *mods)
+{
+	int need_space;
+
+	need_space =3D 1;
+	if (mods !=3D NULL)
+	{
+		int need_paren;
+		struct d_print_mod *p;
+
+		need_paren =3D 0;
+		for (p =3D mods; p !=3D NULL; p =3D p->next)
+		{
+			if (!p->printed)
+			{
+				if (p->mod->type =3D=3D DEMANGLE_COMPONENT_ARRAY_TYPE)
+				{
+					need_space =3D 0;
+					break;
+				} else
+				{
+					need_paren =3D 1;
+					need_space =3D 1;
+					break;
+				}
+			}
+		}
+
+		if (need_paren)
+			d_append_string(dpi, " (");
+
+		d_print_mod_list(dpi, options, mods, 0);
+
+		if (need_paren)
+			d_append_char(dpi, ')');
+	}
+
+	if (need_space)
+		d_append_char(dpi, ' ');
+
+	d_append_char(dpi, '[');
+
+	if (d_left(dc) !=3D NULL)
+		d_print_comp(dpi, options, d_left(dc));
+
+	d_append_char(dpi, ']');
+}
+
+/* Print an operator in an expression.  */
+
+static void d_print_expr_op(struct d_print_info *dpi, int options, struct =
demangle_component *dc)
+{
+	if (dc->type =3D=3D DEMANGLE_COMPONENT_OPERATOR)
+		d_append_buffer(dpi, dc->u.s_operator.op->name, dc->u.s_operator.op->len=
);
+	else
+		d_print_comp(dpi, options, dc);
+}
+
+/* Print a cast.  */
+
+static void d_print_cast(struct d_print_info *dpi, int options, struct dem=
angle_component *dc)
+{
+	d_print_comp(dpi, options, d_left(dc));
+}
+
+/* Print a conversion operator.  */
+
+static void d_print_conversion(struct d_print_info *dpi, int options, stru=
ct demangle_component *dc)
+{
+	struct d_print_template dpt;
+
+	/* For a conversion operator, we need the template parameters from
+	   the enclosing template in scope for processing the type.  */
+	if (dpi->current_template !=3D NULL)
+	{
+		dpt.next =3D dpi->templates;
+		dpi->templates =3D &dpt;
+		dpt.template_decl =3D dpi->current_template;
+	}
+
+	if (d_left(dc)->type !=3D DEMANGLE_COMPONENT_TEMPLATE)
+	{
+		d_print_comp(dpi, options, d_left(dc));
+		if (dpi->current_template !=3D NULL)
+			dpi->templates =3D dpt.next;
+	} else
+	{
+		d_print_comp(dpi, options, d_left(d_left(dc)));
+
+		/* For a templated cast operator, we need to remove the template
+		   parameters from scope after printing the operator name,
+		   so we need to handle the template printing here.  */
+		if (dpi->current_template !=3D NULL)
+			dpi->templates =3D dpt.next;
+
+		if (d_last_char(dpi) =3D=3D '<')
+			d_append_char(dpi, ' ');
+		d_append_char(dpi, '<');
+		d_print_comp(dpi, options, d_right(d_left(dc)));
+		/* Avoid generating two consecutive '>' characters, to avoid
+		   the C++ syntactic ambiguity.  */
+		if (d_last_char(dpi) =3D=3D '>')
+			d_append_char(dpi, ' ');
+		d_append_char(dpi, '>');
+	}
+}
+
+/* Initialize the information structure we use to pass around
+   information.  */
+
+CP_STATIC_IF_GLIBCPP_V3 void cplus_demangle_init_info(const char *mangled,=
 int options, size_t len, struct d_info *di)
+{
+	di->s =3D mangled;
+	di->send =3D mangled + len;
+	di->options =3D options;
+
+	di->n =3D mangled;
+
+	/* We cannot need more components than twice the number of chars in
+	   the mangled string.  Most components correspond directly to
+	   chars, but the ARGLIST types are exceptions.  */
+	di->num_comps =3D 2 * len;
+	di->next_comp =3D 0;
+
+	/* Similarly, we cannot need more substitutions than there are
+	   chars in the mangled string.  */
+	di->num_subs =3D len;
+	di->next_sub =3D 0;
+
+	di->last_name =3D NULL;
+
+	di->expansion =3D 0;
+	di->is_expression =3D 0;
+	di->is_conversion =3D 0;
+	di->recursion_level =3D 0;
+}
+
+/* Internal implementation for the demangler.  If MANGLED is a g++ v3 ABI
+   mangled name, return strings in repeated callback giving the demangled
+   name.  OPTIONS is the usual libiberty demangler options.  On success,
+   this returns 1.  On failure, returns 0.  */
+
+static int d_demangle_callback(const char *mangled, int options, demangle_=
callbackref callback, void *opaque)
+{
+	enum
+	{
+		DCT_TYPE,
+		DCT_MANGLED,
+		DCT_GLOBAL_CTORS,
+		DCT_GLOBAL_DTORS
+	}
+	type;
+	struct d_info di;
+	struct demangle_component *dc;
+	int status;
+
+	if (mangled[0] =3D=3D '_' && mangled[1] =3D=3D 'Z')
+		type =3D DCT_MANGLED;
+	else if (strncmp(mangled, "_GLOBAL_", 8) =3D=3D 0
+			 && (mangled[8] =3D=3D '.' || mangled[8] =3D=3D '_' || mangled[8] =3D=
=3D '$')
+			 && (mangled[9] =3D=3D 'D' || mangled[9] =3D=3D 'I') && mangled[10] =3D=
=3D '_')
+		type =3D mangled[9] =3D=3D 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
+	else
+	{
+		if ((options & DMGL_TYPES) =3D=3D 0)
+			return 0;
+		type =3D DCT_TYPE;
+	}
+
+	di.unresolved_name_state =3D 1;
+
+  again:
+	cplus_demangle_init_info(mangled, options, strlen(mangled), &di);
+
+	/* PR 87675 - Check for a mangled string that is so long
+	   that we do not have enough stack space to demangle it.  */
+	if (((options & DMGL_NO_RECURSE_LIMIT) =3D=3D 0)
+		/* This check is a bit arbitrary, since what we really want to do is to
+		   compare the sizes of the di.comps and di.subs arrays against the
+		   amount of stack space remaining.  But there is no portable way to do
+		   this, so instead we use the recursion limit as a guide to the maximum
+		   size of the arrays.  */
+		&& (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT)
+	{
+		/* FIXME: We need a way to indicate that a stack limit has been reached.=
  */
+		return 0;
+	}
+
+	{
+#ifdef CP_DYNAMIC_ARRAYS
+		__extension__ struct demangle_component comps[di.num_comps];
+		__extension__ struct demangle_component *subs[di.num_subs];
+
+		di.comps =3D comps;
+		di.subs =3D subs;
+#else
+		di.comps =3D alloca(di.num_comps * sizeof(*di.comps));
+		di.subs =3D alloca(di.num_subs * sizeof(*di.subs));
+#endif
+
+		switch (type)
+		{
+		case DCT_TYPE:
+			dc =3D cplus_demangle_type(&di);
+			break;
+		case DCT_MANGLED:
+			dc =3D cplus_demangle_mangled_name(&di, 1);
+			break;
+		case DCT_GLOBAL_CTORS:
+		case DCT_GLOBAL_DTORS:
+			d_advance(&di, 11);
+			dc =3D d_make_comp(&di,
+							 (type =3D=3D DCT_GLOBAL_CTORS
+							  ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
+							  : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
+							 d_make_demangle_mangled_name(&di, d_str(&di)), NULL);
+			d_advance(&di, strlen(d_str(&di)));
+			break;
+		default:
+			abort();					/* We have listed all the cases.  */
+		}
+
+		/* If DMGL_PARAMS is set, then if we didn't consume the entire
+		   mangled string, then we didn't successfully demangle it.  If
+		   DMGL_PARAMS is not set, we didn't look at the trailing
+		   parameters.  */
+		if (((options & DMGL_PARAMS) !=3D 0) && d_peek_char(&di) !=3D '\0')
+			dc =3D NULL;
+
+		/* See discussion in d_unresolved_name.  */
+		if (dc =3D=3D NULL && di.unresolved_name_state =3D=3D -1)
+		{
+			di.unresolved_name_state =3D 0;
+			goto again;
+		}
+
+#ifdef CP_DEMANGLE_DEBUG
+		d_dump(dc, 0);
+#endif
+
+		status =3D (dc !=3D NULL) ? cplus_demangle_print_callback(options, dc, c=
allback, opaque) : 0;
+	}
+
+	return status;
+}
+
+/* Entry point for the demangler.  If MANGLED is a g++ v3 ABI mangled
+   name, return a buffer allocated with malloc holding the demangled
+   name.  OPTIONS is the usual libiberty demangler options.  On
+   success, this sets *PALC to the allocated size of the returned
+   buffer.  On failure, this sets *PALC to 0 for a bad name, or 1 for
+   a memory allocation failure, and returns NULL.  */
+
+static char *d_demangle(const char *mangled, int options, size_t *palc)
+{
+	struct d_growable_string dgs;
+	int status;
+
+	d_growable_string_init(&dgs, 0);
+
+	status =3D d_demangle_callback(mangled, options, d_growable_string_callba=
ck_adapter, &dgs);
+	if (status =3D=3D 0)
+	{
+		free(dgs.buf);
+		*palc =3D 0;
+		return NULL;
+	}
+
+	*palc =3D dgs.allocation_failure ? 1 : dgs.alc;
+	return dgs.buf;
+}
+
+#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
+
+extern char *__cxa_demangle(const char *, char *, size_t *, int *);
+
+/* ia64 ABI-mandated entry point in the C++ runtime library for
+   performing demangling.  MANGLED_NAME is a NUL-terminated character
+   string containing the name to be demangled.
+
+   OUTPUT_BUFFER is a region of memory, allocated with malloc, of
+   *LENGTH bytes, into which the demangled name is stored.  If
+   OUTPUT_BUFFER is not long enough, it is expanded using realloc.
+   OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
+   is placed in a region of memory allocated with malloc.
+
+   If LENGTH is non-NULL, the length of the buffer containing the
+   demangled name, is placed in *LENGTH.
+
+   The return value is a pointer to the start of the NUL-terminated
+   demangled name, or NULL if the demangling fails.  The caller is
+   responsible for deallocating this memory using free.
+
+   *STATUS is set to one of the following values:
+      0: The demangling operation succeeded.
+     -1: A memory allocation failure occurred.
+     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+     -3: One of the arguments is invalid.
+
+   The demangling is performed using the C++ ABI mangling rules, with
+   GNU extensions.  */
+
+char *__cxa_demangle(const char *mangled_name, char *output_buffer, size_t=
 *length, int *status)
+{
+	char *demangled;
+	size_t alc;
+
+	if (mangled_name =3D=3D NULL)
+	{
+		if (status !=3D NULL)
+			*status =3D -3;
+		return NULL;
+	}
+
+	if (output_buffer !=3D NULL && length =3D=3D NULL)
+	{
+		if (status !=3D NULL)
+			*status =3D -3;
+		return NULL;
+	}
+
+	demangled =3D d_demangle(mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc);
+
+	if (demangled =3D=3D NULL)
+	{
+		if (status !=3D NULL)
+		{
+			if (alc =3D=3D 1)
+				*status =3D -1;
+			else
+				*status =3D -2;
+		}
+		return NULL;
+	}
+
+	if (output_buffer =3D=3D NULL)
+	{
+		if (length !=3D NULL)
+			*length =3D alc;
+	} else
+	{
+		if (strlen(demangled) < *length)
+		{
+			strcpy(output_buffer, demangled);
+			free(demangled);
+			demangled =3D output_buffer;
+		} else
+		{
+			free(output_buffer);
+			*length =3D alc;
+		}
+	}
+
+	if (status !=3D NULL)
+		*status =3D 0;
+
+	return demangled;
+}
+
+extern int __gcclibcxx_demangle_callback(const char *, void (*)(const char=
 *, size_t, void *), void *);
+
+/* Alternative, allocationless entry point in the C++ runtime library
+   for performing demangling.  MANGLED_NAME is a NUL-terminated character
+   string containing the name to be demangled.
+
+   CALLBACK is a callback function, called with demangled string
+   segments as demangling progresses; it is called at least once,
+   but may be called more than once.  OPAQUE is a generalized pointer
+   used as a callback argument.
+
+   The return code is one of the following values, equivalent to
+   the STATUS values of __cxa_demangle() (excluding -1, since this
+   function performs no memory allocations):
+      0: The demangling operation succeeded.
+     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+     -3: One of the arguments is invalid.
+
+   The demangling is performed using the C++ ABI mangling rules, with
+   GNU extensions.  */
+
+int
+__gcclibcxx_demangle_callback(const char *mangled_name, void (*callback)(c=
onst char *, size_t, void *), void *opaque)
+{
+	int status;
+
+	if (mangled_name =3D=3D NULL || callback =3D=3D NULL)
+		return -3;
+
+	status =3D d_demangle_callback(mangled_name, DMGL_PARAMS | DMGL_TYPES, ca=
llback, opaque);
+	if (status =3D=3D 0)
+		return -2;
+
+	return 0;
+}
+
+#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
+
+/* Entry point for libiberty demangler.  If MANGLED is a g++ v3 ABI
+   mangled name, return a buffer allocated with malloc holding the
+   demangled name.  Otherwise, return NULL.  */
+
+char *cplus_demangle_v3(const char *mangled, int options)
+{
+	size_t alc;
+
+	if ((options & DMGL_STRIP_UNDERSCORE) && mangled[0] =3D=3D '_')
+	{
+		++mangled;
+		options &=3D ~DMGL_STRIP_UNDERSCORE;
+	}
+
+	return d_demangle(mangled, options, &alc);
+}
+
+int cplus_demangle_v3_callback(const char *mangled, int options, demangle_=
callbackref callback, void *opaque)
+{
+	return d_demangle_callback(mangled, options, callback, opaque);
+}
+
+/* Demangle a Java symbol.  Java uses a subset of the V3 ABI C++ mangling=
=20
+   conventions, but the output formatting is a little different.
+   This instructs the C++ demangler not to emit pointer characters ("*"), =
to
+   use Java's namespace separator symbol ("." instead of "::"), and to out=
put
+   JArray<TYPE> as TYPE[].  */
+
+char *java_demangle_v3(const char *mangled, int options)
+{
+	size_t alc;
+
+	if ((options & DMGL_STRIP_UNDERSCORE) && mangled[0] =3D=3D '_')
+	{
+		++mangled;
+		options &=3D ~DMGL_STRIP_UNDERSCORE;
+	}
+
+	return d_demangle(mangled, options, &alc);
+}
+
+int java_demangle_v3_callback(const char *mangled, int options, demangle_c=
allbackref callback, void *opaque)
+{
+	if ((options & DMGL_STRIP_UNDERSCORE) && mangled[0] =3D=3D '_')
+	{
+		++mangled;
+		options &=3D ~DMGL_STRIP_UNDERSCORE;
+	}
+
+	return d_demangle_callback(mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_PO=
STFIX, callback, opaque);
+}
+
+#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
+
+#ifndef IN_GLIBCPP_V3
+
+/* Demangle a string in order to find out whether it is a constructor
+   or destructor.  Return non-zero on success.  Set *CTOR_KIND and
+   *DTOR_KIND appropriately.  */
+
+static int is_ctor_or_dtor(const char *mangled, enum gnu_v3_ctor_kinds *ct=
or_kind, enum gnu_v3_dtor_kinds *dtor_kind)
+{
+	struct d_info di;
+	struct demangle_component *dc;
+	int ret;
+
+	*ctor_kind =3D (enum gnu_v3_ctor_kinds) 0;
+	*dtor_kind =3D (enum gnu_v3_dtor_kinds) 0;
+
+	cplus_demangle_init_info(mangled, DMGL_GNU_V3, strlen(mangled), &di);
+
+	{
+#ifdef CP_DYNAMIC_ARRAYS
+		__extension__ struct demangle_component comps[di.num_comps];
+		__extension__ struct demangle_component *subs[di.num_subs];
+
+		di.comps =3D comps;
+		di.subs =3D subs;
+#else
+		di.comps =3D alloca(di.num_comps * sizeof(*di.comps));
+		di.subs =3D alloca(di.num_subs * sizeof(*di.subs));
+#endif
+
+		dc =3D cplus_demangle_mangled_name(&di, 1);
+
+		/* Note that because we did not pass DMGL_PARAMS, we don't expect
+		   to demangle the entire string.  */
+
+		ret =3D 0;
+		while (dc !=3D NULL)
+		{
+			switch (dc->type)
+			{
+				/* These cannot appear on a constructor or destructor.  */
+			case DEMANGLE_COMPONENT_RESTRICT_THIS:
+			case DEMANGLE_COMPONENT_VOLATILE_THIS:
+			case DEMANGLE_COMPONENT_CONST_THIS:
+			case DEMANGLE_COMPONENT_REFERENCE_THIS:
+			case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+			default:
+				dc =3D NULL;
+				break;
+			case DEMANGLE_COMPONENT_TYPED_NAME:
+			case DEMANGLE_COMPONENT_TEMPLATE:
+				dc =3D d_left(dc);
+				break;
+			case DEMANGLE_COMPONENT_QUAL_NAME:
+			case DEMANGLE_COMPONENT_LOCAL_NAME:
+				dc =3D d_right(dc);
+				break;
+			case DEMANGLE_COMPONENT_CTOR:
+				*ctor_kind =3D dc->u.s_ctor.kind;
+				ret =3D 1;
+				dc =3D NULL;
+				break;
+			case DEMANGLE_COMPONENT_DTOR:
+				*dtor_kind =3D dc->u.s_dtor.kind;
+				ret =3D 1;
+				dc =3D NULL;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI constructor
+   name.  A non-zero return indicates the type of constructor.  */
+
+enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor(const char *name)
+{
+	enum gnu_v3_ctor_kinds ctor_kind;
+	enum gnu_v3_dtor_kinds dtor_kind;
+
+	if (!is_ctor_or_dtor(name, &ctor_kind, &dtor_kind))
+		return (enum gnu_v3_ctor_kinds) 0;
+	return ctor_kind;
+}
+
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI destructor
+   name.  A non-zero return indicates the type of destructor.  */
+
+enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor(const char *name)
+{
+	enum gnu_v3_ctor_kinds ctor_kind;
+	enum gnu_v3_dtor_kinds dtor_kind;
+
+	if (!is_ctor_or_dtor(name, &ctor_kind, &dtor_kind))
+		return (enum gnu_v3_dtor_kinds) 0;
+	return dtor_kind;
+}
+
+#endif /* IN_GLIBCPP_V3 */
diff --git a/src/debug/demangle.h b/src/debug/demangle.h
new file mode 100644
index 00000000..c16f0738
=2D-- /dev/null
+++ b/src/debug/demangle.h
@@ -0,0 +1,630 @@
+/* Defs for interface to demanglers.
+   Copyright (C) 1992-2022 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License
+   as published by the Free Software Foundation; either version 2, or
+   (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.)
+
+   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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS	 0				/* For readability... */
+#define DMGL_PARAMS	 (1 << 0)			/* Include function args */
+#define DMGL_ANSI	 (1 << 1)			/* Include const, volatile, etc */
+#define DMGL_JAVA	 (1 << 2)			/* Demangle as Java rather than C++. */
+#define DMGL_VERBOSE	 (1 << 3)		/* Include implementation details.  */
+#define DMGL_TYPES	 (1 << 4)			/* Also try to demangle type encodings.  */
+#define DMGL_RET_POSTFIX (1 << 5)		/* Print function return types (when
+										   present) after function signature.
+										   It applies only to the toplevel
+										   function type.  */
+#define DMGL_RET_DROP	 (1 << 6)		/* Suppress printing function return
+										   types, even if present.  It applies
+										   only to the toplevel function type.
+										 */
+#define DMGL_STRIP_UNDERSCORE (1 << 7)
+
+#define DMGL_AUTO	 (1 << 11)
+#define DMGL_GNU_V3	 (1 << 12)
+#define DMGL_GNAT	 (1 << 13)
+#define DMGL_DLANG	 (1 << 14)
+#define DMGL_RUST	 (1 << 15)			/* Rust wraps GNU_V3 style mangling.  */
+
+/* If none of these are set, use 'current_demangling_style' as the default=
=2E */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DL=
ANG|DMGL_RUST)
+
+/* Disable a limit on the depth of recursion in mangled strings.
+   Note if this limit is disabled then stack exhaustion is possible when
+   demangling pathologically complicated strings.  Bug reports about stack
+   exhaustion when the option is enabled will be rejected.  */
+#define DMGL_NO_RECURSE_LIMIT (1 << 18)
+
+/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as
+   the maximum depth of recursion allowed.  It should be enough for any
+   real-world mangled name.  */
+#define DEMANGLE_RECURSION_LIMIT 2048
+
+/* Enumeration of possible demangling styles.
+
+   Lucid and ARM styles are still kept logically distinct, even though
+   they now both behave identically.  The resulting style is actual the
+   union of both.  I.E. either style recognizes both "__pt__" and "__rf__"
+   for operator "->", even though the first is lucid style and the second
+   is ARM style. (FIXME?) */
+
+/* Define string names for the various demangling styles. */
+
+#define NO_DEMANGLING_STYLE_STRING            "none"
+#define AUTO_DEMANGLING_STYLE_STRING	      "auto"
+#define GNU_V3_DEMANGLING_STYLE_STRING        "gnu-v3"
+#define JAVA_DEMANGLING_STYLE_STRING          "java"
+#define GNAT_DEMANGLING_STYLE_STRING          "gnat"
+#define DLANG_DEMANGLING_STYLE_STRING         "dlang"
+#define RUST_DEMANGLING_STYLE_STRING          "rust"
+
+char *cplus_demangle(const char *mangled, int options);
+
+/* Callback typedef for allocation-less demangler interfaces. */
+typedef void (*demangle_callbackref)(const char *, size_t, void *);
+
+/* V3 ABI demangling entry points, defined in cp-demangle.c.  Callback
+   variants return non-zero on success, zero on error.  char* variants
+   return a string allocated by malloc on success, NULL on error.  */
+int cplus_demangle_v3_callback(const char *mangled, int options, demangle_=
callbackref callback, void *opaque);
+
+char *cplus_demangle_v3(const char *mangled, int options);
+
+int java_demangle_v3_callback(const char *mangled, int options, demangle_c=
allbackref callback, void *opaque);
+
+char *java_demangle_v3(const char *mangled, int options);
+
+char *ada_demangle(const char *mangled, int options);
+
+char *dlang_demangle(const char *mangled, int options);
+
+int rust_demangle_callback(const char *mangled, int options, demangle_call=
backref callback, void *opaque);
+
+
+char *rust_demangle(const char *mangled, int options);
+
+enum gnu_v3_ctor_kinds
+{
+	gnu_v3_complete_object_ctor =3D 1,
+	gnu_v3_base_object_ctor,
+	gnu_v3_complete_object_allocating_ctor,
+	/* These are not part of the V3 ABI.  Unified constructors are generated
+	   as a speed-for-space optimization when the -fdeclone-ctor-dtor option
+	   is used, and are always internal symbols.  */
+	gnu_v3_unified_ctor,
+	gnu_v3_object_ctor_group
+};
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+   in the G++ V3 ABI demangling style.  Specifically, return an `enum
+   gnu_v3_ctor_kinds' value indicating what kind of constructor
+   it is.  */
+enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor(const char *name);
+
+
+enum gnu_v3_dtor_kinds
+{
+	gnu_v3_deleting_dtor =3D 1,
+	gnu_v3_complete_object_dtor,
+	gnu_v3_base_object_dtor,
+	/* These are not part of the V3 ABI.  Unified destructors are generated
+	   as a speed-for-space optimization when the -fdeclone-ctor-dtor option
+	   is used, and are always internal symbols.  */
+	gnu_v3_unified_dtor,
+	gnu_v3_object_dtor_group
+};
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+   in the G++ V3 ABI demangling style.  Specifically, return an `enum
+   gnu_v3_dtor_kinds' value, indicating what kind of destructor
+   it is.  */
+enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor(const char *name);
+
+/* The V3 demangler works in two passes.  The first pass builds a tree
+   representation of the mangled name, and the second pass turns the
+   tree representation into a demangled string.  Here we define an
+   interface to permit a caller to build their own tree
+   representation, which they can pass to the demangler to get a
+   demangled string.  This can be used to canonicalize user input into
+   something which the demangler might output.  It could also be used
+   by other demanglers in the future.  */
+
+/* These are the component types which may be found in the tree.  Many
+   component types have one or two subtrees, referred to as left and
+   right (a component type with only one subtree puts it in the left
+   subtree).  */
+
+enum demangle_component_type
+{
+	/* A name, with a length and a pointer to a string.  */
+	DEMANGLE_COMPONENT_NAME,
+	/* A qualified name.  The left subtree is a class or namespace or
+	   some such thing, and the right subtree is a name qualified by
+	   that class.  */
+	DEMANGLE_COMPONENT_QUAL_NAME,
+	/* A local name.  The left subtree describes a function, and the
+	   right subtree is a name which is local to that function.  */
+	DEMANGLE_COMPONENT_LOCAL_NAME,
+	/* A typed name.  The left subtree is a name, and the right subtree
+	   describes that name as a function.  */
+	DEMANGLE_COMPONENT_TYPED_NAME,
+	/* A template.  The left subtree is a template name, and the right
+	   subtree is a template argument list.  */
+	DEMANGLE_COMPONENT_TEMPLATE,
+	/* A template parameter.  This holds a number, which is the template
+	   parameter index.  */
+	DEMANGLE_COMPONENT_TEMPLATE_PARAM,
+	/* A function parameter.  This holds a number, which is the index.  */
+	DEMANGLE_COMPONENT_FUNCTION_PARAM,
+	/* A constructor.  This holds a name and the kind of
+	   constructor.  */
+	DEMANGLE_COMPONENT_CTOR,
+	/* A destructor.  This holds a name and the kind of destructor.  */
+	DEMANGLE_COMPONENT_DTOR,
+	/* A vtable.  This has one subtree, the type for which this is a
+	   vtable.  */
+	DEMANGLE_COMPONENT_VTABLE,
+	/* A VTT structure.  This has one subtree, the type for which this
+	   is a VTT.  */
+	DEMANGLE_COMPONENT_VTT,
+	/* A construction vtable.  The left subtree is the type for which
+	   this is a vtable, and the right subtree is the derived type for
+	   which this vtable is built.  */
+	DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+	/* A typeinfo structure.  This has one subtree, the type for which
+	   this is the tpeinfo structure.  */
+	DEMANGLE_COMPONENT_TYPEINFO,
+	/* A typeinfo name.  This has one subtree, the type for which this
+	   is the typeinfo name.  */
+	DEMANGLE_COMPONENT_TYPEINFO_NAME,
+	/* A typeinfo function.  This has one subtree, the type for which
+	   this is the tpyeinfo function.  */
+	DEMANGLE_COMPONENT_TYPEINFO_FN,
+	/* A thunk.  This has one subtree, the name for which this is a
+	   thunk.  */
+	DEMANGLE_COMPONENT_THUNK,
+	/* A virtual thunk.  This has one subtree, the name for which this
+	   is a virtual thunk.  */
+	DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+	/* A covariant thunk.  This has one subtree, the name for which this
+	   is a covariant thunk.  */
+	DEMANGLE_COMPONENT_COVARIANT_THUNK,
+	/* A Java class.  This has one subtree, the type.  */
+	DEMANGLE_COMPONENT_JAVA_CLASS,
+	/* A guard variable.  This has one subtree, the name for which this
+	   is a guard variable.  */
+	DEMANGLE_COMPONENT_GUARD,
+	/* The init and wrapper functions for C++11 thread_local variables.  */
+	DEMANGLE_COMPONENT_TLS_INIT,
+	DEMANGLE_COMPONENT_TLS_WRAPPER,
+	/* A reference temporary.  This has one subtree, the name for which
+	   this is a temporary.  */
+	DEMANGLE_COMPONENT_REFTEMP,
+	/* A hidden alias.  This has one subtree, the encoding for which it
+	   is providing alternative linkage.  */
+	DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+	/* A standard substitution.  This holds the name of the
+	   substitution.  */
+	DEMANGLE_COMPONENT_SUB_STD,
+	/* The restrict qualifier.  The one subtree is the type which is
+	   being qualified.  */
+	DEMANGLE_COMPONENT_RESTRICT,
+	/* The volatile qualifier.  The one subtree is the type which is
+	   being qualified.  */
+	DEMANGLE_COMPONENT_VOLATILE,
+	/* The const qualifier.  The one subtree is the type which is being
+	   qualified.  */
+	DEMANGLE_COMPONENT_CONST,
+	/* The restrict qualifier modifying a member function.  The one
+	   subtree is the type which is being qualified.  */
+	DEMANGLE_COMPONENT_RESTRICT_THIS,
+	/* The volatile qualifier modifying a member function.  The one
+	   subtree is the type which is being qualified.  */
+	DEMANGLE_COMPONENT_VOLATILE_THIS,
+	/* The const qualifier modifying a member function.  The one subtree
+	   is the type which is being qualified.  */
+	DEMANGLE_COMPONENT_CONST_THIS,
+	/* C++11 A reference modifying a member function.  The one subtree is the
+	   type which is being referenced.  */
+	DEMANGLE_COMPONENT_REFERENCE_THIS,
+	/* C++11: An rvalue reference modifying a member function.  The one
+	   subtree is the type which is being referenced.  */
+	DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
+	/* A vendor qualifier.  The left subtree is the type which is being
+	   qualified, and the right subtree is the name of the
+	   qualifier.  */
+	DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+	/* A pointer.  The one subtree is the type which is being pointed
+	   to.  */
+	DEMANGLE_COMPONENT_POINTER,
+	/* A reference.  The one subtree is the type which is being
+	   referenced.  */
+	DEMANGLE_COMPONENT_REFERENCE,
+	/* C++0x: An rvalue reference.  The one subtree is the type which is
+	   being referenced.  */
+	DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+	/* A complex type.  The one subtree is the base type.  */
+	DEMANGLE_COMPONENT_COMPLEX,
+	/* An imaginary type.  The one subtree is the base type.  */
+	DEMANGLE_COMPONENT_IMAGINARY,
+	/* A builtin type.  This holds the builtin type information.  */
+	DEMANGLE_COMPONENT_BUILTIN_TYPE,
+	/* A vendor's builtin type.  This holds the name of the type.  */
+	DEMANGLE_COMPONENT_VENDOR_TYPE,
+	/* A function type.  The left subtree is the return type.  The right
+	   subtree is a list of ARGLIST nodes.  Either or both may be
+	   NULL.  */
+	DEMANGLE_COMPONENT_FUNCTION_TYPE,
+	/* An array type.  The left subtree is the dimension, which may be
+	   NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
+	   expression.  The right subtree is the element type.  */
+	DEMANGLE_COMPONENT_ARRAY_TYPE,
+	/* A pointer to member type.  The left subtree is the class type,
+	   and the right subtree is the member type.  CV-qualifiers appear
+	   on the latter.  */
+	DEMANGLE_COMPONENT_PTRMEM_TYPE,
+	/* A fixed-point type.  */
+	DEMANGLE_COMPONENT_FIXED_TYPE,
+	/* A vector type.  The left subtree is the number of elements,
+	   the right subtree is the element type.  */
+	DEMANGLE_COMPONENT_VECTOR_TYPE,
+	/* An argument list.  The left subtree is the current argument, and
+	   the right subtree is either NULL or another ARGLIST node.  */
+	DEMANGLE_COMPONENT_ARGLIST,
+	/* A template argument list.  The left subtree is the current
+	   template argument, and the right subtree is either NULL or
+	   another TEMPLATE_ARGLIST node.  */
+	DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+	/* A template parameter object (C++20).  The left subtree is the
+	   corresponding template argument.  */
+	DEMANGLE_COMPONENT_TPARM_OBJ,
+	/* An initializer list.  The left subtree is either an explicit type or
+	   NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST.  */
+	DEMANGLE_COMPONENT_INITIALIZER_LIST,
+	/* An operator.  This holds information about a standard
+	   operator.  */
+	DEMANGLE_COMPONENT_OPERATOR,
+	/* An extended operator.  This holds the number of arguments, and
+	   the name of the extended operator.  */
+	DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
+	/* A typecast, represented as a unary operator.  The one subtree is
+	   the type to which the argument should be cast.  */
+	DEMANGLE_COMPONENT_CAST,
+	/* A conversion operator, represented as a unary operator.  The one
+	   subtree is the type to which the argument should be converted
+	   to.  */
+	DEMANGLE_COMPONENT_CONVERSION,
+	/* A nullary expression.  The left subtree is the operator.  */
+	DEMANGLE_COMPONENT_NULLARY,
+	/* A unary expression.  The left subtree is the operator, and the
+	   right subtree is the single argument.  */
+	DEMANGLE_COMPONENT_UNARY,
+	/* A binary expression.  The left subtree is the operator, and the
+	   right subtree is a BINARY_ARGS.  */
+	DEMANGLE_COMPONENT_BINARY,
+	/* Arguments to a binary expression.  The left subtree is the first
+	   argument, and the right subtree is the second argument.  */
+	DEMANGLE_COMPONENT_BINARY_ARGS,
+	/* A trinary expression.  The left subtree is the operator, and the
+	   right subtree is a TRINARY_ARG1.  */
+	DEMANGLE_COMPONENT_TRINARY,
+	/* Arguments to a trinary expression.  The left subtree is the first
+	   argument, and the right subtree is a TRINARY_ARG2.  */
+	DEMANGLE_COMPONENT_TRINARY_ARG1,
+	/* More arguments to a trinary expression.  The left subtree is the
+	   second argument, and the right subtree is the third argument.  */
+	DEMANGLE_COMPONENT_TRINARY_ARG2,
+	/* A literal.  The left subtree is the type, and the right subtree
+	   is the value, represented as a DEMANGLE_COMPONENT_NAME.  */
+	DEMANGLE_COMPONENT_LITERAL,
+	/* A negative literal.  Like LITERAL, but the value is negated.
+	   This is a minor hack: the NAME used for LITERAL points directly
+	   to the mangled string, but since negative numbers are mangled
+	   using 'n' instead of '-', we want a way to indicate a negative
+	   number which involves neither modifying the mangled string nor
+	   allocating a new copy of the literal in memory.  */
+	DEMANGLE_COMPONENT_LITERAL_NEG,
+	/* A vendor's builtin expression.  The left subtree holds the
+	   expression's name, and the right subtree is a argument list.  */
+	DEMANGLE_COMPONENT_VENDOR_EXPR,
+	/* A libgcj compiled resource.  The left subtree is the name of the
+	   resource.  */
+	DEMANGLE_COMPONENT_JAVA_RESOURCE,
+	/* A name formed by the concatenation of two parts.  The left
+	   subtree is the first part and the right subtree the second.  */
+	DEMANGLE_COMPONENT_COMPOUND_NAME,
+	/* A name formed by a single character.  */
+	DEMANGLE_COMPONENT_CHARACTER,
+	/* A number.  */
+	DEMANGLE_COMPONENT_NUMBER,
+	/* A decltype type.  */
+	DEMANGLE_COMPONENT_DECLTYPE,
+	/* Global constructors keyed to name.  */
+	DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
+	/* Global destructors keyed to name.  */
+	DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
+	/* A lambda closure type.  */
+	DEMANGLE_COMPONENT_LAMBDA,
+	/* A default argument scope.  */
+	DEMANGLE_COMPONENT_DEFAULT_ARG,
+	/* An unnamed type.  */
+	DEMANGLE_COMPONENT_UNNAMED_TYPE,
+	/* A transactional clone.  This has one subtree, the encoding for
+	   which it is providing alternative linkage.  */
+	DEMANGLE_COMPONENT_TRANSACTION_CLONE,
+	/* A non-transactional clone entry point.  In the i386/x86_64 abi,
+	   the unmangled symbol of a tm_callable becomes a thunk and the
+	   non-transactional function version is mangled thus.  */
+	DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
+	/* A pack expansion.  */
+	DEMANGLE_COMPONENT_PACK_EXPANSION,
+	/* A name with an ABI tag.  */
+	DEMANGLE_COMPONENT_TAGGED_NAME,
+	/* A transaction-safe function type.  */
+	DEMANGLE_COMPONENT_TRANSACTION_SAFE,
+	/* A cloned function.  */
+	DEMANGLE_COMPONENT_CLONE,
+	DEMANGLE_COMPONENT_NOEXCEPT,
+	DEMANGLE_COMPONENT_THROW_SPEC,
+
+	DEMANGLE_COMPONENT_STRUCTURED_BINDING,
+
+	DEMANGLE_COMPONENT_MODULE_NAME,
+	DEMANGLE_COMPONENT_MODULE_PARTITION,
+	DEMANGLE_COMPONENT_MODULE_ENTITY,
+	DEMANGLE_COMPONENT_MODULE_INIT,
+};
+
+/* Types which are only used internally.  */
+
+struct demangle_operator_info;
+struct demangle_builtin_type_info;
+
+/* A node in the tree representation is an instance of a struct
+   demangle_component.  Note that the field names of the struct are
+   not well protected against macros defined by the file including
+   this one.  We can fix this if it ever becomes a problem.  */
+
+struct demangle_component
+{
+	/* The type of this component.  */
+	enum demangle_component_type type;
+
+	/* Guard against recursive component printing.
+	   Initialize to zero.  Private to d_print_comp.
+	   All other fields are final after initialization.  */
+	int d_printing;
+	int d_counting;
+
+	union
+	{
+		/* For DEMANGLE_COMPONENT_NAME.  */
+		struct
+		{
+			/* A pointer to the name (which need not NULL terminated) and
+			   its length.  */
+			const char *s;
+			int len;
+		} s_name;
+
+		/* For DEMANGLE_COMPONENT_OPERATOR.  */
+		struct
+		{
+			/* Operator.  */
+			const struct demangle_operator_info *op;
+		} s_operator;
+
+		/* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR.  */
+		struct
+		{
+			/* Number of arguments.  */
+			int args;
+			/* Name.  */
+			struct demangle_component *name;
+		} s_extended_operator;
+
+		/* For DEMANGLE_COMPONENT_FIXED_TYPE.  */
+		struct
+		{
+			/* The length, indicated by a C integer type name.  */
+			struct demangle_component *length;
+			/* _Accum or _Fract?  */
+			short accum;
+			/* Saturating or not?  */
+			short sat;
+		} s_fixed;
+
+		/* For DEMANGLE_COMPONENT_CTOR.  */
+		struct
+		{
+			/* Kind of constructor.  */
+			enum gnu_v3_ctor_kinds kind;
+			/* Name.  */
+			struct demangle_component *name;
+		} s_ctor;
+
+		/* For DEMANGLE_COMPONENT_DTOR.  */
+		struct
+		{
+			/* Kind of destructor.  */
+			enum gnu_v3_dtor_kinds kind;
+			/* Name.  */
+			struct demangle_component *name;
+		} s_dtor;
+
+		/* For DEMANGLE_COMPONENT_BUILTIN_TYPE.  */
+		struct
+		{
+			/* Builtin type.  */
+			const struct demangle_builtin_type_info *type;
+		} s_builtin;
+
+		/* For DEMANGLE_COMPONENT_SUB_STD.  */
+		struct
+		{
+			/* Standard substitution string.  */
+			const char *string;
+			/* Length of string.  */
+			int len;
+		} s_string;
+
+		/* For DEMANGLE_COMPONENT_*_PARAM.  */
+		struct
+		{
+			/* Parameter index.  */
+			long number;
+		} s_number;
+
+		/* For DEMANGLE_COMPONENT_CHARACTER.  */
+		struct
+		{
+			int character;
+		} s_character;
+
+		/* For other types.  */
+		struct
+		{
+			/* Left (or only) subtree.  */
+			struct demangle_component *left;
+			/* Right subtree.  */
+			struct demangle_component *right;
+		} s_binary;
+
+		struct
+		{
+			/* subtree, same place as d_left.  */
+			struct demangle_component *sub;
+			/* integer.  */
+			int num;
+		} s_unary_num;
+
+	} u;
+};
+
+/* People building mangled trees are expected to allocate instances of
+   struct demangle_component themselves.  They can then call one of
+   the following functions to fill them in.  */
+
+/* Fill in most component types with a left subtree and a right
+   subtree.  Returns non-zero on success, zero on failure, such as an
+   unrecognized or inappropriate component type.  */
+
+int cplus_demangle_fill_component(struct demangle_component *fill,
+								  enum demangle_component_type,
+								  struct demangle_component *left, struct demangle_component *righ=
t);
+
+/* Fill in a DEMANGLE_COMPONENT_NAME.  Returns non-zero on success,
+   zero for bad arguments.  */
+
+int cplus_demangle_fill_name(struct demangle_component *fill, const char *=
, int);
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
+   builtin type (e.g., "int", etc.).  Returns non-zero on success,
+   zero if the type is not recognized.  */
+
+int cplus_demangle_fill_builtin_type(struct demangle_component *fill, cons=
t char *type_name);
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
+   operator and the number of arguments which it takes (the latter is
+   used to disambiguate operators which can be both binary and unary,
+   such as '-').  Returns non-zero on success, zero if the operator is
+   not recognized.  */
+
+int cplus_demangle_fill_operator(struct demangle_component *fill, const ch=
ar *opname, int args);
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
+   number of arguments and the name.  Returns non-zero on success,
+   zero for bad arguments.  */
+
+int cplus_demangle_fill_extended_operator(struct demangle_component *fill,
+										  int numargs, struct demangle_component *nm);
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR.  Returns non-zero on success,
+   zero for bad arguments.  */
+
+int cplus_demangle_fill_ctor(struct demangle_component *fill,
+							 enum gnu_v3_ctor_kinds kind, struct demangle_component *name);
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR.  Returns non-zero on success,
+   zero for bad arguments.  */
+
+int cplus_demangle_fill_dtor(struct demangle_component *fill,
+							 enum gnu_v3_dtor_kinds kind, struct demangle_component *name);
+
+/* This function translates a mangled name into a struct
+   demangle_component tree.  The first argument is the mangled name.
+   The second argument is DMGL_* options.  This returns a pointer to a
+   tree on success, or NULL on failure.  On success, the third
+   argument is set to a block of memory allocated by malloc.  This
+   block should be passed to free when the tree is no longer
+   needed.  */
+
+struct demangle_component *cplus_demangle_v3_components(const char *mangle=
d, int options, void **mem);
+
+/* This function takes a struct demangle_component tree and returns
+   the corresponding demangled string.  The first argument is DMGL_*
+   options.  The second is the tree to demangle.  The third is a guess
+   at the length of the demangled string, used to initially allocate
+   the return buffer.  The fourth is a pointer to a size_t.  On
+   success, this function returns a buffer allocated by malloc(), and
+   sets the size_t pointed to by the fourth argument to the size of
+   the allocated buffer (not the length of the returned string).  On
+   failure, this function returns NULL, and sets the size_t pointed to
+   by the fourth argument to 0 for an invalid tree, or to 1 for a
+   memory allocation error.  */
+
+char *cplus_demangle_print(int options, struct demangle_component *tree, i=
nt estimated_length, size_t *p_allocated_size);
+
+/* This function takes a struct demangle_component tree and passes back
+   a demangled string in one or more calls to a callback function.
+   The first argument is DMGL_* options.  The second is the tree to
+   demangle.  The third is a pointer to a callback function; on each call
+   this receives an element of the demangled string, its length, and an
+   opaque value.  The fourth is the opaque value passed to the callback.
+   The callback is called once or more to return the full demangled
+   string.  The demangled element string is always nul-terminated, though
+   its length is also provided for convenience.  In contrast to
+   cplus_demangle_print(), this function does not allocate heap memory
+   to grow output strings (except perhaps where alloca() is implemented
+   by malloc()), and so is normally safe for use where the heap has been
+   corrupted.  On success, this function returns 1; on failure, 0.  */
+
+int cplus_demangle_print_callback(int options,
+								  struct demangle_component *tree, demangle_callbackref callback, =
void *opaque);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif									/* DEMANGLE_H */
diff --git a/src/debug/symbols-common.c b/src/debug/symbols-common.c
index 2db136dd..382e5348 100644
=2D-- a/src/debug/symbols-common.c
+++ b/src/debug/symbols-common.c
@@ -15,6 +15,8 @@
  */
=20
 #include "symbols.h"
+#include "demangle.h"
+#include "cp-dem.c"
=20
 typedef struct {
 	int symbols;		/* initial symbol count */
@@ -37,6 +39,7 @@ typedef struct {
 	bool no_local;
 	bool no_obj;
 	bool sort_name;
+	bool demangle;
 } symbol_opts_t;
=20
 typedef struct {
@@ -698,6 +701,37 @@ static symbol_list_t* symbols_load_dri(FILE *fp, const=
 prg_section_t *sections,
 }
=20
=20
+static char *demangle_it(const char *mangled_name, unsigned int flags)
+{
+	char *result;
+	unsigned int skip_first =3D 0;
+
+	/* _ and $ are sometimes found at the start of function names
+	   in assembler sources in order to distinguish them from other
+	   names (eg register names).  So skip them here.  */
+	if (mangled_name[0] =3D=3D '.' || mangled_name[0] =3D=3D '$')
+		++skip_first;
+
+	result =3D cplus_demangle_v3(mangled_name + skip_first, flags);
+
+	if (result !=3D NULL)
+	{
+		if (mangled_name[0] =3D=3D '.')
+		{
+			char *tmp =3D malloc(strlen(result) + 2);
+			if (tmp !=3D NULL)
+			{
+				tmp[0] =3D '.';
+				strcpy(&tmp[1], result);
+				free(result);
+				result =3D tmp;
+			}
+		}
+	}
+	return result;
+}
+
+
 /**
  * Load symbols of given type and the symbol address addresses from
  * a.out format symbol table, and add given offsets to the addresses.
@@ -855,6 +889,17 @@ static symbol_list_t* symbols_load_gnu(FILE *fp, const=
 prg_section_t *sections,
 		sym->address =3D address;
 		sym->type =3D symtype;
 		sym->name =3D name;
+		if (opts->demangle)
+		{
+			int flags =3D DMGL_AUTO | DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE | DMGL=
_RET_POSTFIX | DMGL_STRIP_UNDERSCORE;
+
+			name =3D demangle_it(sym->name, flags);
+			if (name !=3D NULL && name !=3D sym->name)
+			{
+				sym->name =3D name;
+				sym->name_allocated =3D true;
+			}
+		}
 		sym++;
 		count++;
 		(void) n_desc;
diff --git a/src/debug/symbols.c b/src/debug/symbols.c
index 04df5304..ba3afb3f 100644
=2D-- a/src/debug/symbols.c
+++ b/src/debug/symbols.c
@@ -295,6 +295,7 @@ static symbol_list_t* Symbols_Load(const char *filename=
, uint32_t *offsets, uint
 		opts.notypes =3D 0;
 		opts.no_obj =3D true;
 		opts.no_local =3D true;
+		opts.demangle =3D false;
 		list =3D symbols_load_binary(fp, &opts, update_sections);
 		SymbolsAreForProgram =3D true;
 	} else {
diff --git a/tools/debugger/gst2ascii.c b/tools/debugger/gst2ascii.c
index 8b19149d..c61b9aef 100644
=2D-- a/tools/debugger/gst2ascii.c
+++ b/tools/debugger/gst2ascii.c
@@ -57,6 +57,7 @@ static void usage(const char *msg)
 		{ 'l', "no local (.L*) symbols" },
 		{ 'o', "no object symbols (filenames or GCC internals)" },
 		{ 'n', "sort by name (not address)" },
+		{ '+', "demangle c++ symbol names" },
 	};
 	const char *name;
 	int i;
@@ -234,6 +235,9 @@ int main(int argc, const char *argv[])
 		case 'n':
 			opts.sort_name =3D true;
 			break;
+		case '+':
+			opts.demangle =3D true;
+			break;
 		default:
 			usage("unknown option");
 		}
=2D-=20
2.39.0


--nextPart1937259.O6WyjCxUj0--






Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/