blob: f227addbdaecf8598fb0bc5337cdd649f956bc30 [file] [log] [blame]
Howard Hinnantd213ffd2011-05-05 15:27:28 +00001//===-------------------------- cxa_demangle.cpp --------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Erik Pilkington1c300b92017-11-21 15:04:08 +000010// FIXME: (possibly) incomplete list of features that clang mangles that this
11// file does not yet support:
Erik Pilkington1c300b92017-11-21 15:04:08 +000012// - C++ modules TS
13
Howard Hinnant6c33e762013-06-17 18:10:34 +000014#define _LIBCPP_NO_EXCEPTIONS
Howard Hinnantd213ffd2011-05-05 15:27:28 +000015
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +000016#include "__cxxabi_config.h"
17
Richard Smith29ffb8f2018-08-20 20:14:49 +000018#include "demangle/ItaniumDemangle.h"
Zachary Turnerbcadcdd2018-07-20 17:16:49 +000019
Erik Pilkington761e6b02018-01-31 20:17:06 +000020#include <cassert>
Zachary Turnerbcadcdd2018-07-20 17:16:49 +000021#include <cctype>
Erik Pilkington77101542017-07-28 00:53:30 +000022#include <cstdio>
Howard Hinnant6c33e762013-06-17 18:10:34 +000023#include <cstdlib>
24#include <cstring>
Richard Smith29ffb8f2018-08-20 20:14:49 +000025#include <functional>
Zachary Turnerbcadcdd2018-07-20 17:16:49 +000026#include <numeric>
Erik Pilkington4a3bc0a2018-07-27 17:27:40 +000027#include <utility>
Zachary Turnerbcadcdd2018-07-20 17:16:49 +000028#include <vector>
Howard Hinnantd213ffd2011-05-05 15:27:28 +000029
Richard Smith29ffb8f2018-08-20 20:14:49 +000030using namespace itanium_demangle;
Erik Pilkington761e6b02018-01-31 20:17:06 +000031
Richard Smith29ffb8f2018-08-20 20:14:49 +000032constexpr const char *itanium_demangle::FloatData<float>::spec;
33constexpr const char *itanium_demangle::FloatData<double>::spec;
34constexpr const char *itanium_demangle::FloatData<long double>::spec;
Erik Pilkington0024acd2017-07-28 00:43:49 +000035
Richard Smith29ffb8f2018-08-20 20:14:49 +000036// <discriminator> := _ <non-negative number> # when number < 10
37// := __ <non-negative number> _ # when number >= 10
38// extension := decimal-digit+ # at the end of string
39const char *itanium_demangle::parse_discriminator(const char *first,
40 const char *last) {
41 // parse but ignore discriminator
42 if (first != last) {
43 if (*first == '_') {
44 const char *t1 = first + 1;
45 if (t1 != last) {
46 if (std::isdigit(*t1))
47 first = t1 + 1;
48 else if (*t1 == '_') {
49 for (++t1; t1 != last && std::isdigit(*t1); ++t1)
50 ;
51 if (t1 != last && *t1 == '_')
52 first = t1 + 1;
53 }
Erik Pilkington85619f52018-03-25 22:49:57 +000054 }
Richard Smith29ffb8f2018-08-20 20:14:49 +000055 } else if (std::isdigit(*first)) {
56 const char *t1 = first + 1;
57 for (; t1 != last && std::isdigit(*t1); ++t1)
58 ;
59 if (t1 == last)
60 first = last;
Erik Pilkington0024acd2017-07-28 00:43:49 +000061 }
62 }
Richard Smith29ffb8f2018-08-20 20:14:49 +000063 return first;
Erik Pilkington0024acd2017-07-28 00:43:49 +000064}
65
Richard Smith29ffb8f2018-08-20 20:14:49 +000066#ifndef NDEBUG
67namespace {
68struct DumpVisitor {
69 unsigned Depth = 0;
70 bool PendingNewline = false;
Erik Pilkington0024acd2017-07-28 00:43:49 +000071
Richard Smith29ffb8f2018-08-20 20:14:49 +000072 template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
73 return true;
74 }
75 static bool wantsNewline(NodeArray A) { return !A.empty(); }
76 static constexpr bool wantsNewline(...) { return false; }
77
78 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
79 for (bool B : {wantsNewline(Vs)...})
80 if (B)
81 return true;
82 return false;
Erik Pilkington0024acd2017-07-28 00:43:49 +000083 }
84
Richard Smith29ffb8f2018-08-20 20:14:49 +000085 void printStr(const char *S) { fprintf(stderr, "%s", S); }
86 void print(StringView SV) {
87 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
Erik Pilkington761e6b02018-01-31 20:17:06 +000088 }
Richard Smith29ffb8f2018-08-20 20:14:49 +000089 void print(const Node *N) {
90 if (N)
91 N->visit(std::ref(*this));
Erik Pilkington0024acd2017-07-28 00:43:49 +000092 else
Richard Smith29ffb8f2018-08-20 20:14:49 +000093 printStr("<null>");
Erik Pilkington0024acd2017-07-28 00:43:49 +000094 }
Richard Smith29ffb8f2018-08-20 20:14:49 +000095 void print(NodeOrString NS) {
96 if (NS.isNode())
97 print(NS.asNode());
98 else if (NS.isString())
99 print(NS.asString());
100 else
101 printStr("NodeOrString()");
Erik Pilkington0024acd2017-07-28 00:43:49 +0000102 }
Richard Smith29ffb8f2018-08-20 20:14:49 +0000103 void print(NodeArray A) {
104 ++Depth;
105 printStr("{");
106 bool First = true;
107 for (const Node *N : A) {
108 if (First)
109 print(N);
110 else
111 printWithComma(N);
112 First = false;
Erik Pilkington0024acd2017-07-28 00:43:49 +0000113 }
Richard Smith29ffb8f2018-08-20 20:14:49 +0000114 printStr("}");
115 --Depth;
Erik Pilkington0024acd2017-07-28 00:43:49 +0000116 }
Erik Pilkingtoncd486252018-10-15 22:03:53 +0000117
Richard Smith29ffb8f2018-08-20 20:14:49 +0000118 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
Erik Pilkingtoncd486252018-10-15 22:03:53 +0000119 void print(bool B) { printStr(B ? "true" : "false"); }
120
121 template <class T>
122 typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
123 fprintf(stderr, "%llu", (unsigned long long)N);
Erik Pilkington0024acd2017-07-28 00:43:49 +0000124 }
Erik Pilkingtoncd486252018-10-15 22:03:53 +0000125
126 template <class T>
127 typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
128 fprintf(stderr, "%lld", (long long)N);
Erik Pilkington0024acd2017-07-28 00:43:49 +0000129 }
Erik Pilkingtoncd486252018-10-15 22:03:53 +0000130
Richard Smith29ffb8f2018-08-20 20:14:49 +0000131 void print(ReferenceKind RK) {
132 switch (RK) {
133 case ReferenceKind::LValue:
134 return printStr("ReferenceKind::LValue");
135 case ReferenceKind::RValue:
136 return printStr("ReferenceKind::RValue");
Erik Pilkington7e027ac2018-02-14 01:08:20 +0000137 }
138 }
Richard Smith29ffb8f2018-08-20 20:14:49 +0000139 void print(FunctionRefQual RQ) {
140 switch (RQ) {
141 case FunctionRefQual::FrefQualNone:
142 return printStr("FunctionRefQual::FrefQualNone");
143 case FunctionRefQual::FrefQualLValue:
144 return printStr("FunctionRefQual::FrefQualLValue");
145 case FunctionRefQual::FrefQualRValue:
146 return printStr("FunctionRefQual::FrefQualRValue");
Erik Pilkington0024acd2017-07-28 00:43:49 +0000147 }
148 }
Richard Smith29ffb8f2018-08-20 20:14:49 +0000149 void print(Qualifiers Qs) {
150 if (!Qs) return printStr("QualNone");
151 struct QualName { Qualifiers Q; const char *Name; } Names[] = {
152 {QualConst, "QualConst"},
153 {QualVolatile, "QualVolatile"},
154 {QualRestrict, "QualRestrict"},
Erik Pilkington967b00e2018-04-09 18:33:01 +0000155 };
Richard Smith29ffb8f2018-08-20 20:14:49 +0000156 for (QualName Name : Names) {
157 if (Qs & Name.Q) {
158 printStr(Name.Name);
159 Qs = Qualifiers(Qs & ~Name.Q);
160 if (Qs) printStr(" | ");
Erik Pilkington967b00e2018-04-09 18:33:01 +0000161 }
162 }
Erik Pilkington967b00e2018-04-09 18:33:01 +0000163 }
Richard Smith29ffb8f2018-08-20 20:14:49 +0000164 void print(SpecialSubKind SSK) {
165 switch (SSK) {
166 case SpecialSubKind::allocator:
167 return printStr("SpecialSubKind::allocator");
168 case SpecialSubKind::basic_string:
169 return printStr("SpecialSubKind::basic_string");
170 case SpecialSubKind::string:
171 return printStr("SpecialSubKind::string");
172 case SpecialSubKind::istream:
173 return printStr("SpecialSubKind::istream");
174 case SpecialSubKind::ostream:
175 return printStr("SpecialSubKind::ostream");
176 case SpecialSubKind::iostream:
177 return printStr("SpecialSubKind::iostream");
178 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000179 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000180
Richard Smith29ffb8f2018-08-20 20:14:49 +0000181 void newLine() {
182 printStr("\n");
183 for (unsigned I = 0; I != Depth; ++I)
184 printStr(" ");
185 PendingNewline = false;
Erik Pilkington0024acd2017-07-28 00:43:49 +0000186 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000187
Richard Smith29ffb8f2018-08-20 20:14:49 +0000188 template<typename T> void printWithPendingNewline(T V) {
189 print(V);
190 if (wantsNewline(V))
191 PendingNewline = true;
Erik Pilkington0024acd2017-07-28 00:43:49 +0000192 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000193
Richard Smith29ffb8f2018-08-20 20:14:49 +0000194 template<typename T> void printWithComma(T V) {
195 if (PendingNewline || wantsNewline(V)) {
196 printStr(",");
197 newLine();
198 } else {
199 printStr(", ");
Erik Pilkington0024acd2017-07-28 00:43:49 +0000200 }
201
Richard Smith29ffb8f2018-08-20 20:14:49 +0000202 printWithPendingNewline(V);
203 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000204
Richard Smith29ffb8f2018-08-20 20:14:49 +0000205 struct CtorArgPrinter {
206 DumpVisitor &Visitor;
207
208 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
209 if (Visitor.anyWantNewline(V, Vs...))
210 Visitor.newLine();
211 Visitor.printWithPendingNewline(V);
212 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
213 (void)PrintInOrder;
214 }
215 };
216
217 template<typename NodeT> void operator()(const NodeT *Node) {
218 Depth += 2;
219 fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
220 Node->match(CtorArgPrinter{*this});
221 fprintf(stderr, ")");
222 Depth -= 2;
223 }
224
225 void operator()(const ForwardTemplateReference *Node) {
226 Depth += 2;
227 fprintf(stderr, "ForwardTemplateReference(");
228 if (Node->Ref && !Node->Printing) {
229 Node->Printing = true;
230 CtorArgPrinter{*this}(Node->Ref);
231 Node->Printing = false;
232 } else {
233 CtorArgPrinter{*this}(Node->Index);
234 }
235 fprintf(stderr, ")");
236 Depth -= 2;
Erik Pilkington0024acd2017-07-28 00:43:49 +0000237 }
238};
Richard Smith29ffb8f2018-08-20 20:14:49 +0000239}
Erik Pilkington0024acd2017-07-28 00:43:49 +0000240
Richard Smith29ffb8f2018-08-20 20:14:49 +0000241void itanium_demangle::Node::dump() const {
242 DumpVisitor V;
243 visit(std::ref(V));
244 V.newLine();
245}
Erik Pilkington0024acd2017-07-28 00:43:49 +0000246#endif
Erik Pilkington0024acd2017-07-28 00:43:49 +0000247
Richard Smith29ffb8f2018-08-20 20:14:49 +0000248namespace {
Erik Pilkington0024acd2017-07-28 00:43:49 +0000249class BumpPointerAllocator {
250 struct BlockMeta {
251 BlockMeta* Next;
252 size_t Current;
253 };
Erik Pilkington9dd63d22017-07-08 18:54:07 +0000254
Erik Pilkington0024acd2017-07-28 00:43:49 +0000255 static constexpr size_t AllocSize = 4096;
256 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
Erik Pilkington9dd63d22017-07-08 18:54:07 +0000257
Serge Pavlov047fb732018-07-05 06:24:29 +0000258 alignas(long double) char InitialBuffer[AllocSize];
Erik Pilkington0024acd2017-07-28 00:43:49 +0000259 BlockMeta* BlockList = nullptr;
260
261 void grow() {
Erik Pilkington64f6c6a2018-07-23 22:23:04 +0000262 char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
263 if (NewMeta == nullptr)
264 std::terminate();
Erik Pilkington0024acd2017-07-28 00:43:49 +0000265 BlockList = new (NewMeta) BlockMeta{BlockList, 0};
266 }
267
268 void* allocateMassive(size_t NBytes) {
269 NBytes += sizeof(BlockMeta);
Erik Pilkington64f6c6a2018-07-23 22:23:04 +0000270 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
271 if (NewMeta == nullptr)
272 std::terminate();
Erik Pilkington0024acd2017-07-28 00:43:49 +0000273 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
274 return static_cast<void*>(NewMeta + 1);
275 }
276
277public:
278 BumpPointerAllocator()
279 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
280
281 void* allocate(size_t N) {
282 N = (N + 15u) & ~15u;
283 if (N + BlockList->Current >= UsableAllocSize) {
284 if (N > UsableAllocSize)
285 return allocateMassive(N);
286 grow();
287 }
288 BlockList->Current += N;
289 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
290 BlockList->Current - N);
291 }
292
Erik Pilkington0df654b2018-04-12 20:41:06 +0000293 void reset() {
Erik Pilkington0024acd2017-07-28 00:43:49 +0000294 while (BlockList) {
295 BlockMeta* Tmp = BlockList;
296 BlockList = BlockList->Next;
297 if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
Erik Pilkington64f6c6a2018-07-23 22:23:04 +0000298 std::free(Tmp);
Erik Pilkington0024acd2017-07-28 00:43:49 +0000299 }
Erik Pilkington0df654b2018-04-12 20:41:06 +0000300 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
Erik Pilkington0024acd2017-07-28 00:43:49 +0000301 }
Erik Pilkington0df654b2018-04-12 20:41:06 +0000302
303 ~BumpPointerAllocator() { reset(); }
Erik Pilkington9dd63d22017-07-08 18:54:07 +0000304};
305
Richard Smith70f40ff2018-08-16 22:04:36 +0000306class DefaultAllocator {
307 BumpPointerAllocator Alloc;
308
309public:
310 void reset() { Alloc.reset(); }
311
312 template<typename T, typename ...Args> T *makeNode(Args &&...args) {
313 return new (Alloc.allocate(sizeof(T)))
314 T(std::forward<Args>(args)...);
315 }
316
317 void *allocateNodeArray(size_t sz) {
318 return Alloc.allocate(sizeof(Node *) * sz);
319 }
320};
Howard Hinnant6c33e762013-06-17 18:10:34 +0000321} // unnamed namespace
322
Richard Smith29ffb8f2018-08-20 20:14:49 +0000323//===----------------------------------------------------------------------===//
324// Code beyond this point should not be synchronized with LLVM.
325//===----------------------------------------------------------------------===//
326
Pavel Labath794d4c02018-10-16 14:29:14 +0000327using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
Richard Smith29ffb8f2018-08-20 20:14:49 +0000328
329namespace {
330enum : int {
331 demangle_invalid_args = -3,
332 demangle_invalid_mangled_name = -2,
333 demangle_memory_alloc_failure = -1,
334 demangle_success = 0,
335};
336}
337
Erik Pilkington761e6b02018-01-31 20:17:06 +0000338namespace __cxxabiv1 {
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +0000339extern "C" _LIBCXXABI_FUNC_VIS char *
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000340__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
341 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
342 if (Status)
Zachary Turnerbcadcdd2018-07-20 17:16:49 +0000343 *Status = demangle_invalid_args;
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000344 return nullptr;
345 }
346
Zachary Turnerbcadcdd2018-07-20 17:16:49 +0000347 int InternalStatus = demangle_success;
Richard Smith29ffb8f2018-08-20 20:14:49 +0000348 Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
Erik Pilkington0df654b2018-04-12 20:41:06 +0000349 OutputStream S;
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000350
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000351 Node *AST = Parser.parse();
352
353 if (AST == nullptr)
Zachary Turnerbcadcdd2018-07-20 17:16:49 +0000354 InternalStatus = demangle_invalid_mangled_name;
Nico Weber35919602018-11-11 10:09:06 +0000355 else if (!initializeOutputStream(Buf, N, S, 1024))
Zachary Turnerbcadcdd2018-07-20 17:16:49 +0000356 InternalStatus = demangle_memory_alloc_failure;
Erik Pilkington0df654b2018-04-12 20:41:06 +0000357 else {
Erik Pilkington04f39852018-03-25 22:50:33 +0000358 assert(Parser.ForwardTemplateRefs.empty());
Erik Pilkington0df654b2018-04-12 20:41:06 +0000359 AST->print(S);
360 S += '\0';
361 if (N != nullptr)
362 *N = S.getCurrentPosition();
363 Buf = S.getBuffer();
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000364 }
Erik Pilkington0024acd2017-07-28 00:43:49 +0000365
Erik Pilkingtonf26c8d12018-03-06 14:21:10 +0000366 if (Status)
367 *Status = InternalStatus;
Zachary Turnerbcadcdd2018-07-20 17:16:49 +0000368 return InternalStatus == demangle_success ? Buf : nullptr;
Howard Hinnantd213ffd2011-05-05 15:27:28 +0000369}
Howard Hinnant6c33e762013-06-17 18:10:34 +0000370} // __cxxabiv1