]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Update libiberty demangler to support Rust v0 name mangling
authorAmanieu d'Antras <amanieu@gmail.com>
Sun, 26 Sep 2021 10:42:26 +0000 (12:42 +0200)
committerMark Wielaard <mark@klomp.org>
Sun, 26 Sep 2021 10:42:26 +0000 (12:42 +0200)
Update the libiberty demangler using the auxprogs/update-demangler
script to the gcc git 01d92cfd79872e4cffc78bf233bb9b767336beb8.
Updates rust demangling to support the new v0 mangling scheme.

This includes the following changes:
- Update the update-demangler script to use gcc git instead of svn.
- The result of running the updated script to get an updated
  demangler and resolving the merge conflicts.
- A change to long_namespace_xml.stderr.exp because two overly long
  symbols aren't demangled anymore, but just returned as is.
- an update to the m_demangle/demangle.c source to deal with Rust
  demangling in cp_demangle, which now directly demangles old and
  new style rust symbols.

16 files changed:
NEWS
auxprogs/update-demangler
coregrind/m_demangle/ansidecl.h
coregrind/m_demangle/cp-demangle.c
coregrind/m_demangle/cp-demangle.h
coregrind/m_demangle/cplus-dem.c
coregrind/m_demangle/d-demangle.c
coregrind/m_demangle/demangle.c
coregrind/m_demangle/demangle.h
coregrind/m_demangle/dyn-string.c
coregrind/m_demangle/dyn-string.h
coregrind/m_demangle/rust-demangle.c
coregrind/m_demangle/safe-ctype.c
coregrind/m_demangle/safe-ctype.h
coregrind/m_demangle/vg_libciface.h
memcheck/tests/long_namespace_xml.stderr.exp

diff --git a/NEWS b/NEWS
index 630fc574cba788d3179ba2d3e06bad4d4d4b180f..3e570c7de61e190f07c06d9a92a59c55fb8851fa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 423963  Error in child thread when CLONE_PIDFD is used
 429375  PPC ISA 3.1 support is missing, part 9
 431157  PPC_FEATURE2_SCV needs to be masked in AT_HWCAP2
+431306  Update demangler to support Rust v0 name mangling
 433801  PPC ISA 3.1 support is missing, part 10 (ISA 3.1 support complete)
 433863  s390x: memcheck/tests/s390x/{cds,cs,csg} failures
 434840  PPC64 darn instruction not supported
index 2a788b8bec8d794547491dcfe18f8fb6dc4985aa..947fa5e314cb836391aedcc6880b664ba4a6f620 100755 (executable)
@@ -17,8 +17,8 @@ set -e
 #---------------------------------------------------------------------
 
 # You need to modify these revision numbers for your update.
-old_gcc_revision=r240068  # the revision of the previous update
-new_gcc_revision=r246502  # the revision for this update
+old_gcc_revision=7a312bbd41e190379d80b47e308a32c8bc4575c3  # the revision of the previous update
+new_gcc_revision=01d92cfd79872e4cffc78bf233bb9b767336beb8  # the revision for this update
 
 # Unless the organization of demangler related files has changed, no
 # changes below this line should be necessary.
@@ -33,62 +33,60 @@ cd $DIR
 
 echo "Updating the demangler in $DIR"
 
-# 1) Check out files from old GCC revision
-echo "Checking out GCC files @ $old_gcc_revision"
-
-mkdir gcc-$old_gcc_revision
-cd    gcc-$old_gcc_revision
-svn co -$old_gcc_revision svn://gcc.gnu.org/svn/gcc/trunk/libiberty libiberty > /dev/null
-svn co -$old_gcc_revision svn://gcc.gnu.org/svn/gcc/trunk/include   include   > /dev/null
-rm -rf libiberty/.svn
-rm -rf include/.svn
+# 1) Make a shallow clone of the GCC repo containing only the 2 commits we need
+mkdir gcc
+cd gcc
+git init
+git remote add origin git://gcc.gnu.org/git/gcc.git
+git config core.sparsecheckout true
+echo "libiberty/*" > .git/info/sparse-checkout
+echo "include/*" >> .git/info/sparse-checkout
+git fetch --depth 1 origin $old_gcc_revision $new_gcc_revision
+git checkout $old_gcc_revision
 cd ..
 
-# 2) Assemble the ones we need in $DIR/$old_gcc_revision
+# 2) Check out files from old GCC revision
+echo "Checking out GCC files @ $old_gcc_revision"
+
+# 3) Assemble the ones we need in $DIR/$old_gcc_revision
 mkdir $old_gcc_revision
 cd    $old_gcc_revision
-cp    ../gcc-$old_gcc_revision/include/ansidecl.h .
-cp    ../gcc-$old_gcc_revision/include/demangle.h .
-cp    ../gcc-$old_gcc_revision/include/dyn-string.h .
-cp    ../gcc-$old_gcc_revision/include/safe-ctype.h .
-cp    ../gcc-$old_gcc_revision/libiberty/cp-demangle.c .
-cp    ../gcc-$old_gcc_revision/libiberty/cp-demangle.h .
-cp    ../gcc-$old_gcc_revision/libiberty/cplus-dem.c .
-cp    ../gcc-$old_gcc_revision/libiberty/dyn-string.c .
-cp    ../gcc-$old_gcc_revision/libiberty/d-demangle.c .
-cp    ../gcc-$old_gcc_revision/libiberty/rust-demangle.c .
-cp    ../gcc-$old_gcc_revision/libiberty/safe-ctype.c .
+cp    ../gcc/include/ansidecl.h .
+cp    ../gcc/include/demangle.h .
+cp    ../gcc/include/dyn-string.h .
+cp    ../gcc/include/safe-ctype.h .
+cp    ../gcc/libiberty/cp-demangle.c .
+cp    ../gcc/libiberty/cp-demangle.h .
+cp    ../gcc/libiberty/cplus-dem.c .
+cp    ../gcc/libiberty/dyn-string.c .
+cp    ../gcc/libiberty/d-demangle.c .
+cp    ../gcc/libiberty/rust-demangle.c .
+cp    ../gcc/libiberty/safe-ctype.c .
 cd ..
 
-# 3) Check out files from new GCC revision
-
+# 4) Check out files from new GCC revision
 echo "Checking out GCC files @ $new_gcc_revision"
-mkdir gcc-$new_gcc_revision
-cd    gcc-$new_gcc_revision
-svn co -$new_gcc_revision svn://gcc.gnu.org/svn/gcc/trunk/libiberty libiberty > /dev/null
-svn co -$new_gcc_revision svn://gcc.gnu.org/svn/gcc/trunk/include   include   > /dev/null
-rm -rf libiberty/.svn
-rm -rf include/.svn
+cd gcc
+git checkout $new_gcc_revision
 cd ..
 
-# 4) Assemble the ones we need in $DIR/$new_gcc_revision
-
+# 5) Assemble the ones we need in $DIR/$new_gcc_revision
 mkdir $new_gcc_revision
 cd    $new_gcc_revision
-cp    ../gcc-$new_gcc_revision/include/ansidecl.h .
-cp    ../gcc-$new_gcc_revision/include/demangle.h .
-cp    ../gcc-$new_gcc_revision/include/dyn-string.h .
-cp    ../gcc-$new_gcc_revision/include/safe-ctype.h .
-cp    ../gcc-$new_gcc_revision/libiberty/cp-demangle.c .
-cp    ../gcc-$new_gcc_revision/libiberty/cp-demangle.h .
-cp    ../gcc-$new_gcc_revision/libiberty/cplus-dem.c .
-cp    ../gcc-$new_gcc_revision/libiberty/dyn-string.c .
-cp    ../gcc-$new_gcc_revision/libiberty/d-demangle.c .
-cp    ../gcc-$new_gcc_revision/libiberty/rust-demangle.c .
-cp    ../gcc-$new_gcc_revision/libiberty/safe-ctype.c .
+cp    ../gcc/include/ansidecl.h .
+cp    ../gcc/include/demangle.h .
+cp    ../gcc/include/dyn-string.h .
+cp    ../gcc/include/safe-ctype.h .
+cp    ../gcc/libiberty/cp-demangle.c .
+cp    ../gcc/libiberty/cp-demangle.h .
+cp    ../gcc/libiberty/cplus-dem.c .
+cp    ../gcc/libiberty/dyn-string.c .
+cp    ../gcc/libiberty/d-demangle.c .
+cp    ../gcc/libiberty/rust-demangle.c .
+cp    ../gcc/libiberty/safe-ctype.c .
 cd ..
 
-# 5) Sparse check out valgrind coregrind/m_demangle into old_m_demangle
+# 6) Sparse check out valgrind coregrind/m_demangle into old_m_demangle
 echo "Checking out coregrind/m_demangle"
 mkdir valgrind-sparse-clone
 cd valgrind-sparse-clone
@@ -101,18 +99,18 @@ cd ..
 mv valgrind-sparse-clone/coregrind/m_demangle old_m_demangle
 rm -rf valgrind-sparse-clone
 
-# 6) Create new_m_demangle
+# 7) Create new_m_demangle
 cp -rp old_m_demangle new_m_demangle
 cp -rp $new_gcc_revision/*.[ch] new_m_demangle
 
-# 7) Compare files from previous GCC revision against old_m_demangle
+# 8) Compare files from previous GCC revision against old_m_demangle
 #    (This gets us the changes we made to the demangler).
 echo "Creating patch"
 set +e
 diff -r -u $old_gcc_revision old_m_demangle > our-changes
 echo "Patch file 'our-changes' created"
 
-# 7) See how the patch would apply
+# 9) See how the patch would apply
 echo "Attempting to apply the patch (but not actualy doing it)."
 cd new_m_demangle
 patch --dry -p1 < ../our-changes
index 3822be0cbd86c51e6aec0ac2d677e4178a85fcd2..8e5de9bf5a89493205626536583a0c83689d560b 100644 (file)
@@ -1,5 +1,5 @@
 /* ANSI and traditional C compatibility macros
-   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   Copyright (C) 1991-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
 This program is free software; you can redistribute it and/or modify
@@ -252,7 +252,7 @@ So instead we use the macro below and test it against specific values.  */
 # endif /* GNUC >= 3.0 */
 #endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
 
-/* Useful for structures whose layout must much some binary specification
+/* Useful for structures whose layout must match some binary specification
    regardless of the alignment and padding qualities of the compiler.  */
 #ifndef ATTRIBUTE_PACKED
 # define ATTRIBUTE_PACKED __attribute__ ((packed))
@@ -283,6 +283,49 @@ So instead we use the macro below and test it against specific values.  */
 # endif /* GNUC >= 4.9 */
 #endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
 
+/* Attribute 'nonstring' was valid as of gcc 8.  */
+#ifndef ATTRIBUTE_NONSTRING
+# if GCC_VERSION >= 8000
+#  define ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
+# else
+#  define ATTRIBUTE_NONSTRING
+# endif
+#endif
+
+/* Attribute `alloc_size' was valid as of gcc 4.3.  */
+#ifndef ATTRIBUTE_RESULT_SIZE_1
+# if (GCC_VERSION >= 4003)
+#  define ATTRIBUTE_RESULT_SIZE_1 __attribute__ ((alloc_size (1)))
+# else
+#  define ATTRIBUTE_RESULT_SIZE_1
+#endif
+#endif
+
+#ifndef ATTRIBUTE_RESULT_SIZE_2
+# if (GCC_VERSION >= 4003)
+#  define ATTRIBUTE_RESULT_SIZE_2 __attribute__ ((alloc_size (2)))
+# else
+#  define ATTRIBUTE_RESULT_SIZE_2
+#endif
+#endif
+
+#ifndef ATTRIBUTE_RESULT_SIZE_1_2
+# if (GCC_VERSION >= 4003)
+#  define ATTRIBUTE_RESULT_SIZE_1_2 __attribute__ ((alloc_size (1, 2)))
+# else
+#  define ATTRIBUTE_RESULT_SIZE_1_2
+#endif
+#endif
+
+/* Attribute `warn_unused_result' was valid as of gcc 3.3.  */
+#ifndef ATTRIBUTE_WARN_UNUSED_RESULT
+# if GCC_VERSION >= 3003
+#  define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+# else
+#  define ATTRIBUTE_WARN_UNUSED_RESULT
+# endif
+#endif
+
 /* We use __extension__ in some places to suppress -pedantic warnings
    about GCC extensions.  This feature didn't work properly before
    gcc 2.8.  */
@@ -313,6 +356,12 @@ So instead we use the macro below and test it against specific values.  */
 #define ENUM_BITFIELD(TYPE) unsigned int
 #endif
 
+#if __cpp_constexpr >= 200704
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 /* C++11 adds the ability to add "override" after an implementation of a
    virtual function in a subclass, to:
      (A) document that this is an override of a virtual function
@@ -328,26 +377,58 @@ So instead we use the macro below and test it against specific values.  */
    For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables
    this by default (actually GNU++14).  */
 
-#if __cplusplus >= 201103
-/* C++11 claims to be available: use it.  final/override were only
-   implemented in 4.7, though.  */
-# if GCC_VERSION < 4007
+#if defined __cplusplus
+# if __cplusplus >= 201103
+   /* C++11 claims to be available: use it.  Final/override were only
+      implemented in 4.7, though.  */
+#  if GCC_VERSION < 4007
+#   define OVERRIDE
+#   define FINAL
+#  else
+#   define OVERRIDE override
+#   define FINAL final
+#  endif
+# elif GCC_VERSION >= 4007
+   /* G++ 4.7 supports __final in C++98.  */
 #  define OVERRIDE
-#  define FINAL
+#  define FINAL __final
 # else
-#  define OVERRIDE override
-#  define FINAL final
+   /* No C++11 support; leave the macros empty.  */
+#  define OVERRIDE
+#  define FINAL
 # endif
-#elif GCC_VERSION >= 4007
-/* G++ 4.7 supports __final in C++98.  */
-# define OVERRIDE
-# define FINAL __final
 #else
-/* No C++11 support; leave the macros empty: */
+  /* No C++11 support; leave the macros empty.  */
 # define OVERRIDE
 # define FINAL
 #endif
 
+/* A macro to disable the copy constructor and assignment operator.
+   When building with C++11 and above, the methods are explicitly
+   deleted, causing a compile-time error if something tries to copy.
+   For C++03, this just declares the methods, causing a link-time
+   error if the methods end up called (assuming you don't
+   define them).  For C++03, for best results, place the macro
+   under the private: access specifier, like this,
+
+   class name_lookup
+   {
+     private:
+       DISABLE_COPY_AND_ASSIGN (name_lookup);
+   };
+
+   so that most attempts at copy are caught at compile-time.  */
+
+#if __cplusplus >= 201103
+#define DISABLE_COPY_AND_ASSIGN(TYPE)          \
+  TYPE (const TYPE&) = delete;                 \
+  void operator= (const TYPE &) = delete
+  #else
+#define DISABLE_COPY_AND_ASSIGN(TYPE)          \
+  TYPE (const TYPE&);                          \
+  void operator= (const TYPE &)
+#endif /* __cplusplus >= 201103 */
+
 #ifdef __cplusplus
 }
 #endif
index 4a3fa5d1678ddb20cbaa4f5fb86de820065fd82c..11382a23ca9d1a72b4355bf8a570e9b5087bd57d 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for g++ V3 ABI.
-   Copyright (C) 2003-2017 Free Software Foundation, Inc.
+   Copyright (C) 2003-2021 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@wasabisystems.com>.
 
    This file is part of the libiberty library, which is part of GCC.
@@ -30,7 +30,7 @@
 
 /* This code implements a demangler for the g++ V3 ABI.  The ABI is
    described on this web page:
-       http://www.codesourcery.com/cxx-abi/abi.html#mangling
+       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@codesourcery.com>.
@@ -209,9 +209,9 @@ static void d_init_info (const char *, int, size_t, struct d_info *);
 #else
 #ifdef __STDC__
 #ifdef __STDC_VERSION__
-#if __STDC_VERSION__ >= 199901L
+#if __STDC_VERSION__ >= 199901L && !__STDC_NO_VLA__
 #define CP_DYNAMIC_ARRAYS
-#endif /* __STDC__VERSION >= 199901L */
+#endif /* __STDC_VERSION__ >= 199901L && !__STDC_NO_VLA__ */
 #endif /* defined (__STDC_VERSION__) */
 #endif /* defined (__STDC__) */
 #endif /* ! defined (__GNUC__) */
@@ -333,10 +333,12 @@ struct d_info_checkpoint
   const char *n;
   int next_comp;
   int next_sub;
-  int did_subs;
   int expansion;
 };
 
+/* Maximum number of times d_print_comp may be called recursively.  */
+#define MAX_RECURSION_COUNT 1024
+
 enum { D_PRINT_BUFFER_LENGTH = 256 };
 struct d_print_info
 {
@@ -359,6 +361,9 @@ struct d_print_info
   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;
@@ -441,7 +446,7 @@ static struct demangle_component *d_name (struct d_info *);
 
 static struct demangle_component *d_nested_name (struct d_info *);
 
-static struct demangle_component *d_prefix (struct d_info *);
+static struct demangle_component *d_prefix (struct d_info *, int);
 
 static struct demangle_component *d_unqualified_name (struct d_info *);
 
@@ -529,7 +534,7 @@ d_growable_string_callback_adapter (const char *, size_t, void *);
 
 static void
 d_print_init (struct d_print_info *, demangle_callbackref, void *,
-             const struct demangle_component *);
+             struct demangle_component *);
 
 static inline void d_print_error (struct d_print_info *);
 
@@ -580,22 +585,6 @@ static int d_demangle_callback (const char *, int,
                                 demangle_callbackref, void *);
 static char *d_demangle (const char *, int, size_t *);
 
-/* True iff TYPE is a demangling component representing a
-   function-type-qualifier.  */
-
-static int
-is_fnqual_component_type (enum demangle_component_type type)
-{
-  return (type == DEMANGLE_COMPONENT_RESTRICT_THIS
-         || type == DEMANGLE_COMPONENT_VOLATILE_THIS
-         || type == DEMANGLE_COMPONENT_CONST_THIS
-         || type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
-         || type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
-         || type == DEMANGLE_COMPONENT_NOEXCEPT
-         || type == DEMANGLE_COMPONENT_THROW_SPEC
-         || type == DEMANGLE_COMPONENT_REFERENCE_THIS);
-}
-
 #define FNQUAL_COMPONENT_CASE                          \
     case DEMANGLE_COMPONENT_RESTRICT_THIS:             \
     case DEMANGLE_COMPONENT_VOLATILE_THIS:             \
@@ -606,6 +595,23 @@ is_fnqual_component_type (enum demangle_component_type type)
     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
@@ -636,6 +642,9 @@ d_dump (struct demangle_component *dc, int indent)
     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;
@@ -869,9 +878,10 @@ CP_STATIC_IF_GLIBCPP_V3
 int
 cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len)
 {
-  if (p == NULL || s == NULL || len == 0)
+  if (p == NULL || s == NULL || len <= 0)
     return 0;
   p->d_printing = 0;
+  p->d_counting = 0;
   p->type = DEMANGLE_COMPONENT_NAME;
   p->u.s_name.s = s;
   p->u.s_name.len = len;
@@ -888,6 +898,7 @@ cplus_demangle_fill_extended_operator (struct demangle_component *p, int args,
   if (p == NULL || args < 0 || name == NULL)
     return 0;
   p->d_printing = 0;
+  p->d_counting = 0;
   p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
   p->u.s_extended_operator.args = args;
   p->u.s_extended_operator.name = name;
@@ -908,6 +919,7 @@ cplus_demangle_fill_ctor (struct demangle_component *p,
       || (int) kind > gnu_v3_object_ctor_group)
     return 0;
   p->d_printing = 0;
+  p->d_counting = 0;
   p->type = DEMANGLE_COMPONENT_CTOR;
   p->u.s_ctor.kind = kind;
   p->u.s_ctor.name = name;
@@ -928,6 +940,7 @@ cplus_demangle_fill_dtor (struct demangle_component *p,
       || (int) kind > gnu_v3_object_dtor_group)
     return 0;
   p->d_printing = 0;
+  p->d_counting = 0;
   p->type = DEMANGLE_COMPONENT_DTOR;
   p->u.s_dtor.kind = kind;
   p->u.s_dtor.name = name;
@@ -945,6 +958,7 @@ d_make_empty (struct d_info *di)
     return NULL;
   p = &di->comps[di->next_comp];
   p->d_printing = 0;
+  p->d_counting = 0;
   ++di->next_comp;
   return p;
 }
@@ -1018,6 +1032,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
     case DEMANGLE_COMPONENT_NULLARY:
     case DEMANGLE_COMPONENT_TRINARY_ARG2:
+    case DEMANGLE_COMPONENT_TPARM_OBJ:
       if (left == NULL)
        return NULL;
       break;
@@ -1270,6 +1285,8 @@ has_return_type (struct demangle_component *dc)
     {
     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:
@@ -1312,25 +1329,22 @@ static struct demangle_component *
 d_encoding (struct d_info *di, int top_level)
 {
   char peek = d_peek_char (di);
+  struct demangle_component *dc;
 
   if (peek == 'G' || peek == 'T')
-    return d_special_name (di);
+    dc = d_special_name (di);
   else
     {
-      struct demangle_component *dc;
-
       dc = d_name (di);
 
-      if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
+      if (!dc)
+       /* Failed already.  */;
+      else if (top_level && (di->options & DMGL_PARAMS) == 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 (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
-                || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
-                || dc->type == DEMANGLE_COMPONENT_CONST_THIS
-                || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
-                || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+         while (is_fnqual_component_type (dc->type))
            dc = d_left (dc);
 
          /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
@@ -1339,23 +1353,42 @@ d_encoding (struct d_info *di, int top_level)
             which is local to a function.  */
          if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
            {
-             struct demangle_component *dcr;
+             while (d_right (dc) != NULL
+                    && is_fnqual_component_type (d_right (dc)->type))
+               d_right (dc) = d_left (d_right (dc));
 
-             dcr = d_right (dc);
-             while (is_fnqual_component_type (dcr->type))
-               dcr = d_left (dcr);
-             dc->u.s_binary.right = dcr;
+             if (d_right (dc) == NULL)
+               dc = NULL;
            }
-
-         return dc;
        }
+      else
+       {
+         peek = d_peek_char (di);
+         if (peek != '\0' && peek != 'E')
+           {
+             struct demangle_component *ftype;
 
-      peek = d_peek_char (di);
-      if (dc == NULL || peek == '\0' || peek == 'E')
-       return dc;
-      return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc,
-                         d_bare_function_type (di, has_return_type (dc)));
+             ftype = 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 == DEMANGLE_COMPONENT_LOCAL_NAME
+                     && ftype->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+                   d_left (ftype) = NULL;
+
+                 dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME,
+                                   dc, ftype);
+               }
+             else
+               dc = NULL;
+           }
+       }
     }
+
+  return dc;
 }
 
 /* <tagged-name> ::= <name> B <source-name> */
@@ -1494,7 +1527,7 @@ d_nested_name (struct d_info *di)
      once we have something to attach it to.  */
   rqual = d_ref_qualifier (di, NULL);
 
-  *pret = d_prefix (di);
+  *pret = d_prefix (di, 1);
   if (*pret == NULL)
     return NULL;
 
@@ -1520,10 +1553,12 @@ d_nested_name (struct d_info *di)
    <template-prefix> ::= <prefix> <(template) unqualified-name>
                      ::= <template-param>
                      ::= <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)
+d_prefix (struct d_info *di, int subst)
 {
   struct demangle_component *ret = NULL;
 
@@ -1589,7 +1624,7 @@ d_prefix (struct d_info *di)
       else
        ret = d_make_comp (di, comb_type, ret, dc);
 
-      if (peek != 'S' && d_peek_char (di) != 'E')
+      if (peek != 'S' && d_peek_char (di) != 'E' && subst)
        {
          if (! d_add_substitution (di, ret))
            return NULL;
@@ -1616,9 +1651,15 @@ d_unqualified_name (struct d_info *di)
     ret = d_source_name (di);
   else if (IS_LOWER (peek))
     {
+      int was_expr = di->is_expression;
       if (peek == 'o' && d_peek_next_char (di) == 'n')
-       d_advance (di, 2);
+       {
+         d_advance (di, 2);
+         /* Treat cv as naming a conversion operator.  */
+         di->is_expression = 0;
+       }
       ret = d_operator_name (di);
+      di->is_expression = was_expr;
       if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
        {
          di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
@@ -1704,7 +1745,9 @@ d_number (struct d_info *di)
            ret = - ret;
          return ret;
        }
-      ret = ret * 10 + peek - '0';
+      if (ret > ((INT_MAX - (peek - '0')) / 10))
+        return -1;
+      ret = ret * 10 + (peek - '0');
       d_advance (di, 1);
       peek = d_peek_char (di);
     }
@@ -1784,19 +1827,23 @@ const struct demangle_operator_info cplus_demangle_operators[] =
   { "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 ("/="),        2 },
+  { "dX", NL ("[...]="),     3 }, /* [expr...expr] = expr */
   { "da", NL ("delete[] "), 1 },
   { "dc", NL ("dynamic_cast"), 2 },
   { "de", NL ("*"),         1 },
+  { "di", NL ("="),         2 }, /* .name = expr */
   { "dl", NL ("delete "),   1 },
   { "ds", NL (".*"),        2 },
   { "dt", NL ("."),         2 },
   { "dv", NL ("/"),         2 },
+  { "dx", NL ("]="),        2 }, /* [expr] = expr */
   { "eO", NL ("^="),        2 },
   { "eo", NL ("^"),         2 },
   { "eq", NL ("=="),        2 },
@@ -1841,6 +1888,7 @@ const struct demangle_operator_info cplus_demangle_operators[] =
   { "sP", NL ("sizeof..."), 1 },
   { "sZ", NL ("sizeof..."), 1 },
   { "sc", NL ("static_cast"), 2 },
+  { "ss", NL ("<=>"),       2 },
   { "st", NL ("sizeof "),   1 },
   { "sz", NL ("sizeof "),   1 },
   { "tr", NL ("throw"),     0 },
@@ -2004,6 +2052,7 @@ d_java_resource (struct d_info *di)
                   ::= TT <type>
                   ::= TI <type>
                   ::= TS <type>
+                 ::= TA <template-arg>
                   ::= GV <(object) name>
                   ::= T <call-offset> <(base) encoding>
                   ::= Tc <call-offset> <call-offset> <(base) encoding>
@@ -2096,6 +2145,10 @@ d_special_name (struct d_info *di)
          return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
                              d_name (di), NULL);
 
+       case 'A':
+         return d_make_comp (di, DEMANGLE_COMPONENT_TPARM_OBJ,
+                             d_template_arg (di), NULL);
+
        default:
          return NULL;
        }
@@ -2105,7 +2158,8 @@ d_special_name (struct d_info *di)
       switch (d_next_char (di))
        {
        case 'V':
-         return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
+         return d_make_comp (di, DEMANGLE_COMPONENT_GUARD,
+                             d_name (di), NULL);
 
        case 'R':
          {
@@ -2351,9 +2405,10 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
   /* 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 ("char16_t"),  NL ("char16_t"),        D_PRINT_DEFAULT },
-  /* 31 */ { NL ("char32_t"),  NL ("char32_t"),        D_PRINT_DEFAULT },
-  /* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
+  /* 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 },
 };
 
@@ -2641,14 +2696,19 @@ cplus_demangle_type (struct d_info *di)
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
+       case 'u':
+         /* char8_t */
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+         di->expansion += ret->u.s_builtin.type->len;
+         break;
        case 's':
          /* char16_t */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
        case 'i':
          /* char32_t */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
 
@@ -2674,7 +2734,7 @@ cplus_demangle_type (struct d_info *di)
 
         case 'n':
           /* decltype(nullptr) */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[33]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
 
@@ -2839,21 +2899,35 @@ d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
 static struct demangle_component *
 d_function_type (struct d_info *di)
 {
-  struct demangle_component *ret;
+  struct demangle_component *ret = NULL;
 
-  if (! d_check_char (di, 'F'))
-    return NULL;
-  if (d_peek_char (di) == 'Y')
+  if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
     {
-      /* Function has C linkage.  We don't print this information.
-        FIXME: We should print it in verbose mode.  */
-      d_advance (di, 1);
+      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 ++;
     }
-  ret = d_bare_function_type (di, 1);
-  ret = d_ref_qualifier (di, ret);
 
-  if (! d_check_char (di, 'E'))
-    return NULL;
+  if (d_check_char (di, 'F'))
+    {
+      if (d_peek_char (di) == 'Y')
+       {
+         /* Function has C linkage.  We don't print this information.
+            FIXME: We should print it in verbose mode.  */
+         d_advance (di, 1);
+       }
+      ret = d_bare_function_type (di, 1);
+      ret = d_ref_qualifier (di, ret);
+      
+      if (! d_check_char (di, 'E'))
+       ret = NULL;
+    }
+
+  if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
+    di->recursion_level --;
   return ret;
 }
 
@@ -3092,8 +3166,6 @@ d_template_param (struct d_info *di)
   if (param < 0)
     return NULL;
 
-  ++di->did_subs;
-
   return d_make_template_param (di, param);
 }
 
@@ -3238,18 +3310,68 @@ op_is_new_cast (struct demangle_component *op)
              || code[0] == 'c' || code[0] == 'r'));
 }
 
+/*   <unresolved-name> ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+       ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+       # T::N::x /decltype(p)::N::x
+       ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+       # A::x, N::y, A<T>::z; "gs" means leading "::"
+       ::= [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 = d_peek_char (di);
+  if (di->unresolved_name_state
+      && (IS_DIGIT (peek)
+         || IS_LOWER (peek)
+         || peek == 'C'
+         || peek == 'U'
+         || peek == 'L'))
+    {
+      /* The third production is ambiguous with the old unresolved-name syntax
+        of <type> <base-unresolved-name>; in the old mangling, A::x was mangled
+        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 = -1;
+      type = d_prefix (di, 0);
+      if (d_peek_char (di) == 'E')
+       d_advance (di, 1);
+    }
+  else
+    type = cplus_demangle_type (di);
+  name = d_unqualified_name (di);
+  if (d_peek_char (di) == 'I')
+    name = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+                       d_template_args (di));
+  return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
+}
+
 /* <expression> ::= <(unary) operator-name> <expression>
                 ::= <(binary) operator-name> <expression> <expression>
                 ::= <(trinary) operator-name> <expression> <expression> <expression>
                ::= cl <expression>+ E
                 ::= st <type>
                 ::= <template-param>
-                ::= sr <type> <unqualified-name>
-                ::= sr <type> <unqualified-name> <template-args>
+               ::= <unresolved-name>
                 ::= <expr-primary>
+
+  <braced-expression> ::= <expression>
+                     ::= di <field source-name> <braced-expression>    # .name = expr
+                     ::= dx <index expression> <braced-expression>     # [expr] = expr
+                     ::= dX <range begin expression> <range end expression> <braced-expression>
+                                                                       # [expr ... expr] = expr
 */
 
-static inline struct demangle_component *
+static struct demangle_component *
 d_expression_1 (struct d_info *di)
 {
   char peek;
@@ -3260,20 +3382,7 @@ d_expression_1 (struct d_info *di)
   else if (peek == 'T')
     return d_template_param (di);
   else if (peek == 's' && d_peek_next_char (di) == 'r')
-    {
-      struct demangle_component *type;
-      struct demangle_component *name;
-
-      d_advance (di, 2);
-      type = cplus_demangle_type (di);
-      name = d_unqualified_name (di);
-      if (d_peek_char (di) != 'I')
-       return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
-      else
-       return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
-                           d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
-                                        d_template_args (di)));
-    }
+    return d_unresolved_name (di);
   else if (peek == 's' && d_peek_next_char (di) == 'p')
     {
       d_advance (di, 2);
@@ -3325,11 +3434,11 @@ d_expression_1 (struct d_info *di)
     {
       /* Brace-enclosed initializer list, untyped or typed.  */
       struct demangle_component *type = NULL;
+      d_advance (di, 2);
       if (peek == 't')
        type = cplus_demangle_type (di);
-      if (!d_peek_next_char (di))
+      if (!d_peek_char (di) || !d_peek_next_char (di))
        return NULL;
-      d_advance (di, 2);
       return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
                          type, d_exprlist (di, 'E'));
     }
@@ -3392,13 +3501,10 @@ d_expression_1 (struct d_info *di)
 
            if (suffix)
              /* Indicate the suffix variant for d_print_comp.  */
-             return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-                                 d_make_comp (di,
-                                              DEMANGLE_COMPONENT_BINARY_ARGS,
-                                              operand, operand));
-           else
-             return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-                                 operand);
+             operand = d_make_comp (di, DEMANGLE_COMPONENT_BINARY_ARGS,
+                                    operand, operand);
+
+           return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, operand);
          }
        case 2:
          {
@@ -3412,16 +3518,30 @@ d_expression_1 (struct d_info *di)
            else if (code[0] == 'f')
              /* fold-expression.  */
              left = d_operator_name (di);
+           else if (!strcmp (code, "di"))
+             left = d_unqualified_name (di);
            else
              left = d_expression_1 (di);
            if (!strcmp (code, "cl"))
              right = d_exprlist (di, 'E');
            else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
              {
-               right = d_unqualified_name (di);
-               if (d_peek_char (di) == 'I')
-                 right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
-                                      right, d_template_args (di));
+               peek = d_peek_char (di);
+               /* These codes start a qualified name.  */
+               if ((peek == 'g' && d_peek_next_char (di) == 's')
+                   || (peek == 's' && d_peek_next_char (di) == 'r'))
+                 right = 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 = d_unqualified_name (di);
+                   if (d_peek_char (di) == 'I')
+                     right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
+                                          right, d_template_args (di));
+                 }
              }
            else
              right = d_expression_1 (di);
@@ -3439,7 +3559,8 @@ d_expression_1 (struct d_info *di)
 
            if (code == NULL)
              return NULL;
-           else if (!strcmp (code, "qu"))
+           else if (!strcmp (code, "qu")
+                    || !strcmp (code, "dX"))
              {
                /* ?: expression.  */
                first = d_expression_1 (di);
@@ -3543,6 +3664,17 @@ d_expr_primary (struct d_info *di)
          && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
        di->expansion -= type->u.s_builtin.type->len;
 
+      if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+         && strcmp (type->u.s_builtin.type->name,
+                    cplus_demangle_builtin_types[33].name) == 0)
+       {
+         if (d_peek_char (di) == '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
@@ -3583,11 +3715,14 @@ 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 = d_encoding (di, 0);
+  if (!function)
+    return NULL;
 
   if (! d_check_char (di, 'E'))
     return NULL;
@@ -3597,13 +3732,10 @@ d_local_name (struct d_info *di)
       d_advance (di, 1);
       if (! d_discriminator (di))
        return NULL;
-      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
-                         d_make_name (di, "string literal",
-                                      sizeof "string literal" - 1));
+      name = d_make_name (di, "string literal", sizeof "string literal" - 1);
     }
   else
     {
-      struct demangle_component *name;
       int num = -1;
 
       if (d_peek_char (di) == 'd')
@@ -3616,21 +3748,30 @@ d_local_name (struct d_info *di)
        }
 
       name = d_name (di);
-      if (name)
-       switch (name->type)
-         {
-           /* Lambdas and unnamed types have internal discriminators.  */
-         case DEMANGLE_COMPONENT_LAMBDA:
-         case DEMANGLE_COMPONENT_UNNAMED_TYPE:
-           break;
-         default:
-           if (! d_discriminator (di))
-             return NULL;
-         }
+
+      if (name
+         /* Lambdas and unnamed types have internal discriminators
+            and are not functions.  */
+         && name->type != DEMANGLE_COMPONENT_LAMBDA
+         && name->type != DEMANGLE_COMPONENT_UNNAMED_TYPE)
+       {
+         /* Read and ignore an optional discriminator.  */
+         if (! d_discriminator (di))
+           return NULL;
+       }
+
       if (num >= 0)
        name = d_make_default_arg (di, num, name);
-      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, 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 == DEMANGLE_COMPONENT_TYPED_NAME
+      && d_right (function)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+    d_left (d_right (function)) = NULL;
+
+  return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
 }
 
 /* <discriminator> ::= _ <number>    # when number < 10
@@ -3703,9 +3844,6 @@ d_lambda (struct d_info *di)
       ret->u.s_unary_num.num = num;
     }
 
-  if (! d_add_substitution (di, ret))
-    return NULL;
-
   return ret;
 }
 
@@ -3863,8 +4001,6 @@ d_substitution (struct d_info *di, int prefix)
       if (id >= (unsigned int) di->next_sub)
        return NULL;
 
-      ++di->did_subs;
-
       return di->subs[id];
     }
   else
@@ -3913,7 +4049,8 @@ d_substitution (struct d_info *di, int prefix)
                  /* If there are ABI tags on the abbreviation, it becomes
                     a substitution candidate.  */
                  dc = d_abi_tags (di, dc);
-                 d_add_substitution (di, dc);
+                 if (! d_add_substitution (di, dc))
+                   return NULL;
                }
              return dc;
            }
@@ -3929,7 +4066,6 @@ d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint)
   checkpoint->n = di->n;
   checkpoint->next_comp = di->next_comp;
   checkpoint->next_sub = di->next_sub;
-  checkpoint->did_subs = di->did_subs;
   checkpoint->expansion = di->expansion;
 }
 
@@ -3939,7 +4075,6 @@ d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint)
   di->n = checkpoint->n;
   di->next_comp = checkpoint->next_comp;
   di->next_sub = checkpoint->next_sub;
-  di->did_subs = checkpoint->did_subs;
   di->expansion = checkpoint->expansion;
 }
 
@@ -4027,12 +4162,14 @@ d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
    are larger than the actual numbers encountered.  */
 
 static void
-d_count_templates_scopes (int *num_templates, int *num_scopes,
-                         const struct demangle_component *dc)
+d_count_templates_scopes (struct d_print_info *dpi,
+                         struct demangle_component *dc)
 {
-  if (dc == NULL)
+  if (dc == NULL || dc->d_counting > 1 || dpi->recursion > MAX_RECURSION_COUNT)
     return;
 
+  ++ dc->d_counting;
+
   switch (dc->type)
     {
     case DEMANGLE_COMPONENT_NAME:
@@ -4047,13 +4184,13 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
       break;
 
     case DEMANGLE_COMPONENT_TEMPLATE:
-      (*num_templates)++;
+      dpi->num_copy_templates++;
       goto recurse_left_right;
 
     case DEMANGLE_COMPONENT_REFERENCE:
     case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
       if (d_left (dc)->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
-       (*num_scopes)++;
+       dpi->num_saved_scopes++;
       goto recurse_left_right;
 
     case DEMANGLE_COMPONENT_QUAL_NAME:
@@ -4096,6 +4233,7 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
     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:
@@ -4117,42 +4255,42 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
     case DEMANGLE_COMPONENT_TAGGED_NAME:
     case DEMANGLE_COMPONENT_CLONE:
     recurse_left_right:
-      d_count_templates_scopes (num_templates, num_scopes,
-                               d_left (dc));
-      d_count_templates_scopes (num_templates, num_scopes,
-                               d_right (dc));
+      /* 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 (num_templates, num_scopes,
-                               dc->u.s_ctor.name);
+      d_count_templates_scopes (dpi, dc->u.s_ctor.name);
       break;
 
     case DEMANGLE_COMPONENT_DTOR:
-      d_count_templates_scopes (num_templates, num_scopes,
-                               dc->u.s_dtor.name);
+      d_count_templates_scopes (dpi, dc->u.s_dtor.name);
       break;
 
     case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
-      d_count_templates_scopes (num_templates, num_scopes,
-                               dc->u.s_extended_operator.name);
+      d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
       break;
 
     case DEMANGLE_COMPONENT_FIXED_TYPE:
-      d_count_templates_scopes (num_templates, num_scopes,
-                                dc->u.s_fixed.length);
+      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
       break;
 
     case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
-      d_count_templates_scopes (num_templates, num_scopes,
-                               d_left (dc));
+      d_count_templates_scopes (dpi, d_left (dc));
       break;
 
     case DEMANGLE_COMPONENT_LAMBDA:
     case DEMANGLE_COMPONENT_DEFAULT_ARG:
-      d_count_templates_scopes (num_templates, num_scopes,
-                               dc->u.s_unary_num.sub);
+      d_count_templates_scopes (dpi, dc->u.s_unary_num.sub);
       break;
     }
 }
@@ -4161,7 +4299,7 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
 
 static void
 d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
-             void *opaque, const struct demangle_component *dc)
+             void *opaque, struct demangle_component *dc)
 {
   dpi->len = 0;
   dpi->last_char = '\0';
@@ -4174,6 +4312,7 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
   dpi->opaque = opaque;
 
   dpi->demangle_failure = 0;
+  dpi->recursion = 0;
   dpi->is_lambda_arg = 0;
 
   dpi->component_stack = NULL;
@@ -4186,8 +4325,12 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
   dpi->next_copy_template = 0;
   dpi->num_copy_templates = 0;
 
-  d_count_templates_scopes (&dpi->num_copy_templates,
-                           &dpi->num_saved_scopes, dc);
+  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 = 0;
   dpi->num_copy_templates *= dpi->num_saved_scopes;
 
   dpi->current_template = NULL;
@@ -4625,6 +4768,64 @@ d_maybe_print_fold_expression (struct d_print_info *dpi, int options,
   return 1;
 }
 
+/* True iff DC represents a C99-style designated initializer.  */
+
+static int
+is_designated_init (struct demangle_component *dc)
+{
+  if (dc->type != DEMANGLE_COMPONENT_BINARY
+      && dc->type != DEMANGLE_COMPONENT_TRINARY)
+    return 0;
+
+  struct demangle_component *op = d_left (dc);
+  const char *code = op->u.s_operator.op->code;
+  return (code[0] == 'd'
+         && (code[1] == 'i' || code[1] == 'x' || code[1] == '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 options,
+                              struct demangle_component *dc)
+{
+  if (!is_designated_init (dc))
+    return 0;
+
+  const char *code = d_left (dc)->u.s_operator.op->code;
+
+  struct demangle_component *operands = d_right (dc);
+  struct demangle_component *op1 = d_left (operands);
+  struct demangle_component *op2 = d_right (operands);
+
+  if (code[1] == 'i')
+    d_append_char (dpi, '.');
+  else
+    d_append_char (dpi, '[');
+
+  d_print_comp (dpi, options, op1);
+  if (code[1] == 'X')
+    {
+      d_append_string (dpi, " ... ");
+      d_print_comp (dpi, options, d_left (op2));
+      op2 = d_right (op2);
+    }
+  if (code[1] != 'i')
+    d_append_char (dpi, ']');
+  if (is_designated_init (op2))
+    {
+      /* Don't put '=' or '(' between chained designators.  */
+      d_print_comp (dpi, options, op2);
+    }
+  else
+    {
+      d_append_char (dpi, '=');
+      d_print_subexpr (dpi, options, op2);
+    }
+  return 1;
+}
+
 /* Subroutine to handle components.  */
 
 static void
@@ -4728,32 +4929,17 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
            return;
          }
 
-       /* If typed_name is a template, then it applies to the
-          function type as well.  */
-       if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
-         {
-           dpt.next = dpi->templates;
-           dpi->templates = &dpt;
-           dpt.template_decl = typed_name;
-         }
-
        /* 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 which
+          really apply here; this happens when parsing a class that
           is local to a function.  */
        if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
          {
-           struct demangle_component *local_name;
-
-           local_name = d_right (typed_name);
-           if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
-             local_name = local_name->u.s_unary_num.sub;
-           if (local_name == NULL)
-             {
-               d_print_error (dpi);
-               return;
-             }
-           while (is_fnqual_component_type (local_name->type))
+           typed_name = d_right (typed_name);
+           if (typed_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+             typed_name = typed_name->u.s_unary_num.sub;
+           while (typed_name != NULL
+                  && is_fnqual_component_type (typed_name->type))
              {
                if (i >= sizeof adpm / sizeof adpm[0])
                  {
@@ -4765,15 +4951,29 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
                adpm[i].next = &adpm[i - 1];
                dpi->modifiers = &adpm[i];
 
-               adpm[i - 1].mod = local_name;
+               adpm[i - 1].mod = typed_name;
                adpm[i - 1].printed = 0;
                adpm[i - 1].templates = dpi->templates;
                ++i;
 
-               local_name = d_left (local_name);
+               typed_name = d_left (typed_name);
+             }
+           if (typed_name == 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 == DEMANGLE_COMPONENT_TEMPLATE)
+         {
+           dpt.next = dpi->templates;
+           dpi->templates = &dpt;
+           dpt.template_decl = typed_name;
+         }
+
        d_print_comp (dpi, options, d_right (dc));
 
        if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
@@ -4884,6 +5084,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
        }
       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;
@@ -5337,9 +5542,18 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
       }
 
     case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
-      d_append_string (dpi, "operator ");
-      d_print_comp (dpi, options, dc->u.s_extended_operator.name);
-      return;
+      {
+       struct demangle_component *name = dc->u.s_extended_operator.name;
+       if (name->type == DEMANGLE_COMPONENT_NAME
+           && !strncmp (name->u.s_name.s, "__alignof__", name->u.s_name.len))
+         d_print_comp (dpi, options, dc->u.s_extended_operator.name);
+       else
+         {
+           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 ");
@@ -5404,8 +5618,14 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
        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).  */
+       else if ((code && !strcmp (code, "st"))
+                || (op->type == DEMANGLE_COMPONENT_EXTENDED_OPERATOR
+                    && (op->u.s_extended_operator.name->type
+                        == DEMANGLE_COMPONENT_NAME)
+                    && !strncmp (op->u.s_extended_operator.name->u.s_name.s,
+                                 "__alignof__",
+                                 op->u.s_extended_operator.name->u.s_name.len)))
+         /* Always print parens for sizeof (type) and __alignof__.  */
          {
            d_append_char (dpi, '(');
            d_print_comp (dpi, options, operand);
@@ -5437,6 +5657,9 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
       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.  */
@@ -5494,6 +5717,8 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
        }
       if (d_maybe_print_fold_expression (dpi, options, dc))
        return;
+      if (d_maybe_print_designated_init (dpi, options, dc))
+       return;
       {
        struct demangle_component *op = d_left (dc);
        struct demangle_component *first = d_left (d_right (dc));
@@ -5724,13 +5949,14 @@ d_print_comp (struct d_print_info *dpi, int options,
              struct demangle_component *dc)
 {
   struct d_component_stack self;
-  if (dc == NULL || dc->d_printing > 1)
+  if (dc == NULL || dc->d_printing > 1 || dpi->recursion > MAX_RECURSION_COUNT)
     {
       d_print_error (dpi);
       return;
     }
-  else
-    dc->d_printing++;
+
+  dc->d_printing++;
+  dpi->recursion++;
 
   self.dc = dc;
   self.parent = dpi->component_stack;
@@ -5740,6 +5966,7 @@ d_print_comp (struct d_print_info *dpi, int options,
 
   dpi->component_stack = self.parent;
   dc->d_printing--;
+  dpi->recursion--;
 }
 
 /* Print a Java dentifier.  For Java we try to handle encoded extended
@@ -5941,10 +6168,10 @@ d_print_mod (struct d_print_info *dpi, int options,
       d_append_string (dpi, "&&");
       return;
     case DEMANGLE_COMPONENT_COMPLEX:
-      d_append_string (dpi, "complex ");
+      d_append_string (dpi, " _Complex");
       return;
     case DEMANGLE_COMPONENT_IMAGINARY:
-      d_append_string (dpi, "imaginary ");
+      d_append_string (dpi, " _Imaginary");
       return;
     case DEMANGLE_COMPONENT_PTRMEM_TYPE:
       if (d_last_char (dpi) != '(')
@@ -6182,23 +6409,23 @@ cplus_demangle_init_info (const char *mangled, int options, size_t len,
 
   di->n = mangled;
 
-  /* We can not need more components than twice the number of chars in
+  /* 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 = 2 * len;
   di->next_comp = 0;
 
-  /* Similarly, we can not need more substitutions than there are
+  /* Similarly, we cannot need more substitutions than there are
      chars in the mangled string.  */
   di->num_subs = len;
   di->next_sub = 0;
-  di->did_subs = 0;
 
   di->last_name = NULL;
 
   di->expansion = 0;
   di->is_expression = 0;
   di->is_conversion = 0;
+  di->recursion_level = 0;
 }
 
 /* Internal implementation for the demangler.  If MANGLED is a g++ v3 ABI
@@ -6236,8 +6463,25 @@ d_demangle_callback (const char *mangled, int options,
       type = DCT_TYPE;
     }
 
+  di.unresolved_name_state = 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) == 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;
+    }
+
   {
 #if 0 /* in valgrind */
 #ifdef CP_DYNAMIC_ARRAYS
@@ -6287,6 +6531,13 @@ d_demangle_callback (const char *mangled, int options,
     if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
       dc = NULL;
 
+    /* See discussion in d_unresolved_name.  */
+    if (dc == NULL && di.unresolved_name_state == -1)
+      {
+       di.unresolved_name_state = 0;
+       goto again;
+      }
+
 #ifdef CP_DEMANGLE_DEBUG
     d_dump (dc, 0);
 #endif
index a2657755f11d5359794857eb43e61bbd1656ae49..cb47bdf0d2e4554832f038d0571238b846562c88 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal demangler interface for g++ V3 ABI.
-   Copyright (C) 2003-2017 Free Software Foundation, Inc.
+   Copyright (C) 2003-2021 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@wasabisystems.com>.
 
    This file is part of the libiberty library, which is part of GCC.
@@ -111,10 +111,6 @@ struct d_info
   int next_sub;
   /* The number of available entries in the subs array.  */
   int num_subs;
-  /* The number of substitutions which we actually made from the subs
-     array, plus the number of template parameter references we
-     saw.  */
-  int did_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
@@ -126,6 +122,13 @@ struct d_info
   /* 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:
@@ -177,7 +180,7 @@ d_advance (struct d_info *di, int i)
 extern const struct demangle_operator_info cplus_demangle_operators[];
 #endif
 
-#define D_BUILTIN_TYPE_COUNT (33)
+#define D_BUILTIN_TYPE_COUNT (34)
 
 CP_STATIC_IF_GLIBCPP_V3
 const struct demangle_builtin_type_info
index cf16f381dc8d4dc17a9090442a94fb1085dca045..bf43790544df57fcbe07c0aed9d853c9efaab1e6 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for GNU C++
-   Copyright (C) 1989-2017 Free Software Foundation, Inc.
+   Copyright (C) 1989-2021 Free Software Foundation, Inc.
    Written by James Clark (jjc@jclark.uucp)
    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
    Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
@@ -29,12 +29,6 @@ License along with libiberty; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
-/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
-
-   This file imports xmalloc and xrealloc, which are like malloc and
-   realloc except that they generate a fatal error if there is no
-   available memory.  */
-
 /* This file lives in both GCC and libiberty.  When making changes, please
    try not to break either.  */
 
@@ -49,9 +43,7 @@ Boston, MA 02110-1301, USA.  */
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
-#include <sys/types.h>
 #include <string.h>
-#include <stdio.h>
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
@@ -63,19 +55,10 @@ void * realloc ();
 #endif
 #endif /* ! in valgrind */
 
-#if 0 /* in valgrind */
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#endif /* ! in valgrind */
-#ifndef INT_MAX
-# define INT_MAX       (int)(((unsigned int) ~0) >> 1)          /* 0x7FFFFFFF */ 
-#endif
-
 #if 0 /* in valgrind */
 #include <demangle.h>
 #undef CURRENT_DEMANGLING_STYLE
-#define CURRENT_DEMANGLING_STYLE work->options
+#define CURRENT_DEMANGLING_STYLE options
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
@@ -88,191 +71,8 @@ void * realloc ();
 #include "demangle.h"
 #include "safe-ctype.h"
 
-#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
-
-/* A value at least one greater than the maximum number of characters
-   that will be output when using the `%d' format with `printf'.  */
-#define INTBUF_SIZE 32
-
-extern void fancy_abort (void) ATTRIBUTE_NORETURN;
-
-/* In order to allow a single demangler executable to demangle strings
-   using various common values of CPLUS_MARKER, as well as any specific
-   one set at compile time, we maintain a string containing all the
-   commonly used ones, and check to see if the marker we are looking for
-   is in that string.  CPLUS_MARKER is usually '$' on systems where the
-   assembler can deal with that.  Where the assembler can't, it's usually
-   '.' (but on many systems '.' is used for other things).  We put the
-   current defined CPLUS_MARKER first (which defaults to '$'), followed
-   by the next most common value, followed by an explicit '$' in case
-   the value of CPLUS_MARKER is not '$'.
-
-   We could avoid this if we could just get g++ to tell us what the actual
-   cplus marker character is as part of the debug information, perhaps by
-   ensuring that it is the character that terminates the gcc<n>_compiled
-   marker symbol (FIXME).  */
-
-#if !defined (CPLUS_MARKER)
-#define CPLUS_MARKER '$'
-#endif
-
 enum demangling_styles current_demangling_style = auto_demangling;
 
-static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
-
-static char char_str[2] = { '\000', '\000' };
-
-void
-set_cplus_marker_for_demangling (int ch)
-{
-  cplus_markers[0] = ch;
-}
-
-typedef struct string          /* Beware: these aren't required to be */
-{                              /*  '\0' terminated.  */
-  char *b;                     /* pointer to start of string */
-  char *p;                     /* pointer after last character */
-  char *e;                     /* pointer after end of allocated space */
-} string;
-
-/* Stuff that is shared between sub-routines.
-   Using a shared structure allows cplus_demangle to be reentrant.  */
-
-struct work_stuff
-{
-  int options;
-  char **typevec;
-  char **ktypevec;
-  char **btypevec;
-  int numk;
-  int numb;
-  int ksize;
-  int bsize;
-  int ntypes;
-  int typevec_size;
-  int constructor;
-  int destructor;
-  int static_type;     /* A static member function */
-  int temp_start;       /* index in demangled to start of template args */
-  int type_quals;       /* The type qualifiers.  */
-  int dllimported;     /* Symbol imported from a PE DLL */
-  char **tmpl_argvec;   /* Template function arguments. */
-  int ntmpl_args;       /* The number of template function arguments. */
-  int forgetting_types; /* Nonzero if we are not remembering the types
-                          we see.  */
-  string* previous_argument; /* The last function argument demangled.  */
-  int nrepeats;         /* The number of times to repeat the previous
-                          argument.  */
-  int *proctypevec;     /* Indices of currently processed remembered typevecs.  */
-  int proctypevec_size;
-  int nproctypes;
-};
-
-#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
-#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
-
-static const struct optable
-{
-  const char *const in;
-  const char *const out;
-  const int flags;
-} optable[] = {
-  {"nw",         " new",       DMGL_ANSI},     /* new (1.92,    ansi) */
-  {"dl",         " delete",    DMGL_ANSI},     /* new (1.92,    ansi) */
-  {"new",        " new",       0},             /* old (1.91,    and 1.x) */
-  {"delete",     " delete",    0},             /* old (1.91,    and 1.x) */
-  {"vn",         " new []",    DMGL_ANSI},     /* GNU, pending ansi */
-  {"vd",         " delete []", DMGL_ANSI},     /* GNU, pending ansi */
-  {"as",         "=",          DMGL_ANSI},     /* ansi */
-  {"ne",         "!=",         DMGL_ANSI},     /* old, ansi */
-  {"eq",         "==",         DMGL_ANSI},     /* old, ansi */
-  {"ge",         ">=",         DMGL_ANSI},     /* old, ansi */
-  {"gt",         ">",          DMGL_ANSI},     /* old, ansi */
-  {"le",         "<=",         DMGL_ANSI},     /* old, ansi */
-  {"lt",         "<",          DMGL_ANSI},     /* old, ansi */
-  {"plus",       "+",          0},             /* old */
-  {"pl",         "+",          DMGL_ANSI},     /* ansi */
-  {"apl",        "+=",         DMGL_ANSI},     /* ansi */
-  {"minus",      "-",          0},             /* old */
-  {"mi",         "-",          DMGL_ANSI},     /* ansi */
-  {"ami",        "-=",         DMGL_ANSI},     /* ansi */
-  {"mult",       "*",          0},             /* old */
-  {"ml",         "*",          DMGL_ANSI},     /* ansi */
-  {"amu",        "*=",         DMGL_ANSI},     /* ansi (ARM/Lucid) */
-  {"aml",        "*=",         DMGL_ANSI},     /* ansi (GNU/g++) */
-  {"convert",    "+",          0},             /* old (unary +) */
-  {"negate",     "-",          0},             /* old (unary -) */
-  {"trunc_mod",          "%",          0},             /* old */
-  {"md",         "%",          DMGL_ANSI},     /* ansi */
-  {"amd",        "%=",         DMGL_ANSI},     /* ansi */
-  {"trunc_div",          "/",          0},             /* old */
-  {"dv",         "/",          DMGL_ANSI},     /* ansi */
-  {"adv",        "/=",         DMGL_ANSI},     /* ansi */
-  {"truth_andif", "&&",                0},             /* old */
-  {"aa",         "&&",         DMGL_ANSI},     /* ansi */
-  {"truth_orif",  "||",                0},             /* old */
-  {"oo",         "||",         DMGL_ANSI},     /* ansi */
-  {"truth_not",          "!",          0},             /* old */
-  {"nt",         "!",          DMGL_ANSI},     /* ansi */
-  {"postincrement","++",       0},             /* old */
-  {"pp",         "++",         DMGL_ANSI},     /* ansi */
-  {"postdecrement","--",       0},             /* old */
-  {"mm",         "--",         DMGL_ANSI},     /* ansi */
-  {"bit_ior",    "|",          0},             /* old */
-  {"or",         "|",          DMGL_ANSI},     /* ansi */
-  {"aor",        "|=",         DMGL_ANSI},     /* ansi */
-  {"bit_xor",    "^",          0},             /* old */
-  {"er",         "^",          DMGL_ANSI},     /* ansi */
-  {"aer",        "^=",         DMGL_ANSI},     /* ansi */
-  {"bit_and",    "&",          0},             /* old */
-  {"ad",         "&",          DMGL_ANSI},     /* ansi */
-  {"aad",        "&=",         DMGL_ANSI},     /* ansi */
-  {"bit_not",    "~",          0},             /* old */
-  {"co",         "~",          DMGL_ANSI},     /* ansi */
-  {"call",       "()",         0},             /* old */
-  {"cl",         "()",         DMGL_ANSI},     /* ansi */
-  {"alshift",    "<<",         0},             /* old */
-  {"ls",         "<<",         DMGL_ANSI},     /* ansi */
-  {"als",        "<<=",        DMGL_ANSI},     /* ansi */
-  {"arshift",    ">>",         0},             /* old */
-  {"rs",         ">>",         DMGL_ANSI},     /* ansi */
-  {"ars",        ">>=",        DMGL_ANSI},     /* ansi */
-  {"component",          "->",         0},             /* old */
-  {"pt",         "->",         DMGL_ANSI},     /* ansi; Lucid C++ form */
-  {"rf",         "->",         DMGL_ANSI},     /* ansi; ARM/GNU form */
-  {"indirect",   "*",          0},             /* old */
-  {"method_call",  "->()",     0},             /* old */
-  {"addr",       "&",          0},             /* old (unary &) */
-  {"array",      "[]",         0},             /* old */
-  {"vc",         "[]",         DMGL_ANSI},     /* ansi */
-  {"compound",   ", ",         0},             /* old */
-  {"cm",         ", ",         DMGL_ANSI},     /* ansi */
-  {"cond",       "?:",         0},             /* old */
-  {"cn",         "?:",         DMGL_ANSI},     /* pseudo-ansi */
-  {"max",        ">?",         0},             /* old */
-  {"mx",         ">?",         DMGL_ANSI},     /* pseudo-ansi */
-  {"min",        "<?",         0},             /* old */
-  {"mn",         "<?",         DMGL_ANSI},     /* pseudo-ansi */
-  {"nop",        "",           0},             /* old (for operator=) */
-  {"rm",         "->*",        DMGL_ANSI},     /* ansi */
-  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
-};
-
-/* These values are used to indicate the various type varieties.
-   They are all non-zero so that they can be used as `success'
-   values.  */
-typedef enum type_kind_t
-{
-  tk_none,
-  tk_pointer,
-  tk_reference,
-  tk_rvalue_reference,
-  tk_integral,
-  tk_bool,
-  tk_char,
-  tk_real
-} type_kind_t;
-
 const struct demangler_engine libiberty_demanglers[] =
 {
   {
@@ -287,40 +87,10 @@ const struct demangler_engine libiberty_demanglers[] =
       "Automatic selection based on executable"
   }
   ,
-  {
-    GNU_DEMANGLING_STYLE_STRING,
-      gnu_demangling,
-      "GNU (g++) style demangling"
-  }
-  ,
-  {
-    LUCID_DEMANGLING_STYLE_STRING,
-      lucid_demangling,
-      "Lucid (lcc) style demangling"
-  }
-  ,
-  {
-    ARM_DEMANGLING_STYLE_STRING,
-      arm_demangling,
-      "ARM style demangling"
-  }
-  ,
-  {
-    HP_DEMANGLING_STYLE_STRING,
-      hp_demangling,
-      "HP (aCC) style demangling"
-  }
-  ,
-  {
-    EDG_DEMANGLING_STYLE_STRING,
-      edg_demangling,
-      "EDG style demangling"
-  }
-  ,
   {
     GNU_V3_DEMANGLING_STYLE_STRING,
     gnu_v3_demangling,
-    "GNU (g++) V3 ABI-style demangling"
+    "GNU (g++) V3 (Itanium C++ ABI) style demangling"
   }
   ,
   {
@@ -352,477 +122,6 @@ const struct demangler_engine libiberty_demanglers[] =
   }
 };
 
-#define STRING_EMPTY(str)      ((str) -> b == (str) -> p)
-#define APPEND_BLANK(str)      {if (!STRING_EMPTY(str)) \
-    string_append(str, " ");}
-#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
-
-/* The scope separator appropriate for the language being demangled.  */
-
-#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
-
-#define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/ARM virtual table prefix */
-#define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
-
-/* Prototypes for local functions */
-
-static void delete_work_stuff (struct work_stuff *);
-
-static void delete_non_B_K_work_stuff (struct work_stuff *);
-
-static char *mop_up (struct work_stuff *, string *, int);
-
-static void squangle_mop_up (struct work_stuff *);
-
-static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *);
-
-#if 0
-static int
-demangle_method_args (struct work_stuff *, const char **, string *);
-#endif
-
-static char *
-internal_cplus_demangle (struct work_stuff *, const char *);
-
-static int
-demangle_template_template_parm (struct work_stuff *work,
-                                 const char **, string *);
-
-static int
-demangle_template (struct work_stuff *work, const char **, string *,
-                   string *, int, int);
-
-static int
-arm_pt (const char *, int, const char **, const char **);
-
-static int
-demangle_class_name (struct work_stuff *, const char **, string *);
-
-static int
-demangle_qualified (struct work_stuff *, const char **, string *,
-                    int, int);
-
-static int demangle_class (struct work_stuff *, const char **, string *);
-
-static int demangle_fund_type (struct work_stuff *, const char **, string *);
-
-static int demangle_signature (struct work_stuff *, const char **, string *);
-
-static int demangle_prefix (struct work_stuff *, const char **, string *);
-
-static int gnu_special (struct work_stuff *, const char **, string *);
-
-static int arm_special (const char **, string *);
-
-static void string_need (string *, int);
-
-static void string_delete (string *);
-
-static void
-string_init (string *);
-
-static void string_clear (string *);
-
-#if 0
-static int string_empty (string *);
-#endif
-
-static void string_append (string *, const char *);
-
-static void string_appends (string *, string *);
-
-static void string_appendn (string *, const char *, int);
-
-static void string_prepend (string *, const char *);
-
-static void string_prependn (string *, const char *, int);
-
-static void string_append_template_idx (string *, int);
-
-static int get_count (const char **, int *);
-
-static int consume_count (const char **);
-
-static int consume_count_with_underscores (const char**);
-
-static int demangle_args (struct work_stuff *, const char **, string *);
-
-static int demangle_nested_args (struct work_stuff*, const char**, string*);
-
-static int do_type (struct work_stuff *, const char **, string *);
-
-static int do_arg (struct work_stuff *, const char **, string *);
-
-static int
-demangle_function_name (struct work_stuff *, const char **, string *,
-                        const char *);
-
-static int
-iterate_demangle_function (struct work_stuff *,
-                           const char **, string *, const char *);
-
-static void remember_type (struct work_stuff *, const char *, int);
-
-static void push_processed_type (struct work_stuff *, int);
-
-static void pop_processed_type (struct work_stuff *);
-
-static void remember_Btype (struct work_stuff *, const char *, int, int);
-
-static int register_Btype (struct work_stuff *);
-
-static void remember_Ktype (struct work_stuff *, const char *, int);
-
-static void forget_types (struct work_stuff *);
-
-static void forget_B_and_K_types (struct work_stuff *);
-
-static void string_prepends (string *, string *);
-
-static int
-demangle_template_value_parm (struct work_stuff*, const char**,
-                              string*, type_kind_t);
-
-static int
-do_hpacc_template_const_value (struct work_stuff *, const char **, string *);
-
-static int
-do_hpacc_template_literal (struct work_stuff *, const char **, string *);
-
-static int snarf_numeric_literal (const char **, string *);
-
-/* There is a TYPE_QUAL value for each type qualifier.  They can be
-   combined by bitwise-or to form the complete set of qualifiers for a
-   type.  */
-
-#define TYPE_UNQUALIFIED   0x0
-#define TYPE_QUAL_CONST    0x1
-#define TYPE_QUAL_VOLATILE 0x2
-#define TYPE_QUAL_RESTRICT 0x4
-
-static int code_for_qualifier (int);
-
-static const char* qualifier_string (int);
-
-static const char* demangle_qualifier (int);
-
-static int demangle_expression (struct work_stuff *, const char **, string *, 
-                                type_kind_t);
-
-static int
-demangle_integral_value (struct work_stuff *, const char **, string *);
-
-static int
-demangle_real_value (struct work_stuff *, const char **, string *);
-
-static void
-demangle_arm_hp_template (struct work_stuff *, const char **, int, string *);
-
-static void
-recursively_demangle (struct work_stuff *, const char **, string *, int);
-
-/* Translate count to integer, consuming tokens in the process.
-   Conversion terminates on the first non-digit character.
-
-   Trying to consume something that isn't a count results in no
-   consumption of input and a return of -1.
-
-   Overflow consumes the rest of the digits, and returns -1.  */
-
-static int
-consume_count (const char **type)
-{
-  int count = 0;
-
-  if (! ISDIGIT ((unsigned char)**type))
-    return -1;
-
-  while (ISDIGIT ((unsigned char)**type))
-    {
-      count *= 10;
-
-      /* Check for overflow.
-        We assume that count is represented using two's-complement;
-        no power of two is divisible by ten, so if an overflow occurs
-        when multiplying by ten, the result will not be a multiple of
-        ten.  */
-      if ((count % 10) != 0)
-       {
-         while (ISDIGIT ((unsigned char) **type))
-           (*type)++;
-         return -1;
-       }
-
-      count += **type - '0';
-      (*type)++;
-    }
-
-  if (count < 0)
-    count = -1;
-
-  return (count);
-}
-
-
-/* Like consume_count, but for counts that are preceded and followed
-   by '_' if they are greater than 10.  Also, -1 is returned for
-   failure, since 0 can be a valid value.  */
-
-static int
-consume_count_with_underscores (const char **mangled)
-{
-  int idx;
-
-  if (**mangled == '_')
-    {
-      (*mangled)++;
-      if (!ISDIGIT ((unsigned char)**mangled))
-       return -1;
-
-      idx = consume_count (mangled);
-      if (**mangled != '_')
-       /* The trailing underscore was missing. */
-       return -1;
-
-      (*mangled)++;
-    }
-  else
-    {
-      if (**mangled < '0' || **mangled > '9')
-       return -1;
-
-      idx = **mangled - '0';
-      (*mangled)++;
-    }
-
-  return idx;
-}
-
-/* C is the code for a type-qualifier.  Return the TYPE_QUAL
-   corresponding to this qualifier.  */
-
-static int
-code_for_qualifier (int c)
-{
-  switch (c)
-    {
-    case 'C':
-      return TYPE_QUAL_CONST;
-
-    case 'V':
-      return TYPE_QUAL_VOLATILE;
-
-    case 'u':
-      return TYPE_QUAL_RESTRICT;
-
-    default:
-      break;
-    }
-
-  /* C was an invalid qualifier.  */
-  abort ();
-}
-
-/* Return the string corresponding to the qualifiers given by
-   TYPE_QUALS.  */
-
-static const char*
-qualifier_string (int type_quals)
-{
-  switch (type_quals)
-    {
-    case TYPE_UNQUALIFIED:
-      return "";
-
-    case TYPE_QUAL_CONST:
-      return "const";
-
-    case TYPE_QUAL_VOLATILE:
-      return "volatile";
-
-    case TYPE_QUAL_RESTRICT:
-      return "__restrict";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
-      return "const volatile";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
-      return "const __restrict";
-
-    case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
-      return "volatile __restrict";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
-      return "const volatile __restrict";
-
-    default:
-      break;
-    }
-
-  /* TYPE_QUALS was an invalid qualifier set.  */
-  abort ();
-}
-
-/* C is the code for a type-qualifier.  Return the string
-   corresponding to this qualifier.  This function should only be
-   called with a valid qualifier code.  */
-
-static const char*
-demangle_qualifier (int c)
-{
-  return qualifier_string (code_for_qualifier (c));
-}
-
-int
-cplus_demangle_opname (const char *opname, char *result, int options)
-{
-  int len, len1, ret;
-  string type;
-  struct work_stuff work[1];
-  const char *tem;
-
-  len = strlen(opname);
-  result[0] = '\0';
-  ret = 0;
-  memset ((char *) work, 0, sizeof (work));
-  work->options = options;
-
-  if (opname[0] == '_' && opname[1] == '_'
-      && opname[2] == 'o' && opname[3] == 'p')
-    {
-      /* ANSI.  */
-      /* type conversion operator.  */
-      tem = opname + 4;
-      if (do_type (work, &tem, &type))
-       {
-         strcat (result, "operator ");
-         strncat (result, type.b, type.p - type.b);
-         string_delete (&type);
-         ret = 1;
-       }
-    }
-  else if (opname[0] == '_' && opname[1] == '_'
-          && ISLOWER((unsigned char)opname[2])
-          && ISLOWER((unsigned char)opname[3]))
-    {
-      if (opname[4] == '\0')
-       {
-         /* Operator.  */
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             if (strlen (optable[i].in) == 2
-                 && memcmp (optable[i].in, opname + 2, 2) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-      else
-       {
-         if (opname[2] == 'a' && opname[5] == '\0')
-           {
-             /* Assignment.  */
-             size_t i;
-             for (i = 0; i < ARRAY_SIZE (optable); i++)
-               {
-                 if (strlen (optable[i].in) == 3
-                     && memcmp (optable[i].in, opname + 2, 3) == 0)
-                   {
-                     strcat (result, "operator");
-                     strcat (result, optable[i].out);
-                     ret = 1;
-                     break;
-                   }
-               }
-           }
-       }
-    }
-  else if (len >= 3
-          && opname[0] == 'o'
-          && opname[1] == 'p'
-          && strchr (cplus_markers, opname[2]) != NULL)
-    {
-      /* see if it's an assignment expression */
-      if (len >= 10 /* op$assign_ */
-         && memcmp (opname + 3, "assign_", 7) == 0)
-       {
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             len1 = len - 10;
-             if ((int) strlen (optable[i].in) == len1
-                 && memcmp (optable[i].in, opname + 10, len1) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 strcat (result, "=");
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-      else
-       {
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             len1 = len - 3;
-             if ((int) strlen (optable[i].in) == len1
-                 && memcmp (optable[i].in, opname + 3, len1) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-    }
-  else if (len >= 5 && memcmp (opname, "type", 4) == 0
-          && strchr (cplus_markers, opname[4]) != NULL)
-    {
-      /* type conversion operator */
-      tem = opname + 5;
-      if (do_type (work, &tem, &type))
-       {
-         strcat (result, "operator ");
-         strncat (result, type.b, type.p - type.b);
-         string_delete (&type);
-         ret = 1;
-       }
-    }
-  squangle_mop_up (work);
-  return ret;
-
-}
-
-/* Takes operator name as e.g. "++" and returns mangled
-   operator name (e.g. "postincrement_expr"), or NULL if not found.
-
-   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
-   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
-
-const char *
-cplus_mangle_opname (const char *opname, int options)
-{
-  size_t i;
-  int len;
-
-  len = strlen (opname);
-  for (i = 0; i < ARRAY_SIZE (optable); i++)
-    {
-      if ((int) strlen (optable[i].out) == len
-         && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
-         && memcmp (optable[i].out, opname, len) == 0)
-       return optable[i].in;
-    }
-  return (0);
-}
-
 /* Add a routine to set the demangling style to be sure it is valid and
    allow for any demangler initialization that maybe necessary. */
 
@@ -863,22 +162,6 @@ cplus_demangle_name_to_style (const char *name)
    It is the caller's responsibility to free the string which
    is returned.
 
-   The OPTIONS arg may contain one or more of the following bits:
-
-       DMGL_ANSI       ANSI qualifiers such as `const' and `void' are
-                       included.
-       DMGL_PARAMS     Function parameters are included.
-
-   For example,
-
-   cplus_demangle ("foo__1Ai", DMGL_PARAMS)            => "A::foo(int)"
-   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)        => "A::foo(int)"
-   cplus_demangle ("foo__1Ai", 0)                      => "A::foo"
-
-   cplus_demangle ("foo__1Afe", DMGL_PARAMS)           => "A::foo(float,...)"
-   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
-   cplus_demangle ("foo__1Afe", 0)                     => "A::foo"
-
    Note that any leading underscores, or other such characters prepended by
    the compilation system, are presumed to have already been stripped from
    MANGLED.  */
@@ -887,37 +170,27 @@ char *
 ML_(cplus_demangle) (const char *mangled, int options)
 {
   char *ret;
-  struct work_stuff work[1];
 
   if (current_demangling_style == no_demangling)
     return xstrdup (mangled);
 
-  memset ((char *) work, 0, sizeof (work));
-  work->options = options;
-  if ((work->options & DMGL_STYLE_MASK) == 0)
-    work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+  if ((options & DMGL_STYLE_MASK) == 0)
+    options |= (int) current_demangling_style & DMGL_STYLE_MASK;
 
-  /* The V3 ABI demangling is implemented elsewhere.  */
-  if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING)
+  /* The Rust demangling is implemented elsewhere.
+     Legacy Rust symbols overlap with GNU_V3, so try Rust first.  */
+  if (RUST_DEMANGLING || AUTO_DEMANGLING)
     {
-      ret = cplus_demangle_v3 (mangled, work->options);
-      if (GNU_V3_DEMANGLING)
-       return ret;
-
-      if (ret)
-       {
-         /* Rust symbols are GNU_V3 mangled plus some extra subtitutions.
-            The subtitutions are always smaller, so do in place changes.  */
-         if (rust_is_mangled (ret))
-           rust_demangle_sym (ret);
-         else if (RUST_DEMANGLING)
-           {
-             free (ret);
-             ret = NULL;
-           }
-       }
-
+      ret = rust_demangle (mangled, options);
       if (ret || RUST_DEMANGLING)
+        return ret;
+    }
+
+  /* The V3 ABI demangling is implemented elsewhere.  */
+  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
+    {
+      ret = cplus_demangle_v3 (mangled, options);
+      if (ret || GNU_V3_DEMANGLING)
        return ret;
     }
 
@@ -938,32 +211,9 @@ ML_(cplus_demangle) (const char *mangled, int options)
        return ret;
     }
 
-  ret = internal_cplus_demangle (work, mangled);
-  squangle_mop_up (work);
   return (ret);
 }
 
-char *
-rust_demangle (const char *mangled, int options)
-{
-  /* Rust symbols are GNU_V3 mangled plus some extra subtitutions.  */
-  char *ret = cplus_demangle_v3 (mangled, options);
-
-  /* The Rust subtitutions are always smaller, so do in place changes.  */
-  if (ret != NULL)
-    {
-      if (rust_is_mangled (ret))
-       rust_demangle_sym (ret);
-      else
-       {
-         free (ret);
-         ret = NULL;
-       }
-    }
-
-  return ret;
-}
-
 /* Demangle ada names.  The encoding is documented in gcc/ada/exp_dbug.ads.  */
 
 char *
@@ -1228,3849 +478,3 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
 
   return demangled;
 }
-
-/* This function performs most of what cplus_demangle use to do, but
-   to be able to demangle a name with a B, K or n code, we need to
-   have a longer term memory of what types have been seen. The original
-   now initializes and cleans up the squangle code info, while internal
-   calls go directly to this routine to avoid resetting that info. */
-
-static char *
-internal_cplus_demangle (struct work_stuff *work, const char *mangled)
-{
-
-  string decl;
-  int success = 0;
-  char *demangled = NULL;
-  int s1, s2, s3, s4;
-  s1 = work->constructor;
-  s2 = work->destructor;
-  s3 = work->static_type;
-  s4 = work->type_quals;
-  work->constructor = work->destructor = 0;
-  work->type_quals = TYPE_UNQUALIFIED;
-  work->dllimported = 0;
-
-  if ((mangled != NULL) && (*mangled != '\0'))
-    {
-      string_init (&decl);
-
-      /* First check to see if gnu style demangling is active and if the
-        string to be demangled contains a CPLUS_MARKER.  If so, attempt to
-        recognize one of the gnu special forms rather than looking for a
-        standard prefix.  In particular, don't worry about whether there
-        is a "__" string in the mangled string.  Consider "_$_5__foo" for
-        example.  */
-
-      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
-       {
-         success = gnu_special (work, &mangled, &decl);
-         if (!success)
-           {
-             delete_work_stuff (work);
-             string_delete (&decl);
-           }
-       }
-      if (!success)
-       {
-         success = demangle_prefix (work, &mangled, &decl);
-       }
-      if (success && (*mangled != '\0'))
-       {
-         success = demangle_signature (work, &mangled, &decl);
-       }
-      if (work->constructor == 2)
-        {
-          string_prepend (&decl, "global constructors keyed to ");
-          work->constructor = 0;
-        }
-      else if (work->destructor == 2)
-        {
-          string_prepend (&decl, "global destructors keyed to ");
-          work->destructor = 0;
-        }
-      else if (work->dllimported == 1)
-        {
-          string_prepend (&decl, "import stub for ");
-          work->dllimported = 0;
-        }
-      demangled = mop_up (work, &decl, success);
-    }
-  work->constructor = s1;
-  work->destructor = s2;
-  work->static_type = s3;
-  work->type_quals = s4;
-  return demangled;
-}
-
-
-/* Clear out and squangling related storage */
-static void
-squangle_mop_up (struct work_stuff *work)
-{
-  /* clean up the B and K type mangling types. */
-  forget_B_and_K_types (work);
-  if (work -> btypevec != NULL)
-    {
-      free ((char *) work -> btypevec);
-      work->btypevec = NULL;
-      work->bsize = 0;
-    }
-  if (work -> ktypevec != NULL)
-    {
-      free ((char *) work -> ktypevec);
-      work->ktypevec = NULL;
-      work->ksize = 0;
-    }
-}
-
-
-/* Copy the work state and storage.  */
-
-static void
-work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
-{
-  int i;
-
-  delete_work_stuff (to);
-
-  /* Shallow-copy scalars.  */
-  memcpy (to, from, sizeof (*to));
-
-  /* Deep-copy dynamic storage.  */
-  if (from->typevec_size)
-    to->typevec = XNEWVEC (char *, from->typevec_size);
-
-  for (i = 0; i < from->ntypes; i++)
-    {
-      int len = strlen (from->typevec[i]) + 1;
-
-      to->typevec[i] = XNEWVEC (char, len);
-      memcpy (to->typevec[i], from->typevec[i], len);
-    }
-
-  if (from->ksize)
-    to->ktypevec = XNEWVEC (char *, from->ksize);
-
-  for (i = 0; i < from->numk; i++)
-    {
-      int len = strlen (from->ktypevec[i]) + 1;
-
-      to->ktypevec[i] = XNEWVEC (char, len);
-      memcpy (to->ktypevec[i], from->ktypevec[i], len);
-    }
-
-  if (from->bsize)
-    to->btypevec = XNEWVEC (char *, from->bsize);
-
-  for (i = 0; i < from->numb; i++)
-    {
-      int len = strlen (from->btypevec[i]) + 1;
-
-      to->btypevec[i] = XNEWVEC (char , len);
-      memcpy (to->btypevec[i], from->btypevec[i], len);
-    }
-
-  if (from->proctypevec)
-    to->proctypevec =
-      XDUPVEC (int, from->proctypevec, from->proctypevec_size);
-
-  if (from->ntmpl_args)
-    to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
-
-  for (i = 0; i < from->ntmpl_args; i++)
-    {
-      int len = strlen (from->tmpl_argvec[i]) + 1;
-
-      to->tmpl_argvec[i] = XNEWVEC (char, len);
-      memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
-    }
-
-  if (from->previous_argument)
-    {
-      to->previous_argument = XNEW (string);
-      string_init (to->previous_argument);
-      string_appends (to->previous_argument, from->previous_argument);
-    }
-}
-
-
-/* Delete dynamic stuff in work_stuff that is not to be re-used.  */
-
-static void
-delete_non_B_K_work_stuff (struct work_stuff *work)
-{
-  /* Discard the remembered types, if any.  */
-
-  forget_types (work);
-  if (work->typevec != NULL)
-    {
-      free ((char *) work->typevec);
-      work->typevec = NULL;
-      work->typevec_size = 0;
-    }
-  if (work->proctypevec != NULL)
-    {
-      free (work->proctypevec);
-      work->proctypevec = NULL;
-      work->proctypevec_size = 0;
-    }
-  if (work->tmpl_argvec)
-    {
-      int i;
-
-      for (i = 0; i < work->ntmpl_args; i++)
-       free ((char*) work->tmpl_argvec[i]);
-
-      free ((char*) work->tmpl_argvec);
-      work->tmpl_argvec = NULL;
-    }
-  if (work->previous_argument)
-    {
-      string_delete (work->previous_argument);
-      free ((char*) work->previous_argument);
-      work->previous_argument = NULL;
-    }
-}
-
-
-/* Delete all dynamic storage in work_stuff.  */
-static void
-delete_work_stuff (struct work_stuff *work)
-{
-  delete_non_B_K_work_stuff (work);
-  squangle_mop_up (work);
-}
-
-
-/* Clear out any mangled storage */
-
-static char *
-mop_up (struct work_stuff *work, string *declp, int success)
-{
-  char *demangled = NULL;
-
-  delete_non_B_K_work_stuff (work);
-
-  /* If demangling was successful, ensure that the demangled string is null
-     terminated and return it.  Otherwise, free the demangling decl.  */
-
-  if (!success)
-    {
-      string_delete (declp);
-    }
-  else
-    {
-      string_appendn (declp, "", 1);
-      demangled = declp->b;
-    }
-  return (demangled);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_signature -- demangle the signature part of a mangled name
-
-SYNOPSIS
-
-       static int
-       demangle_signature (struct work_stuff *work, const char **mangled,
-                           string *declp);
-
-DESCRIPTION
-
-       Consume and demangle the signature portion of the mangled name.
-
-       DECLP is the string where demangled output is being built.  At
-       entry it contains the demangled root name from the mangled name
-       prefix.  I.E. either a demangled operator name or the root function
-       name.  In some special cases, it may contain nothing.
-
-       *MANGLED points to the current unconsumed location in the mangled
-       name.  As tokens are consumed and demangling is performed, the
-       pointer is updated to continuously point at the next token to
-       be consumed.
-
-       Demangling GNU style mangled names is nasty because there is no
-       explicit token that marks the start of the outermost function
-       argument list.  */
-
-static int
-demangle_signature (struct work_stuff *work,
-                    const char **mangled, string *declp)
-{
-  int success = 1;
-  int func_done = 0;
-  int expect_func = 0;
-  int expect_return_type = 0;
-  const char *oldmangled = NULL;
-  string trawname;
-  string tname;
-
-  while (success && (**mangled != '\0'))
-    {
-      switch (**mangled)
-       {
-       case 'Q':
-         oldmangled = *mangled;
-         success = demangle_qualified (work, mangled, declp, 1, 0);
-         if (success)
-           remember_type (work, oldmangled, *mangled - oldmangled);
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           expect_func = 1;
-         oldmangled = NULL;
-         break;
-
-        case 'K':
-         //oldmangled = *mangled;
-         success = demangle_qualified (work, mangled, declp, 1, 0);
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             expect_func = 1;
-           }
-         oldmangled = NULL;
-         break;
-
-       case 'S':
-         /* Static member function */
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-         (*mangled)++;
-         work -> static_type = 1;
-         break;
-
-       case 'C':
-       case 'V':
-       case 'u':
-         work->type_quals |= code_for_qualifier (**mangled);
-
-         /* a qualified member function */
-         if (oldmangled == NULL)
-           oldmangled = *mangled;
-         (*mangled)++;
-         break;
-
-       case 'L':
-         /* Local class name follows after "Lnnn_" */
-         if (HP_DEMANGLING)
-           {
-             while (**mangled && (**mangled != '_'))
-               (*mangled)++;
-             if (!**mangled)
-               success = 0;
-             else
-               (*mangled)++;
-           }
-         else
-           success = 0;
-         break;
-
-       case '0': case '1': case '2': case '3': case '4':
-       case '5': case '6': case '7': case '8': case '9':
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-          work->temp_start = -1; /* uppermost call to demangle_class */
-         success = demangle_class (work, mangled, declp);
-         if (success)
-           {
-             remember_type (work, oldmangled, *mangled - oldmangled);
-           }
-         if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
-           {
-              /* EDG and others will have the "F", so we let the loop cycle
-                 if we are looking at one. */
-              if (**mangled != 'F')
-                 expect_func = 1;
-           }
-         oldmangled = NULL;
-         break;
-
-       case 'B':
-         {
-           string s;
-           success = do_type (work, mangled, &s);
-           if (success)
-             {
-               string_append (&s, SCOPE_STRING (work));
-               string_prepends (declp, &s);
-               string_delete (&s);
-             }
-           oldmangled = NULL;
-           expect_func = 1;
-         }
-         break;
-
-       case 'F':
-         /* Function */
-         /* ARM/HP style demangling includes a specific 'F' character after
-            the class name.  For GNU style, it is just implied.  So we can
-            safely just consume any 'F' at this point and be compatible
-            with either style.  */
-
-         oldmangled = NULL;
-         func_done = 1;
-         (*mangled)++;
-
-         /* For lucid/ARM/HP style we have to forget any types we might
-            have remembered up to this point, since they were not argument
-            types.  GNU style considers all types seen as available for
-            back references.  See comment in demangle_args() */
-
-         if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-           {
-             forget_types (work);
-           }
-         success = demangle_args (work, mangled, declp);
-         /* After picking off the function args, we expect to either
-            find the function return type (preceded by an '_') or the
-            end of the string. */
-         if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
-           {
-             ++(*mangled);
-              /* At this level, we do not care about the return type. */
-              success = do_type (work, mangled, &tname);
-              string_delete (&tname);
-            }
-
-         break;
-
-       case 't':
-         /* G++ Template */
-         string_init(&trawname);
-         string_init(&tname);
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-         success = demangle_template (work, mangled, &tname,
-                                      &trawname, 1, 1);
-         if (success)
-           {
-             remember_type (work, oldmangled, *mangled - oldmangled);
-           }
-         string_append (&tname, SCOPE_STRING (work));
-
-         string_prepends(declp, &tname);
-         if (work -> destructor & 1)
-           {
-             string_prepend (&trawname, "~");
-             string_appends (declp, &trawname);
-             work->destructor -= 1;
-           }
-         if ((work->constructor & 1) || (work->destructor & 1))
-           {
-             string_appends (declp, &trawname);
-             work->constructor -= 1;
-           }
-         string_delete(&trawname);
-         string_delete(&tname);
-         oldmangled = NULL;
-         expect_func = 1;
-         break;
-
-       case '_':
-         if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
-           {
-             /* Read the return type. */
-             string return_type;
-
-             (*mangled)++;
-             success = do_type (work, mangled, &return_type);
-             APPEND_BLANK (&return_type);
-
-             string_prepends (declp, &return_type);
-             string_delete (&return_type);
-             break;
-           }
-         else
-           /* At the outermost level, we cannot have a return type specified,
-              so if we run into another '_' at this point we are dealing with
-              a mangled name that is either bogus, or has been mangled by
-              some algorithm we don't know how to deal with.  So just
-              reject the entire demangling.  */
-            /* However, "_nnn" is an expected suffix for alternate entry point
-               numbered nnn for a function, with HP aCC, so skip over that
-               without reporting failure. pai/1997-09-04 */
-            if (HP_DEMANGLING)
-              {
-                (*mangled)++;
-                while (**mangled && ISDIGIT ((unsigned char)**mangled))
-                  (*mangled)++;
-              }
-            else
-             success = 0;
-         break;
-
-       case 'H':
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             /* A G++ template function.  Read the template arguments. */
-             success = demangle_template (work, mangled, declp, 0, 0,
-                                          0);
-             if (!(work->constructor & 1))
-               expect_return_type = 1;
-             if (!**mangled)
-               success = 0;
-             else
-               (*mangled)++;
-             break;
-           }
-         /* fall through */
-
-       default:
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             /* Assume we have stumbled onto the first outermost function
-                argument token, and start processing args.  */
-             func_done = 1;
-             success = demangle_args (work, mangled, declp);
-           }
-         else
-           {
-             /* Non-GNU demanglers use a specific token to mark the start
-                of the outermost function argument tokens.  Typically 'F',
-                for ARM/HP-demangling, for example.  So if we find something
-                we are not prepared for, it must be an error.  */
-             success = 0;
-           }
-         break;
-       }
-      /*
-       if (AUTO_DEMANGLING || GNU_DEMANGLING)
-       */
-      {
-       if (success && expect_func)
-         {
-           func_done = 1;
-              if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
-                {
-                  forget_types (work);
-                }
-           success = demangle_args (work, mangled, declp);
-           /* Since template include the mangling of their return types,
-              we must set expect_func to 0 so that we don't try do
-              demangle more arguments the next time we get here.  */
-           expect_func = 0;
-         }
-      }
-    }
-  if (success && !func_done)
-    {
-      if (AUTO_DEMANGLING || GNU_DEMANGLING)
-       {
-         /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
-            bar__3fooi is 'foo::bar(int)'.  We get here when we find the
-            first case, and need to ensure that the '(void)' gets added to
-            the current declp.  Note that with ARM/HP, the first case
-            represents the name of a static data member 'foo::bar',
-            which is in the current declp, so we leave it alone.  */
-         success = demangle_args (work, mangled, declp);
-       }
-    }
-  if (success && PRINT_ARG_TYPES)
-    {
-      if (work->static_type)
-       string_append (declp, " static");
-      if (work->type_quals != TYPE_UNQUALIFIED)
-       {
-         APPEND_BLANK (declp);
-         string_append (declp, qualifier_string (work->type_quals));
-       }
-    }
-
-  return (success);
-}
-
-#if 0
-
-static int
-demangle_method_args (struct work_stuff *work, const char **mangled,
-                      string *declp)
-{
-  int success = 0;
-
-  if (work -> static_type)
-    {
-      string_append (declp, *mangled + 1);
-      *mangled += strlen (*mangled);
-      success = 1;
-    }
-  else
-    {
-      success = demangle_args (work, mangled, declp);
-    }
-  return (success);
-}
-
-#endif
-
-static int
-demangle_template_template_parm (struct work_stuff *work,
-                                 const char **mangled, string *tname)
-{
-  int i;
-  int r;
-  int need_comma = 0;
-  int success = 1;
-  string temp;
-
-  string_append (tname, "template <");
-  /* get size of template parameter list */
-  if (get_count (mangled, &r))
-    {
-      for (i = 0; i < r; i++)
-       {
-         if (need_comma)
-           {
-             string_append (tname, ", ");
-           }
-
-           /* Z for type parameters */
-           if (**mangled == 'Z')
-             {
-               (*mangled)++;
-               string_append (tname, "class");
-             }
-             /* z for template parameters */
-           else if (**mangled == 'z')
-             {
-               (*mangled)++;
-               success =
-                 demangle_template_template_parm (work, mangled, tname);
-               if (!success)
-                 {
-                   break;
-                 }
-             }
-           else
-             {
-               /* temp is initialized in do_type */
-               success = do_type (work, mangled, &temp);
-               if (success)
-                 {
-                   string_appends (tname, &temp);
-                 }
-               string_delete(&temp);
-               if (!success)
-                 {
-                   break;
-                 }
-             }
-         need_comma = 1;
-       }
-
-    }
-  if (tname->p[-1] == '>')
-    string_append (tname, " ");
-  string_append (tname, "> class");
-  return (success);
-}
-
-static int
-demangle_expression (struct work_stuff *work, const char **mangled,
-                     string *s, type_kind_t tk)
-{
-  int need_operator = 0;
-  int success;
-
-  success = 1;
-  string_appendn (s, "(", 1);
-  (*mangled)++;
-  while (success && **mangled != 'W' && **mangled != '\0')
-    {
-      if (need_operator)
-       {
-         size_t i;
-         size_t len;
-
-         success = 0;
-
-         len = strlen (*mangled);
-
-         for (i = 0; i < ARRAY_SIZE (optable); ++i)
-           {
-             size_t l = strlen (optable[i].in);
-
-             if (l <= len
-                 && memcmp (optable[i].in, *mangled, l) == 0)
-               {
-                 string_appendn (s, " ", 1);
-                 string_append (s, optable[i].out);
-                 string_appendn (s, " ", 1);
-                 success = 1;
-                 (*mangled) += l;
-                 break;
-               }
-           }
-
-         if (!success)
-           break;
-       }
-      else
-       need_operator = 1;
-
-      success = demangle_template_value_parm (work, mangled, s, tk);
-    }
-
-  if (**mangled != 'W')
-    success = 0;
-  else
-    {
-      string_appendn (s, ")", 1);
-      (*mangled)++;
-    }
-
-  return success;
-}
-
-static int
-demangle_integral_value (struct work_stuff *work,
-                         const char **mangled, string *s)
-{
-  int success;
-
-  if (**mangled == 'E')
-    success = demangle_expression (work, mangled, s, tk_integral);
-  else if (**mangled == 'Q' || **mangled == 'K')
-    success = demangle_qualified (work, mangled, s, 0, 1);
-  else
-    {
-      int value;
-
-      /* By default, we let the number decide whether we shall consume an
-        underscore.  */
-      int multidigit_without_leading_underscore = 0;
-      int leave_following_underscore = 0;
-
-      success = 0;
-
-      if (**mangled == '_')
-        {
-         if (mangled[0][1] == 'm')
-           {
-             /* Since consume_count_with_underscores does not handle the
-                `m'-prefix we must do it here, using consume_count and
-                adjusting underscores: we have to consume the underscore
-                matching the prepended one.  */
-             multidigit_without_leading_underscore = 1;
-             string_appendn (s, "-", 1);
-             (*mangled) += 2;
-           }
-         else
-           {
-             /* Do not consume a following underscore;
-                consume_count_with_underscores will consume what
-                should be consumed.  */
-             leave_following_underscore = 1;
-           }
-       }
-      else
-       {
-         /* Negative numbers are indicated with a leading `m'.  */
-         if (**mangled == 'm')
-         {
-           string_appendn (s, "-", 1);
-           (*mangled)++;
-         }
-         /* Since consume_count_with_underscores does not handle
-            multi-digit numbers that do not start with an underscore,
-            and this number can be an integer template parameter,
-            we have to call consume_count. */
-         multidigit_without_leading_underscore = 1;
-         /* These multi-digit numbers never end on an underscore,
-            so if there is one then don't eat it. */
-         leave_following_underscore = 1;
-       }
-
-      /* We must call consume_count if we expect to remove a trailing
-        underscore, since consume_count_with_underscores expects
-        the leading underscore (that we consumed) if it is to handle
-        multi-digit numbers.  */
-      if (multidigit_without_leading_underscore)
-       value = consume_count (mangled);
-      else
-       value = consume_count_with_underscores (mangled);
-
-      if (value != -1)
-       {
-         char buf[INTBUF_SIZE];
-         sprintf (buf, "%d", value);
-         string_append (s, buf);
-
-         /* Numbers not otherwise delimited, might have an underscore
-            appended as a delimiter, which we should skip.
-
-            ??? This used to always remove a following underscore, which
-            is wrong.  If other (arbitrary) cases are followed by an
-            underscore, we need to do something more radical.  */
-
-         if ((value > 9 || multidigit_without_leading_underscore)
-             && ! leave_following_underscore
-             && **mangled == '_')
-           (*mangled)++;
-
-         /* All is well.  */
-         success = 1;
-       }
-      }
-
-  return success;
-}
-
-/* Demangle the real value in MANGLED.  */
-
-static int
-demangle_real_value (struct work_stuff *work,
-                     const char **mangled, string *s)
-{
-  if (**mangled == 'E')
-    return demangle_expression (work, mangled, s, tk_real);
-
-  if (**mangled == 'm')
-    {
-      string_appendn (s, "-", 1);
-      (*mangled)++;
-    }
-  while (ISDIGIT ((unsigned char)**mangled))
-    {
-      string_appendn (s, *mangled, 1);
-      (*mangled)++;
-    }
-  if (**mangled == '.') /* fraction */
-    {
-      string_appendn (s, ".", 1);
-      (*mangled)++;
-      while (ISDIGIT ((unsigned char)**mangled))
-       {
-         string_appendn (s, *mangled, 1);
-         (*mangled)++;
-       }
-    }
-  if (**mangled == 'e') /* exponent */
-    {
-      string_appendn (s, "e", 1);
-      (*mangled)++;
-      while (ISDIGIT ((unsigned char)**mangled))
-       {
-         string_appendn (s, *mangled, 1);
-         (*mangled)++;
-       }
-    }
-
-  return 1;
-}
-
-static int
-demangle_template_value_parm (struct work_stuff *work, const char **mangled,
-                              string *s, type_kind_t tk)
-{
-  int success = 1;
-
-  if (**mangled == 'Y')
-    {
-      /* The next argument is a template parameter. */
-      int idx;
-
-      (*mangled)++;
-      idx = consume_count_with_underscores (mangled);
-      if (idx == -1
-         || (work->tmpl_argvec && idx >= work->ntmpl_args)
-         || consume_count_with_underscores (mangled) == -1)
-       return -1;
-      if (work->tmpl_argvec)
-       string_append (s, work->tmpl_argvec[idx]);
-      else
-       string_append_template_idx (s, idx);
-    }
-  else if (tk == tk_integral)
-    success = demangle_integral_value (work, mangled, s);
-  else if (tk == tk_char)
-    {
-      char tmp[2];
-      int val;
-      if (**mangled == 'm')
-       {
-         string_appendn (s, "-", 1);
-         (*mangled)++;
-       }
-      string_appendn (s, "'", 1);
-      val = consume_count(mangled);
-      if (val <= 0)
-       success = 0;
-      else
-       {
-         tmp[0] = (char)val;
-         tmp[1] = '\0';
-         string_appendn (s, &tmp[0], 1);
-         string_appendn (s, "'", 1);
-       }
-    }
-  else if (tk == tk_bool)
-    {
-      int val = consume_count (mangled);
-      if (val == 0)
-       string_appendn (s, "false", 5);
-      else if (val == 1)
-       string_appendn (s, "true", 4);
-      else
-       success = 0;
-    }
-  else if (tk == tk_real)
-    success = demangle_real_value (work, mangled, s);
-  else if (tk == tk_pointer || tk == tk_reference
-          || tk == tk_rvalue_reference)
-    {
-      if (**mangled == 'Q')
-       success = demangle_qualified (work, mangled, s,
-                                     /*isfuncname=*/0, 
-                                     /*append=*/1);
-      else
-       {
-         int symbol_len  = consume_count (mangled);
-         if (symbol_len == -1
-             || symbol_len > (long) strlen (*mangled))
-           return -1;
-         if (symbol_len == 0)
-           string_appendn (s, "0", 1);
-         else
-           {
-             char *p = XNEWVEC (char, symbol_len + 1), *q;
-             strncpy (p, *mangled, symbol_len);
-             p [symbol_len] = '\0';
-             /* We use cplus_demangle here, rather than
-                internal_cplus_demangle, because the name of the entity
-                mangled here does not make use of any of the squangling
-                or type-code information we have built up thus far; it is
-                mangled independently.  */
-             q = ML_(cplus_demangle) (p, work->options);
-             if (tk == tk_pointer)
-               string_appendn (s, "&", 1);
-             /* FIXME: Pointer-to-member constants should get a
-                qualifying class name here.  */
-             if (q)
-               {
-                 string_append (s, q);
-                 free (q);
-               }
-             else
-               string_append (s, p);
-             free (p);
-           }
-         *mangled += symbol_len;
-       }
-    }
-
-  return success;
-}
-
-/* Demangle the template name in MANGLED.  The full name of the
-   template (e.g., S<int>) is placed in TNAME.  The name without the
-   template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
-   non-NULL.  If IS_TYPE is nonzero, this template is a type template,
-   not a function template.  If both IS_TYPE and REMEMBER are nonzero,
-   the template is remembered in the list of back-referenceable
-   types.  */
-
-static int
-demangle_template (struct work_stuff *work, const char **mangled,
-                   string *tname, string *trawname,
-                   int is_type, int remember)
-{
-  int i;
-  int r;
-  int need_comma = 0;
-  int success = 0;
-  int is_java_array = 0;
-  string temp;
-
-  (*mangled)++;
-  if (is_type)
-    {
-      /* get template name */
-      if (**mangled == 'z')
-       {
-         int idx;
-         (*mangled)++;
-         if (**mangled == '\0')
-           return (0);
-         (*mangled)++;
-
-         idx = consume_count_with_underscores (mangled);
-         if (idx == -1
-             || (work->tmpl_argvec && idx >= work->ntmpl_args)
-             || consume_count_with_underscores (mangled) == -1)
-           return (0);
-
-         if (work->tmpl_argvec)
-           {
-             string_append (tname, work->tmpl_argvec[idx]);
-             if (trawname)
-               string_append (trawname, work->tmpl_argvec[idx]);
-           }
-         else
-           {
-             string_append_template_idx (tname, idx);
-             if (trawname)
-               string_append_template_idx (trawname, idx);
-           }
-       }
-      else
-       {
-         if ((r = consume_count (mangled)) <= 0
-             || (int) strlen (*mangled) < r)
-           {
-             return (0);
-           }
-         is_java_array = (work -> options & DMGL_JAVA)
-           && strncmp (*mangled, "JArray1Z", 8) == 0;
-         if (! is_java_array)
-           {
-             string_appendn (tname, *mangled, r);
-           }
-         if (trawname)
-           string_appendn (trawname, *mangled, r);
-         *mangled += r;
-       }
-    }
-  if (!is_java_array)
-    string_append (tname, "<");
-  /* get size of template parameter list */
-  if (!get_count (mangled, &r))
-    {
-      return (0);
-    }
-  if (!is_type)
-    {
-      /* Create an array for saving the template argument values. */
-      work->tmpl_argvec = XNEWVEC (char *, r);
-      work->ntmpl_args = r;
-      for (i = 0; i < r; i++)
-       work->tmpl_argvec[i] = 0;
-    }
-  for (i = 0; i < r; i++)
-    {
-      if (need_comma)
-       {
-         string_append (tname, ", ");
-       }
-      /* Z for type parameters */
-      if (**mangled == 'Z')
-       {
-         (*mangled)++;
-         /* temp is initialized in do_type */
-         success = do_type (work, mangled, &temp);
-         if (success)
-           {
-             string_appends (tname, &temp);
-
-             if (!is_type)
-               {
-                 /* Save the template argument. */
-                 int len = temp.p - temp.b;
-                 work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
-                 memcpy (work->tmpl_argvec[i], temp.b, len);
-                 work->tmpl_argvec[i][len] = '\0';
-               }
-           }
-         string_delete(&temp);
-         if (!success)
-           {
-             break;
-           }
-       }
-      /* z for template parameters */
-      else if (**mangled == 'z')
-       {
-         int r2;
-         (*mangled)++;
-         success = demangle_template_template_parm (work, mangled, tname);
-
-         if (success
-             && (r2 = consume_count (mangled)) > 0
-             && (int) strlen (*mangled) >= r2)
-           {
-             string_append (tname, " ");
-             string_appendn (tname, *mangled, r2);
-             if (!is_type)
-               {
-                 /* Save the template argument. */
-                 int len = r2;
-                 work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
-                 memcpy (work->tmpl_argvec[i], *mangled, len);
-                 work->tmpl_argvec[i][len] = '\0';
-               }
-             *mangled += r2;
-           }
-         if (!success)
-           {
-             break;
-           }
-       }
-      else
-       {
-         string  param;
-         string* s;
-
-         /* otherwise, value parameter */
-
-         /* temp is initialized in do_type */
-         success = do_type (work, mangled, &temp);
-         string_delete(&temp);
-         if (!success)
-           break;
-
-         if (!is_type)
-           {
-             s = &param;
-             string_init (s);
-           }
-         else
-           s = tname;
-
-         success = demangle_template_value_parm (work, mangled, s,
-                                                 (type_kind_t) success);
-
-         if (!success)
-           {
-             if (!is_type)
-               string_delete (s);
-             success = 0;
-             break;
-           }
-
-         if (!is_type)
-           {
-             int len = s->p - s->b;
-             work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
-             memcpy (work->tmpl_argvec[i], s->b, len);
-             work->tmpl_argvec[i][len] = '\0';
-
-             string_appends (tname, s);
-             string_delete (s);
-           }
-       }
-      need_comma = 1;
-    }
-  if (is_java_array)
-    {
-      string_append (tname, "[]");
-    }
-  else
-    {
-      if (tname->p[-1] == '>')
-       string_append (tname, " ");
-      string_append (tname, ">");
-    }
-
-  if (is_type && remember)
-    {
-      const int bindex = register_Btype (work);
-      remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
-    }
-
-  /*
-    if (work -> static_type)
-    {
-    string_append (declp, *mangled + 1);
-    *mangled += strlen (*mangled);
-    success = 1;
-    }
-    else
-    {
-    success = demangle_args (work, mangled, declp);
-    }
-    }
-    */
-  return (success);
-}
-
-static int
-arm_pt (const char *mangled,
-        int n, const char **anchor, const char **args)
-{
-  /* Check if ARM template with "__pt__" in it ("parameterized type") */
-  /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
-  if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__")))
-    {
-      int len;
-      *args = *anchor + 6;
-      len = consume_count (args);
-      if (len == -1)
-       return 0;
-      if (*args + len == mangled + n && **args == '_')
-       {
-         ++*args;
-         return 1;
-       }
-    }
-  if (AUTO_DEMANGLING || EDG_DEMANGLING)
-    {
-      if ((*anchor = strstr (mangled, "__tm__"))
-          || (*anchor = strstr (mangled, "__ps__"))
-          || (*anchor = strstr (mangled, "__pt__")))
-        {
-          int len;
-          *args = *anchor + 6;
-          len = consume_count (args);
-         if (len == -1)
-           return 0;
-          if (*args + len == mangled + n && **args == '_')
-            {
-              ++*args;
-              return 1;
-            }
-        }
-      else if ((*anchor = strstr (mangled, "__S")))
-        {
-         int len;
-         *args = *anchor + 3;
-         len = consume_count (args);
-         if (len == -1)
-           return 0;
-         if (*args + len == mangled + n && **args == '_')
-            {
-              ++*args;
-             return 1;
-            }
-        }
-    }
-
-  return 0;
-}
-
-static void
-demangle_arm_hp_template (struct work_stuff *work, const char **mangled,
-                          int n, string *declp)
-{
-  const char *p;
-  const char *args;
-  const char *e = *mangled + n;
-  string arg;
-
-  /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
-     template args */
-  if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
-    {
-      char *start_spec_args = NULL;
-      int hold_options;
-
-      /* First check for and omit template specialization pseudo-arguments,
-         such as in "Spec<#1,#1.*>" */
-      start_spec_args = strchr (*mangled, '<');
-      if (start_spec_args && (start_spec_args - *mangled < n))
-        string_appendn (declp, *mangled, start_spec_args - *mangled);
-      else
-        string_appendn (declp, *mangled, n);
-      (*mangled) += n + 1;
-      string_init (&arg);
-      if (work->temp_start == -1) /* non-recursive call */
-        work->temp_start = declp->p - declp->b;
-
-      /* We want to unconditionally demangle parameter types in
-        template parameters.  */
-      hold_options = work->options;
-      work->options |= DMGL_PARAMS;
-
-      string_append (declp, "<");
-      while (1)
-        {
-          string_delete (&arg);
-          switch (**mangled)
-            {
-              case 'T':
-                /* 'T' signals a type parameter */
-                (*mangled)++;
-                if (!do_type (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              case 'U':
-              case 'S':
-                /* 'U' or 'S' signals an integral value */
-                if (!do_hpacc_template_const_value (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              case 'A':
-                /* 'A' signals a named constant expression (literal) */
-                if (!do_hpacc_template_literal (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              default:
-                /* Today, 1997-09-03, we have only the above types
-                   of template parameters */
-                /* FIXME: maybe this should fail and return null */
-                goto hpacc_template_args_done;
-            }
-          string_appends (declp, &arg);
-         /* Check if we're at the end of template args.
-             0 if at end of static member of template class,
-             _ if done with template args for a function */
-          if ((**mangled == '\000') || (**mangled == '_'))
-            break;
-          else
-            string_append (declp, ",");
-        }
-    hpacc_template_args_done:
-      string_append (declp, ">");
-      string_delete (&arg);
-      if (**mangled == '_')
-        (*mangled)++;
-      work->options = hold_options;
-      return;
-    }
-  /* ARM template? (Also handles HP cfront extensions) */
-  else if (arm_pt (*mangled, n, &p, &args))
-    {
-      int hold_options;
-      string type_str;
-
-      string_init (&arg);
-      string_appendn (declp, *mangled, p - *mangled);
-      if (work->temp_start == -1)  /* non-recursive call */
-       work->temp_start = declp->p - declp->b;
-
-      /* We want to unconditionally demangle parameter types in
-        template parameters.  */
-      hold_options = work->options;
-      work->options |= DMGL_PARAMS;
-
-      string_append (declp, "<");
-      /* should do error checking here */
-      while (args < e) {
-       string_delete (&arg);
-
-       /* Check for type or literal here */
-       switch (*args)
-         {
-           /* HP cfront extensions to ARM for template args */
-           /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
-           /* FIXME: We handle only numeric literals for HP cfront */
-          case 'X':
-            /* A typed constant value follows */
-            args++;
-            if (!do_type (work, &args, &type_str))
-             goto cfront_template_args_done;
-            string_append (&arg, "(");
-            string_appends (&arg, &type_str);
-            string_delete (&type_str);
-            string_append (&arg, ")");
-            if (*args != 'L')
-              goto cfront_template_args_done;
-            args++;
-            /* Now snarf a literal value following 'L' */
-            if (!snarf_numeric_literal (&args, &arg))
-             goto cfront_template_args_done;
-            break;
-
-          case 'L':
-            /* Snarf a literal following 'L' */
-            args++;
-            if (!snarf_numeric_literal (&args, &arg))
-             goto cfront_template_args_done;
-            break;
-          default:
-            /* Not handling other HP cfront stuff */
-            {
-              const char* old_args = args;
-              if (!do_type (work, &args, &arg))
-                goto cfront_template_args_done;
-
-              /* Fail if we didn't make any progress: prevent infinite loop. */
-              if (args == old_args)
-               {
-                 work->options = hold_options;
-                 return;
-               }
-            }
-         }
-       string_appends (declp, &arg);
-       string_append (declp, ",");
-      }
-    cfront_template_args_done:
-      string_delete (&arg);
-      if (args >= e)
-       --declp->p; /* remove extra comma */
-      string_append (declp, ">");
-      work->options = hold_options;
-    }
-  else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
-          && (*mangled)[9] == 'N'
-          && (*mangled)[8] == (*mangled)[10]
-          && strchr (cplus_markers, (*mangled)[8]))
-    {
-      /* A member of the anonymous namespace.  */
-      string_append (declp, "{anonymous}");
-    }
-  else
-    {
-      if (work->temp_start == -1) /* non-recursive call only */
-       work->temp_start = 0;     /* disable in recursive calls */
-      string_appendn (declp, *mangled, n);
-    }
-  *mangled += n;
-}
-
-/* Extract a class name, possibly a template with arguments, from the
-   mangled string; qualifiers, local class indicators, etc. have
-   already been dealt with */
-
-static int
-demangle_class_name (struct work_stuff *work, const char **mangled,
-                     string *declp)
-{
-  int n;
-  int success = 0;
-
-  n = consume_count (mangled);
-  if (n == -1)
-    return 0;
-  if ((int) strlen (*mangled) >= n)
-    {
-      demangle_arm_hp_template (work, mangled, n, declp);
-      success = 1;
-    }
-
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_class -- demangle a mangled class sequence
-
-SYNOPSIS
-
-       static int
-       demangle_class (struct work_stuff *work, const char **mangled,
-                       strint *declp)
-
-DESCRIPTION
-
-       DECLP points to the buffer into which demangling is being done.
-
-       *MANGLED points to the current token to be demangled.  On input,
-       it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
-       On exit, it points to the next token after the mangled class on
-       success, or the first unconsumed token on failure.
-
-       If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
-       we are demangling a constructor or destructor.  In this case
-       we prepend "class::class" or "class::~class" to DECLP.
-
-       Otherwise, we prepend "class::" to the current DECLP.
-
-       Reset the constructor/destructor flags once they have been
-       "consumed".  This allows demangle_class to be called later during
-       the same demangling, to do normal class demangling.
-
-       Returns 1 if demangling is successful, 0 otherwise.
-
-*/
-
-static int
-demangle_class (struct work_stuff *work, const char **mangled, string *declp)
-{
-  int success = 0;
-  int btype;
-  string class_name;
-  char *save_class_name_end = 0;
-
-  string_init (&class_name);
-  btype = register_Btype (work);
-  if (demangle_class_name (work, mangled, &class_name))
-    {
-      save_class_name_end = class_name.p;
-      if ((work->constructor & 1) || (work->destructor & 1))
-       {
-          /* adjust so we don't include template args */
-          if (work->temp_start && (work->temp_start != -1))
-            {
-              class_name.p = class_name.b + work->temp_start;
-            }
-         string_prepends (declp, &class_name);
-         if (work -> destructor & 1)
-           {
-             string_prepend (declp, "~");
-              work -> destructor -= 1;
-           }
-         else
-           {
-             work -> constructor -= 1;
-           }
-       }
-      class_name.p = save_class_name_end;
-      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
-      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
-      string_prepend (declp, SCOPE_STRING (work));
-      string_prepends (declp, &class_name);
-      success = 1;
-    }
-  string_delete (&class_name);
-  return (success);
-}
-
-
-/* Called when there's a "__" in the mangled name, with `scan' pointing to
-   the rightmost guess.
-
-   Find the correct "__"-sequence where the function name ends and the
-   signature starts, which is ambiguous with GNU mangling.
-   Call demangle_signature here, so we can make sure we found the right
-   one; *mangled will be consumed so caller will not make further calls to
-   demangle_signature.  */
-
-static int
-iterate_demangle_function (struct work_stuff *work, const char **mangled,
-                           string *declp, const char *scan)
-{
-  const char *mangle_init = *mangled;
-  int success = 0;
-  string decl_init;
-  struct work_stuff work_init;
-
-  if (*(scan + 2) == '\0')
-    return 0;
-
-  /* Do not iterate for some demangling modes, or if there's only one
-     "__"-sequence.  This is the normal case.  */
-  if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
-      || strstr (scan + 2, "__") == NULL)
-    return demangle_function_name (work, mangled, declp, scan);
-
-  /* Save state so we can restart if the guess at the correct "__" was
-     wrong.  */
-  string_init (&decl_init);
-  string_appends (&decl_init, declp);
-  memset (&work_init, 0, sizeof work_init);
-  work_stuff_copy_to_from (&work_init, work);
-
-  /* Iterate over occurrences of __, allowing names and types to have a
-     "__" sequence in them.  We must start with the first (not the last)
-     occurrence, since "__" most often occur between independent mangled
-     parts, hence starting at the last occurrence inside a signature
-     might get us a "successful" demangling of the signature.  */
-
-  while (scan[2])
-    {
-      if (demangle_function_name (work, mangled, declp, scan))
-       {
-         success = demangle_signature (work, mangled, declp);
-         if (success)
-           break;
-       }
-
-      /* Reset demangle state for the next round.  */
-      *mangled = mangle_init;
-      string_clear (declp);
-      string_appends (declp, &decl_init);
-      work_stuff_copy_to_from (work, &work_init);
-
-      /* Leave this underscore-sequence.  */
-      scan += 2;
-
-      /* Scan for the next "__" sequence.  */
-      while (*scan && (scan[0] != '_' || scan[1] != '_'))
-       scan++;
-
-      /* Move to last "__" in this sequence.  */
-      while (*scan && *scan == '_')
-       scan++;
-      scan -= 2;
-    }
-
-  /* Delete saved state.  */
-  delete_work_stuff (&work_init);
-  string_delete (&decl_init);
-
-  return success;
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_prefix -- consume the mangled name prefix and find signature
-
-SYNOPSIS
-
-       static int
-       demangle_prefix (struct work_stuff *work, const char **mangled,
-                        string *declp);
-
-DESCRIPTION
-
-       Consume and demangle the prefix of the mangled name.
-       While processing the function name root, arrange to call
-       demangle_signature if the root is ambiguous.
-
-       DECLP points to the string buffer into which demangled output is
-       placed.  On entry, the buffer is empty.  On exit it contains
-       the root function name, the demangled operator name, or in some
-       special cases either nothing or the completely demangled result.
-
-       MANGLED points to the current pointer into the mangled name.  As each
-       token of the mangled name is consumed, it is updated.  Upon entry
-       the current mangled name pointer points to the first character of
-       the mangled name.  Upon exit, it should point to the first character
-       of the signature if demangling was successful, or to the first
-       unconsumed character if demangling of the prefix was unsuccessful.
-
-       Returns 1 on success, 0 otherwise.
- */
-
-static int
-demangle_prefix (struct work_stuff *work, const char **mangled,
-                 string *declp)
-{
-  int success = 1;
-  const char *scan;
-  int i;
-
-  if (strlen(*mangled) > 6
-      && (strncmp(*mangled, "_imp__", 6) == 0
-          || strncmp(*mangled, "__imp_", 6) == 0))
-    {
-      /* it's a symbol imported from a PE dynamic library. Check for both
-         new style prefix _imp__ and legacy __imp_ used by older versions
-        of dlltool. */
-      (*mangled) += 6;
-      work->dllimported = 1;
-    }
-  else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
-    {
-      char *marker = strchr (cplus_markers, (*mangled)[8]);
-      if (marker != NULL && *marker == (*mangled)[10])
-       {
-         if ((*mangled)[9] == 'D')
-           {
-             /* it's a GNU global destructor to be executed at program exit */
-             (*mangled) += 11;
-             work->destructor = 2;
-             if (gnu_special (work, mangled, declp))
-               return success;
-           }
-         else if ((*mangled)[9] == 'I')
-           {
-             /* it's a GNU global constructor to be executed at program init */
-             (*mangled) += 11;
-             work->constructor = 2;
-             if (gnu_special (work, mangled, declp))
-               return success;
-           }
-       }
-    }
-  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
-    {
-      /* it's a ARM global destructor to be executed at program exit */
-      (*mangled) += 7;
-      work->destructor = 2;
-    }
-  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
-    {
-      /* it's a ARM global constructor to be executed at program initial */
-      (*mangled) += 7;
-      work->constructor = 2;
-    }
-
-  /*  This block of code is a reduction in strength time optimization
-      of:
-      scan = strstr (*mangled, "__"); */
-
-  {
-    scan = *mangled;
-
-    do {
-      scan = strchr (scan, '_');
-    } while (scan != NULL && *++scan != '_');
-
-    if (scan != NULL) --scan;
-  }
-
-  if (scan != NULL)
-    {
-      /* We found a sequence of two or more '_', ensure that we start at
-        the last pair in the sequence.  */
-      i = strspn (scan, "_");
-      if (i > 2)
-       {
-         scan += (i - 2);
-       }
-    }
-
-  if (scan == NULL)
-    {
-      success = 0;
-    }
-  else if (work -> static_type)
-    {
-      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
-       {
-         success = 0;
-       }
-    }
-  else if ((scan == *mangled)
-          && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
-              || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
-    {
-      /* The ARM says nothing about the mangling of local variables.
-        But cfront mangles local variables by prepending __<nesting_level>
-        to them. As an extension to ARM demangling we handle this case.  */
-      if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
-         && ISDIGIT ((unsigned char)scan[2]))
-       {
-         *mangled = scan + 2;
-         consume_count (mangled);
-         string_append (declp, *mangled);
-         *mangled += strlen (*mangled);
-         success = 1;
-       }
-      else
-       {
-         /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
-            names like __Q2_3foo3bar for nested type names.  So don't accept
-            this style of constructor for cfront demangling.  A GNU
-            style member-template constructor starts with 'H'. */
-         if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
-           work -> constructor += 1;
-         *mangled = scan + 2;
-       }
-    }
-  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
-    {
-      /* Cfront-style parameterized type.  Handled later as a signature. */
-      success = 1;
-
-      /* ARM template? */
-      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
-    }
-  else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
-                              || (scan[2] == 'p' && scan[3] == 's')
-                              || (scan[2] == 'p' && scan[3] == 't')))
-    {
-      /* EDG-style parameterized type.  Handled later as a signature. */
-      success = 1;
-
-      /* EDG template? */
-      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
-    }
-  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
-          && (scan[2] != 't'))
-    {
-      /* Mangled name starts with "__".  Skip over any leading '_' characters,
-        then find the next "__" that separates the prefix from the signature.
-        */
-      if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-         || (arm_special (mangled, declp) == 0))
-       {
-         while (*scan == '_')
-           {
-             scan++;
-           }
-         if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
-           {
-             /* No separator (I.E. "__not_mangled"), or empty signature
-                (I.E. "__not_mangled_either__") */
-             success = 0;
-           }
-         else
-           return iterate_demangle_function (work, mangled, declp, scan);
-       }
-    }
-  else if (*(scan + 2) != '\0')
-    {
-      /* Mangled name does not start with "__" but does have one somewhere
-        in there with non empty stuff after it.  Looks like a global
-        function name.  Iterate over all "__":s until the right
-        one is found.  */
-      return iterate_demangle_function (work, mangled, declp, scan);
-    }
-  else
-    {
-      /* Doesn't look like a mangled name */
-      success = 0;
-    }
-
-  if (!success && (work->constructor == 2 || work->destructor == 2))
-    {
-      string_append (declp, *mangled);
-      *mangled += strlen (*mangled);
-      success = 1;
-    }
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       gnu_special -- special handling of gnu mangled strings
-
-SYNOPSIS
-
-       static int
-       gnu_special (struct work_stuff *work, const char **mangled,
-                    string *declp);
-
-
-DESCRIPTION
-
-       Process some special GNU style mangling forms that don't fit
-       the normal pattern.  For example:
-
-               _$_3foo         (destructor for class foo)
-               _vt$foo         (foo virtual table)
-               _vt$foo$bar     (foo::bar virtual table)
-               __vt_foo        (foo virtual table, new style with thunks)
-               _3foo$varname   (static data member)
-               _Q22rs2tu$vw    (static data member)
-               __t6vector1Zii  (constructor with template)
-               __thunk_4__$_7ostream (virtual function thunk)
- */
-
-static int
-gnu_special (struct work_stuff *work, const char **mangled, string *declp)
-{
-  int n;
-  int success = 1;
-  const char *p;
-
-  if ((*mangled)[0] == '_' && (*mangled)[1] != '\0'
-      && strchr (cplus_markers, (*mangled)[1]) != NULL
-      && (*mangled)[2] == '_')
-    {
-      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
-      (*mangled) += 3;
-      work -> destructor += 1;
-    }
-  else if ((*mangled)[0] == '_'
-          && (((*mangled)[1] == '_'
-               && (*mangled)[2] == 'v'
-               && (*mangled)[3] == 't'
-               && (*mangled)[4] == '_')
-              || ((*mangled)[1] == 'v'
-                  && (*mangled)[2] == 't' && (*mangled)[3] != '\0'
-                  && strchr (cplus_markers, (*mangled)[3]) != NULL)))
-    {
-      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
-         and create the decl.  Note that we consume the entire mangled
-        input string, which means that demangle_signature has no work
-        to do.  */
-      if ((*mangled)[2] == 'v')
-       (*mangled) += 5; /* New style, with thunks: "__vt_" */
-      else
-       (*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
-      while (**mangled != '\0')
-       {
-         switch (**mangled)
-           {
-           case 'Q':
-           case 'K':
-             success = demangle_qualified (work, mangled, declp, 0, 1);
-             break;
-           case 't':
-             success = demangle_template (work, mangled, declp, 0, 1,
-                                          1);
-             break;
-           default:
-             if (ISDIGIT((unsigned char)*mangled[0]))
-               {
-                 n = consume_count(mangled);
-                 /* We may be seeing a too-large size, or else a
-                    ".<digits>" indicating a static local symbol.  In
-                    any case, declare victory and move on; *don't* try
-                    to use n to allocate.  */
-                 if (n > (int) strlen (*mangled))
-                   {
-                     success = 1;
-                     break;
-                   }
-                 else if (n == -1)
-                   {
-                     success = 0;
-                     break;
-                   }
-               }
-             else
-               {
-                 n = strcspn (*mangled, cplus_markers);
-               }
-             string_appendn (declp, *mangled, n);
-             (*mangled) += n;
-           }
-
-         p = strpbrk (*mangled, cplus_markers);
-         if (success && ((p == NULL) || (p == *mangled)))
-           {
-             if (p != NULL)
-               {
-                 string_append (declp, SCOPE_STRING (work));
-                 (*mangled)++;
-               }
-           }
-         else
-           {
-             success = 0;
-             break;
-           }
-       }
-      if (success)
-       string_append (declp, " virtual table");
-    }
-  else if ((*mangled)[0] == '_'
-          && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
-          && (p = strpbrk (*mangled, cplus_markers)) != NULL)
-    {
-      /* static data member, "_3foo$varname" for example */
-      (*mangled)++;
-      switch (**mangled)
-       {
-       case 'Q':
-       case 'K':
-         success = demangle_qualified (work, mangled, declp, 0, 1);
-         break;
-       case 't':
-         success = demangle_template (work, mangled, declp, 0, 1, 1);
-         break;
-       default:
-         n = consume_count (mangled);
-         if (n < 0 || n > (long) strlen (*mangled))
-           {
-             success = 0;
-             break;
-           }
-
-         if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
-             && (*mangled)[9] == 'N'
-             && (*mangled)[8] == (*mangled)[10]
-             && strchr (cplus_markers, (*mangled)[8]))
-           {
-             /* A member of the anonymous namespace.  There's information
-                about what identifier or filename it was keyed to, but
-                it's just there to make the mangled name unique; we just
-                step over it.  */
-             string_append (declp, "{anonymous}");
-             (*mangled) += n;
-
-             /* Now p points to the marker before the N, so we need to
-                update it to the first marker after what we consumed.  */
-             p = strpbrk (*mangled, cplus_markers);
-             break;
-           }
-
-         string_appendn (declp, *mangled, n);
-         (*mangled) += n;
-       }
-      if (success && (p == *mangled))
-       {
-         /* Consumed everything up to the cplus_marker, append the
-            variable name.  */
-         (*mangled)++;
-         string_append (declp, SCOPE_STRING (work));
-         n = strlen (*mangled);
-         string_appendn (declp, *mangled, n);
-         (*mangled) += n;
-       }
-      else
-       {
-         success = 0;
-       }
-    }
-  else if (strncmp (*mangled, "__thunk_", 8) == 0)
-    {
-      int delta;
-
-      (*mangled) += 8;
-      delta = consume_count (mangled);
-      if (delta == -1)
-       success = 0;
-      else
-       {
-         char *method = internal_cplus_demangle (work, ++*mangled);
-
-         if (method)
-           {
-             char buf[50];
-             sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
-             string_append (declp, buf);
-             string_append (declp, method);
-             free (method);
-             n = strlen (*mangled);
-             (*mangled) += n;
-           }
-         else
-           {
-             success = 0;
-           }
-       }
-    }
-  else if (strncmp (*mangled, "__t", 3) == 0
-          && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
-    {
-      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
-      (*mangled) += 4;
-      switch (**mangled)
-       {
-       case 'Q':
-       case 'K':
-         success = demangle_qualified (work, mangled, declp, 0, 1);
-         break;
-       case 't':
-         success = demangle_template (work, mangled, declp, 0, 1, 1);
-         break;
-       default:
-         success = do_type (work, mangled, declp);
-         break;
-       }
-      if (success && **mangled != '\0')
-       success = 0;
-      if (success)
-       string_append (declp, p);
-    }
-  else
-    {
-      success = 0;
-    }
-  return (success);
-}
-
-static void
-recursively_demangle(struct work_stuff *work, const char **mangled,
-                     string *result, int namelength)
-{
-  char * recurse = (char *)NULL;
-  char * recurse_dem = (char *)NULL;
-
-  recurse = XNEWVEC (char, namelength + 1);
-  memcpy (recurse, *mangled, namelength);
-  recurse[namelength] = '\000';
-
-  recurse_dem = ML_(cplus_demangle) (recurse, work->options);
-
-  if (recurse_dem)
-    {
-      string_append (result, recurse_dem);
-      free (recurse_dem);
-    }
-  else
-    {
-      string_appendn (result, *mangled, namelength);
-    }
-  free (recurse);
-  *mangled += namelength;
-}
-
-/*
-
-LOCAL FUNCTION
-
-       arm_special -- special handling of ARM/lucid mangled strings
-
-SYNOPSIS
-
-       static int
-       arm_special (const char **mangled,
-                    string *declp);
-
-
-DESCRIPTION
-
-       Process some special ARM style mangling forms that don't fit
-       the normal pattern.  For example:
-
-               __vtbl__3foo            (foo virtual table)
-               __vtbl__3foo__3bar      (bar::foo virtual table)
-
- */
-
-static int
-arm_special (const char **mangled, string *declp)
-{
-  int n;
-  int success = 1;
-  const char *scan;
-
-  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
-    {
-      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
-         and create the decl.  Note that we consume the entire mangled
-        input string, which means that demangle_signature has no work
-        to do.  */
-      scan = *mangled + ARM_VTABLE_STRLEN;
-      while (*scan != '\0')        /* first check it can be demangled */
-        {
-          n = consume_count (&scan);
-          if (n == -1)
-           {
-             return (0);           /* no good */
-           }
-          scan += n;
-          if (scan[0] == '_' && scan[1] == '_')
-           {
-             scan += 2;
-           }
-        }
-      (*mangled) += ARM_VTABLE_STRLEN;
-      while (**mangled != '\0')
-       {
-         n = consume_count (mangled);
-          if (n == -1
-             || n > (long) strlen (*mangled))
-           return 0;
-         string_prependn (declp, *mangled, n);
-         (*mangled) += n;
-         if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
-           {
-             string_prepend (declp, "::");
-             (*mangled) += 2;
-           }
-       }
-      string_append (declp, " virtual table");
-    }
-  else
-    {
-      success = 0;
-    }
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_qualified -- demangle 'Q' qualified name strings
-
-SYNOPSIS
-
-       static int
-       demangle_qualified (struct work_stuff *, const char *mangled,
-                           string *result, int isfuncname, int append);
-
-DESCRIPTION
-
-       Demangle a qualified name, such as "Q25Outer5Inner" which is
-       the mangled form of "Outer::Inner".  The demangled output is
-       prepended or appended to the result string according to the
-       state of the append flag.
-
-       If isfuncname is nonzero, then the qualified name we are building
-       is going to be used as a member function name, so if it is a
-       constructor or destructor function, append an appropriate
-       constructor or destructor name.  I.E. for the above example,
-       the result for use as a constructor is "Outer::Inner::Inner"
-       and the result for use as a destructor is "Outer::Inner::~Inner".
-
-BUGS
-
-       Numeric conversion is ASCII dependent (FIXME).
-
- */
-
-static int
-demangle_qualified (struct work_stuff *work, const char **mangled,
-                    string *result, int isfuncname, int append)
-{
-  int qualifiers = 0;
-  int success = 1;
-  char num[2];
-  string temp;
-  string last_name;
-  int bindex = register_Btype (work);
-
-  /* We only make use of ISFUNCNAME if the entity is a constructor or
-     destructor.  */
-  isfuncname = (isfuncname
-               && ((work->constructor & 1) || (work->destructor & 1)));
-
-  string_init (&temp);
-  string_init (&last_name);
-
-  if ((*mangled)[0] == 'K')
-    {
-    /* Squangling qualified name reuse */
-      int idx;
-      (*mangled)++;
-      idx = consume_count_with_underscores (mangled);
-      if (idx == -1 || idx >= work -> numk)
-        success = 0;
-      else
-        string_append (&temp, work -> ktypevec[idx]);
-    }
-  else
-    switch ((*mangled)[1])
-    {
-    case '_':
-      /* GNU mangled name with more than 9 classes.  The count is preceded
-        by an underscore (to distinguish it from the <= 9 case) and followed
-        by an underscore.  */
-      (*mangled)++;
-      qualifiers = consume_count_with_underscores (mangled);
-      if (qualifiers == -1)
-       success = 0;
-      break;
-
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      /* The count is in a single digit.  */
-      num[0] = (*mangled)[1];
-      num[1] = '\0';
-      qualifiers = atoi (num);
-
-      /* If there is an underscore after the digit, skip it.  This is
-        said to be for ARM-qualified names, but the ARM makes no
-        mention of such an underscore.  Perhaps cfront uses one.  */
-      if ((*mangled)[2] == '_')
-       {
-         (*mangled)++;
-       }
-      (*mangled) += 2;
-      break;
-
-    case '0':
-    default:
-      success = 0;
-    }
-
-  if (!success)
-    return success;
-
-  /* Pick off the names and collect them in the temp buffer in the order
-     in which they are found, separated by '::'.  */
-
-  while (qualifiers-- > 0)
-    {
-      int remember_K = 1;
-      string_clear (&last_name);
-
-      if (*mangled[0] == '_')
-       (*mangled)++;
-
-      if (*mangled[0] == 't')
-       {
-         /* Here we always append to TEMP since we will want to use
-            the template name without the template parameters as a
-            constructor or destructor name.  The appropriate
-            (parameter-less) value is returned by demangle_template
-            in LAST_NAME.  We do not remember the template type here,
-            in order to match the G++ mangling algorithm.  */
-         success = demangle_template(work, mangled, &temp,
-                                     &last_name, 1, 0);
-         if (!success)
-           break;
-       }
-      else if (*mangled[0] == 'K')
-       {
-          int idx;
-          (*mangled)++;
-          idx = consume_count_with_underscores (mangled);
-          if (idx == -1 || idx >= work->numk)
-            success = 0;
-          else
-            string_append (&temp, work->ktypevec[idx]);
-          remember_K = 0;
-
-         if (!success) break;
-       }
-      else
-       {
-         if (EDG_DEMANGLING)
-            {
-             int namelength;
-             /* Now recursively demangle the qualifier
-              * This is necessary to deal with templates in
-              * mangling styles like EDG */
-             namelength = consume_count (mangled);
-             if (namelength == -1)
-               {
-                 success = 0;
-                 break;
-               }
-             recursively_demangle(work, mangled, &temp, namelength);
-            }
-          else
-            {
-              string_delete (&last_name);
-              success = do_type (work, mangled, &last_name);
-              if (!success)
-                break;
-              string_appends (&temp, &last_name);
-            }
-       }
-
-      if (remember_K)
-       remember_Ktype (work, temp.b, LEN_STRING (&temp));
-
-      if (qualifiers > 0)
-       string_append (&temp, SCOPE_STRING (work));
-    }
-
-  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
-
-  /* If we are using the result as a function name, we need to append
-     the appropriate '::' separated constructor or destructor name.
-     We do this here because this is the most convenient place, where
-     we already have a pointer to the name and the length of the name.  */
-
-  if (isfuncname)
-    {
-      string_append (&temp, SCOPE_STRING (work));
-      if (work -> destructor & 1)
-       string_append (&temp, "~");
-      string_appends (&temp, &last_name);
-    }
-
-  /* Now either prepend the temp buffer to the result, or append it,
-     depending upon the state of the append flag.  */
-
-  if (append)
-    string_appends (result, &temp);
-  else
-    {
-      if (!STRING_EMPTY (result))
-       string_append (&temp, SCOPE_STRING (work));
-      string_prepends (result, &temp);
-    }
-
-  string_delete (&last_name);
-  string_delete (&temp);
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       get_count -- convert an ascii count to integer, consuming tokens
-
-SYNOPSIS
-
-       static int
-       get_count (const char **type, int *count)
-
-DESCRIPTION
-
-       Assume that *type points at a count in a mangled name; set
-       *count to its value, and set *type to the next character after
-       the count.  There are some weird rules in effect here.
-
-       If *type does not point at a string of digits, return zero.
-
-       If *type points at a string of digits followed by an
-       underscore, set *count to their value as an integer, advance
-       *type to point *after the underscore, and return 1.
-
-       If *type points at a string of digits not followed by an
-       underscore, consume only the first digit.  Set *count to its
-       value as an integer, leave *type pointing after that digit,
-       and return 1.
-
-        The excuse for this odd behavior: in the ARM and HP demangling
-        styles, a type can be followed by a repeat count of the form
-        `Nxy', where:
-
-        `x' is a single digit specifying how many additional copies
-            of the type to append to the argument list, and
-
-        `y' is one or more digits, specifying the zero-based index of
-            the first repeated argument in the list.  Yes, as you're
-            unmangling the name you can figure this out yourself, but
-            it's there anyway.
-
-        So, for example, in `bar__3fooFPiN51', the first argument is a
-        pointer to an integer (`Pi'), and then the next five arguments
-        are the same (`N5'), and the first repeat is the function's
-        second argument (`1').
-*/
-
-static int
-get_count (const char **type, int *count)
-{
-  const char *p;
-  int n;
-
-  if (!ISDIGIT ((unsigned char)**type))
-    return (0);
-  else
-    {
-      *count = **type - '0';
-      (*type)++;
-      if (ISDIGIT ((unsigned char)**type))
-       {
-         p = *type;
-         n = *count;
-         do
-           {
-             n *= 10;
-             n += *p - '0';
-             p++;
-           }
-         while (ISDIGIT ((unsigned char)*p));
-         if (*p == '_')
-           {
-             *type = p + 1;
-             *count = n;
-           }
-       }
-    }
-  return (1);
-}
-
-/* RESULT will be initialised here; it will be freed on failure.  The
-   value returned is really a type_kind_t.  */
-
-static int
-do_type (struct work_stuff *work, const char **mangled, string *result)
-{
-  int n;
-  int i;
-  int is_proctypevec;
-  int done;
-  int success;
-  string decl;
-  const char *remembered_type;
-  int type_quals;
-  type_kind_t tk = tk_none;
-
-  string_init (&decl);
-  string_init (result);
-
-  done = 0;
-  success = 1;
-  is_proctypevec = 0;
-  while (success && !done)
-    {
-      int member;
-      switch (**mangled)
-       {
-
-         /* A pointer type */
-       case 'P':
-       case 'p':
-         (*mangled)++;
-         if (! (work -> options & DMGL_JAVA))
-           string_prepend (&decl, "*");
-         if (tk == tk_none)
-           tk = tk_pointer;
-         break;
-
-         /* A reference type */
-       case 'R':
-         (*mangled)++;
-         string_prepend (&decl, "&");
-         if (tk == tk_none)
-           tk = tk_reference;
-         break;
-
-         /* An rvalue reference type */
-       case 'O':
-         (*mangled)++;
-         string_prepend (&decl, "&&");
-         if (tk == tk_none)
-           tk = tk_rvalue_reference;
-         break;
-
-         /* An array */
-       case 'A':
-         {
-           ++(*mangled);
-           if (!STRING_EMPTY (&decl)
-               && (decl.b[0] == '*' || decl.b[0] == '&'))
-             {
-               string_prepend (&decl, "(");
-               string_append (&decl, ")");
-             }
-           string_append (&decl, "[");
-           if (**mangled != '_')
-             success = demangle_template_value_parm (work, mangled, &decl,
-                                                     tk_integral);
-           if (**mangled == '_')
-             ++(*mangled);
-           string_append (&decl, "]");
-           break;
-         }
-
-       /* A back reference to a previously seen type */
-       case 'T':
-         (*mangled)++;
-         if (!get_count (mangled, &n) || n < 0 || n >= work -> ntypes)
-           {
-             success = 0;
-           }
-         else
-           for (i = 0; i < work->nproctypes; i++)
-             if (work -> proctypevec [i] == n)
-               success = 0;
-
-         if (success)
-           {    
-             is_proctypevec = 1;
-             push_processed_type (work, n);
-             remembered_type = work->typevec[n];
-             mangled = &remembered_type;
-           }
-         break;
-
-         /* A function */
-       case 'F':
-         (*mangled)++;
-           if (!STRING_EMPTY (&decl)
-               && (decl.b[0] == '*' || decl.b[0] == '&'))
-           {
-             string_prepend (&decl, "(");
-             string_append (&decl, ")");
-           }
-         /* After picking off the function args, we expect to either find the
-            function return type (preceded by an '_') or the end of the
-            string.  */
-         if (!demangle_nested_args (work, mangled, &decl)
-             || (**mangled != '_' && **mangled != '\0'))
-           {
-             success = 0;
-             break;
-           }
-         if (success && (**mangled == '_'))
-           (*mangled)++;
-         break;
-
-       case 'M':
-         {
-           type_quals = TYPE_UNQUALIFIED;
-
-           member = **mangled == 'M';
-           (*mangled)++;
-
-           string_append (&decl, ")");
-
-           /* We don't need to prepend `::' for a qualified name;
-              demangle_qualified will do that for us.  */
-           if (**mangled != 'Q')
-             string_prepend (&decl, SCOPE_STRING (work));
-
-           if (ISDIGIT ((unsigned char)**mangled))
-             {
-               n = consume_count (mangled);
-               if (n == -1
-                   || (int) strlen (*mangled) < n)
-                 {
-                   success = 0;
-                   break;
-                 }
-               string_prependn (&decl, *mangled, n);
-               *mangled += n;
-             }
-           else if (**mangled == 'X' || **mangled == 'Y')
-             {
-               string temp;
-               do_type (work, mangled, &temp);
-               string_prepends (&decl, &temp);
-               string_delete (&temp);
-             }
-           else if (**mangled == 't')
-             {
-               string temp;
-               string_init (&temp);
-               success = demangle_template (work, mangled, &temp,
-                                            NULL, 1, 1);
-               if (success)
-                 {
-                   string_prependn (&decl, temp.b, temp.p - temp.b);
-                   string_delete (&temp);
-                 }
-               else
-                 {
-                   string_delete (&temp);
-                   break;
-                 }
-             }
-           else if (**mangled == 'Q')
-             {
-               success = demangle_qualified (work, mangled, &decl,
-                                             /*isfuncnam=*/0, 
-                                             /*append=*/0);
-               if (!success)
-                 break;
-             }
-           else
-             {
-               success = 0;
-               break;
-             }
-
-           string_prepend (&decl, "(");
-           if (member)
-             {
-               switch (**mangled)
-                 {
-                 case 'C':
-                 case 'V':
-                 case 'u':
-                   type_quals |= code_for_qualifier (**mangled);
-                   (*mangled)++;
-                   break;
-
-                 default:
-                   break;
-                 }
-
-               if (*(*mangled) != 'F')
-                 {
-                   success = 0;
-                   break;
-                 }
-               (*mangled)++;
-             }
-           if ((member && !demangle_nested_args (work, mangled, &decl))
-               || **mangled != '_')
-             {
-               success = 0;
-               break;
-             }
-           (*mangled)++;
-           if (! PRINT_ANSI_QUALIFIERS)
-             {
-               break;
-             }
-           if (type_quals != TYPE_UNQUALIFIED)
-             {
-               APPEND_BLANK (&decl);
-               string_append (&decl, qualifier_string (type_quals));
-             }
-           break;
-         }
-        case 'G':
-         (*mangled)++;
-         break;
-
-       case 'C':
-       case 'V':
-       case 'u':
-         if (PRINT_ANSI_QUALIFIERS)
-           {
-             if (!STRING_EMPTY (&decl))
-               string_prepend (&decl, " ");
-
-             string_prepend (&decl, demangle_qualifier (**mangled));
-           }
-         (*mangled)++;
-         break;
-         /*
-           }
-           */
-
-         /* fall through */
-       default:
-         done = 1;
-         break;
-       }
-    }
-
-  if (success) switch (**mangled)
-    {
-      /* A qualified name, such as "Outer::Inner".  */
-    case 'Q':
-    case 'K':
-      {
-        success = demangle_qualified (work, mangled, result, 0, 1);
-        break;
-      }
-
-    /* A back reference to a previously seen squangled type */
-    case 'B':
-      (*mangled)++;
-      if (!get_count (mangled, &n) || n < 0 || n >= work -> numb)
-       success = 0;
-      else
-       string_append (result, work->btypevec[n]);
-      break;
-
-    case 'X':
-    case 'Y':
-      /* A template parm.  We substitute the corresponding argument. */
-      {
-       int idx;
-
-       (*mangled)++;
-       idx = consume_count_with_underscores (mangled);
-
-       if (idx == -1
-           || (work->tmpl_argvec && idx >= work->ntmpl_args)
-           || consume_count_with_underscores (mangled) == -1)
-         {
-           success = 0;
-           break;
-         }
-
-       if (work->tmpl_argvec)
-         string_append (result, work->tmpl_argvec[idx]);
-       else
-         string_append_template_idx (result, idx);
-
-       success = 1;
-      }
-    break;
-
-    default:
-      success = demangle_fund_type (work, mangled, result);
-      if (tk == tk_none)
-       tk = (type_kind_t) success;
-      break;
-    }
-
-  if (success)
-    {
-      if (!STRING_EMPTY (&decl))
-       {
-         string_append (result, " ");
-         string_appends (result, &decl);
-       }
-    }
-  else
-    string_delete (result);
-  string_delete (&decl);
-
-  if (is_proctypevec)
-    pop_processed_type (work); 
-
-  if (success)
-    /* Assume an integral type, if we're not sure.  */
-    return (int) ((tk == tk_none) ? tk_integral : tk);
-  else
-    return 0;
-}
-
-/* Given a pointer to a type string that represents a fundamental type
-   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
-   string in which the demangled output is being built in RESULT, and
-   the WORK structure, decode the types and add them to the result.
-
-   For example:
-
-       "Ci"    =>      "const int"
-       "Sl"    =>      "signed long"
-       "CUs"   =>      "const unsigned short"
-
-   The value returned is really a type_kind_t.  */
-
-static int
-demangle_fund_type (struct work_stuff *work,
-                    const char **mangled, string *result)
-{
-  int done = 0;
-  int success = 1;
-  char buf[INTBUF_SIZE + 5 /* 'int%u_t' */];
-  /* unsigned int dec = 0; */ /* JRS 2008-Oct-26: unused (see below) */
-  type_kind_t tk = tk_integral;
-
-  /* First pick off any type qualifiers.  There can be more than one.  */
-
-  while (!done)
-    {
-      switch (**mangled)
-       {
-       case 'C':
-       case 'V':
-       case 'u':
-         if (PRINT_ANSI_QUALIFIERS)
-           {
-              if (!STRING_EMPTY (result))
-                string_prepend (result, " ");
-             string_prepend (result, demangle_qualifier (**mangled));
-           }
-         (*mangled)++;
-         break;
-       case 'U':
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "unsigned");
-         break;
-       case 'S': /* signed char only */
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "signed");
-         break;
-       case 'J':
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "__complex");
-         break;
-       default:
-         done = 1;
-         break;
-       }
-    }
-
-  /* Now pick off the fundamental type.  There can be only one.  */
-
-  switch (**mangled)
-    {
-    case '\0':
-    case '_':
-      break;
-    case 'v':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "void");
-      break;
-    case 'x':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long long");
-      break;
-    case 'l':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long");
-      break;
-    case 'i':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "int");
-      break;
-    case 's':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "short");
-      break;
-    case 'b':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "bool");
-      tk = tk_bool;
-      break;
-    case 'c':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "char");
-      tk = tk_char;
-      break;
-    case 'w':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "wchar_t");
-      tk = tk_char;
-      break;
-    case 'r':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long double");
-      tk = tk_real;
-      break;
-    case 'd':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "double");
-      tk = tk_real;
-      break;
-    case 'f':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "float");
-      tk = tk_real;
-      break;
-    case 'G':
-      (*mangled)++;
-      if (!ISDIGIT ((unsigned char)**mangled))
-       {
-         success = 0;
-         break;
-       }
-      /* fall through */
-    case 'I':
-      (*mangled)++;
-      if (**mangled == '_')
-       {
-         int i;
-         (*mangled)++;
-         for (i = 0;
-              i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
-              (*mangled)++, i++)
-           buf[i] = **mangled;
-         if (**mangled != '_')
-           {
-             success = 0;
-             break;
-           }
-         buf[i] = '\0';
-         (*mangled)++;
-       }
-      else
-       {
-         strncpy (buf, *mangled, 2);
-         buf[2] = '\0';
-         *mangled += min (strlen (*mangled), 2);
-       }
-      /* JRS 2008-Oct-26: the next two commented out lines have been
-         replaced by the sprintf that follows.  This is to avoid use
-         of sscanf.  This hack is merely copied from the old demangler
-         port (by Michael Matz, Simon Hausmann?) -- I have no idea if
-         it is really correct/safe, but it looks ok. */
-      /*sscanf (buf, "%x", &dec);
-      sprintf (buf, "int%u_t", dec);*/
-      sprintf (buf, "%s", "intXX_t");
-      /* end JRS 2008-Oct-26 */
-      APPEND_BLANK (result);
-      string_append (result, buf);
-      break;
-
-      /* fall through */
-      /* An explicit type, such as "6mytype" or "7integer" */
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      {
-        int bindex = register_Btype (work);
-        string btype;
-        string_init (&btype);
-        if (demangle_class_name (work, mangled, &btype)) {
-          remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
-          APPEND_BLANK (result);
-          string_appends (result, &btype);
-        }
-        else
-          success = 0;
-        string_delete (&btype);
-        break;
-      }
-    case 't':
-      {
-        string btype;
-        string_init (&btype);
-        success = demangle_template (work, mangled, &btype, 0, 1, 1);
-        string_appends (result, &btype);
-        string_delete (&btype);
-        break;
-      }
-    default:
-      success = 0;
-      break;
-    }
-
-  return success ? ((int) tk) : 0;
-}
-
-
-/* Handle a template's value parameter for HP aCC (extension from ARM)
-   **mangled points to 'S' or 'U' */
-
-static int
-do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED,
-                               const char **mangled, string *result)
-{
-  int unsigned_const;
-
-  if (**mangled != 'U' && **mangled != 'S')
-    return 0;
-
-  unsigned_const = (**mangled == 'U');
-
-  (*mangled)++;
-
-  switch (**mangled)
-    {
-      case 'N':
-        string_append (result, "-");
-        /* fall through */
-      case 'P':
-        (*mangled)++;
-        break;
-      case 'M':
-        /* special case for -2^31 */
-        string_append (result, "-2147483648");
-        (*mangled)++;
-        return 1;
-      default:
-        return 0;
-    }
-
-  /* We have to be looking at an integer now */
-  if (!(ISDIGIT ((unsigned char)**mangled)))
-    return 0;
-
-  /* We only deal with integral values for template
-     parameters -- so it's OK to look only for digits */
-  while (ISDIGIT ((unsigned char)**mangled))
-    {
-      char_str[0] = **mangled;
-      string_append (result, char_str);
-      (*mangled)++;
-    }
-
-  if (unsigned_const)
-    string_append (result, "U");
-
-  /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
-     with L or LL suffixes. pai/1997-09-03 */
-
-  return 1; /* success */
-}
-
-/* Handle a template's literal parameter for HP aCC (extension from ARM)
-   **mangled is pointing to the 'A' */
-
-static int
-do_hpacc_template_literal (struct work_stuff *work, const char **mangled,
-                           string *result)
-{
-  int literal_len = 0;
-  char * recurse;
-  char * recurse_dem;
-
-  if (**mangled != 'A')
-    return 0;
-
-  (*mangled)++;
-
-  literal_len = consume_count (mangled);
-
-  if (literal_len <= 0
-      || literal_len > (long) strlen (*mangled))
-    return 0;
-
-  /* Literal parameters are names of arrays, functions, etc.  and the
-     canonical representation uses the address operator */
-  string_append (result, "&");
-
-  /* Now recursively demangle the literal name */
-  recurse = XNEWVEC (char, literal_len + 1);
-  memcpy (recurse, *mangled, literal_len);
-  recurse[literal_len] = '\000';
-
-  recurse_dem = ML_(cplus_demangle) (recurse, work->options);
-
-  if (recurse_dem)
-    {
-      string_append (result, recurse_dem);
-      free (recurse_dem);
-    }
-  else
-    {
-      string_appendn (result, *mangled, literal_len);
-    }
-  (*mangled) += literal_len;
-  free (recurse);
-
-  return 1;
-}
-
-static int
-snarf_numeric_literal (const char **args, string *arg)
-{
-  if (**args == '-')
-    {
-      char_str[0] = '-';
-      string_append (arg, char_str);
-      (*args)++;
-    }
-  else if (**args == '+')
-    (*args)++;
-
-  if (!ISDIGIT ((unsigned char)**args))
-    return 0;
-
-  while (ISDIGIT ((unsigned char)**args))
-    {
-      char_str[0] = **args;
-      string_append (arg, char_str);
-      (*args)++;
-    }
-
-  return 1;
-}
-
-/* Demangle the next argument, given by MANGLED into RESULT, which
-   *should be an uninitialized* string.  It will be initialized here,
-   and free'd should anything go wrong.  */
-
-static int
-do_arg (struct work_stuff *work, const char **mangled, string *result)
-{
-  /* Remember where we started so that we can record the type, for
-     non-squangling type remembering.  */
-  const char *start = *mangled;
-
-  string_init (result);
-
-  if (work->nrepeats > 0)
-    {
-      --work->nrepeats;
-
-      if (work->previous_argument == 0)
-       return 0;
-
-      /* We want to reissue the previous type in this argument list.  */
-      string_appends (result, work->previous_argument);
-      return 1;
-    }
-
-  if (**mangled == 'n')
-    {
-      /* A squangling-style repeat.  */
-      (*mangled)++;
-      work->nrepeats = consume_count(mangled);
-
-      if (work->nrepeats <= 0)
-       /* This was not a repeat count after all.  */
-       return 0;
-
-      if (work->nrepeats > 9)
-       {
-         if (**mangled != '_')
-           /* The repeat count should be followed by an '_' in this
-              case.  */
-           return 0;
-         else
-           (*mangled)++;
-       }
-
-      /* Now, the repeat is all set up.  */
-      return do_arg (work, mangled, result);
-    }
-
-  /* Save the result in WORK->previous_argument so that we can find it
-     if it's repeated.  Note that saving START is not good enough: we
-     do not want to add additional types to the back-referenceable
-     type vector when processing a repeated type.  */
-  if (work->previous_argument)
-    string_delete (work->previous_argument);
-  else
-    work->previous_argument = XNEW (string);
-
-  if (!do_type (work, mangled, work->previous_argument))
-    return 0;
-
-  string_appends (result, work->previous_argument);
-
-  remember_type (work, start, *mangled - start);
-  return 1;
-}
-
-static void
-push_processed_type (struct work_stuff *work, int typevec_index)
-{
-  if (work->nproctypes >= work->proctypevec_size)
-    {
-      if (!work->proctypevec_size)
-       {
-         work->proctypevec_size = 4;
-         work->proctypevec = XNEWVEC (int, work->proctypevec_size);
-       }
-      else 
-       {
-         if (work->proctypevec_size < 16)
-           /* Double when small.  */
-           work->proctypevec_size *= 2;
-         else
-           {
-             /* Grow slower when large.  */
-             if (work->proctypevec_size > (INT_MAX / 3) * 2)
-                xmalloc_failed (INT_MAX);
-              work->proctypevec_size = (work->proctypevec_size * 3 / 2);
-           }   
-          work->proctypevec
-            = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size);
-       }
-    }
-    work->proctypevec [work->nproctypes++] = typevec_index;
-}
-
-static void
-pop_processed_type (struct work_stuff *work)
-{
-  work->nproctypes--;
-}
-
-static void
-remember_type (struct work_stuff *work, const char *start, int len)
-{
-  char *tem;
-
-  if (work->forgetting_types)
-    return;
-
-  if (work -> ntypes >= work -> typevec_size)
-    {
-      if (work -> typevec_size == 0)
-       {
-         work -> typevec_size = 3;
-         work -> typevec = XNEWVEC (char *, work->typevec_size);
-       }
-      else
-       {
-          if (work -> typevec_size > INT_MAX / 2)
-           xmalloc_failed (INT_MAX);
-         work -> typevec_size *= 2;
-         work -> typevec
-           = XRESIZEVEC (char *, work->typevec, work->typevec_size);
-       }
-    }
-  tem = XNEWVEC (char, len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> typevec[work -> ntypes++] = tem;
-}
-
-
-/* Remember a K type class qualifier. */
-static void
-remember_Ktype (struct work_stuff *work, const char *start, int len)
-{
-  char *tem;
-
-  if (work -> numk >= work -> ksize)
-    {
-      if (work -> ksize == 0)
-       {
-         work -> ksize = 5;
-         work -> ktypevec = XNEWVEC (char *, work->ksize);
-       }
-      else
-       {
-          if (work -> ksize > INT_MAX / 2)
-           xmalloc_failed (INT_MAX);
-         work -> ksize *= 2;
-         work -> ktypevec
-           = XRESIZEVEC (char *, work->ktypevec, work->ksize);
-       }
-    }
-  tem = XNEWVEC (char, len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> ktypevec[work -> numk++] = tem;
-}
-
-/* Register a B code, and get an index for it. B codes are registered
-   as they are seen, rather than as they are completed, so map<temp<char> >
-   registers map<temp<char> > as B0, and temp<char> as B1 */
-
-static int
-register_Btype (struct work_stuff *work)
-{
-  int ret;
-
-  if (work -> numb >= work -> bsize)
-    {
-      if (work -> bsize == 0)
-       {
-         work -> bsize = 5;
-         work -> btypevec = XNEWVEC (char *, work->bsize);
-       }
-      else
-       {
-          if (work -> bsize > INT_MAX / 2)
-           xmalloc_failed (INT_MAX);
-         work -> bsize *= 2;
-         work -> btypevec
-           = XRESIZEVEC (char *, work->btypevec, work->bsize);
-       }
-    }
-  ret = work -> numb++;
-  work -> btypevec[ret] = NULL;
-  return(ret);
-}
-
-/* Store a value into a previously registered B code type. */
-
-static void
-remember_Btype (struct work_stuff *work, const char *start,
-                int len, int indx)
-{
-  char *tem;
-
-  tem = XNEWVEC (char, len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> btypevec[indx] = tem;
-}
-
-/* Lose all the info related to B and K type codes. */
-static void
-forget_B_and_K_types (struct work_stuff *work)
-{
-  int i;
-
-  while (work -> numk > 0)
-    {
-      i = --(work -> numk);
-      if (work -> ktypevec[i] != NULL)
-       {
-         free (work -> ktypevec[i]);
-         work -> ktypevec[i] = NULL;
-       }
-    }
-
-  while (work -> numb > 0)
-    {
-      i = --(work -> numb);
-      if (work -> btypevec[i] != NULL)
-       {
-         free (work -> btypevec[i]);
-         work -> btypevec[i] = NULL;
-       }
-    }
-}
-/* Forget the remembered types, but not the type vector itself.  */
-
-static void
-forget_types (struct work_stuff *work)
-{
-  int i;
-
-  while (work -> ntypes > 0)
-    {
-      i = --(work -> ntypes);
-      if (work -> typevec[i] != NULL)
-       {
-         free (work -> typevec[i]);
-         work -> typevec[i] = NULL;
-       }
-    }
-}
-
-/* Process the argument list part of the signature, after any class spec
-   has been consumed, as well as the first 'F' character (if any).  For
-   example:
-
-   "__als__3fooRT0"            =>      process "RT0"
-   "complexfunc5__FPFPc_PFl_i" =>      process "PFPc_PFl_i"
-
-   DECLP must be already initialised, usually non-empty.  It won't be freed
-   on failure.
-
-   Note that g++ differs significantly from ARM and lucid style mangling
-   with regards to references to previously seen types.  For example, given
-   the source fragment:
-
-     class foo {
-       public:
-       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
-     };
-
-     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
-     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
-
-   g++ produces the names:
-
-     __3fooiRT0iT2iT2
-     foo__FiR3fooiT1iT1
-
-   while lcc (and presumably other ARM style compilers as well) produces:
-
-     foo__FiR3fooT1T2T1T2
-     __ct__3fooFiR3fooT1T2T1T2
-
-   Note that g++ bases its type numbers starting at zero and counts all
-   previously seen types, while lucid/ARM bases its type numbers starting
-   at one and only considers types after it has seen the 'F' character
-   indicating the start of the function args.  For lucid/ARM style, we
-   account for this difference by discarding any previously seen types when
-   we see the 'F' character, and subtracting one from the type number
-   reference.
-
- */
-
-static int
-demangle_args (struct work_stuff *work, const char **mangled,
-               string *declp)
-{
-  string arg;
-  int need_comma = 0;
-  int r;
-  int t;
-  const char *tem;
-  char temptype;
-
-  if (PRINT_ARG_TYPES)
-    {
-      string_append (declp, "(");
-      if (**mangled == '\0')
-       {
-         string_append (declp, "void");
-       }
-    }
-
-  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
-        || work->nrepeats > 0)
-    {
-      if ((**mangled == 'N') || (**mangled == 'T'))
-       {
-         temptype = *(*mangled)++;
-
-         if (temptype == 'N')
-           {
-             if (!get_count (mangled, &r))
-               {
-                 return (0);
-               }
-           }
-         else
-           {
-             r = 1;
-           }
-          if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
-            {
-              /* If we have 10 or more types we might have more than a 1 digit
-                 index so we'll have to consume the whole count here. This
-                 will lose if the next thing is a type name preceded by a
-                 count but it's impossible to demangle that case properly
-                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
-                 Pc, ...)"  or "(..., type12, char *, ...)" */
-              if ((t = consume_count(mangled)) <= 0)
-                {
-                  return (0);
-                }
-            }
-          else
-           {
-             if (!get_count (mangled, &t))
-               {
-                 return (0);
-               }
-           }
-         if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-           {
-             t--;
-           }
-         /* Validate the type index.  Protect against illegal indices from
-            malformed type strings.  */
-         if ((t < 0) || (t >= work -> ntypes))
-           {
-             return (0);
-           }
-         while (work->nrepeats > 0 || --r >= 0)
-           {
-             tem = work -> typevec[t];
-             if (need_comma && PRINT_ARG_TYPES)
-               {
-                 string_append (declp, ", ");
-               }
-             push_processed_type (work, t);  
-             if (!do_arg (work, &tem, &arg))
-               {
-                 pop_processed_type (work);
-                 return (0);
-               }
-             pop_processed_type (work);
-             if (PRINT_ARG_TYPES)
-               {
-                 string_appends (declp, &arg);
-               }
-             string_delete (&arg);
-             need_comma = 1;
-           }
-       }
-      else
-       {
-         if (need_comma && PRINT_ARG_TYPES)
-           string_append (declp, ", ");
-         if (!do_arg (work, mangled, &arg))
-           return (0);
-         if (PRINT_ARG_TYPES)
-           string_appends (declp, &arg);
-         string_delete (&arg);
-         need_comma = 1;
-       }
-    }
-
-  if (**mangled == 'e')
-    {
-      (*mangled)++;
-      if (PRINT_ARG_TYPES)
-       {
-         if (need_comma)
-           {
-             string_append (declp, ",");
-           }
-         string_append (declp, "...");
-       }
-    }
-
-  if (PRINT_ARG_TYPES)
-    {
-      string_append (declp, ")");
-    }
-  return (1);
-}
-
-/* Like demangle_args, but for demangling the argument lists of function
-   and method pointers or references, not top-level declarations.  */
-
-static int
-demangle_nested_args (struct work_stuff *work, const char **mangled,
-                      string *declp)
-{
-  string* saved_previous_argument;
-  int result;
-  int saved_nrepeats;
-
-  /* The G++ name-mangling algorithm does not remember types on nested
-     argument lists, unless -fsquangling is used, and in that case the
-     type vector updated by remember_type is not used.  So, we turn
-     off remembering of types here.  */
-  ++work->forgetting_types;
-
-  /* For the repeat codes used with -fsquangling, we must keep track of
-     the last argument.  */
-  saved_previous_argument = work->previous_argument;
-  saved_nrepeats = work->nrepeats;
-  work->previous_argument = 0;
-  work->nrepeats = 0;
-
-  /* Actually demangle the arguments.  */
-  result = demangle_args (work, mangled, declp);
-
-  /* Restore the previous_argument field.  */
-  if (work->previous_argument)
-    {
-      string_delete (work->previous_argument);
-      free ((char *) work->previous_argument);
-    }
-  work->previous_argument = saved_previous_argument;
-  --work->forgetting_types;
-  work->nrepeats = saved_nrepeats;
-
-  return result;
-}
-
-/* Returns 1 if a valid function name was found or 0 otherwise.  */
-
-static int 
-demangle_function_name (struct work_stuff *work, const char **mangled,
-                        string *declp, const char *scan)
-{
-  size_t i;
-  string type;
-  const char *tem;
-
-  string_appendn (declp, (*mangled), scan - (*mangled));
-  string_need (declp, 1);
-  *(declp -> p) = '\0';
-
-  /* Consume the function name, including the "__" separating the name
-     from the signature.  We are guaranteed that SCAN points to the
-     separator.  */
-
-  (*mangled) = scan + 2;
-  /* We may be looking at an instantiation of a template function:
-     foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
-     following _F marks the start of the function arguments.  Handle
-     the template arguments first. */
-
-  if (HP_DEMANGLING && (**mangled == 'X'))
-    {
-      demangle_arm_hp_template (work, mangled, 0, declp);
-      /* This leaves MANGLED pointing to the 'F' marking func args */
-    }
-
-  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-    {
-
-      /* See if we have an ARM style constructor or destructor operator.
-        If so, then just record it, clear the decl, and return.
-        We can't build the actual constructor/destructor decl until later,
-        when we recover the class name from the signature.  */
-
-      if (strcmp (declp -> b, "__ct") == 0)
-       {
-         work -> constructor += 1;
-         string_clear (declp);
-         return 1;
-       }
-      else if (strcmp (declp -> b, "__dt") == 0)
-       {
-         work -> destructor += 1;
-         string_clear (declp);
-         return 1;
-       }
-    }
-
-  if (declp->p - declp->b >= 3
-      && declp->b[0] == 'o'
-      && declp->b[1] == 'p'
-      && strchr (cplus_markers, declp->b[2]) != NULL)
-    {
-      /* see if it's an assignment expression */
-      if (declp->p - declp->b >= 10 /* op$assign_ */
-         && memcmp (declp->b + 3, "assign_", 7) == 0)
-       {
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             int len = declp->p - declp->b - 10;
-             if ((int) strlen (optable[i].in) == len
-                 && memcmp (optable[i].in, declp->b + 10, len) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 string_append (declp, "=");
-                 break;
-               }
-           }
-       }
-      else
-       {
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             int len = declp->p - declp->b - 3;
-             if ((int) strlen (optable[i].in) == len
-                 && memcmp (optable[i].in, declp->b + 3, len) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 break;
-               }
-           }
-       }
-    }
-  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
-          && strchr (cplus_markers, declp->b[4]) != NULL)
-    {
-      /* type conversion operator */
-      tem = declp->b + 5;
-      if (do_type (work, &tem, &type))
-       {
-         string_clear (declp);
-         string_append (declp, "operator ");
-         string_appends (declp, &type);
-         string_delete (&type);
-       }
-    }
-  else if (declp->b[0] == '_' && declp->b[1] == '_'
-          && declp->b[2] == 'o' && declp->b[3] == 'p')
-    {
-      /* ANSI.  */
-      /* type conversion operator.  */
-      tem = declp->b + 4;
-      if (do_type (work, &tem, &type))
-       {
-         string_clear (declp);
-         string_append (declp, "operator ");
-         string_appends (declp, &type);
-         string_delete (&type);
-       }
-    }
-  else if (declp->b[0] == '_' && declp->b[1] == '_'
-          && ISLOWER((unsigned char)declp->b[2])
-          && ISLOWER((unsigned char)declp->b[3]))
-    {
-      if (declp->b[4] == '\0')
-       {
-         /* Operator.  */
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             if (strlen (optable[i].in) == 2
-                 && memcmp (optable[i].in, declp->b + 2, 2) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 break;
-               }
-           }
-       }
-
-      /* BEGIN hack inserted 20050403 by JRS to deal with apparently
-         non-cfront compliant new[]/delete[] manglings generated by
-         the Portland Group's C++ compiler. */
-      else 
-      if (strcmp (declp -> b, "__nwa") == 0) {
-         string_clear (declp);
-         string_append (declp, "operator new[]");
-      }
-      else 
-      if (strcmp (declp -> b, "__dla") == 0) {
-         string_clear (declp);
-         string_append (declp, "operator delete[]");
-      }
-      /* END hack */
-
-      else
-       {
-         if (declp->b[2] == 'a' && declp->b[5] == '\0')
-           {
-             /* Assignment.  */
-             for (i = 0; i < ARRAY_SIZE (optable); i++)
-               {
-                 if (strlen (optable[i].in) == 3
-                     && memcmp (optable[i].in, declp->b + 2, 3) == 0)
-                   {
-                     string_clear (declp);
-                     string_append (declp, "operator");
-                     string_append (declp, optable[i].out);
-                     break;
-                   }
-               }
-           }
-       }
-    }
-
-  /* If a function name was obtained but it's not valid, we were not
-     successful.  */
-  if (LEN_STRING (declp) == 1 && declp->b[0] == '.')
-    return 0;
-  else
-    return 1;
-}
-
-/* a mini string-handling package */
-
-static void
-string_need (string *s, int n)
-{
-  int tem;
-
-  if (s->b == NULL)
-    {
-      if (n < 32)
-       {
-         n = 32;
-       }
-      s->p = s->b = XNEWVEC (char, n);
-      s->e = s->b + n;
-    }
-  else if (s->e - s->p < n)
-    {
-      tem = s->p - s->b;
-      if (n > INT_MAX / 2 - tem)
-        xmalloc_failed (INT_MAX); 
-      n += tem;
-      n *= 2;
-      s->b = XRESIZEVEC (char, s->b, n);
-      s->p = s->b + tem;
-      s->e = s->b + n;
-    }
-}
-
-static void
-string_delete (string *s)
-{
-  if (s->b != NULL)
-    {
-      free (s->b);
-      s->b = s->e = s->p = NULL;
-    }
-}
-
-static void
-string_init (string *s)
-{
-  s->b = s->p = s->e = NULL;
-}
-
-static void
-string_clear (string *s)
-{
-  s->p = s->b;
-}
-
-#if 0
-
-static int
-string_empty (string *s)
-{
-  return (s->b == s->p);
-}
-
-#endif
-
-static void
-string_append (string *p, const char *s)
-{
-  int n;
-  if (s == NULL || *s == '\0')
-    return;
-  n = strlen (s);
-  string_need (p, n);
-  memcpy (p->p, s, n);
-  p->p += n;
-}
-
-static void
-string_appends (string *p, string *s)
-{
-  int n;
-
-  if (s->b != s->p)
-    {
-      n = s->p - s->b;
-      string_need (p, n);
-      memcpy (p->p, s->b, n);
-      p->p += n;
-    }
-}
-
-static void
-string_appendn (string *p, const char *s, int n)
-{
-  if (n != 0)
-    {
-      string_need (p, n);
-      memcpy (p->p, s, n);
-      p->p += n;
-    }
-}
-
-static void
-string_prepend (string *p, const char *s)
-{
-  if (s != NULL && *s != '\0')
-    {
-      string_prependn (p, s, strlen (s));
-    }
-}
-
-static void
-string_prepends (string *p, string *s)
-{
-  if (s->b != s->p)
-    {
-      string_prependn (p, s->b, s->p - s->b);
-    }
-}
-
-static void
-string_prependn (string *p, const char *s, int n)
-{
-  char *q;
-
-  if (n != 0)
-    {
-      string_need (p, n);
-      for (q = p->p - 1; q >= p->b; q--)
-       {
-         q[n] = q[0];
-       }
-      memcpy (p->b, s, n);
-      p->p += n;
-    }
-}
-
-static void
-string_append_template_idx (string *s, int idx)
-{
-  char buf[INTBUF_SIZE + 1 /* 'T' */];
-  sprintf(buf, "T%d", idx);
-  string_append (s, buf);
-}
index f9a7f1df8d35d009e5b4a42f9f3e0024ff8d7824..1f2fbbe43fc7eac303c00fdfccf06ffd3ae56f8c 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for the D programming language
-   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+   Copyright (C) 2014-2021 Free Software Foundation, Inc.
    Written by Iain Buclaw (ibuclaw@gdcproject.org)
 
 This file is part of the libiberty library.
@@ -26,14 +26,15 @@ You should have received a copy of the GNU Library General Public
 License along with libiberty; see the file COPYING.LIB.
 If not, see <http://www.gnu.org/licenses/>.  */
 
-/* This file exports one function; dlang_demangle.
-
-   This file imports strtol for decoding mangled literals.  */
+/* This file exports one function; dlang_demangle.  */
 
 #if 0 /* in valgrind */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
@@ -49,8 +50,6 @@ If not, see <http://www.gnu.org/licenses/>.  */
 #if 0 /* in valgrind */
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#else
-extern long strtol (const char *nptr, char **endptr, int base);
 #endif
 #endif /* ! in valgrind */
 
@@ -65,6 +64,13 @@ extern long strtol (const char *nptr, char **endptr, int base);
 #include "demangle.h"
 #include "safe-ctype.h"
 
+#ifndef ULONG_MAX
+#define        ULONG_MAX       (~0UL)
+#endif
+#ifndef UINT_MAX
+#define        UINT_MAX        (~0U)
+#endif
+
 /* A mini string-handling package */
 
 typedef struct string          /* Beware: these aren't required to be */
@@ -75,9 +81,9 @@ typedef struct string         /* Beware: these aren't required to be */
 } string;
 
 static void
-string_need (string *s, int n)
+string_need (string *s, size_t n)
 {
-  int tem;
+  size_t tem;
 
   if (s->b == NULL)
     {
@@ -88,7 +94,7 @@ string_need (string *s, int n)
       s->p = s->b = XNEWVEC (char, n);
       s->e = s->b + n;
     }
-  else if (s->e - s->p < n)
+  else if ((size_t) (s->e - s->p) < n)
     {
       tem = s->p - s->b;
       n += tem;
@@ -137,14 +143,14 @@ string_setlength (string *s, int n)
 static void
 string_append (string *p, const char *s)
 {
-  int n = strlen (s);
+  size_t n = strlen (s);
   string_need (p, n);
   memcpy (p->p, s, n);
   p->p += n;
 }
 
 static void
-string_appendn (string *p, const char *s, int n)
+string_appendn (string *p, const char *s, size_t n)
 {
   if (n != 0)
     {
@@ -155,7 +161,7 @@ string_appendn (string *p, const char *s, int n)
 }
 
 static void
-string_prependn (string *p, const char *s, int n)
+string_prependn (string *p, const char *s, size_t n)
 {
   char *q;
 
@@ -180,35 +186,290 @@ string_prepend (string *p, const char *s)
     }
 }
 
-/* What kinds of symbol we could be parsing.  */
-enum dlang_symbol_kinds
+/* Demangle information structure we pass around.  */
+struct dlang_info
 {
-  /* Top-level symbol, needs it's type checked.  */
-  dlang_top_level,
-  /* Function symbol, needs it's type checked.   */
-  dlang_function,
-  /* Strongly typed name, such as for classes, structs and enums.  */
-  dlang_type_name,
-  /* Template identifier.  */
-  dlang_template_ident,
-  /* Template symbol parameter.  */
-  dlang_template_param
+  /* The string we are demangling.  */
+  const char *s;
+  /* The index of the last back reference.  */
+  int last_backref;
 };
 
+/* Pass as the LEN to dlang_parse_template if symbol length is not known.  */
+#define TEMPLATE_LENGTH_UNKNOWN (-1UL)
+
 /* Prototypes for forward referenced functions */
-static const char *dlang_function_args (string *, const char *);
+static const char *dlang_function_type (string *, const char *,
+                                       struct dlang_info *);
 
-static const char *dlang_type (string *, const char *);
+static const char *dlang_function_args (string *, const char *,
+                                       struct dlang_info *);
+
+static const char *dlang_type (string *, const char *, struct dlang_info *);
 
 static const char *dlang_value (string *, const char *, const char *, char);
 
-static const char *dlang_parse_symbol (string *, const char *,
-                                      enum dlang_symbol_kinds);
+static const char *dlang_parse_qualified (string *, const char *,
+                                         struct dlang_info *, int);
+
+static const char *dlang_parse_mangle (string *, const char *,
+                                      struct dlang_info *);
+
+static const char *dlang_parse_tuple (string *, const char *,
+                                     struct dlang_info *);
+
+static const char *dlang_parse_template (string *, const char *,
+                                        struct dlang_info *, unsigned long);
+
+static const char *dlang_lname (string *, const char *, unsigned long);
+
+
+/* Extract the number from MANGLED, and assign the result to RET.
+   Return the remaining string on success or NULL on failure.
+   A result larger than UINT_MAX is considered a failure.  */
+static const char *
+dlang_number (const char *mangled, unsigned long *ret)
+{
+  /* Return NULL if trying to extract something that isn't a digit.  */
+  if (mangled == NULL || !ISDIGIT (*mangled))
+    return NULL;
+
+  unsigned long val = 0;
+
+  while (ISDIGIT (*mangled))
+    {
+      unsigned long digit = mangled[0] - '0';
+
+      /* Check for overflow.  */
+      if (val > (UINT_MAX - digit) / 10)
+       return NULL;
+
+      val = val * 10 + digit;
+      mangled++;
+    }
+
+  if (*mangled == '\0')
+    return NULL;
+
+  *ret = val;
+  return mangled;
+}
+
+/* Extract the hex-digit from MANGLED, and assign the result to RET.
+   Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_hexdigit (const char *mangled, char *ret)
+{
+  char c;
+
+  /* Return NULL if trying to extract something that isn't a hexdigit.  */
+  if (mangled == NULL || !ISXDIGIT (mangled[0]) || !ISXDIGIT (mangled[1]))
+    return NULL;
+
+  c = mangled[0];
+  if (!ISDIGIT (c))
+    (*ret) = (c - (ISUPPER (c) ? 'A' : 'a') + 10);
+  else
+    (*ret) = (c - '0');
+
+  c = mangled[1];
+  if (!ISDIGIT (c))
+    (*ret) = (*ret << 4) | (c - (ISUPPER (c) ? 'A' : 'a') + 10);
+  else
+    (*ret) = (*ret << 4) | (c - '0');
+
+  mangled += 2;
+
+  return mangled;
+}
+
+/* Extract the function calling convention from MANGLED and
+   return 1 on success or 0 on failure.  */
+static int
+dlang_call_convention_p (const char *mangled)
+{
+  switch (*mangled)
+    {
+    case 'F': case 'U': case 'V':
+    case 'W': case 'R': case 'Y':
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Extract the back reference position from MANGLED, and assign the result
+   to RET.  Return the remaining string on success or NULL on failure.
+   A result <= 0 is a failure.  */
+static const char *
+dlang_decode_backref (const char *mangled, long *ret)
+{
+  /* Return NULL if trying to extract something that isn't a digit.  */
+  if (mangled == NULL || !ISALPHA (*mangled))
+    return NULL;
+
+  /* Any identifier or non-basic type that has been emitted to the mangled
+     symbol before will not be emitted again, but is referenced by a special
+     sequence encoding the relative position of the original occurrence in the
+     mangled symbol name.
+
+     Numbers in back references are encoded with base 26 by upper case letters
+     A-Z for higher digits but lower case letters a-z for the last digit.
+
+       NumberBackRef:
+           [a-z]
+           [A-Z] NumberBackRef
+           ^
+   */
+  unsigned long val = 0;
+
+  while (ISALPHA (*mangled))
+    {
+      /* Check for overflow.  */
+      if (val > (ULONG_MAX - 25) / 26)
+       break;
+
+      val *= 26;
+
+      if (mangled[0] >= 'a' && mangled[0] <= 'z')
+       {
+         val += mangled[0] - 'a';
+         if ((long) val <= 0)
+           break;
+         *ret = val;
+         return mangled + 1;
+       }
+
+      val += mangled[0] - 'A';
+      mangled++;
+    }
+
+  return NULL;
+}
+
+/* Extract the symbol pointed at by the back reference and assign the result
+   to RET.  Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_backref (const char *mangled, const char **ret, struct dlang_info *info)
+{
+  (*ret) = NULL;
+
+  if (mangled == NULL || *mangled != 'Q')
+    return NULL;
+
+  /* Position of 'Q'.  */
+  const char *qpos = mangled;
+  long refpos;
+  mangled++;
+
+  mangled = dlang_decode_backref (mangled, &refpos);
+  if (mangled == NULL)
+    return NULL;
+
+  if (refpos > qpos - info->s)
+    return NULL;
+
+  /* Set the position of the back reference.  */
+  (*ret) = qpos - refpos;
+
+  return mangled;
+}
+
+/* Demangle a back referenced symbol from MANGLED and append it to DECL.
+   Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_symbol_backref (string *decl, const char *mangled,
+                     struct dlang_info *info)
+{
+  /* An identifier back reference always points to a digit 0 to 9.
+
+       IdentifierBackRef:
+           Q NumberBackRef
+           ^
+   */
+  const char *backref;
+  unsigned long len;
+
+  /* Get position of the back reference.  */
+  mangled = dlang_backref (mangled, &backref, info);
+
+  /* Must point to a simple identifier.  */
+  backref = dlang_number (backref, &len);
+  if (backref == NULL)
+    return NULL;
+
+  backref = dlang_lname (decl, backref, len);
+  if (backref == NULL)
+    return NULL;
+
+  return mangled;
+}
+
+/* Demangle a back referenced type from MANGLED and append it to DECL.
+   IS_FUNCTION is 1 if the back referenced type is expected to be a function.
+   Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_type_backref (string *decl, const char *mangled, struct dlang_info *info,
+                   int is_function)
+{
+  /* A type back reference always points to a letter.
+
+       TypeBackRef:
+           Q NumberBackRef
+           ^
+   */
+  const char *backref;
+
+  /* If we appear to be moving backwards through the mangle string, then
+     bail as this may be a recursive back reference.  */
+  if (mangled - info->s >= info->last_backref)
+    return NULL;
+
+  int save_refpos = info->last_backref;
+  info->last_backref = mangled - info->s;
+
+  /* Get position of the back reference.  */
+  mangled = dlang_backref (mangled, &backref, info);
+
+  /* Must point to a type.  */
+  if (is_function)
+    backref = dlang_function_type (decl, backref, info);
+  else
+    backref = dlang_type (decl, backref, info);
+
+  info->last_backref = save_refpos;
+
+  if (backref == NULL)
+    return NULL;
+
+  return mangled;
+}
+
+/* Extract the beginning of a symbol name from MANGLED and
+   return 1 on success or 0 on failure.  */
+static int
+dlang_symbol_name_p (const char *mangled, struct dlang_info *info)
+{
+  long ret;
+  const char *qref = mangled;
 
-static const char *dlang_parse_tuple (string *, const char *);
+  if (ISDIGIT (*mangled))
+    return 1;
 
-static const char *dlang_parse_template (string *, const char *, long);
+  if (mangled[0] == '_' && mangled[1] == '_'
+      && (mangled[2] == 'T' || mangled[2] == 'U'))
+    return 1;
 
+  if (*mangled != 'Q')
+    return 0;
+
+  mangled = dlang_decode_backref (mangled + 1, &ret);
+  if (mangled == NULL || ret > qref - info->s)
+    return 0;
+
+  return ISDIGIT (qref[-ret]);
+}
 
 /* Demangle the calling convention from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
@@ -343,6 +604,14 @@ dlang_attributes (string *decl, const char *mangled)
          mangled++;
          string_append (decl, "return ");
          continue;
+       case 'l': /* scope */
+         mangled++;
+         string_append (decl, "scope ");
+         continue;
+       case 'm': /* @live */
+         mangled++;
+         string_append (decl, "@live ");
+         continue;
 
        default: /* unknown attribute */
          return NULL;
@@ -353,13 +622,39 @@ dlang_attributes (string *decl, const char *mangled)
   return mangled;
 }
 
+/* Demangle the function type from MANGLED without the return type.
+   The arguments are appended to ARGS, the calling convention is appended
+   to CALL and attributes are appended to ATTR.  Any of these can be NULL
+   to throw the information away.  Return the remaining string on success
+   or NULL on failure.  */
+static const char *
+dlang_function_type_noreturn (string *args, string *call, string *attr,
+                             const char *mangled, struct dlang_info *info)
+{
+  string dump;
+  string_init (&dump);
+
+  /* Skip over calling convention and attributes.  */
+  mangled = dlang_call_convention (call ? call : &dump, mangled);
+  mangled = dlang_attributes (attr ? attr : &dump, mangled);
+
+  if (args)
+    string_append (args, "(");
+
+  mangled = dlang_function_args (args ? args : &dump, mangled, info);
+  if (args)
+    string_append (args, ")");
+
+  string_delete (&dump);
+  return mangled;
+}
+
 /* Demangle the function type from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_function_type (string *decl, const char *mangled)
+dlang_function_type (string *decl, const char *mangled, struct dlang_info *info)
 {
   string attr, args, type;
-  size_t szattr, szargs, sztype;
 
   if (mangled == NULL || *mangled == '\0')
     return NULL;
@@ -374,27 +669,16 @@ dlang_function_type (string *decl, const char *mangled)
   string_init (&args);
   string_init (&type);
 
-  /* Function call convention.  */
-  mangled = dlang_call_convention (decl, mangled);
-
-  /* Function attributes.  */
-  mangled = dlang_attributes (&attr, mangled);
-  szattr = string_length (&attr);
-
-  /* Function arguments.  */
-  mangled = dlang_function_args (&args, mangled);
-  szargs = string_length (&args);
+  mangled = dlang_function_type_noreturn (&args, decl, &attr, mangled, info);
 
   /* Function return type.  */
-  mangled = dlang_type (&type, mangled);
-  sztype = string_length (&type);
+  mangled = dlang_type (&type, mangled, info);
 
   /* Append to decl in order. */
-  string_appendn (decl, type.b, sztype);
-  string_append (decl, "(");
-  string_appendn (decl, args.b, szargs);
-  string_append (decl, ") ");
-  string_appendn (decl, attr.b, szattr);
+  string_appendn (decl, type.b, string_length (&type));
+  string_appendn (decl, args.b, string_length (&args));
+  string_append (decl, " ");
+  string_appendn (decl, attr.b, string_length (&attr));
 
   string_delete (&attr);
   string_delete (&args);
@@ -405,7 +689,7 @@ dlang_function_type (string *decl, const char *mangled)
 /* Demangle the argument list from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_function_args (string *decl, const char *mangled)
+dlang_function_args (string *decl, const char *mangled, struct dlang_info *info)
 {
   size_t n = 0;
 
@@ -445,6 +729,15 @@ dlang_function_args (string *decl, const char *mangled)
 
       switch (*mangled)
        {
+       case 'I': /* in(T) */
+         mangled++;
+         string_append (decl, "in ");
+         if (*mangled == 'K') /* in ref(T) */
+           {
+             mangled++;
+             string_append (decl, "ref ");
+           }
+         break;
        case 'J': /* out(T) */
          mangled++;
          string_append (decl, "out ");
@@ -458,7 +751,7 @@ dlang_function_args (string *decl, const char *mangled)
          string_append (decl, "lazy ");
          break;
        }
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
     }
 
   return mangled;
@@ -467,7 +760,7 @@ dlang_function_args (string *decl, const char *mangled)
 /* Demangle the type from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_type (string *decl, const char *mangled)
+dlang_type (string *decl, const char *mangled, struct dlang_info *info)
 {
   if (mangled == NULL || *mangled == '\0')
     return NULL;
@@ -477,19 +770,19 @@ dlang_type (string *decl, const char *mangled)
     case 'O': /* shared(T) */
       mangled++;
       string_append (decl, "shared(");
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, ")");
       return mangled;
     case 'x': /* const(T) */
       mangled++;
       string_append (decl, "const(");
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, ")");
       return mangled;
     case 'y': /* immutable(T) */
       mangled++;
       string_append (decl, "immutable(");
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, ")");
       return mangled;
     case 'N':
@@ -498,7 +791,7 @@ dlang_type (string *decl, const char *mangled)
        {
          mangled++;
          string_append (decl, "inout(");
-         mangled = dlang_type (decl, mangled);
+         mangled = dlang_type (decl, mangled, info);
          string_append (decl, ")");
          return mangled;
        }
@@ -506,7 +799,7 @@ dlang_type (string *decl, const char *mangled)
        {
          mangled++;
          string_append (decl, "__vector(");
-         mangled = dlang_type (decl, mangled);
+         mangled = dlang_type (decl, mangled, info);
          string_append (decl, ")");
          return mangled;
        }
@@ -514,7 +807,7 @@ dlang_type (string *decl, const char *mangled)
        return NULL;
     case 'A': /* dynamic array (T[]) */
       mangled++;
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, "[]");
       return mangled;
     case 'G': /* static array (T[N]) */
@@ -529,7 +822,7 @@ dlang_type (string *decl, const char *mangled)
          num++;
          mangled++;
        }
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, "[");
       string_appendn (decl, numptr, num);
       string_append (decl, "]");
@@ -542,10 +835,10 @@ dlang_type (string *decl, const char *mangled)
       mangled++;
 
       string_init (&type);
-      mangled = dlang_type (&type, mangled);
+      mangled = dlang_type (&type, mangled, info);
       sztype = string_length (&type);
 
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
       string_append (decl, "[");
       string_appendn (decl, type.b, sztype);
       string_append (decl, "]");
@@ -555,25 +848,29 @@ dlang_type (string *decl, const char *mangled)
     }
     case 'P': /* pointer (T*) */
       mangled++;
-      /* Function pointer types don't include the trailing asterisk.  */
-      switch (*mangled)
+      if (!dlang_call_convention_p (mangled))
        {
-       case 'F': case 'U': case 'W':
-       case 'V': case 'R': case 'Y':
-         mangled = dlang_function_type (decl, mangled);
-         string_append (decl, "function");
+         mangled = dlang_type (decl, mangled, info);
+         string_append (decl, "*");
          return mangled;
        }
-      mangled = dlang_type (decl, mangled);
-      string_append (decl, "*");
+      /* Fall through */
+    case 'F': /* function T (D) */
+    case 'U': /* function T (C) */
+    case 'W': /* function T (Windows) */
+    case 'V': /* function T (Pascal) */
+    case 'R': /* function T (C++) */
+    case 'Y': /* function T (Objective-C) */
+      /* Function pointer types don't include the trailing asterisk.  */
+      mangled = dlang_function_type (decl, mangled, info);
+      string_append (decl, "function");
       return mangled;
-    case 'I': /* ident T */
     case 'C': /* class T */
     case 'S': /* struct T */
     case 'E': /* enum T */
     case 'T': /* typedef T */
       mangled++;
-      return dlang_parse_symbol (decl, mangled, dlang_type_name);
+      return dlang_parse_qualified (decl, mangled, info, 0);
     case 'D': /* delegate T */
     {
       string mods;
@@ -584,7 +881,12 @@ dlang_type (string *decl, const char *mangled)
       mangled = dlang_type_modifiers (&mods, mangled);
       szmods = string_length (&mods);
 
-      mangled = dlang_function_type (decl, mangled);
+      /* Back referenced function type.  */
+      if (*mangled == 'Q')
+       mangled = dlang_type_backref (decl, mangled, info, 1);
+      else
+       mangled = dlang_function_type (decl, mangled, info);
+
       string_append (decl, "delegate");
       string_appendn (decl, mods.b, szmods);
 
@@ -593,7 +895,7 @@ dlang_type (string *decl, const char *mangled)
     }
     case 'B': /* tuple T */
       mangled++;
-      return dlang_parse_tuple (decl, mangled);
+      return dlang_parse_tuple (decl, mangled, info);
 
     /* Basic types */
     case 'n':
@@ -707,6 +1009,10 @@ dlang_type (string *decl, const char *mangled)
        }
       return NULL;
 
+    /* Back referenced type.  */
+    case 'Q':
+      return dlang_type_backref (decl, mangled, info, 0);
+
     default: /* unhandled */
       return NULL;
     }
@@ -715,163 +1021,127 @@ dlang_type (string *decl, const char *mangled)
 /* Extract the identifier from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_identifier (string *decl, const char *mangled,
-                 enum dlang_symbol_kinds kind)
+dlang_identifier (string *decl, const char *mangled, struct dlang_info *info)
 {
-  char *endptr;
-  long len;
+  unsigned long len;
 
   if (mangled == NULL || *mangled == '\0')
     return NULL;
 
-  len = strtol (mangled, &endptr, 10);
+  if (*mangled == 'Q')
+    return dlang_symbol_backref (decl, mangled, info);
 
-  if (endptr == NULL || len <= 0)
-    return NULL;
+  /* May be a template instance without a length prefix.  */
+  if (mangled[0] == '_' && mangled[1] == '_'
+      && (mangled[2] == 'T' || mangled[2] == 'U'))
+    return dlang_parse_template (decl, mangled, info, TEMPLATE_LENGTH_UNKNOWN);
 
-  /* In template parameter symbols, the first character of the mangled
-     name can be a digit.  This causes ambiguity issues because the
-     digits of the two numbers are adjacent.  */
-  if (kind == dlang_template_param)
-    {
-      long psize = len;
-      char *pend;
-      int saved = string_length (decl);
+  const char *endptr = dlang_number (mangled, &len);
 
-      /* Work backwards until a match is found.  */
-      for (pend = endptr; endptr != NULL; pend--)
-       {
-         mangled = pend;
+  if (endptr == NULL || len == 0)
+    return NULL;
 
-         /* Reached the beginning of the pointer to the name length,
-            try parsing the entire symbol.  */
-         if (psize == 0)
-           {
-             psize = len;
-             pend = endptr;
-             endptr = NULL;
-           }
+  if (strlen (endptr) < len)
+    return NULL;
 
-         /* Check whether template parameter is a function with a valid
-            return type or an untyped identifier.  */
-         if (ISDIGIT (*mangled))
-           mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident);
-         else if (strncmp (mangled, "_D", 2) == 0)
-           {
-             mangled += 2;
-             mangled = dlang_parse_symbol (decl, mangled, dlang_function);
-           }
+  mangled = endptr;
 
-         /* Check for name length mismatch.  */
-         if (mangled && (mangled - pend) == psize)
-           return mangled;
+  /* May be a template instance with a length prefix.  */
+  if (len >= 5 && mangled[0] == '_' && mangled[1] == '_'
+      && (mangled[2] == 'T' || mangled[2] == 'U'))
+    return dlang_parse_template (decl, mangled, info, len);
 
-         psize /= 10;
-         string_setlength (decl, saved);
-       }
+  return dlang_lname (decl, mangled, len);
+}
 
-      /* No match on any combinations.  */
-      return NULL;
-    }
-  else
+/* Extract the plain identifier from MANGLED and prepend/append it to DECL
+   with special treatment for some magic compiler generted symbols.
+   Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_lname (string *decl, const char *mangled, unsigned long len)
+{
+  switch (len)
     {
-      if (strlen (endptr) < (size_t) len)
-       return NULL;
-
-      mangled = endptr;
-
-      /* May be a template instance.  */
-      if (len >= 5 && strncmp (mangled, "__T", 3) == 0)
+    case 6:
+      if (strncmp (mangled, "__ctor", len) == 0)
        {
-         /* Template symbol.  */
-         if (ISDIGIT (mangled[3]) && mangled[3] != '0')
-           return dlang_parse_template (decl, mangled, len);
-
-         return NULL;
+         /* Constructor symbol for a class/struct.  */
+         string_append (decl, "this");
+         mangled += len;
+         return mangled;
        }
-
-      switch (len)
+      else if (strncmp (mangled, "__dtor", len) == 0)
        {
-       case 6:
-         if (strncmp (mangled, "__ctor", len) == 0)
-           {
-             /* Constructor symbol for a class/struct.  */
-             string_append (decl, "this");
-             mangled += len;
-             return mangled;
-           }
-         else if (strncmp (mangled, "__dtor", len) == 0)
-           {
-             /* Destructor symbol for a class/struct.  */
-             string_append (decl, "~this");
-             mangled += len;
-             return mangled;
-           }
-         else if (strncmp (mangled, "__initZ", len+1) == 0)
-           {
-             /* The static initialiser for a given symbol.  */
-             string_append (decl, "init$");
-             mangled += len;
-             return mangled;
-           }
-         else if (strncmp (mangled, "__vtblZ", len+1) == 0)
-           {
-             /* The vtable symbol for a given class.  */
-             string_prepend (decl, "vtable for ");
-             string_setlength (decl, string_length (decl) - 1);
-             mangled += len;
-             return mangled;
-           }
-         break;
-
-       case 7:
-         if (strncmp (mangled, "__ClassZ", len+1) == 0)
-           {
-             /* The classinfo symbol for a given class.  */
-             string_prepend (decl, "ClassInfo for ");
-             string_setlength (decl, string_length (decl) - 1);
-             mangled += len;
-             return mangled;
-           }
-         break;
+         /* Destructor symbol for a class/struct.  */
+         string_append (decl, "~this");
+         mangled += len;
+         return mangled;
+       }
+      else if (strncmp (mangled, "__initZ", len + 1) == 0)
+       {
+         /* The static initialiser for a given symbol.  */
+         string_prepend (decl, "initializer for ");
+         string_setlength (decl, string_length (decl) - 1);
+         mangled += len;
+         return mangled;
+       }
+      else if (strncmp (mangled, "__vtblZ", len + 1) == 0)
+       {
+         /* The vtable symbol for a given class.  */
+         string_prepend (decl, "vtable for ");
+         string_setlength (decl, string_length (decl) - 1);
+         mangled += len;
+         return mangled;
+       }
+      break;
 
-       case 10:
-         if (strncmp (mangled, "__postblitMFZ", len+3) == 0)
-           {
-             /* Postblit symbol for a struct.  */
-             string_append (decl, "this(this)");
-             mangled += len + 3;
-             return mangled;
-           }
-         break;
+    case 7:
+      if (strncmp (mangled, "__ClassZ", len + 1) == 0)
+       {
+         /* The classinfo symbol for a given class.  */
+         string_prepend (decl, "ClassInfo for ");
+         string_setlength (decl, string_length (decl) - 1);
+         mangled += len;
+         return mangled;
+       }
+      break;
 
-       case 11:
-         if (strncmp (mangled, "__InterfaceZ", len+1) == 0)
-           {
-             /* The interface symbol for a given class.  */
-             string_prepend (decl, "Interface for ");
-             string_setlength (decl, string_length (decl) - 1);
-             mangled += len;
-             return mangled;
-           }
-         break;
+    case 10:
+      if (strncmp (mangled, "__postblitMFZ", len + 3) == 0)
+       {
+         /* Postblit symbol for a struct.  */
+         string_append (decl, "this(this)");
+         mangled += len + 3;
+         return mangled;
+       }
+      break;
 
-       case 12:
-         if (strncmp (mangled, "__ModuleInfoZ", len+1) == 0)
-           {
-             /* The ModuleInfo symbol for a given module.  */
-             string_prepend (decl, "ModuleInfo for ");
-             string_setlength (decl, string_length (decl) - 1);
-             mangled += len;
-             return mangled;
-           }
-         break;
+    case 11:
+      if (strncmp (mangled, "__InterfaceZ", len + 1) == 0)
+       {
+         /* The interface symbol for a given class.  */
+         string_prepend (decl, "Interface for ");
+         string_setlength (decl, string_length (decl) - 1);
+         mangled += len;
+         return mangled;
        }
+      break;
 
-      string_appendn (decl, mangled, len);
-      mangled += len;
+    case 12:
+      if (strncmp (mangled, "__ModuleInfoZ", len + 1) == 0)
+       {
+         /* The ModuleInfo symbol for a given module.  */
+         string_prepend (decl, "ModuleInfo for ");
+         string_setlength (decl, string_length (decl) - 1);
+         mangled += len;
+         return mangled;
+       }
+      break;
     }
 
+  string_appendn (decl, mangled, len);
+  mangled += len;
+
   return mangled;
 }
 
@@ -884,13 +1154,13 @@ dlang_parse_integer (string *decl, const char *mangled, char type)
   if (type == 'a' || type == 'u' || type == 'w')
     {
       /* Parse character value.  */
-      char value[10];
-      int pos = 10;
+      char value[20];
+      int pos = sizeof(value);
       int width = 0;
-      char *endptr;
-      long val = strtol (mangled, &endptr, 10);
+      unsigned long val;
 
-      if (endptr == NULL || val < 0)
+      mangled = dlang_number (mangled, &val);
+      if (mangled == NULL)
        return NULL;
 
       string_append (decl, "'");
@@ -936,22 +1206,20 @@ dlang_parse_integer (string *decl, const char *mangled, char type)
          for (; width > 0; width--)
            value[--pos] = '0';
 
-         string_appendn (decl, &(value[pos]), 10 - pos);
+         string_appendn (decl, &(value[pos]), sizeof(value) - pos);
        }
       string_append (decl, "'");
-      mangled = endptr;
     }
   else if (type == 'b')
     {
       /* Parse boolean value.  */
-      char *endptr;
-      long val = strtol (mangled, &endptr, 10);
+      unsigned long val;
 
-      if (endptr == NULL || val < 0)
+      mangled = dlang_number (mangled, &val);
+      if (mangled == NULL)
        return NULL;
 
       string_append (decl, val ? "true" : "false");
-      mangled = endptr;
     }
   else
     {
@@ -959,6 +1227,9 @@ dlang_parse_integer (string *decl, const char *mangled, char type)
       const char *numptr = mangled;
       size_t num = 0;
 
+      if (! ISDIGIT (*mangled))
+       return NULL;
+
       while (ISDIGIT (*mangled))
        {
          num++;
@@ -991,9 +1262,6 @@ dlang_parse_integer (string *decl, const char *mangled, char type)
 static const char *
 dlang_parse_real (string *decl, const char *mangled)
 {
-  char buffer[64];
-  int len = 0;
-
   /* Handle NAN and +-INF.  */
   if (strncmp (mangled, "NAN", 3) == 0)
     {
@@ -1017,23 +1285,22 @@ dlang_parse_real (string *decl, const char *mangled)
   /* Hexadecimal prefix and leading bit.  */
   if (*mangled == 'N')
     {
-      buffer[len++] = '-';
+      string_append (decl, "-");
       mangled++;
     }
 
   if (!ISXDIGIT (*mangled))
     return NULL;
 
-  buffer[len++] = '0';
-  buffer[len++] = 'x';
-  buffer[len++] = *mangled;
-  buffer[len++] = '.';
+  string_append (decl, "0x");
+  string_appendn (decl, mangled, 1);
+  string_append (decl, ".");
   mangled++;
 
   /* Significand.  */
   while (ISXDIGIT (*mangled))
     {
-      buffer[len++] = *mangled;
+      string_appendn (decl, mangled, 1);
       mangled++;
     }
 
@@ -1041,110 +1308,80 @@ dlang_parse_real (string *decl, const char *mangled)
   if (*mangled != 'P')
     return NULL;
 
-  buffer[len++] = 'p';
+  string_append (decl, "p");
   mangled++;
 
   if (*mangled == 'N')
     {
-      buffer[len++] = '-';
+      string_append (decl, "-");
       mangled++;
     }
 
   while (ISDIGIT (*mangled))
     {
-      buffer[len++] = *mangled;
+      string_appendn (decl, mangled, 1);
       mangled++;
     }
 
-  /* Write out the demangled hexadecimal, rather than trying to
-     convert the buffer into a floating-point value.  */
-  buffer[len] = '\0';
-  len = strlen (buffer);
-  string_appendn (decl, buffer, len);
   return mangled;
 }
 
-/* Convert VAL from an ascii hexdigit to value.  */
-static char
-ascii2hex (char val)
-{
-  if (val >= 'a' && val <= 'f')
-    return (val - 'a' + 10);
-
-  if (val >= 'A' && val <= 'F')
-    return (val - 'A' + 10);
-
-  if (val >= '0' && val <= '9')
-    return (val - '0');
-
-  return 0;
-}
-
 /* Extract the string value from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
 dlang_parse_string (string *decl, const char *mangled)
 {
   char type = *mangled;
-  char *endptr;
-  long len;
+  unsigned long len;
 
   mangled++;
-  len = strtol (mangled, &endptr, 10);
-
-  if (endptr == NULL || len < 0)
-    return NULL;
-
-  mangled = endptr;
-  if (*mangled != '_')
+  mangled = dlang_number (mangled, &len);
+  if (mangled == NULL || *mangled != '_')
     return NULL;
 
   mangled++;
   string_append (decl, "\"");
   while (len--)
     {
-      if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
+      char val;
+      const char *endptr = dlang_hexdigit (mangled, &val);
+
+      if (endptr == NULL)
+       return NULL;
+
+      /* Sanitize white and non-printable characters.  */
+      switch (val)
        {
-         char a = ascii2hex (mangled[0]);
-         char b = ascii2hex (mangled[1]);
-         char val = (a << 4) | b;
+       case ' ':
+         string_append (decl, " ");
+         break;
+       case '\t':
+         string_append (decl, "\\t");
+         break;
+       case '\n':
+         string_append (decl, "\\n");
+         break;
+       case '\r':
+         string_append (decl, "\\r");
+         break;
+       case '\f':
+         string_append (decl, "\\f");
+         break;
+       case '\v':
+         string_append (decl, "\\v");
+         break;
 
-         /* Sanitize white and non-printable characters.  */
-         switch (val)
+       default:
+         if (ISPRINT (val))
+           string_appendn (decl, &val, 1);
+         else
            {
-           case ' ':
-             string_append (decl, " ");
-             break;
-           case '\t':
-             string_append (decl, "\\t");
-             break;
-           case '\n':
-             string_append (decl, "\\n");
-             break;
-           case '\r':
-             string_append (decl, "\\r");
-             break;
-           case '\f':
-             string_append (decl, "\\f");
-             break;
-           case '\v':
-             string_append (decl, "\\v");
-             break;
-
-           default:
-             if (ISPRINT (val))
-               string_appendn (decl, &val, 1);
-             else
-               {
-                 string_append (decl, "\\x");
-                 string_appendn (decl, mangled, 2);
-               }
+             string_append (decl, "\\x");
+             string_appendn (decl, mangled, 2);
            }
        }
-      else
-       return NULL;
 
-      mangled += 2;
+      mangled = endptr;
     }
   string_append (decl, "\"");
 
@@ -1159,17 +1396,19 @@ dlang_parse_string (string *decl, const char *mangled)
 static const char *
 dlang_parse_arrayliteral (string *decl, const char *mangled)
 {
-  char *endptr;
-  long elements = strtol (mangled, &endptr, 10);
+  unsigned long elements;
 
-  if (endptr == NULL || elements < 0)
+  mangled = dlang_number (mangled, &elements);
+  if (mangled == NULL)
     return NULL;
 
-  mangled = endptr;
   string_append (decl, "[");
   while (elements--)
     {
       mangled = dlang_value (decl, mangled, NULL, '\0');
+      if (mangled == NULL)
+       return NULL;
+
       if (elements != 0)
        string_append (decl, ", ");
     }
@@ -1183,19 +1422,23 @@ dlang_parse_arrayliteral (string *decl, const char *mangled)
 static const char *
 dlang_parse_assocarray (string *decl, const char *mangled)
 {
-  char *endptr;
-  long elements = strtol (mangled, &endptr, 10);
+  unsigned long elements;
 
-  if (endptr == NULL || elements < 0)
+  mangled = dlang_number (mangled, &elements);
+  if (mangled == NULL)
     return NULL;
 
-  mangled = endptr;
   string_append (decl, "[");
   while (elements--)
     {
       mangled = dlang_value (decl, mangled, NULL, '\0');
+      if (mangled == NULL)
+       return NULL;
+
       string_append (decl, ":");
       mangled = dlang_value (decl, mangled, NULL, '\0');
+      if (mangled == NULL)
+       return NULL;
 
       if (elements != 0)
        string_append (decl, ", ");
@@ -1210,13 +1453,12 @@ dlang_parse_assocarray (string *decl, const char *mangled)
 static const char *
 dlang_parse_structlit (string *decl, const char *mangled, const char *name)
 {
-  char *endptr;
-  long args = strtol (mangled, &endptr, 10);
+  unsigned long args;
 
-  if (endptr == NULL || args < 0)
+  mangled = dlang_number (mangled, &args);
+  if (mangled == NULL)
     return NULL;
 
-  mangled = endptr;
   if (name != NULL)
     string_append (decl, name);
 
@@ -1224,6 +1466,9 @@ dlang_parse_structlit (string *decl, const char *mangled, const char *name)
   while (args--)
     {
       mangled = dlang_value (decl, mangled, NULL, '\0');
+      if (mangled == NULL)
+       return NULL;
+
       if (args != 0)
        string_append (decl, ", ");
     }
@@ -1257,9 +1502,11 @@ dlang_value (string *decl, const char *mangled, const char *name, char type)
 
     case 'i':
       mangled++;
-      if (*mangled < '0' || *mangled > '9')
-       return NULL;
       /* Fall through */
+
+      /* There really should always be an `i' before encoded numbers, but there
+        wasn't in early versions of D2, so this case range must remain for
+        backwards compatibility.  */
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
       mangled = dlang_parse_integer (decl, mangled, type);
@@ -1312,143 +1559,118 @@ dlang_value (string *decl, const char *mangled, const char *name, char type)
   return mangled;
 }
 
-/* Extract the type modifiers from MANGLED and return the string
-   length that it consumes in MANGLED on success or 0 on failure.  */
-static int
-dlang_type_modifier_p (const char *mangled)
+/* Extract and demangle the symbol in MANGLED and append it to DECL.
+   Returns the remaining signature on success or NULL on failure.  */
+static const char *
+dlang_parse_mangle (string *decl, const char *mangled, struct dlang_info *info)
 {
-  int i;
-
-  switch (*mangled)
-    {
-    case 'x': case 'y':
-      return 1;
+  /* A D mangled symbol is comprised of both scope and type information.
+
+       MangleName:
+           _D QualifiedName Type
+           _D QualifiedName Z
+           ^
+     The caller should have guaranteed that the start pointer is at the
+     above location.
+     Note that type is never a function type, but only the return type of
+     a function or the type of a variable.
+   */
+  mangled += 2;
 
-    case 'O':
-      mangled++;
-      i = dlang_type_modifier_p (mangled);
-      return i + 1;
+  mangled = dlang_parse_qualified (decl, mangled, info, 1);
 
-    case 'N':
-      mangled++;
-      if (*mangled == 'g')
+  if (mangled != NULL)
+    {
+      /* Artificial symbols end with 'Z' and have no type.  */
+      if (*mangled == 'Z')
+       mangled++;
+      else
        {
-         mangled++;
-         i = dlang_type_modifier_p (mangled);
-         return i + 2;
-       }
-    }
-
-  return 0;
-}
+         /* Discard the declaration or return type.  */
+         string type;
 
-/* Extract the function calling convention from MANGLED and
-   return 1 on success or 0 on failure.  */
-static int
-dlang_call_convention_p (const char *mangled)
-{
-  /* Prefix for functions needing 'this' */
-  if (*mangled == 'M')
-    {
-      mangled++;
-      /* Also skip over any type modifiers.  */
-      mangled += dlang_type_modifier_p (mangled);
+         string_init (&type);
+         mangled = dlang_type (&type, mangled, info);
+         string_delete (&type);
+       }
     }
 
-  switch (*mangled)
-    {
-    case 'F': case 'U': case 'V':
-    case 'W': case 'R': case 'Y':
-      return 1;
-
-    default:
-      return 0;
-    }
+  return mangled;
 }
 
-/* Extract and demangle the symbol in MANGLED and append it to DECL.
+/* Extract and demangle the qualified symbol in MANGLED and append it to DECL.
+   SUFFIX_MODIFIERS is 1 if we are printing modifiers on this after the symbol.
    Returns the remaining signature on success or NULL on failure.  */
 static const char *
-dlang_parse_symbol (string *decl, const char *mangled,
-                   enum dlang_symbol_kinds kind)
+dlang_parse_qualified (string *decl, const char *mangled,
+                      struct dlang_info *info, int suffix_modifiers)
 {
-  int saved;
+  /* Qualified names are identifiers separated by their encoded length.
+     Nested functions also encode their argument types without specifying
+     what they return.
+
+       QualifiedName:
+           SymbolFunctionName
+           SymbolFunctionName QualifiedName
+           ^
+
+       SymbolFunctionName:
+           SymbolName
+           SymbolName TypeFunctionNoReturn
+           SymbolName M TypeFunctionNoReturn
+           SymbolName M TypeModifiers TypeFunctionNoReturn
+
+     The start pointer should be at the above location.
+   */
   size_t n = 0;
   do
     {
       if (n++)
        string_append (decl, ".");
 
-      mangled = dlang_identifier (decl, mangled, kind);
+      /* Skip over anonymous symbols.  */
+      while (*mangled == '0')
+       mangled++;
+
+      mangled = dlang_identifier (decl, mangled, info);
 
-      if (mangled && dlang_call_convention_p (mangled))
+      /* Consume the encoded arguments.  However if this is not followed by the
+        next encoded length or mangle type, then this is not a continuation of
+        a qualified name, in which case we backtrack and return the current
+        unconsumed position of the mangled decl.  */
+      if (mangled && (*mangled == 'M' || dlang_call_convention_p (mangled)))
        {
          string mods;
-         const char *start = NULL;
-         int checkpoint = 0;
+         const char *start = mangled;
+         int saved = string_length (decl);
 
-         /* Skip over 'this' parameter.  */
-         if (*mangled == 'M')
-           mangled++;
+         /* Save the type modifiers for appending at the end if needed.  */
+         string_init (&mods);
 
-         /* We have reached here because we expect an extern(Pascal) function.
-            However this is so rare, that it is more likely a template value
-            parameter.  Since this can't be assumed, first attempt parsing
-            the symbol as a function, and then back out on failure.  */
-         if (*mangled == 'V')
+         /* Skip over 'this' parameter and type modifiers.  */
+         if (*mangled == 'M')
            {
-             start = mangled;
-             checkpoint = string_length (decl);
+             mangled++;
+             mangled = dlang_type_modifiers (&mods, mangled);
+             string_setlength (decl, saved);
            }
 
-         /* Save the type modifiers for appending at the end.  */
-         string_init (&mods);
-         mangled = dlang_type_modifiers (&mods, mangled);
-
-         /* Skip over calling convention and attributes in qualified name.  */
-         saved = string_length (decl);
-         mangled = dlang_call_convention (decl, mangled);
-         mangled = dlang_attributes (decl, mangled);
-         string_setlength (decl, saved);
+         mangled = dlang_function_type_noreturn (decl, NULL, NULL,
+                                                 mangled, info);
+         if (suffix_modifiers)
+           string_appendn (decl, mods.b, string_length (&mods));
 
-         string_append (decl, "(");
-         mangled = dlang_function_args (decl, mangled);
-         string_append (decl, ")");
-
-         /* Add any const/immutable/shared modifier. */
-         string_appendn (decl, mods.b, string_length (&mods));
-         string_delete (&mods);
-
-         if (mangled == NULL && checkpoint != 0)
+         if (mangled == NULL || *mangled == '\0')
            {
+             /* Did not match the rule we were looking for.  */
              mangled = start;
-             string_setlength (decl, checkpoint);
+             string_setlength (decl, saved);
            }
-       }
-    }
-  while (mangled && ISDIGIT (*mangled));
-
-  /* Only top-level symbols or function template parameters have
-     a type that needs checking.  */
-  if (kind == dlang_top_level || kind == dlang_function)
-    {
-      /* Artificial symbols end with 'Z' and have no type.  */
-      if (mangled && *mangled == 'Z')
-       mangled++;
-      else
-       {
-         saved = string_length (decl);
-         mangled = dlang_type (decl, mangled);
-         string_setlength (decl, saved);
-       }
 
-      /* Check that the entire symbol was successfully demangled.  */
-      if (kind == dlang_top_level)
-       {
-         if (mangled == NULL || *mangled != '\0')
-           return NULL;
+         string_delete (&mods);
        }
     }
+  while (mangled && dlang_symbol_name_p (mangled, info));
 
   return mangled;
 }
@@ -1456,20 +1678,22 @@ dlang_parse_symbol (string *decl, const char *mangled,
 /* Demangle the tuple from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_parse_tuple (string *decl, const char *mangled)
+dlang_parse_tuple (string *decl, const char *mangled, struct dlang_info *info)
 {
-  char *endptr;
-  long elements = strtol (mangled, &endptr, 10);
+  unsigned long elements;
 
-  if (endptr == NULL || elements < 0)
+  mangled = dlang_number (mangled, &elements);
+  if (mangled == NULL)
     return NULL;
 
-  mangled = endptr;
   string_append (decl, "Tuple!(");
 
   while (elements--)
     {
-      mangled = dlang_type (decl, mangled);
+      mangled = dlang_type (decl, mangled, info);
+      if (mangled == NULL)
+       return NULL;
+
       if (elements != 0)
        string_append (decl, ", ");
     }
@@ -1478,10 +1702,71 @@ dlang_parse_tuple (string *decl, const char *mangled)
   return mangled;
 }
 
+/* Demangle the template symbol parameter from MANGLED and append it to DECL.
+   Return the remaining string on success or NULL on failure.  */
+static const char *
+dlang_template_symbol_param (string *decl, const char *mangled,
+                            struct dlang_info *info)
+{
+  if (strncmp (mangled, "_D", 2) == 0
+      && dlang_symbol_name_p (mangled + 2, info))
+    return dlang_parse_mangle (decl, mangled, info);
+
+  if (*mangled == 'Q')
+    return dlang_parse_qualified (decl, mangled, info, 0);
+
+  unsigned long len;
+  const char *endptr = dlang_number (mangled, &len);
+
+  if (endptr == NULL || len == 0)
+    return NULL;
+
+  /* In template parameter symbols generated by the frontend up to 2.076,
+     the symbol length is encoded and the first character of the mangled
+     name can be a digit.  This causes ambiguity issues because the digits
+     of the two numbers are adjacent.  */
+  long psize = len;
+  const char *pend;
+  int saved = string_length (decl);
+
+  /* Work backwards until a match is found.  */
+  for (pend = endptr; endptr != NULL; pend--)
+    {
+      mangled = pend;
+
+      /* Reached the beginning of the pointer to the name length,
+        try parsing the entire symbol.  */
+      if (psize == 0)
+       {
+         psize = len;
+         pend = endptr;
+         endptr = NULL;
+       }
+
+      /* Check whether template parameter is a function with a valid
+        return type or an untyped identifier.  */
+      if (dlang_symbol_name_p (mangled, info))
+       mangled = dlang_parse_qualified (decl, mangled, info, 0);
+      else if (strncmp (mangled, "_D", 2) == 0
+              && dlang_symbol_name_p (mangled + 2, info))
+       mangled = dlang_parse_mangle (decl, mangled, info);
+
+      /* Check for name length mismatch.  */
+      if (mangled && (endptr == NULL || (mangled - pend) == psize))
+       return mangled;
+
+      psize /= 10;
+      string_setlength (decl, saved);
+    }
+
+  /* No match on any combinations.  */
+  return NULL;
+}
+
 /* Demangle the argument list from MANGLED and append it to DECL.
    Return the remaining string on success or NULL on failure.  */
 static const char *
-dlang_template_args (string *decl, const char *mangled)
+dlang_template_args (string *decl, const char *mangled, struct dlang_info *info)
 {
   size_t n = 0;
 
@@ -1505,11 +1790,11 @@ dlang_template_args (string *decl, const char *mangled)
        {
        case 'S': /* Symbol parameter.  */
          mangled++;
-         mangled = dlang_parse_symbol (decl, mangled, dlang_template_param);
+         mangled = dlang_template_symbol_param (decl, mangled, info);
          break;
        case 'T': /* Type parameter.  */
          mangled++;
-         mangled = dlang_type (decl, mangled);
+         mangled = dlang_type (decl, mangled, info);
          break;
        case 'V': /* Value parameter.  */
        {
@@ -1520,10 +1805,20 @@ dlang_template_args (string *decl, const char *mangled)
          mangled++;
          type = *mangled;
 
+         if (type == 'Q')
+           {
+             /* Value type is a back reference, peek at the real type.  */
+             const char *backref;
+             if (dlang_backref (mangled, &backref, info) == NULL)
+               return NULL;
+
+             type = *backref;
+           }
+
          /* In the few instances where the type is actually desired in
             the output, it should precede the value from dlang_value.  */
          string_init (&name);
-         mangled = dlang_type (&name, mangled);
+         mangled = dlang_type (&name, mangled, info);
          string_need (&name, 1);
          *(name.p) = '\0';
 
@@ -1531,7 +1826,20 @@ dlang_template_args (string *decl, const char *mangled)
          string_delete (&name);
          break;
        }
+       case 'X': /* Externally mangled parameter.  */
+       {
+         unsigned long len;
+         const char *endptr;
+
+         mangled++;
+         endptr = dlang_number (mangled, &len);
+         if (endptr == NULL || strlen (endptr) < len)
+           return NULL;
 
+         string_appendn (decl, endptr, len);
+         mangled = endptr + len;
+         break;
+       }
        default:
          return NULL;
        }
@@ -1541,42 +1849,63 @@ dlang_template_args (string *decl, const char *mangled)
 }
 
 /* Extract and demangle the template symbol in MANGLED, expected to
-   be made up of LEN characters, and append it to DECL.
+   be made up of LEN characters (-1 if unknown), and append it to DECL.
    Returns the remaining signature on success or NULL on failure.  */
 static const char *
-dlang_parse_template (string *decl, const char *mangled, long len)
+dlang_parse_template (string *decl, const char *mangled,
+                     struct dlang_info *info, unsigned long len)
 {
   const char *start = mangled;
+  string args;
 
   /* Template instance names have the types and values of its parameters
      encoded into it.
 
        TemplateInstanceName:
            Number __T LName TemplateArgs Z
+           Number __U LName TemplateArgs Z
                   ^
      The start pointer should be at the above location, and LEN should be
      the value of the decoded number.
    */
-  if (strncmp (mangled, "__T", 3) != 0)
+
+  /* Template symbol.  */
+  if (!dlang_symbol_name_p (mangled + 3, info) || mangled[3] == '0')
     return NULL;
 
   mangled += 3;
 
   /* Template identifier.  */
-  mangled = dlang_identifier (decl, mangled, dlang_template_ident);
+  mangled = dlang_identifier (decl, mangled, info);
 
   /* Template arguments.  */
+  string_init (&args);
+  mangled = dlang_template_args (&args, mangled, info);
+
   string_append (decl, "!(");
-  mangled = dlang_template_args (decl, mangled);
+  string_appendn (decl, args.b, string_length (&args));
   string_append (decl, ")");
 
+  string_delete (&args);
+
   /* Check for template name length mismatch.  */
-  if (mangled && (mangled - start) != len)
+  if (len != TEMPLATE_LENGTH_UNKNOWN
+      && mangled
+      && (unsigned long) (mangled - start) != len)
     return NULL;
 
   return mangled;
 }
 
+/* Initialize the information structure we use to pass around information.  */
+static void
+dlang_demangle_init_info (const char *mangled, int last_backref,
+                         struct dlang_info *info)
+{
+  info->s = mangled;
+  info->last_backref = last_backref;
+}
+
 /* Extract and demangle the symbol in MANGLED.  Returns the demangled
    signature on success or NULL on failure.  */
 
@@ -1600,9 +1929,13 @@ dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
     }
   else
     {
-      mangled += 2;
+      struct dlang_info info;
+
+      dlang_demangle_init_info (mangled, strlen (mangled), &info);
+      mangled = dlang_parse_mangle (&decl, mangled, &info);
 
-      if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL)
+      /* Check that the entire symbol was successfully demangled.  */
+      if (mangled == NULL || *mangled != '\0')
        string_delete (&decl);
     }
 
index 29afa8973a55e4598199f9df6b340932d6eda4b5..16161da2af45421bb43a58ea43f2349a7eff4524 100644 (file)
 /*------------------------------------------------------------*/
 
 /* The demangler's job is to take a raw symbol name and turn it into
-   something a Human Bean can understand.  Our mangling model
-   comprises a three stage pipeline.  Mangling pushes names forward
-   through the pipeline (0, then 1, then 2) and demangling is
-   obviously the reverse.  In practice it is highly unlikely that a
-   name would require all stages, but it is not impossible either.
+   something a Human Bean can understand.  There are two levels of
+   mangling.
 
-   0. If we're working with Rust, Rust names are lightly mangled by
-      the Rust front end.
-
-   1. Then the name is subject to standard C++ mangling.
+   1. First, C++ names are mangled by the compiler.  So we'll have to
+      undo that.
 
    2. Optionally, in relatively rare cases, the resulting name is then
       itself encoded using Z-escaping (see pub_core_redir.h) so as to
@@ -64,8 +59,7 @@
 
    Therefore, VG_(demangle) first tries to undo (2).  If successful,
    the soname part is discarded (humans don't want to see that).
-   Then, it tries to undo (1) (using demangling code from GNU/FSF) and
-   finally it tries to undo (0).
+   Then, it tries to undo (1) (using demangling code from GNU/FSF).
 
    Finally, it changes the name of all symbols which are known to be
    functions below main() to "(below main)".  This helps reduce
    If do_cxx_demangle == True, it does all the above stages:
    - undo (2) [Z-encoding]
    - undo (1) [C++ mangling]
-   - if (1) succeeds, undo (0) [Rust mangling]
    - do the below-main hack
 
-   Rust demangling (0) is only done if C++ demangling (1) succeeds
-   because Rust demangling is performed in-place, and it is difficult
-   to prove that we "own" the storage -- hence, that the in-place
-   operation is safe -- unless it is clear that it has come from the
-   C++ demangler, which returns its output in a heap-allocated buffer
-   which we can be sure we own.  In practice (Nov 2016) this does not
-   seem to be a problem, since the Rust compiler appears to apply C++
-   mangling after Rust mangling, so we never encounter symbols that
-   require Rust demangling but not C++ demangling.
-
    If do_cxx_demangle == False, the C++ and Rust stags are skipped:
    - undo (2) [Z-encoding]
    - do the below-main hack
@@ -149,23 +132,6 @@ void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling,
       demangled = ML_(cplus_demangle) ( orig, DMGL_ANSI | DMGL_PARAMS );
 
       *result = (demangled == NULL) ? orig : demangled;
-
-      if (demangled) {
-         /* Possibly undo (0).  This is the only place where it is
-            safe, from a storage management perspective, to
-            Rust-demangle the symbol.  That's because Rust demangling
-            happens in place, so we need to be sure that the storage
-            it is happening in is actually owned by us, and non-const.
-            In this case, the value returned by ML_(cplus_demangle)
-            does have that property. */
-         if (rust_is_mangled(demangled)) {
-            rust_demangle_sym(demangled);
-         }
-         *result = demangled;
-      } else {
-         *result = orig;
-      }
-
    } else {
       *result = orig;
    }
index f5a214362d0a402d0b7d0582d20cc8705d10e979..bcccf45d0c1ac4361b6eee2467eccfb8068bd580 100644 (file)
@@ -1,5 +1,5 @@
 /* Defs for interface to demanglers.
-   Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   Copyright (C) 1992-2021 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
@@ -55,21 +55,25 @@ extern "C" {
                                           */
 
 #define DMGL_AUTO       (1 << 8)
-#define DMGL_GNU        (1 << 9)
-#define DMGL_LUCID      (1 << 10)
-#define DMGL_ARM        (1 << 11)
-#define DMGL_HP         (1 << 12)       /* For the HP aCC compiler;
-                                            same as ARM except for
-                                            template arguments, etc. */
-#define DMGL_EDG        (1 << 13)
 #define DMGL_GNU_V3     (1 << 14)
 #define DMGL_GNAT       (1 << 15)
 #define DMGL_DLANG      (1 << 16)
 #define DMGL_RUST       (1 << 17)      /* Rust wraps GNU_V3 style mangling.  */
 
 /* If none of these are set, use 'current_demangling_style' as the default. */
-#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST)
-
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|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
@@ -83,11 +87,6 @@ extern enum demangling_styles
   no_demangling = -1,
   unknown_demangling = 0,
   auto_demangling = DMGL_AUTO,
-  gnu_demangling = DMGL_GNU,
-  lucid_demangling = DMGL_LUCID,
-  arm_demangling = DMGL_ARM,
-  hp_demangling = DMGL_HP,
-  edg_demangling = DMGL_EDG,
   gnu_v3_demangling = DMGL_GNU_V3,
   java_demangling = DMGL_JAVA,
   gnat_demangling = DMGL_GNAT,
@@ -99,11 +98,6 @@ extern enum demangling_styles
 
 #define NO_DEMANGLING_STYLE_STRING            "none"
 #define AUTO_DEMANGLING_STYLE_STRING         "auto"
-#define GNU_DEMANGLING_STYLE_STRING                  "gnu"
-#define LUCID_DEMANGLING_STYLE_STRING        "lucid"
-#define ARM_DEMANGLING_STYLE_STRING          "arm"
-#define HP_DEMANGLING_STYLE_STRING           "hp"
-#define EDG_DEMANGLING_STYLE_STRING          "edg"
 #define GNU_V3_DEMANGLING_STYLE_STRING        "gnu-v3"
 #define JAVA_DEMANGLING_STYLE_STRING          "java"
 #define GNAT_DEMANGLING_STYLE_STRING          "gnat"
@@ -114,11 +108,6 @@ extern enum demangling_styles
 
 #define CURRENT_DEMANGLING_STYLE current_demangling_style
 #define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
-#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
-#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
-#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
-#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
-#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
 #define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
 #define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
 #define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
@@ -138,17 +127,8 @@ extern const struct demangler_engine
 extern char *
 ML_(cplus_demangle) (const char *mangled, int options);
 
-extern int
-cplus_demangle_opname (const char *opname, char *result, int options);
-
-extern const char *
-cplus_mangle_opname (const char *opname, int options);
-
 /* Note: This sets global state.  FIXME if you care about multi-threading. */
 
-extern void
-set_cplus_marker_for_demangling (int ch);
-
 extern enum demangling_styles
 cplus_demangle_set_style (enum demangling_styles style);
 
@@ -181,24 +161,11 @@ ada_demangle (const char *mangled, int options);
 extern char *
 dlang_demangle (const char *mangled, int options);
 
-/* Returns non-zero iff MANGLED is a rust mangled symbol.  MANGLED must
-   already have been demangled through cplus_demangle_v3.  If this function
-   returns non-zero then MANGLED can be demangled (in-place) using
-   RUST_DEMANGLE_SYM.  */
 extern int
-rust_is_mangled (const char *mangled);
-
-/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM.
-   If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might
-   replace characters that cannot be demangled with '?' and might truncate
-   SYM.  After calling RUST_DEMANGLE_SYM SYM might be shorter, but never
-   larger.  */
-extern void
-rust_demangle_sym (char *sym);
-
-/* Demangles MANGLED if it was GNU_V3 and then RUST mangled, otherwise
-   returns NULL. Uses CPLUS_DEMANGLE_V3, RUST_IS_MANGLED and
-   RUST_DEMANGLE_SYM.  Returns a new string that is owned by the caller.  */
+rust_demangle_callback (const char *mangled, int options,
+                        demangle_callbackref callback, void *opaque);
+
+
 extern char *
 rust_demangle (const char *mangled, int options);
 
@@ -394,6 +361,9 @@ enum demangle_component_type
      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,
@@ -500,6 +470,7 @@ struct demangle_component
      Initialize to zero.  Private to d_print_comp.
      All other fields are final after initialization.  */
   int d_printing;
+  int d_counting;
 
   union
   {
index 9beba6e4682d0707011f3ec12f27fc4aa640c88b..8b688a24ad6f07dc39b040add057a19ece683924 100644 (file)
@@ -1,5 +1,5 @@
 /* An abstract string datatype.
-   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   Copyright (C) 1998-2021 Free Software Foundation, Inc.
    Contributed by Mark Mitchell (mark@markmitchell.com).
 
 This file is part of GNU CC.
index 6c0accc72460379e07be10b54d82442e2cc8c52e..6c5e66012d6b10ab2eecc0d557d676eafdf3f537 100644 (file)
@@ -1,5 +1,5 @@
 /* An abstract string datatype.
-   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   Copyright (C) 1998-2021 Free Software Foundation, Inc.
    Contributed by Mark Mitchell (mark@markmitchell.com).
 
 This file is part of GCC.
index 3bfde6d750c9f0e4f340518aa215260d20ff6c23..9ad424e85cd0e6b082cd10cc471e40be6854c62f 100644 (file)
@@ -1,6 +1,7 @@
 /* Demangler for the Rust programming language
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   Copyright (C) 2016-2021 Free Software Foundation, Inc.
    Written by David Tolnay (dtolnay@gmail.com).
+   Rewritten by Eduard-Mihai Burtescu (eddyb@lyken.rs) for v0 support.
 
 This file is part of the libiberty library.
 Libiberty is free software; you can redistribute it and/or
@@ -38,9 +39,11 @@ If not, see <http://www.gnu.org/licenses/>.  */
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
+#include <inttypes.h>
 #include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
 #endif /* ! in valgrind */
 
 #if 0 /* in valgrind */
@@ -64,300 +67,1483 @@ extern void *memset(void *s, int c, size_t n);
 #include "demangle.h"
 #include "safe-ctype.h"
 
-/* Mangled Rust symbols look like this:
-     _$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a
+typedef UChar uint8_t;
+typedef Char int8_t;
+typedef UShort uint16_t;
+typedef Short int16_t;
+typedef UInt uint32_t;
+typedef Int int32_t;
+typedef ULong uint64_t;
+typedef Long int64_t;
+#define PRIu64 "llu"
+#define PRIx64 "llx"
 
-   The original symbol is:
-     <std::sys::fd::FileDesc as core::ops::Drop>::drop
+struct rust_demangler
+{
+  const char *sym;
+  size_t sym_len;
 
-   The last component of the path is a 64-bit hash in lowercase hex,
-   prefixed with "h". Rust does not have a global namespace between
-   crates, an illusion which Rust maintains by using the hash to
-   distinguish things that would otherwise have the same symbol.
+  void *callback_opaque;
+  demangle_callbackref callback;
 
-   Any path component not starting with a XID_Start character is
-   prefixed with "_".
+  /* Position of the next character to read from the symbol. */
+  size_t next;
 
-   The following escape sequences are used:
+  /* Non-zero if any error occurred. */
+  int errored;
 
-   ","  =>  $C$
-   "@"  =>  $SP$
-   "*"  =>  $BP$
-   "&"  =>  $RF$
-   "<"  =>  $LT$
-   ">"  =>  $GT$
-   "("  =>  $LP$
-   ")"  =>  $RP$
-   " "  =>  $u20$
-   "\"" =>  $u22$
-   "'"  =>  $u27$
-   "+"  =>  $u2b$
-   ";"  =>  $u3b$
-   "["  =>  $u5b$
-   "]"  =>  $u5d$
-   "{"  =>  $u7b$
-   "}"  =>  $u7d$
-   "~"  =>  $u7e$
+  /* Non-zero if nothing should be printed. */
+  int skipping_printing;
 
-   A double ".." means "::" and a single "." means "-".
+  /* Non-zero if printing should be verbose (e.g. include hashes). */
+  int verbose;
 
-   The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$  */
+  /* Rust mangling version, with legacy mangling being -1. */
+  int version;
 
-static const char *hash_prefix = "::h";
-static const size_t hash_prefix_len = 3;
-static const size_t hash_len = 16;
+  uint64_t bound_lifetime_depth;
+};
 
-static int is_prefixed_hash (const char *start);
-static int looks_like_rust (const char *sym, size_t len);
-static int unescape (const char **in, char **out, const char *seq, char value);
+/* Parsing functions. */
 
-/* INPUT: sym: symbol that has been through C++ (gnu v3) demangling
+static char
+peek (const struct rust_demangler *rdm)
+{
+  if (rdm->next < rdm->sym_len)
+    return rdm->sym[rdm->next];
+  return 0;
+}
 
-   This function looks for the following indicators:
+static int
+eat (struct rust_demangler *rdm, char c)
+{
+  if (peek (rdm) == c)
+    {
+      rdm->next++;
+      return 1;
+    }
+  else
+    return 0;
+}
 
-   1. The hash must consist of "h" followed by 16 lowercase hex digits.
+static char
+next (struct rust_demangler *rdm)
+{
+  char c = peek (rdm);
+  if (!c)
+    rdm->errored = 1;
+  else
+    rdm->next++;
+  return c;
+}
 
-   2. As a sanity check, the hash must use between 5 and 15 of the 16
-      possible hex digits. This is true of 99.9998% of hashes so once
-      in your life you may see a false negative. The point is to
-      notice path components that could be Rust hashes but are
-      probably not, like "haaaaaaaaaaaaaaaa". In this case a false
-      positive (non-Rust symbol has an important path component
-      removed because it looks like a Rust hash) is worse than a false
-      negative (the rare Rust symbol is not demangled) so this sets
-      the balance in favor of false negatives.
+static uint64_t
+parse_integer_62 (struct rust_demangler *rdm)
+{
+  char c;
+  uint64_t x;
 
-   3. There must be no characters other than a-zA-Z0-9 and _.:$
+  if (eat (rdm, '_'))
+    return 0;
 
-   4. There must be no unrecognized $-sign sequences.
+  x = 0;
+  while (!eat (rdm, '_'))
+    {
+      c = next (rdm);
+      x *= 62;
+      if (ISDIGIT (c))
+        x += c - '0';
+      else if (ISLOWER (c))
+        x += 10 + (c - 'a');
+      else if (ISUPPER (c))
+        x += 10 + 26 + (c - 'A');
+      else
+        {
+          rdm->errored = 1;
+          return 0;
+        }
+    }
+  return x + 1;
+}
 
-   5. There must be no sequence of three or more dots in a row ("...").  */
+static uint64_t
+parse_opt_integer_62 (struct rust_demangler *rdm, char tag)
+{
+  if (!eat (rdm, tag))
+    return 0;
+  return 1 + parse_integer_62 (rdm);
+}
 
-int
-rust_is_mangled (const char *sym)
+static uint64_t
+parse_disambiguator (struct rust_demangler *rdm)
 {
-  size_t len, len_without_hash;
+  return parse_opt_integer_62 (rdm, 's');
+}
 
-  if (!sym)
-    return 0;
+static size_t
+parse_hex_nibbles (struct rust_demangler *rdm, uint64_t *value)
+{
+  char c;
+  size_t hex_len;
 
-  len = strlen (sym);
-  if (len <= hash_prefix_len + hash_len)
-    /* Not long enough to contain "::h" + hash + something else */
-    return 0;
+  hex_len = 0;
+  *value = 0;
 
-  len_without_hash = len - (hash_prefix_len + hash_len);
-  if (!is_prefixed_hash (sym + len_without_hash))
-    return 0;
+  while (!eat (rdm, '_'))
+    {
+      *value <<= 4;
+
+      c = next (rdm);
+      if (ISDIGIT (c))
+        *value |= c - '0';
+      else if (c >= 'a' && c <= 'f')
+        *value |= 10 + (c - 'a');
+      else
+        {
+          rdm->errored = 1;
+          return 0;
+        }
+      hex_len++;
+    }
 
-  return looks_like_rust (sym, len_without_hash);
+  return hex_len;
 }
 
-/* A hash is the prefix "::h" followed by 16 lowercase hex digits. The
-   hex digits must comprise between 5 and 15 (inclusive) distinct
-   digits.  */
+struct rust_mangled_ident
+{
+  /* ASCII part of the identifier. */
+  const char *ascii;
+  size_t ascii_len;
+
+  /* Punycode insertion codes for Unicode codepoints, if any. */
+  const char *punycode;
+  size_t punycode_len;
+};
+
+static struct rust_mangled_ident
+parse_ident (struct rust_demangler *rdm)
+{
+  char c;
+  size_t start, len;
+  int is_punycode = 0;
+  struct rust_mangled_ident ident;
+
+  ident.ascii = NULL;
+  ident.ascii_len = 0;
+  ident.punycode = NULL;
+  ident.punycode_len = 0;
+
+  if (rdm->version != -1)
+    is_punycode = eat (rdm, 'u');
+
+  c = next (rdm);
+  if (!ISDIGIT (c))
+    {
+      rdm->errored = 1;
+      return ident;
+    }
+  len = c - '0';
+
+  if (c != '0')
+    while (ISDIGIT (peek (rdm)))
+      len = len * 10 + (next (rdm) - '0');
+
+  /* Skip past the optional `_` separator (v0). */
+  if (rdm->version != -1)
+    eat (rdm, '_');
+
+  start = rdm->next;
+  rdm->next += len;
+  /* Check for overflows. */
+  if ((start > rdm->next) || (rdm->next > rdm->sym_len))
+    {
+      rdm->errored = 1;
+      return ident;
+    }
 
+  ident.ascii = rdm->sym + start;
+  ident.ascii_len = len;
+
+  if (is_punycode)
+    {
+      ident.punycode_len = 0;
+      while (ident.ascii_len > 0)
+        {
+          ident.ascii_len--;
+
+          /* The last '_' is a separator between ascii & punycode. */
+          if (ident.ascii[ident.ascii_len] == '_')
+            break;
+
+          ident.punycode_len++;
+        }
+      if (!ident.punycode_len)
+        {
+          rdm->errored = 1;
+          return ident;
+        }
+      ident.punycode = ident.ascii + (len - ident.punycode_len);
+    }
+
+  if (ident.ascii_len == 0)
+    ident.ascii = NULL;
+
+  return ident;
+}
+
+/* Printing functions. */
+
+static void
+print_str (struct rust_demangler *rdm, const char *data, size_t len)
+{
+  if (!rdm->errored && !rdm->skipping_printing)
+    rdm->callback (data, len, rdm->callback_opaque);
+}
+
+#define PRINT(s) print_str (rdm, s, strlen (s))
+
+static void
+print_uint64 (struct rust_demangler *rdm, uint64_t x)
+{
+  char s[21];
+  snprintf (s, 21, "%" PRIu64, x);
+  PRINT (s);
+}
+
+static void
+print_uint64_hex (struct rust_demangler *rdm, uint64_t x)
+{
+  char s[17];
+  snprintf (s, 17, "%" PRIx64, x);
+  PRINT (s);
+}
+
+/* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
 static int
-is_prefixed_hash (const char *str)
+decode_lower_hex_nibble (char nibble)
+{
+  if ('0' <= nibble && nibble <= '9')
+    return nibble - '0';
+  if ('a' <= nibble && nibble <= 'f')
+    return 0xa + (nibble - 'a');
+  return -1;
+}
+
+/* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
+static char
+decode_legacy_escape (const char *e, size_t len, size_t *out_len)
 {
-  const char *end;
-  char seen[16];
-  size_t i;
-  int count;
+  char c = 0;
+  size_t escape_len = 0;
+  int lo_nibble = -1, hi_nibble = -1;
 
-  if (strncmp (str, hash_prefix, hash_prefix_len))
+  if (len < 3 || e[0] != '$')
     return 0;
-  str += hash_prefix_len;
-
-  memset (seen, 0, sizeof(seen));
-  for (end = str + hash_len; str < end; str++)
-    if (*str >= '0' && *str <= '9')
-      seen[*str - '0'] = 1;
-    else if (*str >= 'a' && *str <= 'f')
-      seen[*str - 'a' + 10] = 1;
-    else
-      return 0;
 
-  /* Count how many distinct digits seen */
-  count = 0;
-  for (i = 0; i < 16; i++)
-    if (seen[i])
-      count++;
+  e++;
+  len--;
+
+  if (e[0] == 'C')
+    {
+      escape_len = 1;
+
+      c = ',';
+    }
+  else if (len > 2)
+    {
+      escape_len = 2;
+
+      if (e[0] == 'S' && e[1] == 'P')
+        c = '@';
+      else if (e[0] == 'B' && e[1] == 'P')
+        c = '*';
+      else if (e[0] == 'R' && e[1] == 'F')
+        c = '&';
+      else if (e[0] == 'L' && e[1] == 'T')
+        c = '<';
+      else if (e[0] == 'G' && e[1] == 'T')
+        c = '>';
+      else if (e[0] == 'L' && e[1] == 'P')
+        c = '(';
+      else if (e[0] == 'R' && e[1] == 'P')
+        c = ')';
+      else if (e[0] == 'u' && len > 3)
+        {
+          escape_len = 3;
+
+          hi_nibble = decode_lower_hex_nibble (e[1]);
+          if (hi_nibble < 0)
+            return 0;
+          lo_nibble = decode_lower_hex_nibble (e[2]);
+          if (lo_nibble < 0)
+            return 0;
+
+          /* Only allow non-control ASCII characters. */
+          if (hi_nibble > 7)
+            return 0;
+          c = (hi_nibble << 4) | lo_nibble;
+          if (c < 0x20)
+            return 0;
+        }
+    }
+
+  if (!c || len <= escape_len || e[escape_len] != '$')
+    return 0;
 
-  return count >= 5 && count <= 15;
+  *out_len = 2 + escape_len;
+  return c;
 }
 
+static void
+print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
+{
+  char unescaped;
+  uint8_t *out, *p, d;
+  size_t len, cap, punycode_pos, j;
+  /* Punycode parameters and state. */
+  uint32_t c;
+  size_t base, t_min, t_max, skew, damp, bias, i;
+  size_t delta, w, k, t;
+
+  if (rdm->errored || rdm->skipping_printing)
+    return;
+
+  if (rdm->version == -1)
+    {
+      /* Ignore leading underscores preceding escape sequences.
+         The mangler inserts an underscore to make sure the
+         identifier begins with a XID_Start character. */
+      if (ident.ascii_len >= 2 && ident.ascii[0] == '_'
+          && ident.ascii[1] == '$')
+        {
+          ident.ascii++;
+          ident.ascii_len--;
+        }
+
+      while (ident.ascii_len > 0)
+        {
+          /* Handle legacy escape sequences ("$...$", ".." or "."). */
+          if (ident.ascii[0] == '$')
+            {
+              unescaped
+                  = decode_legacy_escape (ident.ascii, ident.ascii_len, &len);
+              if (unescaped)
+                print_str (rdm, &unescaped, 1);
+              else
+                {
+                  /* Unexpected escape sequence, print the rest verbatim. */
+                  print_str (rdm, ident.ascii, ident.ascii_len);
+                  return;
+                }
+            }
+          else if (ident.ascii[0] == '.')
+            {
+              if (ident.ascii_len >= 2 && ident.ascii[1] == '.')
+                {
+                  /* ".." becomes "::" */
+                  PRINT ("::");
+                  len = 2;
+                }
+              else
+                {
+                  PRINT (".");
+                  len = 1;
+                }
+            }
+          else
+            {
+              /* Print everything before the next escape sequence, at once. */
+              for (len = 0; len < ident.ascii_len; len++)
+                if (ident.ascii[len] == '$' || ident.ascii[len] == '.')
+                  break;
+
+              print_str (rdm, ident.ascii, len);
+            }
+
+          ident.ascii += len;
+          ident.ascii_len -= len;
+        }
+
+      return;
+    }
+
+  if (!ident.punycode)
+    {
+      print_str (rdm, ident.ascii, ident.ascii_len);
+      return;
+    }
+
+  len = 0;
+  cap = 4;
+  while (cap < ident.ascii_len)
+    {
+      cap *= 2;
+      /* Check for overflows. */
+      if ((cap * 4) / 4 != cap)
+        {
+          rdm->errored = 1;
+          return;
+        }
+    }
+
+  /* Store the output codepoints as groups of 4 UTF-8 bytes. */
+  out = (uint8_t *)xmalloc (cap * 4);
+  if (!out)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  /* Populate initial output from ASCII fragment. */
+  for (len = 0; len < ident.ascii_len; len++)
+    {
+      p = out + 4 * len;
+      p[0] = 0;
+      p[1] = 0;
+      p[2] = 0;
+      p[3] = ident.ascii[len];
+    }
+
+  /* Punycode parameters and initial state. */
+  base = 36;
+  t_min = 1;
+  t_max = 26;
+  skew = 38;
+  damp = 700;
+  bias = 72;
+  i = 0;
+  c = 0x80;
+
+  punycode_pos = 0;
+  while (punycode_pos < ident.punycode_len)
+    {
+      /* Read one delta value. */
+      delta = 0;
+      w = 1;
+      k = 0;
+      do
+        {
+          k += base;
+          t = k < bias ? 0 : (k - bias);
+          if (t < t_min)
+            t = t_min;
+          if (t > t_max)
+            t = t_max;
+
+          if (punycode_pos >= ident.punycode_len)
+            goto cleanup;
+          d = ident.punycode[punycode_pos++];
+
+          if (ISLOWER (d))
+            d = d - 'a';
+          else if (ISDIGIT (d))
+            d = 26 + (d - '0');
+          else
+            {
+              rdm->errored = 1;
+              goto cleanup;
+            }
+
+          delta += d * w;
+          w *= base - t;
+        }
+      while (d >= t);
+
+      /* Compute the new insert position and character. */
+      len++;
+      i += delta;
+      c += i / len;
+      i %= len;
+
+      /* Ensure enough space is available. */
+      if (cap < len)
+        {
+          cap *= 2;
+          /* Check for overflows. */
+          if ((cap * 4) / 4 != cap || cap < len)
+            {
+              rdm->errored = 1;
+              goto cleanup;
+            }
+        }
+      p = (uint8_t *)xrealloc (out, cap * 4);
+      if (!p)
+        {
+          rdm->errored = 1;
+          goto cleanup;
+        }
+      out = p;
+
+      /* Move the characters after the insert position. */
+      p = out + i * 4;
+      memmove (p + 4, p, (len - i - 1) * 4);
+
+      /* Insert the new character, as UTF-8 bytes. */
+      p[0] = c >= 0x10000 ? 0xf0 | (c >> 18) : 0;
+      p[1] = c >= 0x800 ? (c < 0x10000 ? 0xe0 : 0x80) | ((c >> 12) & 0x3f) : 0;
+      p[2] = (c < 0x800 ? 0xc0 : 0x80) | ((c >> 6) & 0x3f);
+      p[3] = 0x80 | (c & 0x3f);
+
+      /* If there are no more deltas, decoding is complete. */
+      if (punycode_pos == ident.punycode_len)
+        break;
+
+      i++;
+
+      /* Perform bias adaptation. */
+      delta /= damp;
+      damp = 2;
+
+      delta += delta / len;
+      k = 0;
+      while (delta > ((base - t_min) * t_max) / 2)
+        {
+          delta /= base - t_min;
+          k += base;
+        }
+      bias = k + ((base - t_min + 1) * delta) / (delta + skew);
+    }
+
+  /* Remove all the 0 bytes to leave behind an UTF-8 string. */
+  for (i = 0, j = 0; i < len * 4; i++)
+    if (out[i] != 0)
+      out[j++] = out[i];
+
+  print_str (rdm, (const char *)out, j);
+
+cleanup:
+  free (out);
+}
+
+/* Print the lifetime according to the previously decoded index.
+   An index of `0` always refers to `'_`, but starting with `1`,
+   indices refer to late-bound lifetimes introduced by a binder. */
+static void
+print_lifetime_from_index (struct rust_demangler *rdm, uint64_t lt)
+{
+  char c;
+  uint64_t depth;
+
+  PRINT ("'");
+  if (lt == 0)
+    {
+      PRINT ("_");
+      return;
+    }
+
+  depth = rdm->bound_lifetime_depth - lt;
+  /* Try to print lifetimes alphabetically first. */
+  if (depth < 26)
+    {
+      c = 'a' + depth;
+      print_str (rdm, &c, 1);
+    }
+  else
+    {
+      /* Use `'_123` after running out of letters. */
+      PRINT ("_");
+      print_uint64 (rdm, depth);
+    }
+}
+
+/* Demangling functions. */
+
+static void demangle_binder (struct rust_demangler *rdm);
+static void demangle_path (struct rust_demangler *rdm, int in_value);
+static void demangle_generic_arg (struct rust_demangler *rdm);
+static void demangle_type (struct rust_demangler *rdm);
+static int demangle_path_maybe_open_generics (struct rust_demangler *rdm);
+static void demangle_dyn_trait (struct rust_demangler *rdm);
+static void demangle_const (struct rust_demangler *rdm);
+static void demangle_const_uint (struct rust_demangler *rdm);
+static void demangle_const_int (struct rust_demangler *rdm);
+static void demangle_const_bool (struct rust_demangler *rdm);
+static void demangle_const_char (struct rust_demangler *rdm);
+
+/* Optionally enter a binder ('G') for late-bound lifetimes,
+   printing e.g. `for<'a, 'b> `, and make those lifetimes visible
+   to the caller (via depth level, which the caller should reset). */
+static void
+demangle_binder (struct rust_demangler *rdm)
+{
+  uint64_t i, bound_lifetimes;
+
+  if (rdm->errored)
+    return;
+
+  bound_lifetimes = parse_opt_integer_62 (rdm, 'G');
+  if (bound_lifetimes > 0)
+    {
+      PRINT ("for<");
+      for (i = 0; i < bound_lifetimes; i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          rdm->bound_lifetime_depth++;
+          print_lifetime_from_index (rdm, 1);
+        }
+      PRINT ("> ");
+    }
+}
+
+static void
+demangle_path (struct rust_demangler *rdm, int in_value)
+{
+  char tag, ns;
+  int was_skipping_printing;
+  size_t i, backref, old_next;
+  uint64_t dis;
+  struct rust_mangled_ident name;
+
+  if (rdm->errored)
+    return;
+
+  switch (tag = next (rdm))
+    {
+    case 'C':
+      dis = parse_disambiguator (rdm);
+      name = parse_ident (rdm);
+
+      print_ident (rdm, name);
+      if (rdm->verbose)
+        {
+          PRINT ("[");
+          print_uint64_hex (rdm, dis);
+          PRINT ("]");
+        }
+      break;
+    case 'N':
+      ns = next (rdm);
+      if (!ISLOWER (ns) && !ISUPPER (ns))
+        {
+          rdm->errored = 1;
+          return;
+        }
+
+      demangle_path (rdm, in_value);
+
+      dis = parse_disambiguator (rdm);
+      name = parse_ident (rdm);
+
+      if (ISUPPER (ns))
+        {
+          /* Special namespaces, like closures and shims. */
+          PRINT ("::{");
+          switch (ns)
+            {
+            case 'C':
+              PRINT ("closure");
+              break;
+            case 'S':
+              PRINT ("shim");
+              break;
+            default:
+              print_str (rdm, &ns, 1);
+            }
+          if (name.ascii || name.punycode)
+            {
+              PRINT (":");
+              print_ident (rdm, name);
+            }
+          PRINT ("#");
+          print_uint64 (rdm, dis);
+          PRINT ("}");
+        }
+      else
+        {
+          /* Implementation-specific/unspecified namespaces. */
+
+          if (name.ascii || name.punycode)
+            {
+              PRINT ("::");
+              print_ident (rdm, name);
+            }
+        }
+      break;
+    case 'M':
+    case 'X':
+      /* Ignore the `impl`'s own path.*/
+      parse_disambiguator (rdm);
+      was_skipping_printing = rdm->skipping_printing;
+      rdm->skipping_printing = 1;
+      demangle_path (rdm, in_value);
+      rdm->skipping_printing = was_skipping_printing;
+      /* fallthrough */
+    case 'Y':
+      PRINT ("<");
+      demangle_type (rdm);
+      if (tag != 'M')
+        {
+          PRINT (" as ");
+          demangle_path (rdm, 0);
+        }
+      PRINT (">");
+      break;
+    case 'I':
+      demangle_path (rdm, in_value);
+      if (in_value)
+        PRINT ("::");
+      PRINT ("<");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_generic_arg (rdm);
+        }
+      PRINT (">");
+      break;
+    case 'B':
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_path (rdm, in_value);
+          rdm->next = old_next;
+        }
+      break;
+    default:
+      rdm->errored = 1;
+      return;
+    }
+}
+
+static void
+demangle_generic_arg (struct rust_demangler *rdm)
+{
+  uint64_t lt;
+  if (eat (rdm, 'L'))
+    {
+      lt = parse_integer_62 (rdm);
+      print_lifetime_from_index (rdm, lt);
+    }
+  else if (eat (rdm, 'K'))
+    demangle_const (rdm);
+  else
+    demangle_type (rdm);
+}
+
+static const char *
+basic_type (char tag)
+{
+  switch (tag)
+    {
+    case 'b':
+      return "bool";
+    case 'c':
+      return "char";
+    case 'e':
+      return "str";
+    case 'u':
+      return "()";
+    case 'a':
+      return "i8";
+    case 's':
+      return "i16";
+    case 'l':
+      return "i32";
+    case 'x':
+      return "i64";
+    case 'n':
+      return "i128";
+    case 'i':
+      return "isize";
+    case 'h':
+      return "u8";
+    case 't':
+      return "u16";
+    case 'm':
+      return "u32";
+    case 'y':
+      return "u64";
+    case 'o':
+      return "u128";
+    case 'j':
+      return "usize";
+    case 'f':
+      return "f32";
+    case 'd':
+      return "f64";
+    case 'z':
+      return "!";
+    case 'p':
+      return "_";
+    case 'v':
+      return "...";
+
+    default:
+      return NULL;
+    }
+}
+
+static void
+demangle_type (struct rust_demangler *rdm)
+{
+  char tag;
+  size_t i, old_next, backref;
+  uint64_t lt, old_bound_lifetime_depth;
+  const char *basic;
+  struct rust_mangled_ident abi;
+
+  if (rdm->errored)
+    return;
+
+  tag = next (rdm);
+
+  basic = basic_type (tag);
+  if (basic)
+    {
+      PRINT (basic);
+      return;
+    }
+
+  switch (tag)
+    {
+    case 'R':
+    case 'Q':
+      PRINT ("&");
+      if (eat (rdm, 'L'))
+        {
+          lt = parse_integer_62 (rdm);
+          if (lt)
+            {
+              print_lifetime_from_index (rdm, lt);
+              PRINT (" ");
+            }
+        }
+      if (tag != 'R')
+        PRINT ("mut ");
+      demangle_type (rdm);
+      break;
+    case 'P':
+    case 'O':
+      PRINT ("*");
+      if (tag != 'P')
+        PRINT ("mut ");
+      else
+        PRINT ("const ");
+      demangle_type (rdm);
+      break;
+    case 'A':
+    case 'S':
+      PRINT ("[");
+      demangle_type (rdm);
+      if (tag == 'A')
+        {
+          PRINT ("; ");
+          demangle_const (rdm);
+        }
+      PRINT ("]");
+      break;
+    case 'T':
+      PRINT ("(");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_type (rdm);
+        }
+      if (i == 1)
+        PRINT (",");
+      PRINT (")");
+      break;
+    case 'F':
+      old_bound_lifetime_depth = rdm->bound_lifetime_depth;
+      demangle_binder (rdm);
+
+      if (eat (rdm, 'U'))
+        PRINT ("unsafe ");
+
+      if (eat (rdm, 'K'))
+        {
+          if (eat (rdm, 'C'))
+            {
+              abi.ascii = "C";
+              abi.ascii_len = 1;
+            }
+          else
+            {
+              abi = parse_ident (rdm);
+              if (!abi.ascii || abi.punycode)
+                {
+                  rdm->errored = 1;
+                  goto restore;
+                }
+            }
+
+          PRINT ("extern \"");
+
+          /* If the ABI had any `-`, they were replaced with `_`,
+             so the parts between `_` have to be re-joined with `-`. */
+          for (i = 0; i < abi.ascii_len; i++)
+            {
+              if (abi.ascii[i] == '_')
+                {
+                  print_str (rdm, abi.ascii, i);
+                  PRINT ("-");
+                  abi.ascii += i + 1;
+                  abi.ascii_len -= i + 1;
+                  i = 0;
+                }
+            }
+          print_str (rdm, abi.ascii, abi.ascii_len);
+
+          PRINT ("\" ");
+        }
+
+      PRINT ("fn(");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_type (rdm);
+        }
+      PRINT (")");
+
+      if (eat (rdm, 'u'))
+        {
+          /* Skip printing the return type if it's 'u', i.e. `()`. */
+        }
+      else
+        {
+          PRINT (" -> ");
+          demangle_type (rdm);
+        }
+
+    /* Restore `bound_lifetime_depth` to outside the binder. */
+    restore:
+      rdm->bound_lifetime_depth = old_bound_lifetime_depth;
+      break;
+    case 'D':
+      PRINT ("dyn ");
+
+      old_bound_lifetime_depth = rdm->bound_lifetime_depth;
+      demangle_binder (rdm);
+
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (" + ");
+          demangle_dyn_trait (rdm);
+        }
+
+      /* Restore `bound_lifetime_depth` to outside the binder. */
+      rdm->bound_lifetime_depth = old_bound_lifetime_depth;
+
+      if (!eat (rdm, 'L'))
+        {
+          rdm->errored = 1;
+          return;
+        }
+      lt = parse_integer_62 (rdm);
+      if (lt)
+        {
+          PRINT (" + ");
+          print_lifetime_from_index (rdm, lt);
+        }
+      break;
+    case 'B':
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_type (rdm);
+          rdm->next = old_next;
+        }
+      break;
+    default:
+      /* Go back to the tag, so `demangle_path` also sees it. */
+      rdm->next--;
+      demangle_path (rdm, 0);
+    }
+}
+
+/* A trait in a trait object may have some "existential projections"
+   (i.e. associated type bindings) after it, which should be printed
+   in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
+   To this end, this method will keep the `<...>` of an 'I' path
+   open, by omitting the `>`, and return `Ok(true)` in that case. */
 static int
-looks_like_rust (const char *str, size_t len)
-{
-  const char *end = str + len;
-
-  while (str < end)
-    switch (*str)
-      {
-      case '$':
-       if (!strncmp (str, "$C$", 3))
-         str += 3;
-       else if (!strncmp (str, "$SP$", 4)
-                || !strncmp (str, "$BP$", 4)
-                || !strncmp (str, "$RF$", 4)
-                || !strncmp (str, "$LT$", 4)
-                || !strncmp (str, "$GT$", 4)
-                || !strncmp (str, "$LP$", 4)
-                || !strncmp (str, "$RP$", 4))
-         str += 4;
-       else if (!strncmp (str, "$u20$", 5)
-                || !strncmp (str, "$u22$", 5)
-                || !strncmp (str, "$u27$", 5)
-                || !strncmp (str, "$u2b$", 5)
-                || !strncmp (str, "$u3b$", 5)
-                || !strncmp (str, "$u5b$", 5)
-                || !strncmp (str, "$u5d$", 5)
-                || !strncmp (str, "$u7b$", 5)
-                || !strncmp (str, "$u7d$", 5)
-                || !strncmp (str, "$u7e$", 5))
-         str += 5;
-       else
-         return 0;
-       break;
-      case '.':
-       /* Do not allow three or more consecutive dots */
-       if (!strncmp (str, "...", 3))
-         return 0;
-       /* Fall through */
-      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-      case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
-      case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
-      case 's': case 't': case 'u': case 'v': case 'w': case 'x':
-      case 'y': case 'z':
-      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-      case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
-      case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
-      case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
-      case 'Y': case 'Z':
-      case '0': case '1': case '2': case '3': case '4': case '5':
-      case '6': case '7': case '8': case '9':
-      case '_':
-      case ':':
-       str++;
-       break;
-      default:
-       return 0;
-      }
-
-  return 1;
-}
-
-/*
-  INPUT: sym: symbol for which rust_is_mangled(sym) returned 1.
-
-  The input is demangled in-place because the mangled name is always
-  longer than the demangled one.  */
-
-void
-rust_demangle_sym (char *sym)
-{
-  const char *in;
-  char *out;
-  const char *end;
-
-  if (!sym)
+demangle_path_maybe_open_generics (struct rust_demangler *rdm)
+{
+  int open;
+  size_t i, old_next, backref;
+
+  open = 0;
+
+  if (rdm->errored)
+    return open;
+
+  if (eat (rdm, 'B'))
+    {
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          open = demangle_path_maybe_open_generics (rdm);
+          rdm->next = old_next;
+        }
+    }
+  else if (eat (rdm, 'I'))
+    {
+      demangle_path (rdm, 0);
+      PRINT ("<");
+      open = 1;
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_generic_arg (rdm);
+        }
+    }
+  else
+    demangle_path (rdm, 0);
+  return open;
+}
+
+static void
+demangle_dyn_trait (struct rust_demangler *rdm)
+{
+  int open;
+  struct rust_mangled_ident name;
+
+  if (rdm->errored)
     return;
 
-  in = sym;
-  out = sym;
-  end = sym + strlen (sym) - (hash_prefix_len + hash_len);
-
-  while (in < end)
-    switch (*in)
-      {
-      case '$':
-       if (!(unescape (&in, &out, "$C$", ',')
-             || unescape (&in, &out, "$SP$", '@')
-             || unescape (&in, &out, "$BP$", '*')
-             || unescape (&in, &out, "$RF$", '&')
-             || unescape (&in, &out, "$LT$", '<')
-             || unescape (&in, &out, "$GT$", '>')
-             || unescape (&in, &out, "$LP$", '(')
-             || unescape (&in, &out, "$RP$", ')')
-             || unescape (&in, &out, "$u20$", ' ')
-             || unescape (&in, &out, "$u22$", '\"')
-             || unescape (&in, &out, "$u27$", '\'')
-             || unescape (&in, &out, "$u2b$", '+')
-             || unescape (&in, &out, "$u3b$", ';')
-             || unescape (&in, &out, "$u5b$", '[')
-             || unescape (&in, &out, "$u5d$", ']')
-             || unescape (&in, &out, "$u7b$", '{')
-             || unescape (&in, &out, "$u7d$", '}')
-             || unescape (&in, &out, "$u7e$", '~'))) {
-         /* unexpected escape sequence, not looks_like_rust. */
-         goto fail;
-       }
-       break;
-      case '_':
-       /* If this is the start of a path component and the next
-          character is an escape sequence, ignore the underscore. The
-          mangler inserts an underscore to make sure the path
-          component begins with a XID_Start character. */
-       if ((in == sym || in[-1] == ':') && in[1] == '$')
-         in++;
-       else
-         *out++ = *in++;
-       break;
-      case '.':
-       if (in[1] == '.')
-         {
-           /* ".." becomes "::" */
-           *out++ = ':';
-           *out++ = ':';
-           in += 2;
-         }
-       else
-         {
-           /* "." becomes "-" */
-           *out++ = '-';
-           in++;
-         }
-       break;
-      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-      case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
-      case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
-      case 's': case 't': case 'u': case 'v': case 'w': case 'x':
-      case 'y': case 'z':
-      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-      case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
-      case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
-      case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
-      case 'Y': case 'Z':
-      case '0': case '1': case '2': case '3': case '4': case '5':
-      case '6': case '7': case '8': case '9':
-      case ':':
-       *out++ = *in++;
-       break;
-      default:
-       /* unexpected character in symbol, not looks_like_rust.  */
-       goto fail;
-      }
-  goto done;
-
-fail:
-  *out++ = '?'; /* This is pretty lame, but it's hard to do better. */
-done:
-  *out = '\0';
+  open = demangle_path_maybe_open_generics (rdm);
+
+  while (eat (rdm, 'p'))
+    {
+      if (!open)
+        PRINT ("<");
+      else
+        PRINT (", ");
+      open = 1;
+
+      name = parse_ident (rdm);
+      print_ident (rdm, name);
+      PRINT (" = ");
+      demangle_type (rdm);
+    }
+
+  if (open)
+    PRINT (">");
 }
 
+static void
+demangle_const (struct rust_demangler *rdm)
+{
+  char ty_tag;
+  size_t old_next, backref;
+
+  if (rdm->errored)
+    return;
+
+  if (eat (rdm, 'B'))
+    {
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_const (rdm);
+          rdm->next = old_next;
+        }
+      return;
+    }
+
+  ty_tag = next (rdm);
+  switch (ty_tag)
+    {
+    /* Placeholder. */
+    case 'p':
+      PRINT ("_");
+      return;
+
+    /* Unsigned integer types. */
+    case 'h':
+    case 't':
+    case 'm':
+    case 'y':
+    case 'o':
+    case 'j':
+      demangle_const_uint (rdm);
+      break;
+
+    /* Signed integer types. */
+    case 'a':
+    case 's':
+    case 'l':
+    case 'x':
+    case 'n':
+    case 'i':
+      demangle_const_int (rdm);
+      break;
+
+    /* Boolean. */
+    case 'b':
+      demangle_const_bool (rdm);
+      break;
+
+    /* Character. */
+    case 'c':
+      demangle_const_char (rdm);
+      break;
+
+    default:
+      rdm->errored = 1;
+      return;
+    }
+
+  if (rdm->errored)
+    return;
+
+  if (rdm->verbose)
+    {
+      PRINT (": ");
+      PRINT (basic_type (ty_tag));
+    }
+}
+
+static void
+demangle_const_uint (struct rust_demangler *rdm)
+{
+  size_t hex_len;
+  uint64_t value;
+
+  if (rdm->errored)
+    return;
+
+  hex_len = parse_hex_nibbles (rdm, &value);
+
+  if (hex_len > 16)
+    {
+      /* Print anything that doesn't fit in `uint64_t` verbatim. */
+      PRINT ("0x");
+      print_str (rdm, rdm->sym + (rdm->next - hex_len), hex_len);
+    }
+  else if (hex_len > 0)
+    print_uint64 (rdm, value);
+  else
+    rdm->errored = 1;
+}
+
+static void
+demangle_const_int (struct rust_demangler *rdm)
+{
+  if (eat (rdm, 'n'))
+    PRINT ("-");
+  demangle_const_uint (rdm);
+}
+
+static void
+demangle_const_bool (struct rust_demangler *rdm)
+{
+  uint64_t value;
+
+  if (parse_hex_nibbles (rdm, &value) != 1)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  if (value == 0)
+    PRINT ("false");
+  else if (value == 1)
+    PRINT ("true");
+  else
+    rdm->errored = 1;
+}
+
+static void
+demangle_const_char (struct rust_demangler *rdm)
+{
+  size_t hex_len;
+  uint64_t value;
+
+  hex_len = parse_hex_nibbles (rdm, &value);
+
+  if (hex_len == 0 || hex_len > 8)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  /* Match Rust's character "debug" output as best as we can. */
+  PRINT ("'");
+  if (value == '\t')
+    PRINT ("\\t");
+  else if (value == '\r')
+    PRINT ("\\r");
+  else if (value == '\n')
+    PRINT ("\\n");
+  else if (value > ' ' && value < '~')
+    /* Rust also considers many non-ASCII codepoints to be printable, but
+       that logic is not easily ported to C. */
+    print_str (rdm, (char *) &value, 1);
+  else
+    {
+      PRINT ("\\u{");
+      print_uint64_hex (rdm, value);
+      PRINT ("}");
+    }
+  PRINT ("'");
+}
+
+/* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
+   The hex digits must contain at least 5 distinct digits. */
 static int
-unescape (const char **in, char **out, const char *seq, char value)
+is_legacy_prefixed_hash (struct rust_mangled_ident ident)
+{
+  uint16_t seen;
+  int nibble;
+  size_t i, count;
+
+  if (ident.ascii_len != 17 || ident.ascii[0] != 'h')
+    return 0;
+
+  seen = 0;
+  for (i = 0; i < 16; i++)
+    {
+      nibble = decode_lower_hex_nibble (ident.ascii[1 + i]);
+      if (nibble < 0)
+        return 0;
+      seen |= (uint16_t)1 << nibble;
+    }
+
+  /* Count how many distinct digits were seen. */
+  count = 0;
+  while (seen)
+    {
+      if (seen & 1)
+        count++;
+      seen >>= 1;
+    }
+
+  return count >= 5;
+}
+
+int
+rust_demangle_callback (const char *mangled, int options,
+                        demangle_callbackref callback, void *opaque)
 {
-  size_t len = strlen (seq);
+  const char *p;
+  struct rust_demangler rdm;
+  struct rust_mangled_ident ident;
+
+  rdm.sym = mangled;
+  rdm.sym_len = 0;
+
+  rdm.callback_opaque = opaque;
+  rdm.callback = callback;
+
+  rdm.next = 0;
+  rdm.errored = 0;
+  rdm.skipping_printing = 0;
+  rdm.verbose = (options & DMGL_VERBOSE) != 0;
+  rdm.version = 0;
+  rdm.bound_lifetime_depth = 0;
 
-  if (strncmp (*in, seq, len))
+  /* Rust symbols always start with _R (v0) or _ZN (legacy). */
+  if (rdm.sym[0] == '_' && rdm.sym[1] == 'R')
+    rdm.sym += 2;
+  else if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N')
+    {
+      rdm.sym += 3;
+      rdm.version = -1;
+    }
+  else
     return 0;
 
-  **out = value;
+  /* Paths (v0) always start with uppercase characters. */
+  if (rdm.version != -1 && !ISUPPER (rdm.sym[0]))
+    return 0;
+
+  /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
+  for (p = rdm.sym; *p; p++)
+    {
+      rdm.sym_len++;
+
+      if (*p == '_' || ISALNUM (*p))
+        continue;
+
+      /* Legacy Rust symbols can also contain [.:$] characters. */
+      if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':'))
+        continue;
+
+      return 0;
+    }
+
+  /* Legacy Rust symbols need to be handled separately. */
+  if (rdm.version == -1)
+    {
+      /* Legacy Rust symbols always end with E. */
+      if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E'))
+        return 0;
+      rdm.sym_len--;
+
+      /* Legacy Rust symbols also always end with a path segment
+         that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
+         This early check, before any parse_ident calls, should
+         quickly filter out most C++ symbols unrelated to Rust. */
+      if (!(rdm.sym_len > 19
+            && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3)))
+        return 0;
+
+      do
+        {
+          ident = parse_ident (&rdm);
+          if (rdm.errored || !ident.ascii)
+            return 0;
+        }
+      while (rdm.next < rdm.sym_len);
+
+      /* The last path segment should be the hash. */
+      if (!is_legacy_prefixed_hash (ident))
+        return 0;
+
+      /* Reset the state for a second pass, to print the symbol. */
+      rdm.next = 0;
+      if (!rdm.verbose && rdm.sym_len > 19)
+        {
+          /* Hide the last segment, containing the hash, if not verbose. */
+          rdm.sym_len -= 19;
+        }
+
+      do
+        {
+          if (rdm.next > 0)
+            print_str (&rdm, "::", 2);
+
+          ident = parse_ident (&rdm);
+          print_ident (&rdm, ident);
+        }
+      while (rdm.next < rdm.sym_len);
+    }
+  else
+    {
+      demangle_path (&rdm, 1);
+
+      /* Skip instantiating crate. */
+      if (!rdm.errored && rdm.next < rdm.sym_len)
+        {
+          rdm.skipping_printing = 1;
+          demangle_path (&rdm, 0);
+        }
+
+      /* It's an error to not reach the end. */
+      rdm.errored |= rdm.next != rdm.sym_len;
+    }
+
+  return !rdm.errored;
+}
+
+/* Growable string buffers. */
+struct str_buf
+{
+  char *ptr;
+  size_t len;
+  size_t cap;
+  int errored;
+};
+
+static void
+str_buf_reserve (struct str_buf *buf, size_t extra)
+{
+  size_t available, min_new_cap, new_cap;
+  char *new_ptr;
+
+  /* Allocation failed before. */
+  if (buf->errored)
+    return;
+
+  available = buf->cap - buf->len;
+
+  if (extra <= available)
+    return;
+
+  min_new_cap = buf->cap + (extra - available);
+
+  /* Check for overflows. */
+  if (min_new_cap < buf->cap)
+    {
+      buf->errored = 1;
+      return;
+    }
+
+  new_cap = buf->cap;
+
+  if (new_cap == 0)
+    new_cap = 4;
+
+  /* Double capacity until sufficiently large. */
+  while (new_cap < min_new_cap)
+    {
+      new_cap *= 2;
+
+      /* Check for overflows. */
+      if (new_cap < buf->cap)
+        {
+          buf->errored = 1;
+          return;
+        }
+    }
+
+  new_ptr = (char *)xrealloc (buf->ptr, new_cap);
+  if (new_ptr == NULL)
+    {
+      free (buf->ptr);
+      buf->ptr = NULL;
+      buf->len = 0;
+      buf->cap = 0;
+      buf->errored = 1;
+    }
+  else
+    {
+      buf->ptr = new_ptr;
+      buf->cap = new_cap;
+    }
+}
+
+static void
+str_buf_append (struct str_buf *buf, const char *data, size_t len)
+{
+  str_buf_reserve (buf, len);
+  if (buf->errored)
+    return;
+
+  memcpy (buf->ptr + buf->len, data, len);
+  buf->len += len;
+}
+
+static void
+str_buf_demangle_callback (const char *data, size_t len, void *opaque)
+{
+  str_buf_append ((struct str_buf *)opaque, data, len);
+}
+
+char *
+rust_demangle (const char *mangled, int options)
+{
+  struct str_buf out;
+  int success;
+
+  out.ptr = NULL;
+  out.len = 0;
+  out.cap = 0;
+  out.errored = 0;
+
+  success = rust_demangle_callback (mangled, options,
+                                    str_buf_demangle_callback, &out);
 
-  *in += len;
-  *out += 1;
+  if (!success)
+    {
+      free (out.ptr);
+      return NULL;
+    }
 
-  return 1;
+  str_buf_append (&out, "\0", 1);
+  return out.ptr;
 }
index d3247eddb86911c46a50c0a45f3f2fed9b8b5e46..14da119183cbe5fd9962d61a1fd1329cd6217f25 100644 (file)
@@ -1,6 +1,6 @@
 /* <ctype.h> replacement macros.
 
-   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   Copyright (C) 2000-2021 Free Software Foundation, Inc.
    Contributed by Zack Weinberg <zackw@stanford.edu>.
 
 This file is part of the libiberty library.
index 66c8fe9d3e5ee5b3cafee85990f7a23f50b52925..a7389c32e040148a18413d05d962b9b505da0046 100644 (file)
@@ -1,6 +1,6 @@
 /* <ctype.h> replacement macros.
 
-   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   Copyright (C) 2000-2021 Free Software Foundation, Inc.
    Contributed by Zack Weinberg <zackw@stanford.edu>.
 
 This file is part of the libiberty library.
index 79b5c8ce090feb4c64d3ece9bd3355be58bf71a6..d64d5a70c1ab6bc02e5a6a7393edb02c3fd2a542 100644 (file)
 #define free(_pt)            VG_(arena_free)   (VG_AR_DEMANGLE,(_pt))
 #define memcmp(_s1,_s2,_sz)  VG_(memcmp)((_s1),(_s2),(_sz))
 #define memcpy(_dd,_ss,_sz)  VG_(memcpy)((_dd),(_ss),(_sz))
+#define memmove(_dd,_ss,_sz) VG_(memmove)((_dd),(_ss),(_sz))
 #define memset(_ss,_cc,_sz)  VG_(memset)((_ss),(_cc),(_sz))
 #define realloc(_cc,_pt,_sz) VG_(arena_realloc)(VG_AR_DEMANGLE,(_cc),(_pt),(_sz))
-#define sprintf(_buf,_fmt,_args...)  VG_(sprintf)((_buf),(_fmt),(_args))
+#define sprintf(_buf,_fmt,_args...) VG_(sprintf)((_buf),(_fmt),(_args))
+#define snprintf(_buf,_size,_fmt,_args...) VG_(snprintf)((_buf),(_size),(_fmt),(_args))
 #define strcat(_dd,_ss)      VG_(strcat)((_dd),(_ss))
 #define strchr(_ss,_cc)      VG_(strchr)((_ss),(_cc))
 #define strcmp(_s1,_s2)      VG_(strcmp)((_s1),(_s2))
index 6148729cddbbd2eee5564d4f67cc0071a201548d..775fac002bf3e1a6333217b46be76acd06bbc2d9 100644 (file)
@@ -37,7 +37,7 @@
     <frame>
       <ip>0x........</ip>
       <obj>...</obj>
-      <fn>abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz::ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ::f()</fn>
+      <fn>_ZN5304abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz5304ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ1fEv</fn>
       <dir>...</dir>
       <file>long_namespace_xml.cpp</file>
       <line>...</line>
@@ -64,7 +64,7 @@
     <frame>
       <ip>0x........</ip>
       <obj>...</obj>
-      <fn>abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz::ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ::f()</fn>
+      <fn>_ZN5304abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz5304ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ1fEv</fn>
       <dir>...</dir>
       <file>long_namespace_xml.cpp</file>
       <line>...</line>