xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Demangle/MicrosoftDemangle.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
12 #include "llvm/Demangle/MicrosoftDemangleNodes.h"
13 
14 #include <cassert>
15 #include <string_view>
16 #include <utility>
17 
18 namespace llvm {
19 namespace ms_demangle {
20 // This memory allocator is extremely fast, but it doesn't call dtors
21 // for allocated objects. That means you can't use STL containers
22 // (such as std::vector) with this allocator. But it pays off --
23 // the demangler is 3x faster with this allocator compared to one with
24 // STL containers.
25 constexpr size_t AllocUnit = 4096;
26 
27 class ArenaAllocator {
28   struct AllocatorNode {
29     uint8_t *Buf = nullptr;
30     size_t Used = 0;
31     size_t Capacity = 0;
32     AllocatorNode *Next = nullptr;
33   };
34 
addNode(size_t Capacity)35   void addNode(size_t Capacity) {
36     AllocatorNode *NewHead = new AllocatorNode;
37     NewHead->Buf = new uint8_t[Capacity];
38     NewHead->Next = Head;
39     NewHead->Capacity = Capacity;
40     Head = NewHead;
41     NewHead->Used = 0;
42   }
43 
44 public:
ArenaAllocator()45   ArenaAllocator() { addNode(AllocUnit); }
46 
~ArenaAllocator()47   ~ArenaAllocator() {
48     while (Head) {
49       assert(Head->Buf);
50       delete[] Head->Buf;
51       AllocatorNode *Next = Head->Next;
52       delete Head;
53       Head = Next;
54     }
55   }
56 
57   // Delete the copy constructor and the copy assignment operator.
58   ArenaAllocator(const ArenaAllocator &) = delete;
59   ArenaAllocator &operator=(const ArenaAllocator &) = delete;
60 
allocUnalignedBuffer(size_t Size)61   char *allocUnalignedBuffer(size_t Size) {
62     assert(Head && Head->Buf);
63 
64     uint8_t *P = Head->Buf + Head->Used;
65 
66     Head->Used += Size;
67     if (Head->Used <= Head->Capacity)
68       return reinterpret_cast<char *>(P);
69 
70     addNode(std::max(AllocUnit, Size));
71     Head->Used = Size;
72     return reinterpret_cast<char *>(Head->Buf);
73   }
74 
allocArray(size_t Count)75   template <typename T, typename... Args> T *allocArray(size_t Count) {
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(std::max(AllocUnit, Size));
90     Head->Used = Size;
91     return new (Head->Buf) T[Count]();
92   }
93 
alloc(Args &&...ConstructorArgs)94   template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
95     constexpr size_t Size = sizeof(T);
96     assert(Head && Head->Buf);
97 
98     size_t P = (size_t)Head->Buf + Head->Used;
99     uintptr_t AlignedP =
100         (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
101     uint8_t *PP = (uint8_t *)AlignedP;
102     size_t Adjustment = AlignedP - P;
103 
104     Head->Used += Size + Adjustment;
105     if (Head->Used <= Head->Capacity)
106       return new (PP) T(std::forward<Args>(ConstructorArgs)...);
107 
108     static_assert(Size < AllocUnit);
109     addNode(AllocUnit);
110     Head->Used = Size;
111     return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
112   }
113 
114 private:
115   AllocatorNode *Head = nullptr;
116 };
117 
118 struct 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 
130 enum class QualifierMangleMode { Drop, Mangle, Result };
131 
132 enum 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 
138 enum 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.
143 class Demangler {
144 public:
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(std::string_view &MangledName);
151 
152   TagTypeNode *parseTagUniqueName(std::string_view &MangledName);
153 
154   // True if an error occurred.
155   bool Error = false;
156 
157   void dumpBackReferences();
158 
159 private:
160   SymbolNode *demangleEncodedSymbol(std::string_view &MangledName,
161                                     QualifiedNameNode *QN);
162   SymbolNode *demangleDeclarator(std::string_view &MangledName);
163   SymbolNode *demangleMD5Name(std::string_view &MangledName);
164   SymbolNode *demangleTypeinfoName(std::string_view &MangledName);
165 
166   VariableSymbolNode *demangleVariableEncoding(std::string_view &MangledName,
167                                                StorageClass SC);
168   FunctionSymbolNode *demangleFunctionEncoding(std::string_view &MangledName);
169 
170   Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName);
171 
172   // Parser functions. This is a recursive-descent parser.
173   TypeNode *demangleType(std::string_view &MangledName,
174                          QualifierMangleMode QMM);
175   PrimitiveTypeNode *demanglePrimitiveType(std::string_view &MangledName);
176   CustomTypeNode *demangleCustomType(std::string_view &MangledName);
177   TagTypeNode *demangleClassType(std::string_view &MangledName);
178   PointerTypeNode *demanglePointerType(std::string_view &MangledName);
179   PointerTypeNode *demangleMemberPointerType(std::string_view &MangledName);
180   FunctionSignatureNode *demangleFunctionType(std::string_view &MangledName,
181                                               bool HasThisQuals);
182 
183   ArrayTypeNode *demangleArrayType(std::string_view &MangledName);
184 
185   NodeArrayNode *demangleFunctionParameterList(std::string_view &MangledName,
186                                                bool &IsVariadic);
187   NodeArrayNode *demangleTemplateParameterList(std::string_view &MangledName);
188 
189   std::pair<uint64_t, bool> demangleNumber(std::string_view &MangledName);
190   uint64_t demangleUnsigned(std::string_view &MangledName);
191   int64_t demangleSigned(std::string_view &MangledName);
192 
193   void memorizeString(std::string_view s);
194   void memorizeIdentifier(IdentifierNode *Identifier);
195 
196   /// Allocate a copy of \p Borrowed into memory that we own.
197   std::string_view copyString(std::string_view Borrowed);
198 
199   QualifiedNameNode *
200   demangleFullyQualifiedTypeName(std::string_view &MangledName);
201   QualifiedNameNode *
202   demangleFullyQualifiedSymbolName(std::string_view &MangledName);
203 
204   IdentifierNode *demangleUnqualifiedTypeName(std::string_view &MangledName,
205                                               bool Memorize);
206   IdentifierNode *demangleUnqualifiedSymbolName(std::string_view &MangledName,
207                                                 NameBackrefBehavior NBB);
208 
209   QualifiedNameNode *demangleNameScopeChain(std::string_view &MangledName,
210                                             IdentifierNode *UnqualifiedName);
211   IdentifierNode *demangleNameScopePiece(std::string_view &MangledName);
212 
213   NamedIdentifierNode *demangleBackRefName(std::string_view &MangledName);
214   IdentifierNode *
215   demangleTemplateInstantiationName(std::string_view &MangledName,
216                                     NameBackrefBehavior NBB);
217   IntrinsicFunctionKind
218   translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group);
219   IdentifierNode *demangleFunctionIdentifierCode(std::string_view &MangledName);
220   IdentifierNode *
221   demangleFunctionIdentifierCode(std::string_view &MangledName,
222                                  FunctionIdentifierCodeGroup Group);
223   StructorIdentifierNode *
224   demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor);
225   ConversionOperatorIdentifierNode *
226   demangleConversionOperatorIdentifier(std::string_view &MangledName);
227   LiteralOperatorIdentifierNode *
228   demangleLiteralOperatorIdentifier(std::string_view &MangledName);
229 
230   SymbolNode *demangleSpecialIntrinsic(std::string_view &MangledName);
231   SpecialTableSymbolNode *
232   demangleSpecialTableSymbolNode(std::string_view &MangledName,
233                                  SpecialIntrinsicKind SIK);
234   LocalStaticGuardVariableNode *
235   demangleLocalStaticGuard(std::string_view &MangledName, bool IsThread);
236   VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,
237                                               std::string_view &MangledName,
238                                               std::string_view VariableName);
239   VariableSymbolNode *
240   demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
241                                       std::string_view &MangledName);
242   FunctionSymbolNode *demangleInitFiniStub(std::string_view &MangledName,
243                                            bool IsDestructor);
244 
245   NamedIdentifierNode *demangleSimpleName(std::string_view &MangledName,
246                                           bool Memorize);
247   NamedIdentifierNode *
248   demangleAnonymousNamespaceName(std::string_view &MangledName);
249   NamedIdentifierNode *
250   demangleLocallyScopedNamePiece(std::string_view &MangledName);
251   EncodedStringLiteralNode *
252   demangleStringLiteral(std::string_view &MangledName);
253   FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName);
254 
255   std::string_view demangleSimpleString(std::string_view &MangledName,
256                                         bool Memorize);
257 
258   FuncClass demangleFunctionClass(std::string_view &MangledName);
259   CallingConv demangleCallingConvention(std::string_view &MangledName);
260   StorageClass demangleVariableStorageClass(std::string_view &MangledName);
261   bool demangleThrowSpecification(std::string_view &MangledName);
262   wchar_t demangleWcharLiteral(std::string_view &MangledName);
263   uint8_t demangleCharLiteral(std::string_view &MangledName);
264 
265   std::pair<Qualifiers, bool> demangleQualifiers(std::string_view &MangledName);
266 
267   // Memory allocator.
268   ArenaAllocator Arena;
269 
270   // A single type uses one global back-ref table for all function params.
271   // This means back-refs can even go "into" other types.  Examples:
272   //
273   //  // Second int* is a back-ref to first.
274   //  void foo(int *, int*);
275   //
276   //  // Second int* is not a back-ref to first (first is not a function param).
277   //  int* foo(int*);
278   //
279   //  // Second int* is a back-ref to first (ALL function types share the same
280   //  // back-ref map.
281   //  using F = void(*)(int*);
282   //  F G(int *);
283   BackrefContext Backrefs;
284 };
285 
286 } // namespace ms_demangle
287 } // namespace llvm
288 
289 #endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
290