LLVM 22.0.0git
MicrosoftDemangle.h
Go to the documentation of this file.
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
15
16#include <cassert>
17#include <string_view>
18#include <utility>
19
20namespace llvm {
21namespace ms_demangle {
22// This memory allocator is extremely fast, but it doesn't call dtors
23// for allocated objects. That means you can't use STL containers
24// (such as std::vector) with this allocator. But it pays off --
25// the demangler is 3x faster with this allocator compared to one with
26// STL containers.
27constexpr size_t AllocUnit = 4096;
28
30 struct AllocatorNode {
31 uint8_t *Buf = nullptr;
32 size_t Used = 0;
33 size_t Capacity = 0;
34 AllocatorNode *Next = nullptr;
35 };
36
37 void addNode(size_t Capacity) {
38 AllocatorNode *NewHead = new AllocatorNode;
39 NewHead->Buf = new uint8_t[Capacity];
40 NewHead->Next = Head;
41 NewHead->Capacity = Capacity;
42 Head = NewHead;
43 NewHead->Used = 0;
44 }
45
46public:
47 ArenaAllocator() { addNode(AllocUnit); }
48
50 while (Head) {
51 assert(Head->Buf);
52 delete[] Head->Buf;
53 AllocatorNode *Next = Head->Next;
54 delete Head;
55 Head = Next;
56 }
57 }
58
59 // Delete the copy constructor and the copy assignment operator.
60 ArenaAllocator(const ArenaAllocator &) = delete;
62
63 char *allocUnalignedBuffer(size_t Size) {
64 assert(Head && Head->Buf);
65
66 uint8_t *P = Head->Buf + Head->Used;
67
68 Head->Used += Size;
69 if (Head->Used <= Head->Capacity)
70 return reinterpret_cast<char *>(P);
71
72 addNode(std::max(AllocUnit, Size));
73 Head->Used = Size;
74 return reinterpret_cast<char *>(Head->Buf);
75 }
76
77 template <typename T, typename... Args> T *allocArray(size_t Count) {
78 size_t Size = Count * sizeof(T);
79 assert(Head && Head->Buf);
80
81 size_t P = (size_t)Head->Buf + Head->Used;
82 uintptr_t AlignedP =
83 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
84 uint8_t *PP = (uint8_t *)AlignedP;
85 size_t Adjustment = AlignedP - P;
86
87 Head->Used += Size + Adjustment;
88 if (Head->Used <= Head->Capacity)
89 return new (PP) T[Count]();
90
91 addNode(std::max(AllocUnit, Size));
92 Head->Used = Size;
93 return new (Head->Buf) T[Count]();
94 }
95
96 template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
97 constexpr size_t Size = sizeof(T);
98 assert(Head && Head->Buf);
99
100 size_t P = (size_t)Head->Buf + Head->Used;
101 uintptr_t AlignedP =
102 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
103 uint8_t *PP = (uint8_t *)AlignedP;
104 size_t Adjustment = AlignedP - P;
105
106 Head->Used += Size + Adjustment;
107 if (Head->Used <= Head->Capacity)
108 return new (PP) T(std::forward<Args>(ConstructorArgs)...);
109
110 static_assert(Size < AllocUnit);
111 addNode(AllocUnit);
112 Head->Used = Size;
113 return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
114 }
115
116private:
117 AllocatorNode *Head = nullptr;
118};
119
121 static constexpr size_t Max = 10;
122
125
126 // The first 10 BackReferences in a mangled name can be back-referenced by
127 // special name @[0-9]. This is a storage for the first 10 BackReferences.
129 size_t NamesCount = 0;
130};
131
133
135 NBB_None = 0, // don't save any names as backrefs.
136 NBB_Template = 1 << 0, // save template instanations.
137 NBB_Simple = 1 << 1, // save simple names.
138};
139
141
142// Demangler class takes the main role in demangling symbols.
143// It has a set of functions to parse mangled symbols into Type instances.
144// It also has a set of functions to convert Type instances to strings.
146 friend std::optional<size_t>
147 llvm::getArm64ECInsertionPointInMangledName(std::string_view MangledName);
148
149public:
150 Demangler() = default;
151 virtual ~Demangler() = default;
152
153 // You are supposed to call parse() first and then check if error is true. If
154 // it is false, call output() to write the formatted name to the given stream.
155 DEMANGLE_ABI SymbolNode *parse(std::string_view &MangledName);
156
157 DEMANGLE_ABI TagTypeNode *parseTagUniqueName(std::string_view &MangledName);
158
159 // True if an error occurred.
160 bool Error = false;
161
163
164private:
165 SymbolNode *demangleEncodedSymbol(std::string_view &MangledName,
167 SymbolNode *demangleDeclarator(std::string_view &MangledName);
168 SymbolNode *demangleMD5Name(std::string_view &MangledName);
169 SymbolNode *demangleTypeinfoName(std::string_view &MangledName);
170
171 VariableSymbolNode *demangleVariableEncoding(std::string_view &MangledName,
172 StorageClass SC);
173 FunctionSymbolNode *demangleFunctionEncoding(std::string_view &MangledName);
174
175 Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName);
176
177 bool isMemberPointer(std::string_view MangledName, bool &Error);
178
179 std::optional<PointerAuthQualifierNode::ArgArray>
180 demanglePointerAuthQualifier(std::string_view &MangledName);
181
183 createPointerAuthQualifier(std::string_view &MangledName);
184
185 // Parser functions. This is a recursive-descent parser.
186 TypeNode *demangleType(std::string_view &MangledName,
188 PrimitiveTypeNode *demanglePrimitiveType(std::string_view &MangledName);
189 CustomTypeNode *demangleCustomType(std::string_view &MangledName);
190 TagTypeNode *demangleClassType(std::string_view &MangledName);
191 PointerTypeNode *demanglePointerType(std::string_view &MangledName);
192 PointerTypeNode *demangleMemberPointerType(std::string_view &MangledName);
193 FunctionSignatureNode *demangleFunctionType(std::string_view &MangledName,
194 bool HasThisQuals);
195
196 ArrayTypeNode *demangleArrayType(std::string_view &MangledName);
197
198 NodeArrayNode *demangleFunctionParameterList(std::string_view &MangledName,
199 bool &IsVariadic);
200 NodeArrayNode *demangleTemplateParameterList(std::string_view &MangledName);
201
202 std::pair<uint64_t, bool> demangleNumber(std::string_view &MangledName);
203 uint64_t demangleUnsigned(std::string_view &MangledName);
204 int64_t demangleSigned(std::string_view &MangledName);
205
206 void memorizeString(std::string_view s);
207 void memorizeIdentifier(IdentifierNode *Identifier);
208
209 /// Allocate a copy of \p Borrowed into memory that we own.
210 std::string_view copyString(std::string_view Borrowed);
211
213 demangleFullyQualifiedTypeName(std::string_view &MangledName);
215 demangleFullyQualifiedSymbolName(std::string_view &MangledName);
216
217 IdentifierNode *demangleUnqualifiedTypeName(std::string_view &MangledName,
218 bool Memorize);
219 IdentifierNode *demangleUnqualifiedSymbolName(std::string_view &MangledName,
221
222 QualifiedNameNode *demangleNameScopeChain(std::string_view &MangledName,
223 IdentifierNode *UnqualifiedName);
224 IdentifierNode *demangleNameScopePiece(std::string_view &MangledName);
225
226 NamedIdentifierNode *demangleBackRefName(std::string_view &MangledName);
228 demangleTemplateInstantiationName(std::string_view &MangledName,
231 translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group);
232 IdentifierNode *demangleFunctionIdentifierCode(std::string_view &MangledName);
234 demangleFunctionIdentifierCode(std::string_view &MangledName,
237 demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor);
239 demangleConversionOperatorIdentifier(std::string_view &MangledName);
241 demangleLiteralOperatorIdentifier(std::string_view &MangledName);
242
243 SymbolNode *demangleSpecialIntrinsic(std::string_view &MangledName);
245 demangleSpecialTableSymbolNode(std::string_view &MangledName,
248 demangleLocalStaticGuard(std::string_view &MangledName, bool IsThread);
249 VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,
250 std::string_view &MangledName,
251 std::string_view VariableName);
253 demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
254 std::string_view &MangledName);
255 FunctionSymbolNode *demangleInitFiniStub(std::string_view &MangledName,
256 bool IsDestructor);
257
258 NamedIdentifierNode *demangleSimpleName(std::string_view &MangledName,
259 bool Memorize);
261 demangleAnonymousNamespaceName(std::string_view &MangledName);
263 demangleLocallyScopedNamePiece(std::string_view &MangledName);
265 demangleStringLiteral(std::string_view &MangledName);
266 FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName);
267
268 std::string_view demangleSimpleString(std::string_view &MangledName,
269 bool Memorize);
270
271 FuncClass demangleFunctionClass(std::string_view &MangledName);
272 CallingConv demangleCallingConvention(std::string_view &MangledName);
273 StorageClass demangleVariableStorageClass(std::string_view &MangledName);
274 bool demangleThrowSpecification(std::string_view &MangledName);
275 wchar_t demangleWcharLiteral(std::string_view &MangledName);
276 uint8_t demangleCharLiteral(std::string_view &MangledName);
277
278 std::pair<Qualifiers, bool> demangleQualifiers(std::string_view &MangledName);
279
280 // Memory allocator.
281 ArenaAllocator Arena;
282
283 // A single type uses one global back-ref table for all function params.
284 // This means back-refs can even go "into" other types. Examples:
285 //
286 // // Second int* is a back-ref to first.
287 // void foo(int *, int*);
288 //
289 // // Second int* is not a back-ref to first (first is not a function param).
290 // int* foo(int*);
291 //
292 // // Second int* is a back-ref to first (ALL function types share the same
293 // // back-ref map.
294 // using F = void(*)(int*);
295 // F G(int *);
296 BackrefContext Backrefs;
297};
298
299} // namespace ms_demangle
300} // namespace llvm
301
302#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define DEMANGLE_ABI
DEMANGLE_ABI is the export/visibility macro used to mark symbols delcared in llvm/Demangle as exporte...
uint64_t Size
#define T
#define P(N)
#define CH(x, y, z)
Definition: SHA256.cpp:34
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
T * alloc(Args &&... ConstructorArgs)
char * allocUnalignedBuffer(size_t Size)
ArenaAllocator & operator=(const ArenaAllocator &)=delete
ArenaAllocator(const ArenaAllocator &)=delete
DEMANGLE_ABI TagTypeNode * parseTagUniqueName(std::string_view &MangledName)
virtual ~Demangler()=default
DEMANGLE_ABI void dumpBackReferences()
constexpr size_t AllocUnit
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
DEMANGLE_ABI std::optional< size_t > getArm64ECInsertionPointInMangledName(std::string_view MangledName)
NamedIdentifierNode * Names[Max]
Definition: regcomp.c:186