LLVM: lib/Demangle/ItaniumDemangle.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
15
16#include
17#include
18#include
19#include
20#include
21#include
22#include
23#include
24
25using namespace llvm;
27
28
29
30
31const char *itanium_demangle::parse_discriminator(const char *first,
32 const char *last) {
33
34 if (first != last) {
35 if (*first == '_') {
36 const char *t1 = first + 1;
37 if (t1 != last) {
38 if (std::isdigit(*t1))
39 first = t1 + 1;
40 else if (*t1 == '_') {
41 for (++t1; t1 != last && std::isdigit(*t1); ++t1)
42 ;
43 if (t1 != last && *t1 == '_')
44 first = t1 + 1;
45 }
46 }
47 } else if (std::isdigit(*first)) {
48 const char *t1 = first + 1;
49 for (; t1 != last && std::isdigit(*t1); ++t1)
50 ;
51 if (t1 == last)
53 }
54 }
55 return first;
56}
57
58#ifndef NDEBUG
59namespace {
60struct DumpVisitor {
61 unsigned Depth = 0;
62 bool PendingNewline = false;
63
64 template static constexpr bool wantsNewline(const NodeT *) {
65 return true;
66 }
67 static bool wantsNewline(NodeArray A) { return .empty(); }
68 static constexpr bool wantsNewline(...) { return false; }
69
70 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
71 for (bool B : {wantsNewline(Vs)...})
72 if (B)
73 return true;
74 return false;
75 }
76
77 void printStr(const char *S) { fprintf(stderr, "%s", S); }
78 void print(std::string_view SV) {
79 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data());
80 }
81 void print(const Node *N) {
82 if (N)
83 N->visit(std::ref(*this));
84 else
85 printStr("");
86 }
88 ++Depth;
89 printStr("{");
90 bool First = true;
94 else
95 printWithComma(N);
97 }
98 printStr("}");
99 --Depth;
100 }
101
102
103 void print(bool B) { printStr(B ? "true" : "false"); }
104
105 template std::enable_if_t<std::is_unsigned::value> print(T N) {
106 fprintf(stderr, "%llu", (unsigned long long)N);
107 }
108
109 template std::enable_if_t<std::is_signed::value> print(T N) {
110 fprintf(stderr, "%lld", (long long)N);
111 }
112
114 switch (RK) {
116 return printStr("ReferenceKind::LValue");
118 return printStr("ReferenceKind::RValue");
119 }
120 }
122 switch (RQ) {
124 return printStr("FunctionRefQual::FrefQualNone");
126 return printStr("FunctionRefQual::FrefQualLValue");
128 return printStr("FunctionRefQual::FrefQualRValue");
129 }
130 }
132 if (!Qs) return printStr("QualNone");
133 struct QualName { Qualifiers Q; const char *Name; } Names[] = {
137 };
138 for (QualName Name : Names) {
139 if (Qs & Name.Q) {
140 printStr(Name.Name);
142 if (Qs) printStr(" | ");
143 }
144 }
145 }
147 switch (SSK) {
149 return printStr("SpecialSubKind::allocator");
151 return printStr("SpecialSubKind::basic_string");
153 return printStr("SpecialSubKind::string");
155 return printStr("SpecialSubKind::istream");
157 return printStr("SpecialSubKind::ostream");
159 return printStr("SpecialSubKind::iostream");
160 }
161 }
163 switch (TPK) {
165 return printStr("TemplateParamKind::Type");
167 return printStr("TemplateParamKind::NonType");
169 return printStr("TemplateParamKind::Template");
170 }
171 }
173 switch (P) {
175 return printStr("Node::Prec::Primary");
177 return printStr("Node::Prec::Postfix");
179 return printStr("Node::Prec::Unary");
181 return printStr("Node::Prec::Cast");
183 return printStr("Node::Prec::PtrMem");
185 return printStr("Node::Prec::Multiplicative");
187 return printStr("Node::Prec::Additive");
189 return printStr("Node::Prec::Shift");
191 return printStr("Node::Prec::Spaceship");
193 return printStr("Node::Prec::Relational");
195 return printStr("Node::Prec::Equality");
197 return printStr("Node::Prec::And");
199 return printStr("Node::Prec::Xor");
201 return printStr("Node::Prec::Ior");
203 return printStr("Node::Prec::AndIf");
205 return printStr("Node::Prec::OrIf");
207 return printStr("Node::Prec::Conditional");
209 return printStr("Node::Prec::Assign");
211 return printStr("Node::Prec::Comma");
213 return printStr("Node::Prec::Default");
214 }
215 }
216
217 void newLine() {
218 printStr("\n");
219 for (unsigned I = 0; I != Depth; ++I)
220 printStr(" ");
221 PendingNewline = false;
222 }
223
224 template void printWithPendingNewline(T V) {
226 if (wantsNewline(V))
227 PendingNewline = true;
228 }
229
230 template void printWithComma(T V) {
231 if (PendingNewline || wantsNewline(V)) {
232 printStr(",");
233 newLine();
234 } else {
235 printStr(", ");
236 }
237
238 printWithPendingNewline(V);
239 }
240
241 struct CtorArgPrinter {
242 DumpVisitor &Visitor;
243
244 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
245 if (Visitor.anyWantNewline(V, Vs...))
246 Visitor.newLine();
247 Visitor.printWithPendingNewline(V);
248 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
249 (void)PrintInOrder;
250 }
251 };
252
253 template void operator()(const NodeT *Node) {
254 Depth += 2;
255 fprintf(stderr, "%s(", itanium_demangle::NodeKind::name());
256 Node->match(CtorArgPrinter{*this});
257 fprintf(stderr, ")");
258 Depth -= 2;
259 }
260
261 void operator()(const ForwardTemplateReference *Node) {
262 Depth += 2;
263 fprintf(stderr, "ForwardTemplateReference(");
264 if (Node->Ref && ->Printing) {
265 Node->Printing = true;
266 CtorArgPrinter{*this}(Node->Ref);
267 Node->Printing = false;
268 } else {
269 CtorArgPrinter{*this}(Node->Index);
270 }
271 fprintf(stderr, ")");
272 Depth -= 2;
273 }
274};
275}
276
277void itanium_demangle::Node::dump() const {
278 DumpVisitor V;
279 visit(std::ref(V));
280 V.newLine();
281}
282#endif
283
284namespace {
285class BumpPointerAllocator {
286 struct BlockMeta {
287 BlockMeta* Next;
288 size_t Current;
289 };
290
291 static constexpr size_t AllocSize = 4096;
292 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
293
294 alignas(long double) char InitialBuffer[AllocSize];
295 BlockMeta* BlockList = nullptr;
296
297 void grow() {
298 char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
299 if (NewMeta == nullptr)
300 std::terminate();
301 BlockList = new (NewMeta) BlockMeta{BlockList, 0};
302 }
303
304 void* allocateMassive(size_t NBytes) {
305 NBytes += sizeof(BlockMeta);
306 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
307 if (NewMeta == nullptr)
308 std::terminate();
309 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
310 return static_cast<void*>(NewMeta + 1);
311 }
312
313public:
314 BumpPointerAllocator()
315 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
316
317 void* allocate(size_t N) {
319 if (N + BlockList->Current >= UsableAllocSize) {
320 if (N > UsableAllocSize)
321 return allocateMassive(N);
322 grow();
323 }
324 BlockList->Current += N;
325 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
326 BlockList->Current - N);
327 }
328
329 void reset() {
330 while (BlockList) {
331 BlockMeta* Tmp = BlockList;
332 BlockList = BlockList->Next;
333 if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
334 std::free(Tmp);
335 }
336 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
337 }
338
339 ~BumpPointerAllocator() { reset(); }
340};
341
342class DefaultAllocator {
343 BumpPointerAllocator Alloc;
344
345public:
346 void reset() { Alloc.reset(); }
347
348 template<typename T, typename ...Args> T *makeNode(Args &&...args) {
349 return new (Alloc.allocate(sizeof(T)))
351 }
352
353 void *allocateNodeArray(size_t sz) {
354 return Alloc.allocate(sizeof(Node *) * sz);
355 }
356};
357}
358
359
360
361
362
363using Demangler = itanium_demangle::ManglingParser;
364
366 if (MangledName.empty())
367 return nullptr;
368
369 Demangler Parser(MangledName.data(),
370 MangledName.data() + MangledName.length());
371 Node *AST = Parser.parse(ParseParams);
372 if (!AST)
373 return nullptr;
374
376 assert(Parser.ForwardTemplateRefs.empty());
378 OB += '\0';
379 return OB.getBuffer();
380}
381
383 : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
384
386 delete static_cast<Demangler *>(Context);
387}
388
391 : RootNode(Other.RootNode), Context(Other.Context) {
392 Other.Context = Other.RootNode = nullptr;
393}
394
401
402
404 Demangler *Parser = static_cast<Demangler *>(Context);
405 size_t Len = std::strlen(MangledName);
406 Parser->reset(MangledName, MangledName + Len);
407 RootNode = Parser->parse();
408 return RootNode == nullptr;
409}
411 RootNode->print(OB);
412 OB += '\0';
413 if (N != nullptr)
414 *N = OB.getCurrentPosition();
415 return OB.getBuffer();
416}
417
422
425 return nullptr;
426
428
429 while (true) {
430 switch (Name->getKind()) {
431 case Node::KAbiTagAttr:
433 continue;
434 case Node::KModuleEntity:
435 Name = static_cast<const ModuleEntity *>(Name)->Name;
436 continue;
437 case Node::KNestedName:
438 Name = static_cast<const NestedName *>(Name)->Name;
439 continue;
440 case Node::KLocalName:
441 Name = static_cast<const LocalName *>(Name)->Entity;
442 continue;
443 case Node::KNameWithTemplateArgs:
445 continue;
446 default:
448 }
449 }
450}
451
453 size_t *N) const {
455 return nullptr;
457
459
460 KeepGoingLocalFunction:
461 while (true) {
462 if (Name->getKind() == Node::KAbiTagAttr) {
464 continue;
465 }
466 if (Name->getKind() == Node::KNameWithTemplateArgs) {
468 continue;
469 }
470 break;
471 }
472
473 if (Name->getKind() == Node::KModuleEntity)
474 Name = static_cast<const ModuleEntity *>(Name)->Name;
475
476 switch (Name->getKind()) {
477 case Node::KNestedName:
479 break;
480 case Node::KLocalName: {
481 auto *LN = static_cast<const LocalName *>(Name);
483 OB += "::";
484 Name = LN->Entity;
485 goto KeepGoingLocalFunction;
486 }
487 default:
488 break;
489 }
490 OB += '\0';
491 if (N != nullptr)
492 *N = OB.getCurrentPosition();
493 return OB.getBuffer();
494}
495
502
504 size_t *N) const {
506 return nullptr;
508
510
511 OB += '(';
513 OB += ')';
514 OB += '\0';
515 if (N != nullptr)
516 *N = OB.getCurrentPosition();
517 return OB.getBuffer();
518}
519
521 char *Buf, size_t *N) const {
523 return nullptr;
524
526
527 if (const Node *Ret =
528 static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
529 Ret->print(OB);
530
531 OB += '\0';
532 if (N != nullptr)
533 *N = OB.getCurrentPosition();
534 return OB.getBuffer();
535}
536
538 assert(RootNode != nullptr && "must call partialDemangle()");
539 return printNode(static_cast<Node *>(RootNode), Buf, N);
540}
541
543 assert(RootNode != nullptr && "must call partialDemangle()");
544 assert(OB != nullptr && "valid OutputBuffer argument required");
547 nullptr);
548}
549
551 assert(RootNode != nullptr && "must call partialDemangle()");
553 return false;
556}
557
559 const Node *N = static_cast<const Node *>(RootNode);
560 while (N) {
561 switch (N->getKind()) {
562 default:
563 return false;
564 case Node::KCtorDtorName:
565 return true;
566
567 case Node::KAbiTagAttr:
569 break;
570 case Node::KFunctionEncoding:
572 break;
573 case Node::KLocalName:
574 N = static_cast<const LocalName *>(N)->Entity;
575 break;
576 case Node::KNameWithTemplateArgs:
578 break;
579 case Node::KNestedName:
580 N = static_cast<const NestedName *>(N)->Name;
581 break;
582 case Node::KModuleEntity:
584 break;
585 }
586 }
587 return false;
588}
589
591 assert(RootNode != nullptr && "must call partialDemangle()");
592 return static_cast<const Node *>(RootNode)->getKind() ==
593 Node::KFunctionEncoding;
594}
595
597 assert(RootNode != nullptr && "must call partialDemangle()");
598 auto K = static_cast<const Node *>(RootNode)->getKind();
599 return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
600}
601
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void printNode(raw_ostream &OS, LazyCallGraph::Node &N)
static StringRef getName(Value *V)
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
Qualifiers getCVQuals() const
void printWithComma(OutputBuffer &OB) const
void print(OutputBuffer &OB) const
Prec
Operator precedence for expression nodes.
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
DEMANGLE_ABI char * itaniumDemangle(std::string_view mangled_name, bool ParseParams=true)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
Definition ItaniumDemangle.cpp:365
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
DEMANGLE_ABI char * getFunctionParameters(char *Buf, size_t *N) const
Get the parameters for this function.
Definition ItaniumDemangle.cpp:503
DEMANGLE_ABI bool isFunction() const
If this symbol describes a function.
Definition ItaniumDemangle.cpp:590
DEMANGLE_ABI char * getFunctionBaseName(char *Buf, size_t *N) const
Get the base name of a function.
Definition ItaniumDemangle.cpp:423
DEMANGLE_ABI bool isSpecialName() const
If this symbol is a .
Definition ItaniumDemangle.cpp:596
DEMANGLE_ABI bool partialDemangle(const char *MangledName)
Demangle into an AST.
Definition ItaniumDemangle.cpp:403
DEMANGLE_ABI char * getFunctionName(char *Buf, size_t *N) const
Get the entire name of this function.
Definition ItaniumDemangle.cpp:496
DEMANGLE_ABI bool hasFunctionQualifiers() const
If this function has any cv or reference qualifiers.
Definition ItaniumDemangle.cpp:550
DEMANGLE_ABI char * finishDemangle(char *Buf, size_t *N) const
Just print the entire mangled name into Buf.
Definition ItaniumDemangle.cpp:537
DEMANGLE_ABI char * getFunctionReturnType(char *Buf, size_t *N) const
Definition ItaniumDemangle.cpp:520
DEMANGLE_ABI ItaniumPartialDemangler()
Definition ItaniumDemangle.cpp:382
DEMANGLE_ABI ItaniumPartialDemangler & operator=(ItaniumPartialDemangler &&Other)
Definition ItaniumDemangle.cpp:396
DEMANGLE_ABI bool isCtorOrDtor() const
If this symbol describes a constructor or destructor.
Definition ItaniumDemangle.cpp:558
DEMANGLE_ABI ~ItaniumPartialDemangler()
Definition ItaniumDemangle.cpp:385
DEMANGLE_ABI char * getFunctionDeclContextName(char *Buf, size_t *N) const
Get the context name for a function.
Definition ItaniumDemangle.cpp:452
DEMANGLE_ABI bool isData() const
If this symbol describes a variable.
Definition ItaniumDemangle.cpp:602