diff --git a/GPL/DemanglerGnu/build.gradle b/GPL/DemanglerGnu/build.gradle index 0e50950bdf..255fd56a5c 100644 --- a/GPL/DemanglerGnu/build.gradle +++ b/GPL/DemanglerGnu/build.gradle @@ -17,9 +17,9 @@ apply plugin: 'eclipse' eclipse.project.name = 'GPL DemanglerGnu' -def v33_1 = "demangler_gnu_v2_33_1" +def v41 = "demangler_gnu_v2_41" def v24 = "demangler_gnu_v2_24" -def srcVersion33_1 = "src/demangler_gnu_v2_33_1" +def srcVersion41 = "src/demangler_gnu_v2_41" def srcVersion24 = "src/demangler_gnu_v2_24" /** @@ -39,21 +39,20 @@ task zipBuildableSource(type:Zip) { description "Collects the source files needed to build this module." archiveBaseName = project.name + "-src-for-build" archiveExtension = 'zip' - + // - // Version 2.33.1 + // Version 2.41 // - from (project.projectDir.toString() + "/" + srcVersion33_1 + "c") { - into "/" + srcVersion33_1 + from (project.projectDir.toString() + "/" + srcVersion41 + "c") { + into "/" + srcVersion41 } - from (project.projectDir.toString() + "/" + srcVersion33_1 + "/headers") { - into "/" + srcVersion33_1 + from (project.projectDir.toString() + "/" + srcVersion41 + "/headers") { + into "/" + srcVersion41 } - from (project.projectDir.toString() + "/" + srcVersion33_1 + "/build") { - into "/" + srcVersion33_1 + from (project.projectDir.toString() + "/" + srcVersion41 + "/build") { + into "/" + srcVersion41 } - from (project.projectDir.toString() + "/" + srcVersion33_1 + "/README.txt") - + from (project.projectDir.toString() + "/" + srcVersion41 + "/README.txt") // // Version 2.24 @@ -72,11 +71,11 @@ task zipBuildableSource(type:Zip) { model { - // - // Version 2.33.1 - // components { - demangler_gnu_v2_33_1(NativeExecutableSpec) { + // + // Version 2.41 + // + demangler_gnu_v2_41(NativeExecutableSpec) { targetPlatform "win_x86_64" targetPlatform "linux_x86_64" targetPlatform "linux_arm_64" @@ -85,10 +84,10 @@ model { sources { c { source { - srcDir srcVersion33_1 + "/c" + srcDir srcVersion41 + "/c" } exportedHeaders { - srcDir srcVersion33_1 + "/headers" + srcDir srcVersion41 + "/headers" } } } @@ -127,8 +126,8 @@ model { def version = b.getApplication().getName() - if (version.equals(v33_1)) { - if (toolChain in Gcc) { + if (version.equals(v41)) { + if (toolChain in Gcc) { //cCompiler.args "-DCP_DEMANGLE_DEBUG" cCompiler.args "-DHAVE_STDLIB_H" cCompiler.args "-DHAVE_STRING_H" diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/README.txt b/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/README.txt deleted file mode 100644 index 56d860b1be..0000000000 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/README.txt +++ /dev/null @@ -1,81 +0,0 @@ -PURPOSE - -This is a readme file to note the changes made to the binutils-2.33.1 source -code in to build its GNU demangler. The files in this directory are used to create a demangling -utility during the full build process. - - - - -COPIED SOURCE CODE / BUILDING RESTRICTIONS - -Most of the files used to build the Ghidra GNU demangler are copied from binutils and have -not been changed. Further, the files in this directory are a small subset of the files used to -build the binutils suite. By copying specific files we are able to use Make and Visual Studio -to build a stand alone demangler without having to perform the more complicated build needed -to build binutils. Specifically, we do not have to run the configure utility that is -provided by binutils. This is critical, as we are using Visual Studio to build on Windows, -which does not have the configure utility support. If we ever wished to build the entire -binutils suite on Windows, then we would most likely need to use a GNU environment made for -Windows, such as MinGW. - - - - -CHANGES TO BINUTILS SOURCE - -cp-demangle.c - -This file contains a small, one-line change to flush to the standard output stream. Without -this change, the program, when called repeatedly from Java would hang as it attempts to read -characters that are buffered on the native side. - - - - -UPDATING - -If we ever wish to update to a newer version of binutils, then we will need to re-copy the files -in this directory. That is, unless at least one of the following changes happens: - -1) building a stand alone c++filt is simple enough that we can do it on each platform, or -2) we decide to build the entire binutils suite and use the full c++filt binary. - - - - -SOURCE FILES - -binutils/libiberty/alloca.c -binutils/libiberty/argv.c -binutils/libiberty/cp-demangle.c -binutils/libiberty/cplus-dem.c -binutils/libiberty/d-demangle.c -binutils/libiberty/dyn-string.c -binutils/libiberty/getopt.c -binutils/libiberty/getopt1.c -binutils/libiberty/rust-demangle.c -binutils/libiberty/safe-ctype.c -binutils/libiberty/xexit.c -binutils/libiberty/xstrdup.c -binutils/include/ansidecl.h -binutils/libiberty/cp-demangle.h -binutils/include/demangle.h -binutils/include/dyn-string.h -binutils/include/getopt.h -binutils/include/libiberty.h -binutils/libiberty/rust-demangle.h -binutils/include/safe-ctype.h - - -This file is created to add minor missing dependencies. - -missing.c - - - - -LICENSE - -The files listed above are licensed by using the file header or the COPYING or COPYING.LIB file -listed in the original source directory of binutils. diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/rust-demangle.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/rust-demangle.c deleted file mode 100644 index 951791bad8..0000000000 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/rust-demangle.c +++ /dev/null @@ -1,353 +0,0 @@ -/* ### - * IP: LGPL 2.1 - * NOTE: See binutils/libiberty/COPYING.LIB - */ -/* Demangler for the Rust programming language - Copyright (C) 2016-2019 Free Software Foundation, Inc. - Written by David Tolnay (dtolnay@gmail.com). - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -In addition to the permissions in the GNU Library General Public -License, the Free Software Foundation gives you unlimited permission -to link the compiled version of this file into combinations with other -programs, and to distribute those combinations without any restriction -coming from the use of this file. (The Library Public License -restrictions do apply in other respects; for example, they cover -modification of the file, and distribution when not linked into a -combined executable.) - -Libiberty is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. -If not, see . */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "safe-ctype.h" - -#include -#include -#include - -#ifdef HAVE_STRING_H -#include -#else -extern size_t strlen(const char *s); -extern int strncmp(const char *s1, const char *s2, size_t n); -extern void *memset(void *s, int c, size_t n); -#endif - -#include -#include "libiberty.h" -#include "rust-demangle.h" - - -/* Mangled Rust symbols look like this: - _$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a - - The original symbol is: - ::drop - - 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. - - Any path component not starting with a XID_Start character is - prefixed with "_". - - The following escape sequences are used: - - "," => $C$ - "@" => $SP$ - "*" => $BP$ - "&" => $RF$ - "<" => $LT$ - ">" => $GT$ - "(" => $LP$ - ")" => $RP$ - " " => $u20$ - "\"" => $u22$ - "'" => $u27$ - "+" => $u2b$ - ";" => $u3b$ - "[" => $u5b$ - "]" => $u5d$ - "{" => $u7b$ - "}" => $u7d$ - "~" => $u7e$ - - A double ".." means "::" and a single "." means "-". - - The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$ */ - -static const char *hash_prefix = "::h"; -static const size_t hash_prefix_len = 3; -static const size_t hash_len = 16; - -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); - -/* INPUT: sym: symbol that has been through C++ (gnu v3) demangling - - This function looks for the following indicators: - - 1. The hash must consist of "h" followed by 16 lowercase hex digits. - - 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. - - 3. There must be no characters other than a-zA-Z0-9 and _.:$ - - 4. There must be no unrecognized $-sign sequences. - - 5. There must be no sequence of three or more dots in a row ("..."). */ - -int -rust_is_mangled (const char *sym) -{ - size_t len, len_without_hash; - - if (!sym) - return 0; - - len = strlen (sym); - if (len <= hash_prefix_len + hash_len) - /* Not long enough to contain "::h" + hash + something else */ - return 0; - - len_without_hash = len - (hash_prefix_len + hash_len); - if (!is_prefixed_hash (sym + len_without_hash)) - return 0; - - return looks_like_rust (sym, len_without_hash); -} - -/* A hash is the prefix "::h" followed by 16 lowercase hex digits. The - hex digits must comprise between 5 and 15 (inclusive) distinct - digits. */ - -static int -is_prefixed_hash (const char *str) -{ - const char *end; - char seen[16]; - size_t i; - int count; - - if (strncmp (str, hash_prefix, hash_prefix_len)) - 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++; - - return count >= 5 && count <= 15; -} - -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) - 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'; -} - -static int -unescape (const char **in, char **out, const char *seq, char value) -{ - size_t len = strlen (seq); - - if (strncmp (*in, seq, len)) - return 0; - - **out = value; - - *in += len; - *out += 1; - - return 1; -} diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/rust-demangle.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/rust-demangle.h deleted file mode 100644 index c1cd4aa916..0000000000 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/rust-demangle.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ### - * IP: LGPL 2.1 - * NOTE: See binutils/libiberty/COPYING.LIB - */ -/* Internal demangler interface for the Rust programming language. - Copyright (C) 2016-2019 Free Software Foundation, Inc. - Written by David Tolnay (dtolnay@gmail.com). - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -In addition to the permissions in the GNU Library General Public -License, the Free Software Foundation gives you unlimited permission -to link the compiled version of this file into combinations with other -programs, and to distribute those combinations without any restriction -coming from the use of this file. (The Library Public License -restrictions do apply in other respects; for example, they cover -modification of the file, and distribution when not linked into a -combined executable.) - -Libiberty is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. -If not, see . */ - -/* This file provides some definitions shared by cplus-dem.c and - rust-demangle.c. It should not be included by any other files. */ - -/* 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); diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/alloca.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/alloca.c similarity index 98% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/alloca.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/alloca.c index 02a214860c..ee0159f8bc 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/alloca.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/alloca.c @@ -1,6 +1,6 @@ /* ### * IP: LGPL 2.1 - * NOTE: license is not in file, but in the directory from whence it came: binutils-2.24/libiberty/COPYING.LIB + * NOTE: See binutils/libiberty/COPYING.LIB */ /* alloca.c -- allocate automatically reclaimed memory (Mostly) portable public-domain implementation -- D A Gwyn @@ -162,7 +162,7 @@ static header *last_alloca_header = NULL; /* -> last alloca header. */ /* @undocumented C_alloca */ -PTR +void * C_alloca (size_t size) { auto char probe; /* Probes stack depth: */ @@ -185,7 +185,7 @@ C_alloca (size_t size) { register header *np = hp->h.next; - free ((PTR) hp); /* Collect garbage. */ + free ((void *) hp); /* Collect garbage. */ hp = np; /* -> next header. */ } @@ -214,7 +214,7 @@ C_alloca (size_t size) /* User storage begins just after header. */ - return (PTR) ((char *) new_storage + sizeof (header)); + return (void *) ((char *) new_storage + sizeof (header)); } } diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/argv.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/argv.c similarity index 96% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/argv.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/argv.c index c3c2a63e3c..e1c8f23a60 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/argv.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/argv.c @@ -3,7 +3,7 @@ * NOTE: See binutils/libiberty/COPYING.LIB */ /* Create and destroy argument vectors (argv's) - Copyright (C) 1992-2019 Free Software Foundation, Inc. + Copyright (C) 1992-2023 Free Software Foundation, Inc. Written by Fred Fish @ Cygnus Support This file is part of the libiberty library. @@ -293,8 +293,8 @@ char **buildargv (const char *input) @deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file}) Write each member of ARGV, handling all necessary quoting, to the file -named by FILE, separated by whitespace. Return 0 on success, non-zero -if an error occurred while writing to FILE. +associated with FILE, separated by whitespace. Return 0 on success, +non-zero if an error occurred while writing to FILE. @end deftypefn @@ -303,8 +303,6 @@ if an error occurred while writing to FILE. int writeargv (char * const *argv, FILE *f) { - int status = 0; - if (f == NULL) return 1; @@ -318,29 +316,26 @@ writeargv (char * const *argv, FILE *f) if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') if (EOF == fputc ('\\', f)) - { - status = 1; - goto done; - } + return 1; if (EOF == fputc (c, f)) - { - status = 1; - goto done; - } + return 1; + arg++; } + /* Write out a pair of quotes for an empty argument. */ + if (arg == *argv) + if (EOF == fputs ("\"\"", f)) + return 1; + if (EOF == fputc ('\n', f)) - { - status = 1; - goto done; - } + return 1; + argv++; } - done: - return status; + return 0; } /* @@ -438,7 +433,10 @@ expandargv (int *argcp, char ***argvp) due to CR/LF->CR translation when reading text files. That does not in-and-of itself indicate failure. */ && ferror (f)) - goto error; + { + free (buffer); + goto error; + } /* Add a NUL terminator. */ buffer[len] = '\0'; /* If the file is empty or contains only whitespace, buildargv would diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cp-demangle.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cp-demangle.c similarity index 88% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cp-demangle.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cp-demangle.c index f5a517515f..049d97c0c7 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cp-demangle.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cp-demangle.c @@ -3,7 +3,7 @@ * NOTE: See binutils/libiberty/COPYING.LIB; Used GPL 3 from this file's header */ /* Demangler for g++ V3 ABI. - Copyright (C) 2003-2019 Free Software Foundation, Inc. + Copyright (C) 2003-2023 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of the libiberty library, which is part of GCC. @@ -29,12 +29,13 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - CHANGE NOTICE: - This file was changed on January 22nd, 2020: - -A call to flush stdout was added in the main function of this file - + + CHANGE NOTICE: + This file was changed on October 31st, 2023: + -A call to flush stdout was added in the main function of this file + */ /* This code implements a demangler for the g++ V3 ABI. The ABI is @@ -356,9 +357,9 @@ struct d_print_info /* 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; + /* 1 more than the number of explicit template parms of a lambda. Template + parm references >= are actually 'auto'. */ + int lambda_tpl_parms; /* The current index into any template argument packs we are using for printing, or -1 to print the whole pack. */ int pack_index; @@ -434,13 +435,16 @@ is_ctor_dtor_or_conversion (struct demangle_component *); static struct demangle_component *d_encoding (struct d_info *, int); -static struct demangle_component *d_name (struct d_info *); +static struct demangle_component *d_name (struct d_info *, int substable); static struct demangle_component *d_nested_name (struct d_info *); -static struct demangle_component *d_prefix (struct d_info *); +static int d_maybe_module_name (struct d_info *, struct demangle_component **); -static struct demangle_component *d_unqualified_name (struct d_info *); +static struct demangle_component *d_prefix (struct d_info *, int); + +static struct demangle_component *d_unqualified_name (struct d_info *, + struct demangle_component *scope, struct demangle_component *module); static struct demangle_component *d_source_name (struct d_info *); @@ -471,7 +475,7 @@ static struct demangle_component * d_bare_function_type (struct d_info *, int); static struct demangle_component * -d_class_enum_type (struct d_info *); +d_class_enum_type (struct d_info *, int); static struct demangle_component *d_array_type (struct d_info *); @@ -497,6 +501,10 @@ static struct demangle_component *d_local_name (struct d_info *); static int d_discriminator (struct d_info *); +static struct demangle_component *d_template_parm (struct d_info *, int *bad); + +static struct demangle_component *d_template_head (struct d_info *, int *bad); + static struct demangle_component *d_lambda (struct d_info *); static struct demangle_component *d_unnamed_type (struct d_info *); @@ -526,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 *); @@ -654,6 +662,13 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_BUILTIN_TYPE: printf ("builtin type %s\n", dc->u.s_builtin.type->name); return; + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + { + char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 }; + printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->arg, suffix); + } + return; case DEMANGLE_COMPONENT_OPERATOR: printf ("operator %s\n", dc->u.s_operator.op->name); return; @@ -777,11 +792,6 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_PTRMEM_TYPE: printf ("pointer to member type\n"); break; - case DEMANGLE_COMPONENT_FIXED_TYPE: - printf ("fixed-point type, accum? %d, sat? %d\n", - dc->u.s_fixed.accum, dc->u.s_fixed.sat); - d_dump (dc->u.s_fixed.length, indent + 2); - break; case DEMANGLE_COMPONENT_ARGLIST: printf ("argument list\n"); break; @@ -824,6 +834,9 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_LITERAL_NEG: printf ("negative literal\n"); break; + case DEMANGLE_COMPONENT_VENDOR_EXPR: + printf ("vendor expression\n"); + break; case DEMANGLE_COMPONENT_JAVA_RESOURCE: printf ("java resource\n"); break; @@ -873,6 +886,7 @@ cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len) 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; @@ -889,6 +903,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; @@ -909,6 +924,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; @@ -929,6 +945,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; @@ -946,6 +963,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; } @@ -980,9 +998,11 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_TRINARY_ARG1: case DEMANGLE_COMPONENT_LITERAL: case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_VENDOR_EXPR: case DEMANGLE_COMPONENT_COMPOUND_NAME: case DEMANGLE_COMPONENT_VECTOR_TYPE: case DEMANGLE_COMPONENT_CLONE: + case DEMANGLE_COMPONENT_MODULE_ENTITY: if (left == NULL || right == NULL) return NULL; break; @@ -1020,6 +1040,12 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_NULLARY: case DEMANGLE_COMPONENT_TRINARY_ARG2: case DEMANGLE_COMPONENT_TPARM_OBJ: + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + case DEMANGLE_COMPONENT_MODULE_INIT: + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: if (left == NULL) return NULL; break; @@ -1028,6 +1054,8 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, empty. */ case DEMANGLE_COMPONENT_ARRAY_TYPE: case DEMANGLE_COMPONENT_INITIALIZER_LIST: + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: if (right == NULL) return NULL; break; @@ -1040,6 +1068,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_CONST: case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: FNQUAL_COMPONENT_CASE: break; @@ -1101,6 +1130,28 @@ d_make_builtin_type (struct d_info *di, return p; } +/* Add a new extended builtin type component. */ + +static struct demangle_component * +d_make_extended_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type, + short arg, char suffix) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE; + p->u.s_extended_builtin.type = type; + p->u.s_extended_builtin.arg = arg; + p->u.s_extended_builtin.suffix = suffix; + } + return p; +} + /* Add a new operator component. */ static struct demangle_component * @@ -1322,7 +1373,7 @@ d_encoding (struct d_info *di, int top_level) dc = d_special_name (di); else { - dc = d_name (di); + dc = d_name (di, 0); if (!dc) /* Failed already. */; @@ -1416,80 +1467,74 @@ d_abi_tags (struct d_info *di, struct demangle_component *dc) */ static struct demangle_component * -d_name (struct d_info *di) +d_name (struct d_info *di, int substable) { char peek = d_peek_char (di); - struct demangle_component *dc; + struct demangle_component *dc = NULL; + struct demangle_component *module = NULL; + int subst = 0; switch (peek) { case 'N': - return d_nested_name (di); + dc = d_nested_name (di); + break; case 'Z': - return d_local_name (di); + dc = d_local_name (di); + break; case 'U': - return d_unqualified_name (di); + dc = d_unqualified_name (di, NULL, NULL); + break; case 'S': { - int subst; - - if (d_peek_next_char (di) != 't') - { - dc = d_substitution (di, 0); - subst = 1; - } - else + if (d_peek_next_char (di) == 't') { d_advance (di, 2); - dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, - d_make_name (di, "std", 3), - d_unqualified_name (di)); + dc = d_make_name (di, "std", 3); di->expansion += 3; - subst = 0; } - if (d_peek_char (di) != 'I') + if (d_peek_char (di) == 'S') { - /* The grammar does not permit this case to occur if we - called d_substitution() above (i.e., subst == 1). We - don't bother to check. */ - } - else - { - /* This is , which means that we just saw - , which is a substitution - candidate if we didn't just get it from a - substitution. */ - if (! subst) + module = d_substitution (di, 0); + if (!module) + return NULL; + if (!(module->type == DEMANGLE_COMPONENT_MODULE_NAME + || module->type == DEMANGLE_COMPONENT_MODULE_PARTITION)) { - if (! d_add_substitution (di, dc)) + if (dc) return NULL; + subst = 1; + dc = module; + module = NULL; } - dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, - d_template_args (di)); } - - return dc; } + /* FALLTHROUGH */ case 'L': default: - dc = d_unqualified_name (di); + if (!subst) + dc = d_unqualified_name (di, dc, module); if (d_peek_char (di) == 'I') { /* This is , which means that we just saw , which is a substitution candidate. */ - if (! d_add_substitution (di, dc)) + if (!subst && !d_add_substitution (di, dc)) return NULL; dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, d_template_args (di)); + subst = 0; } - return dc; + break; } + if (substable && !subst && !d_add_substitution (di, dc)) + return NULL; + return dc; } /* ::= N [] [] E @@ -1514,7 +1559,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; @@ -1540,105 +1585,141 @@ 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 substable) { struct demangle_component *ret = NULL; - while (1) + for (;;) { - char peek; - enum demangle_component_type comb_type; - struct demangle_component *dc; - - peek = d_peek_char (di); - if (peek == '\0') - return NULL; + char peek = d_peek_char (di); /* The older code accepts a here, but I don't see that in the grammar. The older code does not accept a here. */ - comb_type = DEMANGLE_COMPONENT_QUAL_NAME; - if (peek == 'D') + if (peek == 'D' + && (d_peek_next_char (di) == 'T' + || d_peek_next_char (di) == 't')) { - char peek2 = d_peek_next_char (di); - if (peek2 == 'T' || peek2 == 't') - /* Decltype. */ - dc = cplus_demangle_type (di); - else - /* Destructor name. */ - dc = d_unqualified_name (di); + /* Decltype. */ + if (ret) + return NULL; + ret = cplus_demangle_type (di); } - else if (IS_DIGIT (peek) - || IS_LOWER (peek) - || peek == 'C' - || peek == 'U' - || peek == 'L') - dc = d_unqualified_name (di); - else if (peek == 'S') - dc = d_substitution (di, 1); else if (peek == 'I') { if (ret == NULL) return NULL; - comb_type = DEMANGLE_COMPONENT_TEMPLATE; - dc = d_template_args (di); + struct demangle_component *dc = d_template_args (di); + if (!dc) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, dc); } else if (peek == 'T') - dc = d_template_param (di); - else if (peek == 'E') - return ret; + { + if (ret) + return NULL; + ret = d_template_param (di); + } else if (peek == 'M') { - /* Initializer scope for a lambda. We don't need to represent - this; the normal code will just treat the variable as a type - scope, which gives appropriate output. */ - if (ret == NULL) - return NULL; + /* Initializer scope for a lambda. We already added it as a + substitution candidate, don't do that again. */ d_advance (di, 1); continue; } else - return NULL; - - if (ret == NULL) - ret = dc; - else - ret = d_make_comp (di, comb_type, ret, dc); - - if (peek != 'S' && d_peek_char (di) != 'E') { - if (! d_add_substitution (di, ret)) - return NULL; + struct demangle_component *module = NULL; + if (peek == 'S') + { + module = d_substitution (di, 1); + if (!module) + return NULL; + if (!(module->type == DEMANGLE_COMPONENT_MODULE_NAME + || module->type == DEMANGLE_COMPONENT_MODULE_PARTITION)) + { + if (ret) + return NULL; + ret = module; + continue; + } + } + ret = d_unqualified_name (di, ret, module); } + + if (!ret) + break; + + if (d_peek_char (di) == 'E') + break; + + if (substable && !d_add_substitution (di, ret)) + return NULL; } + + return ret; } -/* ::= - ::= - ::= - ::= +static int +d_maybe_module_name (struct d_info *di, struct demangle_component **name) +{ + while (d_peek_char (di) == 'W') + { + d_advance (di, 1); + enum demangle_component_type code = DEMANGLE_COMPONENT_MODULE_NAME; + if (d_peek_char (di) == 'P') + { + code = DEMANGLE_COMPONENT_MODULE_PARTITION; + d_advance (di, 1); + } - ::= L + *name = d_make_comp (di, code, *name, d_source_name (di)); + if (!*name) + return 0; + if (!d_add_substitution (di, *name)) + return 0; + } + return 1; +} + +/* ::= [] [] + ::= [] [] + ::= [] [] + ::= [] [] + ::= [] DC + E [] + ::= L [] */ static struct demangle_component * -d_unqualified_name (struct d_info *di) +d_unqualified_name (struct d_info *di, struct demangle_component *scope, + struct demangle_component *module) { struct demangle_component *ret; char peek; + if (!d_maybe_module_name (di, &module)) + return NULL; + peek = d_peek_char (di); if (IS_DIGIT (peek)) 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; @@ -1647,6 +1728,28 @@ d_unqualified_name (struct d_info *di) d_source_name (di)); } } + else if (peek == 'D' && d_peek_next_char (di) == 'C') + { + // structured binding + d_advance (di, 2); + struct demangle_component *prev = NULL; + do + { + struct demangle_component *next = + d_make_comp (di, DEMANGLE_COMPONENT_STRUCTURED_BINDING, + d_source_name (di), NULL); + if (prev) + d_right (prev) = next; + else + ret = next; + prev = next; + } + while (prev && d_peek_char (di) != 'E'); + if (prev) + d_advance (di, 1); + else + ret = NULL; + } else if (peek == 'C' || peek == 'D') ret = d_ctor_dtor_name (di); else if (peek == 'L') @@ -1676,8 +1779,13 @@ d_unqualified_name (struct d_info *di) else return NULL; + if (module) + ret = d_make_comp (di, DEMANGLE_COMPONENT_MODULE_ENTITY, ret, module); if (d_peek_char (di) == 'B') ret = d_abi_tags (di, ret); + if (scope) + ret = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, scope, ret); + return ret; } @@ -1726,7 +1834,7 @@ d_number (struct d_info *di) } if (ret > ((INT_MAX - (peek - '0')) / 10)) return -1; - ret = ret * 10 + peek - '0'; + ret = ret * 10 + (peek - '0'); d_advance (di, 1); peek = d_peek_char (di); } @@ -1806,19 +1914,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 }, @@ -1845,6 +1957,7 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "ng", NL ("-"), 1 }, { "nt", NL ("!"), 1 }, { "nw", NL ("new"), 3 }, + { "nx", NL ("noexcept"), 1 }, { "oR", NL ("|="), 2 }, { "oo", NL ("||"), 2 }, { "or", NL ("|"), 2 }, @@ -1863,6 +1976,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 }, @@ -2113,11 +2227,11 @@ d_special_name (struct d_info *di) case 'H': return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT, - d_name (di), NULL); + d_name (di, 0), NULL); case 'W': return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER, - d_name (di), NULL); + d_name (di, 0), NULL); case 'A': return d_make_comp (di, DEMANGLE_COMPONENT_TPARM_OBJ, @@ -2133,11 +2247,11 @@ d_special_name (struct d_info *di) { case 'V': return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, - d_name (di), NULL); + d_name (di, 0), NULL); case 'R': { - struct demangle_component *name = d_name (di); + struct demangle_component *name = d_name (di, 0); return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name, d_number_component (di)); } @@ -2146,6 +2260,14 @@ d_special_name (struct d_info *di) return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, d_encoding (di, 0), NULL); + case 'I': + { + struct demangle_component *module = NULL; + if (!d_maybe_module_name (di, &module) || !module) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_MODULE_INIT, + module, NULL); + } case 'T': switch (d_next_char (di)) { @@ -2384,6 +2506,8 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = /* 32 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"), D_PRINT_DEFAULT }, + /* 34 */ { NL ("_Float"), NL ("_Float"), D_PRINT_FLOAT }, + /* 35 */ { NL ("std::bfloat16_t"), NL ("std::bfloat16_t"), D_PRINT_FLOAT }, }; CP_STATIC_IF_GLIBCPP_V3 @@ -2468,13 +2592,6 @@ cplus_demangle_type (struct d_info *di) ret = d_function_type (di); break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'N': - case 'Z': - ret = d_class_enum_type (di); - break; - case 'A': ret = d_array_type (di); break; @@ -2545,39 +2662,6 @@ cplus_demangle_type (struct d_info *di) } break; - case 'S': - /* If this is a special substitution, then it is the start of - . */ - { - char peek_next; - - peek_next = d_peek_next_char (di); - if (IS_DIGIT (peek_next) - || peek_next == '_' - || IS_UPPER (peek_next)) - { - ret = d_substitution (di, 0); - /* The substituted name may have been a template name and - may be followed by tepmlate args. */ - if (d_peek_char (di) == 'I') - ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, - d_template_args (di)); - else - can_subst = 0; - } - else - { - ret = d_class_enum_type (di); - /* If the substitution was a complete type, then it is not - a new substitution candidate. However, if the - substitution was followed by template arguments, then - the whole thing is a substitution candidate. */ - if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD) - can_subst = 0; - } - } - break; - case 'O': d_advance (di, 1); ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, @@ -2687,19 +2771,37 @@ cplus_demangle_type (struct d_info *di) break; case 'F': - /* Fixed point types. DF */ - ret = d_make_empty (di); - ret->type = DEMANGLE_COMPONENT_FIXED_TYPE; - if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di)))) - /* For demangling we don't care about the bits. */ - d_number (di); - ret->u.s_fixed.length = cplus_demangle_type (di); - if (ret->u.s_fixed.length == NULL) - return NULL; - d_number (di); - peek = d_next_char (di); - ret->u.s_fixed.sat = (peek == 's'); - break; + /* DF_ - _Float. + DFx - _Floatx + DF16b - std::bfloat16_t. */ + { + int arg = d_number (di); + char buf[12]; + char suffix = 0; + if (d_peek_char (di) == 'b') + { + if (arg != 16) + return NULL; + d_advance (di, 1); + ret = d_make_builtin_type (di, + &cplus_demangle_builtin_types[35]); + di->expansion += ret->u.s_builtin.type->len; + break; + } + if (d_peek_char (di) == 'x') + suffix = 'x'; + if (!suffix && d_peek_char (di) != '_') + return NULL; + ret + = d_make_extended_builtin_type (di, + &cplus_demangle_builtin_types[34], + arg, suffix); + d_advance (di, 1); + sprintf (buf, "%d", arg); + di->expansion += ret->u.s_extended_builtin.type->len + + strlen (buf) + (suffix != 0); + break; + } case 'v': ret = d_vector_type (di); @@ -2718,7 +2820,7 @@ cplus_demangle_type (struct d_info *di) break; default: - return NULL; + return d_class_enum_type (di, 1); } if (can_subst) @@ -2991,9 +3093,9 @@ d_bare_function_type (struct d_info *di, int has_return_type) /* ::= */ static struct demangle_component * -d_class_enum_type (struct d_info *di) +d_class_enum_type (struct d_info *di, int substable) { - return d_name (di); + return d_name (di, substable); } /* ::= A <(positive dimension) number> _ <(element) type> @@ -3284,18 +3386,69 @@ 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, type, NULL); + if (d_peek_char (di) == 'I') + name = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di)); + return name; +} + /* ::= <(unary) operator-name> ::= <(binary) operator-name> ::= <(trinary) operator-name> ::= cl + E ::= st ::= - ::= sr - ::= sr + ::= u * E # vendor extended expression + ::= ::= + + ::= + ::= 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; @@ -3306,20 +3459,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); @@ -3357,7 +3497,7 @@ d_expression_1 (struct d_info *di) /* operator-function-id, i.e. operator+(t). */ d_advance (di, 2); - name = d_unqualified_name (di); + name = d_unqualified_name (di, NULL, NULL); if (name == NULL) return NULL; if (d_peek_char (di) == 'I') @@ -3379,6 +3519,15 @@ d_expression_1 (struct d_info *di) return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, type, d_exprlist (di, 'E')); } + else if (peek == 'u') + { + /* A vendor extended expression. */ + struct demangle_component *name, *args; + d_advance (di, 1); + name = d_source_name (di); + args = d_template_args_1 (di); + return d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_EXPR, name, args); + } else { struct demangle_component *op; @@ -3455,16 +3604,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, NULL, NULL); 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, NULL, NULL); + 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); @@ -3482,7 +3645,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); @@ -3586,6 +3750,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 @@ -3658,7 +3833,7 @@ d_local_name (struct d_info *di) return NULL; } - name = d_name (di); + name = d_name (di, 0); if (name /* Lambdas and unnamed types have internal discriminators @@ -3722,32 +3897,120 @@ d_discriminator (struct d_info *di) return 1; } -/* ::= Ul E [ ] _ */ +/* ::= Ty + ::= Tn + ::= Tt E + ::= Tp */ + +static struct demangle_component * +d_template_parm (struct d_info *di, int *bad) +{ + if (d_peek_char (di) != 'T') + return NULL; + + struct demangle_component *op; + enum demangle_component_type kind; + switch (d_peek_next_char (di)) + { + default: + return NULL; + + case 'p': /* Pack */ + d_advance (di, 2); + op = d_template_parm (di, bad); + kind = DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM; + if (!op) + { + *bad = 1; + return NULL; + } + break; + + case 'y': /* Typename */ + d_advance (di, 2); + op = NULL; + kind = DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM; + break; + + case 'n': /* Non-Type */ + d_advance (di, 2); + op = cplus_demangle_type (di); + kind = DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM; + if (!op) + { + *bad = 1; + return NULL; + } + break; + + case 't': /* Template */ + d_advance (di, 2); + op = d_template_head (di, bad); + kind = DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM; + if (!op || !d_check_char (di, 'E')) + { + *bad = 1; + return NULL; + } + } + + return d_make_comp (di, kind, op, NULL); +} + +/* ::= ? */ + +static struct demangle_component * +d_template_head (struct d_info *di, int *bad) +{ + struct demangle_component *res = NULL, **slot = &res; + struct demangle_component *op; + + while ((op = d_template_parm (di, bad))) + { + *slot = op; + slot = &d_right (op); + } + + /* Wrap it in a template head, to make concatenating with any parm list, and + printing simpler. */ + if (res) + res = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_HEAD, res, NULL); + + return res; +} + +/* ::= Ul ? E [ ] _ */ static struct demangle_component * d_lambda (struct d_info *di) { - struct demangle_component *tl; - struct demangle_component *ret; - int num; - if (! d_check_char (di, 'U')) return NULL; if (! d_check_char (di, 'l')) return NULL; - tl = d_parmlist (di); + int bad = 0; + struct demangle_component *head = d_template_head (di, &bad); + if (bad) + return NULL; + + struct demangle_component *tl = d_parmlist (di); if (tl == NULL) return NULL; + if (head) + { + d_right (head) = tl; + tl = head; + } if (! d_check_char (di, 'E')) return NULL; - num = d_compact_number (di); + int num = d_compact_number (di); if (num < 0) return NULL; - ret = d_make_empty (di); + struct demangle_component *ret = d_make_empty (di); if (ret) { ret->type = DEMANGLE_COMPONENT_LAMBDA; @@ -3755,9 +4018,6 @@ d_lambda (struct d_info *di) ret->u.s_unary_num.num = num; } - if (! d_add_substitution (di, ret)) - return NULL; - return ret; } @@ -3801,10 +4061,11 @@ d_clone_suffix (struct d_info *di, struct demangle_component *encoding) const char *pend = suffix; struct demangle_component *n; - if (*pend == '.' && (IS_LOWER (pend[1]) || pend[1] == '_')) + if (*pend == '.' && (IS_LOWER (pend[1]) || IS_DIGIT (pend[1]) + || pend[1] == '_')) { pend += 2; - while (IS_LOWER (*pend) || *pend == '_') + while (IS_LOWER (*pend) || IS_DIGIT (*pend) || *pend == '_') ++pend; } while (*pend == '.' && IS_DIGIT (pend[1])) @@ -4077,11 +4338,13 @@ d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) static void d_count_templates_scopes (struct d_print_info *dpi, - const struct demangle_component *dc) + 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: @@ -4089,10 +4352,21 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_FUNCTION_PARAM: case DEMANGLE_COMPONENT_SUB_STD: case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_CHARACTER: case DEMANGLE_COMPONENT_NUMBER: case DEMANGLE_COMPONENT_UNNAMED_TYPE: + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: + case DEMANGLE_COMPONENT_MODULE_INIT: + case DEMANGLE_COMPONENT_FIXED_TYPE: + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: break; case DEMANGLE_COMPONENT_TEMPLATE: @@ -4158,6 +4432,7 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_TRINARY_ARG2: case DEMANGLE_COMPONENT_LITERAL: case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_VENDOR_EXPR: case DEMANGLE_COMPONENT_JAVA_RESOURCE: case DEMANGLE_COMPONENT_COMPOUND_NAME: case DEMANGLE_COMPONENT_DECLTYPE: @@ -4191,12 +4466,9 @@ d_count_templates_scopes (struct d_print_info *dpi, d_count_templates_scopes (dpi, dc->u.s_extended_operator.name); break; - case DEMANGLE_COMPONENT_FIXED_TYPE: - d_count_templates_scopes (dpi, dc->u.s_fixed.length); - break; - case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_MODULE_ENTITY: d_count_templates_scopes (dpi, d_left (dc)); break; @@ -4211,7 +4483,7 @@ d_count_templates_scopes (struct d_print_info *dpi, 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'; @@ -4225,7 +4497,7 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback, dpi->demangle_failure = 0; dpi->recursion = 0; - dpi->is_lambda_arg = 0; + dpi->lambda_tpl_parms = 0; dpi->component_stack = NULL; @@ -4461,11 +4733,11 @@ d_find_pack (struct d_print_info *dpi, case DEMANGLE_COMPONENT_TAGGED_NAME: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: case DEMANGLE_COMPONENT_SUB_STD: case DEMANGLE_COMPONENT_CHARACTER: case DEMANGLE_COMPONENT_FUNCTION_PARAM: case DEMANGLE_COMPONENT_UNNAMED_TYPE: - case DEMANGLE_COMPONENT_FIXED_TYPE: case DEMANGLE_COMPONENT_DEFAULT_ARG: case DEMANGLE_COMPONENT_NUMBER: return NULL; @@ -4664,6 +4936,91 @@ 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; +} + +static void +d_print_lambda_parm_name (struct d_print_info *dpi, int type, unsigned index) +{ + const char *str; + switch (type) + { + default: + dpi->demangle_failure = 1; + str = ""; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + str = "$T"; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + str = "$N"; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + str = "$TT"; + break; + } + d_append_string (dpi, str); + d_append_num (dpi, index); +} + /* Subroutine to handle components. */ static void @@ -4705,6 +5062,38 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_append_char (dpi, ']'); return; + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + d_append_char (dpi, '['); + for (;;) + { + d_print_comp (dpi, options, d_left (dc)); + dc = d_right (dc); + if (!dc) + break; + d_append_string (dpi, ", "); + } + d_append_char (dpi, ']'); + return; + + case DEMANGLE_COMPONENT_MODULE_ENTITY: + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, '@'); + d_print_comp (dpi, options, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: + { + if (d_left (dc)) + d_print_comp (dpi, options, d_left (dc)); + char c = dc->type == DEMANGLE_COMPONENT_MODULE_PARTITION + ? ':' : d_left (dc) ? '.' : 0; + if (c) + d_append_char (dpi, c); + d_print_comp (dpi, options, d_right (dc)); + } + return; + case DEMANGLE_COMPONENT_QUAL_NAME: case DEMANGLE_COMPONENT_LOCAL_NAME: d_print_comp (dpi, options, d_left (dc)); @@ -4886,7 +5275,21 @@ d_print_comp_inner (struct d_print_info *dpi, int options, } case DEMANGLE_COMPONENT_TEMPLATE_PARAM: - if (dpi->is_lambda_arg) + if (dpi->lambda_tpl_parms > dc->u.s_number.number + 1) + { + const struct demangle_component *a + = d_left (dpi->templates->template_decl); + unsigned c; + for (c = dc->u.s_number.number; a && c; c--) + a = d_right (a); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM) + a = d_left (a); + if (!a) + dpi->demangle_failure = 1; + else + d_print_lambda_parm_name (dpi, a->type, dc->u.s_number.number); + } + else if (dpi->lambda_tpl_parms) { /* Show the template parm index, as that's how g++ displays these, and future proofs us against potential @@ -4936,6 +5339,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_print_comp (dpi, options, dc->u.s_dtor.name); return; + case DEMANGLE_COMPONENT_MODULE_INIT: + d_append_string (dpi, "initializer for module "); + d_print_comp (dpi, options, d_left (dc)); + return; + case DEMANGLE_COMPONENT_VTABLE: d_append_string (dpi, "vtable for "); d_print_comp (dpi, options, d_left (dc)); @@ -5062,7 +5470,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options, { /* Handle reference smashing: & + && = &. */ struct demangle_component *sub = d_left (dc); - if (!dpi->is_lambda_arg + if (!dpi->lambda_tpl_parms && sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) { struct d_saved_scope *scope = d_get_saved_scope (dpi, sub); @@ -5173,6 +5581,14 @@ d_print_comp_inner (struct d_print_info *dpi, int options, dc->u.s_builtin.type->java_len); return; + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + d_append_buffer (dpi, dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->len); + d_append_num (dpi, dc->u.s_extended_builtin.arg); + if (dc->u.s_extended_builtin.suffix) + d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1); + return; + case DEMANGLE_COMPONENT_VENDOR_TYPE: d_print_comp (dpi, options, d_left (dc)); return; @@ -5311,22 +5727,6 @@ d_print_comp_inner (struct d_print_info *dpi, int options, return; } - case DEMANGLE_COMPONENT_FIXED_TYPE: - if (dc->u.s_fixed.sat) - d_append_string (dpi, "_Sat "); - /* Don't print "int _Accum". */ - if (dc->u.s_fixed.length->u.s_builtin.type - != &cplus_demangle_builtin_types['i'-'a']) - { - d_print_comp (dpi, options, dc->u.s_fixed.length); - d_append_char (dpi, ' '); - } - if (dc->u.s_fixed.accum) - d_append_string (dpi, "_Accum"); - else - d_append_string (dpi, "_Fract"); - return; - case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: if (d_left (dc) != NULL) @@ -5447,8 +5847,8 @@ 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") || !strcmp (code, "nx"))) + /* Always print parens for sizeof (type) and noexcept(expr). */ { d_append_char (dpi, '('); d_print_comp (dpi, options, operand); @@ -5480,6 +5880,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. */ @@ -5537,6 +5940,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)); @@ -5656,6 +6061,13 @@ d_print_comp_inner (struct d_print_info *dpi, int options, } return; + case DEMANGLE_COMPONENT_VENDOR_EXPR: + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ')'); + return; + case DEMANGLE_COMPONENT_NUMBER: d_append_num (dpi, dc->u.s_number.number); return; @@ -5682,9 +6094,10 @@ d_print_comp_inner (struct d_print_info *dpi, int options, case DEMANGLE_COMPONENT_PACK_EXPANSION: { - int len; - int i; - struct demangle_component *a = d_find_pack (dpi, d_left (dc)); + struct demangle_component *a = NULL; + + if (!dpi->lambda_tpl_parms) + a = d_find_pack (dpi, d_left (dc)); if (a == NULL) { /* d_find_pack won't find anything if the only packs involved @@ -5692,17 +6105,20 @@ d_print_comp_inner (struct d_print_info *dpi, int options, case, just print the pattern and "...". */ d_print_subexpr (dpi, options, d_left (dc)); d_append_string (dpi, "..."); - return; } - - len = d_pack_length (a); - dc = d_left (dc); - for (i = 0; i < len; ++i) + else { - dpi->pack_index = i; - d_print_comp (dpi, options, dc); - if (i < len-1) - d_append_string (dpi, ", "); + int len = d_pack_length (a); + int i; + + dc = d_left (dc); + for (i = 0; i < len; ++i) + { + if (i) + d_append_string (dpi, ", "); + dpi->pack_index = i; + d_print_comp (dpi, options, dc); + } } } return; @@ -5732,15 +6148,50 @@ d_print_comp_inner (struct d_print_info *dpi, int options, return; case DEMANGLE_COMPONENT_LAMBDA: - d_append_string (dpi, "{lambda("); - /* Generic lambda auto parms are mangled as the template type - parm they are. */ - dpi->is_lambda_arg++; - d_print_comp (dpi, options, dc->u.s_unary_num.sub); - dpi->is_lambda_arg--; - d_append_string (dpi, ")#"); - d_append_num (dpi, dc->u.s_unary_num.num + 1); - d_append_char (dpi, '}'); + { + d_append_string (dpi, "{lambda"); + struct demangle_component *parms = dc->u.s_unary_num.sub; + struct d_print_template dpt; + /* Generic lambda auto parms are mangled as the (synthedic) template + type parm they are. We need to tell the printer that (a) we're in + a lambda, and (b) the number of synthetic parms. */ + int saved_tpl_parms = dpi->lambda_tpl_parms; + dpi->lambda_tpl_parms = 0; + /* Hang any lambda head as-if template args. */ + dpt.template_decl = NULL; + dpt.next = dpi->templates; + dpi->templates = &dpt; + if (parms && parms->type == DEMANGLE_COMPONENT_TEMPLATE_HEAD) + { + dpt.template_decl = parms; + + d_append_char (dpi, '<'); + struct demangle_component *parm; + for (parm = d_left (parms); parm; parm = d_right (parm)) + { + if (dpi->lambda_tpl_parms++) + d_append_string (dpi, ", "); + d_print_comp (dpi, options, parm); + d_append_char (dpi, ' '); + if (parm->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM) + parm = d_left (parm); + d_print_lambda_parm_name (dpi, parm->type, + dpi->lambda_tpl_parms - 1); + } + d_append_char (dpi, '>'); + + parms = d_right (parms); + } + dpi->lambda_tpl_parms++; + + d_append_char (dpi, '('); + d_print_comp (dpi, options, parms); + dpi->lambda_tpl_parms = saved_tpl_parms; + dpi->templates = dpt.next; + d_append_string (dpi, ")#"); + d_append_num (dpi, dc->u.s_unary_num.num + 1); + d_append_char (dpi, '}'); + } return; case DEMANGLE_COMPONENT_UNNAMED_TYPE: @@ -5756,6 +6207,40 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_append_char (dpi, ']'); return; + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + { + d_append_char (dpi, '<'); + int count = 0; + struct demangle_component *parm; + for (parm = d_left (dc); parm; parm = d_right (parm)) + { + if (count++) + d_append_string (dpi, ", "); + d_print_comp (dpi, options, parm); + } + d_append_char (dpi, '>'); + } + return; + + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + d_append_string (dpi, "typename"); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + d_append_string (dpi, "template"); + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, " class"); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "..."); + return; + default: d_print_error (dpi); return; @@ -5986,10 +6471,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) != '(') @@ -6185,32 +6670,10 @@ d_print_conversion (struct d_print_info *dpi, int options, dpt.template_decl = dpi->current_template; } - if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) - { - d_print_comp (dpi, options, d_left (dc)); - if (dpi->current_template != NULL) - dpi->templates = dpt.next; - } - else - { - d_print_comp (dpi, options, d_left (d_left (dc))); + d_print_comp (dpi, options, d_left (dc)); - /* For a templated cast operator, we need to remove the template - parameters from scope after printing the operator name, - so we need to handle the template printing here. */ - if (dpi->current_template != NULL) - dpi->templates = dpt.next; - - if (d_last_char (dpi) == '<') - d_append_char (dpi, ' '); - d_append_char (dpi, '<'); - d_print_comp (dpi, options, d_right (d_left (dc))); - /* Avoid generating two consecutive '>' characters, to avoid - the C++ syntactic ambiguity. */ - if (d_last_char (dpi) == '>') - d_append_char (dpi, ' '); - d_append_char (dpi, '>'); - } + if (dpi->current_template != NULL) + dpi->templates = dpt.next; } /* Initialize the information structure we use to pass around @@ -6281,6 +6744,9 @@ 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 @@ -6339,6 +6805,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 @@ -6762,7 +7235,6 @@ main (int argc, char *argv[]) /* Pile characters into mangled until we hit one that can't occur in a mangled name. */ c = getchar (); - while (!feof (stdin) && is_mangled_char (c)) { dyn_string_append_char (mangled, c); @@ -6796,12 +7268,15 @@ main (int argc, char *argv[]) /* If we haven't hit EOF yet, we've read one character that can't occur in a mangled name, so print it out. */ + + // Changed 10/31/23 if (!feof (stdin)) { putchar (c); - } - - // Changed Jan 22, 2020 - flush buffer for waiting program - fflush(stdout); + } + + // Changed 10/31/23 - flush buffer for waiting program + fflush(stdout); + } dyn_string_delete (mangled); diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cplus-dem.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cplus-dem.c similarity index 93% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cplus-dem.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cplus-dem.c index e7e2736b2e..c789b2abbf 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cplus-dem.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cplus-dem.c @@ -3,7 +3,7 @@ * NOTE: See binutils/libiberty/COPYING.LIB */ /* Demangler for GNU C++ - Copyright (C) 1989-2019 Free Software Foundation, Inc. + Copyright (C) 1989-2023 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 @@ -56,7 +56,6 @@ void * realloc (); #define CURRENT_DEMANGLING_STYLE options #include "libiberty.h" -#include "rust-demangle.h" enum demangling_styles current_demangling_style = auto_demangling; @@ -164,27 +163,20 @@ cplus_demangle (const char *mangled, int options) if ((options & DMGL_STYLE_MASK) == 0) options |= (int) current_demangling_style & DMGL_STYLE_MASK; + /* The Rust demangling is implemented elsewhere. + Legacy Rust symbols overlap with GNU_V3, so try Rust first. */ + if (RUST_DEMANGLING || AUTO_DEMANGLING) + { + ret = rust_demangle (mangled, options); + if (ret || RUST_DEMANGLING) + return ret; + } + /* The V3 ABI demangling is implemented elsewhere. */ - if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING) + if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) { ret = cplus_demangle_v3 (mangled, 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; - } - } - - if (ret || RUST_DEMANGLING) + if (ret || GNU_V3_DEMANGLING) return ret; } @@ -208,27 +200,6 @@ cplus_demangle (const char *mangled, int options) 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 * diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cxxfilt.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cxxfilt.c similarity index 82% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cxxfilt.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cxxfilt.c index 8a277e17a3..0b914332d9 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/cxxfilt.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/cxxfilt.c @@ -2,7 +2,7 @@ * IP: GPL 3 */ /* Demangler for GNU C++ - main program - Copyright (C) 1989-2019 Free Software Foundation, Inc. + Copyright (C) 1989-2023 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 @@ -23,23 +23,34 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - - CHANGE NOTICE: - This file was changed on July 22nd, 2020. -*/ + + CHANGE NOTICE: + This file was changed on October 31st, 2023. + + */ -#include -#include +// #include "sysdep.h" // Changed 10/31/23 +// error reporting front end +// #include "bfd.h" // Changed 10/31/23 + +#include // Changed 10/31/23 +#include // Changed 10/31/23 #include "libiberty.h" #include "demangle.h" #include "getopt.h" #include "safe-ctype.h" +// bfd code +// #include "bucomm.h" // Changed 10/31/23 + static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE; -static int strip_underscore = 0; // TARGET_PREPENDS_UNDERSCORE; // Changed Jan 22, 2020 -static const char *program_name; // Changed Jan 22, 2020 +static int strip_underscore = 0; // TARGET_PREPENDS_UNDERSCORE; // Changed 10/31/23 + +// declared in bucomm.c +static const char *program_name; // Changed 10/31/23 + static const struct option long_options[] = { @@ -108,10 +119,12 @@ Usage: %s [options] [mangled names]\n", program_name); fprintf (stream, "\ Options are:\n\ [-_|--strip-underscore] Ignore first leading underscore%s\n", - strip_underscore ? " (default)" : ""); // Changed Jan 22, 2020 + // TARGET_PREPENDS_UNDERSCORE ? " (default)" : ""); // Changed 10/31/23 + strip_underscore ? " (default)" : ""); // Changed 10/31/23 fprintf (stream, "\ [-n|--no-strip-underscore] Do not ignore a leading underscore%s\n", - strip_underscore ? "" : " (default)"); // Changed Jan 22, 2020 + // TARGET_PREPENDS_UNDERSCORE ? "" : " (default)"); // Changed 10/31/23 + strip_underscore ? "" : " (default)"); // Changed 10/31/23 fprintf (stream, "\ [-p|--no-params] Do not display function arguments\n\ [-i|--no-verbose] Do not show implementation details (if any)\n\ @@ -130,11 +143,11 @@ Demangled names are displayed to stdout.\n\ If a name cannot be demangled it is just echoed to stdout.\n\ If no names are provided on the command line, stdin is read.\n"); - /* Changed Jan 22, 2020 +/* Changed 10/31/23 + // defined in version.h if (REPORT_BUGS_TO[0] && status == 0) fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO); - */ - +*/ exit (status); } @@ -158,8 +171,8 @@ main (int argc, char **argv) enum demangling_styles style = auto_demangling; program_name = argv[0]; - // xmalloc_set_program_name (program_name); // Changed Jan 22, 2020 - // bfd_set_error_program_name (program_name); // Changed Jan 22, 2020 + // xmalloc_set_program_name (program_name); // Changed 10/31/23 + // bfd_set_error_program_name (program_name); // Changed 10/31/23 expandargv (&argc, &argv); @@ -191,7 +204,8 @@ main (int argc, char **argv) flags &= ~ DMGL_VERBOSE; break; case 'v': - printf ("(GNU Binutils) c++filt 2.33.1\n"); // Changed Jan 22, 2020 + // print_version ("c++filt"); // Changed 10/31/23 + printf ("c++filt 2.41\n"); // Changed 10/31/23 return 0; case '_': strip_underscore = 1; @@ -230,13 +244,14 @@ main (int argc, char **argv) case rust_demangling: valid_symbols = standard_symbol_characters (); break; - default: { + default: /* Folks should explicitly indicate the appropriate alphabet for each demangling. Providing a default would allow the question to go unconsidered. */ - fprintf (stderr, "Internal error: no symbol alphabet for current style\n"); // Changed Jan 22, 2020 - exit (1); // Changed Jan 22, 2020 - } + // fatal ("Internal error: no symbol alphabet for current style"); // Changed 10/31/23 + fprintf (stderr, "Internal error: no symbol alphabet for current style\n"); // Changed 10/31/23 + exit (1); // Changed 10/31/23 + } for (;;) diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/d-demangle.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/d-demangle.c similarity index 60% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/d-demangle.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/d-demangle.c index 95477dc890..c4b49cef47 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/d-demangle.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/d-demangle.c @@ -3,7 +3,7 @@ * NOTE: See binutils/libiberty/COPYING.LIB */ /* Demangler for the D programming language - Copyright (C) 2014-2019 Free Software Foundation, Inc. + Copyright (C) 2014-2023 Free Software Foundation, Inc. Written by Iain Buclaw (ibuclaw@gdcproject.org) This file is part of the libiberty library. @@ -35,6 +35,9 @@ If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#ifdef HAVE_LIMITS_H +#include +#endif #include "safe-ctype.h" @@ -49,6 +52,13 @@ If not, see . */ #include #include "libiberty.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 */ @@ -59,9 +69,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) { @@ -72,7 +82,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; @@ -121,14 +131,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) { @@ -139,7 +149,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; @@ -164,66 +174,73 @@ 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_value (string *, const char *, const char *, char); +static const char *dlang_type (string *, const char *, struct dlang_info *); + +static const char *dlang_value (string *, const char *, const char *, char, + struct dlang_info *); static const char *dlang_parse_qualified (string *, const char *, - enum dlang_symbol_kinds); + struct dlang_info *, int); static const char *dlang_parse_mangle (string *, const char *, - enum dlang_symbol_kinds); + struct dlang_info *); -static const char *dlang_parse_tuple (string *, const char *); +static const char *dlang_parse_tuple (string *, const char *, + struct dlang_info *); -static const char *dlang_parse_template (string *, const char *, long); +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. */ + 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, long *ret) +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; - (*ret) = 0; + unsigned long val = 0; while (ISDIGIT (*mangled)) { - (*ret) *= 10; + unsigned long digit = mangled[0] - '0'; - /* If an overflow occured when multiplying by ten, the result - will not be a multiple of ten. */ - if ((*ret % 10) != 0) + /* Check for overflow. */ + if (val > (UINT_MAX - digit) / 10) return NULL; - (*ret) += mangled[0] - '0'; + val = val * 10 + digit; mangled++; } - if (*mangled == '\0' || *ret < 0) + if (*mangled == '\0') return NULL; + *ret = val; return mangled; } @@ -240,15 +257,15 @@ dlang_hexdigit (const char *mangled, char *ret) c = mangled[0]; if (!ISDIGIT (c)) - (*ret) = (c - (ISUPPER (c) ? 'A' : 'a') + 10); + *ret = c - (ISUPPER (c) ? 'A' : 'a') + 10; else - (*ret) = (c - '0'); + *ret = c - '0'; c = mangled[1]; if (!ISDIGIT (c)) - (*ret) = (*ret << 4) | (c - (ISUPPER (c) ? 'A' : 'a') + 10); + *ret = (*ret << 4) | (c - (ISUPPER (c) ? 'A' : 'a') + 10); else - (*ret) = (*ret << 4) | (c - '0'); + *ret = (*ret << 4) | (c - '0'); mangled += 2; @@ -271,6 +288,178 @@ dlang_call_convention_p (const char *mangled) } } +/* 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 || strlen(backref) < len) + 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; + + if (ISDIGIT (*mangled)) + return 1; + + 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. */ static const char * @@ -389,9 +578,11 @@ dlang_attributes (string *decl, const char *mangled) case 'g': case 'h': case 'k': + case 'n': /* inout parameter is represented as 'Ng'. vector parameter is represented as 'Nh'. - return paramenter is represented as 'Nk'. + return parameter is represented as 'Nk'. + typeof(*null) parameter is represented as 'Nn'. If we see this, then we know we're really in the parameter list. Rewind and break. */ mangled--; @@ -408,6 +599,10 @@ dlang_attributes (string *decl, const char *mangled) mangled++; string_append (decl, "scope "); continue; + case 'm': /* @live */ + mangled++; + string_append (decl, "@live "); + continue; default: /* unknown attribute */ return NULL; @@ -418,13 +613,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; @@ -439,27 +660,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); @@ -470,7 +680,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; @@ -510,6 +720,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 "); @@ -523,7 +742,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; @@ -532,7 +751,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; @@ -542,19 +761,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': @@ -563,7 +782,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; } @@ -571,15 +790,21 @@ 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; } + else if (*mangled == 'n') /* typeof(*null) */ + { + mangled++; + string_append (decl, "typeof(*null)"); + return mangled; + } else 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]) */ @@ -594,7 +819,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, "]"); @@ -607,10 +832,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, "]"); @@ -622,7 +847,7 @@ dlang_type (string *decl, const char *mangled) mangled++; if (!dlang_call_convention_p (mangled)) { - mangled = dlang_type (decl, mangled); + mangled = dlang_type (decl, mangled, info); string_append (decl, "*"); return mangled; } @@ -634,16 +859,15 @@ dlang_type (string *decl, const char *mangled) 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); + 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_qualified (decl, mangled, dlang_type_name); + return dlang_parse_qualified (decl, mangled, info, 0); case 'D': /* delegate T */ { string mods; @@ -654,7 +878,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 && *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); @@ -663,12 +892,12 @@ 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': mangled++; - string_append (decl, "none"); + string_append (decl, "typeof(null)"); return mangled; case 'v': mangled++; @@ -777,6 +1006,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; } @@ -785,152 +1018,146 @@ 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) { - long len; + unsigned long len; + + if (mangled == NULL || *mangled == '\0') + return NULL; + + if (*mangled == 'Q') + return dlang_symbol_backref (decl, mangled, info); + + /* 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); + const char *endptr = dlang_number (mangled, &len); if (endptr == NULL || len == 0) return NULL; - /* 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) + if (strlen (endptr) < len) + return NULL; + + mangled = endptr; + + /* 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); + + /* There can be multiple different declarations in the same function that have + the same mangled name. To make the mangled names unique, a fake parent in + the form `__Sddd' is added to the symbol. */ + if (len >= 4 && mangled[0] == '_' && mangled[1] == '_' && mangled[2] == 'S') { - long psize = len; - const char *pend; - int saved = string_length (decl); + const char *numptr = mangled + 3; + while (numptr < (mangled + len) && ISDIGIT (*numptr)) + numptr++; - /* Work backwards until a match is found. */ - for (pend = endptr; endptr != NULL; pend--) + if (mangled + len == numptr) { - 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 (ISDIGIT (*mangled)) - mangled = dlang_parse_qualified (decl, mangled, - dlang_template_ident); - else if (strncmp (mangled, "_D", 2) == 0) - mangled = dlang_parse_mangle (decl, mangled, dlang_function); - - /* Check for name length mismatch. */ - if (mangled && (mangled - pend) == psize) - return mangled; - - psize /= 10; - string_setlength (decl, saved); + /* Skip over the fake parent. */ + mangled += len; + return dlang_identifier (decl, mangled, info); } - /* No match on any combinations. */ - return NULL; + /* else demangle it as a plain identifier. */ } - else + + return dlang_lname (decl, mangled, len); +} + +/* 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 && mangled[0] == '_' && mangled[1] == '_' - && (mangled[2] == 'T' || mangled[2] == 'U')) - return dlang_parse_template (decl, mangled, len); - - switch (len) + case 6: + if (strncmp (mangled, "__ctor", 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_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 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 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 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 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; + /* 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_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; - string_appendn (decl, mangled, len); - mangled += len; + 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 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 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 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; } @@ -946,7 +1173,7 @@ dlang_parse_integer (string *decl, const char *mangled, char type) char value[20]; int pos = sizeof(value); int width = 0; - long val; + unsigned long val; mangled = dlang_number (mangled, &val); if (mangled == NULL) @@ -1002,7 +1229,7 @@ dlang_parse_integer (string *decl, const char *mangled, char type) else if (type == 'b') { /* Parse boolean value. */ - long val; + unsigned long val; mangled = dlang_number (mangled, &val); if (mangled == NULL) @@ -1121,7 +1348,7 @@ static const char * dlang_parse_string (string *decl, const char *mangled) { char type = *mangled; - long len; + unsigned long len; mangled++; mangled = dlang_number (mangled, &len); @@ -1183,9 +1410,10 @@ dlang_parse_string (string *decl, const char *mangled) /* Extract the static array value from MANGLED and append it to DECL. Return the remaining string on success or NULL on failure. */ static const char * -dlang_parse_arrayliteral (string *decl, const char *mangled) +dlang_parse_arrayliteral (string *decl, const char *mangled, + struct dlang_info *info) { - long elements; + unsigned long elements; mangled = dlang_number (mangled, &elements); if (mangled == NULL) @@ -1194,7 +1422,7 @@ dlang_parse_arrayliteral (string *decl, const char *mangled) string_append (decl, "["); while (elements--) { - mangled = dlang_value (decl, mangled, NULL, '\0'); + mangled = dlang_value (decl, mangled, NULL, '\0', info); if (mangled == NULL) return NULL; @@ -1209,9 +1437,10 @@ dlang_parse_arrayliteral (string *decl, const char *mangled) /* Extract the associative array value from MANGLED and append it to DECL. Return the remaining string on success or NULL on failure. */ static const char * -dlang_parse_assocarray (string *decl, const char *mangled) +dlang_parse_assocarray (string *decl, const char *mangled, + struct dlang_info *info) { - long elements; + unsigned long elements; mangled = dlang_number (mangled, &elements); if (mangled == NULL) @@ -1220,12 +1449,12 @@ dlang_parse_assocarray (string *decl, const char *mangled) string_append (decl, "["); while (elements--) { - mangled = dlang_value (decl, mangled, NULL, '\0'); + mangled = dlang_value (decl, mangled, NULL, '\0', info); if (mangled == NULL) return NULL; string_append (decl, ":"); - mangled = dlang_value (decl, mangled, NULL, '\0'); + mangled = dlang_value (decl, mangled, NULL, '\0', info); if (mangled == NULL) return NULL; @@ -1240,9 +1469,10 @@ dlang_parse_assocarray (string *decl, const char *mangled) /* Extract the struct literal value for NAME from MANGLED and append it to DECL. Return the remaining string on success or NULL on failure. */ static const char * -dlang_parse_structlit (string *decl, const char *mangled, const char *name) +dlang_parse_structlit (string *decl, const char *mangled, const char *name, + struct dlang_info *info) { - long args; + unsigned long args; mangled = dlang_number (mangled, &args); if (mangled == NULL) @@ -1254,7 +1484,7 @@ dlang_parse_structlit (string *decl, const char *mangled, const char *name) string_append (decl, "("); while (args--) { - mangled = dlang_value (decl, mangled, NULL, '\0'); + mangled = dlang_value (decl, mangled, NULL, '\0', info); if (mangled == NULL) return NULL; @@ -1269,7 +1499,8 @@ dlang_parse_structlit (string *decl, const char *mangled, const char *name) /* Extract the value from MANGLED and append it to DECL. Return the remaining string on success or NULL on failure. */ static const char * -dlang_value (string *decl, const char *mangled, const char *name, char type) +dlang_value (string *decl, const char *mangled, const char *name, char type, + struct dlang_info *info) { if (mangled == NULL || *mangled == '\0') return NULL; @@ -1330,15 +1561,24 @@ dlang_value (string *decl, const char *mangled, const char *name, char type) case 'A': mangled++; if (type == 'H') - mangled = dlang_parse_assocarray (decl, mangled); + mangled = dlang_parse_assocarray (decl, mangled, info); else - mangled = dlang_parse_arrayliteral (decl, mangled); + mangled = dlang_parse_arrayliteral (decl, mangled, info); break; /* Struct values. */ case 'S': mangled++; - mangled = dlang_parse_structlit (decl, mangled, name); + mangled = dlang_parse_structlit (decl, mangled, name, info); + break; + + /* Function literal symbol. */ + case 'f': + mangled++; + if (strncmp (mangled, "_D", 2) != 0 + || !dlang_symbol_name_p (mangled + 2, info)) + return NULL; + mangled = dlang_parse_mangle (decl, mangled, info); break; default: @@ -1351,22 +1591,22 @@ dlang_value (string *decl, const char *mangled, const char *name, char type) /* 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, - enum dlang_symbol_kinds kind) +dlang_parse_mangle (string *decl, const char *mangled, struct dlang_info *info) { /* A D mangled symbol is comprised of both scope and type information. MangleName: _D QualifiedName Type - _D QualifiedName M 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; - mangled = dlang_parse_qualified (decl, mangled, dlang_top_level); + mangled = dlang_parse_qualified (decl, mangled, info, 1); if (mangled != NULL) { @@ -1375,123 +1615,97 @@ dlang_parse_mangle (string *decl, const char *mangled, mangled++; else { - string mods; - int saved; + /* Discard the declaration or return type. */ + string type; - /* Skip over 'this' parameter. */ - if (*mangled == 'M') - mangled++; - - /* Save the type modifiers for appending at the end if needed. */ - string_init (&mods); - mangled = dlang_type_modifiers (&mods, mangled); - - if (mangled && dlang_call_convention_p (mangled)) - { - /* Skip over calling convention and attributes. */ - saved = string_length (decl); - mangled = dlang_call_convention (decl, mangled); - mangled = dlang_attributes (decl, mangled); - string_setlength (decl, saved); - - string_append (decl, "("); - mangled = dlang_function_args (decl, mangled); - string_append (decl, ")"); - - /* Add any const/immutable/shared modifier. */ - string_appendn (decl, mods.b, string_length (&mods)); - } - - /* Consume the decl type of symbol. */ - saved = string_length (decl); - mangled = dlang_type (decl, mangled); - string_setlength (decl, saved); - - string_delete (&mods); + string_init (&type); + mangled = dlang_type (&type, mangled, info); + string_delete (&type); } } - /* Check that the entire symbol was successfully demangled. */ - if (kind == dlang_top_level) - { - if (mangled == NULL || *mangled != '\0') - return NULL; - } - return mangled; } /* 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_qualified (string *decl, const char *mangled, - enum dlang_symbol_kinds kind) + struct dlang_info *info, int suffix_modifiers) { /* Qualified names are identifiers separated by their encoded length. Nested functions also encode their argument types without specifying what they return. QualifiedName: - SymbolName - SymbolName QualifiedName - SymbolName TypeFunctionNoReturn QualifiedName - SymbolName M TypeModifiers TypeFunctionNoReturn 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 { + /* Skip over anonymous symbols. */ + if (*mangled == '0') + { + do + mangled++; + while (*mangled == '0'); + + continue; + } + if (n++) string_append (decl, "."); - /* Skip over anonymous symbols. */ - while (*mangled == '0') - mangled++; - - mangled = dlang_identifier (decl, mangled, kind); + mangled = dlang_identifier (decl, mangled, info); /* Consume the encoded arguments. However if this is not followed by the - next encoded length, 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. */ + 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 = mangled; int saved = string_length (decl); + /* Save the type modifiers for appending at the end if needed. */ + string_init (&mods); + /* Skip over 'this' parameter and type modifiers. */ if (*mangled == 'M') { mangled++; - mangled = dlang_type_modifiers (decl, mangled); + mangled = dlang_type_modifiers (&mods, mangled); string_setlength (decl, saved); } - /* The rule we expect to match in the mangled string is: + mangled = dlang_function_type_noreturn (decl, NULL, NULL, + mangled, info); + if (suffix_modifiers) + string_appendn (decl, mods.b, string_length (&mods)); - TypeFunctionNoReturn: - CallConvention FuncAttrs Arguments ArgClose - - The calling convention and function attributes are not included - in the demangled string. */ - mangled = dlang_call_convention (decl, mangled); - mangled = dlang_attributes (decl, mangled); - string_setlength (decl, saved); - - string_append (decl, "("); - mangled = dlang_function_args (decl, mangled); - string_append (decl, ")"); - - if (mangled == NULL || !ISDIGIT (*mangled)) + if (mangled == NULL || *mangled == '\0') { /* Did not match the rule we were looking for. */ mangled = start; string_setlength (decl, saved); } + + string_delete (&mods); } } - while (mangled && ISDIGIT (*mangled)); + while (mangled && dlang_symbol_name_p (mangled, info)); return mangled; } @@ -1499,9 +1713,9 @@ dlang_parse_qualified (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) { - long elements; + unsigned long elements; mangled = dlang_number (mangled, &elements); if (mangled == NULL) @@ -1511,7 +1725,7 @@ dlang_parse_tuple (string *decl, const char *mangled) while (elements--) { - mangled = dlang_type (decl, mangled); + mangled = dlang_type (decl, mangled, info); if (mangled == NULL) return NULL; @@ -1523,10 +1737,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; @@ -1550,11 +1825,11 @@ dlang_template_args (string *decl, const char *mangled) { case 'S': /* Symbol parameter. */ mangled++; - mangled = dlang_identifier (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. */ { @@ -1565,18 +1840,41 @@ 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'; - mangled = dlang_value (decl, mangled, name.b, type); + mangled = dlang_value (decl, mangled, name.b, type, info); 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; } @@ -1586,12 +1884,14 @@ 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. @@ -1605,26 +1905,42 @@ dlang_parse_template (string *decl, const char *mangled, long len) */ /* Template symbol. */ - if (!ISDIGIT (mangled[3]) || mangled[3] == '0') + 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. */ @@ -1648,7 +1964,13 @@ dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) } else { - if (dlang_parse_mangle (&decl, mangled, dlang_top_level) == NULL) + struct dlang_info info; + + dlang_demangle_init_info (mangled, strlen (mangled), &info); + mangled = dlang_parse_mangle (&decl, mangled, &info); + + /* Check that the entire symbol was successfully demangled. */ + if (mangled == NULL || *mangled != '\0') string_delete (&decl); } diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/dyn-string.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/dyn-string.c similarity index 99% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/dyn-string.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/dyn-string.c index b8944e7d1a..ea2edd09af 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/dyn-string.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/dyn-string.c @@ -3,7 +3,7 @@ * NOTE: See binutils/include/COPYING3 */ /* An abstract string datatype. - Copyright (C) 1998-2019 Free Software Foundation, Inc. + Copyright (C) 1998-2023 Free Software Foundation, Inc. Contributed by Mark Mitchell (mark@markmitchell.com). This file is part of GNU CC. @@ -281,7 +281,7 @@ dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) for (i = dest->length; i >= pos; --i) dest->s[i + length] = dest->s[i]; /* Splice in the new stuff. */ - strncpy (dest->s + pos, src, length); + memcpy (dest->s + pos, src, length); /* Compute the new length. */ dest->length += length; return 1; diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt.c similarity index 99% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt.c index bcc37ae794..85446e2954 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt.c @@ -1,5 +1,5 @@ /* ### - * IP: GPL 3 + * IP: GPL 3 Linking Permitted * NOTE: See binutils/include/COPYING3 */ /* Getopt for GNU. @@ -7,7 +7,7 @@ "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! - Copyright (C) 1987-2019 Free Software Foundation, Inc. + Copyright (C) 1987-2023 Free Software Foundation, Inc. NOTE: This source is derived from an old version taken from the GNU C Library (glibc). diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt1.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt1.c similarity index 97% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt1.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt1.c index eeb180525f..e5a58089a0 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/getopt1.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/getopt1.c @@ -1,9 +1,9 @@ /* ### - * IP: GPL 3 + * IP: GPL 3 Linking Permitted * NOTE: See binutils/include/COPYING3 */ /* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987-2019 Free Software Foundation, Inc. + Copyright (C) 1987-2023 Free Software Foundation, Inc. NOTE: This source is derived from an old version taken from the GNU C Library (glibc). diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/missing.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/missing.c similarity index 97% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/missing.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/missing.c index 741fce4fee..84bb54e907 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/missing.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/missing.c @@ -28,7 +28,7 @@ CHANGE NOTICE: - This file was created on January 22nd, 2020: + This file was created on October 31st, 2023: -This code was copied and modified from a previous version of libiberty */ diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/rust-demangle.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/rust-demangle.c new file mode 100644 index 0000000000..562d2567f6 --- /dev/null +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/rust-demangle.c @@ -0,0 +1,1608 @@ +/* ### + * IP: LGPL 2.1 + * NOTE: See binutils/libiberty/COPYING.LIB + */ +/* Demangler for the Rust programming language + Copyright (C) 2016-2023 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 +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. +If not, see . */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "safe-ctype.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#else +extern size_t strlen(const char *s); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern void *memset(void *s, int c, size_t n); +#endif + +#include +#include "libiberty.h" + +struct rust_demangler +{ + const char *sym; + size_t sym_len; + + void *callback_opaque; + demangle_callbackref callback; + + /* Position of the next character to read from the symbol. */ + size_t next; + + /* Non-zero if any error occurred. */ + int errored; + + /* Non-zero if nothing should be printed. */ + int skipping_printing; + + /* Non-zero if printing should be verbose (e.g. include hashes). */ + int verbose; + + /* Rust mangling version, with legacy mangling being -1. */ + int version; + + /* Recursion depth. */ + unsigned int recursion; + /* Maximum number of times demangle_path may be called recursively. */ +#define RUST_MAX_RECURSION_COUNT 1024 +#define RUST_NO_RECURSION_LIMIT ((unsigned int) -1) + + uint64_t bound_lifetime_depth; +}; + +/* Parsing functions. */ + +static char +peek (const struct rust_demangler *rdm) +{ + if (rdm->next < rdm->sym_len) + return rdm->sym[rdm->next]; + return 0; +} + +static int +eat (struct rust_demangler *rdm, char c) +{ + if (peek (rdm) == c) + { + rdm->next++; + return 1; + } + else + return 0; +} + +static char +next (struct rust_demangler *rdm) +{ + char c = peek (rdm); + if (!c) + rdm->errored = 1; + else + rdm->next++; + return c; +} + +static uint64_t +parse_integer_62 (struct rust_demangler *rdm) +{ + char c; + uint64_t x; + + if (eat (rdm, '_')) + return 0; + + x = 0; + while (!eat (rdm, '_') && !rdm->errored) + { + 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; +} + +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); +} + +static uint64_t +parse_disambiguator (struct rust_demangler *rdm) +{ + return parse_opt_integer_62 (rdm, 's'); +} + +static size_t +parse_hex_nibbles (struct rust_demangler *rdm, uint64_t *value) +{ + char c; + size_t hex_len; + + hex_len = 0; + *value = 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 hex_len; +} + +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 +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) +{ + char c = 0; + size_t escape_len = 0; + int lo_nibble = -1, hi_nibble = -1; + + if (len < 3 || e[0] != '$') + return 0; + + 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; + + *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 *)malloc (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 *)realloc (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; + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + goto fail_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)) + goto fail_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: + goto fail_return; + } + goto pass_return; + + fail_return: + rdm->errored = 1; + pass_return: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +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; + } + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + { + rdm->errored = 1; + -- rdm->recursion; + 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); + } + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +/* 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 +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 (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + { + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + rdm->errored = 1; + goto end_of_func; + } + } + + 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); + + end_of_func: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; + + return open; +} + +static void +demangle_dyn_trait (struct rust_demangler *rdm) +{ + int open; + struct rust_mangled_ident name; + + if (rdm->errored) + return; + + 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 (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + goto fail_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; + } + goto pass_return; + } + + ty_tag = next (rdm); + switch (ty_tag) + { + /* Placeholder. */ + case 'p': + PRINT ("_"); + goto pass_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: + goto fail_return; + } + + if (!rdm->errored && rdm->verbose) + { + PRINT (": "); + PRINT (basic_type (ty_tag)); + } + goto pass_return; + + fail_return: + rdm->errored = 1; + pass_return: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +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. */ + char c = value; + print_str (rdm, &c, 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 +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) +{ + 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.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0; + rdm.bound_lifetime_depth = 0; + + /* 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; + + /* 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++) + { + /* Rust v0 symbols can have '.' suffixes, ignore those. */ + if (rdm.version == 0 && *p == '.') + break; + + rdm.sym_len++; + + if (*p == '_' || ISALNUM (*p)) + continue; + + /* Legacy Rust symbols can also contain [.:$] characters. + Or @ in the .suffix (which will be skipped, see below). */ + if (rdm.version == -1 && (*p == '$' || *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. But can be followed by a + .suffix (which we want to ignore). */ + int dot_suffix = 1; + while (rdm.sym_len > 0 && + !(dot_suffix && rdm.sym[rdm.sym_len - 1] == 'E')) + { + dot_suffix = rdm.sym[rdm.sym_len - 1] == '.'; + rdm.sym_len--; + } + + 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 *)realloc (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); + + if (!success) + { + free (out.ptr); + return NULL; + } + + str_buf_append (&out, "\0", 1); + return out.ptr; +} diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/safe-ctype.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/safe-ctype.c similarity index 99% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/safe-ctype.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/safe-ctype.c index 38815a628a..85d4848099 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/safe-ctype.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/safe-ctype.c @@ -1,10 +1,10 @@ /* ### * IP: LGPL 2.1 - * NOTE: See binutils/include/COPYING + * NOTE: See binutils/libiberty/COPYING.LIB */ /* replacement macros. - Copyright (C) 2000-2019 Free Software Foundation, Inc. + Copyright (C) 2000-2023 Free Software Foundation, Inc. Contributed by Zack Weinberg . This file is part of the libiberty library. diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/xexit.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/xexit.c similarity index 96% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/xexit.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/xexit.c index 8b41bb3e85..56438dbe9c 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/xexit.c +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/xexit.c @@ -3,7 +3,7 @@ * NOTE: See binutils/libiberty/COPYING.LIB */ /* xexit.c -- Run any exit handlers, then exit. - Copyright (C) 1994-2019 Free Software Foundation, Inc. + Copyright (C) 1994-2023 Free Software Foundation, Inc. This file is part of the libiberty library. Libiberty is free software; you can redistribute it and/or diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/xstrdup.c b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/xstrdup.c similarity index 100% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/c/xstrdup.c rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/xstrdup.c diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/ansidecl.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/ansidecl.h similarity index 79% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/ansidecl.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/ansidecl.h index 7119fb8abf..421303b1ef 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/ansidecl.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/ansidecl.h @@ -2,8 +2,8 @@ * IP: LGPL 2.1 * NOTE: See binutils/include/COPYING */ -/* ANSI and traditional C compatability macros - Copyright (C) 1991-2019 Free Software Foundation, Inc. +/* Compiler compatibility macros + Copyright (C) 1991-2023 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 @@ -20,18 +20,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -/* ANSI and traditional C compatibility macros - - ANSI C is assumed if __STDC__ is #defined. - - Macro ANSI C definition Traditional C definition - ----- ---- - ---------- ----------- - ---------- - PTR `void *' `char *' - const not defined `' - volatile not defined `' - signed not defined `' - - For ease of writing code which uses GCC extensions but needs to be +/* For ease of writing code which uses GCC extensions but needs to be portable to other compilers, we provide the GCC_VERSION macro that simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various wrappers around __attribute__. Also, __extension__ will be #defined @@ -66,24 +55,10 @@ So instead we use the macro below and test it against specific values. */ #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) #endif /* GCC_VERSION */ -#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) -/* All known AIX compilers implement these things (but don't always - define __STDC__). The RISC/OS MIPS compiler defines these things - in SVR4 mode, but does not define __STDC__. */ -/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other - C++ compilers, does not define __STDC__, though it acts as if this - was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ - -#define PTR void * - -#undef const -#undef volatile -#undef signed - /* inline requires special treatment; it's in C99, and GCC >=2.7 supports it too, but it's not in C89. */ #undef inline -#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) +#if (!defined(__cplusplus) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) /* it's a keyword */ #else # if GCC_VERSION >= 2007 @@ -93,22 +68,6 @@ So instead we use the macro below and test it against specific values. */ # endif #endif -#else /* Not ANSI C. */ - -#define PTR char * - -/* some systems define these in header files for non-ansi mode */ -#undef const -#undef volatile -#undef signed -#undef inline -#define const -#define volatile -#define signed -#define inline - -#endif /* ANSI C. */ - /* Define macros for some gcc attributes. This permits us to use the macros freely, and know that they will come into play for the version of gcc in which they are supported. */ @@ -296,6 +255,40 @@ So instead we use the macro below and test it against specific values. */ # 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. */ @@ -326,53 +319,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 +#if defined(__cplusplus) && __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 - (B) allow the compiler to issue a warning if it isn't (e.g. a mismatch - of the type signature). - - Similarly, it allows us to add a "final" to indicate that no subclass - may subsequently override the vfunc. - - Provide OVERRIDE and FINAL as macros, allowing us to get these benefits - when compiling with C++11 support, but without requiring C++11. - - For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables - this by default (actually GNU++14). */ - -#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 __final -# else - /* No C++11 support; leave the macros empty. */ -# define OVERRIDE -# define FINAL -# endif -#else - /* 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. @@ -389,7 +341,7 @@ So instead we use the macro below and test it against specific values. */ so that most attempts at copy are caught at compile-time. */ -#if __cplusplus >= 201103 +#if defined(__cplusplus) && __cplusplus >= 201103 #define DISABLE_COPY_AND_ASSIGN(TYPE) \ TYPE (const TYPE&) = delete; \ void operator= (const TYPE &) = delete diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/cp-demangle.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/cp-demangle.h similarity index 94% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/cp-demangle.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/cp-demangle.h index 8b2545e6f1..e60b3925d1 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/cp-demangle.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/cp-demangle.h @@ -1,9 +1,9 @@ /* ### - * IP: GPL 3 Linking Permitted - * NOTE: See binutils/libiberty/COPYING.LIB; Used GPL 3 from this file's header + * IP: LGPL 2.1 + * NOTE: See binutils/include/COPYING */ /* Internal demangler interface for g++ V3 ABI. - Copyright (C) 2003-2019 Free Software Foundation, Inc. + Copyright (C) 2003-2023 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of the libiberty library, which is part of GCC. @@ -126,6 +126,10 @@ 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; @@ -180,7 +184,7 @@ d_advance (struct d_info *di, int i) extern const struct demangle_operator_info cplus_demangle_operators[]; #endif -#define D_BUILTIN_TYPE_COUNT (34) +#define D_BUILTIN_TYPE_COUNT (36) CP_STATIC_IF_GLIBCPP_V3 const struct demangle_builtin_type_info diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/demangle.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/demangle.h similarity index 95% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/demangle.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/demangle.h index 03fec28933..280c230f72 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/demangle.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/demangle.h @@ -3,7 +3,7 @@ * NOTE: See binutils/include/COPYING */ /* Defs for interface to demanglers. - Copyright (C) 1992-2019 Free Software Foundation, Inc. + Copyright (C) 1992-2023 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 @@ -163,24 +163,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); +rust_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); -/* 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. */ extern char * rust_demangle (const char *mangled, int options); @@ -425,6 +412,9 @@ enum demangle_component_type number which involves neither modifying the mangled string nor allocating a new copy of the literal in memory. */ DEMANGLE_COMPONENT_LITERAL_NEG, + /* A vendor's builtin expression. The left subtree holds the + expression's name, and the right subtree is a argument list. */ + DEMANGLE_COMPONENT_VENDOR_EXPR, /* A libgcj compiled resource. The left subtree is the name of the resource. */ DEMANGLE_COMPONENT_JAVA_RESOURCE, @@ -463,7 +453,25 @@ enum demangle_component_type /* A cloned function. */ DEMANGLE_COMPONENT_CLONE, DEMANGLE_COMPONENT_NOEXCEPT, - DEMANGLE_COMPONENT_THROW_SPEC + DEMANGLE_COMPONENT_THROW_SPEC, + + DEMANGLE_COMPONENT_STRUCTURED_BINDING, + + DEMANGLE_COMPONENT_MODULE_NAME, + DEMANGLE_COMPONENT_MODULE_PARTITION, + DEMANGLE_COMPONENT_MODULE_ENTITY, + DEMANGLE_COMPONENT_MODULE_INIT, + + DEMANGLE_COMPONENT_TEMPLATE_HEAD, + DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM, + + /* A builtin type with argument. This holds the builtin type + information. */ + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE + }; /* Types which are only used internally. */ @@ -485,6 +493,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 { @@ -549,6 +558,15 @@ struct demangle_component const struct demangle_builtin_type_info *type; } s_builtin; + /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + short arg; + char suffix; + } s_extended_builtin; + /* For DEMANGLE_COMPONENT_SUB_STD. */ struct { diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/dyn-string.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/dyn-string.h similarity index 97% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/dyn-string.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/dyn-string.h index 1c7c61ea03..5cff8e3358 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/dyn-string.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/dyn-string.h @@ -3,7 +3,7 @@ * NOTE: See binutils/include/COPYING3 */ /* An abstract string datatype. - Copyright (C) 1998-2019 Free Software Foundation, Inc. + Copyright (C) 1998-2023 Free Software Foundation, Inc. Contributed by Mark Mitchell (mark@markmitchell.com). This file is part of GCC. diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/getopt.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/getopt.h similarity index 98% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/getopt.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/getopt.h index 24c199c1a5..44b8a7e4f5 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/getopt.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/getopt.h @@ -3,7 +3,7 @@ * NOTE: See binutils/include/COPYING3 */ /* Declarations for getopt. - Copyright (C) 1989-2019 Free Software Foundation, Inc. + Copyright (C) 1989-2023 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/libiberty.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/libiberty.h similarity index 97% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/libiberty.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/libiberty.h index c64f913da7..c5d8ee3b77 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/libiberty.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/libiberty.h @@ -4,7 +4,7 @@ */ /* Function declarations for libiberty. - Copyright (C) 1997-2019 Free Software Foundation, Inc. + Copyright (C) 1997-2023 Free Software Foundation, Inc. Note - certain prototypes declared in this header file are for functions whoes implementation copyright does not belong to the @@ -141,6 +141,10 @@ extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRI extern char *lrealpath (const char *); +/* Return true when FD file descriptor exists. */ + +extern int is_valid_fd (int fd); + /* Concatenate an arbitrary number of strings. You must pass NULL as the last argument of this function, to terminate the list of strings. Allocates memory using xmalloc. */ @@ -314,30 +318,30 @@ extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN; message to stderr (using the name set by xmalloc_set_program_name, if any) and then call xexit. */ -extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; +extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1 ATTRIBUTE_WARN_UNUSED_RESULT; /* Reallocate memory without fail. This works like xmalloc. Note, realloc type functions are not suitable for attribute malloc since they may return the same address across multiple calls. */ -extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL; +extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_2 ATTRIBUTE_WARN_UNUSED_RESULT; /* Allocate memory without fail and set it to zero. This works like xmalloc. */ -extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; +extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1_2 ATTRIBUTE_WARN_UNUSED_RESULT; /* Copy a string into a memory buffer without fail. */ -extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; +extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; /* Copy at most N characters from string into a buffer without fail. */ -extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; +extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; /* Copy an existing memory buffer to a new memory buffer without fail. */ -extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; +extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; /* Physical memory routines. Return values are in BYTES. */ extern double physmem_total (void); @@ -641,6 +645,13 @@ extern int pexecute (const char *, char * const *, const char *, extern int pwait (int, int *, int); +/* Like bsearch, but takes and passes on an argument like qsort_r. */ + +extern void *bsearch_r (const void *, const void *, + size_t, size_t, + int (*)(const void *, const void *, void *), + void *); + #if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF /* Like sprintf but provides a pointer to malloc'd storage, which must be freed by the caller. */ @@ -653,7 +664,7 @@ extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2; extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1; -#if !HAVE_DECL_VASPRINTF +#if defined(HAVE_DECL_VASPRINTF) && !HAVE_DECL_VASPRINTF /* Like vsprintf but provides a pointer to malloc'd storage, which must be freed by the caller. */ @@ -706,11 +717,6 @@ extern unsigned long long int strtoull (const char *nptr, char **endptr, int base); #endif -#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP -/* Compare version strings. */ -extern int strverscmp (const char *, const char *); -#endif - /* Set the title of a process */ extern void setproctitle (const char *name, ...); diff --git a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/safe-ctype.h b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/safe-ctype.h similarity index 98% rename from GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/safe-ctype.h rename to GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/safe-ctype.h index eb216a1729..035b745d04 100644 --- a/GPL/DemanglerGnu/src/demangler_gnu_v2_33_1/headers/safe-ctype.h +++ b/GPL/DemanglerGnu/src/demangler_gnu_v2_41/headers/safe-ctype.h @@ -4,7 +4,7 @@ */ /* replacement macros. - Copyright (C) 2000-2019 Free Software Foundation, Inc. + Copyright (C) 2000-2023 Free Software Foundation, Inc. Contributed by Zack Weinberg . This file is part of the libiberty library. diff --git a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm index a02bd3981b..780b09b3a2 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm @@ -441,7 +441,7 @@

Use Deprecated Demangler - By default, GCC symbols will be demangled using the most up-to-date demangler - that Ghidra contains (version 2.33.1 as of this writing). Turning this + that Ghidra contains (version 2.41 as of this writing). Turning this option on will invoke the now deprecated version of the demangler (version 2.24).

@@ -457,7 +457,7 @@

  • <GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/os/<OS>/ - demangler_gnu_v2_33_1
  • + demangler_gnu_v2_41
  • <GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/os/<OS>/ demangler_gnu_v2_24
  • diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java index 7ba4275019..d68b3a8f6f 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerOptions.java @@ -34,14 +34,15 @@ public class GnuDemanglerOptions extends DemanglerOptions { public static final String GNU_DEMANGLER_V2_24 = "demangler_gnu_v2_24"; /** - * Version 2.33.1 of the GNU demangler. This version supports less formats than older versions. + * Version 2.41 of the GNU demangler. This version supports less formats than + * {@link #GNU_DEMANGLER_V2_24}. */ - public static final String GNU_DEMANGLER_V2_33_1 = "demangler_gnu_v2_33_1"; + public static final String GNU_DEMANGLER_V2_41 = "demangler_gnu_v2_41"; /** * The default version to use of the GNU demangler */ - public static final String GNU_DEMANGLER_DEFAULT = GNU_DEMANGLER_V2_33_1; + public static final String GNU_DEMANGLER_DEFAULT = GNU_DEMANGLER_V2_41; private final GnuDemanglerFormat format; private final boolean isDeprecated; @@ -112,7 +113,7 @@ public class GnuDemanglerOptions extends DemanglerOptions { * @return the name */ public String getDemanglerName() { - return isDeprecated ? GNU_DEMANGLER_V2_24 : GNU_DEMANGLER_V2_33_1; + return isDeprecated ? GNU_DEMANGLER_V2_24 : GNU_DEMANGLER_V2_41; } /** diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java index 5a66637191..f56bf27726 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java @@ -320,6 +320,22 @@ public class GnuDemanglerParser { */ private static final Pattern LITERAL_NUMBER_PATTERN = Pattern.compile("-*\\d+[ul]{0,1}"); + /** + * Pattern to identify a legacy rust string that contains its hash id suffix and capture the + * non-hash portion. + * + * Legacy mangled rust symbols: + * - start with _ZN + * - end withe E or E. + * - have a 16 digit hash that starts with 17h + * + * The demangled string has the leading '17' and trailing 'E|E.' removed. + * + * Sample: std::io::Read::read_to_end::hb85a0f6802e14499 + */ + private static final Pattern RUST_LEGACY_SUFFIX_PATTERN = + Pattern.compile("(.*)::h[0-9a-f]{16}"); + private String mangledSource; private String demangledSource; @@ -333,6 +349,8 @@ public class GnuDemanglerParser { */ public DemangledObject parse(String mangled, String demangled) throws DemanglerParseException { + demangled = cleanupRustLegacySymbol(demangled); + this.mangledSource = mangled; this.demangledSource = demangled; @@ -465,6 +483,14 @@ public class GnuDemanglerParser { return function; } + private String cleanupRustLegacySymbol(String demangled) { + Matcher m = RUST_LEGACY_SUFFIX_PATTERN.matcher(demangled); + if (m.matches()) { + return m.group(1); + } + return demangled; + } + private void setReturnType(String demangled, DemangledFunction function, String returnType) { String updatedReturnType = returnType; diff --git a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java index 1922a5c323..e03c6375c4 100644 --- a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java +++ b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java @@ -33,7 +33,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { @Before public void setUp() throws Exception { process = GnuDemanglerNativeProcess - .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1); + .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_41); parser = new GnuDemanglerParser(); } @@ -1025,12 +1025,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String demangled = process.demangle(mangled); /* - typeinfo for - std::__ndk1::__function::__func< - dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}, - std::__ndk1::allocator<{lambda(dummy::it::other::Namespace*)#1}>, - int (dummy::it::other::Namespace*) - > + typeinfo for + std::__ndk1::__function::__func< + dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}, + std::__ndk1::allocator, + int (dummy::it::other::Namespace*)> '__func' has 3 template parameters, the operator and the allocator @@ -1042,7 +1041,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String lambdaOperator = dummyNs + "::function(float)::$_2::operator()(" + dummyNsP + ")const::" + lambda; - String lambdaAllocator = "std::__ndk1::allocator<" + lambda + ">"; + String lambdaAllocator = "std::__ndk1::allocator<" + lambdaOperator + ">"; String thirdParam = "int(" + dummyNsP + ")"; String infoNs = "std::__ndk1::__function::"; @@ -1092,7 +1091,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String signature = object.getSignature(false); assertEquals( - "undefined std::__array_traits,4ul>::_S_ref(LayerDetails::LayerBase::initRandom(long,long) const::{lambda(long&, unsigned int)#1} const &[],unsigned long)", + "undefined std::__array_traits,4ul>::_S_ref(LayerDetails::RandomProviderT const &[],unsigned long)", signature); } @@ -1163,6 +1162,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { lambda contents - lambdas in templates and as a parameter + Note: the demangled string makes use of the 'auto' parameter keyword + bool (*** const* std:: __addressof< @@ -1196,7 +1197,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String signature = object.getSignature(false); assertEquals( - "undefined Bedrock::Threading::TLSDetail::DefaultConstructor::create()::{lambda(bool(***const*std::__addressof::create()::{lambda(bool(***const)(AssertHandlerContext_const&))#1}>(Bedrock::Threading::TLSDetail::DefaultConstructor::create()::{lambda(bool(***const&)(AssertHandlerContext_const&))#1}))(AssertHandlerContext_const&))#1}", + "undefined Bedrock::Threading::TLSDetail::DefaultConstructor::create()::{lambda(bool(***const*std::__addressof::create()::{lambda(bool(***const)(AssertHandlerContext_const&))#1}>(auto:1&))(AssertHandlerContext_const&))#1}", signature); } @@ -1997,7 +1998,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { String signature = object.getSignature(false); assertEquals( - "int LayerDetails::RandomProviderT::operator()(LayerDetails::RandomProviderT::operator() const &[])", + "int LayerDetails::RandomProviderT::operator()(int const &[])", signature); } @@ -2140,6 +2141,34 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { new DemangledDataType("fake", "fake", DemangledDataType.LONG_LONG).getDataType(null)); } + @Test + public void testRustLegacyHashIsIgnored() throws Exception { + + // + // Mangled: _ZN3std2io4Read11read_to_end17hb85a0f6802e14499E + // + // Demangled: std::io::Read::read_to_end::hb85a0f6802e14499 + // + // Parsed: std::io::Read::read_to_end + // + // Legacy mangled rust symbols: + // - start with _ZN + // - end withe E or E. + // - have a 16 digit hash that starts with 17h + // + String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E"; + String demangled = process.demangle(mangled); + + assertEquals(demangled, "std::io::Read::read_to_end::hb85a0f6802e14499"); + + DemangledObject object = parser.parse(mangled, demangled); + assertNotNull(object); + assertType(object, DemangledVariable.class); + + String signature = object.getSignature(false); + assertEquals("std::io::Read::read_to_end", signature); + } + private void assertType(Demangled o, Class c) { assertTrue("Wrong demangled type. " + "\nExpected " + c + "; " + "\nfound " + o.getClass(), c.isInstance(o));