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