1 //===- MicrosoftDemangle.cpp ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines a demangler for MSVC-style mangled symbols.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Demangle/MicrosoftDemangleNodes.h"
14 #include "llvm/Demangle/DemangleConfig.h"
15 #include "llvm/Demangle/Utility.h"
20 using namespace ms_demangle;
22 #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
27 // Writes a space if the last token does not end with a punctuation.
28 static void outputSpaceIfNecessary(OutputStream &OS) {
33 if (std::isalnum(C) || C == '>')
37 static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
53 static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
54 Qualifiers Mask, bool NeedSpace) {
61 outputSingleQualifier(OS, Mask);
65 static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
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)
79 static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
80 outputSpaceIfNecessary(OS);
83 case CallingConv::Cdecl:
86 case CallingConv::Fastcall:
89 case CallingConv::Pascal:
92 case CallingConv::Regcall:
95 case CallingConv::Stdcall:
98 case CallingConv::Thiscall:
101 case CallingConv::Eabi:
104 case CallingConv::Vectorcall:
105 OS << "__vectorcall";
107 case CallingConv::Clrcall:
115 std::string Node::toString(OutputFlags Flags) const {
117 initializeOutputStream(nullptr, nullptr, OS, 1024);
118 this->output(OS, Flags);
120 return {OS.getBuffer()};
123 void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}
125 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
127 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
128 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
129 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
130 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
131 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
132 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
133 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
134 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
135 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
136 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
137 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
138 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
139 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
140 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
141 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
142 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
143 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
144 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
145 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
146 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
147 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
149 outputQualifiers(OS, Quals, true, false);
152 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
153 output(OS, Flags, ", ");
156 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
157 StringView Separator) const {
161 Nodes[0]->output(OS, Flags);
162 for (size_t I = 1; I < Count; ++I) {
164 Nodes[I]->output(OS, Flags);
168 void EncodedStringLiteralNode::output(OutputStream &OS,
169 OutputFlags Flags) const {
171 case CharKind::Wchar:
177 case CharKind::Char16:
180 case CharKind::Char32:
184 OS << DecodedString << "\"";
189 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
195 void TemplateParameterReferenceNode::output(OutputStream &OS,
196 OutputFlags Flags) const {
197 if (ThunkOffsetCount > 0)
199 else if (Affinity == PointerAffinity::Pointer)
203 Symbol->output(OS, Flags);
204 if (ThunkOffsetCount > 0)
208 if (ThunkOffsetCount > 0)
209 OS << ThunkOffsets[0];
210 for (int I = 1; I < ThunkOffsetCount; ++I) {
211 OS << ", " << ThunkOffsets[I];
213 if (ThunkOffsetCount > 0)
217 void IdentifierNode::outputTemplateParameters(OutputStream &OS,
218 OutputFlags Flags) const {
222 TemplateParams->output(OS, Flags);
226 void DynamicStructorIdentifierNode::output(OutputStream &OS,
227 OutputFlags Flags) const {
229 OS << "`dynamic atexit destructor for ";
231 OS << "`dynamic initializer for ";
235 Variable->output(OS, Flags);
239 Name->output(OS, Flags);
244 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
246 outputTemplateParameters(OS, Flags);
249 void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
250 OutputFlags Flags) const {
252 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
253 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
254 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
255 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
256 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
257 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
258 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
259 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
260 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
262 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
263 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
264 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
265 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
266 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
267 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
268 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
269 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
271 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
272 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
273 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
274 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
275 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
276 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
278 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
279 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
280 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
281 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
282 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
283 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
284 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
285 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
286 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
287 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
288 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
289 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
290 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
291 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
292 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
294 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
296 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
298 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
299 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
300 "`vector deleting dtor'");
301 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
302 "`default ctor closure'");
303 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
304 "`scalar deleting dtor'");
305 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
306 "`vector ctor iterator'");
307 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
308 "`vector dtor iterator'");
309 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
310 "`vector vbase ctor iterator'");
311 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
312 "`virtual displacement map'");
313 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
314 "`eh vector ctor iterator'");
315 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
316 "`eh vector dtor iterator'");
317 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
318 "`eh vector vbase ctor iterator'");
319 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
320 "`copy ctor closure'");
321 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
322 "`local vftable ctor closure'");
323 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
324 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
325 "operator delete[]");
326 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
327 "`managed vector ctor iterator'");
328 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
329 "`managed vector dtor iterator'");
330 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
331 "`EH vector copy ctor iterator'");
332 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
333 "`EH vector vbase copy ctor iterator'");
334 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
335 "`vector copy ctor iterator'");
336 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
337 "`vector vbase copy constructor iterator'");
338 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
339 "`managed vector vbase copy constructor iterator'");
340 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
341 "operator co_await");
342 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
343 case IntrinsicFunctionKind::MaxIntrinsic:
344 case IntrinsicFunctionKind::None:
347 outputTemplateParameters(OS, Flags);
350 void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
351 OutputFlags Flags) const {
353 OS << "`local static thread guard'";
355 OS << "`local static guard'";
357 OS << "{" << ScopeIndex << "}";
360 void ConversionOperatorIdentifierNode::output(OutputStream &OS,
361 OutputFlags Flags) const {
363 outputTemplateParameters(OS, Flags);
365 TargetType->output(OS, Flags);
368 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
371 Class->output(OS, Flags);
372 outputTemplateParameters(OS, Flags);
375 void LiteralOperatorIdentifierNode::output(OutputStream &OS,
376 OutputFlags Flags) const {
377 OS << "operator \"\"" << Name;
378 outputTemplateParameters(OS, Flags);
381 void FunctionSignatureNode::outputPre(OutputStream &OS,
382 OutputFlags Flags) const {
383 if (FunctionClass & FC_Public)
385 if (FunctionClass & FC_Protected)
387 if (FunctionClass & FC_Private)
390 if (!(FunctionClass & FC_Global)) {
391 if (FunctionClass & FC_Static)
394 if (FunctionClass & FC_Virtual)
397 if (FunctionClass & FC_ExternC)
398 OS << "extern \"C\" ";
401 ReturnType->outputPre(OS, Flags);
405 if (!(Flags & OF_NoCallingConvention))
406 outputCallingConvention(OS, CallConvention);
409 void FunctionSignatureNode::outputPost(OutputStream &OS,
410 OutputFlags Flags) const {
411 if (!(FunctionClass & FC_NoParameterList)) {
414 Params->output(OS, Flags);
419 if (OS.back() != '(')
428 if (Quals & Q_Volatile)
430 if (Quals & Q_Restrict)
432 if (Quals & Q_Unaligned)
433 OS << " __unaligned";
438 if (RefQualifier == FunctionRefQualifier::Reference)
440 else if (RefQualifier == FunctionRefQualifier::RValueReference)
444 ReturnType->outputPost(OS, Flags);
447 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
450 FunctionSignatureNode::outputPre(OS, Flags);
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 << "}'";
462 OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
463 << ThisAdjust.StaticOffset << "}'";
467 FunctionSignatureNode::outputPost(OS, Flags);
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);
476 Sig->outputPre(OS, OF_NoCallingConvention);
478 Pointee->outputPre(OS, Flags);
480 outputSpaceIfNecessary(OS);
482 if (Quals & Q_Unaligned)
483 OS << "__unaligned ";
485 if (Pointee->kind() == NodeKind::ArrayType) {
487 } else if (Pointee->kind() == NodeKind::FunctionSignature) {
489 const FunctionSignatureNode *Sig =
490 static_cast<const FunctionSignatureNode *>(Pointee);
491 outputCallingConvention(OS, Sig->CallConvention);
496 ClassParent->output(OS, Flags);
501 case PointerAffinity::Pointer:
504 case PointerAffinity::Reference:
507 case PointerAffinity::RValueReference:
513 outputQualifiers(OS, Quals, false, false);
516 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
517 if (Pointee->kind() == NodeKind::ArrayType ||
518 Pointee->kind() == NodeKind::FunctionSignature)
521 Pointee->outputPost(OS, Flags);
524 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
525 if (!(Flags & OF_NoTagSpecifier)) {
527 OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
528 OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
529 OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
530 OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
534 QualifiedName->output(OS, Flags);
535 outputQualifiers(OS, Quals, true, false);
538 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
540 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
541 ElementType->outputPre(OS, Flags);
542 outputQualifiers(OS, Quals, true, false);
545 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
547 assert(N->kind() == NodeKind::IntegerLiteral);
548 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
550 ILN->output(OS, Flags);
553 void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
554 OutputFlags Flags) const {
555 if (Dimensions->Count == 0)
558 outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
559 for (size_t I = 1; I < Dimensions->Count; ++I) {
561 outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
565 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
567 outputDimensionsImpl(OS, Flags);
570 ElementType->outputPost(OS, Flags);
573 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
574 Name->output(OS, Flags);
577 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
578 Signature->outputPre(OS, Flags);
579 outputSpaceIfNecessary(OS);
580 Name->output(OS, Flags);
581 Signature->outputPost(OS, Flags);
584 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
586 case StorageClass::PrivateStatic:
587 OS << "private: static ";
589 case StorageClass::PublicStatic:
590 OS << "public: static ";
592 case StorageClass::ProtectedStatic:
593 OS << "protected: static ";
600 Type->outputPre(OS, Flags);
601 outputSpaceIfNecessary(OS);
603 Name->output(OS, Flags);
605 Type->outputPost(OS, Flags);
608 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
609 Identifier->output(OS, Flags);
611 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
613 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
614 Components->output(OS, Flags, "::");
617 void RttiBaseClassDescriptorNode::output(OutputStream &OS,
618 OutputFlags Flags) const {
619 OS << "`RTTI Base Class Descriptor at (";
620 OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
625 void LocalStaticGuardVariableNode::output(OutputStream &OS,
626 OutputFlags Flags) const {
627 Name->output(OS, Flags);
630 void VcallThunkIdentifierNode::output(OutputStream &OS,
631 OutputFlags Flags) const {
632 OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
635 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
636 outputQualifiers(OS, Quals, false, true);
637 Name->output(OS, Flags);
640 TargetName->output(OS, Flags);