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/Demangle.h" 13 #include "llvm/Demangle/MicrosoftDemangleNodes.h" 14 15 #include <cassert> 16 #include <string_view> 17 #include <utility> 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 addNode(size_t Capacity)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: ArenaAllocator()46 ArenaAllocator() { addNode(AllocUnit); } 47 ~ArenaAllocator()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 // Delete the copy constructor and the copy assignment operator. 59 ArenaAllocator(const ArenaAllocator &) = delete; 60 ArenaAllocator &operator=(const ArenaAllocator &) = delete; 61 allocUnalignedBuffer(size_t Size)62 char *allocUnalignedBuffer(size_t Size) { 63 assert(Head && Head->Buf); 64 65 uint8_t *P = Head->Buf + Head->Used; 66 67 Head->Used += Size; 68 if (Head->Used <= Head->Capacity) 69 return reinterpret_cast<char *>(P); 70 71 addNode(std::max(AllocUnit, Size)); 72 Head->Used = Size; 73 return reinterpret_cast<char *>(Head->Buf); 74 } 75 allocArray(size_t Count)76 template <typename T, typename... Args> T *allocArray(size_t Count) { 77 size_t Size = Count * sizeof(T); 78 assert(Head && Head->Buf); 79 80 size_t P = (size_t)Head->Buf + Head->Used; 81 uintptr_t AlignedP = 82 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); 83 uint8_t *PP = (uint8_t *)AlignedP; 84 size_t Adjustment = AlignedP - P; 85 86 Head->Used += Size + Adjustment; 87 if (Head->Used <= Head->Capacity) 88 return new (PP) T[Count](); 89 90 addNode(std::max(AllocUnit, Size)); 91 Head->Used = Size; 92 return new (Head->Buf) T[Count](); 93 } 94 alloc(Args &&...ConstructorArgs)95 template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) { 96 constexpr size_t Size = sizeof(T); 97 assert(Head && Head->Buf); 98 99 size_t P = (size_t)Head->Buf + Head->Used; 100 uintptr_t AlignedP = 101 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); 102 uint8_t *PP = (uint8_t *)AlignedP; 103 size_t Adjustment = AlignedP - P; 104 105 Head->Used += Size + Adjustment; 106 if (Head->Used <= Head->Capacity) 107 return new (PP) T(std::forward<Args>(ConstructorArgs)...); 108 109 static_assert(Size < AllocUnit); 110 addNode(AllocUnit); 111 Head->Used = Size; 112 return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...); 113 } 114 115 private: 116 AllocatorNode *Head = nullptr; 117 }; 118 119 struct BackrefContext { 120 static constexpr size_t Max = 10; 121 122 TypeNode *FunctionParams[Max]; 123 size_t FunctionParamCount = 0; 124 125 // The first 10 BackReferences in a mangled name can be back-referenced by 126 // special name @[0-9]. This is a storage for the first 10 BackReferences. 127 NamedIdentifierNode *Names[Max]; 128 size_t NamesCount = 0; 129 }; 130 131 enum class QualifierMangleMode { Drop, Mangle, Result }; 132 133 enum NameBackrefBehavior : uint8_t { 134 NBB_None = 0, // don't save any names as backrefs. 135 NBB_Template = 1 << 0, // save template instanations. 136 NBB_Simple = 1 << 1, // save simple names. 137 }; 138 139 enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder }; 140 141 // Demangler class takes the main role in demangling symbols. 142 // It has a set of functions to parse mangled symbols into Type instances. 143 // It also has a set of functions to convert Type instances to strings. 144 class Demangler { 145 friend std::optional<size_t> 146 llvm::getArm64ECInsertionPointInMangledName(std::string_view MangledName); 147 148 public: 149 Demangler() = default; 150 virtual ~Demangler() = default; 151 152 // You are supposed to call parse() first and then check if error is true. If 153 // it is false, call output() to write the formatted name to the given stream. 154 SymbolNode *parse(std::string_view &MangledName); 155 156 TagTypeNode *parseTagUniqueName(std::string_view &MangledName); 157 158 // True if an error occurred. 159 bool Error = false; 160 161 void dumpBackReferences(); 162 163 private: 164 SymbolNode *demangleEncodedSymbol(std::string_view &MangledName, 165 QualifiedNameNode *QN); 166 SymbolNode *demangleDeclarator(std::string_view &MangledName); 167 SymbolNode *demangleMD5Name(std::string_view &MangledName); 168 SymbolNode *demangleTypeinfoName(std::string_view &MangledName); 169 170 VariableSymbolNode *demangleVariableEncoding(std::string_view &MangledName, 171 StorageClass SC); 172 FunctionSymbolNode *demangleFunctionEncoding(std::string_view &MangledName); 173 174 Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName); 175 176 bool isMemberPointer(std::string_view MangledName, bool &Error); 177 178 std::optional<PointerAuthQualifierNode::ArgArray> 179 demanglePointerAuthQualifier(std::string_view &MangledName); 180 181 PointerAuthQualifierNode * 182 createPointerAuthQualifier(std::string_view &MangledName); 183 184 // Parser functions. This is a recursive-descent parser. 185 TypeNode *demangleType(std::string_view &MangledName, 186 QualifierMangleMode QMM); 187 PrimitiveTypeNode *demanglePrimitiveType(std::string_view &MangledName); 188 CustomTypeNode *demangleCustomType(std::string_view &MangledName); 189 TagTypeNode *demangleClassType(std::string_view &MangledName); 190 PointerTypeNode *demanglePointerType(std::string_view &MangledName); 191 PointerTypeNode *demangleMemberPointerType(std::string_view &MangledName); 192 FunctionSignatureNode *demangleFunctionType(std::string_view &MangledName, 193 bool HasThisQuals); 194 195 ArrayTypeNode *demangleArrayType(std::string_view &MangledName); 196 197 NodeArrayNode *demangleFunctionParameterList(std::string_view &MangledName, 198 bool &IsVariadic); 199 NodeArrayNode *demangleTemplateParameterList(std::string_view &MangledName); 200 201 std::pair<uint64_t, bool> demangleNumber(std::string_view &MangledName); 202 uint64_t demangleUnsigned(std::string_view &MangledName); 203 int64_t demangleSigned(std::string_view &MangledName); 204 205 void memorizeString(std::string_view s); 206 void memorizeIdentifier(IdentifierNode *Identifier); 207 208 /// Allocate a copy of \p Borrowed into memory that we own. 209 std::string_view copyString(std::string_view Borrowed); 210 211 QualifiedNameNode * 212 demangleFullyQualifiedTypeName(std::string_view &MangledName); 213 QualifiedNameNode * 214 demangleFullyQualifiedSymbolName(std::string_view &MangledName); 215 216 IdentifierNode *demangleUnqualifiedTypeName(std::string_view &MangledName, 217 bool Memorize); 218 IdentifierNode *demangleUnqualifiedSymbolName(std::string_view &MangledName, 219 NameBackrefBehavior NBB); 220 221 QualifiedNameNode *demangleNameScopeChain(std::string_view &MangledName, 222 IdentifierNode *UnqualifiedName); 223 IdentifierNode *demangleNameScopePiece(std::string_view &MangledName); 224 225 NamedIdentifierNode *demangleBackRefName(std::string_view &MangledName); 226 IdentifierNode * 227 demangleTemplateInstantiationName(std::string_view &MangledName, 228 NameBackrefBehavior NBB); 229 IntrinsicFunctionKind 230 translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group); 231 IdentifierNode *demangleFunctionIdentifierCode(std::string_view &MangledName); 232 IdentifierNode * 233 demangleFunctionIdentifierCode(std::string_view &MangledName, 234 FunctionIdentifierCodeGroup Group); 235 StructorIdentifierNode * 236 demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor); 237 ConversionOperatorIdentifierNode * 238 demangleConversionOperatorIdentifier(std::string_view &MangledName); 239 LiteralOperatorIdentifierNode * 240 demangleLiteralOperatorIdentifier(std::string_view &MangledName); 241 242 SymbolNode *demangleSpecialIntrinsic(std::string_view &MangledName); 243 SpecialTableSymbolNode * 244 demangleSpecialTableSymbolNode(std::string_view &MangledName, 245 SpecialIntrinsicKind SIK); 246 LocalStaticGuardVariableNode * 247 demangleLocalStaticGuard(std::string_view &MangledName, bool IsThread); 248 VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, 249 std::string_view &MangledName, 250 std::string_view VariableName); 251 VariableSymbolNode * 252 demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, 253 std::string_view &MangledName); 254 FunctionSymbolNode *demangleInitFiniStub(std::string_view &MangledName, 255 bool IsDestructor); 256 257 NamedIdentifierNode *demangleSimpleName(std::string_view &MangledName, 258 bool Memorize); 259 NamedIdentifierNode * 260 demangleAnonymousNamespaceName(std::string_view &MangledName); 261 NamedIdentifierNode * 262 demangleLocallyScopedNamePiece(std::string_view &MangledName); 263 EncodedStringLiteralNode * 264 demangleStringLiteral(std::string_view &MangledName); 265 FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName); 266 267 std::string_view demangleSimpleString(std::string_view &MangledName, 268 bool Memorize); 269 270 FuncClass demangleFunctionClass(std::string_view &MangledName); 271 CallingConv demangleCallingConvention(std::string_view &MangledName); 272 StorageClass demangleVariableStorageClass(std::string_view &MangledName); 273 bool demangleThrowSpecification(std::string_view &MangledName); 274 wchar_t demangleWcharLiteral(std::string_view &MangledName); 275 uint8_t demangleCharLiteral(std::string_view &MangledName); 276 277 std::pair<Qualifiers, bool> demangleQualifiers(std::string_view &MangledName); 278 279 // Memory allocator. 280 ArenaAllocator Arena; 281 282 // A single type uses one global back-ref table for all function params. 283 // This means back-refs can even go "into" other types. Examples: 284 // 285 // // Second int* is a back-ref to first. 286 // void foo(int *, int*); 287 // 288 // // Second int* is not a back-ref to first (first is not a function param). 289 // int* foo(int*); 290 // 291 // // Second int* is a back-ref to first (ALL function types share the same 292 // // back-ref map. 293 // using F = void(*)(int*); 294 // F G(int *); 295 BackrefContext Backrefs; 296 }; 297 298 } // namespace ms_demangle 299 } // namespace llvm 300 301 #endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H 302