build: More repo cleanup, move libimhex and external libs to /lib folder

This commit is contained in:
WerWolv
2022-01-16 14:20:52 +01:00
parent a5a1ae6725
commit 40d7e4aa6e
232 changed files with 62 additions and 75 deletions

View File

@@ -0,0 +1,124 @@
//===--- Demangle.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_DEMANGLE_H
#define LLVM_DEMANGLE_DEMANGLE_H
#include <cstddef>
#include <string>
namespace llvm {
/// This is a llvm local version of __cxa_demangle. Other than the name and
/// being in the llvm namespace it is identical.
///
/// The mangled_name is demangled into buf and returned. If the buffer is not
/// large enough, realloc is used to expand it.
///
/// The *status will be set to a value from the following enumeration
enum : int {
demangle_unknown_error = -4,
demangle_invalid_args = -3,
demangle_invalid_mangled_name = -2,
demangle_memory_alloc_failure = -1,
demangle_success = 0,
};
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
int *status);
enum MSDemangleFlags {
MSDF_None = 0,
MSDF_DumpBackrefs = 1 << 0,
MSDF_NoAccessSpecifier = 1 << 1,
MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
};
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
/// Returns a pointer to the start of a null-terminated demangled string on
/// success, or nullptr on error.
/// If n_read is non-null and demangling was successful, it receives how many
/// bytes of the input string were consumed.
/// buf can point to a *n_buf bytes large buffer where the demangled name is
/// stored. If the buffer is too small, it is grown with realloc(). If buf is
/// nullptr, then this malloc()s memory for the result.
/// *n_buf stores the size of buf on input if buf is non-nullptr, and it
/// receives the size of the demangled string on output if n_buf is not nullptr.
/// status receives one of the demangle_ enum entries above if it's not nullptr.
/// Flags controls various details of the demangled representation.
char *microsoftDemangle(const char *mangled_name, size_t *n_read,
char *buf, size_t *n_buf,
int *status, MSDemangleFlags Flags = MSDF_None);
/// Attempt to demangle a string using different demangling schemes.
/// The function uses heuristics to determine which demangling scheme to use.
/// \param MangledName - reference to string to demangle.
/// \returns - the demangled string, or a copy of the input string if no
/// demangling occurred.
std::string demangle(const std::string &MangledName);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
/// properties or partially printing the demangled name.
struct ItaniumPartialDemangler {
ItaniumPartialDemangler();
ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
/// Demangle into an AST. Subsequent calls to the rest of the member functions
/// implicitly operate on the AST this produces.
/// \return true on error, false otherwise
bool partialDemangle(const char *MangledName);
/// Just print the entire mangled name into Buf. Buf and N behave like the
/// second and third parameters to itaniumDemangle.
char *finishDemangle(char *Buf, size_t *N) const;
/// Get the base name of a function. This doesn't include trailing template
/// arguments, ie for "a::b<int>" this function returns "b".
char *getFunctionBaseName(char *Buf, size_t *N) const;
/// Get the context name for a function. For "a::b::c", this function returns
/// "a::b".
char *getFunctionDeclContextName(char *Buf, size_t *N) const;
/// Get the entire name of this function.
char *getFunctionName(char *Buf, size_t *N) const;
/// Get the parameters for this function.
char *getFunctionParameters(char *Buf, size_t *N) const;
char *getFunctionReturnType(char *Buf, size_t *N) const;
/// If this function has any any cv or reference qualifiers. These imply that
/// the function is a non-static member function.
bool hasFunctionQualifiers() const;
/// If this symbol describes a constructor or destructor.
bool isCtorOrDtor() const;
/// If this symbol describes a function.
bool isFunction() const;
/// If this symbol describes a variable.
bool isData() const;
/// If this symbol is a <special-name>. These are generally implicitly
/// generated by the implementation, such as vtables and typeinfo names.
bool isSpecialName() const;
~ItaniumPartialDemangler();
private:
void *RootNode;
void *Context;
};
} // namespace llvm
#endif

View File

@@ -0,0 +1,92 @@
//===--- DemangleConfig.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
//
//===----------------------------------------------------------------------===//
//
// This file contains a variety of feature test macros copied from
// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take
// a dependency on LLVMSupport.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H
#define LLVM_DEMANGLE_COMPILER_H
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef DEMANGLE_GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
((maj) << 20) + ((min) << 10) + (patch))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
#else
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
#endif
#endif
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
#else
#define DEMANGLE_ATTRIBUTE_USED
#endif
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define DEMANGLE_UNREACHABLE __assume(false)
#else
#define DEMANGLE_UNREACHABLE
#endif
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if !defined(NDEBUG)
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
#else
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define DEMANGLE_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
#else
#define DEMANGLE_FALLTHROUGH
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
//===------------------------- 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

View File

@@ -0,0 +1,629 @@
//===- MicrosoftDemangleNodes.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
//
//===----------------------------------------------------------------------===//
//
// This file defines the AST nodes used in the MSVC demangler.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/StringView.h"
#include <array>
#include <cstdint>
#include <string>
namespace llvm {
namespace itanium_demangle {
class OutputStream;
}
}
using llvm::itanium_demangle::OutputStream;
using llvm::itanium_demangle::StringView;
namespace llvm {
namespace ms_demangle {
// Storage classes
enum Qualifiers : uint8_t {
Q_None = 0,
Q_Const = 1 << 0,
Q_Volatile = 1 << 1,
Q_Far = 1 << 2,
Q_Huge = 1 << 3,
Q_Unaligned = 1 << 4,
Q_Restrict = 1 << 5,
Q_Pointer64 = 1 << 6
};
enum class StorageClass : uint8_t {
None,
PrivateStatic,
ProtectedStatic,
PublicStatic,
Global,
FunctionLocalStatic,
};
enum class PointerAffinity { None, Pointer, Reference, RValueReference };
enum class FunctionRefQualifier { None, Reference, RValueReference };
// Calling conventions
enum class CallingConv : uint8_t {
None,
Cdecl,
Pascal,
Thiscall,
Stdcall,
Fastcall,
Clrcall,
Eabi,
Vectorcall,
Regcall,
};
enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
enum OutputFlags {
OF_Default = 0,
OF_NoCallingConvention = 1,
OF_NoTagSpecifier = 2,
OF_NoAccessSpecifier = 4,
OF_NoMemberType = 8,
OF_NoReturnType = 16,
};
// Types
enum class PrimitiveKind {
Void,
Bool,
Char,
Schar,
Uchar,
Char8,
Char16,
Char32,
Short,
Ushort,
Int,
Uint,
Long,
Ulong,
Int64,
Uint64,
Wchar,
Float,
Double,
Ldouble,
Nullptr,
};
enum class CharKind {
Char,
Char16,
Char32,
Wchar,
};
enum class IntrinsicFunctionKind : uint8_t {
None,
New, // ?2 # operator new
Delete, // ?3 # operator delete
Assign, // ?4 # operator=
RightShift, // ?5 # operator>>
LeftShift, // ?6 # operator<<
LogicalNot, // ?7 # operator!
Equals, // ?8 # operator==
NotEquals, // ?9 # operator!=
ArraySubscript, // ?A # operator[]
Pointer, // ?C # operator->
Dereference, // ?D # operator*
Increment, // ?E # operator++
Decrement, // ?F # operator--
Minus, // ?G # operator-
Plus, // ?H # operator+
BitwiseAnd, // ?I # operator&
MemberPointer, // ?J # operator->*
Divide, // ?K # operator/
Modulus, // ?L # operator%
LessThan, // ?M operator<
LessThanEqual, // ?N operator<=
GreaterThan, // ?O operator>
GreaterThanEqual, // ?P operator>=
Comma, // ?Q operator,
Parens, // ?R operator()
BitwiseNot, // ?S operator~
BitwiseXor, // ?T operator^
BitwiseOr, // ?U operator|
LogicalAnd, // ?V operator&&
LogicalOr, // ?W operator||
TimesEqual, // ?X operator*=
PlusEqual, // ?Y operator+=
MinusEqual, // ?Z operator-=
DivEqual, // ?_0 operator/=
ModEqual, // ?_1 operator%=
RshEqual, // ?_2 operator>>=
LshEqual, // ?_3 operator<<=
BitwiseAndEqual, // ?_4 operator&=
BitwiseOrEqual, // ?_5 operator|=
BitwiseXorEqual, // ?_6 operator^=
VbaseDtor, // ?_D # vbase destructor
VecDelDtor, // ?_E # vector deleting destructor
DefaultCtorClosure, // ?_F # default constructor closure
ScalarDelDtor, // ?_G # scalar deleting destructor
VecCtorIter, // ?_H # vector constructor iterator
VecDtorIter, // ?_I # vector destructor iterator
VecVbaseCtorIter, // ?_J # vector vbase constructor iterator
VdispMap, // ?_K # virtual displacement map
EHVecCtorIter, // ?_L # eh vector constructor iterator
EHVecDtorIter, // ?_M # eh vector destructor iterator
EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator
CopyCtorClosure, // ?_O # copy constructor closure
LocalVftableCtorClosure, // ?_T # local vftable constructor closure
ArrayNew, // ?_U operator new[]
ArrayDelete, // ?_V operator delete[]
ManVectorCtorIter, // ?__A managed vector ctor iterator
ManVectorDtorIter, // ?__B managed vector dtor iterator
EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator
EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iterator
VectorCopyCtorIter, // ?__G vector copy constructor iterator
VectorVbaseCopyCtorIter, // ?__H vector vbase copy constructor iterator
ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor
CoAwait, // ?__L operator co_await
Spaceship, // ?__M operator<=>
MaxIntrinsic
};
enum class SpecialIntrinsicKind {
None,
Vftable,
Vbtable,
Typeof,
VcallThunk,
LocalStaticGuard,
StringLiteralSymbol,
UdtReturning,
Unknown,
DynamicInitializer,
DynamicAtexitDestructor,
RttiTypeDescriptor,
RttiBaseClassDescriptor,
RttiBaseClassArray,
RttiClassHierarchyDescriptor,
RttiCompleteObjLocator,
LocalVftable,
LocalStaticThreadGuard,
};
// Function classes
enum FuncClass : uint16_t {
FC_None = 0,
FC_Public = 1 << 0,
FC_Protected = 1 << 1,
FC_Private = 1 << 2,
FC_Global = 1 << 3,
FC_Static = 1 << 4,
FC_Virtual = 1 << 5,
FC_Far = 1 << 6,
FC_ExternC = 1 << 7,
FC_NoParameterList = 1 << 8,
FC_VirtualThisAdjust = 1 << 9,
FC_VirtualThisAdjustEx = 1 << 10,
FC_StaticThisAdjust = 1 << 11,
};
enum class TagKind { Class, Struct, Union, Enum };
enum class NodeKind {
Unknown,
Md5Symbol,
PrimitiveType,
FunctionSignature,
Identifier,
NamedIdentifier,
VcallThunkIdentifier,
LocalStaticGuardIdentifier,
IntrinsicFunctionIdentifier,
ConversionOperatorIdentifier,
DynamicStructorIdentifier,
StructorIdentifier,
LiteralOperatorIdentifier,
ThunkSignature,
PointerType,
TagType,
ArrayType,
Custom,
IntrinsicType,
NodeArray,
QualifiedName,
TemplateParameterReference,
EncodedStringLiteral,
IntegerLiteral,
RttiBaseClassDescriptor,
LocalStaticGuardVariable,
FunctionSymbol,
VariableSymbol,
SpecialTableSymbol
};
struct Node {
explicit Node(NodeKind K) : Kind(K) {}
virtual ~Node() = default;
NodeKind kind() const { return Kind; }
virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;
std::string toString(OutputFlags Flags = OF_Default) const;
private:
NodeKind Kind;
};
struct TypeNode;
struct PrimitiveTypeNode;
struct FunctionSignatureNode;
struct IdentifierNode;
struct NamedIdentifierNode;
struct VcallThunkIdentifierNode;
struct IntrinsicFunctionIdentifierNode;
struct LiteralOperatorIdentifierNode;
struct ConversionOperatorIdentifierNode;
struct StructorIdentifierNode;
struct ThunkSignatureNode;
struct PointerTypeNode;
struct ArrayTypeNode;
struct CustomNode;
struct TagTypeNode;
struct IntrinsicTypeNode;
struct NodeArrayNode;
struct QualifiedNameNode;
struct TemplateParameterReferenceNode;
struct EncodedStringLiteralNode;
struct IntegerLiteralNode;
struct RttiBaseClassDescriptorNode;
struct LocalStaticGuardVariableNode;
struct SymbolNode;
struct FunctionSymbolNode;
struct VariableSymbolNode;
struct SpecialTableSymbolNode;
struct TypeNode : public Node {
explicit TypeNode(NodeKind K) : Node(K) {}
virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;
virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;
void output(OutputStream &OS, OutputFlags Flags) const override {
outputPre(OS, Flags);
outputPost(OS, Flags);
}
Qualifiers Quals = Q_None;
};
struct PrimitiveTypeNode : public TypeNode {
explicit PrimitiveTypeNode(PrimitiveKind K)
: TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override {}
PrimitiveKind PrimKind;
};
struct FunctionSignatureNode : public TypeNode {
explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
// Valid if this FunctionTypeNode is the Pointee of a PointerType or
// MemberPointerType.
PointerAffinity Affinity = PointerAffinity::None;
// The function's calling convention.
CallingConv CallConvention = CallingConv::None;
// Function flags (gloabl, public, etc)
FuncClass FunctionClass = FC_Global;
FunctionRefQualifier RefQualifier = FunctionRefQualifier::None;
// The return type of the function.
TypeNode *ReturnType = nullptr;
// True if this is a C-style ... varargs function.
bool IsVariadic = false;
// Function parameters
NodeArrayNode *Params = nullptr;
// True if the function type is noexcept.
bool IsNoexcept = false;
};
struct IdentifierNode : public Node {
explicit IdentifierNode(NodeKind K) : Node(K) {}
NodeArrayNode *TemplateParams = nullptr;
protected:
void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;
};
struct VcallThunkIdentifierNode : public IdentifierNode {
VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
uint64_t OffsetInVTable = 0;
};
struct DynamicStructorIdentifierNode : public IdentifierNode {
DynamicStructorIdentifierNode()
: IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
VariableSymbolNode *Variable = nullptr;
QualifiedNameNode *Name = nullptr;
bool IsDestructor = false;
};
struct NamedIdentifierNode : public IdentifierNode {
NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
StringView Name;
};
struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator)
: IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
Operator(Operator) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
IntrinsicFunctionKind Operator;
};
struct LiteralOperatorIdentifierNode : public IdentifierNode {
LiteralOperatorIdentifierNode()
: IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
StringView Name;
};
struct LocalStaticGuardIdentifierNode : public IdentifierNode {
LocalStaticGuardIdentifierNode()
: IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
bool IsThread = false;
uint32_t ScopeIndex = 0;
};
struct ConversionOperatorIdentifierNode : public IdentifierNode {
ConversionOperatorIdentifierNode()
: IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
// The type that this operator converts too.
TypeNode *TargetType = nullptr;
};
struct StructorIdentifierNode : public IdentifierNode {
StructorIdentifierNode() : IdentifierNode(NodeKind::StructorIdentifier) {}
explicit StructorIdentifierNode(bool IsDestructor)
: IdentifierNode(NodeKind::StructorIdentifier),
IsDestructor(IsDestructor) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
// The name of the class that this is a structor of.
IdentifierNode *Class = nullptr;
bool IsDestructor = false;
};
struct ThunkSignatureNode : public FunctionSignatureNode {
ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
struct ThisAdjustor {
uint32_t StaticOffset = 0;
int32_t VBPtrOffset = 0;
int32_t VBOffsetOffset = 0;
int32_t VtordispOffset = 0;
};
ThisAdjustor ThisAdjust;
};
struct PointerTypeNode : public TypeNode {
PointerTypeNode() : TypeNode(NodeKind::PointerType) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
// Is this a pointer, reference, or rvalue-reference?
PointerAffinity Affinity = PointerAffinity::None;
// If this is a member pointer, this is the class that the member is in.
QualifiedNameNode *ClassParent = nullptr;
// Represents a type X in "a pointer to X", "a reference to X", or
// "rvalue-reference to X"
TypeNode *Pointee = nullptr;
};
struct TagTypeNode : public TypeNode {
explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
QualifiedNameNode *QualifiedName = nullptr;
TagKind Tag;
};
struct ArrayTypeNode : public TypeNode {
ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;
void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;
// A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]`
NodeArrayNode *Dimensions = nullptr;
// The type of array element.
TypeNode *ElementType = nullptr;
};
struct IntrinsicNode : public TypeNode {
IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}
void output(OutputStream &OS, OutputFlags Flags) const override {}
};
struct CustomTypeNode : public TypeNode {
CustomTypeNode() : TypeNode(NodeKind::Custom) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
IdentifierNode *Identifier = nullptr;
};
struct NodeArrayNode : public Node {
NodeArrayNode() : Node(NodeKind::NodeArray) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const;
Node **Nodes = nullptr;
size_t Count = 0;
};
struct QualifiedNameNode : public Node {
QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
NodeArrayNode *Components = nullptr;
IdentifierNode *getUnqualifiedIdentifier() {
Node *LastComponent = Components->Nodes[Components->Count - 1];
return static_cast<IdentifierNode *>(LastComponent);
}
};
struct TemplateParameterReferenceNode : public Node {
TemplateParameterReferenceNode()
: Node(NodeKind::TemplateParameterReference) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
SymbolNode *Symbol = nullptr;
int ThunkOffsetCount = 0;
std::array<int64_t, 3> ThunkOffsets;
PointerAffinity Affinity = PointerAffinity::None;
bool IsMemberPointer = false;
};
struct IntegerLiteralNode : public Node {
IntegerLiteralNode() : Node(NodeKind::IntegerLiteral) {}
IntegerLiteralNode(uint64_t Value, bool IsNegative)
: Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
uint64_t Value = 0;
bool IsNegative = false;
};
struct RttiBaseClassDescriptorNode : public IdentifierNode {
RttiBaseClassDescriptorNode()
: IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
uint32_t NVOffset = 0;
int32_t VBPtrOffset = 0;
uint32_t VBTableOffset = 0;
uint32_t Flags = 0;
};
struct SymbolNode : public Node {
explicit SymbolNode(NodeKind K) : Node(K) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
QualifiedNameNode *Name = nullptr;
};
struct SpecialTableSymbolNode : public SymbolNode {
explicit SpecialTableSymbolNode()
: SymbolNode(NodeKind::SpecialTableSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
QualifiedNameNode *TargetName = nullptr;
Qualifiers Quals = Qualifiers::Q_None;
};
struct LocalStaticGuardVariableNode : public SymbolNode {
LocalStaticGuardVariableNode()
: SymbolNode(NodeKind::LocalStaticGuardVariable) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
bool IsVisible = false;
};
struct EncodedStringLiteralNode : public SymbolNode {
EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
StringView DecodedString;
bool IsTruncated = false;
CharKind Char = CharKind::Char;
};
struct VariableSymbolNode : public SymbolNode {
VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
StorageClass SC = StorageClass::None;
TypeNode *Type = nullptr;
};
struct FunctionSymbolNode : public SymbolNode {
FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
FunctionSignatureNode *Signature = nullptr;
};
} // namespace ms_demangle
} // namespace llvm
#endif

View File

@@ -0,0 +1,126 @@
//===--- StringView.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
//
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
DEMANGLE_NAMESPACE_BEGIN
class StringView {
const char *First;
const char *Last;
public:
static const size_t npos = ~size_t(0);
template <size_t N>
StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
StringView(const char *First_, const char *Last_)
: First(First_), Last(Last_) {}
StringView(const char *First_, size_t Len)
: First(First_), Last(First_ + Len) {}
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const {
return StringView(begin() + From, size() - From);
}
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
if (FindBegin < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First + N, Last);
}
StringView dropBack(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First, Last - N);
}
char front() const {
assert(!empty());
return *begin();
}
char back() const {
assert(!empty());
return *(end() - 1);
}
char popFront() {
assert(!empty());
return *First++;
}
bool consumeFront(char C) {
if (!startsWith(C))
return false;
*this = dropFront(1);
return true;
}
bool consumeFront(StringView S) {
if (!startsWith(S))
return false;
*this = dropFront(S.size());
return true;
}
bool startsWith(char C) const { return !empty() && *begin() == C; }
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
return std::equal(Str.begin(), Str.end(), begin());
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
const char *begin() const { return First; }
const char *end() const { return Last; }
size_t size() const { return static_cast<size_t>(Last - First); }
bool empty() const { return First == Last; }
};
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
DEMANGLE_NAMESPACE_END
#endif

View File

@@ -0,0 +1,191 @@
//===--- Utility.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
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there is at least n more positions in buffer.
void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) {
BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition)
BufferCapacity = N + CurrentPosition;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
void writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case...
if (N == 0) {
*this << '0';
return;
}
char Temp[21];
char *TempPtr = std::end(Temp);
while (N) {
*--TempPtr = '0' + char(N % 10);
N /= 10;
}
// Add negative sign...
if (isNeg)
*--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
}
public:
OutputStream(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputStream() = default;
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) {
size_t Size = R.size();
if (Size == 0)
return *this;
grow(Size);
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputStream &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputStream &operator<<(StringView R) { return (*this += R); }
OutputStream &operator<<(char C) { return (*this += C); }
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
OutputStream &operator<<(unsigned long long N) {
writeUnsigned(N, false);
return *this;
}
OutputStream &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputStream &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class SwapAndRestore {
T &Restore;
T OriginalValue;
bool ShouldRestore = true;
public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
SwapAndRestore(T &Restore_, T NewVal)
: Restore(Restore_), OriginalValue(Restore) {
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
}
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
};
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif