[PATCH 2/2] Add demangle option to Symbols_Load() command |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/hatari-devel Archives
]
- Subject: [PATCH 2/2] Add demangle option to Symbols_Load() command
- From: Thorsten Otto <admin@xxxxxxxxxxx>
- Date: Mon, 27 Feb 2023 09:33:31 +0100
---
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--