├── README.md ├── xllvmdemangler.pri ├── LICENSE └── 3rdparty └── llvm └── Demangle ├── Demangle.cpp ├── _Demangle.cpp ├── DemangleConfig.h ├── StringView.h ├── Demangle.h ├── _Demangle.h ├── Utility.h ├── MicrosoftDemangle.h ├── ItaniumDemangle.cpp ├── MicrosoftDemangleNodes.h ├── MicrosoftDemangleNodes.cpp └── MicrosoftDemangle.cpp /README.md: -------------------------------------------------------------------------------- 1 | # XLLVMDemangler 2 | -------------------------------------------------------------------------------- /xllvmdemangler.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD/3rdparty 2 | DEPENDPATH += $$PWD/3rdparty 3 | 4 | CONFIG += c++14 # TODO Check !!! 5 | 6 | HEADERS += \ 7 | $$PWD/3rdparty/llvm/Demangle/_Demangle.h \ 8 | $$PWD/3rdparty/llvm/Demangle/DemangleConfig.h \ 9 | $$PWD/3rdparty/llvm/Demangle/ItaniumDemangle.h \ 10 | $$PWD/3rdparty/llvm/Demangle/MicrosoftDemangle.h \ 11 | $$PWD/3rdparty/llvm/Demangle/MicrosoftDemangleNodes.h \ 12 | $$PWD/3rdparty/llvm/Demangle/StringView.h \ 13 | $$PWD/3rdparty/llvm/Demangle/Utility.h 14 | 15 | SOURCES += \ 16 | $$PWD/3rdparty/llvm/Demangle/_Demangle.cpp \ 17 | $$PWD/3rdparty/llvm/Demangle/ItaniumDemangle.cpp \ 18 | $$PWD/3rdparty/llvm/Demangle/MicrosoftDemangle.cpp \ 19 | $$PWD/3rdparty/llvm/Demangle/MicrosoftDemangleNodes.cpp 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2025 hors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/Demangle.cpp: -------------------------------------------------------------------------------- 1 | //===-- Demangle.cpp - Common demangling functions ------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | /// 9 | /// \file This file contains definitions of common demangling functions. 10 | /// 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "llvm/Demangle/Demangle.h" 14 | #include 15 | 16 | static bool isItaniumEncoding(const std::string &MangledName) { 17 | size_t Pos = MangledName.find_first_not_of('_'); 18 | // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'. 19 | return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z'; 20 | } 21 | 22 | std::string llvm::demangle(const std::string &MangledName) { 23 | char *Demangled; 24 | if (isItaniumEncoding(MangledName)) 25 | Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); 26 | else 27 | Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, 28 | nullptr, nullptr); 29 | 30 | if (!Demangled) 31 | return MangledName; 32 | 33 | std::string Ret = Demangled; 34 | std::free(Demangled); 35 | return Ret; 36 | } 37 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/_Demangle.cpp: -------------------------------------------------------------------------------- 1 | //===-- Demangle.cpp - Common demangling functions ------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | /// 9 | /// \file This file contains definitions of common demangling functions. 10 | /// 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "llvm/Demangle/Demangle.h" 14 | #include 15 | 16 | static bool isItaniumEncoding(const std::string &MangledName) { 17 | size_t Pos = MangledName.find_first_not_of('_'); 18 | // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'. 19 | return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z'; 20 | } 21 | 22 | std::string llvm::demangle(const std::string &MangledName) { 23 | char *Demangled; 24 | if (isItaniumEncoding(MangledName)) 25 | Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); 26 | else 27 | Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, 28 | nullptr, nullptr); 29 | 30 | if (!Demangled) 31 | return MangledName; 32 | 33 | std::string Ret = Demangled; 34 | std::free(Demangled); 35 | return Ret; 36 | } 37 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/DemangleConfig.h: -------------------------------------------------------------------------------- 1 | //===--- DemangleConfig.h ---------------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains a variety of feature test macros copied from 10 | // include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take 11 | // a dependency on LLVMSupport. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H 16 | #define LLVM_DEMANGLE_DEMANGLECONFIG_H 17 | 18 | #ifndef __has_feature 19 | #define __has_feature(x) 0 20 | #endif 21 | 22 | #ifndef __has_cpp_attribute 23 | #define __has_cpp_attribute(x) 0 24 | #endif 25 | 26 | #ifndef __has_attribute 27 | #define __has_attribute(x) 0 28 | #endif 29 | 30 | #ifndef __has_builtin 31 | #define __has_builtin(x) 0 32 | #endif 33 | 34 | #ifndef DEMANGLE_GNUC_PREREQ 35 | #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) 36 | #define DEMANGLE_GNUC_PREREQ(maj, min, patch) \ 37 | ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ 38 | ((maj) << 20) + ((min) << 10) + (patch)) 39 | #elif defined(__GNUC__) && defined(__GNUC_MINOR__) 40 | #define DEMANGLE_GNUC_PREREQ(maj, min, patch) \ 41 | ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) 42 | #else 43 | #define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0 44 | #endif 45 | #endif 46 | 47 | #if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0) 48 | #define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__)) 49 | #else 50 | #define DEMANGLE_ATTRIBUTE_USED 51 | #endif 52 | 53 | #if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0) 54 | #define DEMANGLE_UNREACHABLE __builtin_unreachable() 55 | #elif defined(_MSC_VER) 56 | #define DEMANGLE_UNREACHABLE __assume(false) 57 | #else 58 | #define DEMANGLE_UNREACHABLE 59 | #endif 60 | 61 | #if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0) 62 | #define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline)) 63 | #elif defined(_MSC_VER) 64 | #define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline) 65 | #else 66 | #define DEMANGLE_ATTRIBUTE_NOINLINE 67 | #endif 68 | 69 | #if !defined(NDEBUG) 70 | #define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED 71 | #else 72 | #define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE 73 | #endif 74 | 75 | #if __cplusplus > 201402L && __has_cpp_attribute(fallthrough) 76 | #define DEMANGLE_FALLTHROUGH [[fallthrough]] 77 | #elif __has_cpp_attribute(gnu::fallthrough) 78 | #define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]] 79 | #elif !__cplusplus 80 | // Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious 81 | // error when __has_cpp_attribute is given a scoped attribute in C mode. 82 | #define DEMANGLE_FALLTHROUGH 83 | #elif __has_cpp_attribute(clang::fallthrough) 84 | #define DEMANGLE_FALLTHROUGH [[clang::fallthrough]] 85 | #else 86 | #define DEMANGLE_FALLTHROUGH 87 | #endif 88 | 89 | #define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle { 90 | #define DEMANGLE_NAMESPACE_END } } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/StringView.h: -------------------------------------------------------------------------------- 1 | //===--- StringView.h -------------------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // FIXME: Use std::string_view instead when we support C++17. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef LLVM_DEMANGLE_STRINGVIEW_H 14 | #define LLVM_DEMANGLE_STRINGVIEW_H 15 | 16 | #include "DemangleConfig.h" 17 | #include 18 | #include 19 | #include 20 | 21 | DEMANGLE_NAMESPACE_BEGIN 22 | 23 | class StringView { 24 | const char *First; 25 | const char *Last; 26 | 27 | public: 28 | static const size_t npos = ~size_t(0); 29 | 30 | template 31 | StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} 32 | StringView(const char *First_, const char *Last_) 33 | : First(First_), Last(Last_) {} 34 | StringView(const char *First_, size_t Len) 35 | : First(First_), Last(First_ + Len) {} 36 | StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} 37 | StringView() : First(nullptr), Last(nullptr) {} 38 | 39 | StringView substr(size_t From) const { 40 | return StringView(begin() + From, size() - From); 41 | } 42 | 43 | size_t find(char C, size_t From = 0) const { 44 | size_t FindBegin = std::min(From, size()); 45 | // Avoid calling memchr with nullptr. 46 | if (FindBegin < size()) { 47 | // Just forward to memchr, which is faster than a hand-rolled loop. 48 | if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) 49 | return size_t(static_cast(P) - First); 50 | } 51 | return npos; 52 | } 53 | 54 | StringView substr(size_t From, size_t To) const { 55 | if (To >= size()) 56 | To = size() - 1; 57 | if (From >= size()) 58 | From = size() - 1; 59 | return StringView(First + From, First + To); 60 | } 61 | 62 | StringView dropFront(size_t N = 1) const { 63 | if (N >= size()) 64 | N = size(); 65 | return StringView(First + N, Last); 66 | } 67 | 68 | StringView dropBack(size_t N = 1) const { 69 | if (N >= size()) 70 | N = size(); 71 | return StringView(First, Last - N); 72 | } 73 | 74 | char front() const { 75 | assert(!empty()); 76 | return *begin(); 77 | } 78 | 79 | char back() const { 80 | assert(!empty()); 81 | return *(end() - 1); 82 | } 83 | 84 | char popFront() { 85 | assert(!empty()); 86 | return *First++; 87 | } 88 | 89 | bool consumeFront(char C) { 90 | if (!startsWith(C)) 91 | return false; 92 | *this = dropFront(1); 93 | return true; 94 | } 95 | 96 | bool consumeFront(StringView S) { 97 | if (!startsWith(S)) 98 | return false; 99 | *this = dropFront(S.size()); 100 | return true; 101 | } 102 | 103 | bool startsWith(char C) const { return !empty() && *begin() == C; } 104 | 105 | bool startsWith(StringView Str) const { 106 | if (Str.size() > size()) 107 | return false; 108 | return std::equal(Str.begin(), Str.end(), begin()); 109 | } 110 | 111 | const char &operator[](size_t Idx) const { return *(begin() + Idx); } 112 | 113 | const char *begin() const { return First; } 114 | const char *end() const { return Last; } 115 | size_t size() const { return static_cast(Last - First); } 116 | bool empty() const { return First == Last; } 117 | }; 118 | 119 | inline bool operator==(const StringView &LHS, const StringView &RHS) { 120 | return LHS.size() == RHS.size() && 121 | std::equal(LHS.begin(), LHS.end(), RHS.begin()); 122 | } 123 | 124 | DEMANGLE_NAMESPACE_END 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/Demangle.h: -------------------------------------------------------------------------------- 1 | //===--- Demangle.h ---------------------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #ifndef LLVM_DEMANGLE_DEMANGLE_H 10 | #define LLVM_DEMANGLE_DEMANGLE_H 11 | 12 | #include 13 | #include 14 | 15 | namespace llvm { 16 | /// This is a llvm local version of __cxa_demangle. Other than the name and 17 | /// being in the llvm namespace it is identical. 18 | /// 19 | /// The mangled_name is demangled into buf and returned. If the buffer is not 20 | /// large enough, realloc is used to expand it. 21 | /// 22 | /// The *status will be set to a value from the following enumeration 23 | enum : int { 24 | demangle_unknown_error = -4, 25 | demangle_invalid_args = -3, 26 | demangle_invalid_mangled_name = -2, 27 | demangle_memory_alloc_failure = -1, 28 | demangle_success = 0, 29 | }; 30 | 31 | char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, 32 | int *status); 33 | 34 | 35 | enum MSDemangleFlags { 36 | MSDF_None = 0, 37 | MSDF_DumpBackrefs = 1 << 0, 38 | MSDF_NoAccessSpecifier = 1 << 1, 39 | MSDF_NoCallingConvention = 1 << 2, 40 | MSDF_NoReturnType = 1 << 3, 41 | MSDF_NoMemberType = 1 << 4, 42 | }; 43 | 44 | /// Demangles the Microsoft symbol pointed at by mangled_name and returns it. 45 | /// Returns a pointer to the start of a null-terminated demangled string on 46 | /// success, or nullptr on error. 47 | /// If n_read is non-null and demangling was successful, it receives how many 48 | /// bytes of the input string were consumed. 49 | /// buf can point to a *n_buf bytes large buffer where the demangled name is 50 | /// stored. If the buffer is too small, it is grown with realloc(). If buf is 51 | /// nullptr, then this malloc()s memory for the result. 52 | /// *n_buf stores the size of buf on input if buf is non-nullptr, and it 53 | /// receives the size of the demangled string on output if n_buf is not nullptr. 54 | /// status receives one of the demangle_ enum entries above if it's not nullptr. 55 | /// Flags controls various details of the demangled representation. 56 | char *microsoftDemangle(const char *mangled_name, size_t *n_read, 57 | char *buf, size_t *n_buf, 58 | int *status, MSDemangleFlags Flags = MSDF_None); 59 | 60 | /// Attempt to demangle a string using different demangling schemes. 61 | /// The function uses heuristics to determine which demangling scheme to use. 62 | /// \param MangledName - reference to string to demangle. 63 | /// \returns - the demangled string, or a copy of the input string if no 64 | /// demangling occurred. 65 | std::string demangle(const std::string &MangledName); 66 | 67 | /// "Partial" demangler. This supports demangling a string into an AST 68 | /// (typically an intermediate stage in itaniumDemangle) and querying certain 69 | /// properties or partially printing the demangled name. 70 | struct ItaniumPartialDemangler { 71 | ItaniumPartialDemangler(); 72 | 73 | ItaniumPartialDemangler(ItaniumPartialDemangler &&Other); 74 | ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other); 75 | 76 | /// Demangle into an AST. Subsequent calls to the rest of the member functions 77 | /// implicitly operate on the AST this produces. 78 | /// \return true on error, false otherwise 79 | bool partialDemangle(const char *MangledName); 80 | 81 | /// Just print the entire mangled name into Buf. Buf and N behave like the 82 | /// second and third parameters to itaniumDemangle. 83 | char *finishDemangle(char *Buf, size_t *N) const; 84 | 85 | /// Get the base name of a function. This doesn't include trailing template 86 | /// arguments, ie for "a::b" this function returns "b". 87 | char *getFunctionBaseName(char *Buf, size_t *N) const; 88 | 89 | /// Get the context name for a function. For "a::b::c", this function returns 90 | /// "a::b". 91 | char *getFunctionDeclContextName(char *Buf, size_t *N) const; 92 | 93 | /// Get the entire name of this function. 94 | char *getFunctionName(char *Buf, size_t *N) const; 95 | 96 | /// Get the parameters for this function. 97 | char *getFunctionParameters(char *Buf, size_t *N) const; 98 | char *getFunctionReturnType(char *Buf, size_t *N) const; 99 | 100 | /// If this function has any any cv or reference qualifiers. These imply that 101 | /// the function is a non-static member function. 102 | bool hasFunctionQualifiers() const; 103 | 104 | /// If this symbol describes a constructor or destructor. 105 | bool isCtorOrDtor() const; 106 | 107 | /// If this symbol describes a function. 108 | bool isFunction() const; 109 | 110 | /// If this symbol describes a variable. 111 | bool isData() const; 112 | 113 | /// If this symbol is a . These are generally implicitly 114 | /// generated by the implementation, such as vtables and typeinfo names. 115 | bool isSpecialName() const; 116 | 117 | ~ItaniumPartialDemangler(); 118 | private: 119 | void *RootNode; 120 | void *Context; 121 | }; 122 | } // namespace llvm 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/_Demangle.h: -------------------------------------------------------------------------------- 1 | //===--- Demangle.h ---------------------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #ifndef LLVM_DEMANGLE_DEMANGLE_H 10 | #define LLVM_DEMANGLE_DEMANGLE_H 11 | 12 | #include 13 | #include 14 | 15 | namespace llvm { 16 | /// This is a llvm local version of __cxa_demangle. Other than the name and 17 | /// being in the llvm namespace it is identical. 18 | /// 19 | /// The mangled_name is demangled into buf and returned. If the buffer is not 20 | /// large enough, realloc is used to expand it. 21 | /// 22 | /// The *status will be set to a value from the following enumeration 23 | enum : int { 24 | demangle_unknown_error = -4, 25 | demangle_invalid_args = -3, 26 | demangle_invalid_mangled_name = -2, 27 | demangle_memory_alloc_failure = -1, 28 | demangle_success = 0, 29 | }; 30 | 31 | char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, 32 | int *status); 33 | 34 | 35 | enum MSDemangleFlags { 36 | MSDF_None = 0, 37 | MSDF_DumpBackrefs = 1 << 0, 38 | MSDF_NoAccessSpecifier = 1 << 1, 39 | MSDF_NoCallingConvention = 1 << 2, 40 | MSDF_NoReturnType = 1 << 3, 41 | MSDF_NoMemberType = 1 << 4, 42 | }; 43 | 44 | /// Demangles the Microsoft symbol pointed at by mangled_name and returns it. 45 | /// Returns a pointer to the start of a null-terminated demangled string on 46 | /// success, or nullptr on error. 47 | /// If n_read is non-null and demangling was successful, it receives how many 48 | /// bytes of the input string were consumed. 49 | /// buf can point to a *n_buf bytes large buffer where the demangled name is 50 | /// stored. If the buffer is too small, it is grown with realloc(). If buf is 51 | /// nullptr, then this malloc()s memory for the result. 52 | /// *n_buf stores the size of buf on input if buf is non-nullptr, and it 53 | /// receives the size of the demangled string on output if n_buf is not nullptr. 54 | /// status receives one of the demangle_ enum entries above if it's not nullptr. 55 | /// Flags controls various details of the demangled representation. 56 | char *microsoftDemangle(const char *mangled_name, size_t *n_read, 57 | char *buf, size_t *n_buf, 58 | int *status, MSDemangleFlags Flags = MSDF_None); 59 | 60 | /// Attempt to demangle a string using different demangling schemes. 61 | /// The function uses heuristics to determine which demangling scheme to use. 62 | /// \param MangledName - reference to string to demangle. 63 | /// \returns - the demangled string, or a copy of the input string if no 64 | /// demangling occurred. 65 | std::string demangle(const std::string &MangledName); 66 | 67 | /// "Partial" demangler. This supports demangling a string into an AST 68 | /// (typically an intermediate stage in itaniumDemangle) and querying certain 69 | /// properties or partially printing the demangled name. 70 | struct ItaniumPartialDemangler { 71 | ItaniumPartialDemangler(); 72 | 73 | ItaniumPartialDemangler(ItaniumPartialDemangler &&Other); 74 | ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other); 75 | 76 | /// Demangle into an AST. Subsequent calls to the rest of the member functions 77 | /// implicitly operate on the AST this produces. 78 | /// \return true on error, false otherwise 79 | bool partialDemangle(const char *MangledName); 80 | 81 | /// Just print the entire mangled name into Buf. Buf and N behave like the 82 | /// second and third parameters to itaniumDemangle. 83 | char *finishDemangle(char *Buf, size_t *N) const; 84 | 85 | /// Get the base name of a function. This doesn't include trailing template 86 | /// arguments, ie for "a::b" this function returns "b". 87 | char *getFunctionBaseName(char *Buf, size_t *N) const; 88 | 89 | /// Get the context name for a function. For "a::b::c", this function returns 90 | /// "a::b". 91 | char *getFunctionDeclContextName(char *Buf, size_t *N) const; 92 | 93 | /// Get the entire name of this function. 94 | char *getFunctionName(char *Buf, size_t *N) const; 95 | 96 | /// Get the parameters for this function. 97 | char *getFunctionParameters(char *Buf, size_t *N) const; 98 | char *getFunctionReturnType(char *Buf, size_t *N) const; 99 | 100 | /// If this function has any any cv or reference qualifiers. These imply that 101 | /// the function is a non-static member function. 102 | bool hasFunctionQualifiers() const; 103 | 104 | /// If this symbol describes a constructor or destructor. 105 | bool isCtorOrDtor() const; 106 | 107 | /// If this symbol describes a function. 108 | bool isFunction() const; 109 | 110 | /// If this symbol describes a variable. 111 | bool isData() const; 112 | 113 | /// If this symbol is a . These are generally implicitly 114 | /// generated by the implementation, such as vtables and typeinfo names. 115 | bool isSpecialName() const; 116 | 117 | ~ItaniumPartialDemangler(); 118 | private: 119 | void *RootNode; 120 | void *Context; 121 | }; 122 | } // namespace llvm 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/Utility.h: -------------------------------------------------------------------------------- 1 | //===--- Utility.h ----------------------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // Provide some utility classes for use in the demangler(s). 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef LLVM_DEMANGLE_UTILITY_H 14 | #define LLVM_DEMANGLE_UTILITY_H 15 | 16 | #include "StringView.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | DEMANGLE_NAMESPACE_BEGIN 24 | 25 | // Stream that AST nodes write their string representation into after the AST 26 | // has been parsed. 27 | class OutputStream { 28 | char *Buffer = nullptr; 29 | size_t CurrentPosition = 0; 30 | size_t BufferCapacity = 0; 31 | 32 | // Ensure there is at least n more positions in buffer. 33 | void grow(size_t N) { 34 | if (N + CurrentPosition >= BufferCapacity) { 35 | BufferCapacity *= 2; 36 | if (BufferCapacity < N + CurrentPosition) 37 | BufferCapacity = N + CurrentPosition; 38 | Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); 39 | if (Buffer == nullptr) 40 | std::terminate(); 41 | } 42 | } 43 | 44 | void writeUnsigned(uint64_t N, bool isNeg = false) { 45 | // Handle special case... 46 | if (N == 0) { 47 | *this << '0'; 48 | return; 49 | } 50 | 51 | char Temp[21]; 52 | char *TempPtr = std::end(Temp); 53 | 54 | while (N) { 55 | *--TempPtr = char('0' + N % 10); 56 | N /= 10; 57 | } 58 | 59 | // Add negative sign... 60 | if (isNeg) 61 | *--TempPtr = '-'; 62 | this->operator<<(StringView(TempPtr, std::end(Temp))); 63 | } 64 | 65 | public: 66 | OutputStream(char *StartBuf, size_t Size) 67 | : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 68 | OutputStream() = default; 69 | void reset(char *Buffer_, size_t BufferCapacity_) { 70 | CurrentPosition = 0; 71 | Buffer = Buffer_; 72 | BufferCapacity = BufferCapacity_; 73 | } 74 | 75 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset 76 | /// into the pack that we're currently printing. 77 | unsigned CurrentPackIndex = std::numeric_limits::max(); 78 | unsigned CurrentPackMax = std::numeric_limits::max(); 79 | 80 | OutputStream &operator+=(StringView R) { 81 | size_t Size = R.size(); 82 | if (Size == 0) 83 | return *this; 84 | grow(Size); 85 | std::memmove(Buffer + CurrentPosition, R.begin(), Size); 86 | CurrentPosition += Size; 87 | return *this; 88 | } 89 | 90 | OutputStream &operator+=(char C) { 91 | grow(1); 92 | Buffer[CurrentPosition++] = C; 93 | return *this; 94 | } 95 | 96 | OutputStream &operator<<(StringView R) { return (*this += R); } 97 | 98 | OutputStream &operator<<(char C) { return (*this += C); } 99 | 100 | OutputStream &operator<<(long long N) { 101 | if (N < 0) 102 | writeUnsigned(static_cast(-N), true); 103 | else 104 | writeUnsigned(static_cast(N)); 105 | return *this; 106 | } 107 | 108 | OutputStream &operator<<(unsigned long long N) { 109 | writeUnsigned(N, false); 110 | return *this; 111 | } 112 | 113 | OutputStream &operator<<(long N) { 114 | return this->operator<<(static_cast(N)); 115 | } 116 | 117 | OutputStream &operator<<(unsigned long N) { 118 | return this->operator<<(static_cast(N)); 119 | } 120 | 121 | OutputStream &operator<<(int N) { 122 | return this->operator<<(static_cast(N)); 123 | } 124 | 125 | OutputStream &operator<<(unsigned int N) { 126 | return this->operator<<(static_cast(N)); 127 | } 128 | 129 | size_t getCurrentPosition() const { return CurrentPosition; } 130 | void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 131 | 132 | char back() const { 133 | return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; 134 | } 135 | 136 | bool empty() const { return CurrentPosition == 0; } 137 | 138 | char *getBuffer() { return Buffer; } 139 | char *getBufferEnd() { return Buffer + CurrentPosition - 1; } 140 | size_t getBufferCapacity() const { return BufferCapacity; } 141 | }; 142 | 143 | template class SwapAndRestore { 144 | T &Restore; 145 | T OriginalValue; 146 | bool ShouldRestore = true; 147 | 148 | public: 149 | SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} 150 | 151 | SwapAndRestore(T &Restore_, T NewVal) 152 | : Restore(Restore_), OriginalValue(Restore) { 153 | Restore = std::move(NewVal); 154 | } 155 | ~SwapAndRestore() { 156 | if (ShouldRestore) 157 | Restore = std::move(OriginalValue); 158 | } 159 | 160 | void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } 161 | 162 | void restoreNow(bool Force) { 163 | if (!Force && !ShouldRestore) 164 | return; 165 | 166 | Restore = std::move(OriginalValue); 167 | ShouldRestore = false; 168 | } 169 | 170 | SwapAndRestore(const SwapAndRestore &) = delete; 171 | SwapAndRestore &operator=(const SwapAndRestore &) = delete; 172 | }; 173 | 174 | inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, 175 | size_t InitSize) { 176 | size_t BufferSize; 177 | if (Buf == nullptr) { 178 | Buf = static_cast(std::malloc(InitSize)); 179 | if (Buf == nullptr) 180 | return false; 181 | BufferSize = InitSize; 182 | } else 183 | BufferSize = *N; 184 | 185 | S.reset(Buf, BufferSize); 186 | return true; 187 | } 188 | 189 | DEMANGLE_NAMESPACE_END 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/MicrosoftDemangle.h: -------------------------------------------------------------------------------- 1 | //===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H 10 | #define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H 11 | 12 | #include "llvm/Demangle/DemangleConfig.h" 13 | #include "llvm/Demangle/MicrosoftDemangleNodes.h" 14 | #include "llvm/Demangle/StringView.h" 15 | #include "llvm/Demangle/Utility.h" 16 | 17 | #include 18 | 19 | namespace llvm { 20 | namespace ms_demangle { 21 | // This memory allocator is extremely fast, but it doesn't call dtors 22 | // for allocated objects. That means you can't use STL containers 23 | // (such as std::vector) with this allocator. But it pays off -- 24 | // the demangler is 3x faster with this allocator compared to one with 25 | // STL containers. 26 | constexpr size_t AllocUnit = 4096; 27 | 28 | class ArenaAllocator { 29 | struct AllocatorNode { 30 | uint8_t *Buf = nullptr; 31 | size_t Used = 0; 32 | size_t Capacity = 0; 33 | AllocatorNode *Next = nullptr; 34 | }; 35 | 36 | void addNode(size_t Capacity) { 37 | AllocatorNode *NewHead = new AllocatorNode; 38 | NewHead->Buf = new uint8_t[Capacity]; 39 | NewHead->Next = Head; 40 | NewHead->Capacity = Capacity; 41 | Head = NewHead; 42 | NewHead->Used = 0; 43 | } 44 | 45 | public: 46 | ArenaAllocator() { addNode(AllocUnit); } 47 | 48 | ~ArenaAllocator() { 49 | while (Head) { 50 | assert(Head->Buf); 51 | delete[] Head->Buf; 52 | AllocatorNode *Next = Head->Next; 53 | delete Head; 54 | Head = Next; 55 | } 56 | } 57 | 58 | char *allocUnalignedBuffer(size_t Size) { 59 | assert(Head && Head->Buf); 60 | 61 | uint8_t *P = Head->Buf + Head->Used; 62 | 63 | Head->Used += Size; 64 | if (Head->Used <= Head->Capacity) 65 | return reinterpret_cast(P); 66 | 67 | addNode(std::max(AllocUnit, Size)); 68 | Head->Used = Size; 69 | return reinterpret_cast(Head->Buf); 70 | } 71 | 72 | template T *allocArray(size_t Count) { 73 | size_t Size = Count * sizeof(T); 74 | assert(Head && Head->Buf); 75 | 76 | size_t P = (size_t)Head->Buf + Head->Used; 77 | uintptr_t AlignedP = 78 | (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); 79 | uint8_t *PP = (uint8_t *)AlignedP; 80 | size_t Adjustment = AlignedP - P; 81 | 82 | Head->Used += Size + Adjustment; 83 | if (Head->Used <= Head->Capacity) 84 | return new (PP) T[Count](); 85 | 86 | addNode(std::max(AllocUnit, Size)); 87 | Head->Used = Size; 88 | return new (Head->Buf) T[Count](); 89 | } 90 | 91 | template T *alloc(Args &&... ConstructorArgs) { 92 | constexpr size_t Size = sizeof(T); 93 | assert(Head && Head->Buf); 94 | 95 | size_t P = (size_t)Head->Buf + Head->Used; 96 | uintptr_t AlignedP = 97 | (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); 98 | uint8_t *PP = (uint8_t *)AlignedP; 99 | size_t Adjustment = AlignedP - P; 100 | 101 | Head->Used += Size + Adjustment; 102 | if (Head->Used <= Head->Capacity) 103 | return new (PP) T(std::forward(ConstructorArgs)...); 104 | 105 | static_assert(Size < AllocUnit, ""); 106 | addNode(AllocUnit); 107 | Head->Used = Size; 108 | return new (Head->Buf) T(std::forward(ConstructorArgs)...); 109 | } 110 | 111 | private: 112 | AllocatorNode *Head = nullptr; 113 | }; 114 | 115 | struct BackrefContext { 116 | static constexpr size_t Max = 10; 117 | 118 | TypeNode *FunctionParams[Max]; 119 | size_t FunctionParamCount = 0; 120 | 121 | // The first 10 BackReferences in a mangled name can be back-referenced by 122 | // special name @[0-9]. This is a storage for the first 10 BackReferences. 123 | NamedIdentifierNode *Names[Max]; 124 | size_t NamesCount = 0; 125 | }; 126 | 127 | enum class QualifierMangleMode { Drop, Mangle, Result }; 128 | 129 | enum NameBackrefBehavior : uint8_t { 130 | NBB_None = 0, // don't save any names as backrefs. 131 | NBB_Template = 1 << 0, // save template instanations. 132 | NBB_Simple = 1 << 1, // save simple names. 133 | }; 134 | 135 | enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder }; 136 | 137 | // Demangler class takes the main role in demangling symbols. 138 | // It has a set of functions to parse mangled symbols into Type instances. 139 | // It also has a set of functions to convert Type instances to strings. 140 | class Demangler { 141 | public: 142 | Demangler() = default; 143 | virtual ~Demangler() = default; 144 | 145 | // You are supposed to call parse() first and then check if error is true. If 146 | // it is false, call output() to write the formatted name to the given stream. 147 | SymbolNode *parse(StringView &MangledName); 148 | 149 | TagTypeNode *parseTagUniqueName(StringView &MangledName); 150 | 151 | // True if an error occurred. 152 | bool Error = false; 153 | 154 | void dumpBackReferences(); 155 | 156 | private: 157 | SymbolNode *demangleEncodedSymbol(StringView &MangledName, 158 | QualifiedNameNode *QN); 159 | SymbolNode *demangleDeclarator(StringView &MangledName); 160 | SymbolNode *demangleMD5Name(StringView &MangledName); 161 | SymbolNode *demangleTypeinfoName(StringView &MangledName); 162 | 163 | VariableSymbolNode *demangleVariableEncoding(StringView &MangledName, 164 | StorageClass SC); 165 | FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName); 166 | 167 | Qualifiers demanglePointerExtQualifiers(StringView &MangledName); 168 | 169 | // Parser functions. This is a recursive-descent parser. 170 | TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM); 171 | PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName); 172 | CustomTypeNode *demangleCustomType(StringView &MangledName); 173 | TagTypeNode *demangleClassType(StringView &MangledName); 174 | PointerTypeNode *demanglePointerType(StringView &MangledName); 175 | PointerTypeNode *demangleMemberPointerType(StringView &MangledName); 176 | FunctionSignatureNode *demangleFunctionType(StringView &MangledName, 177 | bool HasThisQuals); 178 | 179 | ArrayTypeNode *demangleArrayType(StringView &MangledName); 180 | 181 | NodeArrayNode *demangleFunctionParameterList(StringView &MangledName, 182 | bool &IsVariadic); 183 | NodeArrayNode *demangleTemplateParameterList(StringView &MangledName); 184 | 185 | std::pair demangleNumber(StringView &MangledName); 186 | uint64_t demangleUnsigned(StringView &MangledName); 187 | int64_t demangleSigned(StringView &MangledName); 188 | 189 | void memorizeString(StringView s); 190 | void memorizeIdentifier(IdentifierNode *Identifier); 191 | 192 | /// Allocate a copy of \p Borrowed into memory that we own. 193 | StringView copyString(StringView Borrowed); 194 | 195 | QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName); 196 | QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName); 197 | 198 | IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName, 199 | bool Memorize); 200 | IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName, 201 | NameBackrefBehavior NBB); 202 | 203 | QualifiedNameNode *demangleNameScopeChain(StringView &MangledName, 204 | IdentifierNode *UnqualifiedName); 205 | IdentifierNode *demangleNameScopePiece(StringView &MangledName); 206 | 207 | NamedIdentifierNode *demangleBackRefName(StringView &MangledName); 208 | IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName, 209 | NameBackrefBehavior NBB); 210 | IntrinsicFunctionKind 211 | translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group); 212 | IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName); 213 | IdentifierNode * 214 | demangleFunctionIdentifierCode(StringView &MangledName, 215 | FunctionIdentifierCodeGroup Group); 216 | StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName, 217 | bool IsDestructor); 218 | ConversionOperatorIdentifierNode * 219 | demangleConversionOperatorIdentifier(StringView &MangledName); 220 | LiteralOperatorIdentifierNode * 221 | demangleLiteralOperatorIdentifier(StringView &MangledName); 222 | 223 | SymbolNode *demangleSpecialIntrinsic(StringView &MangledName); 224 | SpecialTableSymbolNode * 225 | demangleSpecialTableSymbolNode(StringView &MangledName, 226 | SpecialIntrinsicKind SIK); 227 | LocalStaticGuardVariableNode * 228 | demangleLocalStaticGuard(StringView &MangledName, bool IsThread); 229 | VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, 230 | StringView &MangledName, 231 | StringView VariableName); 232 | VariableSymbolNode * 233 | demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, 234 | StringView &MangledName); 235 | FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName, 236 | bool IsDestructor); 237 | 238 | NamedIdentifierNode *demangleSimpleName(StringView &MangledName, 239 | bool Memorize); 240 | NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName); 241 | NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName); 242 | EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName); 243 | FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName); 244 | 245 | StringView demangleSimpleString(StringView &MangledName, bool Memorize); 246 | 247 | FuncClass demangleFunctionClass(StringView &MangledName); 248 | CallingConv demangleCallingConvention(StringView &MangledName); 249 | StorageClass demangleVariableStorageClass(StringView &MangledName); 250 | bool demangleThrowSpecification(StringView &MangledName); 251 | wchar_t demangleWcharLiteral(StringView &MangledName); 252 | uint8_t demangleCharLiteral(StringView &MangledName); 253 | 254 | std::pair demangleQualifiers(StringView &MangledName); 255 | 256 | // Memory allocator. 257 | ArenaAllocator Arena; 258 | 259 | // A single type uses one global back-ref table for all function params. 260 | // This means back-refs can even go "into" other types. Examples: 261 | // 262 | // // Second int* is a back-ref to first. 263 | // void foo(int *, int*); 264 | // 265 | // // Second int* is not a back-ref to first (first is not a function param). 266 | // int* foo(int*); 267 | // 268 | // // Second int* is a back-ref to first (ALL function types share the same 269 | // // back-ref map. 270 | // using F = void(*)(int*); 271 | // F G(int *); 272 | BackrefContext Backrefs; 273 | }; 274 | 275 | } // namespace ms_demangle 276 | } // namespace llvm 277 | 278 | #endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H 279 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/ItaniumDemangle.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------- ItaniumDemangle.cpp ------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | // FIXME: (possibly) incomplete list of features that clang mangles that this 10 | // file does not yet support: 11 | // - C++ modules TS 12 | 13 | #include "llvm/Demangle/Demangle.h" 14 | #include "llvm/Demangle/ItaniumDemangle.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace llvm; 27 | using namespace llvm::itanium_demangle; 28 | 29 | constexpr const char *itanium_demangle::FloatData::spec; 30 | constexpr const char *itanium_demangle::FloatData::spec; 31 | constexpr const char *itanium_demangle::FloatData::spec; 32 | 33 | // := _ # when number < 10 34 | // := __ _ # when number >= 10 35 | // extension := decimal-digit+ # at the end of string 36 | const char *itanium_demangle::parse_discriminator(const char *first, 37 | const char *last) { 38 | // parse but ignore discriminator 39 | if (first != last) { 40 | if (*first == '_') { 41 | const char *t1 = first + 1; 42 | if (t1 != last) { 43 | if (std::isdigit(*t1)) 44 | first = t1 + 1; 45 | else if (*t1 == '_') { 46 | for (++t1; t1 != last && std::isdigit(*t1); ++t1) 47 | ; 48 | if (t1 != last && *t1 == '_') 49 | first = t1 + 1; 50 | } 51 | } 52 | } else if (std::isdigit(*first)) { 53 | const char *t1 = first + 1; 54 | for (; t1 != last && std::isdigit(*t1); ++t1) 55 | ; 56 | if (t1 == last) 57 | first = last; 58 | } 59 | } 60 | return first; 61 | } 62 | 63 | #ifndef NDEBUG 64 | namespace { 65 | struct DumpVisitor { 66 | unsigned Depth = 0; 67 | bool PendingNewline = false; 68 | 69 | template static constexpr bool wantsNewline(const NodeT *) { 70 | return true; 71 | } 72 | static bool wantsNewline(NodeArray A) { return !A.empty(); } 73 | static constexpr bool wantsNewline(...) { return false; } 74 | 75 | template static bool anyWantNewline(Ts ...Vs) { 76 | for (bool B : {wantsNewline(Vs)...}) 77 | if (B) 78 | return true; 79 | return false; 80 | } 81 | 82 | void printStr(const char *S) { fprintf(stderr, "%s", S); } 83 | void print(StringView SV) { 84 | fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); 85 | } 86 | void print(const Node *N) { 87 | if (N) 88 | N->visit(std::ref(*this)); 89 | else 90 | printStr(""); 91 | } 92 | void print(NodeArray A) { 93 | ++Depth; 94 | printStr("{"); 95 | bool First = true; 96 | for (const Node *N : A) { 97 | if (First) 98 | print(N); 99 | else 100 | printWithComma(N); 101 | First = false; 102 | } 103 | printStr("}"); 104 | --Depth; 105 | } 106 | 107 | // Overload used when T is exactly 'bool', not merely convertible to 'bool'. 108 | void print(bool B) { printStr(B ? "true" : "false"); } 109 | 110 | template std::enable_if_t::value> print(T N) { 111 | fprintf(stderr, "%llu", (unsigned long long)N); 112 | } 113 | 114 | template std::enable_if_t::value> print(T N) { 115 | fprintf(stderr, "%lld", (long long)N); 116 | } 117 | 118 | void print(ReferenceKind RK) { 119 | switch (RK) { 120 | case ReferenceKind::LValue: 121 | return printStr("ReferenceKind::LValue"); 122 | case ReferenceKind::RValue: 123 | return printStr("ReferenceKind::RValue"); 124 | } 125 | } 126 | void print(FunctionRefQual RQ) { 127 | switch (RQ) { 128 | case FunctionRefQual::FrefQualNone: 129 | return printStr("FunctionRefQual::FrefQualNone"); 130 | case FunctionRefQual::FrefQualLValue: 131 | return printStr("FunctionRefQual::FrefQualLValue"); 132 | case FunctionRefQual::FrefQualRValue: 133 | return printStr("FunctionRefQual::FrefQualRValue"); 134 | } 135 | } 136 | void print(Qualifiers Qs) { 137 | if (!Qs) return printStr("QualNone"); 138 | struct QualName { Qualifiers Q; const char *Name; } Names[] = { 139 | {QualConst, "QualConst"}, 140 | {QualVolatile, "QualVolatile"}, 141 | {QualRestrict, "QualRestrict"}, 142 | }; 143 | for (QualName Name : Names) { 144 | if (Qs & Name.Q) { 145 | printStr(Name.Name); 146 | Qs = Qualifiers(Qs & ~Name.Q); 147 | if (Qs) printStr(" | "); 148 | } 149 | } 150 | } 151 | void print(SpecialSubKind SSK) { 152 | switch (SSK) { 153 | case SpecialSubKind::allocator: 154 | return printStr("SpecialSubKind::allocator"); 155 | case SpecialSubKind::basic_string: 156 | return printStr("SpecialSubKind::basic_string"); 157 | case SpecialSubKind::string: 158 | return printStr("SpecialSubKind::string"); 159 | case SpecialSubKind::istream: 160 | return printStr("SpecialSubKind::istream"); 161 | case SpecialSubKind::ostream: 162 | return printStr("SpecialSubKind::ostream"); 163 | case SpecialSubKind::iostream: 164 | return printStr("SpecialSubKind::iostream"); 165 | } 166 | } 167 | void print(TemplateParamKind TPK) { 168 | switch (TPK) { 169 | case TemplateParamKind::Type: 170 | return printStr("TemplateParamKind::Type"); 171 | case TemplateParamKind::NonType: 172 | return printStr("TemplateParamKind::NonType"); 173 | case TemplateParamKind::Template: 174 | return printStr("TemplateParamKind::Template"); 175 | } 176 | } 177 | 178 | void newLine() { 179 | printStr("\n"); 180 | for (unsigned I = 0; I != Depth; ++I) 181 | printStr(" "); 182 | PendingNewline = false; 183 | } 184 | 185 | template void printWithPendingNewline(T V) { 186 | print(V); 187 | if (wantsNewline(V)) 188 | PendingNewline = true; 189 | } 190 | 191 | template void printWithComma(T V) { 192 | if (PendingNewline || wantsNewline(V)) { 193 | printStr(","); 194 | newLine(); 195 | } else { 196 | printStr(", "); 197 | } 198 | 199 | printWithPendingNewline(V); 200 | } 201 | 202 | struct CtorArgPrinter { 203 | DumpVisitor &Visitor; 204 | 205 | template void operator()(T V, Rest ...Vs) { 206 | if (Visitor.anyWantNewline(V, Vs...)) 207 | Visitor.newLine(); 208 | Visitor.printWithPendingNewline(V); 209 | int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; 210 | (void)PrintInOrder; 211 | } 212 | }; 213 | 214 | template void operator()(const NodeT *Node) { 215 | Depth += 2; 216 | fprintf(stderr, "%s(", itanium_demangle::NodeKind::name()); 217 | Node->match(CtorArgPrinter{*this}); 218 | fprintf(stderr, ")"); 219 | Depth -= 2; 220 | } 221 | 222 | void operator()(const ForwardTemplateReference *Node) { 223 | Depth += 2; 224 | fprintf(stderr, "ForwardTemplateReference("); 225 | if (Node->Ref && !Node->Printing) { 226 | Node->Printing = true; 227 | CtorArgPrinter{*this}(Node->Ref); 228 | Node->Printing = false; 229 | } else { 230 | CtorArgPrinter{*this}(Node->Index); 231 | } 232 | fprintf(stderr, ")"); 233 | Depth -= 2; 234 | } 235 | }; 236 | } 237 | 238 | void itanium_demangle::Node::dump() const { 239 | DumpVisitor V; 240 | visit(std::ref(V)); 241 | V.newLine(); 242 | } 243 | #endif 244 | 245 | namespace { 246 | class BumpPointerAllocator { 247 | struct BlockMeta { 248 | BlockMeta* Next; 249 | size_t Current; 250 | }; 251 | 252 | static constexpr size_t AllocSize = 4096; 253 | static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); 254 | 255 | alignas(long double) char InitialBuffer[AllocSize]; 256 | BlockMeta* BlockList = nullptr; 257 | 258 | void grow() { 259 | char* NewMeta = static_cast(std::malloc(AllocSize)); 260 | if (NewMeta == nullptr) 261 | std::terminate(); 262 | BlockList = new (NewMeta) BlockMeta{BlockList, 0}; 263 | } 264 | 265 | void* allocateMassive(size_t NBytes) { 266 | NBytes += sizeof(BlockMeta); 267 | BlockMeta* NewMeta = reinterpret_cast(std::malloc(NBytes)); 268 | if (NewMeta == nullptr) 269 | std::terminate(); 270 | BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; 271 | return static_cast(NewMeta + 1); 272 | } 273 | 274 | public: 275 | BumpPointerAllocator() 276 | : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} 277 | 278 | void* allocate(size_t N) { 279 | N = (N + 15u) & ~15u; 280 | if (N + BlockList->Current >= UsableAllocSize) { 281 | if (N > UsableAllocSize) 282 | return allocateMassive(N); 283 | grow(); 284 | } 285 | BlockList->Current += N; 286 | return static_cast(reinterpret_cast(BlockList + 1) + 287 | BlockList->Current - N); 288 | } 289 | 290 | void reset() { 291 | while (BlockList) { 292 | BlockMeta* Tmp = BlockList; 293 | BlockList = BlockList->Next; 294 | if (reinterpret_cast(Tmp) != InitialBuffer) 295 | std::free(Tmp); 296 | } 297 | BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; 298 | } 299 | 300 | ~BumpPointerAllocator() { reset(); } 301 | }; 302 | 303 | class DefaultAllocator { 304 | BumpPointerAllocator Alloc; 305 | 306 | public: 307 | void reset() { Alloc.reset(); } 308 | 309 | template T *makeNode(Args &&...args) { 310 | return new (Alloc.allocate(sizeof(T))) 311 | T(std::forward(args)...); 312 | } 313 | 314 | void *allocateNodeArray(size_t sz) { 315 | return Alloc.allocate(sizeof(Node *) * sz); 316 | } 317 | }; 318 | } // unnamed namespace 319 | 320 | //===----------------------------------------------------------------------===// 321 | // Code beyond this point should not be synchronized with libc++abi. 322 | //===----------------------------------------------------------------------===// 323 | 324 | using Demangler = itanium_demangle::ManglingParser; 325 | 326 | char *llvm::itaniumDemangle(const char *MangledName, char *Buf, 327 | size_t *N, int *Status) { 328 | if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { 329 | if (Status) 330 | *Status = demangle_invalid_args; 331 | return nullptr; 332 | } 333 | 334 | int InternalStatus = demangle_success; 335 | Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); 336 | OutputStream S; 337 | 338 | Node *AST = Parser.parse(); 339 | 340 | if (AST == nullptr) 341 | InternalStatus = demangle_invalid_mangled_name; 342 | else if (!initializeOutputStream(Buf, N, S, 1024)) 343 | InternalStatus = demangle_memory_alloc_failure; 344 | else { 345 | assert(Parser.ForwardTemplateRefs.empty()); 346 | AST->print(S); 347 | S += '\0'; 348 | if (N != nullptr) 349 | *N = S.getCurrentPosition(); 350 | Buf = S.getBuffer(); 351 | } 352 | 353 | if (Status) 354 | *Status = InternalStatus; 355 | return InternalStatus == demangle_success ? Buf : nullptr; 356 | } 357 | 358 | ItaniumPartialDemangler::ItaniumPartialDemangler() 359 | : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} 360 | 361 | ItaniumPartialDemangler::~ItaniumPartialDemangler() { 362 | delete static_cast(Context); 363 | } 364 | 365 | ItaniumPartialDemangler::ItaniumPartialDemangler( 366 | ItaniumPartialDemangler &&Other) 367 | : RootNode(Other.RootNode), Context(Other.Context) { 368 | Other.Context = Other.RootNode = nullptr; 369 | } 370 | 371 | ItaniumPartialDemangler &ItaniumPartialDemangler:: 372 | operator=(ItaniumPartialDemangler &&Other) { 373 | std::swap(RootNode, Other.RootNode); 374 | std::swap(Context, Other.Context); 375 | return *this; 376 | } 377 | 378 | // Demangle MangledName into an AST, storing it into this->RootNode. 379 | bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { 380 | Demangler *Parser = static_cast(Context); 381 | size_t Len = std::strlen(MangledName); 382 | Parser->reset(MangledName, MangledName + Len); 383 | RootNode = Parser->parse(); 384 | return RootNode == nullptr; 385 | } 386 | 387 | static char *printNode(const Node *RootNode, char *Buf, size_t *N) { 388 | OutputStream S; 389 | if (!initializeOutputStream(Buf, N, S, 128)) 390 | return nullptr; 391 | RootNode->print(S); 392 | S += '\0'; 393 | if (N != nullptr) 394 | *N = S.getCurrentPosition(); 395 | return S.getBuffer(); 396 | } 397 | 398 | char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { 399 | if (!isFunction()) 400 | return nullptr; 401 | 402 | const Node *Name = static_cast(RootNode)->getName(); 403 | 404 | while (true) { 405 | switch (Name->getKind()) { 406 | case Node::KAbiTagAttr: 407 | Name = static_cast(Name)->Base; 408 | continue; 409 | case Node::KStdQualifiedName: 410 | Name = static_cast(Name)->Child; 411 | continue; 412 | case Node::KNestedName: 413 | Name = static_cast(Name)->Name; 414 | continue; 415 | case Node::KLocalName: 416 | Name = static_cast(Name)->Entity; 417 | continue; 418 | case Node::KNameWithTemplateArgs: 419 | Name = static_cast(Name)->Name; 420 | continue; 421 | default: 422 | return printNode(Name, Buf, N); 423 | } 424 | } 425 | } 426 | 427 | char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, 428 | size_t *N) const { 429 | if (!isFunction()) 430 | return nullptr; 431 | const Node *Name = static_cast(RootNode)->getName(); 432 | 433 | OutputStream S; 434 | if (!initializeOutputStream(Buf, N, S, 128)) 435 | return nullptr; 436 | 437 | KeepGoingLocalFunction: 438 | while (true) { 439 | if (Name->getKind() == Node::KAbiTagAttr) { 440 | Name = static_cast(Name)->Base; 441 | continue; 442 | } 443 | if (Name->getKind() == Node::KNameWithTemplateArgs) { 444 | Name = static_cast(Name)->Name; 445 | continue; 446 | } 447 | break; 448 | } 449 | 450 | switch (Name->getKind()) { 451 | case Node::KStdQualifiedName: 452 | S += "std"; 453 | break; 454 | case Node::KNestedName: 455 | static_cast(Name)->Qual->print(S); 456 | break; 457 | case Node::KLocalName: { 458 | auto *LN = static_cast(Name); 459 | LN->Encoding->print(S); 460 | S += "::"; 461 | Name = LN->Entity; 462 | goto KeepGoingLocalFunction; 463 | } 464 | default: 465 | break; 466 | } 467 | S += '\0'; 468 | if (N != nullptr) 469 | *N = S.getCurrentPosition(); 470 | return S.getBuffer(); 471 | } 472 | 473 | char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { 474 | if (!isFunction()) 475 | return nullptr; 476 | auto *Name = static_cast(RootNode)->getName(); 477 | return printNode(Name, Buf, N); 478 | } 479 | 480 | char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, 481 | size_t *N) const { 482 | if (!isFunction()) 483 | return nullptr; 484 | NodeArray Params = static_cast(RootNode)->getParams(); 485 | 486 | OutputStream S; 487 | if (!initializeOutputStream(Buf, N, S, 128)) 488 | return nullptr; 489 | 490 | S += '('; 491 | Params.printWithComma(S); 492 | S += ')'; 493 | S += '\0'; 494 | if (N != nullptr) 495 | *N = S.getCurrentPosition(); 496 | return S.getBuffer(); 497 | } 498 | 499 | char *ItaniumPartialDemangler::getFunctionReturnType( 500 | char *Buf, size_t *N) const { 501 | if (!isFunction()) 502 | return nullptr; 503 | 504 | OutputStream S; 505 | if (!initializeOutputStream(Buf, N, S, 128)) 506 | return nullptr; 507 | 508 | if (const Node *Ret = 509 | static_cast(RootNode)->getReturnType()) 510 | Ret->print(S); 511 | 512 | S += '\0'; 513 | if (N != nullptr) 514 | *N = S.getCurrentPosition(); 515 | return S.getBuffer(); 516 | } 517 | 518 | char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { 519 | assert(RootNode != nullptr && "must call partialDemangle()"); 520 | return printNode(static_cast(RootNode), Buf, N); 521 | } 522 | 523 | bool ItaniumPartialDemangler::hasFunctionQualifiers() const { 524 | assert(RootNode != nullptr && "must call partialDemangle()"); 525 | if (!isFunction()) 526 | return false; 527 | auto *E = static_cast(RootNode); 528 | return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; 529 | } 530 | 531 | bool ItaniumPartialDemangler::isCtorOrDtor() const { 532 | const Node *N = static_cast(RootNode); 533 | while (N) { 534 | switch (N->getKind()) { 535 | default: 536 | return false; 537 | case Node::KCtorDtorName: 538 | return true; 539 | 540 | case Node::KAbiTagAttr: 541 | N = static_cast(N)->Base; 542 | break; 543 | case Node::KFunctionEncoding: 544 | N = static_cast(N)->getName(); 545 | break; 546 | case Node::KLocalName: 547 | N = static_cast(N)->Entity; 548 | break; 549 | case Node::KNameWithTemplateArgs: 550 | N = static_cast(N)->Name; 551 | break; 552 | case Node::KNestedName: 553 | N = static_cast(N)->Name; 554 | break; 555 | case Node::KStdQualifiedName: 556 | N = static_cast(N)->Child; 557 | break; 558 | } 559 | } 560 | return false; 561 | } 562 | 563 | bool ItaniumPartialDemangler::isFunction() const { 564 | assert(RootNode != nullptr && "must call partialDemangle()"); 565 | return static_cast(RootNode)->getKind() == 566 | Node::KFunctionEncoding; 567 | } 568 | 569 | bool ItaniumPartialDemangler::isSpecialName() const { 570 | assert(RootNode != nullptr && "must call partialDemangle()"); 571 | auto K = static_cast(RootNode)->getKind(); 572 | return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; 573 | } 574 | 575 | bool ItaniumPartialDemangler::isData() const { 576 | return !isFunction() && !isSpecialName(); 577 | } 578 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/MicrosoftDemangleNodes.h: -------------------------------------------------------------------------------- 1 | //===- MicrosoftDemangleNodes.h ---------------------------------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file defines the AST nodes used in the MSVC demangler. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H 14 | #define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H 15 | 16 | #include "llvm/Demangle/DemangleConfig.h" 17 | #include "llvm/Demangle/StringView.h" 18 | #include 19 | #include 20 | #include 21 | 22 | namespace llvm { 23 | namespace itanium_demangle { 24 | class OutputStream; 25 | } 26 | } 27 | 28 | using llvm::itanium_demangle::OutputStream; 29 | using llvm::itanium_demangle::StringView; 30 | 31 | namespace llvm { 32 | namespace ms_demangle { 33 | 34 | // Storage classes 35 | enum Qualifiers : uint8_t { 36 | Q_None = 0, 37 | Q_Const = 1 << 0, 38 | Q_Volatile = 1 << 1, 39 | Q_Far = 1 << 2, 40 | Q_Huge = 1 << 3, 41 | Q_Unaligned = 1 << 4, 42 | Q_Restrict = 1 << 5, 43 | Q_Pointer64 = 1 << 6 44 | }; 45 | 46 | enum class StorageClass : uint8_t { 47 | None, 48 | PrivateStatic, 49 | ProtectedStatic, 50 | PublicStatic, 51 | Global, 52 | FunctionLocalStatic, 53 | }; 54 | 55 | enum class PointerAffinity { None, Pointer, Reference, RValueReference }; 56 | enum class FunctionRefQualifier { None, Reference, RValueReference }; 57 | 58 | // Calling conventions 59 | enum class CallingConv : uint8_t { 60 | None, 61 | Cdecl, 62 | Pascal, 63 | Thiscall, 64 | Stdcall, 65 | Fastcall, 66 | Clrcall, 67 | Eabi, 68 | Vectorcall, 69 | Regcall, 70 | Swift, // Clang-only 71 | }; 72 | 73 | enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef }; 74 | 75 | enum OutputFlags { 76 | OF_Default = 0, 77 | OF_NoCallingConvention = 1, 78 | OF_NoTagSpecifier = 2, 79 | OF_NoAccessSpecifier = 4, 80 | OF_NoMemberType = 8, 81 | OF_NoReturnType = 16, 82 | }; 83 | 84 | // Types 85 | enum class PrimitiveKind { 86 | Void, 87 | Bool, 88 | Char, 89 | Schar, 90 | Uchar, 91 | Char8, 92 | Char16, 93 | Char32, 94 | Short, 95 | Ushort, 96 | Int, 97 | Uint, 98 | Long, 99 | Ulong, 100 | Int64, 101 | Uint64, 102 | Wchar, 103 | Float, 104 | Double, 105 | Ldouble, 106 | Nullptr, 107 | }; 108 | 109 | enum class CharKind { 110 | Char, 111 | Char16, 112 | Char32, 113 | Wchar, 114 | }; 115 | 116 | enum class IntrinsicFunctionKind : uint8_t { 117 | None, 118 | New, // ?2 # operator new 119 | Delete, // ?3 # operator delete 120 | Assign, // ?4 # operator= 121 | RightShift, // ?5 # operator>> 122 | LeftShift, // ?6 # operator<< 123 | LogicalNot, // ?7 # operator! 124 | Equals, // ?8 # operator== 125 | NotEquals, // ?9 # operator!= 126 | ArraySubscript, // ?A # operator[] 127 | Pointer, // ?C # operator-> 128 | Dereference, // ?D # operator* 129 | Increment, // ?E # operator++ 130 | Decrement, // ?F # operator-- 131 | Minus, // ?G # operator- 132 | Plus, // ?H # operator+ 133 | BitwiseAnd, // ?I # operator& 134 | MemberPointer, // ?J # operator->* 135 | Divide, // ?K # operator/ 136 | Modulus, // ?L # operator% 137 | LessThan, // ?M operator< 138 | LessThanEqual, // ?N operator<= 139 | GreaterThan, // ?O operator> 140 | GreaterThanEqual, // ?P operator>= 141 | Comma, // ?Q operator, 142 | Parens, // ?R operator() 143 | BitwiseNot, // ?S operator~ 144 | BitwiseXor, // ?T operator^ 145 | BitwiseOr, // ?U operator| 146 | LogicalAnd, // ?V operator&& 147 | LogicalOr, // ?W operator|| 148 | TimesEqual, // ?X operator*= 149 | PlusEqual, // ?Y operator+= 150 | MinusEqual, // ?Z operator-= 151 | DivEqual, // ?_0 operator/= 152 | ModEqual, // ?_1 operator%= 153 | RshEqual, // ?_2 operator>>= 154 | LshEqual, // ?_3 operator<<= 155 | BitwiseAndEqual, // ?_4 operator&= 156 | BitwiseOrEqual, // ?_5 operator|= 157 | BitwiseXorEqual, // ?_6 operator^= 158 | VbaseDtor, // ?_D # vbase destructor 159 | VecDelDtor, // ?_E # vector deleting destructor 160 | DefaultCtorClosure, // ?_F # default constructor closure 161 | ScalarDelDtor, // ?_G # scalar deleting destructor 162 | VecCtorIter, // ?_H # vector constructor iterator 163 | VecDtorIter, // ?_I # vector destructor iterator 164 | VecVbaseCtorIter, // ?_J # vector vbase constructor iterator 165 | VdispMap, // ?_K # virtual displacement map 166 | EHVecCtorIter, // ?_L # eh vector constructor iterator 167 | EHVecDtorIter, // ?_M # eh vector destructor iterator 168 | EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator 169 | CopyCtorClosure, // ?_O # copy constructor closure 170 | LocalVftableCtorClosure, // ?_T # local vftable constructor closure 171 | ArrayNew, // ?_U operator new[] 172 | ArrayDelete, // ?_V operator delete[] 173 | ManVectorCtorIter, // ?__A managed vector ctor iterator 174 | ManVectorDtorIter, // ?__B managed vector dtor iterator 175 | EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator 176 | EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iterator 177 | VectorCopyCtorIter, // ?__G vector copy constructor iterator 178 | VectorVbaseCopyCtorIter, // ?__H vector vbase copy constructor iterator 179 | ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor 180 | CoAwait, // ?__L operator co_await 181 | Spaceship, // ?__M operator<=> 182 | MaxIntrinsic 183 | }; 184 | 185 | enum class SpecialIntrinsicKind { 186 | None, 187 | Vftable, 188 | Vbtable, 189 | Typeof, 190 | VcallThunk, 191 | LocalStaticGuard, 192 | StringLiteralSymbol, 193 | UdtReturning, 194 | Unknown, 195 | DynamicInitializer, 196 | DynamicAtexitDestructor, 197 | RttiTypeDescriptor, 198 | RttiBaseClassDescriptor, 199 | RttiBaseClassArray, 200 | RttiClassHierarchyDescriptor, 201 | RttiCompleteObjLocator, 202 | LocalVftable, 203 | LocalStaticThreadGuard, 204 | }; 205 | 206 | // Function classes 207 | enum FuncClass : uint16_t { 208 | FC_None = 0, 209 | FC_Public = 1 << 0, 210 | FC_Protected = 1 << 1, 211 | FC_Private = 1 << 2, 212 | FC_Global = 1 << 3, 213 | FC_Static = 1 << 4, 214 | FC_Virtual = 1 << 5, 215 | FC_Far = 1 << 6, 216 | FC_ExternC = 1 << 7, 217 | FC_NoParameterList = 1 << 8, 218 | FC_VirtualThisAdjust = 1 << 9, 219 | FC_VirtualThisAdjustEx = 1 << 10, 220 | FC_StaticThisAdjust = 1 << 11, 221 | }; 222 | 223 | enum class TagKind { Class, Struct, Union, Enum }; 224 | 225 | enum class NodeKind { 226 | Unknown, 227 | Md5Symbol, 228 | PrimitiveType, 229 | FunctionSignature, 230 | Identifier, 231 | NamedIdentifier, 232 | VcallThunkIdentifier, 233 | LocalStaticGuardIdentifier, 234 | IntrinsicFunctionIdentifier, 235 | ConversionOperatorIdentifier, 236 | DynamicStructorIdentifier, 237 | StructorIdentifier, 238 | LiteralOperatorIdentifier, 239 | ThunkSignature, 240 | PointerType, 241 | TagType, 242 | ArrayType, 243 | Custom, 244 | IntrinsicType, 245 | NodeArray, 246 | QualifiedName, 247 | TemplateParameterReference, 248 | EncodedStringLiteral, 249 | IntegerLiteral, 250 | RttiBaseClassDescriptor, 251 | LocalStaticGuardVariable, 252 | FunctionSymbol, 253 | VariableSymbol, 254 | SpecialTableSymbol 255 | }; 256 | 257 | struct Node { 258 | explicit Node(NodeKind K) : Kind(K) {} 259 | virtual ~Node() = default; 260 | 261 | NodeKind kind() const { return Kind; } 262 | 263 | virtual void output(OutputStream &OS, OutputFlags Flags) const = 0; 264 | 265 | std::string toString(OutputFlags Flags = OF_Default) const; 266 | 267 | private: 268 | NodeKind Kind; 269 | }; 270 | 271 | struct TypeNode; 272 | struct PrimitiveTypeNode; 273 | struct FunctionSignatureNode; 274 | struct IdentifierNode; 275 | struct NamedIdentifierNode; 276 | struct VcallThunkIdentifierNode; 277 | struct IntrinsicFunctionIdentifierNode; 278 | struct LiteralOperatorIdentifierNode; 279 | struct ConversionOperatorIdentifierNode; 280 | struct StructorIdentifierNode; 281 | struct ThunkSignatureNode; 282 | struct PointerTypeNode; 283 | struct ArrayTypeNode; 284 | struct CustomNode; 285 | struct TagTypeNode; 286 | struct IntrinsicTypeNode; 287 | struct NodeArrayNode; 288 | struct QualifiedNameNode; 289 | struct TemplateParameterReferenceNode; 290 | struct EncodedStringLiteralNode; 291 | struct IntegerLiteralNode; 292 | struct RttiBaseClassDescriptorNode; 293 | struct LocalStaticGuardVariableNode; 294 | struct SymbolNode; 295 | struct FunctionSymbolNode; 296 | struct VariableSymbolNode; 297 | struct SpecialTableSymbolNode; 298 | 299 | struct TypeNode : public Node { 300 | explicit TypeNode(NodeKind K) : Node(K) {} 301 | 302 | virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0; 303 | virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0; 304 | 305 | void output(OutputStream &OS, OutputFlags Flags) const override { 306 | outputPre(OS, Flags); 307 | outputPost(OS, Flags); 308 | } 309 | 310 | Qualifiers Quals = Q_None; 311 | }; 312 | 313 | struct PrimitiveTypeNode : public TypeNode { 314 | explicit PrimitiveTypeNode(PrimitiveKind K) 315 | : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {} 316 | 317 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 318 | void outputPost(OutputStream &OS, OutputFlags Flags) const override {} 319 | 320 | PrimitiveKind PrimKind; 321 | }; 322 | 323 | struct FunctionSignatureNode : public TypeNode { 324 | explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {} 325 | FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {} 326 | 327 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 328 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 329 | 330 | // Valid if this FunctionTypeNode is the Pointee of a PointerType or 331 | // MemberPointerType. 332 | PointerAffinity Affinity = PointerAffinity::None; 333 | 334 | // The function's calling convention. 335 | CallingConv CallConvention = CallingConv::None; 336 | 337 | // Function flags (gloabl, public, etc) 338 | FuncClass FunctionClass = FC_Global; 339 | 340 | FunctionRefQualifier RefQualifier = FunctionRefQualifier::None; 341 | 342 | // The return type of the function. 343 | TypeNode *ReturnType = nullptr; 344 | 345 | // True if this is a C-style ... varargs function. 346 | bool IsVariadic = false; 347 | 348 | // Function parameters 349 | NodeArrayNode *Params = nullptr; 350 | 351 | // True if the function type is noexcept. 352 | bool IsNoexcept = false; 353 | }; 354 | 355 | struct IdentifierNode : public Node { 356 | explicit IdentifierNode(NodeKind K) : Node(K) {} 357 | 358 | NodeArrayNode *TemplateParams = nullptr; 359 | 360 | protected: 361 | void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const; 362 | }; 363 | 364 | struct VcallThunkIdentifierNode : public IdentifierNode { 365 | VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {} 366 | 367 | void output(OutputStream &OS, OutputFlags Flags) const override; 368 | 369 | uint64_t OffsetInVTable = 0; 370 | }; 371 | 372 | struct DynamicStructorIdentifierNode : public IdentifierNode { 373 | DynamicStructorIdentifierNode() 374 | : IdentifierNode(NodeKind::DynamicStructorIdentifier) {} 375 | 376 | void output(OutputStream &OS, OutputFlags Flags) const override; 377 | 378 | VariableSymbolNode *Variable = nullptr; 379 | QualifiedNameNode *Name = nullptr; 380 | bool IsDestructor = false; 381 | }; 382 | 383 | struct NamedIdentifierNode : public IdentifierNode { 384 | NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {} 385 | 386 | void output(OutputStream &OS, OutputFlags Flags) const override; 387 | 388 | StringView Name; 389 | }; 390 | 391 | struct IntrinsicFunctionIdentifierNode : public IdentifierNode { 392 | explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator) 393 | : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier), 394 | Operator(Operator) {} 395 | 396 | void output(OutputStream &OS, OutputFlags Flags) const override; 397 | 398 | IntrinsicFunctionKind Operator; 399 | }; 400 | 401 | struct LiteralOperatorIdentifierNode : public IdentifierNode { 402 | LiteralOperatorIdentifierNode() 403 | : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {} 404 | 405 | void output(OutputStream &OS, OutputFlags Flags) const override; 406 | 407 | StringView Name; 408 | }; 409 | 410 | struct LocalStaticGuardIdentifierNode : public IdentifierNode { 411 | LocalStaticGuardIdentifierNode() 412 | : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {} 413 | 414 | void output(OutputStream &OS, OutputFlags Flags) const override; 415 | 416 | bool IsThread = false; 417 | uint32_t ScopeIndex = 0; 418 | }; 419 | 420 | struct ConversionOperatorIdentifierNode : public IdentifierNode { 421 | ConversionOperatorIdentifierNode() 422 | : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {} 423 | 424 | void output(OutputStream &OS, OutputFlags Flags) const override; 425 | 426 | // The type that this operator converts too. 427 | TypeNode *TargetType = nullptr; 428 | }; 429 | 430 | struct StructorIdentifierNode : public IdentifierNode { 431 | StructorIdentifierNode() : IdentifierNode(NodeKind::StructorIdentifier) {} 432 | explicit StructorIdentifierNode(bool IsDestructor) 433 | : IdentifierNode(NodeKind::StructorIdentifier), 434 | IsDestructor(IsDestructor) {} 435 | 436 | void output(OutputStream &OS, OutputFlags Flags) const override; 437 | 438 | // The name of the class that this is a structor of. 439 | IdentifierNode *Class = nullptr; 440 | bool IsDestructor = false; 441 | }; 442 | 443 | struct ThunkSignatureNode : public FunctionSignatureNode { 444 | ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {} 445 | 446 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 447 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 448 | 449 | struct ThisAdjustor { 450 | uint32_t StaticOffset = 0; 451 | int32_t VBPtrOffset = 0; 452 | int32_t VBOffsetOffset = 0; 453 | int32_t VtordispOffset = 0; 454 | }; 455 | 456 | ThisAdjustor ThisAdjust; 457 | }; 458 | 459 | struct PointerTypeNode : public TypeNode { 460 | PointerTypeNode() : TypeNode(NodeKind::PointerType) {} 461 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 462 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 463 | 464 | // Is this a pointer, reference, or rvalue-reference? 465 | PointerAffinity Affinity = PointerAffinity::None; 466 | 467 | // If this is a member pointer, this is the class that the member is in. 468 | QualifiedNameNode *ClassParent = nullptr; 469 | 470 | // Represents a type X in "a pointer to X", "a reference to X", or 471 | // "rvalue-reference to X" 472 | TypeNode *Pointee = nullptr; 473 | }; 474 | 475 | struct TagTypeNode : public TypeNode { 476 | explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {} 477 | 478 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 479 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 480 | 481 | QualifiedNameNode *QualifiedName = nullptr; 482 | TagKind Tag; 483 | }; 484 | 485 | struct ArrayTypeNode : public TypeNode { 486 | ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {} 487 | 488 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 489 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 490 | 491 | void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const; 492 | void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const; 493 | 494 | // A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]` 495 | NodeArrayNode *Dimensions = nullptr; 496 | 497 | // The type of array element. 498 | TypeNode *ElementType = nullptr; 499 | }; 500 | 501 | struct IntrinsicNode : public TypeNode { 502 | IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {} 503 | void output(OutputStream &OS, OutputFlags Flags) const override {} 504 | }; 505 | 506 | struct CustomTypeNode : public TypeNode { 507 | CustomTypeNode() : TypeNode(NodeKind::Custom) {} 508 | 509 | void outputPre(OutputStream &OS, OutputFlags Flags) const override; 510 | void outputPost(OutputStream &OS, OutputFlags Flags) const override; 511 | 512 | IdentifierNode *Identifier = nullptr; 513 | }; 514 | 515 | struct NodeArrayNode : public Node { 516 | NodeArrayNode() : Node(NodeKind::NodeArray) {} 517 | 518 | void output(OutputStream &OS, OutputFlags Flags) const override; 519 | 520 | void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const; 521 | 522 | Node **Nodes = nullptr; 523 | size_t Count = 0; 524 | }; 525 | 526 | struct QualifiedNameNode : public Node { 527 | QualifiedNameNode() : Node(NodeKind::QualifiedName) {} 528 | 529 | void output(OutputStream &OS, OutputFlags Flags) const override; 530 | 531 | NodeArrayNode *Components = nullptr; 532 | 533 | IdentifierNode *getUnqualifiedIdentifier() { 534 | Node *LastComponent = Components->Nodes[Components->Count - 1]; 535 | return static_cast(LastComponent); 536 | } 537 | }; 538 | 539 | struct TemplateParameterReferenceNode : public Node { 540 | TemplateParameterReferenceNode() 541 | : Node(NodeKind::TemplateParameterReference) {} 542 | 543 | void output(OutputStream &OS, OutputFlags Flags) const override; 544 | 545 | SymbolNode *Symbol = nullptr; 546 | 547 | int ThunkOffsetCount = 0; 548 | std::array ThunkOffsets; 549 | PointerAffinity Affinity = PointerAffinity::None; 550 | bool IsMemberPointer = false; 551 | }; 552 | 553 | struct IntegerLiteralNode : public Node { 554 | IntegerLiteralNode() : Node(NodeKind::IntegerLiteral) {} 555 | IntegerLiteralNode(uint64_t Value, bool IsNegative) 556 | : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {} 557 | 558 | void output(OutputStream &OS, OutputFlags Flags) const override; 559 | 560 | uint64_t Value = 0; 561 | bool IsNegative = false; 562 | }; 563 | 564 | struct RttiBaseClassDescriptorNode : public IdentifierNode { 565 | RttiBaseClassDescriptorNode() 566 | : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {} 567 | 568 | void output(OutputStream &OS, OutputFlags Flags) const override; 569 | 570 | uint32_t NVOffset = 0; 571 | int32_t VBPtrOffset = 0; 572 | uint32_t VBTableOffset = 0; 573 | uint32_t Flags = 0; 574 | }; 575 | 576 | struct SymbolNode : public Node { 577 | explicit SymbolNode(NodeKind K) : Node(K) {} 578 | void output(OutputStream &OS, OutputFlags Flags) const override; 579 | QualifiedNameNode *Name = nullptr; 580 | }; 581 | 582 | struct SpecialTableSymbolNode : public SymbolNode { 583 | explicit SpecialTableSymbolNode() 584 | : SymbolNode(NodeKind::SpecialTableSymbol) {} 585 | 586 | void output(OutputStream &OS, OutputFlags Flags) const override; 587 | QualifiedNameNode *TargetName = nullptr; 588 | Qualifiers Quals = Qualifiers::Q_None; 589 | }; 590 | 591 | struct LocalStaticGuardVariableNode : public SymbolNode { 592 | LocalStaticGuardVariableNode() 593 | : SymbolNode(NodeKind::LocalStaticGuardVariable) {} 594 | 595 | void output(OutputStream &OS, OutputFlags Flags) const override; 596 | 597 | bool IsVisible = false; 598 | }; 599 | 600 | struct EncodedStringLiteralNode : public SymbolNode { 601 | EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {} 602 | 603 | void output(OutputStream &OS, OutputFlags Flags) const override; 604 | 605 | StringView DecodedString; 606 | bool IsTruncated = false; 607 | CharKind Char = CharKind::Char; 608 | }; 609 | 610 | struct VariableSymbolNode : public SymbolNode { 611 | VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {} 612 | 613 | void output(OutputStream &OS, OutputFlags Flags) const override; 614 | 615 | StorageClass SC = StorageClass::None; 616 | TypeNode *Type = nullptr; 617 | }; 618 | 619 | struct FunctionSymbolNode : public SymbolNode { 620 | FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {} 621 | 622 | void output(OutputStream &OS, OutputFlags Flags) const override; 623 | 624 | FunctionSignatureNode *Signature = nullptr; 625 | }; 626 | 627 | } // namespace ms_demangle 628 | } // namespace llvm 629 | 630 | #endif 631 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/MicrosoftDemangleNodes.cpp: -------------------------------------------------------------------------------- 1 | //===- MicrosoftDemangle.cpp ----------------------------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file defines a demangler for MSVC-style mangled symbols. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "llvm/Demangle/MicrosoftDemangleNodes.h" 14 | #include "llvm/Demangle/DemangleConfig.h" 15 | #include "llvm/Demangle/Utility.h" 16 | #include 17 | #include 18 | 19 | using namespace llvm; 20 | using namespace ms_demangle; 21 | 22 | #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ 23 | case Enum::Value: \ 24 | OS << Desc; \ 25 | break; 26 | 27 | // Writes a space if the last token does not end with a punctuation. 28 | static void outputSpaceIfNecessary(OutputStream &OS) { 29 | if (OS.empty()) 30 | return; 31 | 32 | char C = OS.back(); 33 | if (std::isalnum(C) || C == '>') 34 | OS << " "; 35 | } 36 | 37 | static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { 38 | switch (Q) { 39 | case Q_Const: 40 | OS << "const"; 41 | break; 42 | case Q_Volatile: 43 | OS << "volatile"; 44 | break; 45 | case Q_Restrict: 46 | OS << "__restrict"; 47 | break; 48 | default: 49 | break; 50 | } 51 | } 52 | 53 | static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, 54 | Qualifiers Mask, bool NeedSpace) { 55 | if (!(Q & Mask)) 56 | return NeedSpace; 57 | 58 | if (NeedSpace) 59 | OS << " "; 60 | 61 | outputSingleQualifier(OS, Mask); 62 | return true; 63 | } 64 | 65 | static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, 66 | bool SpaceAfter) { 67 | if (Q == Q_None) 68 | return; 69 | 70 | size_t Pos1 = OS.getCurrentPosition(); 71 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); 72 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); 73 | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); 74 | size_t Pos2 = OS.getCurrentPosition(); 75 | if (SpaceAfter && Pos2 > Pos1) 76 | OS << " "; 77 | } 78 | 79 | static void outputCallingConvention(OutputStream &OS, CallingConv CC) { 80 | outputSpaceIfNecessary(OS); 81 | 82 | switch (CC) { 83 | case CallingConv::Cdecl: 84 | OS << "__cdecl"; 85 | break; 86 | case CallingConv::Fastcall: 87 | OS << "__fastcall"; 88 | break; 89 | case CallingConv::Pascal: 90 | OS << "__pascal"; 91 | break; 92 | case CallingConv::Regcall: 93 | OS << "__regcall"; 94 | break; 95 | case CallingConv::Stdcall: 96 | OS << "__stdcall"; 97 | break; 98 | case CallingConv::Thiscall: 99 | OS << "__thiscall"; 100 | break; 101 | case CallingConv::Eabi: 102 | OS << "__eabi"; 103 | break; 104 | case CallingConv::Vectorcall: 105 | OS << "__vectorcall"; 106 | break; 107 | case CallingConv::Clrcall: 108 | OS << "__clrcall"; 109 | break; 110 | case CallingConv::Swift: 111 | OS << "__attribute__((__swiftcall__)) "; 112 | break; 113 | default: 114 | break; 115 | } 116 | } 117 | 118 | std::string Node::toString(OutputFlags Flags) const { 119 | OutputStream OS; 120 | initializeOutputStream(nullptr, nullptr, OS, 1024); 121 | this->output(OS, Flags); 122 | OS << '\0'; 123 | return {OS.getBuffer()}; 124 | } 125 | 126 | void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 127 | switch (PrimKind) { 128 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); 129 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); 130 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char"); 131 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char"); 132 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char"); 133 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t"); 134 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t"); 135 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t"); 136 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short"); 137 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short"); 138 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int"); 139 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int"); 140 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long"); 141 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long"); 142 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64"); 143 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64"); 144 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t"); 145 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float"); 146 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double"); 147 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); 148 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); 149 | } 150 | outputQualifiers(OS, Quals, true, false); 151 | } 152 | 153 | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { 154 | output(OS, Flags, ", "); 155 | } 156 | 157 | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, 158 | StringView Separator) const { 159 | if (Count == 0) 160 | return; 161 | if (Nodes[0]) 162 | Nodes[0]->output(OS, Flags); 163 | for (size_t I = 1; I < Count; ++I) { 164 | OS << Separator; 165 | Nodes[I]->output(OS, Flags); 166 | } 167 | } 168 | 169 | void EncodedStringLiteralNode::output(OutputStream &OS, 170 | OutputFlags Flags) const { 171 | switch (Char) { 172 | case CharKind::Wchar: 173 | OS << "L\""; 174 | break; 175 | case CharKind::Char: 176 | OS << "\""; 177 | break; 178 | case CharKind::Char16: 179 | OS << "u\""; 180 | break; 181 | case CharKind::Char32: 182 | OS << "U\""; 183 | break; 184 | } 185 | OS << DecodedString << "\""; 186 | if (IsTruncated) 187 | OS << "..."; 188 | } 189 | 190 | void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { 191 | if (IsNegative) 192 | OS << '-'; 193 | OS << Value; 194 | } 195 | 196 | void TemplateParameterReferenceNode::output(OutputStream &OS, 197 | OutputFlags Flags) const { 198 | if (ThunkOffsetCount > 0) 199 | OS << "{"; 200 | else if (Affinity == PointerAffinity::Pointer) 201 | OS << "&"; 202 | 203 | if (Symbol) { 204 | Symbol->output(OS, Flags); 205 | if (ThunkOffsetCount > 0) 206 | OS << ", "; 207 | } 208 | 209 | if (ThunkOffsetCount > 0) 210 | OS << ThunkOffsets[0]; 211 | for (int I = 1; I < ThunkOffsetCount; ++I) { 212 | OS << ", " << ThunkOffsets[I]; 213 | } 214 | if (ThunkOffsetCount > 0) 215 | OS << "}"; 216 | } 217 | 218 | void IdentifierNode::outputTemplateParameters(OutputStream &OS, 219 | OutputFlags Flags) const { 220 | if (!TemplateParams) 221 | return; 222 | OS << "<"; 223 | TemplateParams->output(OS, Flags); 224 | OS << ">"; 225 | } 226 | 227 | void DynamicStructorIdentifierNode::output(OutputStream &OS, 228 | OutputFlags Flags) const { 229 | if (IsDestructor) 230 | OS << "`dynamic atexit destructor for "; 231 | else 232 | OS << "`dynamic initializer for "; 233 | 234 | if (Variable) { 235 | OS << "`"; 236 | Variable->output(OS, Flags); 237 | OS << "''"; 238 | } else { 239 | OS << "'"; 240 | Name->output(OS, Flags); 241 | OS << "''"; 242 | } 243 | } 244 | 245 | void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 246 | OS << Name; 247 | outputTemplateParameters(OS, Flags); 248 | } 249 | 250 | void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, 251 | OutputFlags Flags) const { 252 | switch (Operator) { 253 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); 254 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete"); 255 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator="); 256 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>"); 257 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<"); 258 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!"); 259 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator=="); 260 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!="); 261 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, 262 | "operator[]"); 263 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->"); 264 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++"); 265 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--"); 266 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-"); 267 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+"); 268 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*"); 269 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&"); 270 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, 271 | "operator->*"); 272 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/"); 273 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%"); 274 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<"); 275 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<="); 276 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>"); 277 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, 278 | "operator>="); 279 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,"); 280 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()"); 281 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~"); 282 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^"); 283 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|"); 284 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&"); 285 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||"); 286 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*="); 287 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+="); 288 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-="); 289 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/="); 290 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%="); 291 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>="); 292 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<="); 293 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, 294 | "operator&="); 295 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, 296 | "operator|="); 297 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, 298 | "operator^="); 299 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'"); 300 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, 301 | "`vector deleting dtor'"); 302 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, 303 | "`default ctor closure'"); 304 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, 305 | "`scalar deleting dtor'"); 306 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, 307 | "`vector ctor iterator'"); 308 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, 309 | "`vector dtor iterator'"); 310 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, 311 | "`vector vbase ctor iterator'"); 312 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, 313 | "`virtual displacement map'"); 314 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, 315 | "`eh vector ctor iterator'"); 316 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, 317 | "`eh vector dtor iterator'"); 318 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, 319 | "`eh vector vbase ctor iterator'"); 320 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, 321 | "`copy ctor closure'"); 322 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, 323 | "`local vftable ctor closure'"); 324 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]"); 325 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, 326 | "operator delete[]"); 327 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, 328 | "`managed vector ctor iterator'"); 329 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, 330 | "`managed vector dtor iterator'"); 331 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, 332 | "`EH vector copy ctor iterator'"); 333 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, 334 | "`EH vector vbase copy ctor iterator'"); 335 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, 336 | "`vector copy ctor iterator'"); 337 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, 338 | "`vector vbase copy constructor iterator'"); 339 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, 340 | "`managed vector vbase copy constructor iterator'"); 341 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, 342 | "operator co_await"); 343 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); 344 | case IntrinsicFunctionKind::MaxIntrinsic: 345 | case IntrinsicFunctionKind::None: 346 | break; 347 | } 348 | outputTemplateParameters(OS, Flags); 349 | } 350 | 351 | void LocalStaticGuardIdentifierNode::output(OutputStream &OS, 352 | OutputFlags Flags) const { 353 | if (IsThread) 354 | OS << "`local static thread guard'"; 355 | else 356 | OS << "`local static guard'"; 357 | if (ScopeIndex > 0) 358 | OS << "{" << ScopeIndex << "}"; 359 | } 360 | 361 | void ConversionOperatorIdentifierNode::output(OutputStream &OS, 362 | OutputFlags Flags) const { 363 | OS << "operator"; 364 | outputTemplateParameters(OS, Flags); 365 | OS << " "; 366 | TargetType->output(OS, Flags); 367 | } 368 | 369 | void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 370 | if (IsDestructor) 371 | OS << "~"; 372 | Class->output(OS, Flags); 373 | outputTemplateParameters(OS, Flags); 374 | } 375 | 376 | void LiteralOperatorIdentifierNode::output(OutputStream &OS, 377 | OutputFlags Flags) const { 378 | OS << "operator \"\"" << Name; 379 | outputTemplateParameters(OS, Flags); 380 | } 381 | 382 | void FunctionSignatureNode::outputPre(OutputStream &OS, 383 | OutputFlags Flags) const { 384 | if (!(Flags & OF_NoAccessSpecifier)) { 385 | if (FunctionClass & FC_Public) 386 | OS << "public: "; 387 | if (FunctionClass & FC_Protected) 388 | OS << "protected: "; 389 | if (FunctionClass & FC_Private) 390 | OS << "private: "; 391 | } 392 | 393 | if (!(Flags & OF_NoMemberType)) { 394 | if (!(FunctionClass & FC_Global)) { 395 | if (FunctionClass & FC_Static) 396 | OS << "static "; 397 | } 398 | if (FunctionClass & FC_Virtual) 399 | OS << "virtual "; 400 | 401 | if (FunctionClass & FC_ExternC) 402 | OS << "extern \"C\" "; 403 | } 404 | 405 | if (!(Flags & OF_NoReturnType) && ReturnType) { 406 | ReturnType->outputPre(OS, Flags); 407 | OS << " "; 408 | } 409 | 410 | if (!(Flags & OF_NoCallingConvention)) 411 | outputCallingConvention(OS, CallConvention); 412 | } 413 | 414 | void FunctionSignatureNode::outputPost(OutputStream &OS, 415 | OutputFlags Flags) const { 416 | if (!(FunctionClass & FC_NoParameterList)) { 417 | OS << "("; 418 | if (Params) 419 | Params->output(OS, Flags); 420 | else 421 | OS << "void"; 422 | 423 | if (IsVariadic) { 424 | if (OS.back() != '(') 425 | OS << ", "; 426 | OS << "..."; 427 | } 428 | OS << ")"; 429 | } 430 | 431 | if (Quals & Q_Const) 432 | OS << " const"; 433 | if (Quals & Q_Volatile) 434 | OS << " volatile"; 435 | if (Quals & Q_Restrict) 436 | OS << " __restrict"; 437 | if (Quals & Q_Unaligned) 438 | OS << " __unaligned"; 439 | 440 | if (IsNoexcept) 441 | OS << " noexcept"; 442 | 443 | if (RefQualifier == FunctionRefQualifier::Reference) 444 | OS << " &"; 445 | else if (RefQualifier == FunctionRefQualifier::RValueReference) 446 | OS << " &&"; 447 | 448 | if (!(Flags & OF_NoReturnType) && ReturnType) 449 | ReturnType->outputPost(OS, Flags); 450 | } 451 | 452 | void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 453 | OS << "[thunk]: "; 454 | 455 | FunctionSignatureNode::outputPre(OS, Flags); 456 | } 457 | 458 | void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 459 | if (FunctionClass & FC_StaticThisAdjust) { 460 | OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; 461 | } else if (FunctionClass & FC_VirtualThisAdjust) { 462 | if (FunctionClass & FC_VirtualThisAdjustEx) { 463 | OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " 464 | << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset 465 | << ", " << ThisAdjust.StaticOffset << "}'"; 466 | } else { 467 | OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " 468 | << ThisAdjust.StaticOffset << "}'"; 469 | } 470 | } 471 | 472 | FunctionSignatureNode::outputPost(OS, Flags); 473 | } 474 | 475 | void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 476 | if (Pointee->kind() == NodeKind::FunctionSignature) { 477 | // If this is a pointer to a function, don't output the calling convention. 478 | // It needs to go inside the parentheses. 479 | const FunctionSignatureNode *Sig = 480 | static_cast(Pointee); 481 | Sig->outputPre(OS, OF_NoCallingConvention); 482 | } else 483 | Pointee->outputPre(OS, Flags); 484 | 485 | outputSpaceIfNecessary(OS); 486 | 487 | if (Quals & Q_Unaligned) 488 | OS << "__unaligned "; 489 | 490 | if (Pointee->kind() == NodeKind::ArrayType) { 491 | OS << "("; 492 | } else if (Pointee->kind() == NodeKind::FunctionSignature) { 493 | OS << "("; 494 | const FunctionSignatureNode *Sig = 495 | static_cast(Pointee); 496 | outputCallingConvention(OS, Sig->CallConvention); 497 | OS << " "; 498 | } 499 | 500 | if (ClassParent) { 501 | ClassParent->output(OS, Flags); 502 | OS << "::"; 503 | } 504 | 505 | switch (Affinity) { 506 | case PointerAffinity::Pointer: 507 | OS << "*"; 508 | break; 509 | case PointerAffinity::Reference: 510 | OS << "&"; 511 | break; 512 | case PointerAffinity::RValueReference: 513 | OS << "&&"; 514 | break; 515 | default: 516 | assert(false); 517 | } 518 | outputQualifiers(OS, Quals, false, false); 519 | } 520 | 521 | void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 522 | if (Pointee->kind() == NodeKind::ArrayType || 523 | Pointee->kind() == NodeKind::FunctionSignature) 524 | OS << ")"; 525 | 526 | Pointee->outputPost(OS, Flags); 527 | } 528 | 529 | void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 530 | if (!(Flags & OF_NoTagSpecifier)) { 531 | switch (Tag) { 532 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); 533 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct"); 534 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); 535 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); 536 | } 537 | OS << " "; 538 | } 539 | QualifiedName->output(OS, Flags); 540 | outputQualifiers(OS, Quals, true, false); 541 | } 542 | 543 | void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 544 | 545 | void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 546 | ElementType->outputPre(OS, Flags); 547 | outputQualifiers(OS, Quals, true, false); 548 | } 549 | 550 | void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, 551 | Node *N) const { 552 | assert(N->kind() == NodeKind::IntegerLiteral); 553 | IntegerLiteralNode *ILN = static_cast(N); 554 | if (ILN->Value != 0) 555 | ILN->output(OS, Flags); 556 | } 557 | 558 | void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, 559 | OutputFlags Flags) const { 560 | if (Dimensions->Count == 0) 561 | return; 562 | 563 | outputOneDimension(OS, Flags, Dimensions->Nodes[0]); 564 | for (size_t I = 1; I < Dimensions->Count; ++I) { 565 | OS << "]["; 566 | outputOneDimension(OS, Flags, Dimensions->Nodes[I]); 567 | } 568 | } 569 | 570 | void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 571 | OS << "["; 572 | outputDimensionsImpl(OS, Flags); 573 | OS << "]"; 574 | 575 | ElementType->outputPost(OS, Flags); 576 | } 577 | 578 | void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 579 | Name->output(OS, Flags); 580 | } 581 | 582 | void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 583 | Signature->outputPre(OS, Flags); 584 | outputSpaceIfNecessary(OS); 585 | Name->output(OS, Flags); 586 | Signature->outputPost(OS, Flags); 587 | } 588 | 589 | void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 590 | const char *AccessSpec = nullptr; 591 | bool IsStatic = true; 592 | switch (SC) { 593 | case StorageClass::PrivateStatic: 594 | AccessSpec = "private"; 595 | break; 596 | case StorageClass::PublicStatic: 597 | AccessSpec = "public"; 598 | break; 599 | case StorageClass::ProtectedStatic: 600 | AccessSpec = "protected"; 601 | break; 602 | default: 603 | IsStatic = false; 604 | break; 605 | } 606 | if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) 607 | OS << AccessSpec << ": "; 608 | if (!(Flags & OF_NoMemberType) && IsStatic) 609 | OS << "static "; 610 | 611 | if (Type) { 612 | Type->outputPre(OS, Flags); 613 | outputSpaceIfNecessary(OS); 614 | } 615 | Name->output(OS, Flags); 616 | if (Type) 617 | Type->outputPost(OS, Flags); 618 | } 619 | 620 | void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 621 | Identifier->output(OS, Flags); 622 | } 623 | void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 624 | 625 | void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { 626 | Components->output(OS, Flags, "::"); 627 | } 628 | 629 | void RttiBaseClassDescriptorNode::output(OutputStream &OS, 630 | OutputFlags Flags) const { 631 | OS << "`RTTI Base Class Descriptor at ("; 632 | OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " 633 | << this->Flags; 634 | OS << ")'"; 635 | } 636 | 637 | void LocalStaticGuardVariableNode::output(OutputStream &OS, 638 | OutputFlags Flags) const { 639 | Name->output(OS, Flags); 640 | } 641 | 642 | void VcallThunkIdentifierNode::output(OutputStream &OS, 643 | OutputFlags Flags) const { 644 | OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; 645 | } 646 | 647 | void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 648 | outputQualifiers(OS, Quals, false, true); 649 | Name->output(OS, Flags); 650 | if (TargetName) { 651 | OS << "{for `"; 652 | TargetName->output(OS, Flags); 653 | OS << "'}"; 654 | } 655 | } 656 | -------------------------------------------------------------------------------- /3rdparty/llvm/Demangle/MicrosoftDemangle.cpp: -------------------------------------------------------------------------------- 1 | //===- MicrosoftDemangle.cpp ----------------------------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file defines a demangler for MSVC-style mangled symbols. 10 | // 11 | // This file has no dependencies on the rest of LLVM so that it can be 12 | // easily reused in other programs such as libcxxabi. 13 | // 14 | //===----------------------------------------------------------------------===// 15 | 16 | #include "llvm/Demangle/MicrosoftDemangle.h" 17 | #include "llvm/Demangle/Demangle.h" 18 | #include "llvm/Demangle/MicrosoftDemangleNodes.h" 19 | 20 | #include "llvm/Demangle/DemangleConfig.h" 21 | #include "llvm/Demangle/StringView.h" 22 | #include "llvm/Demangle/Utility.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace llvm; 30 | using namespace ms_demangle; 31 | 32 | static bool startsWithDigit(StringView S) { 33 | return !S.empty() && std::isdigit(S.front()); 34 | } 35 | 36 | 37 | struct NodeList { 38 | Node *N = nullptr; 39 | NodeList *Next = nullptr; 40 | }; 41 | 42 | static bool isMemberPointer(StringView MangledName, bool &Error) { 43 | Error = false; 44 | switch (MangledName.popFront()) { 45 | case '$': 46 | // This is probably an rvalue reference (e.g. $$Q), and you cannot have an 47 | // rvalue reference to a member. 48 | return false; 49 | case 'A': 50 | // 'A' indicates a reference, and you cannot have a reference to a member 51 | // function or member. 52 | return false; 53 | case 'P': 54 | case 'Q': 55 | case 'R': 56 | case 'S': 57 | // These 4 values indicate some kind of pointer, but we still don't know 58 | // what. 59 | break; 60 | default: 61 | // isMemberPointer() is called only if isPointerType() returns true, 62 | // and it rejects other prefixes. 63 | DEMANGLE_UNREACHABLE; 64 | } 65 | 66 | // If it starts with a number, then 6 indicates a non-member function 67 | // pointer, and 8 indicates a member function pointer. 68 | if (startsWithDigit(MangledName)) { 69 | if (MangledName[0] != '6' && MangledName[0] != '8') { 70 | Error = true; 71 | return false; 72 | } 73 | return (MangledName[0] == '8'); 74 | } 75 | 76 | // Remove ext qualifiers since those can appear on either type and are 77 | // therefore not indicative. 78 | MangledName.consumeFront('E'); // 64-bit 79 | MangledName.consumeFront('I'); // restrict 80 | MangledName.consumeFront('F'); // unaligned 81 | 82 | if (MangledName.empty()) { 83 | Error = true; 84 | return false; 85 | } 86 | 87 | // The next value should be either ABCD (non-member) or QRST (member). 88 | switch (MangledName.front()) { 89 | case 'A': 90 | case 'B': 91 | case 'C': 92 | case 'D': 93 | return false; 94 | case 'Q': 95 | case 'R': 96 | case 'S': 97 | case 'T': 98 | return true; 99 | default: 100 | Error = true; 101 | return false; 102 | } 103 | } 104 | 105 | static SpecialIntrinsicKind 106 | consumeSpecialIntrinsicKind(StringView &MangledName) { 107 | if (MangledName.consumeFront("?_7")) 108 | return SpecialIntrinsicKind::Vftable; 109 | if (MangledName.consumeFront("?_8")) 110 | return SpecialIntrinsicKind::Vbtable; 111 | if (MangledName.consumeFront("?_9")) 112 | return SpecialIntrinsicKind::VcallThunk; 113 | if (MangledName.consumeFront("?_A")) 114 | return SpecialIntrinsicKind::Typeof; 115 | if (MangledName.consumeFront("?_B")) 116 | return SpecialIntrinsicKind::LocalStaticGuard; 117 | if (MangledName.consumeFront("?_C")) 118 | return SpecialIntrinsicKind::StringLiteralSymbol; 119 | if (MangledName.consumeFront("?_P")) 120 | return SpecialIntrinsicKind::UdtReturning; 121 | if (MangledName.consumeFront("?_R0")) 122 | return SpecialIntrinsicKind::RttiTypeDescriptor; 123 | if (MangledName.consumeFront("?_R1")) 124 | return SpecialIntrinsicKind::RttiBaseClassDescriptor; 125 | if (MangledName.consumeFront("?_R2")) 126 | return SpecialIntrinsicKind::RttiBaseClassArray; 127 | if (MangledName.consumeFront("?_R3")) 128 | return SpecialIntrinsicKind::RttiClassHierarchyDescriptor; 129 | if (MangledName.consumeFront("?_R4")) 130 | return SpecialIntrinsicKind::RttiCompleteObjLocator; 131 | if (MangledName.consumeFront("?_S")) 132 | return SpecialIntrinsicKind::LocalVftable; 133 | if (MangledName.consumeFront("?__E")) 134 | return SpecialIntrinsicKind::DynamicInitializer; 135 | if (MangledName.consumeFront("?__F")) 136 | return SpecialIntrinsicKind::DynamicAtexitDestructor; 137 | if (MangledName.consumeFront("?__J")) 138 | return SpecialIntrinsicKind::LocalStaticThreadGuard; 139 | return SpecialIntrinsicKind::None; 140 | } 141 | 142 | static bool startsWithLocalScopePattern(StringView S) { 143 | if (!S.consumeFront('?')) 144 | return false; 145 | 146 | size_t End = S.find('?'); 147 | if (End == StringView::npos) 148 | return false; 149 | StringView Candidate = S.substr(0, End); 150 | if (Candidate.empty()) 151 | return false; 152 | 153 | // \?[0-9]\? 154 | // ?@? is the discriminator 0. 155 | if (Candidate.size() == 1) 156 | return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9'); 157 | 158 | // If it's not 0-9, then it's an encoded number terminated with an @ 159 | if (Candidate.back() != '@') 160 | return false; 161 | Candidate = Candidate.dropBack(); 162 | 163 | // An encoded number starts with B-P and all subsequent digits are in A-P. 164 | // Note that the reason the first digit cannot be A is two fold. First, it 165 | // would create an ambiguity with ?A which delimits the beginning of an 166 | // anonymous namespace. Second, A represents 0, and you don't start a multi 167 | // digit number with a leading 0. Presumably the anonymous namespace 168 | // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J. 169 | if (Candidate[0] < 'B' || Candidate[0] > 'P') 170 | return false; 171 | Candidate = Candidate.dropFront(); 172 | while (!Candidate.empty()) { 173 | if (Candidate[0] < 'A' || Candidate[0] > 'P') 174 | return false; 175 | Candidate = Candidate.dropFront(); 176 | } 177 | 178 | return true; 179 | } 180 | 181 | static bool isTagType(StringView S) { 182 | switch (S.front()) { 183 | case 'T': // union 184 | case 'U': // struct 185 | case 'V': // class 186 | case 'W': // enum 187 | return true; 188 | } 189 | return false; 190 | } 191 | 192 | static bool isCustomType(StringView S) { return S[0] == '?'; } 193 | 194 | static bool isPointerType(StringView S) { 195 | if (S.startsWith("$$Q")) // foo && 196 | return true; 197 | 198 | switch (S.front()) { 199 | case 'A': // foo & 200 | case 'P': // foo * 201 | case 'Q': // foo *const 202 | case 'R': // foo *volatile 203 | case 'S': // foo *const volatile 204 | return true; 205 | } 206 | return false; 207 | } 208 | 209 | static bool isArrayType(StringView S) { return S[0] == 'Y'; } 210 | 211 | static bool isFunctionType(StringView S) { 212 | return S.startsWith("$$A8@@") || S.startsWith("$$A6"); 213 | } 214 | 215 | static FunctionRefQualifier 216 | demangleFunctionRefQualifier(StringView &MangledName) { 217 | if (MangledName.consumeFront('G')) 218 | return FunctionRefQualifier::Reference; 219 | else if (MangledName.consumeFront('H')) 220 | return FunctionRefQualifier::RValueReference; 221 | return FunctionRefQualifier::None; 222 | } 223 | 224 | static std::pair 225 | demanglePointerCVQualifiers(StringView &MangledName) { 226 | if (MangledName.consumeFront("$$Q")) 227 | return std::make_pair(Q_None, PointerAffinity::RValueReference); 228 | 229 | switch (MangledName.popFront()) { 230 | case 'A': 231 | return std::make_pair(Q_None, PointerAffinity::Reference); 232 | case 'P': 233 | return std::make_pair(Q_None, PointerAffinity::Pointer); 234 | case 'Q': 235 | return std::make_pair(Q_Const, PointerAffinity::Pointer); 236 | case 'R': 237 | return std::make_pair(Q_Volatile, PointerAffinity::Pointer); 238 | case 'S': 239 | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), 240 | PointerAffinity::Pointer); 241 | } 242 | // This function is only called if isPointerType() returns true, 243 | // and it only returns true for the six cases listed above. 244 | DEMANGLE_UNREACHABLE; 245 | } 246 | 247 | StringView Demangler::copyString(StringView Borrowed) { 248 | char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); 249 | std::strcpy(Stable, Borrowed.begin()); 250 | 251 | return {Stable, Borrowed.size()}; 252 | } 253 | 254 | SpecialTableSymbolNode * 255 | Demangler::demangleSpecialTableSymbolNode(StringView &MangledName, 256 | SpecialIntrinsicKind K) { 257 | NamedIdentifierNode *NI = Arena.alloc(); 258 | switch (K) { 259 | case SpecialIntrinsicKind::Vftable: 260 | NI->Name = "`vftable'"; 261 | break; 262 | case SpecialIntrinsicKind::Vbtable: 263 | NI->Name = "`vbtable'"; 264 | break; 265 | case SpecialIntrinsicKind::LocalVftable: 266 | NI->Name = "`local vftable'"; 267 | break; 268 | case SpecialIntrinsicKind::RttiCompleteObjLocator: 269 | NI->Name = "`RTTI Complete Object Locator'"; 270 | break; 271 | default: 272 | DEMANGLE_UNREACHABLE; 273 | } 274 | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); 275 | SpecialTableSymbolNode *STSN = Arena.alloc(); 276 | STSN->Name = QN; 277 | bool IsMember = false; 278 | if (MangledName.empty()) { 279 | Error = true; 280 | return nullptr; 281 | } 282 | char Front = MangledName.popFront(); 283 | if (Front != '6' && Front != '7') { 284 | Error = true; 285 | return nullptr; 286 | } 287 | 288 | std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName); 289 | if (!MangledName.consumeFront('@')) 290 | STSN->TargetName = demangleFullyQualifiedTypeName(MangledName); 291 | return STSN; 292 | } 293 | 294 | LocalStaticGuardVariableNode * 295 | Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) { 296 | LocalStaticGuardIdentifierNode *LSGI = 297 | Arena.alloc(); 298 | LSGI->IsThread = IsThread; 299 | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI); 300 | LocalStaticGuardVariableNode *LSGVN = 301 | Arena.alloc(); 302 | LSGVN->Name = QN; 303 | 304 | if (MangledName.consumeFront("4IA")) 305 | LSGVN->IsVisible = false; 306 | else if (MangledName.consumeFront("5")) 307 | LSGVN->IsVisible = true; 308 | else { 309 | Error = true; 310 | return nullptr; 311 | } 312 | 313 | if (!MangledName.empty()) 314 | LSGI->ScopeIndex = demangleUnsigned(MangledName); 315 | return LSGVN; 316 | } 317 | 318 | static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena, 319 | StringView Name) { 320 | NamedIdentifierNode *Id = Arena.alloc(); 321 | Id->Name = Name; 322 | return Id; 323 | } 324 | 325 | static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, 326 | IdentifierNode *Identifier) { 327 | QualifiedNameNode *QN = Arena.alloc(); 328 | QN->Components = Arena.alloc(); 329 | QN->Components->Count = 1; 330 | QN->Components->Nodes = Arena.allocArray(1); 331 | QN->Components->Nodes[0] = Identifier; 332 | return QN; 333 | } 334 | 335 | static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, 336 | StringView Name) { 337 | NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name); 338 | return synthesizeQualifiedName(Arena, Id); 339 | } 340 | 341 | static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena, 342 | TypeNode *Type, 343 | StringView VariableName) { 344 | VariableSymbolNode *VSN = Arena.alloc(); 345 | VSN->Type = Type; 346 | VSN->Name = synthesizeQualifiedName(Arena, VariableName); 347 | return VSN; 348 | } 349 | 350 | VariableSymbolNode *Demangler::demangleUntypedVariable( 351 | ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) { 352 | NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName); 353 | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); 354 | VariableSymbolNode *VSN = Arena.alloc(); 355 | VSN->Name = QN; 356 | if (MangledName.consumeFront("8")) 357 | return VSN; 358 | 359 | Error = true; 360 | return nullptr; 361 | } 362 | 363 | VariableSymbolNode * 364 | Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, 365 | StringView &MangledName) { 366 | RttiBaseClassDescriptorNode *RBCDN = 367 | Arena.alloc(); 368 | RBCDN->NVOffset = demangleUnsigned(MangledName); 369 | RBCDN->VBPtrOffset = demangleSigned(MangledName); 370 | RBCDN->VBTableOffset = demangleUnsigned(MangledName); 371 | RBCDN->Flags = demangleUnsigned(MangledName); 372 | if (Error) 373 | return nullptr; 374 | 375 | VariableSymbolNode *VSN = Arena.alloc(); 376 | VSN->Name = demangleNameScopeChain(MangledName, RBCDN); 377 | MangledName.consumeFront('8'); 378 | return VSN; 379 | } 380 | 381 | FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, 382 | bool IsDestructor) { 383 | DynamicStructorIdentifierNode *DSIN = 384 | Arena.alloc(); 385 | DSIN->IsDestructor = IsDestructor; 386 | 387 | bool IsKnownStaticDataMember = false; 388 | if (MangledName.consumeFront('?')) 389 | IsKnownStaticDataMember = true; 390 | 391 | SymbolNode *Symbol = demangleDeclarator(MangledName); 392 | if (Error) 393 | return nullptr; 394 | 395 | FunctionSymbolNode *FSN = nullptr; 396 | 397 | if (Symbol->kind() == NodeKind::VariableSymbol) { 398 | DSIN->Variable = static_cast(Symbol); 399 | 400 | // Older versions of clang mangled this type of symbol incorrectly. They 401 | // would omit the leading ? and they would only emit a single @ at the end. 402 | // The correct mangling is a leading ? and 2 trailing @ signs. Handle 403 | // both cases. 404 | int AtCount = IsKnownStaticDataMember ? 2 : 1; 405 | for (int I = 0; I < AtCount; ++I) { 406 | if (MangledName.consumeFront('@')) 407 | continue; 408 | Error = true; 409 | return nullptr; 410 | } 411 | 412 | FSN = demangleFunctionEncoding(MangledName); 413 | if (FSN) 414 | FSN->Name = synthesizeQualifiedName(Arena, DSIN); 415 | } else { 416 | if (IsKnownStaticDataMember) { 417 | // This was supposed to be a static data member, but we got a function. 418 | Error = true; 419 | return nullptr; 420 | } 421 | 422 | FSN = static_cast(Symbol); 423 | DSIN->Name = Symbol->Name; 424 | FSN->Name = synthesizeQualifiedName(Arena, DSIN); 425 | } 426 | 427 | return FSN; 428 | } 429 | 430 | SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { 431 | SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName); 432 | 433 | switch (SIK) { 434 | case SpecialIntrinsicKind::None: 435 | return nullptr; 436 | case SpecialIntrinsicKind::StringLiteralSymbol: 437 | return demangleStringLiteral(MangledName); 438 | case SpecialIntrinsicKind::Vftable: 439 | case SpecialIntrinsicKind::Vbtable: 440 | case SpecialIntrinsicKind::LocalVftable: 441 | case SpecialIntrinsicKind::RttiCompleteObjLocator: 442 | return demangleSpecialTableSymbolNode(MangledName, SIK); 443 | case SpecialIntrinsicKind::VcallThunk: 444 | return demangleVcallThunkNode(MangledName); 445 | case SpecialIntrinsicKind::LocalStaticGuard: 446 | return demangleLocalStaticGuard(MangledName, /*IsThread=*/false); 447 | case SpecialIntrinsicKind::LocalStaticThreadGuard: 448 | return demangleLocalStaticGuard(MangledName, /*IsThread=*/true); 449 | case SpecialIntrinsicKind::RttiTypeDescriptor: { 450 | TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); 451 | if (Error) 452 | break; 453 | if (!MangledName.consumeFront("@8")) 454 | break; 455 | if (!MangledName.empty()) 456 | break; 457 | return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'"); 458 | } 459 | case SpecialIntrinsicKind::RttiBaseClassArray: 460 | return demangleUntypedVariable(Arena, MangledName, 461 | "`RTTI Base Class Array'"); 462 | case SpecialIntrinsicKind::RttiClassHierarchyDescriptor: 463 | return demangleUntypedVariable(Arena, MangledName, 464 | "`RTTI Class Hierarchy Descriptor'"); 465 | case SpecialIntrinsicKind::RttiBaseClassDescriptor: 466 | return demangleRttiBaseClassDescriptorNode(Arena, MangledName); 467 | case SpecialIntrinsicKind::DynamicInitializer: 468 | return demangleInitFiniStub(MangledName, /*IsDestructor=*/false); 469 | case SpecialIntrinsicKind::DynamicAtexitDestructor: 470 | return demangleInitFiniStub(MangledName, /*IsDestructor=*/true); 471 | case SpecialIntrinsicKind::Typeof: 472 | case SpecialIntrinsicKind::UdtReturning: 473 | // It's unclear which tools produces these manglings, so demangling 474 | // support is not (yet?) implemented. 475 | break; 476 | case SpecialIntrinsicKind::Unknown: 477 | DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind. 478 | } 479 | Error = true; 480 | return nullptr; 481 | } 482 | 483 | IdentifierNode * 484 | Demangler::demangleFunctionIdentifierCode(StringView &MangledName) { 485 | assert(MangledName.startsWith('?')); 486 | MangledName = MangledName.dropFront(); 487 | if (MangledName.empty()) { 488 | Error = true; 489 | return nullptr; 490 | } 491 | 492 | if (MangledName.consumeFront("__")) 493 | return demangleFunctionIdentifierCode( 494 | MangledName, FunctionIdentifierCodeGroup::DoubleUnder); 495 | if (MangledName.consumeFront("_")) 496 | return demangleFunctionIdentifierCode(MangledName, 497 | FunctionIdentifierCodeGroup::Under); 498 | return demangleFunctionIdentifierCode(MangledName, 499 | FunctionIdentifierCodeGroup::Basic); 500 | } 501 | 502 | StructorIdentifierNode * 503 | Demangler::demangleStructorIdentifier(StringView &MangledName, 504 | bool IsDestructor) { 505 | StructorIdentifierNode *N = Arena.alloc(); 506 | N->IsDestructor = IsDestructor; 507 | return N; 508 | } 509 | 510 | ConversionOperatorIdentifierNode * 511 | Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) { 512 | ConversionOperatorIdentifierNode *N = 513 | Arena.alloc(); 514 | return N; 515 | } 516 | 517 | LiteralOperatorIdentifierNode * 518 | Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) { 519 | LiteralOperatorIdentifierNode *N = 520 | Arena.alloc(); 521 | N->Name = demangleSimpleString(MangledName, /*Memorize=*/false); 522 | return N; 523 | } 524 | 525 | IntrinsicFunctionKind 526 | Demangler::translateIntrinsicFunctionCode(char CH, 527 | FunctionIdentifierCodeGroup Group) { 528 | using IFK = IntrinsicFunctionKind; 529 | if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) { 530 | Error = true; 531 | return IFK::None; 532 | } 533 | 534 | // Not all ? identifiers are intrinsics *functions*. This function only maps 535 | // operator codes for the special functions, all others are handled elsewhere, 536 | // hence the IFK::None entries in the table. 537 | static IFK Basic[36] = { 538 | IFK::None, // ?0 # Foo::Foo() 539 | IFK::None, // ?1 # Foo::~Foo() 540 | IFK::New, // ?2 # operator new 541 | IFK::Delete, // ?3 # operator delete 542 | IFK::Assign, // ?4 # operator= 543 | IFK::RightShift, // ?5 # operator>> 544 | IFK::LeftShift, // ?6 # operator<< 545 | IFK::LogicalNot, // ?7 # operator! 546 | IFK::Equals, // ?8 # operator== 547 | IFK::NotEquals, // ?9 # operator!= 548 | IFK::ArraySubscript, // ?A # operator[] 549 | IFK::None, // ?B # Foo::operator () 550 | IFK::Pointer, // ?C # operator-> 551 | IFK::Dereference, // ?D # operator* 552 | IFK::Increment, // ?E # operator++ 553 | IFK::Decrement, // ?F # operator-- 554 | IFK::Minus, // ?G # operator- 555 | IFK::Plus, // ?H # operator+ 556 | IFK::BitwiseAnd, // ?I # operator& 557 | IFK::MemberPointer, // ?J # operator->* 558 | IFK::Divide, // ?K # operator/ 559 | IFK::Modulus, // ?L # operator% 560 | IFK::LessThan, // ?M operator< 561 | IFK::LessThanEqual, // ?N operator<= 562 | IFK::GreaterThan, // ?O operator> 563 | IFK::GreaterThanEqual, // ?P operator>= 564 | IFK::Comma, // ?Q operator, 565 | IFK::Parens, // ?R operator() 566 | IFK::BitwiseNot, // ?S operator~ 567 | IFK::BitwiseXor, // ?T operator^ 568 | IFK::BitwiseOr, // ?U operator| 569 | IFK::LogicalAnd, // ?V operator&& 570 | IFK::LogicalOr, // ?W operator|| 571 | IFK::TimesEqual, // ?X operator*= 572 | IFK::PlusEqual, // ?Y operator+= 573 | IFK::MinusEqual, // ?Z operator-= 574 | }; 575 | static IFK Under[36] = { 576 | IFK::DivEqual, // ?_0 operator/= 577 | IFK::ModEqual, // ?_1 operator%= 578 | IFK::RshEqual, // ?_2 operator>>= 579 | IFK::LshEqual, // ?_3 operator<<= 580 | IFK::BitwiseAndEqual, // ?_4 operator&= 581 | IFK::BitwiseOrEqual, // ?_5 operator|= 582 | IFK::BitwiseXorEqual, // ?_6 operator^= 583 | IFK::None, // ?_7 # vftable 584 | IFK::None, // ?_8 # vbtable 585 | IFK::None, // ?_9 # vcall 586 | IFK::None, // ?_A # typeof 587 | IFK::None, // ?_B # local static guard 588 | IFK::None, // ?_C # string literal 589 | IFK::VbaseDtor, // ?_D # vbase destructor 590 | IFK::VecDelDtor, // ?_E # vector deleting destructor 591 | IFK::DefaultCtorClosure, // ?_F # default constructor closure 592 | IFK::ScalarDelDtor, // ?_G # scalar deleting destructor 593 | IFK::VecCtorIter, // ?_H # vector constructor iterator 594 | IFK::VecDtorIter, // ?_I # vector destructor iterator 595 | IFK::VecVbaseCtorIter, // ?_J # vector vbase constructor iterator 596 | IFK::VdispMap, // ?_K # virtual displacement map 597 | IFK::EHVecCtorIter, // ?_L # eh vector constructor iterator 598 | IFK::EHVecDtorIter, // ?_M # eh vector destructor iterator 599 | IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator 600 | IFK::CopyCtorClosure, // ?_O # copy constructor closure 601 | IFK::None, // ?_P # udt returning 602 | IFK::None, // ?_Q # 603 | IFK::None, // ?_R0 - ?_R4 # RTTI Codes 604 | IFK::None, // ?_S # local vftable 605 | IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure 606 | IFK::ArrayNew, // ?_U operator new[] 607 | IFK::ArrayDelete, // ?_V operator delete[] 608 | IFK::None, // ?_W 609 | IFK::None, // ?_X 610 | IFK::None, // ?_Y 611 | IFK::None, // ?_Z 612 | }; 613 | static IFK DoubleUnder[36] = { 614 | IFK::None, // ?__0 615 | IFK::None, // ?__1 616 | IFK::None, // ?__2 617 | IFK::None, // ?__3 618 | IFK::None, // ?__4 619 | IFK::None, // ?__5 620 | IFK::None, // ?__6 621 | IFK::None, // ?__7 622 | IFK::None, // ?__8 623 | IFK::None, // ?__9 624 | IFK::ManVectorCtorIter, // ?__A managed vector ctor iterator 625 | IFK::ManVectorDtorIter, // ?__B managed vector dtor iterator 626 | IFK::EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator 627 | IFK::EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iter 628 | IFK::None, // ?__E dynamic initializer for `T' 629 | IFK::None, // ?__F dynamic atexit destructor for `T' 630 | IFK::VectorCopyCtorIter, // ?__G vector copy constructor iter 631 | IFK::VectorVbaseCopyCtorIter, // ?__H vector vbase copy ctor iter 632 | IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor 633 | // iter 634 | IFK::None, // ?__J local static thread guard 635 | IFK::None, // ?__K operator ""_name 636 | IFK::CoAwait, // ?__L operator co_await 637 | IFK::Spaceship, // ?__M operator<=> 638 | IFK::None, // ?__N 639 | IFK::None, // ?__O 640 | IFK::None, // ?__P 641 | IFK::None, // ?__Q 642 | IFK::None, // ?__R 643 | IFK::None, // ?__S 644 | IFK::None, // ?__T 645 | IFK::None, // ?__U 646 | IFK::None, // ?__V 647 | IFK::None, // ?__W 648 | IFK::None, // ?__X 649 | IFK::None, // ?__Y 650 | IFK::None, // ?__Z 651 | }; 652 | 653 | int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10); 654 | switch (Group) { 655 | case FunctionIdentifierCodeGroup::Basic: 656 | return Basic[Index]; 657 | case FunctionIdentifierCodeGroup::Under: 658 | return Under[Index]; 659 | case FunctionIdentifierCodeGroup::DoubleUnder: 660 | return DoubleUnder[Index]; 661 | } 662 | DEMANGLE_UNREACHABLE; 663 | } 664 | 665 | IdentifierNode * 666 | Demangler::demangleFunctionIdentifierCode(StringView &MangledName, 667 | FunctionIdentifierCodeGroup Group) { 668 | if (MangledName.empty()) { 669 | Error = true; 670 | return nullptr; 671 | } 672 | switch (Group) { 673 | case FunctionIdentifierCodeGroup::Basic: 674 | switch (char CH = MangledName.popFront()) { 675 | case '0': 676 | case '1': 677 | return demangleStructorIdentifier(MangledName, CH == '1'); 678 | case 'B': 679 | return demangleConversionOperatorIdentifier(MangledName); 680 | default: 681 | return Arena.alloc( 682 | translateIntrinsicFunctionCode(CH, Group)); 683 | } 684 | case FunctionIdentifierCodeGroup::Under: 685 | return Arena.alloc( 686 | translateIntrinsicFunctionCode(MangledName.popFront(), Group)); 687 | case FunctionIdentifierCodeGroup::DoubleUnder: 688 | switch (char CH = MangledName.popFront()) { 689 | case 'K': 690 | return demangleLiteralOperatorIdentifier(MangledName); 691 | default: 692 | return Arena.alloc( 693 | translateIntrinsicFunctionCode(CH, Group)); 694 | } 695 | } 696 | 697 | DEMANGLE_UNREACHABLE; 698 | } 699 | 700 | SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName, 701 | QualifiedNameNode *Name) { 702 | if (MangledName.empty()) { 703 | Error = true; 704 | return nullptr; 705 | } 706 | 707 | // Read a variable. 708 | switch (MangledName.front()) { 709 | case '0': 710 | case '1': 711 | case '2': 712 | case '3': 713 | case '4': { 714 | StorageClass SC = demangleVariableStorageClass(MangledName); 715 | return demangleVariableEncoding(MangledName, SC); 716 | } 717 | } 718 | FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName); 719 | 720 | IdentifierNode *UQN = Name->getUnqualifiedIdentifier(); 721 | if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) { 722 | ConversionOperatorIdentifierNode *COIN = 723 | static_cast(UQN); 724 | if (FSN) 725 | COIN->TargetType = FSN->Signature->ReturnType; 726 | } 727 | return FSN; 728 | } 729 | 730 | SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) { 731 | // What follows is a main symbol name. This may include namespaces or class 732 | // back references. 733 | QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName); 734 | if (Error) 735 | return nullptr; 736 | 737 | SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN); 738 | if (Error) 739 | return nullptr; 740 | Symbol->Name = QN; 741 | 742 | IdentifierNode *UQN = QN->getUnqualifiedIdentifier(); 743 | if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) { 744 | ConversionOperatorIdentifierNode *COIN = 745 | static_cast(UQN); 746 | if (!COIN->TargetType) { 747 | Error = true; 748 | return nullptr; 749 | } 750 | } 751 | return Symbol; 752 | } 753 | 754 | SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) { 755 | assert(MangledName.startsWith("??@")); 756 | // This is an MD5 mangled name. We can't demangle it, just return the 757 | // mangled name. 758 | // An MD5 mangled name is ??@ followed by 32 characters and a terminating @. 759 | size_t MD5Last = MangledName.find('@', strlen("??@")); 760 | if (MD5Last == StringView::npos) { 761 | Error = true; 762 | return nullptr; 763 | } 764 | const char *Start = MangledName.begin(); 765 | MangledName = MangledName.dropFront(MD5Last + 1); 766 | 767 | // There are two additional special cases for MD5 names: 768 | // 1. For complete object locators where the object name is long enough 769 | // for the object to have an MD5 name, the complete object locator is 770 | // called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual 771 | // leading "??_R4". This is handled here. 772 | // 2. For catchable types, in versions of MSVC before 2015 (<1900) or after 773 | // 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8 774 | // instead of_CT??@...@8 with just one MD5 name. Since we don't yet 775 | // demangle catchable types anywhere, this isn't handled for MD5 names 776 | // either. 777 | MangledName.consumeFront("??_R4@"); 778 | 779 | StringView MD5(Start, MangledName.begin()); 780 | SymbolNode *S = Arena.alloc(NodeKind::Md5Symbol); 781 | S->Name = synthesizeQualifiedName(Arena, MD5); 782 | 783 | return S; 784 | } 785 | 786 | SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) { 787 | assert(MangledName.startsWith('.')); 788 | MangledName.consumeFront('.'); 789 | 790 | TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); 791 | if (Error || !MangledName.empty()) { 792 | Error = true; 793 | return nullptr; 794 | } 795 | return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'"); 796 | } 797 | 798 | // Parser entry point. 799 | SymbolNode *Demangler::parse(StringView &MangledName) { 800 | // Typeinfo names are strings stored in RTTI data. They're not symbol names. 801 | // It's still useful to demangle them. They're the only demangled entity 802 | // that doesn't start with a "?" but a ".". 803 | if (MangledName.startsWith('.')) 804 | return demangleTypeinfoName(MangledName); 805 | 806 | if (MangledName.startsWith("??@")) 807 | return demangleMD5Name(MangledName); 808 | 809 | // MSVC-style mangled symbols must start with '?'. 810 | if (!MangledName.startsWith('?')) { 811 | Error = true; 812 | return nullptr; 813 | } 814 | 815 | MangledName.consumeFront('?'); 816 | 817 | // ?$ is a template instantiation, but all other names that start with ? are 818 | // operators / special names. 819 | if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName)) 820 | return SI; 821 | 822 | return demangleDeclarator(MangledName); 823 | } 824 | 825 | TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) { 826 | if (!MangledName.consumeFront(".?A")) 827 | return nullptr; 828 | MangledName.consumeFront(".?A"); 829 | if (MangledName.empty()) 830 | return nullptr; 831 | 832 | return demangleClassType(MangledName); 833 | } 834 | 835 | // ::= 836 | // ::= 0 # private static member 837 | // ::= 1 # protected static member 838 | // ::= 2 # public static member 839 | // ::= 3 # global 840 | // ::= 4 # static local 841 | 842 | VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName, 843 | StorageClass SC) { 844 | VariableSymbolNode *VSN = Arena.alloc(); 845 | 846 | VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop); 847 | VSN->SC = SC; 848 | 849 | if (Error) 850 | return nullptr; 851 | 852 | // ::= 853 | // ::= # pointers, references 854 | switch (VSN->Type->kind()) { 855 | case NodeKind::PointerType: { 856 | PointerTypeNode *PTN = static_cast(VSN->Type); 857 | 858 | Qualifiers ExtraChildQuals = Q_None; 859 | PTN->Quals = Qualifiers(VSN->Type->Quals | 860 | demanglePointerExtQualifiers(MangledName)); 861 | 862 | bool IsMember = false; 863 | std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName); 864 | 865 | if (PTN->ClassParent) { 866 | QualifiedNameNode *BackRefName = 867 | demangleFullyQualifiedTypeName(MangledName); 868 | (void)BackRefName; 869 | } 870 | PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals); 871 | 872 | break; 873 | } 874 | default: 875 | VSN->Type->Quals = demangleQualifiers(MangledName).first; 876 | break; 877 | } 878 | 879 | return VSN; 880 | } 881 | 882 | // Sometimes numbers are encoded in mangled symbols. For example, 883 | // "int (*x)[20]" is a valid C type (x is a pointer to an array of 884 | // length 20), so we need some way to embed numbers as part of symbols. 885 | // This function parses it. 886 | // 887 | // ::= [?] 888 | // 889 | // ::= # when 1 <= Number <= 10 890 | // ::= + @ # when Number == 0 or >= 10 891 | // 892 | // ::= [A-P] # A = 0, B = 1, ... 893 | std::pair Demangler::demangleNumber(StringView &MangledName) { 894 | bool IsNegative = MangledName.consumeFront('?'); 895 | 896 | if (startsWithDigit(MangledName)) { 897 | uint64_t Ret = MangledName[0] - '0' + 1; 898 | MangledName = MangledName.dropFront(1); 899 | return {Ret, IsNegative}; 900 | } 901 | 902 | uint64_t Ret = 0; 903 | for (size_t i = 0; i < MangledName.size(); ++i) { 904 | char C = MangledName[i]; 905 | if (C == '@') { 906 | MangledName = MangledName.dropFront(i + 1); 907 | return {Ret, IsNegative}; 908 | } 909 | if ('A' <= C && C <= 'P') { 910 | Ret = (Ret << 4) + (C - 'A'); 911 | continue; 912 | } 913 | break; 914 | } 915 | 916 | Error = true; 917 | return {0ULL, false}; 918 | } 919 | 920 | uint64_t Demangler::demangleUnsigned(StringView &MangledName) { 921 | bool IsNegative = false; 922 | uint64_t Number = 0; 923 | std::tie(Number, IsNegative) = demangleNumber(MangledName); 924 | if (IsNegative) 925 | Error = true; 926 | return Number; 927 | } 928 | 929 | int64_t Demangler::demangleSigned(StringView &MangledName) { 930 | bool IsNegative = false; 931 | uint64_t Number = 0; 932 | std::tie(Number, IsNegative) = demangleNumber(MangledName); 933 | if (Number > INT64_MAX) 934 | Error = true; 935 | int64_t I = static_cast(Number); 936 | return IsNegative ? -I : I; 937 | } 938 | 939 | // First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9. 940 | // Memorize it. 941 | void Demangler::memorizeString(StringView S) { 942 | if (Backrefs.NamesCount >= BackrefContext::Max) 943 | return; 944 | for (size_t i = 0; i < Backrefs.NamesCount; ++i) 945 | if (S == Backrefs.Names[i]->Name) 946 | return; 947 | NamedIdentifierNode *N = Arena.alloc(); 948 | N->Name = S; 949 | Backrefs.Names[Backrefs.NamesCount++] = N; 950 | } 951 | 952 | NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { 953 | assert(startsWithDigit(MangledName)); 954 | 955 | size_t I = MangledName[0] - '0'; 956 | if (I >= Backrefs.NamesCount) { 957 | Error = true; 958 | return nullptr; 959 | } 960 | 961 | MangledName = MangledName.dropFront(); 962 | return Backrefs.Names[I]; 963 | } 964 | 965 | void Demangler::memorizeIdentifier(IdentifierNode *Identifier) { 966 | // Render this class template name into a string buffer so that we can 967 | // memorize it for the purpose of back-referencing. 968 | OutputStream OS; 969 | if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) 970 | // FIXME: Propagate out-of-memory as an error? 971 | std::terminate(); 972 | Identifier->output(OS, OF_Default); 973 | OS << '\0'; 974 | char *Name = OS.getBuffer(); 975 | 976 | StringView Owned = copyString(Name); 977 | memorizeString(Owned); 978 | std::free(Name); 979 | } 980 | 981 | IdentifierNode * 982 | Demangler::demangleTemplateInstantiationName(StringView &MangledName, 983 | NameBackrefBehavior NBB) { 984 | assert(MangledName.startsWith("?$")); 985 | MangledName.consumeFront("?$"); 986 | 987 | BackrefContext OuterContext; 988 | std::swap(OuterContext, Backrefs); 989 | 990 | IdentifierNode *Identifier = 991 | demangleUnqualifiedSymbolName(MangledName, NBB_Simple); 992 | if (!Error) 993 | Identifier->TemplateParams = demangleTemplateParameterList(MangledName); 994 | 995 | std::swap(OuterContext, Backrefs); 996 | if (Error) 997 | return nullptr; 998 | 999 | if (NBB & NBB_Template) { 1000 | // NBB_Template is only set for types and non-leaf names ("a::" in "a::b"). 1001 | // Structors and conversion operators only makes sense in a leaf name, so 1002 | // reject them in NBB_Template contexts. 1003 | if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier || 1004 | Identifier->kind() == NodeKind::StructorIdentifier) { 1005 | Error = true; 1006 | return nullptr; 1007 | } 1008 | 1009 | memorizeIdentifier(Identifier); 1010 | } 1011 | 1012 | return Identifier; 1013 | } 1014 | 1015 | NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName, 1016 | bool Memorize) { 1017 | StringView S = demangleSimpleString(MangledName, Memorize); 1018 | if (Error) 1019 | return nullptr; 1020 | 1021 | NamedIdentifierNode *Name = Arena.alloc(); 1022 | Name->Name = S; 1023 | return Name; 1024 | } 1025 | 1026 | static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); } 1027 | 1028 | static uint8_t rebasedHexDigitToNumber(char C) { 1029 | assert(isRebasedHexDigit(C)); 1030 | return (C <= 'J') ? (C - 'A') : (10 + C - 'K'); 1031 | } 1032 | 1033 | uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { 1034 | assert(!MangledName.empty()); 1035 | if (!MangledName.startsWith('?')) 1036 | return MangledName.popFront(); 1037 | 1038 | MangledName = MangledName.dropFront(); 1039 | if (MangledName.empty()) 1040 | goto CharLiteralError; 1041 | 1042 | if (MangledName.consumeFront('$')) { 1043 | // Two hex digits 1044 | if (MangledName.size() < 2) 1045 | goto CharLiteralError; 1046 | StringView Nibbles = MangledName.substr(0, 2); 1047 | if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1])) 1048 | goto CharLiteralError; 1049 | // Don't append the null terminator. 1050 | uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]); 1051 | uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]); 1052 | MangledName = MangledName.dropFront(2); 1053 | return (C1 << 4) | C2; 1054 | } 1055 | 1056 | if (startsWithDigit(MangledName)) { 1057 | const char *Lookup = ",/\\:. \n\t'-"; 1058 | char C = Lookup[MangledName[0] - '0']; 1059 | MangledName = MangledName.dropFront(); 1060 | return C; 1061 | } 1062 | 1063 | if (MangledName[0] >= 'a' && MangledName[0] <= 'z') { 1064 | char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', 1065 | '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', 1066 | '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', 1067 | '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'}; 1068 | char C = Lookup[MangledName[0] - 'a']; 1069 | MangledName = MangledName.dropFront(); 1070 | return C; 1071 | } 1072 | 1073 | if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') { 1074 | char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', 1075 | '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', 1076 | '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', 1077 | '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'}; 1078 | char C = Lookup[MangledName[0] - 'A']; 1079 | MangledName = MangledName.dropFront(); 1080 | return C; 1081 | } 1082 | 1083 | CharLiteralError: 1084 | Error = true; 1085 | return '\0'; 1086 | } 1087 | 1088 | wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) { 1089 | uint8_t C1, C2; 1090 | 1091 | C1 = demangleCharLiteral(MangledName); 1092 | if (Error || MangledName.empty()) 1093 | goto WCharLiteralError; 1094 | C2 = demangleCharLiteral(MangledName); 1095 | if (Error) 1096 | goto WCharLiteralError; 1097 | 1098 | return ((wchar_t)C1 << 8) | (wchar_t)C2; 1099 | 1100 | WCharLiteralError: 1101 | Error = true; 1102 | return L'\0'; 1103 | } 1104 | 1105 | static void writeHexDigit(char *Buffer, uint8_t Digit) { 1106 | assert(Digit <= 15); 1107 | *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10); 1108 | } 1109 | 1110 | static void outputHex(OutputStream &OS, unsigned C) { 1111 | assert (C != 0); 1112 | 1113 | // It's easier to do the math if we can work from right to left, but we need 1114 | // to print the numbers from left to right. So render this into a temporary 1115 | // buffer first, then output the temporary buffer. Each byte is of the form 1116 | // \xAB, which means that each byte needs 4 characters. Since there are at 1117 | // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer. 1118 | char TempBuffer[17]; 1119 | 1120 | ::memset(TempBuffer, 0, sizeof(TempBuffer)); 1121 | constexpr int MaxPos = sizeof(TempBuffer) - 1; 1122 | 1123 | int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0. 1124 | while (C != 0) { 1125 | for (int I = 0; I < 2; ++I) { 1126 | writeHexDigit(&TempBuffer[Pos--], C % 16); 1127 | C /= 16; 1128 | } 1129 | } 1130 | TempBuffer[Pos--] = 'x'; 1131 | assert(Pos >= 0); 1132 | TempBuffer[Pos--] = '\\'; 1133 | OS << StringView(&TempBuffer[Pos + 1]); 1134 | } 1135 | 1136 | static void outputEscapedChar(OutputStream &OS, unsigned C) { 1137 | switch (C) { 1138 | case '\0': // nul 1139 | OS << "\\0"; 1140 | return; 1141 | case '\'': // single quote 1142 | OS << "\\\'"; 1143 | return; 1144 | case '\"': // double quote 1145 | OS << "\\\""; 1146 | return; 1147 | case '\\': // backslash 1148 | OS << "\\\\"; 1149 | return; 1150 | case '\a': // bell 1151 | OS << "\\a"; 1152 | return; 1153 | case '\b': // backspace 1154 | OS << "\\b"; 1155 | return; 1156 | case '\f': // form feed 1157 | OS << "\\f"; 1158 | return; 1159 | case '\n': // new line 1160 | OS << "\\n"; 1161 | return; 1162 | case '\r': // carriage return 1163 | OS << "\\r"; 1164 | return; 1165 | case '\t': // tab 1166 | OS << "\\t"; 1167 | return; 1168 | case '\v': // vertical tab 1169 | OS << "\\v"; 1170 | return; 1171 | default: 1172 | break; 1173 | } 1174 | 1175 | if (C > 0x1F && C < 0x7F) { 1176 | // Standard ascii char. 1177 | OS << (char)C; 1178 | return; 1179 | } 1180 | 1181 | outputHex(OS, C); 1182 | } 1183 | 1184 | static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { 1185 | const uint8_t *End = StringBytes + Length - 1; 1186 | unsigned Count = 0; 1187 | while (Length > 0 && *End == 0) { 1188 | --Length; 1189 | --End; 1190 | ++Count; 1191 | } 1192 | return Count; 1193 | } 1194 | 1195 | static unsigned countEmbeddedNulls(const uint8_t *StringBytes, 1196 | unsigned Length) { 1197 | unsigned Result = 0; 1198 | for (unsigned I = 0; I < Length; ++I) { 1199 | if (*StringBytes++ == 0) 1200 | ++Result; 1201 | } 1202 | return Result; 1203 | } 1204 | 1205 | // A mangled (non-wide) string literal stores the total length of the string it 1206 | // refers to (passed in NumBytes), and it contains up to 32 bytes of actual text 1207 | // (passed in StringBytes, NumChars). 1208 | static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars, 1209 | uint64_t NumBytes) { 1210 | assert(NumBytes > 0); 1211 | 1212 | // If the number of bytes is odd, this is guaranteed to be a char string. 1213 | if (NumBytes % 2 == 1) 1214 | return 1; 1215 | 1216 | // All strings can encode at most 32 bytes of data. If it's less than that, 1217 | // then we encoded the entire string. In this case we check for a 1-byte, 1218 | // 2-byte, or 4-byte null terminator. 1219 | if (NumBytes < 32) { 1220 | unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars); 1221 | if (TrailingNulls >= 4 && NumBytes % 4 == 0) 1222 | return 4; 1223 | if (TrailingNulls >= 2) 1224 | return 2; 1225 | return 1; 1226 | } 1227 | 1228 | // The whole string was not able to be encoded. Try to look at embedded null 1229 | // terminators to guess. The heuristic is that we count all embedded null 1230 | // terminators. If more than 2/3 are null, it's a char32. If more than 1/3 1231 | // are null, it's a char16. Otherwise it's a char8. This obviously isn't 1232 | // perfect and is biased towards languages that have ascii alphabets, but this 1233 | // was always going to be best effort since the encoding is lossy. 1234 | unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars); 1235 | if (Nulls >= 2 * NumChars / 3 && NumBytes % 4 == 0) 1236 | return 4; 1237 | if (Nulls >= NumChars / 3) 1238 | return 2; 1239 | return 1; 1240 | } 1241 | 1242 | static unsigned decodeMultiByteChar(const uint8_t *StringBytes, 1243 | unsigned CharIndex, unsigned CharBytes) { 1244 | assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4); 1245 | unsigned Offset = CharIndex * CharBytes; 1246 | unsigned Result = 0; 1247 | StringBytes = StringBytes + Offset; 1248 | for (unsigned I = 0; I < CharBytes; ++I) { 1249 | unsigned C = static_cast(StringBytes[I]); 1250 | Result |= C << (8 * I); 1251 | } 1252 | return Result; 1253 | } 1254 | 1255 | FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { 1256 | FunctionSymbolNode *FSN = Arena.alloc(); 1257 | VcallThunkIdentifierNode *VTIN = Arena.alloc(); 1258 | FSN->Signature = Arena.alloc(); 1259 | FSN->Signature->FunctionClass = FC_NoParameterList; 1260 | 1261 | FSN->Name = demangleNameScopeChain(MangledName, VTIN); 1262 | if (!Error) 1263 | Error = !MangledName.consumeFront("$B"); 1264 | if (!Error) 1265 | VTIN->OffsetInVTable = demangleUnsigned(MangledName); 1266 | if (!Error) 1267 | Error = !MangledName.consumeFront('A'); 1268 | if (!Error) 1269 | FSN->Signature->CallConvention = demangleCallingConvention(MangledName); 1270 | return (Error) ? nullptr : FSN; 1271 | } 1272 | 1273 | EncodedStringLiteralNode * 1274 | Demangler::demangleStringLiteral(StringView &MangledName) { 1275 | // This function uses goto, so declare all variables up front. 1276 | OutputStream OS; 1277 | StringView CRC; 1278 | uint64_t StringByteSize; 1279 | bool IsWcharT = false; 1280 | bool IsNegative = false; 1281 | size_t CrcEndPos = 0; 1282 | char *ResultBuffer = nullptr; 1283 | 1284 | EncodedStringLiteralNode *Result = Arena.alloc(); 1285 | 1286 | // Must happen before the first `goto StringLiteralError`. 1287 | if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) 1288 | // FIXME: Propagate out-of-memory as an error? 1289 | std::terminate(); 1290 | 1291 | // Prefix indicating the beginning of a string literal 1292 | if (!MangledName.consumeFront("@_")) 1293 | goto StringLiteralError; 1294 | if (MangledName.empty()) 1295 | goto StringLiteralError; 1296 | 1297 | // Char Type (regular or wchar_t) 1298 | switch (MangledName.popFront()) { 1299 | case '1': 1300 | IsWcharT = true; 1301 | DEMANGLE_FALLTHROUGH; 1302 | case '0': 1303 | break; 1304 | default: 1305 | goto StringLiteralError; 1306 | } 1307 | 1308 | // Encoded Length 1309 | std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName); 1310 | if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1)) 1311 | goto StringLiteralError; 1312 | 1313 | // CRC 32 (always 8 characters plus a terminator) 1314 | CrcEndPos = MangledName.find('@'); 1315 | if (CrcEndPos == StringView::npos) 1316 | goto StringLiteralError; 1317 | CRC = MangledName.substr(0, CrcEndPos); 1318 | MangledName = MangledName.dropFront(CrcEndPos + 1); 1319 | if (MangledName.empty()) 1320 | goto StringLiteralError; 1321 | 1322 | if (IsWcharT) { 1323 | Result->Char = CharKind::Wchar; 1324 | if (StringByteSize > 64) 1325 | Result->IsTruncated = true; 1326 | 1327 | while (!MangledName.consumeFront('@')) { 1328 | if (MangledName.size() < 2) 1329 | goto StringLiteralError; 1330 | wchar_t W = demangleWcharLiteral(MangledName); 1331 | if (StringByteSize != 2 || Result->IsTruncated) 1332 | outputEscapedChar(OS, W); 1333 | StringByteSize -= 2; 1334 | if (Error) 1335 | goto StringLiteralError; 1336 | } 1337 | } else { 1338 | // The max byte length is actually 32, but some compilers mangled strings 1339 | // incorrectly, so we have to assume it can go higher. 1340 | constexpr unsigned MaxStringByteLength = 32 * 4; 1341 | uint8_t StringBytes[MaxStringByteLength]; 1342 | 1343 | unsigned BytesDecoded = 0; 1344 | while (!MangledName.consumeFront('@')) { 1345 | if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength) 1346 | goto StringLiteralError; 1347 | StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName); 1348 | } 1349 | 1350 | if (StringByteSize > BytesDecoded) 1351 | Result->IsTruncated = true; 1352 | 1353 | unsigned CharBytes = 1354 | guessCharByteSize(StringBytes, BytesDecoded, StringByteSize); 1355 | assert(StringByteSize % CharBytes == 0); 1356 | switch (CharBytes) { 1357 | case 1: 1358 | Result->Char = CharKind::Char; 1359 | break; 1360 | case 2: 1361 | Result->Char = CharKind::Char16; 1362 | break; 1363 | case 4: 1364 | Result->Char = CharKind::Char32; 1365 | break; 1366 | default: 1367 | DEMANGLE_UNREACHABLE; 1368 | } 1369 | const unsigned NumChars = BytesDecoded / CharBytes; 1370 | for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) { 1371 | unsigned NextChar = 1372 | decodeMultiByteChar(StringBytes, CharIndex, CharBytes); 1373 | if (CharIndex + 1 < NumChars || Result->IsTruncated) 1374 | outputEscapedChar(OS, NextChar); 1375 | } 1376 | } 1377 | 1378 | OS << '\0'; 1379 | ResultBuffer = OS.getBuffer(); 1380 | Result->DecodedString = copyString(ResultBuffer); 1381 | std::free(ResultBuffer); 1382 | return Result; 1383 | 1384 | StringLiteralError: 1385 | Error = true; 1386 | std::free(OS.getBuffer()); 1387 | return nullptr; 1388 | } 1389 | 1390 | // Returns MangledName's prefix before the first '@', or an error if 1391 | // MangledName contains no '@' or the prefix has length 0. 1392 | StringView Demangler::demangleSimpleString(StringView &MangledName, 1393 | bool Memorize) { 1394 | StringView S; 1395 | for (size_t i = 0; i < MangledName.size(); ++i) { 1396 | if (MangledName[i] != '@') 1397 | continue; 1398 | if (i == 0) 1399 | break; 1400 | S = MangledName.substr(0, i); 1401 | MangledName = MangledName.dropFront(i + 1); 1402 | 1403 | if (Memorize) 1404 | memorizeString(S); 1405 | return S; 1406 | } 1407 | 1408 | Error = true; 1409 | return {}; 1410 | } 1411 | 1412 | NamedIdentifierNode * 1413 | Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { 1414 | assert(MangledName.startsWith("?A")); 1415 | MangledName.consumeFront("?A"); 1416 | 1417 | NamedIdentifierNode *Node = Arena.alloc(); 1418 | Node->Name = "`anonymous namespace'"; 1419 | size_t EndPos = MangledName.find('@'); 1420 | if (EndPos == StringView::npos) { 1421 | Error = true; 1422 | return nullptr; 1423 | } 1424 | StringView NamespaceKey = MangledName.substr(0, EndPos); 1425 | memorizeString(NamespaceKey); 1426 | MangledName = MangledName.substr(EndPos + 1); 1427 | return Node; 1428 | } 1429 | 1430 | NamedIdentifierNode * 1431 | Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { 1432 | assert(startsWithLocalScopePattern(MangledName)); 1433 | 1434 | NamedIdentifierNode *Identifier = Arena.alloc(); 1435 | MangledName.consumeFront('?'); 1436 | uint64_t Number = 0; 1437 | bool IsNegative = false; 1438 | std::tie(Number, IsNegative) = demangleNumber(MangledName); 1439 | assert(!IsNegative); 1440 | 1441 | // One ? to terminate the number 1442 | MangledName.consumeFront('?'); 1443 | 1444 | assert(!Error); 1445 | Node *Scope = parse(MangledName); 1446 | if (Error) 1447 | return nullptr; 1448 | 1449 | // Render the parent symbol's name into a buffer. 1450 | OutputStream OS; 1451 | if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) 1452 | // FIXME: Propagate out-of-memory as an error? 1453 | std::terminate(); 1454 | OS << '`'; 1455 | Scope->output(OS, OF_Default); 1456 | OS << '\''; 1457 | OS << "::`" << Number << "'"; 1458 | OS << '\0'; 1459 | char *Result = OS.getBuffer(); 1460 | Identifier->Name = copyString(Result); 1461 | std::free(Result); 1462 | return Identifier; 1463 | } 1464 | 1465 | // Parses a type name in the form of A@B@C@@ which represents C::B::A. 1466 | QualifiedNameNode * 1467 | Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { 1468 | IdentifierNode *Identifier = 1469 | demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); 1470 | if (Error) 1471 | return nullptr; 1472 | assert(Identifier); 1473 | 1474 | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); 1475 | if (Error) 1476 | return nullptr; 1477 | assert(QN); 1478 | return QN; 1479 | } 1480 | 1481 | // Parses a symbol name in the form of A@B@C@@ which represents C::B::A. 1482 | // Symbol names have slightly different rules regarding what can appear 1483 | // so we separate out the implementations for flexibility. 1484 | QualifiedNameNode * 1485 | Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { 1486 | // This is the final component of a symbol name (i.e. the leftmost component 1487 | // of a mangled name. Since the only possible template instantiation that 1488 | // can appear in this context is a function template, and since those are 1489 | // not saved for the purposes of name backreferences, only backref simple 1490 | // names. 1491 | IdentifierNode *Identifier = 1492 | demangleUnqualifiedSymbolName(MangledName, NBB_Simple); 1493 | if (Error) 1494 | return nullptr; 1495 | 1496 | QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); 1497 | if (Error) 1498 | return nullptr; 1499 | 1500 | if (Identifier->kind() == NodeKind::StructorIdentifier) { 1501 | if (QN->Components->Count < 2) { 1502 | Error = true; 1503 | return nullptr; 1504 | } 1505 | StructorIdentifierNode *SIN = 1506 | static_cast(Identifier); 1507 | Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2]; 1508 | SIN->Class = static_cast(ClassNode); 1509 | } 1510 | assert(QN); 1511 | return QN; 1512 | } 1513 | 1514 | IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName, 1515 | bool Memorize) { 1516 | // An inner-most name can be a back-reference, because a fully-qualified name 1517 | // (e.g. Scope + Inner) can contain other fully qualified names inside of 1518 | // them (for example template parameters), and these nested parameters can 1519 | // refer to previously mangled types. 1520 | if (startsWithDigit(MangledName)) 1521 | return demangleBackRefName(MangledName); 1522 | 1523 | if (MangledName.startsWith("?$")) 1524 | return demangleTemplateInstantiationName(MangledName, NBB_Template); 1525 | 1526 | return demangleSimpleName(MangledName, Memorize); 1527 | } 1528 | 1529 | IdentifierNode * 1530 | Demangler::demangleUnqualifiedSymbolName(StringView &MangledName, 1531 | NameBackrefBehavior NBB) { 1532 | if (startsWithDigit(MangledName)) 1533 | return demangleBackRefName(MangledName); 1534 | if (MangledName.startsWith("?$")) 1535 | return demangleTemplateInstantiationName(MangledName, NBB); 1536 | if (MangledName.startsWith('?')) 1537 | return demangleFunctionIdentifierCode(MangledName); 1538 | return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0); 1539 | } 1540 | 1541 | IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) { 1542 | if (startsWithDigit(MangledName)) 1543 | return demangleBackRefName(MangledName); 1544 | 1545 | if (MangledName.startsWith("?$")) 1546 | return demangleTemplateInstantiationName(MangledName, NBB_Template); 1547 | 1548 | if (MangledName.startsWith("?A")) 1549 | return demangleAnonymousNamespaceName(MangledName); 1550 | 1551 | if (startsWithLocalScopePattern(MangledName)) 1552 | return demangleLocallyScopedNamePiece(MangledName); 1553 | 1554 | return demangleSimpleName(MangledName, /*Memorize=*/true); 1555 | } 1556 | 1557 | static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head, 1558 | size_t Count) { 1559 | NodeArrayNode *N = Arena.alloc(); 1560 | N->Count = Count; 1561 | N->Nodes = Arena.allocArray(Count); 1562 | for (size_t I = 0; I < Count; ++I) { 1563 | N->Nodes[I] = Head->N; 1564 | Head = Head->Next; 1565 | } 1566 | return N; 1567 | } 1568 | 1569 | QualifiedNameNode * 1570 | Demangler::demangleNameScopeChain(StringView &MangledName, 1571 | IdentifierNode *UnqualifiedName) { 1572 | NodeList *Head = Arena.alloc(); 1573 | 1574 | Head->N = UnqualifiedName; 1575 | 1576 | size_t Count = 1; 1577 | while (!MangledName.consumeFront("@")) { 1578 | ++Count; 1579 | NodeList *NewHead = Arena.alloc(); 1580 | NewHead->Next = Head; 1581 | Head = NewHead; 1582 | 1583 | if (MangledName.empty()) { 1584 | Error = true; 1585 | return nullptr; 1586 | } 1587 | 1588 | assert(!Error); 1589 | IdentifierNode *Elem = demangleNameScopePiece(MangledName); 1590 | if (Error) 1591 | return nullptr; 1592 | 1593 | Head->N = Elem; 1594 | } 1595 | 1596 | QualifiedNameNode *QN = Arena.alloc(); 1597 | QN->Components = nodeListToNodeArray(Arena, Head, Count); 1598 | return QN; 1599 | } 1600 | 1601 | FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { 1602 | switch (MangledName.popFront()) { 1603 | case '9': 1604 | return FuncClass(FC_ExternC | FC_NoParameterList); 1605 | case 'A': 1606 | return FC_Private; 1607 | case 'B': 1608 | return FuncClass(FC_Private | FC_Far); 1609 | case 'C': 1610 | return FuncClass(FC_Private | FC_Static); 1611 | case 'D': 1612 | return FuncClass(FC_Private | FC_Static | FC_Far); 1613 | case 'E': 1614 | return FuncClass(FC_Private | FC_Virtual); 1615 | case 'F': 1616 | return FuncClass(FC_Private | FC_Virtual | FC_Far); 1617 | case 'G': 1618 | return FuncClass(FC_Private | FC_StaticThisAdjust); 1619 | case 'H': 1620 | return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far); 1621 | case 'I': 1622 | return FuncClass(FC_Protected); 1623 | case 'J': 1624 | return FuncClass(FC_Protected | FC_Far); 1625 | case 'K': 1626 | return FuncClass(FC_Protected | FC_Static); 1627 | case 'L': 1628 | return FuncClass(FC_Protected | FC_Static | FC_Far); 1629 | case 'M': 1630 | return FuncClass(FC_Protected | FC_Virtual); 1631 | case 'N': 1632 | return FuncClass(FC_Protected | FC_Virtual | FC_Far); 1633 | case 'O': 1634 | return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust); 1635 | case 'P': 1636 | return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far); 1637 | case 'Q': 1638 | return FuncClass(FC_Public); 1639 | case 'R': 1640 | return FuncClass(FC_Public | FC_Far); 1641 | case 'S': 1642 | return FuncClass(FC_Public | FC_Static); 1643 | case 'T': 1644 | return FuncClass(FC_Public | FC_Static | FC_Far); 1645 | case 'U': 1646 | return FuncClass(FC_Public | FC_Virtual); 1647 | case 'V': 1648 | return FuncClass(FC_Public | FC_Virtual | FC_Far); 1649 | case 'W': 1650 | return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust); 1651 | case 'X': 1652 | return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far); 1653 | case 'Y': 1654 | return FuncClass(FC_Global); 1655 | case 'Z': 1656 | return FuncClass(FC_Global | FC_Far); 1657 | case '$': { 1658 | FuncClass VFlag = FC_VirtualThisAdjust; 1659 | if (MangledName.consumeFront('R')) 1660 | VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx); 1661 | if (MangledName.empty()) 1662 | break; 1663 | switch (MangledName.popFront()) { 1664 | case '0': 1665 | return FuncClass(FC_Private | FC_Virtual | VFlag); 1666 | case '1': 1667 | return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far); 1668 | case '2': 1669 | return FuncClass(FC_Protected | FC_Virtual | VFlag); 1670 | case '3': 1671 | return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far); 1672 | case '4': 1673 | return FuncClass(FC_Public | FC_Virtual | VFlag); 1674 | case '5': 1675 | return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far); 1676 | } 1677 | } 1678 | } 1679 | 1680 | Error = true; 1681 | return FC_Public; 1682 | } 1683 | 1684 | CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { 1685 | if (MangledName.empty()) { 1686 | Error = true; 1687 | return CallingConv::None; 1688 | } 1689 | 1690 | switch (MangledName.popFront()) { 1691 | case 'A': 1692 | case 'B': 1693 | return CallingConv::Cdecl; 1694 | case 'C': 1695 | case 'D': 1696 | return CallingConv::Pascal; 1697 | case 'E': 1698 | case 'F': 1699 | return CallingConv::Thiscall; 1700 | case 'G': 1701 | case 'H': 1702 | return CallingConv::Stdcall; 1703 | case 'I': 1704 | case 'J': 1705 | return CallingConv::Fastcall; 1706 | case 'M': 1707 | case 'N': 1708 | return CallingConv::Clrcall; 1709 | case 'O': 1710 | case 'P': 1711 | return CallingConv::Eabi; 1712 | case 'Q': 1713 | return CallingConv::Vectorcall; 1714 | case 'S': 1715 | return CallingConv::Swift; 1716 | } 1717 | 1718 | return CallingConv::None; 1719 | } 1720 | 1721 | StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { 1722 | assert(MangledName.front() >= '0' && MangledName.front() <= '4'); 1723 | 1724 | switch (MangledName.popFront()) { 1725 | case '0': 1726 | return StorageClass::PrivateStatic; 1727 | case '1': 1728 | return StorageClass::ProtectedStatic; 1729 | case '2': 1730 | return StorageClass::PublicStatic; 1731 | case '3': 1732 | return StorageClass::Global; 1733 | case '4': 1734 | return StorageClass::FunctionLocalStatic; 1735 | } 1736 | DEMANGLE_UNREACHABLE; 1737 | } 1738 | 1739 | std::pair 1740 | Demangler::demangleQualifiers(StringView &MangledName) { 1741 | if (MangledName.empty()) { 1742 | Error = true; 1743 | return std::make_pair(Q_None, false); 1744 | } 1745 | 1746 | switch (MangledName.popFront()) { 1747 | // Member qualifiers 1748 | case 'Q': 1749 | return std::make_pair(Q_None, true); 1750 | case 'R': 1751 | return std::make_pair(Q_Const, true); 1752 | case 'S': 1753 | return std::make_pair(Q_Volatile, true); 1754 | case 'T': 1755 | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true); 1756 | // Non-Member qualifiers 1757 | case 'A': 1758 | return std::make_pair(Q_None, false); 1759 | case 'B': 1760 | return std::make_pair(Q_Const, false); 1761 | case 'C': 1762 | return std::make_pair(Q_Volatile, false); 1763 | case 'D': 1764 | return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false); 1765 | } 1766 | Error = true; 1767 | return std::make_pair(Q_None, false); 1768 | } 1769 | 1770 | // ::= 1771 | // ::= # pointers, references 1772 | TypeNode *Demangler::demangleType(StringView &MangledName, 1773 | QualifierMangleMode QMM) { 1774 | Qualifiers Quals = Q_None; 1775 | bool IsMember = false; 1776 | if (QMM == QualifierMangleMode::Mangle) { 1777 | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); 1778 | } else if (QMM == QualifierMangleMode::Result) { 1779 | if (MangledName.consumeFront('?')) 1780 | std::tie(Quals, IsMember) = demangleQualifiers(MangledName); 1781 | } 1782 | 1783 | if (MangledName.empty()) { 1784 | Error = true; 1785 | return nullptr; 1786 | } 1787 | 1788 | TypeNode *Ty = nullptr; 1789 | if (isTagType(MangledName)) 1790 | Ty = demangleClassType(MangledName); 1791 | else if (isPointerType(MangledName)) { 1792 | if (isMemberPointer(MangledName, Error)) 1793 | Ty = demangleMemberPointerType(MangledName); 1794 | else if (!Error) 1795 | Ty = demanglePointerType(MangledName); 1796 | else 1797 | return nullptr; 1798 | } else if (isArrayType(MangledName)) 1799 | Ty = demangleArrayType(MangledName); 1800 | else if (isFunctionType(MangledName)) { 1801 | if (MangledName.consumeFront("$$A8@@")) 1802 | Ty = demangleFunctionType(MangledName, true); 1803 | else { 1804 | assert(MangledName.startsWith("$$A6")); 1805 | MangledName.consumeFront("$$A6"); 1806 | Ty = demangleFunctionType(MangledName, false); 1807 | } 1808 | } else if (isCustomType(MangledName)) { 1809 | Ty = demangleCustomType(MangledName); 1810 | } else { 1811 | Ty = demanglePrimitiveType(MangledName); 1812 | } 1813 | 1814 | if (!Ty || Error) 1815 | return Ty; 1816 | Ty->Quals = Qualifiers(Ty->Quals | Quals); 1817 | return Ty; 1818 | } 1819 | 1820 | bool Demangler::demangleThrowSpecification(StringView &MangledName) { 1821 | if (MangledName.consumeFront("_E")) 1822 | return true; 1823 | if (MangledName.consumeFront('Z')) 1824 | return false; 1825 | 1826 | Error = true; 1827 | return false; 1828 | } 1829 | 1830 | FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, 1831 | bool HasThisQuals) { 1832 | FunctionSignatureNode *FTy = Arena.alloc(); 1833 | 1834 | if (HasThisQuals) { 1835 | FTy->Quals = demanglePointerExtQualifiers(MangledName); 1836 | FTy->RefQualifier = demangleFunctionRefQualifier(MangledName); 1837 | FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first); 1838 | } 1839 | 1840 | // Fields that appear on both member and non-member functions. 1841 | FTy->CallConvention = demangleCallingConvention(MangledName); 1842 | 1843 | // ::= 1844 | // ::= @ # structors (they have no declared return type) 1845 | bool IsStructor = MangledName.consumeFront('@'); 1846 | if (!IsStructor) 1847 | FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); 1848 | 1849 | FTy->Params = demangleFunctionParameterList(MangledName, FTy->IsVariadic); 1850 | 1851 | FTy->IsNoexcept = demangleThrowSpecification(MangledName); 1852 | 1853 | return FTy; 1854 | } 1855 | 1856 | FunctionSymbolNode * 1857 | Demangler::demangleFunctionEncoding(StringView &MangledName) { 1858 | FuncClass ExtraFlags = FC_None; 1859 | if (MangledName.consumeFront("$$J0")) 1860 | ExtraFlags = FC_ExternC; 1861 | 1862 | if (MangledName.empty()) { 1863 | Error = true; 1864 | return nullptr; 1865 | } 1866 | 1867 | FuncClass FC = demangleFunctionClass(MangledName); 1868 | FC = FuncClass(ExtraFlags | FC); 1869 | 1870 | FunctionSignatureNode *FSN = nullptr; 1871 | ThunkSignatureNode *TTN = nullptr; 1872 | if (FC & FC_StaticThisAdjust) { 1873 | TTN = Arena.alloc(); 1874 | TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); 1875 | } else if (FC & FC_VirtualThisAdjust) { 1876 | TTN = Arena.alloc(); 1877 | if (FC & FC_VirtualThisAdjustEx) { 1878 | TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName); 1879 | TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName); 1880 | } 1881 | TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName); 1882 | TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); 1883 | } 1884 | 1885 | if (FC & FC_NoParameterList) { 1886 | // This is an extern "C" function whose full signature hasn't been mangled. 1887 | // This happens when we need to mangle a local symbol inside of an extern 1888 | // "C" function. 1889 | FSN = Arena.alloc(); 1890 | } else { 1891 | bool HasThisQuals = !(FC & (FC_Global | FC_Static)); 1892 | FSN = demangleFunctionType(MangledName, HasThisQuals); 1893 | } 1894 | 1895 | if (Error) 1896 | return nullptr; 1897 | 1898 | if (TTN) { 1899 | *static_cast(TTN) = *FSN; 1900 | FSN = TTN; 1901 | } 1902 | FSN->FunctionClass = FC; 1903 | 1904 | FunctionSymbolNode *Symbol = Arena.alloc(); 1905 | Symbol->Signature = FSN; 1906 | return Symbol; 1907 | } 1908 | 1909 | CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) { 1910 | assert(MangledName.startsWith('?')); 1911 | MangledName.popFront(); 1912 | 1913 | CustomTypeNode *CTN = Arena.alloc(); 1914 | CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); 1915 | if (!MangledName.consumeFront('@')) 1916 | Error = true; 1917 | if (Error) 1918 | return nullptr; 1919 | return CTN; 1920 | } 1921 | 1922 | // Reads a primitive type. 1923 | PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { 1924 | if (MangledName.consumeFront("$$T")) 1925 | return Arena.alloc(PrimitiveKind::Nullptr); 1926 | 1927 | switch (MangledName.popFront()) { 1928 | case 'X': 1929 | return Arena.alloc(PrimitiveKind::Void); 1930 | case 'D': 1931 | return Arena.alloc(PrimitiveKind::Char); 1932 | case 'C': 1933 | return Arena.alloc(PrimitiveKind::Schar); 1934 | case 'E': 1935 | return Arena.alloc(PrimitiveKind::Uchar); 1936 | case 'F': 1937 | return Arena.alloc(PrimitiveKind::Short); 1938 | case 'G': 1939 | return Arena.alloc(PrimitiveKind::Ushort); 1940 | case 'H': 1941 | return Arena.alloc(PrimitiveKind::Int); 1942 | case 'I': 1943 | return Arena.alloc(PrimitiveKind::Uint); 1944 | case 'J': 1945 | return Arena.alloc(PrimitiveKind::Long); 1946 | case 'K': 1947 | return Arena.alloc(PrimitiveKind::Ulong); 1948 | case 'M': 1949 | return Arena.alloc(PrimitiveKind::Float); 1950 | case 'N': 1951 | return Arena.alloc(PrimitiveKind::Double); 1952 | case 'O': 1953 | return Arena.alloc(PrimitiveKind::Ldouble); 1954 | case '_': { 1955 | if (MangledName.empty()) { 1956 | Error = true; 1957 | return nullptr; 1958 | } 1959 | switch (MangledName.popFront()) { 1960 | case 'N': 1961 | return Arena.alloc(PrimitiveKind::Bool); 1962 | case 'J': 1963 | return Arena.alloc(PrimitiveKind::Int64); 1964 | case 'K': 1965 | return Arena.alloc(PrimitiveKind::Uint64); 1966 | case 'W': 1967 | return Arena.alloc(PrimitiveKind::Wchar); 1968 | case 'Q': 1969 | return Arena.alloc(PrimitiveKind::Char8); 1970 | case 'S': 1971 | return Arena.alloc(PrimitiveKind::Char16); 1972 | case 'U': 1973 | return Arena.alloc(PrimitiveKind::Char32); 1974 | } 1975 | break; 1976 | } 1977 | } 1978 | Error = true; 1979 | return nullptr; 1980 | } 1981 | 1982 | TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { 1983 | TagTypeNode *TT = nullptr; 1984 | 1985 | switch (MangledName.popFront()) { 1986 | case 'T': 1987 | TT = Arena.alloc(TagKind::Union); 1988 | break; 1989 | case 'U': 1990 | TT = Arena.alloc(TagKind::Struct); 1991 | break; 1992 | case 'V': 1993 | TT = Arena.alloc(TagKind::Class); 1994 | break; 1995 | case 'W': 1996 | if (!MangledName.consumeFront('4')) { 1997 | Error = true; 1998 | return nullptr; 1999 | } 2000 | TT = Arena.alloc(TagKind::Enum); 2001 | break; 2002 | default: 2003 | assert(false); 2004 | } 2005 | 2006 | TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName); 2007 | return TT; 2008 | } 2009 | 2010 | // ::= E? 2011 | // # the E is required for 64-bit non-static pointers 2012 | PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) { 2013 | PointerTypeNode *Pointer = Arena.alloc(); 2014 | 2015 | std::tie(Pointer->Quals, Pointer->Affinity) = 2016 | demanglePointerCVQualifiers(MangledName); 2017 | 2018 | if (MangledName.consumeFront("6")) { 2019 | Pointer->Pointee = demangleFunctionType(MangledName, false); 2020 | return Pointer; 2021 | } 2022 | 2023 | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); 2024 | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); 2025 | 2026 | Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); 2027 | return Pointer; 2028 | } 2029 | 2030 | PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { 2031 | PointerTypeNode *Pointer = Arena.alloc(); 2032 | 2033 | std::tie(Pointer->Quals, Pointer->Affinity) = 2034 | demanglePointerCVQualifiers(MangledName); 2035 | assert(Pointer->Affinity == PointerAffinity::Pointer); 2036 | 2037 | Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); 2038 | Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); 2039 | 2040 | // isMemberPointer() only returns true if there is at least one character 2041 | // after the qualifiers. 2042 | if (MangledName.consumeFront("8")) { 2043 | Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); 2044 | Pointer->Pointee = demangleFunctionType(MangledName, true); 2045 | } else { 2046 | Qualifiers PointeeQuals = Q_None; 2047 | bool IsMember = false; 2048 | std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName); 2049 | assert(IsMember || Error); 2050 | Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); 2051 | 2052 | Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop); 2053 | if (Pointer->Pointee) 2054 | Pointer->Pointee->Quals = PointeeQuals; 2055 | } 2056 | 2057 | return Pointer; 2058 | } 2059 | 2060 | Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) { 2061 | Qualifiers Quals = Q_None; 2062 | if (MangledName.consumeFront('E')) 2063 | Quals = Qualifiers(Quals | Q_Pointer64); 2064 | if (MangledName.consumeFront('I')) 2065 | Quals = Qualifiers(Quals | Q_Restrict); 2066 | if (MangledName.consumeFront('F')) 2067 | Quals = Qualifiers(Quals | Q_Unaligned); 2068 | 2069 | return Quals; 2070 | } 2071 | 2072 | ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { 2073 | assert(MangledName.front() == 'Y'); 2074 | MangledName.popFront(); 2075 | 2076 | uint64_t Rank = 0; 2077 | bool IsNegative = false; 2078 | std::tie(Rank, IsNegative) = demangleNumber(MangledName); 2079 | if (IsNegative || Rank == 0) { 2080 | Error = true; 2081 | return nullptr; 2082 | } 2083 | 2084 | ArrayTypeNode *ATy = Arena.alloc(); 2085 | NodeList *Head = Arena.alloc(); 2086 | NodeList *Tail = Head; 2087 | 2088 | for (uint64_t I = 0; I < Rank; ++I) { 2089 | uint64_t D = 0; 2090 | std::tie(D, IsNegative) = demangleNumber(MangledName); 2091 | if (Error || IsNegative) { 2092 | Error = true; 2093 | return nullptr; 2094 | } 2095 | Tail->N = Arena.alloc(D, IsNegative); 2096 | if (I + 1 < Rank) { 2097 | Tail->Next = Arena.alloc(); 2098 | Tail = Tail->Next; 2099 | } 2100 | } 2101 | ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank); 2102 | 2103 | if (MangledName.consumeFront("$$C")) { 2104 | bool IsMember = false; 2105 | std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName); 2106 | if (IsMember) { 2107 | Error = true; 2108 | return nullptr; 2109 | } 2110 | } 2111 | 2112 | ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop); 2113 | return ATy; 2114 | } 2115 | 2116 | // Reads a function's parameters. 2117 | NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, 2118 | bool &IsVariadic) { 2119 | // Empty parameter list. 2120 | if (MangledName.consumeFront('X')) 2121 | return nullptr; 2122 | 2123 | NodeList *Head = Arena.alloc(); 2124 | NodeList **Current = &Head; 2125 | size_t Count = 0; 2126 | while (!Error && !MangledName.startsWith('@') && 2127 | !MangledName.startsWith('Z')) { 2128 | ++Count; 2129 | 2130 | if (startsWithDigit(MangledName)) { 2131 | size_t N = MangledName[0] - '0'; 2132 | if (N >= Backrefs.FunctionParamCount) { 2133 | Error = true; 2134 | return nullptr; 2135 | } 2136 | MangledName = MangledName.dropFront(); 2137 | 2138 | *Current = Arena.alloc(); 2139 | (*Current)->N = Backrefs.FunctionParams[N]; 2140 | Current = &(*Current)->Next; 2141 | continue; 2142 | } 2143 | 2144 | size_t OldSize = MangledName.size(); 2145 | 2146 | *Current = Arena.alloc(); 2147 | TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop); 2148 | if (!TN || Error) 2149 | return nullptr; 2150 | 2151 | (*Current)->N = TN; 2152 | 2153 | size_t CharsConsumed = OldSize - MangledName.size(); 2154 | assert(CharsConsumed != 0); 2155 | 2156 | // Single-letter types are ignored for backreferences because memorizing 2157 | // them doesn't save anything. 2158 | if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1) 2159 | Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN; 2160 | 2161 | Current = &(*Current)->Next; 2162 | } 2163 | 2164 | if (Error) 2165 | return nullptr; 2166 | 2167 | NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count); 2168 | // A non-empty parameter list is terminated by either 'Z' (variadic) parameter 2169 | // list or '@' (non variadic). Careful not to consume "@Z", as in that case 2170 | // the following Z could be a throw specifier. 2171 | if (MangledName.consumeFront('@')) 2172 | return NA; 2173 | 2174 | if (MangledName.consumeFront('Z')) { 2175 | IsVariadic = true; 2176 | return NA; 2177 | } 2178 | 2179 | DEMANGLE_UNREACHABLE; 2180 | } 2181 | 2182 | NodeArrayNode * 2183 | Demangler::demangleTemplateParameterList(StringView &MangledName) { 2184 | NodeList *Head = nullptr; 2185 | NodeList **Current = &Head; 2186 | size_t Count = 0; 2187 | 2188 | while (!MangledName.startsWith('@')) { 2189 | if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || 2190 | MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) { 2191 | // parameter pack separator 2192 | continue; 2193 | } 2194 | 2195 | ++Count; 2196 | 2197 | // Template parameter lists don't participate in back-referencing. 2198 | *Current = Arena.alloc(); 2199 | 2200 | NodeList &TP = **Current; 2201 | 2202 | TemplateParameterReferenceNode *TPRN = nullptr; 2203 | if (MangledName.consumeFront("$$Y")) { 2204 | // Template alias 2205 | TP.N = demangleFullyQualifiedTypeName(MangledName); 2206 | } else if (MangledName.consumeFront("$$B")) { 2207 | // Array 2208 | TP.N = demangleType(MangledName, QualifierMangleMode::Drop); 2209 | } else if (MangledName.consumeFront("$$C")) { 2210 | // Type has qualifiers. 2211 | TP.N = demangleType(MangledName, QualifierMangleMode::Mangle); 2212 | } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") || 2213 | MangledName.startsWith("$I") || MangledName.startsWith("$J")) { 2214 | // Pointer to member 2215 | TP.N = TPRN = Arena.alloc(); 2216 | TPRN->IsMemberPointer = true; 2217 | 2218 | MangledName = MangledName.dropFront(); 2219 | // 1 - single inheritance 2220 | // H - multiple inheritance 2221 | // I - virtual inheritance 2222 | // J - unspecified inheritance 2223 | char InheritanceSpecifier = MangledName.popFront(); 2224 | SymbolNode *S = nullptr; 2225 | if (MangledName.startsWith('?')) { 2226 | S = parse(MangledName); 2227 | if (Error || !S->Name) { 2228 | Error = true; 2229 | return nullptr; 2230 | } 2231 | memorizeIdentifier(S->Name->getUnqualifiedIdentifier()); 2232 | } 2233 | 2234 | switch (InheritanceSpecifier) { 2235 | case 'J': 2236 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2237 | demangleSigned(MangledName); 2238 | DEMANGLE_FALLTHROUGH; 2239 | case 'I': 2240 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2241 | demangleSigned(MangledName); 2242 | DEMANGLE_FALLTHROUGH; 2243 | case 'H': 2244 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2245 | demangleSigned(MangledName); 2246 | DEMANGLE_FALLTHROUGH; 2247 | case '1': 2248 | break; 2249 | default: 2250 | DEMANGLE_UNREACHABLE; 2251 | } 2252 | TPRN->Affinity = PointerAffinity::Pointer; 2253 | TPRN->Symbol = S; 2254 | } else if (MangledName.startsWith("$E?")) { 2255 | MangledName.consumeFront("$E"); 2256 | // Reference to symbol 2257 | TP.N = TPRN = Arena.alloc(); 2258 | TPRN->Symbol = parse(MangledName); 2259 | TPRN->Affinity = PointerAffinity::Reference; 2260 | } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) { 2261 | TP.N = TPRN = Arena.alloc(); 2262 | 2263 | // Data member pointer. 2264 | MangledName = MangledName.dropFront(); 2265 | char InheritanceSpecifier = MangledName.popFront(); 2266 | 2267 | switch (InheritanceSpecifier) { 2268 | case 'G': 2269 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2270 | demangleSigned(MangledName); 2271 | DEMANGLE_FALLTHROUGH; 2272 | case 'F': 2273 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2274 | demangleSigned(MangledName); 2275 | TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = 2276 | demangleSigned(MangledName); 2277 | break; 2278 | default: 2279 | DEMANGLE_UNREACHABLE; 2280 | } 2281 | TPRN->IsMemberPointer = true; 2282 | 2283 | } else if (MangledName.consumeFront("$0")) { 2284 | // Integral non-type template parameter 2285 | bool IsNegative = false; 2286 | uint64_t Value = 0; 2287 | std::tie(Value, IsNegative) = demangleNumber(MangledName); 2288 | 2289 | TP.N = Arena.alloc(Value, IsNegative); 2290 | } else { 2291 | TP.N = demangleType(MangledName, QualifierMangleMode::Drop); 2292 | } 2293 | if (Error) 2294 | return nullptr; 2295 | 2296 | Current = &TP.Next; 2297 | } 2298 | 2299 | // The loop above returns nullptr on Error. 2300 | assert(!Error); 2301 | 2302 | // Template parameter lists cannot be variadic, so it can only be terminated 2303 | // by @ (as opposed to 'Z' in the function parameter case). 2304 | assert(MangledName.startsWith('@')); // The above loop exits only on '@'. 2305 | MangledName.consumeFront('@'); 2306 | return nodeListToNodeArray(Arena, Head, Count); 2307 | } 2308 | 2309 | void Demangler::dumpBackReferences() { 2310 | std::printf("%d function parameter backreferences\n", 2311 | (int)Backrefs.FunctionParamCount); 2312 | 2313 | // Create an output stream so we can render each type. 2314 | OutputStream OS; 2315 | if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) 2316 | std::terminate(); 2317 | for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { 2318 | OS.setCurrentPosition(0); 2319 | 2320 | TypeNode *T = Backrefs.FunctionParams[I]; 2321 | T->output(OS, OF_Default); 2322 | 2323 | printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(), 2324 | OS.getBuffer()); 2325 | } 2326 | std::free(OS.getBuffer()); 2327 | 2328 | if (Backrefs.FunctionParamCount > 0) 2329 | std::printf("\n"); 2330 | std::printf("%d name backreferences\n", (int)Backrefs.NamesCount); 2331 | for (size_t I = 0; I < Backrefs.NamesCount; ++I) { 2332 | std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(), 2333 | Backrefs.Names[I]->Name.begin()); 2334 | } 2335 | if (Backrefs.NamesCount > 0) 2336 | std::printf("\n"); 2337 | } 2338 | 2339 | char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, 2340 | char *Buf, size_t *N, 2341 | int *Status, MSDemangleFlags Flags) { 2342 | Demangler D; 2343 | OutputStream S; 2344 | 2345 | StringView Name{MangledName}; 2346 | SymbolNode *AST = D.parse(Name); 2347 | if (!D.Error && NMangled) 2348 | *NMangled = Name.begin() - MangledName; 2349 | 2350 | if (Flags & MSDF_DumpBackrefs) 2351 | D.dumpBackReferences(); 2352 | 2353 | OutputFlags OF = OF_Default; 2354 | if (Flags & MSDF_NoCallingConvention) 2355 | OF = OutputFlags(OF | OF_NoCallingConvention); 2356 | if (Flags & MSDF_NoAccessSpecifier) 2357 | OF = OutputFlags(OF | OF_NoAccessSpecifier); 2358 | if (Flags & MSDF_NoReturnType) 2359 | OF = OutputFlags(OF | OF_NoReturnType); 2360 | if (Flags & MSDF_NoMemberType) 2361 | OF = OutputFlags(OF | OF_NoMemberType); 2362 | 2363 | int InternalStatus = demangle_success; 2364 | if (D.Error) 2365 | InternalStatus = demangle_invalid_mangled_name; 2366 | else if (!initializeOutputStream(Buf, N, S, 1024)) 2367 | InternalStatus = demangle_memory_alloc_failure; 2368 | else { 2369 | AST->output(S, OF); 2370 | S += '\0'; 2371 | if (N != nullptr) 2372 | *N = S.getCurrentPosition(); 2373 | Buf = S.getBuffer(); 2374 | } 2375 | 2376 | if (Status) 2377 | *Status = InternalStatus; 2378 | return InternalStatus == demangle_success ? Buf : nullptr; 2379 | } 2380 | --------------------------------------------------------------------------------