//===------------------------- 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_MICROSOFTDEMANGLE_H #define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H #include "MicrosoftDemangleNodes.h" #include "StringView.h" #include 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(P); addNode(std::max(AllocUnit, Size)); Head->Used = Size; return reinterpret_cast(Head->Buf); } template 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 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(ConstructorArgs)...); static_assert(Size < AllocUnit, ""); addNode(AllocUnit); Head->Used = Size; return new (Head->Buf) T(std::forward(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(); 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 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); FuncClassType 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 demangleQualifiers(StringView& MangledName); private: // 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_MICROSOFTDEMANGLE_H