LLVM  9.0.0svn
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 "llvm/Demangle/Utility.h"
16 #include <cctype>
17 #include <string>
18 
19 using namespace llvm;
20 using namespace ms_demangle;
21 
22 #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
23  case Enum::Value: \
24  OS << Desc; \
25  break;
26 
27 // Writes a space if the last token does not end with a punctuation.
28 static void outputSpaceIfNecessary(OutputStream &OS) {
29  if (OS.empty())
30  return;
31 
32  char C = OS.back();
33  if (std::isalnum(C) || C == '>')
34  OS << " ";
35 }
36 
37 static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
38  switch (Q) {
39  case Q_Const:
40  OS << "const";
41  break;
42  case Q_Volatile:
43  OS << "volatile";
44  break;
45  case Q_Restrict:
46  OS << "__restrict";
47  break;
48  default:
49  break;
50  }
51 }
52 
53 static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
54  Qualifiers Mask, bool NeedSpace) {
55  if (!(Q & Mask))
56  return NeedSpace;
57 
58  if (NeedSpace)
59  OS << " ";
60 
61  outputSingleQualifier(OS, Mask);
62  return true;
63 }
64 
65 static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
66  bool SpaceAfter) {
67  if (Q == Q_None)
68  return;
69 
70  size_t Pos1 = OS.getCurrentPosition();
71  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
72  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
73  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
74  size_t Pos2 = OS.getCurrentPosition();
75  if (SpaceAfter && Pos2 > Pos1)
76  OS << " ";
77 }
78 
79 static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
81 
82  switch (CC) {
83  case CallingConv::Cdecl:
84  OS << "__cdecl";
85  break;
87  OS << "__fastcall";
88  break;
90  OS << "__pascal";
91  break;
93  OS << "__regcall";
94  break;
96  OS << "__stdcall";
97  break;
99  OS << "__thiscall";
100  break;
101  case CallingConv::Eabi:
102  OS << "__eabi";
103  break;
105  OS << "__vectorcall";
106  break;
108  OS << "__clrcall";
109  break;
110  default:
111  break;
112  }
113 }
114 
115 std::string Node::toString(OutputFlags Flags) const {
116  OutputStream OS;
117  initializeOutputStream(nullptr, nullptr, OS, 1024);
118  this->output(OS, Flags);
119  OS << '\0';
120  return {OS.getBuffer()};
121 }
122 
123 void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}
124 
125 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
126  switch (PrimKind) {
131  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
136  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
138  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
140  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
142  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
147  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
148  }
149  outputQualifiers(OS, Quals, true, false);
150 }
151 
152 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
153  output(OS, Flags, ", ");
154 }
155 
156 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
157  StringView Separator) const {
158  if (Count == 0)
159  return;
160  if (Nodes[0])
161  Nodes[0]->output(OS, Flags);
162  for (size_t I = 1; I < Count; ++I) {
163  OS << Separator;
164  Nodes[I]->output(OS, Flags);
165  }
166 }
167 
168 void EncodedStringLiteralNode::output(OutputStream &OS,
169  OutputFlags Flags) const {
170  switch (Char) {
171  case CharKind::Wchar:
172  OS << "L\"";
173  break;
174  case CharKind::Char:
175  OS << "\"";
176  break;
177  case CharKind::Char16:
178  OS << "u\"";
179  break;
180  case CharKind::Char32:
181  OS << "U\"";
182  break;
183  }
184  OS << DecodedString << "\"";
185  if (IsTruncated)
186  OS << "...";
187 }
188 
189 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
190  if (IsNegative)
191  OS << '-';
192  OS << Value;
193 }
194 
196  OutputFlags Flags) const {
197  if (ThunkOffsetCount > 0)
198  OS << "{";
199  else if (Affinity == PointerAffinity::Pointer)
200  OS << "&";
201 
202  if (Symbol) {
203  Symbol->output(OS, Flags);
204  if (ThunkOffsetCount > 0)
205  OS << ", ";
206  }
207 
208  if (ThunkOffsetCount > 0)
209  OS << ThunkOffsets[0];
210  for (int I = 1; I < ThunkOffsetCount; ++I) {
211  OS << ", " << ThunkOffsets[I];
212  }
213  if (ThunkOffsetCount > 0)
214  OS << "}";
215 }
216 
218  OutputFlags Flags) const {
219  if (!TemplateParams)
220  return;
221  OS << "<";
222  TemplateParams->output(OS, Flags);
223  OS << ">";
224 }
225 
227  OutputFlags Flags) const {
228  if (IsDestructor)
229  OS << "`dynamic atexit destructor for ";
230  else
231  OS << "`dynamic initializer for ";
232 
233  if (Variable) {
234  OS << "`";
235  Variable->output(OS, Flags);
236  OS << "''";
237  } else {
238  OS << "'";
239  Name->output(OS, Flags);
240  OS << "''";
241  }
242 }
243 
244 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
245  OS << Name;
246  outputTemplateParameters(OS, Flags);
247 }
248 
250  OutputFlags Flags) const {
251  switch (Operator) {
261  "operator[]");
270  "operator->*");
277  "operator>=");
293  "operator&=");
295  "operator|=");
297  "operator^=");
300  "`vector deleting dtor'");
302  "`default ctor closure'");
304  "`scalar deleting dtor'");
306  "`vector ctor iterator'");
308  "`vector dtor iterator'");
310  "`vector vbase ctor iterator'");
312  "`virtual displacement map'");
314  "`eh vector ctor iterator'");
316  "`eh vector dtor iterator'");
318  "`eh vector vbase ctor iterator'");
320  "`copy ctor closure'");
322  "`local vftable ctor closure'");
325  "operator delete[]");
327  "`managed vector ctor iterator'");
329  "`managed vector dtor iterator'");
331  "`EH vector copy ctor iterator'");
333  "`EH vector vbase copy ctor iterator'");
335  "`vector copy ctor iterator'");
337  "`vector vbase copy constructor iterator'");
339  "`managed vector vbase copy constructor iterator'");
341  "operator co_await");
345  break;
346  }
347  outputTemplateParameters(OS, Flags);
348 }
349 
351  OutputFlags Flags) const {
352  if (IsThread)
353  OS << "`local static thread guard'";
354  else
355  OS << "`local static guard'";
356  if (ScopeIndex > 0)
357  OS << "{" << ScopeIndex << "}";
358 }
359 
361  OutputFlags Flags) const {
362  OS << "operator";
363  outputTemplateParameters(OS, Flags);
364  OS << " ";
365  TargetType->output(OS, Flags);
366 }
367 
368 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
369  if (IsDestructor)
370  OS << "~";
371  Class->output(OS, Flags);
372  outputTemplateParameters(OS, Flags);
373 }
374 
376  OutputFlags Flags) const {
377  OS << "operator \"\"" << Name;
378  outputTemplateParameters(OS, Flags);
379 }
380 
381 void FunctionSignatureNode::outputPre(OutputStream &OS,
382  OutputFlags Flags) const {
383  if (FunctionClass & FC_Public)
384  OS << "public: ";
385  if (FunctionClass & FC_Protected)
386  OS << "protected: ";
387  if (FunctionClass & FC_Private)
388  OS << "private: ";
389 
390  if (!(FunctionClass & FC_Global)) {
391  if (FunctionClass & FC_Static)
392  OS << "static ";
393  }
394  if (FunctionClass & FC_Virtual)
395  OS << "virtual ";
396 
397  if (FunctionClass & FC_ExternC)
398  OS << "extern \"C\" ";
399 
400  if (ReturnType) {
401  ReturnType->outputPre(OS, Flags);
402  OS << " ";
403  }
404 
405  if (!(Flags & OF_NoCallingConvention))
406  outputCallingConvention(OS, CallConvention);
407 }
408 
409 void FunctionSignatureNode::outputPost(OutputStream &OS,
410  OutputFlags Flags) const {
411  if (!(FunctionClass & FC_NoParameterList)) {
412  OS << "(";
413  if (Params)
414  Params->output(OS, Flags);
415  else
416  OS << "void";
417 
418  if (IsVariadic) {
419  if (OS.back() != '(')
420  OS << ", ";
421  OS << "...";
422  }
423  OS << ")";
424  }
425 
426  if (Quals & Q_Const)
427  OS << " const";
428  if (Quals & Q_Volatile)
429  OS << " volatile";
430  if (Quals & Q_Restrict)
431  OS << " __restrict";
432  if (Quals & Q_Unaligned)
433  OS << " __unaligned";
434 
435  if (IsNoexcept)
436  OS << " noexcept";
437 
438  if (RefQualifier == FunctionRefQualifier::Reference)
439  OS << " &";
440  else if (RefQualifier == FunctionRefQualifier::RValueReference)
441  OS << " &&";
442 
443  if (ReturnType)
444  ReturnType->outputPost(OS, Flags);
445 }
446 
447 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
448  OS << "[thunk]: ";
449 
451 }
452 
453 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
454  if (FunctionClass & FC_StaticThisAdjust) {
455  OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
456  } else if (FunctionClass & FC_VirtualThisAdjust) {
457  if (FunctionClass & FC_VirtualThisAdjustEx) {
458  OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
459  << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
460  << ", " << ThisAdjust.StaticOffset << "}'";
461  } else {
462  OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
463  << ThisAdjust.StaticOffset << "}'";
464  }
465  }
466 
468 }
469 
470 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
471  if (Pointee->kind() == NodeKind::FunctionSignature) {
472  // If this is a pointer to a function, don't output the calling convention.
473  // It needs to go inside the parentheses.
474  const FunctionSignatureNode *Sig =
475  static_cast<const FunctionSignatureNode *>(Pointee);
477  } else
478  Pointee->outputPre(OS, Flags);
479 
481 
482  if (Quals & Q_Unaligned)
483  OS << "__unaligned ";
484 
485  if (Pointee->kind() == NodeKind::ArrayType) {
486  OS << "(";
487  } else if (Pointee->kind() == NodeKind::FunctionSignature) {
488  OS << "(";
489  const FunctionSignatureNode *Sig =
490  static_cast<const FunctionSignatureNode *>(Pointee);
492  OS << " ";
493  }
494 
495  if (ClassParent) {
496  ClassParent->output(OS, Flags);
497  OS << "::";
498  }
499 
500  switch (Affinity) {
502  OS << "*";
503  break;
505  OS << "&";
506  break;
508  OS << "&&";
509  break;
510  default:
511  assert(false);
512  }
513  outputQualifiers(OS, Quals, false, false);
514 }
515 
516 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
517  if (Pointee->kind() == NodeKind::ArrayType ||
518  Pointee->kind() == NodeKind::FunctionSignature)
519  OS << ")";
520 
521  Pointee->outputPost(OS, Flags);
522 }
523 
524 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
525  if (!(Flags & OF_NoTagSpecifier)) {
526  switch (Tag) {
531  }
532  OS << " ";
533  }
534  QualifiedName->output(OS, Flags);
535  outputQualifiers(OS, Quals, true, false);
536 }
537 
538 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
539 
540 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
541  ElementType->outputPre(OS, Flags);
542  outputQualifiers(OS, Quals, true, false);
543 }
544 
545 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
546  Node *N) const {
548  IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
549  if (ILN->Value != 0)
550  ILN->output(OS, Flags);
551 }
552 
554  OutputFlags Flags) const {
555  if (Dimensions->Count == 0)
556  return;
557 
558  outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
559  for (size_t I = 1; I < Dimensions->Count; ++I) {
560  OS << "][";
561  outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
562  }
563 }
564 
565 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
566  OS << "[";
567  outputDimensionsImpl(OS, Flags);
568  OS << "]";
569 
570  ElementType->outputPost(OS, Flags);
571 }
572 
573 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
574  Name->output(OS, Flags);
575 }
576 
577 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
578  Signature->outputPre(OS, Flags);
580  Name->output(OS, Flags);
581  Signature->outputPost(OS, Flags);
582 }
583 
584 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
585  switch (SC) {
587  OS << "private: static ";
588  break;
590  OS << "public: static ";
591  break;
593  OS << "protected: static ";
594  break;
595  default:
596  break;
597  }
598 
599  if (Type) {
600  Type->outputPre(OS, Flags);
602  }
603  Name->output(OS, Flags);
604  if (Type)
605  Type->outputPost(OS, Flags);
606 }
607 
608 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
609  Identifier->output(OS, Flags);
610 }
611 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
612 
613 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
614  Components->output(OS, Flags, "::");
615 }
616 
618  OutputFlags Flags) const {
619  OS << "`RTTI Base Class Descriptor at (";
620  OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
621  << this->Flags;
622  OS << ")'";
623 }
624 
626  OutputFlags Flags) const {
627  Name->output(OS, Flags);
628 }
629 
630 void VcallThunkIdentifierNode::output(OutputStream &OS,
631  OutputFlags Flags) const {
632  OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
633 }
634 
635 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
636  outputQualifiers(OS, Quals, false, true);
637  Name->output(OS, Flags);
638  if (TargetName) {
639  OS << "{for `";
640  TargetName->output(OS, Flags);
641  OS << "'}";
642  }
643  return;
644 }
uint64_t CallInst * C
void outputQuals(bool SpaceBefore, bool SpaceAfter) const
void output(OutputStream &OS, OutputFlags Flags) const override
void outputPost(OutputStream &OS, OutputFlags Flags) const
void output(OutputStream &OS, OutputFlags Flags) const override
This class represents lattice values for constants.
Definition: AllocatorList.h:23
static void outputSpaceIfNecessary(OutputStream &OS)
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
static void outputCallingConvention(OutputStream &OS, CallingConv CC)
void outputPre(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void outputPost(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const
static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, Qualifiers Mask, bool NeedSpace)
void outputPre(OutputStream &OS, OutputFlags Flags) const
static void outputSingleQualifier(OutputStream &OS, Qualifiers Q)
void outputPost(OutputStream &OS, OutputFlags Flags) const override
void outputPre(OutputStream &OS, OutputFlags Flags) const override
void outputPost(OutputStream &OS, OutputFlags Flags) const
std::string toString(OutputFlags Flags=OF_Default) const
void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
void outputPre(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)
void outputPre(OutputStream &OS, OutputFlags Flags) const
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
This is a utility class that provides an abstraction for the common functionality between Instruction...
Definition: Operator.h:30
CHAIN = SC CHAIN, Imm128 - System call.
Qualifiers
void output(OutputStream &OS, OutputFlags Flags) const override
void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const
void output(OutputStream &OS, OutputFlags Flags) const override
static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, bool SpaceAfter)
void outputPre(OutputStream &OS, OutputFlags Flags) const override
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void output(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, size_t InitSize)
Definition: Utility.h:174
std::underlying_type< E >::type Mask()
Get a bitmask with 1s in all places up to the high-order bit of E&#39;s largest value.
Definition: BitmaskEnum.h:80
virtual void output(OutputStream &OS, OutputFlags Flags) const =0
void outputPost(OutputStream &OS, OutputFlags Flags) const override
void output(OutputStream &OS, OutputFlags Flags) const override
void outputPost(OutputStream &OS, OutputFlags Flags) const override
void outputPre(OutputStream &OS, OutputFlags Flags) const