LLVM 24.0.0git
MicrosoftDemangleNodes.cpp
Go to the documentation of this file.
1//===- MicrosoftDemangle.cpp ----------------------------------------------===//
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// This file defines a demangler for MSVC-style mangled symbols.
10//
11//===----------------------------------------------------------------------===//
12
15#include <cctype>
16#include <string>
17
18using namespace llvm;
19using namespace ms_demangle;
20
21#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
22 case Enum::Value: \
23 OB << Desc; \
24 break;
25
26// Writes a space if the last token does not end with a punctuation.
28 if (OB.empty())
29 return;
30
31 char C = OB.back();
32 if (std::isalnum(C) || C == '>')
33 OB << " ";
34}
35
37 switch (Q) {
38 case Q_Const:
39 OB << "const";
40 break;
41 case Q_Volatile:
42 OB << "volatile";
43 break;
44 case Q_Restrict:
45 OB << "__restrict";
46 break;
47 default:
48 break;
49 }
50}
51
53 Qualifiers Mask, bool NeedSpace) {
54 if (!(Q & Mask))
55 return NeedSpace;
56
57 if (NeedSpace)
58 OB << " ";
59
60 outputSingleQualifier(OB, Mask);
61 return true;
62}
63
64static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
65 bool SpaceAfter) {
66 if (Q == Q_None)
67 return;
68
69 size_t Pos1 = OB.getCurrentPosition();
70 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
71 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
72 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
73 size_t Pos2 = OB.getCurrentPosition();
74 if (SpaceAfter && Pos2 > Pos1)
75 OB << " ";
76}
77
80
81 switch (CC) {
82 case CallingConv::Cdecl:
83 OB << "__cdecl";
84 break;
85 case CallingConv::Fastcall:
86 OB << "__fastcall";
87 break;
88 case CallingConv::Pascal:
89 OB << "__pascal";
90 break;
91 case CallingConv::Regcall:
92 OB << "__regcall";
93 break;
94 case CallingConv::Stdcall:
95 OB << "__stdcall";
96 break;
97 case CallingConv::Thiscall:
98 OB << "__thiscall";
99 break;
100 case CallingConv::Eabi:
101 OB << "__eabi";
102 break;
103 case CallingConv::Vectorcall:
104 OB << "__vectorcall";
105 break;
106 case CallingConv::Clrcall:
107 OB << "__clrcall";
108 break;
110 OB << "__attribute__((__swiftcall__)) ";
111 break;
112 case CallingConv::SwiftAsync:
113 OB << "__attribute__((__swiftasynccall__)) ";
114 break;
115 default:
116 break;
117 }
118}
119
120std::string Node::toString(OutputFlags Flags) const {
121 OutputBuffer OB;
122 this->output(OB, Flags);
123 std::string_view SV = OB;
124 std::string Owned(SV.begin(), SV.end());
125 std::free(OB.getBuffer());
126 return Owned;
127}
128
130 switch (PrimKind) {
140 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
146 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
154 }
155 outputQualifiers(OB, Quals, true, false);
156}
157
159 output(OB, Flags, ", ");
160}
161
163 std::string_view Separator) const {
164 if (Count == 0)
165 return;
166 if (Nodes[0])
167 Nodes[0]->output(OB, Flags);
168 for (size_t I = 1; I < Count; ++I) {
169 OB << Separator;
170 Nodes[I]->output(OB, Flags);
171 }
172}
173
175 OutputFlags Flags) const {
176 switch (Char) {
177 case CharKind::Wchar:
178 OB << "L\"";
179 break;
180 case CharKind::Char:
181 OB << "\"";
182 break;
183 case CharKind::Char16:
184 OB << "u\"";
185 break;
186 case CharKind::Char32:
187 OB << "U\"";
188 break;
189 }
190 OB << DecodedString << "\"";
191 if (IsTruncated)
192 OB << "...";
193}
194
196 if (IsNegative)
197 OB << '-';
198 OB << Value;
199}
200
202 OutputFlags Flags) const {
203 if (ThunkOffsetCount > 0)
204 OB << "{";
206 OB << "&";
207
208 if (Symbol) {
209 Symbol->output(OB, Flags);
210 if (ThunkOffsetCount > 0)
211 OB << ", ";
212 }
213
214 if (ThunkOffsetCount > 0)
215 OB << ThunkOffsets[0];
216 for (int I = 1; I < ThunkOffsetCount; ++I) {
217 OB << ", " << ThunkOffsets[I];
218 }
219 if (ThunkOffsetCount > 0)
220 OB << "}";
221}
222
224 OutputFlags Flags) const {
225 if (!TemplateParams)
226 return;
227 OB << "<";
228 std::string_view Sep = (Flags & OF_CompactTemplateLists) ? "," : ", ";
229 TemplateParams->output(OB, Flags, Sep);
230 if ((Flags & OF_SplitTemplateClosers) != 0 && OB.back() == '>')
231 OB << ' ';
232 OB << ">";
233}
234
236 OutputFlags Flags) const {
237 if (IsDestructor)
238 OB << "`dynamic atexit destructor for ";
239 else
240 OB << "`dynamic initializer for ";
241
242 if (Variable) {
243 OB << "`";
244 Variable->output(OB, Flags);
245 OB << "''";
246 } else {
247 OB << "'";
248 Name->output(OB, Flags);
249 OB << "''";
250 }
251}
252
254 OB << Name;
255 outputTemplateParameters(OB, Flags);
256}
257
259 OutputFlags Flags) const {
260 switch (Operator) {
270 "operator[]");
279 "operator->*");
286 "operator>=");
302 "operator&=");
304 "operator|=");
306 "operator^=");
309 "`vector deleting dtor'");
311 "`default ctor closure'");
313 "`scalar deleting dtor'");
315 "`vector ctor iterator'");
317 "`vector dtor iterator'");
319 "`vector vbase ctor iterator'");
321 "`virtual displacement map'");
323 "`eh vector ctor iterator'");
325 "`eh vector dtor iterator'");
327 "`eh vector vbase ctor iterator'");
329 "`copy ctor closure'");
331 "`local vftable ctor closure'");
334 "operator delete[]");
336 "`managed vector ctor iterator'");
338 "`managed vector dtor iterator'");
340 "`EH vector copy ctor iterator'");
342 "`EH vector vbase copy ctor iterator'");
344 "`vector copy ctor iterator'");
346 "`vector vbase copy constructor iterator'");
348 "`managed vector vbase copy constructor iterator'");
350 "operator co_await");
354 break;
355 }
356 outputTemplateParameters(OB, Flags);
357}
358
360 OutputFlags Flags) const {
361 if (IsThread)
362 OB << "`local static thread guard'";
363 else
364 OB << "`local static guard'";
365 if (ScopeIndex > 0)
366 OB << "{" << ScopeIndex << "}";
367}
368
370 OutputFlags Flags) const {
371 OB << "operator";
372 outputTemplateParameters(OB, Flags);
373 OB << " ";
374 TargetType->output(OB, Flags);
375}
376
378 if (IsDestructor)
379 OB << "~";
380 Class->output(OB, Flags);
381 outputTemplateParameters(OB, Flags);
382}
383
385 OutputFlags Flags) const {
386 OB << "operator \"\"" << Name;
387 outputTemplateParameters(OB, Flags);
388}
389
391 OutputFlags Flags) const {
392 if (!(Flags & OF_NoAccessSpecifier)) {
394 OB << "public: ";
396 OB << "protected: ";
398 OB << "private: ";
399 }
400
401 if (!(Flags & OF_NoMemberType)) {
402 if (!(FunctionClass & FC_Global)) {
404 OB << "static ";
405 }
407 OB << "virtual ";
408
410 OB << "extern \"C\" ";
411 }
412
413 if (!(Flags & OF_NoReturnType) && ReturnType) {
414 ReturnType->outputPre(OB, Flags);
415 OB << " ";
416 }
417}
418
420 OutputFlags Flags) const {
421 outputPreSignature(OB, Flags);
422
423 if (!(Flags & OF_NoCallingConvention))
425}
426
428 OutputFlags Flags) const {
430 OB << "(";
431 if (Params)
432 Params->output(OB, Flags);
433 else if (!(Flags & OF_NoVoidParameter))
434 OB << "void";
435
436 if (IsVariadic) {
437 if (OB.back() != '(')
438 OB << ", ";
439 OB << "...";
440 }
441 OB << ")";
442 }
443
444 if (Quals & Q_Const)
445 OB << " const";
446 if (Quals & Q_Volatile)
447 OB << " volatile";
448 if (Quals & Q_Restrict)
449 OB << " __restrict";
450 if (Quals & Q_Unaligned)
451 OB << " __unaligned";
452
453 if (IsNoexcept)
454 OB << " noexcept";
455
457 OB << " &";
459 OB << " &&";
460
461 if (!(Flags & OF_NoReturnType) && ReturnType)
462 ReturnType->outputPost(OB, Flags);
463}
464
466 OB << "[thunk]: ";
467
469}
470
473 OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
474 } else if (FunctionClass & FC_VirtualThisAdjust) {
476 OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
477 << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
478 << ", " << ThisAdjust.StaticOffset << "}'";
479 } else {
480 OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
481 << ThisAdjust.StaticOffset << "}'";
482 }
483 }
484
486}
487
489 if (Pointee->kind() == NodeKind::FunctionSignature) {
490 // If this is a pointer to a function, don't output the calling convention.
491 // It needs to go inside the parentheses.
492 const FunctionSignatureNode *Sig =
493 static_cast<const FunctionSignatureNode *>(Pointee);
494 // A function pointer's return type is part of its type, so we ignore
495 // OF_NoReturnType.
497 } else
498 Pointee->outputPre(OB, Flags);
499
501
502 if (Quals & Q_Unaligned)
503 OB << "__unaligned ";
504
505 if (Pointee->kind() == NodeKind::ArrayType) {
506 OB << "(";
507 } else if (Pointee->kind() == NodeKind::FunctionSignature) {
508 OB << "(";
509 const FunctionSignatureNode *Sig =
510 static_cast<const FunctionSignatureNode *>(Pointee);
511 if (!(Flags & OF_NoCallingConvention)) {
513 OB << " ";
514 }
515 }
516
517 if (ClassParent) {
518 ClassParent->output(OB, Flags);
519 OB << "::";
520 }
521
522 switch (Affinity) {
524 OB << "*";
525 break;
527 OB << "&";
528 break;
530 OB << "&&";
531 break;
532 default:
533 assert(false);
534 }
535 outputQualifiers(OB, Quals, false, false);
536
538 PointerAuthQualifier->output(OB, Flags);
539}
540
542 if (Pointee->kind() == NodeKind::ArrayType ||
544 OB << ")";
545
546 if (Pointee->kind() == NodeKind::FunctionSignature) {
547 // A function pointer's return type is part of its type, so we ignore
548 // OF_NoReturnType.
549 Pointee->outputPost(OB, OutputFlags(Flags & ~OF_NoReturnType));
550 } else
551 Pointee->outputPost(OB, Flags);
552}
553
555 if (!(Flags & OF_NoTagSpecifier)) {
556 switch (Tag) {
561 }
562 OB << " ";
563 }
564 QualifiedName->output(OB, Flags);
565 outputQualifiers(OB, Quals, true, false);
566}
567
569
571 ElementType->outputPre(OB, Flags);
572 outputQualifiers(OB, Quals, true, false);
573}
574
576 Node *N) const {
578 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
579 if (ILN->Value != 0)
580 ILN->output(OB, Flags);
581}
582
584 OutputFlags Flags) const {
585 if (Dimensions->Count == 0)
586 return;
587
588 outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
589 for (size_t I = 1; I < Dimensions->Count; ++I) {
590 OB << "][";
591 outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
592 }
593}
594
596 OB << "[";
597 outputDimensionsImpl(OB, Flags);
598 OB << "]";
599
600 ElementType->outputPost(OB, Flags);
601}
602
604 Name->output(OB, Flags);
605}
606
608 Signature->outputPre(OB, Flags);
610 Name->output(OB, Flags);
611 Signature->outputPost(OB, Flags);
612}
613
615 OutputFlags Flags) const {
616 OB << "__ptrauth(";
617 Components->output(OB, Flags);
618 OB << ")";
619}
620
622 const char *AccessSpec = nullptr;
623 bool IsStatic = true;
624 switch (SC) {
626 AccessSpec = "private";
627 break;
629 AccessSpec = "public";
630 break;
632 AccessSpec = "protected";
633 break;
634 default:
635 IsStatic = false;
636 break;
637 }
638 if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
639 OB << AccessSpec << ": ";
640 if (!(Flags & OF_NoMemberType) && IsStatic)
641 OB << "static ";
642
643 if (!(Flags & OF_NoVariableType) && Type)
644 Type->outputPre(OB, Flags);
645 if (shouldOutputName(Flags)) {
647 Name->output(OB, Flags);
648 }
649 if (!(Flags & OF_NoVariableType) && Type)
650 Type->outputPost(OB, Flags);
651}
652
654 Identifier->output(OB, Flags);
655}
657
659 Components->output(OB, Flags, "::");
660}
661
663 OutputFlags Flags) const {
664 OB << "`RTTI Base Class Descriptor at (";
665 OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
666 << this->Flags;
667 OB << ")'";
668}
669
671 OutputFlags Flags) const {
672 Name->output(OB, Flags);
673}
674
676 OutputFlags Flags) const {
677 OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
678}
679
681 outputQualifiers(OB, Quals, false, true);
682 Name->output(OB, Flags);
683 if (TargetNames) {
684 OB << "{for `";
685 TargetNames->output(OB, Flags, "'s `");
686 OB << "'}";
687 }
688}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
Qualifiers
#define I(x, y, z)
Definition MD5.cpp:57
static void outputCallingConvention(OutputBuffer &OB, CallingConv CC)
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)
static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q)
static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, Qualifiers Mask, bool NeedSpace)
static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, bool SpaceAfter)
static void outputSpaceIfNecessary(OutputBuffer &OB)
RISCVCC::CondCode CC
CallingConv Namespace - This namespace contains an enum with a value for the well-known calling conve...
Definition CallingConv.h:21
@ Swift
Calling convention for Swift.
Definition CallingConv.h:69
@ OF_CompactTemplateLists
Do not insert a space between template arguments (like MSVC does).
@ OF_SplitTemplateClosers
Add a space between nested closing braces of templates.
This is an optimization pass for GlobalISel generic memory operations.
#define N
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const
void output(OutputBuffer &OB, OutputFlags Flags) const override
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void outputPreSignature(OutputBuffer &OB, OutputFlags Flags) const
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
DEMANGLE_ABI void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
virtual void output(OutputBuffer &OB, OutputFlags Flags) const =0
DEMANGLE_ABI std::string toString(OutputFlags Flags=OF_Default) const
void output(OutputBuffer &OB, OutputFlags Flags) const override
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
PointerAuthQualifierNode * PointerAuthQualifier
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override
void output(OutputBuffer &OB, OutputFlags Flags) const override
virtual bool shouldOutputName(OutputFlags Flags) const
void output(OutputBuffer &OB, OutputFlags Flags) const override