LLVM  10.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 PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
124  switch (PrimKind) {
129  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
134  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
136  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
138  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
140  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
145  OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
146  }
147  outputQualifiers(OS, Quals, true, false);
148 }
149 
150 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
151  output(OS, Flags, ", ");
152 }
153 
154 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
155  StringView Separator) const {
156  if (Count == 0)
157  return;
158  if (Nodes[0])
159  Nodes[0]->output(OS, Flags);
160  for (size_t I = 1; I < Count; ++I) {
161  OS << Separator;
162  Nodes[I]->output(OS, Flags);
163  }
164 }
165 
166 void EncodedStringLiteralNode::output(OutputStream &OS,
167  OutputFlags Flags) const {
168  switch (Char) {
169  case CharKind::Wchar:
170  OS << "L\"";
171  break;
172  case CharKind::Char:
173  OS << "\"";
174  break;
175  case CharKind::Char16:
176  OS << "u\"";
177  break;
178  case CharKind::Char32:
179  OS << "U\"";
180  break;
181  }
182  OS << DecodedString << "\"";
183  if (IsTruncated)
184  OS << "...";
185 }
186 
187 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
188  if (IsNegative)
189  OS << '-';
190  OS << Value;
191 }
192 
194  OutputFlags Flags) const {
195  if (ThunkOffsetCount > 0)
196  OS << "{";
197  else if (Affinity == PointerAffinity::Pointer)
198  OS << "&";
199 
200  if (Symbol) {
201  Symbol->output(OS, Flags);
202  if (ThunkOffsetCount > 0)
203  OS << ", ";
204  }
205 
206  if (ThunkOffsetCount > 0)
207  OS << ThunkOffsets[0];
208  for (int I = 1; I < ThunkOffsetCount; ++I) {
209  OS << ", " << ThunkOffsets[I];
210  }
211  if (ThunkOffsetCount > 0)
212  OS << "}";
213 }
214 
216  OutputFlags Flags) const {
217  if (!TemplateParams)
218  return;
219  OS << "<";
220  TemplateParams->output(OS, Flags);
221  OS << ">";
222 }
223 
225  OutputFlags Flags) const {
226  if (IsDestructor)
227  OS << "`dynamic atexit destructor for ";
228  else
229  OS << "`dynamic initializer for ";
230 
231  if (Variable) {
232  OS << "`";
233  Variable->output(OS, Flags);
234  OS << "''";
235  } else {
236  OS << "'";
237  Name->output(OS, Flags);
238  OS << "''";
239  }
240 }
241 
242 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
243  OS << Name;
244  outputTemplateParameters(OS, Flags);
245 }
246 
248  OutputFlags Flags) const {
249  switch (Operator) {
259  "operator[]");
268  "operator->*");
275  "operator>=");
291  "operator&=");
293  "operator|=");
295  "operator^=");
298  "`vector deleting dtor'");
300  "`default ctor closure'");
302  "`scalar deleting dtor'");
304  "`vector ctor iterator'");
306  "`vector dtor iterator'");
308  "`vector vbase ctor iterator'");
310  "`virtual displacement map'");
312  "`eh vector ctor iterator'");
314  "`eh vector dtor iterator'");
316  "`eh vector vbase ctor iterator'");
318  "`copy ctor closure'");
320  "`local vftable ctor closure'");
323  "operator delete[]");
325  "`managed vector ctor iterator'");
327  "`managed vector dtor iterator'");
329  "`EH vector copy ctor iterator'");
331  "`EH vector vbase copy ctor iterator'");
333  "`vector copy ctor iterator'");
335  "`vector vbase copy constructor iterator'");
337  "`managed vector vbase copy constructor iterator'");
339  "operator co_await");
343  break;
344  }
345  outputTemplateParameters(OS, Flags);
346 }
347 
349  OutputFlags Flags) const {
350  if (IsThread)
351  OS << "`local static thread guard'";
352  else
353  OS << "`local static guard'";
354  if (ScopeIndex > 0)
355  OS << "{" << ScopeIndex << "}";
356 }
357 
359  OutputFlags Flags) const {
360  OS << "operator";
361  outputTemplateParameters(OS, Flags);
362  OS << " ";
363  TargetType->output(OS, Flags);
364 }
365 
366 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
367  if (IsDestructor)
368  OS << "~";
369  Class->output(OS, Flags);
370  outputTemplateParameters(OS, Flags);
371 }
372 
374  OutputFlags Flags) const {
375  OS << "operator \"\"" << Name;
376  outputTemplateParameters(OS, Flags);
377 }
378 
379 void FunctionSignatureNode::outputPre(OutputStream &OS,
380  OutputFlags Flags) const {
381  if (!(Flags & OF_NoAccessSpecifier)) {
382  if (FunctionClass & FC_Public)
383  OS << "public: ";
384  if (FunctionClass & FC_Protected)
385  OS << "protected: ";
386  if (FunctionClass & FC_Private)
387  OS << "private: ";
388  }
389 
390  if (!(Flags & OF_NoMemberType)) {
391  if (!(FunctionClass & FC_Global)) {
392  if (FunctionClass & FC_Static)
393  OS << "static ";
394  }
395  if (FunctionClass & FC_Virtual)
396  OS << "virtual ";
397 
398  if (FunctionClass & FC_ExternC)
399  OS << "extern \"C\" ";
400  }
401 
402  if (!(Flags & OF_NoReturnType) && ReturnType) {
403  ReturnType->outputPre(OS, Flags);
404  OS << " ";
405  }
406 
407  if (!(Flags & OF_NoCallingConvention))
408  outputCallingConvention(OS, CallConvention);
409 }
410 
411 void FunctionSignatureNode::outputPost(OutputStream &OS,
412  OutputFlags Flags) const {
413  if (!(FunctionClass & FC_NoParameterList)) {
414  OS << "(";
415  if (Params)
416  Params->output(OS, Flags);
417  else
418  OS << "void";
419 
420  if (IsVariadic) {
421  if (OS.back() != '(')
422  OS << ", ";
423  OS << "...";
424  }
425  OS << ")";
426  }
427 
428  if (Quals & Q_Const)
429  OS << " const";
430  if (Quals & Q_Volatile)
431  OS << " volatile";
432  if (Quals & Q_Restrict)
433  OS << " __restrict";
434  if (Quals & Q_Unaligned)
435  OS << " __unaligned";
436 
437  if (IsNoexcept)
438  OS << " noexcept";
439 
440  if (RefQualifier == FunctionRefQualifier::Reference)
441  OS << " &";
442  else if (RefQualifier == FunctionRefQualifier::RValueReference)
443  OS << " &&";
444 
445  if (!(Flags & OF_NoReturnType) && ReturnType)
446  ReturnType->outputPost(OS, Flags);
447 }
448 
449 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
450  OS << "[thunk]: ";
451 
453 }
454 
455 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
456  if (FunctionClass & FC_StaticThisAdjust) {
457  OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
458  } else if (FunctionClass & FC_VirtualThisAdjust) {
459  if (FunctionClass & FC_VirtualThisAdjustEx) {
460  OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
461  << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
462  << ", " << ThisAdjust.StaticOffset << "}'";
463  } else {
464  OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
465  << ThisAdjust.StaticOffset << "}'";
466  }
467  }
468 
470 }
471 
472 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
473  if (Pointee->kind() == NodeKind::FunctionSignature) {
474  // If this is a pointer to a function, don't output the calling convention.
475  // It needs to go inside the parentheses.
476  const FunctionSignatureNode *Sig =
477  static_cast<const FunctionSignatureNode *>(Pointee);
479  } else
480  Pointee->outputPre(OS, Flags);
481 
483 
484  if (Quals & Q_Unaligned)
485  OS << "__unaligned ";
486 
487  if (Pointee->kind() == NodeKind::ArrayType) {
488  OS << "(";
489  } else if (Pointee->kind() == NodeKind::FunctionSignature) {
490  OS << "(";
491  const FunctionSignatureNode *Sig =
492  static_cast<const FunctionSignatureNode *>(Pointee);
494  OS << " ";
495  }
496 
497  if (ClassParent) {
498  ClassParent->output(OS, Flags);
499  OS << "::";
500  }
501 
502  switch (Affinity) {
504  OS << "*";
505  break;
507  OS << "&";
508  break;
510  OS << "&&";
511  break;
512  default:
513  assert(false);
514  }
515  outputQualifiers(OS, Quals, false, false);
516 }
517 
518 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
519  if (Pointee->kind() == NodeKind::ArrayType ||
520  Pointee->kind() == NodeKind::FunctionSignature)
521  OS << ")";
522 
523  Pointee->outputPost(OS, Flags);
524 }
525 
526 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
527  if (!(Flags & OF_NoTagSpecifier)) {
528  switch (Tag) {
533  }
534  OS << " ";
535  }
536  QualifiedName->output(OS, Flags);
537  outputQualifiers(OS, Quals, true, false);
538 }
539 
540 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
541 
542 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
543  ElementType->outputPre(OS, Flags);
544  outputQualifiers(OS, Quals, true, false);
545 }
546 
547 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
548  Node *N) const {
550  IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
551  if (ILN->Value != 0)
552  ILN->output(OS, Flags);
553 }
554 
556  OutputFlags Flags) const {
557  if (Dimensions->Count == 0)
558  return;
559 
560  outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
561  for (size_t I = 1; I < Dimensions->Count; ++I) {
562  OS << "][";
563  outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
564  }
565 }
566 
567 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
568  OS << "[";
569  outputDimensionsImpl(OS, Flags);
570  OS << "]";
571 
572  ElementType->outputPost(OS, Flags);
573 }
574 
575 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
576  Name->output(OS, Flags);
577 }
578 
579 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
580  Signature->outputPre(OS, Flags);
582  Name->output(OS, Flags);
583  Signature->outputPost(OS, Flags);
584 }
585 
586 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
587  const char *AccessSpec = nullptr;
588  bool IsStatic = true;
589  switch (SC) {
591  AccessSpec = "private";
592  break;
594  AccessSpec = "public";
595  break;
597  AccessSpec = "protected";
598  break;
599  default:
600  IsStatic = false;
601  break;
602  }
603  if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
604  OS << AccessSpec << ": ";
605  if (!(Flags & OF_NoMemberType) && IsStatic)
606  OS << "static ";
607 
608  if (Type) {
609  Type->outputPre(OS, Flags);
611  }
612  Name->output(OS, Flags);
613  if (Type)
614  Type->outputPost(OS, Flags);
615 }
616 
617 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
618  Identifier->output(OS, Flags);
619 }
620 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
621 
622 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
623  Components->output(OS, Flags, "::");
624 }
625 
627  OutputFlags Flags) const {
628  OS << "`RTTI Base Class Descriptor at (";
629  OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
630  << this->Flags;
631  OS << ")'";
632 }
633 
635  OutputFlags Flags) const {
636  Name->output(OS, Flags);
637 }
638 
639 void VcallThunkIdentifierNode::output(OutputStream &OS,
640  OutputFlags Flags) const {
641  OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
642 }
643 
644 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
645  outputQualifiers(OS, Quals, false, true);
646  Name->output(OS, Flags);
647  if (TargetName) {
648  OS << "{for `";
649  TargetName->output(OS, Flags);
650  OS << "'}";
651  }
652  return;
653 }
uint64_t CallInst * C
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:46
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