From: Amanieu d'Antras Date: Sun, 26 Sep 2021 10:42:26 +0000 (+0200) Subject: Update libiberty demangler to support Rust v0 name mangling X-Git-Tag: VALGRIND_3_18_0~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c2e0ab8694f44b18a90ca9139506ffaf55d05a52;p=thirdparty%2Fvalgrind.git Update libiberty demangler to support Rust v0 name mangling 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. --- diff --git a/NEWS b/NEWS index 630fc574cb..3e570c7de6 100644 --- 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 diff --git a/auxprogs/update-demangler b/auxprogs/update-demangler index 2a788b8bec..947fa5e314 100755 --- a/auxprogs/update-demangler +++ b/auxprogs/update-demangler @@ -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 diff --git a/coregrind/m_demangle/ansidecl.h b/coregrind/m_demangle/ansidecl.h index 3822be0cbd..8e5de9bf5a 100644 --- a/coregrind/m_demangle/ansidecl.h +++ b/coregrind/m_demangle/ansidecl.h @@ -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 diff --git a/coregrind/m_demangle/cp-demangle.c b/coregrind/m_demangle/cp-demangle.c index 4a3fa5d167..11382a23ca 100644 --- a/coregrind/m_demangle/cp-demangle.c +++ b/coregrind/m_demangle/cp-demangle.c @@ -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 . 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 . @@ -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; } /* ::= B */ @@ -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) unqualified-name> ::= ::= -*/ + + 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 ::= TI ::= TS + ::= TA ::= GV <(object) name> ::= T <(base) encoding> ::= Tc <(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')); } +/* ::= [gs] # x or (with "gs") ::x + ::= sr # T::x / decltype(p)::x + # T::N::x /decltype(p)::N::x + ::= srN + E + # A::x, N::y, A::z; "gs" means leading "::" + ::= [gs] sr + E + + "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 ; 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); +} + /* ::= <(unary) operator-name> ::= <(binary) operator-name> ::= <(trinary) operator-name> ::= cl + E ::= st ::= - ::= sr - ::= sr + ::= ::= + + ::= + ::= di # .name = expr + ::= dx # [expr] = expr + ::= dX + # [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); } /* ::= _ # 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 diff --git a/coregrind/m_demangle/cp-demangle.h b/coregrind/m_demangle/cp-demangle.h index a2657755f1..cb47bdf0d2 100644 --- a/coregrind/m_demangle/cp-demangle.h +++ b/coregrind/m_demangle/cp-demangle.h @@ -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 . 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 diff --git a/coregrind/m_demangle/cplus-dem.c b/coregrind/m_demangle/cplus-dem.c index cf16f381dc..bf43790544 100644 --- a/coregrind/m_demangle/cplus-dem.c +++ b/coregrind/m_demangle/cplus-dem.c @@ -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 #include -#include #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 -#endif -#endif /* ! in valgrind */ -#ifndef INT_MAX -# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */ -#endif - #if 0 /* in valgrind */ #include #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_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", "*", 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) 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 = ¶m; - 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 __ - 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 "__" */ - (*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" - 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" */ - 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 - "." 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 > - registers map > as B0, and temp 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); -} diff --git a/coregrind/m_demangle/d-demangle.c b/coregrind/m_demangle/d-demangle.c index f9a7f1df8d..1f2fbbe43f 100644 --- a/coregrind/m_demangle/d-demangle.c +++ b/coregrind/m_demangle/d-demangle.c @@ -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 . */ -/* 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 +#endif #endif /* ! in valgrind */ #if 0 /* in valgrind */ @@ -49,8 +50,6 @@ If not, see . */ #if 0 /* in valgrind */ #ifdef HAVE_STDLIB_H #include -#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); } diff --git a/coregrind/m_demangle/demangle.c b/coregrind/m_demangle/demangle.c index 29afa8973a..16161da2af 100644 --- a/coregrind/m_demangle/demangle.c +++ b/coregrind/m_demangle/demangle.c @@ -47,16 +47,11 @@ /*------------------------------------------------------------*/ /* 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 @@ -76,19 +70,8 @@ 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; } diff --git a/coregrind/m_demangle/demangle.h b/coregrind/m_demangle/demangle.h index f5a214362d..bcccf45d0c 100644 --- a/coregrind/m_demangle/demangle.h +++ b/coregrind/m_demangle/demangle.h @@ -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 { diff --git a/coregrind/m_demangle/dyn-string.c b/coregrind/m_demangle/dyn-string.c index 9beba6e468..8b688a24ad 100644 --- a/coregrind/m_demangle/dyn-string.c +++ b/coregrind/m_demangle/dyn-string.c @@ -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. diff --git a/coregrind/m_demangle/dyn-string.h b/coregrind/m_demangle/dyn-string.h index 6c0accc724..6c5e66012d 100644 --- a/coregrind/m_demangle/dyn-string.h +++ b/coregrind/m_demangle/dyn-string.h @@ -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. diff --git a/coregrind/m_demangle/rust-demangle.c b/coregrind/m_demangle/rust-demangle.c index 3bfde6d750..9ad424e85c 100644 --- a/coregrind/m_demangle/rust-demangle.c +++ b/coregrind/m_demangle/rust-demangle.c @@ -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 . */ #endif /* ! in valgrind */ #if 0 /* in valgrind */ +#include #include #include #include +#include #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: - ::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`. + 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; } diff --git a/coregrind/m_demangle/safe-ctype.c b/coregrind/m_demangle/safe-ctype.c index d3247eddb8..14da119183 100644 --- a/coregrind/m_demangle/safe-ctype.c +++ b/coregrind/m_demangle/safe-ctype.c @@ -1,6 +1,6 @@ /* replacement macros. - Copyright (C) 2000-2017 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. Contributed by Zack Weinberg . This file is part of the libiberty library. diff --git a/coregrind/m_demangle/safe-ctype.h b/coregrind/m_demangle/safe-ctype.h index 66c8fe9d3e..a7389c32e0 100644 --- a/coregrind/m_demangle/safe-ctype.h +++ b/coregrind/m_demangle/safe-ctype.h @@ -1,6 +1,6 @@ /* replacement macros. - Copyright (C) 2000-2017 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. Contributed by Zack Weinberg . This file is part of the libiberty library. diff --git a/coregrind/m_demangle/vg_libciface.h b/coregrind/m_demangle/vg_libciface.h index 79b5c8ce09..d64d5a70c1 100644 --- a/coregrind/m_demangle/vg_libciface.h +++ b/coregrind/m_demangle/vg_libciface.h @@ -47,9 +47,11 @@ #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)) diff --git a/memcheck/tests/long_namespace_xml.stderr.exp b/memcheck/tests/long_namespace_xml.stderr.exp index 6148729cdd..775fac002b 100644 --- a/memcheck/tests/long_namespace_xml.stderr.exp +++ b/memcheck/tests/long_namespace_xml.stderr.exp @@ -37,7 +37,7 @@ 0x........ ... - abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz::ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ::f() + _ZN5304abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz5304ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ1fEv ... long_namespace_xml.cpp ... @@ -64,7 +64,7 @@ 0x........ ... - abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz::ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ::f() + _ZN5304abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz5304ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ1fEv ... long_namespace_xml.cpp ...