| //===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H |
| #define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H |
| |
| #include "llvm/Demangle/DemangleConfig.h" |
| #include "llvm/Demangle/MicrosoftDemangleNodes.h" |
| #include "llvm/Demangle/StringView.h" |
| #include "llvm/Demangle/Utility.h" |
| |
| #include <utility> |
| |
| namespace llvm { |
| namespace ms_demangle { |
| // This memory allocator is extremely fast, but it doesn't call dtors |
| // for allocated objects. That means you can't use STL containers |
| // (such as std::vector) with this allocator. But it pays off -- |
| // the demangler is 3x faster with this allocator compared to one with |
| // STL containers. |
| constexpr size_t AllocUnit = 4096; |
| |
| class ArenaAllocator { |
| struct AllocatorNode { |
| uint8_t *Buf = nullptr; |
| size_t Used = 0; |
| size_t Capacity = 0; |
| AllocatorNode *Next = nullptr; |
| }; |
| |
| void addNode(size_t Capacity) { |
| AllocatorNode *NewHead = new AllocatorNode; |
| NewHead->Buf = new uint8_t[Capacity]; |
| NewHead->Next = Head; |
| NewHead->Capacity = Capacity; |
| Head = NewHead; |
| NewHead->Used = 0; |
| } |
| |
| public: |
| ArenaAllocator() { addNode(AllocUnit); } |
| |
| ~ArenaAllocator() { |
| while (Head) { |
| assert(Head->Buf); |
| delete[] Head->Buf; |
| AllocatorNode *Next = Head->Next; |
| delete Head; |
| Head = Next; |
| } |
| } |
| |
| char *allocUnalignedBuffer(size_t Size) { |
| assert(Head && Head->Buf); |
| |
| uint8_t *P = Head->Buf + Head->Used; |
| |
| Head->Used += Size; |
| if (Head->Used <= Head->Capacity) |
| return reinterpret_cast<char *>(P); |
| |
| addNode(std::max(AllocUnit, Size)); |
| Head->Used = Size; |
| return reinterpret_cast<char *>(Head->Buf); |
| } |
| |
| template <typename T, typename... Args> T *allocArray(size_t Count) { |
| size_t Size = Count * sizeof(T); |
| assert(Head && Head->Buf); |
| |
| size_t P = (size_t)Head->Buf + Head->Used; |
| uintptr_t AlignedP = |
| (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); |
| uint8_t *PP = (uint8_t *)AlignedP; |
| size_t Adjustment = AlignedP - P; |
| |
| Head->Used += Size + Adjustment; |
| if (Head->Used <= Head->Capacity) |
| return new (PP) T[Count](); |
| |
| addNode(std::max(AllocUnit, Size)); |
| Head->Used = Size; |
| return new (Head->Buf) T[Count](); |
| } |
| |
| template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) { |
| constexpr size_t Size = sizeof(T); |
| assert(Head && Head->Buf); |
| |
| size_t P = (size_t)Head->Buf + Head->Used; |
| uintptr_t AlignedP = |
| (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); |
| uint8_t *PP = (uint8_t *)AlignedP; |
| size_t Adjustment = AlignedP - P; |
| |
| Head->Used += Size + Adjustment; |
| if (Head->Used <= Head->Capacity) |
| return new (PP) T(std::forward<Args>(ConstructorArgs)...); |
| |
| static_assert(Size < AllocUnit, ""); |
| addNode(AllocUnit); |
| Head->Used = Size; |
| return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...); |
| } |
| |
| private: |
| AllocatorNode *Head = nullptr; |
| }; |
| |
| struct BackrefContext { |
| static constexpr size_t Max = 10; |
| |
| TypeNode *FunctionParams[Max]; |
| size_t FunctionParamCount = 0; |
| |
| // The first 10 BackReferences in a mangled name can be back-referenced by |
| // special name @[0-9]. This is a storage for the first 10 BackReferences. |
| NamedIdentifierNode *Names[Max]; |
| size_t NamesCount = 0; |
| }; |
| |
| enum class QualifierMangleMode { Drop, Mangle, Result }; |
| |
| enum NameBackrefBehavior : uint8_t { |
| NBB_None = 0, // don't save any names as backrefs. |
| NBB_Template = 1 << 0, // save template instanations. |
| NBB_Simple = 1 << 1, // save simple names. |
| }; |
| |
| enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder }; |
| |
| // Demangler class takes the main role in demangling symbols. |
| // It has a set of functions to parse mangled symbols into Type instances. |
| // It also has a set of functions to convert Type instances to strings. |
| class Demangler { |
| public: |
| Demangler() = default; |
| virtual ~Demangler() = default; |
| |
| // You are supposed to call parse() first and then check if error is true. If |
| // it is false, call output() to write the formatted name to the given stream. |
| SymbolNode *parse(StringView &MangledName); |
| |
| TagTypeNode *parseTagUniqueName(StringView &MangledName); |
| |
| // True if an error occurred. |
| bool Error = false; |
| |
| void dumpBackReferences(); |
| |
| private: |
| SymbolNode *demangleEncodedSymbol(StringView &MangledName, |
| QualifiedNameNode *QN); |
| SymbolNode *demangleDeclarator(StringView &MangledName); |
| SymbolNode *demangleMD5Name(StringView &MangledName); |
| SymbolNode *demangleTypeinfoName(StringView &MangledName); |
| |
| VariableSymbolNode *demangleVariableEncoding(StringView &MangledName, |
| StorageClass SC); |
| FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName); |
| |
| Qualifiers demanglePointerExtQualifiers(StringView &MangledName); |
| |
| // Parser functions. This is a recursive-descent parser. |
| TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM); |
| PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName); |
| CustomTypeNode *demangleCustomType(StringView &MangledName); |
| TagTypeNode *demangleClassType(StringView &MangledName); |
| PointerTypeNode *demanglePointerType(StringView &MangledName); |
| PointerTypeNode *demangleMemberPointerType(StringView &MangledName); |
| FunctionSignatureNode *demangleFunctionType(StringView &MangledName, |
| bool HasThisQuals); |
| |
| ArrayTypeNode *demangleArrayType(StringView &MangledName); |
| |
| NodeArrayNode *demangleFunctionParameterList(StringView &MangledName, |
| bool &IsVariadic); |
| NodeArrayNode *demangleTemplateParameterList(StringView &MangledName); |
| |
| std::pair<uint64_t, bool> demangleNumber(StringView &MangledName); |
| uint64_t demangleUnsigned(StringView &MangledName); |
| int64_t demangleSigned(StringView &MangledName); |
| |
| void memorizeString(StringView s); |
| void memorizeIdentifier(IdentifierNode *Identifier); |
| |
| /// Allocate a copy of \p Borrowed into memory that we own. |
| StringView copyString(StringView Borrowed); |
| |
| QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName); |
| QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName); |
| |
| IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName, |
| bool Memorize); |
| IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName, |
| NameBackrefBehavior NBB); |
| |
| QualifiedNameNode *demangleNameScopeChain(StringView &MangledName, |
| IdentifierNode *UnqualifiedName); |
| IdentifierNode *demangleNameScopePiece(StringView &MangledName); |
| |
| NamedIdentifierNode *demangleBackRefName(StringView &MangledName); |
| IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName, |
| NameBackrefBehavior NBB); |
| IntrinsicFunctionKind |
| translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group); |
| IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName); |
| IdentifierNode * |
| demangleFunctionIdentifierCode(StringView &MangledName, |
| FunctionIdentifierCodeGroup Group); |
| StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName, |
| bool IsDestructor); |
| ConversionOperatorIdentifierNode * |
| demangleConversionOperatorIdentifier(StringView &MangledName); |
| LiteralOperatorIdentifierNode * |
| demangleLiteralOperatorIdentifier(StringView &MangledName); |
| |
| SymbolNode *demangleSpecialIntrinsic(StringView &MangledName); |
| SpecialTableSymbolNode * |
| demangleSpecialTableSymbolNode(StringView &MangledName, |
| SpecialIntrinsicKind SIK); |
| LocalStaticGuardVariableNode * |
| demangleLocalStaticGuard(StringView &MangledName, bool IsThread); |
| VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, |
| StringView &MangledName, |
| StringView VariableName); |
| VariableSymbolNode * |
| demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, |
| StringView &MangledName); |
| FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName, |
| bool IsDestructor); |
| |
| NamedIdentifierNode *demangleSimpleName(StringView &MangledName, |
| bool Memorize); |
| NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName); |
| NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName); |
| EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName); |
| FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName); |
| |
| StringView demangleSimpleString(StringView &MangledName, bool Memorize); |
| |
| FuncClass demangleFunctionClass(StringView &MangledName); |
| CallingConv demangleCallingConvention(StringView &MangledName); |
| StorageClass demangleVariableStorageClass(StringView &MangledName); |
| bool demangleThrowSpecification(StringView &MangledName); |
| wchar_t demangleWcharLiteral(StringView &MangledName); |
| uint8_t demangleCharLiteral(StringView &MangledName); |
| |
| std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName); |
| |
| // Memory allocator. |
| ArenaAllocator Arena; |
| |
| // A single type uses one global back-ref table for all function params. |
| // This means back-refs can even go "into" other types. Examples: |
| // |
| // // Second int* is a back-ref to first. |
| // void foo(int *, int*); |
| // |
| // // Second int* is not a back-ref to first (first is not a function param). |
| // int* foo(int*); |
| // |
| // // Second int* is a back-ref to first (ALL function types share the same |
| // // back-ref map. |
| // using F = void(*)(int*); |
| // F G(int *); |
| BackrefContext Backrefs; |
| }; |
| |
| } // namespace ms_demangle |
| } // namespace llvm |
| |
| #endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H |