Path: blob/main/contrib/llvm-project/llvm/lib/Demangle/MicrosoftDemangle.cpp
35232 views
//===- MicrosoftDemangle.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines a demangler for MSVC-style mangled symbols.9//10// This file has no dependencies on the rest of LLVM so that it can be11// easily reused in other programs such as libcxxabi.12//13//===----------------------------------------------------------------------===//1415#include "llvm/Demangle/MicrosoftDemangle.h"1617#include "llvm/Demangle/Demangle.h"18#include "llvm/Demangle/DemangleConfig.h"19#include "llvm/Demangle/MicrosoftDemangleNodes.h"20#include "llvm/Demangle/StringViewExtras.h"21#include "llvm/Demangle/Utility.h"2223#include <array>24#include <cctype>25#include <cstdio>26#include <optional>27#include <string_view>28#include <tuple>2930using namespace llvm;31using namespace ms_demangle;3233static bool startsWithDigit(std::string_view S) {34return !S.empty() && std::isdigit(S.front());35}3637struct NodeList {38Node *N = nullptr;39NodeList *Next = nullptr;40};4142static bool consumeFront(std::string_view &S, char C) {43if (!llvm::itanium_demangle::starts_with(S, C))44return false;45S.remove_prefix(1);46return true;47}4849static bool consumeFront(std::string_view &S, std::string_view C) {50if (!llvm::itanium_demangle::starts_with(S, C))51return false;52S.remove_prefix(C.size());53return true;54}5556static bool consumeFront(std::string_view &S, std::string_view PrefixA,57std::string_view PrefixB, bool A) {58const std::string_view &Prefix = A ? PrefixA : PrefixB;59return consumeFront(S, Prefix);60}6162static bool startsWith(std::string_view S, std::string_view PrefixA,63std::string_view PrefixB, bool A) {64const std::string_view &Prefix = A ? PrefixA : PrefixB;65return llvm::itanium_demangle::starts_with(S, Prefix);66}6768static bool isMemberPointer(std::string_view MangledName, bool &Error) {69Error = false;70const char F = MangledName.front();71MangledName.remove_prefix(1);72switch (F) {73case '$':74// This is probably an rvalue reference (e.g. $$Q), and you cannot have an75// rvalue reference to a member.76return false;77case 'A':78// 'A' indicates a reference, and you cannot have a reference to a member79// function or member.80return false;81case 'P':82case 'Q':83case 'R':84case 'S':85// These 4 values indicate some kind of pointer, but we still don't know86// what.87break;88default:89// isMemberPointer() is called only if isPointerType() returns true,90// and it rejects other prefixes.91DEMANGLE_UNREACHABLE;92}9394// If it starts with a number, then 6 indicates a non-member function95// pointer, and 8 indicates a member function pointer.96if (startsWithDigit(MangledName)) {97if (MangledName[0] != '6' && MangledName[0] != '8') {98Error = true;99return false;100}101return (MangledName[0] == '8');102}103104// Remove ext qualifiers since those can appear on either type and are105// therefore not indicative.106consumeFront(MangledName, 'E'); // 64-bit107consumeFront(MangledName, 'I'); // restrict108consumeFront(MangledName, 'F'); // unaligned109110if (MangledName.empty()) {111Error = true;112return false;113}114115// The next value should be either ABCD (non-member) or QRST (member).116switch (MangledName.front()) {117case 'A':118case 'B':119case 'C':120case 'D':121return false;122case 'Q':123case 'R':124case 'S':125case 'T':126return true;127default:128Error = true;129return false;130}131}132133static SpecialIntrinsicKind134consumeSpecialIntrinsicKind(std::string_view &MangledName) {135if (consumeFront(MangledName, "?_7"))136return SpecialIntrinsicKind::Vftable;137if (consumeFront(MangledName, "?_8"))138return SpecialIntrinsicKind::Vbtable;139if (consumeFront(MangledName, "?_9"))140return SpecialIntrinsicKind::VcallThunk;141if (consumeFront(MangledName, "?_A"))142return SpecialIntrinsicKind::Typeof;143if (consumeFront(MangledName, "?_B"))144return SpecialIntrinsicKind::LocalStaticGuard;145if (consumeFront(MangledName, "?_C"))146return SpecialIntrinsicKind::StringLiteralSymbol;147if (consumeFront(MangledName, "?_P"))148return SpecialIntrinsicKind::UdtReturning;149if (consumeFront(MangledName, "?_R0"))150return SpecialIntrinsicKind::RttiTypeDescriptor;151if (consumeFront(MangledName, "?_R1"))152return SpecialIntrinsicKind::RttiBaseClassDescriptor;153if (consumeFront(MangledName, "?_R2"))154return SpecialIntrinsicKind::RttiBaseClassArray;155if (consumeFront(MangledName, "?_R3"))156return SpecialIntrinsicKind::RttiClassHierarchyDescriptor;157if (consumeFront(MangledName, "?_R4"))158return SpecialIntrinsicKind::RttiCompleteObjLocator;159if (consumeFront(MangledName, "?_S"))160return SpecialIntrinsicKind::LocalVftable;161if (consumeFront(MangledName, "?__E"))162return SpecialIntrinsicKind::DynamicInitializer;163if (consumeFront(MangledName, "?__F"))164return SpecialIntrinsicKind::DynamicAtexitDestructor;165if (consumeFront(MangledName, "?__J"))166return SpecialIntrinsicKind::LocalStaticThreadGuard;167return SpecialIntrinsicKind::None;168}169170static bool startsWithLocalScopePattern(std::string_view S) {171if (!consumeFront(S, '?'))172return false;173174size_t End = S.find('?');175if (End == std::string_view::npos)176return false;177std::string_view Candidate = S.substr(0, End);178if (Candidate.empty())179return false;180181// \?[0-9]\?182// ?@? is the discriminator 0.183if (Candidate.size() == 1)184return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9');185186// If it's not 0-9, then it's an encoded number terminated with an @187if (Candidate.back() != '@')188return false;189Candidate.remove_suffix(1);190191// An encoded number starts with B-P and all subsequent digits are in A-P.192// Note that the reason the first digit cannot be A is two fold. First, it193// would create an ambiguity with ?A which delimits the beginning of an194// anonymous namespace. Second, A represents 0, and you don't start a multi195// digit number with a leading 0. Presumably the anonymous namespace196// ambiguity is also why single digit encoded numbers use 0-9 rather than A-J.197if (Candidate[0] < 'B' || Candidate[0] > 'P')198return false;199Candidate.remove_prefix(1);200while (!Candidate.empty()) {201if (Candidate[0] < 'A' || Candidate[0] > 'P')202return false;203Candidate.remove_prefix(1);204}205206return true;207}208209static bool isTagType(std::string_view S) {210switch (S.front()) {211case 'T': // union212case 'U': // struct213case 'V': // class214case 'W': // enum215return true;216}217return false;218}219220static bool isCustomType(std::string_view S) { return S[0] == '?'; }221222static bool isPointerType(std::string_view S) {223if (llvm::itanium_demangle::starts_with(S, "$$Q")) // foo &&224return true;225226switch (S.front()) {227case 'A': // foo &228case 'P': // foo *229case 'Q': // foo *const230case 'R': // foo *volatile231case 'S': // foo *const volatile232return true;233}234return false;235}236237static bool isArrayType(std::string_view S) { return S[0] == 'Y'; }238239static bool isFunctionType(std::string_view S) {240return llvm::itanium_demangle::starts_with(S, "$$A8@@") ||241llvm::itanium_demangle::starts_with(S, "$$A6");242}243244static FunctionRefQualifier245demangleFunctionRefQualifier(std::string_view &MangledName) {246if (consumeFront(MangledName, 'G'))247return FunctionRefQualifier::Reference;248else if (consumeFront(MangledName, 'H'))249return FunctionRefQualifier::RValueReference;250return FunctionRefQualifier::None;251}252253static std::pair<Qualifiers, PointerAffinity>254demanglePointerCVQualifiers(std::string_view &MangledName) {255if (consumeFront(MangledName, "$$Q"))256return std::make_pair(Q_None, PointerAffinity::RValueReference);257258const char F = MangledName.front();259MangledName.remove_prefix(1);260switch (F) {261case 'A':262return std::make_pair(Q_None, PointerAffinity::Reference);263case 'P':264return std::make_pair(Q_None, PointerAffinity::Pointer);265case 'Q':266return std::make_pair(Q_Const, PointerAffinity::Pointer);267case 'R':268return std::make_pair(Q_Volatile, PointerAffinity::Pointer);269case 'S':270return std::make_pair(Qualifiers(Q_Const | Q_Volatile),271PointerAffinity::Pointer);272}273// This function is only called if isPointerType() returns true,274// and it only returns true for the six cases listed above.275DEMANGLE_UNREACHABLE;276}277278std::string_view Demangler::copyString(std::string_view Borrowed) {279char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());280// This is not a micro-optimization, it avoids UB, should Borrowed be an null281// buffer.282if (Borrowed.size())283std::memcpy(Stable, Borrowed.data(), Borrowed.size());284285return {Stable, Borrowed.size()};286}287288SpecialTableSymbolNode *289Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,290SpecialIntrinsicKind K) {291NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();292switch (K) {293case SpecialIntrinsicKind::Vftable:294NI->Name = "`vftable'";295break;296case SpecialIntrinsicKind::Vbtable:297NI->Name = "`vbtable'";298break;299case SpecialIntrinsicKind::LocalVftable:300NI->Name = "`local vftable'";301break;302case SpecialIntrinsicKind::RttiCompleteObjLocator:303NI->Name = "`RTTI Complete Object Locator'";304break;305default:306DEMANGLE_UNREACHABLE;307}308QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);309SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();310STSN->Name = QN;311bool IsMember = false;312if (MangledName.empty()) {313Error = true;314return nullptr;315}316char Front = MangledName.front();317MangledName.remove_prefix(1);318if (Front != '6' && Front != '7') {319Error = true;320return nullptr;321}322323std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);324if (!consumeFront(MangledName, '@'))325STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);326return STSN;327}328329LocalStaticGuardVariableNode *330Demangler::demangleLocalStaticGuard(std::string_view &MangledName,331bool IsThread) {332LocalStaticGuardIdentifierNode *LSGI =333Arena.alloc<LocalStaticGuardIdentifierNode>();334LSGI->IsThread = IsThread;335QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);336LocalStaticGuardVariableNode *LSGVN =337Arena.alloc<LocalStaticGuardVariableNode>();338LSGVN->Name = QN;339340if (consumeFront(MangledName, "4IA"))341LSGVN->IsVisible = false;342else if (consumeFront(MangledName, "5"))343LSGVN->IsVisible = true;344else {345Error = true;346return nullptr;347}348349if (!MangledName.empty())350LSGI->ScopeIndex = demangleUnsigned(MangledName);351return LSGVN;352}353354static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,355std::string_view Name) {356NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();357Id->Name = Name;358return Id;359}360361static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,362IdentifierNode *Identifier) {363QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();364QN->Components = Arena.alloc<NodeArrayNode>();365QN->Components->Count = 1;366QN->Components->Nodes = Arena.allocArray<Node *>(1);367QN->Components->Nodes[0] = Identifier;368return QN;369}370371static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,372std::string_view Name) {373NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name);374return synthesizeQualifiedName(Arena, Id);375}376377static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,378TypeNode *Type,379std::string_view VariableName) {380VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();381VSN->Type = Type;382VSN->Name = synthesizeQualifiedName(Arena, VariableName);383return VSN;384}385386VariableSymbolNode *387Demangler::demangleUntypedVariable(ArenaAllocator &Arena,388std::string_view &MangledName,389std::string_view VariableName) {390NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName);391QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);392VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();393VSN->Name = QN;394if (consumeFront(MangledName, "8"))395return VSN;396397Error = true;398return nullptr;399}400401VariableSymbolNode *402Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,403std::string_view &MangledName) {404RttiBaseClassDescriptorNode *RBCDN =405Arena.alloc<RttiBaseClassDescriptorNode>();406RBCDN->NVOffset = demangleUnsigned(MangledName);407RBCDN->VBPtrOffset = demangleSigned(MangledName);408RBCDN->VBTableOffset = demangleUnsigned(MangledName);409RBCDN->Flags = demangleUnsigned(MangledName);410if (Error)411return nullptr;412413VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();414VSN->Name = demangleNameScopeChain(MangledName, RBCDN);415consumeFront(MangledName, '8');416return VSN;417}418419FunctionSymbolNode *420Demangler::demangleInitFiniStub(std::string_view &MangledName,421bool IsDestructor) {422DynamicStructorIdentifierNode *DSIN =423Arena.alloc<DynamicStructorIdentifierNode>();424DSIN->IsDestructor = IsDestructor;425426bool IsKnownStaticDataMember = false;427if (consumeFront(MangledName, '?'))428IsKnownStaticDataMember = true;429430SymbolNode *Symbol = demangleDeclarator(MangledName);431if (Error)432return nullptr;433434FunctionSymbolNode *FSN = nullptr;435436if (Symbol->kind() == NodeKind::VariableSymbol) {437DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol);438439// Older versions of clang mangled this type of symbol incorrectly. They440// would omit the leading ? and they would only emit a single @ at the end.441// The correct mangling is a leading ? and 2 trailing @ signs. Handle442// both cases.443int AtCount = IsKnownStaticDataMember ? 2 : 1;444for (int I = 0; I < AtCount; ++I) {445if (consumeFront(MangledName, '@'))446continue;447Error = true;448return nullptr;449}450451FSN = demangleFunctionEncoding(MangledName);452if (FSN)453FSN->Name = synthesizeQualifiedName(Arena, DSIN);454} else {455if (IsKnownStaticDataMember) {456// This was supposed to be a static data member, but we got a function.457Error = true;458return nullptr;459}460461FSN = static_cast<FunctionSymbolNode *>(Symbol);462DSIN->Name = Symbol->Name;463FSN->Name = synthesizeQualifiedName(Arena, DSIN);464}465466return FSN;467}468469SymbolNode *Demangler::demangleSpecialIntrinsic(std::string_view &MangledName) {470SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);471472switch (SIK) {473case SpecialIntrinsicKind::None:474return nullptr;475case SpecialIntrinsicKind::StringLiteralSymbol:476return demangleStringLiteral(MangledName);477case SpecialIntrinsicKind::Vftable:478case SpecialIntrinsicKind::Vbtable:479case SpecialIntrinsicKind::LocalVftable:480case SpecialIntrinsicKind::RttiCompleteObjLocator:481return demangleSpecialTableSymbolNode(MangledName, SIK);482case SpecialIntrinsicKind::VcallThunk:483return demangleVcallThunkNode(MangledName);484case SpecialIntrinsicKind::LocalStaticGuard:485return demangleLocalStaticGuard(MangledName, /*IsThread=*/false);486case SpecialIntrinsicKind::LocalStaticThreadGuard:487return demangleLocalStaticGuard(MangledName, /*IsThread=*/true);488case SpecialIntrinsicKind::RttiTypeDescriptor: {489TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);490if (Error)491break;492if (!consumeFront(MangledName, "@8"))493break;494if (!MangledName.empty())495break;496return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'");497}498case SpecialIntrinsicKind::RttiBaseClassArray:499return demangleUntypedVariable(Arena, MangledName,500"`RTTI Base Class Array'");501case SpecialIntrinsicKind::RttiClassHierarchyDescriptor:502return demangleUntypedVariable(Arena, MangledName,503"`RTTI Class Hierarchy Descriptor'");504case SpecialIntrinsicKind::RttiBaseClassDescriptor:505return demangleRttiBaseClassDescriptorNode(Arena, MangledName);506case SpecialIntrinsicKind::DynamicInitializer:507return demangleInitFiniStub(MangledName, /*IsDestructor=*/false);508case SpecialIntrinsicKind::DynamicAtexitDestructor:509return demangleInitFiniStub(MangledName, /*IsDestructor=*/true);510case SpecialIntrinsicKind::Typeof:511case SpecialIntrinsicKind::UdtReturning:512// It's unclear which tools produces these manglings, so demangling513// support is not (yet?) implemented.514break;515case SpecialIntrinsicKind::Unknown:516DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind.517}518Error = true;519return nullptr;520}521522IdentifierNode *523Demangler::demangleFunctionIdentifierCode(std::string_view &MangledName) {524assert(llvm::itanium_demangle::starts_with(MangledName, '?'));525MangledName.remove_prefix(1);526if (MangledName.empty()) {527Error = true;528return nullptr;529}530531if (consumeFront(MangledName, "__"))532return demangleFunctionIdentifierCode(533MangledName, FunctionIdentifierCodeGroup::DoubleUnder);534if (consumeFront(MangledName, "_"))535return demangleFunctionIdentifierCode(MangledName,536FunctionIdentifierCodeGroup::Under);537return demangleFunctionIdentifierCode(MangledName,538FunctionIdentifierCodeGroup::Basic);539}540541StructorIdentifierNode *542Demangler::demangleStructorIdentifier(std::string_view &MangledName,543bool IsDestructor) {544StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();545N->IsDestructor = IsDestructor;546return N;547}548549ConversionOperatorIdentifierNode *550Demangler::demangleConversionOperatorIdentifier(std::string_view &MangledName) {551ConversionOperatorIdentifierNode *N =552Arena.alloc<ConversionOperatorIdentifierNode>();553return N;554}555556LiteralOperatorIdentifierNode *557Demangler::demangleLiteralOperatorIdentifier(std::string_view &MangledName) {558LiteralOperatorIdentifierNode *N =559Arena.alloc<LiteralOperatorIdentifierNode>();560N->Name = demangleSimpleString(MangledName, /*Memorize=*/false);561return N;562}563564IntrinsicFunctionKind565Demangler::translateIntrinsicFunctionCode(char CH,566FunctionIdentifierCodeGroup Group) {567using IFK = IntrinsicFunctionKind;568if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) {569Error = true;570return IFK::None;571}572573// Not all ? identifiers are intrinsics *functions*. This function only maps574// operator codes for the special functions, all others are handled elsewhere,575// hence the IFK::None entries in the table.576static IFK Basic[36] = {577IFK::None, // ?0 # Foo::Foo()578IFK::None, // ?1 # Foo::~Foo()579IFK::New, // ?2 # operator new580IFK::Delete, // ?3 # operator delete581IFK::Assign, // ?4 # operator=582IFK::RightShift, // ?5 # operator>>583IFK::LeftShift, // ?6 # operator<<584IFK::LogicalNot, // ?7 # operator!585IFK::Equals, // ?8 # operator==586IFK::NotEquals, // ?9 # operator!=587IFK::ArraySubscript, // ?A # operator[]588IFK::None, // ?B # Foo::operator <type>()589IFK::Pointer, // ?C # operator->590IFK::Dereference, // ?D # operator*591IFK::Increment, // ?E # operator++592IFK::Decrement, // ?F # operator--593IFK::Minus, // ?G # operator-594IFK::Plus, // ?H # operator+595IFK::BitwiseAnd, // ?I # operator&596IFK::MemberPointer, // ?J # operator->*597IFK::Divide, // ?K # operator/598IFK::Modulus, // ?L # operator%599IFK::LessThan, // ?M operator<600IFK::LessThanEqual, // ?N operator<=601IFK::GreaterThan, // ?O operator>602IFK::GreaterThanEqual, // ?P operator>=603IFK::Comma, // ?Q operator,604IFK::Parens, // ?R operator()605IFK::BitwiseNot, // ?S operator~606IFK::BitwiseXor, // ?T operator^607IFK::BitwiseOr, // ?U operator|608IFK::LogicalAnd, // ?V operator&&609IFK::LogicalOr, // ?W operator||610IFK::TimesEqual, // ?X operator*=611IFK::PlusEqual, // ?Y operator+=612IFK::MinusEqual, // ?Z operator-=613};614static IFK Under[36] = {615IFK::DivEqual, // ?_0 operator/=616IFK::ModEqual, // ?_1 operator%=617IFK::RshEqual, // ?_2 operator>>=618IFK::LshEqual, // ?_3 operator<<=619IFK::BitwiseAndEqual, // ?_4 operator&=620IFK::BitwiseOrEqual, // ?_5 operator|=621IFK::BitwiseXorEqual, // ?_6 operator^=622IFK::None, // ?_7 # vftable623IFK::None, // ?_8 # vbtable624IFK::None, // ?_9 # vcall625IFK::None, // ?_A # typeof626IFK::None, // ?_B # local static guard627IFK::None, // ?_C # string literal628IFK::VbaseDtor, // ?_D # vbase destructor629IFK::VecDelDtor, // ?_E # vector deleting destructor630IFK::DefaultCtorClosure, // ?_F # default constructor closure631IFK::ScalarDelDtor, // ?_G # scalar deleting destructor632IFK::VecCtorIter, // ?_H # vector constructor iterator633IFK::VecDtorIter, // ?_I # vector destructor iterator634IFK::VecVbaseCtorIter, // ?_J # vector vbase constructor iterator635IFK::VdispMap, // ?_K # virtual displacement map636IFK::EHVecCtorIter, // ?_L # eh vector constructor iterator637IFK::EHVecDtorIter, // ?_M # eh vector destructor iterator638IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator639IFK::CopyCtorClosure, // ?_O # copy constructor closure640IFK::None, // ?_P<name> # udt returning <name>641IFK::None, // ?_Q # <unknown>642IFK::None, // ?_R0 - ?_R4 # RTTI Codes643IFK::None, // ?_S # local vftable644IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure645IFK::ArrayNew, // ?_U operator new[]646IFK::ArrayDelete, // ?_V operator delete[]647IFK::None, // ?_W <unused>648IFK::None, // ?_X <unused>649IFK::None, // ?_Y <unused>650IFK::None, // ?_Z <unused>651};652static IFK DoubleUnder[36] = {653IFK::None, // ?__0 <unused>654IFK::None, // ?__1 <unused>655IFK::None, // ?__2 <unused>656IFK::None, // ?__3 <unused>657IFK::None, // ?__4 <unused>658IFK::None, // ?__5 <unused>659IFK::None, // ?__6 <unused>660IFK::None, // ?__7 <unused>661IFK::None, // ?__8 <unused>662IFK::None, // ?__9 <unused>663IFK::ManVectorCtorIter, // ?__A managed vector ctor iterator664IFK::ManVectorDtorIter, // ?__B managed vector dtor iterator665IFK::EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator666IFK::EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iter667IFK::None, // ?__E dynamic initializer for `T'668IFK::None, // ?__F dynamic atexit destructor for `T'669IFK::VectorCopyCtorIter, // ?__G vector copy constructor iter670IFK::VectorVbaseCopyCtorIter, // ?__H vector vbase copy ctor iter671IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor672// iter673IFK::None, // ?__J local static thread guard674IFK::None, // ?__K operator ""_name675IFK::CoAwait, // ?__L operator co_await676IFK::Spaceship, // ?__M operator<=>677IFK::None, // ?__N <unused>678IFK::None, // ?__O <unused>679IFK::None, // ?__P <unused>680IFK::None, // ?__Q <unused>681IFK::None, // ?__R <unused>682IFK::None, // ?__S <unused>683IFK::None, // ?__T <unused>684IFK::None, // ?__U <unused>685IFK::None, // ?__V <unused>686IFK::None, // ?__W <unused>687IFK::None, // ?__X <unused>688IFK::None, // ?__Y <unused>689IFK::None, // ?__Z <unused>690};691692int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10);693switch (Group) {694case FunctionIdentifierCodeGroup::Basic:695return Basic[Index];696case FunctionIdentifierCodeGroup::Under:697return Under[Index];698case FunctionIdentifierCodeGroup::DoubleUnder:699return DoubleUnder[Index];700}701DEMANGLE_UNREACHABLE;702}703704IdentifierNode *705Demangler::demangleFunctionIdentifierCode(std::string_view &MangledName,706FunctionIdentifierCodeGroup Group) {707if (MangledName.empty()) {708Error = true;709return nullptr;710}711const char CH = MangledName.front();712switch (Group) {713case FunctionIdentifierCodeGroup::Basic:714MangledName.remove_prefix(1);715switch (CH) {716case '0':717case '1':718return demangleStructorIdentifier(MangledName, CH == '1');719case 'B':720return demangleConversionOperatorIdentifier(MangledName);721default:722return Arena.alloc<IntrinsicFunctionIdentifierNode>(723translateIntrinsicFunctionCode(CH, Group));724}725case FunctionIdentifierCodeGroup::Under:726MangledName.remove_prefix(1);727return Arena.alloc<IntrinsicFunctionIdentifierNode>(728translateIntrinsicFunctionCode(CH, Group));729case FunctionIdentifierCodeGroup::DoubleUnder:730MangledName.remove_prefix(1);731switch (CH) {732case 'K':733return demangleLiteralOperatorIdentifier(MangledName);734default:735return Arena.alloc<IntrinsicFunctionIdentifierNode>(736translateIntrinsicFunctionCode(CH, Group));737}738}739740DEMANGLE_UNREACHABLE;741}742743SymbolNode *Demangler::demangleEncodedSymbol(std::string_view &MangledName,744QualifiedNameNode *Name) {745if (MangledName.empty()) {746Error = true;747return nullptr;748}749750// Read a variable.751switch (MangledName.front()) {752case '0':753case '1':754case '2':755case '3':756case '4': {757StorageClass SC = demangleVariableStorageClass(MangledName);758return demangleVariableEncoding(MangledName, SC);759}760}761FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);762763IdentifierNode *UQN = Name->getUnqualifiedIdentifier();764if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {765ConversionOperatorIdentifierNode *COIN =766static_cast<ConversionOperatorIdentifierNode *>(UQN);767if (FSN)768COIN->TargetType = FSN->Signature->ReturnType;769}770return FSN;771}772773SymbolNode *Demangler::demangleDeclarator(std::string_view &MangledName) {774// What follows is a main symbol name. This may include namespaces or class775// back references.776QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);777if (Error)778return nullptr;779780SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);781if (Error)782return nullptr;783Symbol->Name = QN;784785IdentifierNode *UQN = QN->getUnqualifiedIdentifier();786if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {787ConversionOperatorIdentifierNode *COIN =788static_cast<ConversionOperatorIdentifierNode *>(UQN);789if (!COIN->TargetType) {790Error = true;791return nullptr;792}793}794return Symbol;795}796797SymbolNode *Demangler::demangleMD5Name(std::string_view &MangledName) {798assert(llvm::itanium_demangle::starts_with(MangledName, "??@"));799// This is an MD5 mangled name. We can't demangle it, just return the800// mangled name.801// An MD5 mangled name is ??@ followed by 32 characters and a terminating @.802size_t MD5Last = MangledName.find('@', strlen("??@"));803if (MD5Last == std::string_view::npos) {804Error = true;805return nullptr;806}807const char *Start = MangledName.data();808const size_t StartSize = MangledName.size();809MangledName.remove_prefix(MD5Last + 1);810811// There are two additional special cases for MD5 names:812// 1. For complete object locators where the object name is long enough813// for the object to have an MD5 name, the complete object locator is814// called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual815// leading "??_R4". This is handled here.816// 2. For catchable types, in versions of MSVC before 2015 (<1900) or after817// 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8818// instead of_CT??@...@8 with just one MD5 name. Since we don't yet819// demangle catchable types anywhere, this isn't handled for MD5 names820// either.821consumeFront(MangledName, "??_R4@");822823assert(MangledName.size() < StartSize);824const size_t Count = StartSize - MangledName.size();825std::string_view MD5(Start, Count);826SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);827S->Name = synthesizeQualifiedName(Arena, MD5);828829return S;830}831832SymbolNode *Demangler::demangleTypeinfoName(std::string_view &MangledName) {833assert(llvm::itanium_demangle::starts_with(MangledName, '.'));834consumeFront(MangledName, '.');835836TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);837if (Error || !MangledName.empty()) {838Error = true;839return nullptr;840}841return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'");842}843844// Parser entry point.845SymbolNode *Demangler::parse(std::string_view &MangledName) {846// Typeinfo names are strings stored in RTTI data. They're not symbol names.847// It's still useful to demangle them. They're the only demangled entity848// that doesn't start with a "?" but a ".".849if (llvm::itanium_demangle::starts_with(MangledName, '.'))850return demangleTypeinfoName(MangledName);851852if (llvm::itanium_demangle::starts_with(MangledName, "??@"))853return demangleMD5Name(MangledName);854855// MSVC-style mangled symbols must start with '?'.856if (!llvm::itanium_demangle::starts_with(MangledName, '?')) {857Error = true;858return nullptr;859}860861consumeFront(MangledName, '?');862863// ?$ is a template instantiation, but all other names that start with ? are864// operators / special names.865if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName))866return SI;867868return demangleDeclarator(MangledName);869}870871TagTypeNode *Demangler::parseTagUniqueName(std::string_view &MangledName) {872if (!consumeFront(MangledName, ".?A")) {873Error = true;874return nullptr;875}876consumeFront(MangledName, ".?A");877if (MangledName.empty()) {878Error = true;879return nullptr;880}881882return demangleClassType(MangledName);883}884885// <type-encoding> ::= <storage-class> <variable-type>886// <storage-class> ::= 0 # private static member887// ::= 1 # protected static member888// ::= 2 # public static member889// ::= 3 # global890// ::= 4 # static local891892VariableSymbolNode *893Demangler::demangleVariableEncoding(std::string_view &MangledName,894StorageClass SC) {895VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();896897VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);898VSN->SC = SC;899900if (Error)901return nullptr;902903// <variable-type> ::= <type> <cvr-qualifiers>904// ::= <type> <pointee-cvr-qualifiers> # pointers, references905switch (VSN->Type->kind()) {906case NodeKind::PointerType: {907PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type);908909Qualifiers ExtraChildQuals = Q_None;910PTN->Quals = Qualifiers(VSN->Type->Quals |911demanglePointerExtQualifiers(MangledName));912913bool IsMember = false;914std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);915916if (PTN->ClassParent) {917QualifiedNameNode *BackRefName =918demangleFullyQualifiedTypeName(MangledName);919(void)BackRefName;920}921PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals);922923break;924}925default:926VSN->Type->Quals = demangleQualifiers(MangledName).first;927break;928}929930return VSN;931}932933// Sometimes numbers are encoded in mangled symbols. For example,934// "int (*x)[20]" is a valid C type (x is a pointer to an array of935// length 20), so we need some way to embed numbers as part of symbols.936// This function parses it.937//938// <number> ::= [?] <non-negative integer>939//940// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10941// ::= <hex digit>+ @ # when Number == 0 or >= 10942//943// <hex-digit> ::= [A-P] # A = 0, B = 1, ...944std::pair<uint64_t, bool>945Demangler::demangleNumber(std::string_view &MangledName) {946bool IsNegative = consumeFront(MangledName, '?');947948if (startsWithDigit(MangledName)) {949uint64_t Ret = MangledName[0] - '0' + 1;950MangledName.remove_prefix(1);951return {Ret, IsNegative};952}953954uint64_t Ret = 0;955for (size_t i = 0; i < MangledName.size(); ++i) {956char C = MangledName[i];957if (C == '@') {958MangledName.remove_prefix(i + 1);959return {Ret, IsNegative};960}961if ('A' <= C && C <= 'P') {962Ret = (Ret << 4) + (C - 'A');963continue;964}965break;966}967968Error = true;969return {0ULL, false};970}971972uint64_t Demangler::demangleUnsigned(std::string_view &MangledName) {973bool IsNegative = false;974uint64_t Number = 0;975std::tie(Number, IsNegative) = demangleNumber(MangledName);976if (IsNegative)977Error = true;978return Number;979}980981int64_t Demangler::demangleSigned(std::string_view &MangledName) {982bool IsNegative = false;983uint64_t Number = 0;984std::tie(Number, IsNegative) = demangleNumber(MangledName);985if (Number > INT64_MAX)986Error = true;987int64_t I = static_cast<int64_t>(Number);988return IsNegative ? -I : I;989}990991// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.992// Memorize it.993void Demangler::memorizeString(std::string_view S) {994if (Backrefs.NamesCount >= BackrefContext::Max)995return;996for (size_t i = 0; i < Backrefs.NamesCount; ++i)997if (S == Backrefs.Names[i]->Name)998return;999NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>();1000N->Name = S;1001Backrefs.Names[Backrefs.NamesCount++] = N;1002}10031004NamedIdentifierNode *1005Demangler::demangleBackRefName(std::string_view &MangledName) {1006assert(startsWithDigit(MangledName));10071008size_t I = MangledName[0] - '0';1009if (I >= Backrefs.NamesCount) {1010Error = true;1011return nullptr;1012}10131014MangledName.remove_prefix(1);1015return Backrefs.Names[I];1016}10171018void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {1019// Render this class template name into a string buffer so that we can1020// memorize it for the purpose of back-referencing.1021OutputBuffer OB;1022Identifier->output(OB, OF_Default);1023std::string_view Owned = copyString(OB);1024memorizeString(Owned);1025std::free(OB.getBuffer());1026}10271028IdentifierNode *1029Demangler::demangleTemplateInstantiationName(std::string_view &MangledName,1030NameBackrefBehavior NBB) {1031assert(llvm::itanium_demangle::starts_with(MangledName, "?$"));1032consumeFront(MangledName, "?$");10331034BackrefContext OuterContext;1035std::swap(OuterContext, Backrefs);10361037IdentifierNode *Identifier =1038demangleUnqualifiedSymbolName(MangledName, NBB_Simple);1039if (!Error)1040Identifier->TemplateParams = demangleTemplateParameterList(MangledName);10411042std::swap(OuterContext, Backrefs);1043if (Error)1044return nullptr;10451046if (NBB & NBB_Template) {1047// NBB_Template is only set for types and non-leaf names ("a::" in "a::b").1048// Structors and conversion operators only makes sense in a leaf name, so1049// reject them in NBB_Template contexts.1050if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier ||1051Identifier->kind() == NodeKind::StructorIdentifier) {1052Error = true;1053return nullptr;1054}10551056memorizeIdentifier(Identifier);1057}10581059return Identifier;1060}10611062NamedIdentifierNode *1063Demangler::demangleSimpleName(std::string_view &MangledName, bool Memorize) {1064std::string_view S = demangleSimpleString(MangledName, Memorize);1065if (Error)1066return nullptr;10671068NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>();1069Name->Name = S;1070return Name;1071}10721073static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); }10741075static uint8_t rebasedHexDigitToNumber(char C) {1076assert(isRebasedHexDigit(C));1077return (C <= 'J') ? (C - 'A') : (10 + C - 'K');1078}10791080uint8_t Demangler::demangleCharLiteral(std::string_view &MangledName) {1081assert(!MangledName.empty());1082if (!llvm::itanium_demangle::starts_with(MangledName, '?')) {1083const uint8_t F = MangledName.front();1084MangledName.remove_prefix(1);1085return F;1086}10871088MangledName.remove_prefix(1);1089if (MangledName.empty())1090goto CharLiteralError;10911092if (consumeFront(MangledName, '$')) {1093// Two hex digits1094if (MangledName.size() < 2)1095goto CharLiteralError;1096std::string_view Nibbles = MangledName.substr(0, 2);1097if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1]))1098goto CharLiteralError;1099// Don't append the null terminator.1100uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]);1101uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]);1102MangledName.remove_prefix(2);1103return (C1 << 4) | C2;1104}11051106if (startsWithDigit(MangledName)) {1107const char *Lookup = ",/\\:. \n\t'-";1108char C = Lookup[MangledName[0] - '0'];1109MangledName.remove_prefix(1);1110return C;1111}11121113if (MangledName[0] >= 'a' && MangledName[0] <= 'z') {1114char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7',1115'\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE',1116'\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5',1117'\xF6', '\xF7', '\xF8', '\xF9', '\xFA'};1118char C = Lookup[MangledName[0] - 'a'];1119MangledName.remove_prefix(1);1120return C;1121}11221123if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') {1124char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7',1125'\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE',1126'\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5',1127'\xD6', '\xD7', '\xD8', '\xD9', '\xDA'};1128char C = Lookup[MangledName[0] - 'A'];1129MangledName.remove_prefix(1);1130return C;1131}11321133CharLiteralError:1134Error = true;1135return '\0';1136}11371138wchar_t Demangler::demangleWcharLiteral(std::string_view &MangledName) {1139uint8_t C1, C2;11401141C1 = demangleCharLiteral(MangledName);1142if (Error || MangledName.empty())1143goto WCharLiteralError;1144C2 = demangleCharLiteral(MangledName);1145if (Error)1146goto WCharLiteralError;11471148return ((wchar_t)C1 << 8) | (wchar_t)C2;11491150WCharLiteralError:1151Error = true;1152return L'\0';1153}11541155static void writeHexDigit(char *Buffer, uint8_t Digit) {1156assert(Digit <= 15);1157*Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);1158}11591160static void outputHex(OutputBuffer &OB, unsigned C) {1161assert (C != 0);11621163// It's easier to do the math if we can work from right to left, but we need1164// to print the numbers from left to right. So render this into a temporary1165// buffer first, then output the temporary buffer. Each byte is of the form1166// \xAB, which means that each byte needs 4 characters. Since there are at1167// most 4 bytes, we need a 4*4+1 = 17 character temporary buffer.1168char TempBuffer[17];11691170::memset(TempBuffer, 0, sizeof(TempBuffer));1171constexpr int MaxPos = sizeof(TempBuffer) - 1;11721173int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0.1174while (C != 0) {1175for (int I = 0; I < 2; ++I) {1176writeHexDigit(&TempBuffer[Pos--], C % 16);1177C /= 16;1178}1179}1180TempBuffer[Pos--] = 'x';1181assert(Pos >= 0);1182TempBuffer[Pos--] = '\\';1183OB << std::string_view(&TempBuffer[Pos + 1]);1184}11851186static void outputEscapedChar(OutputBuffer &OB, unsigned C) {1187switch (C) {1188case '\0': // nul1189OB << "\\0";1190return;1191case '\'': // single quote1192OB << "\\\'";1193return;1194case '\"': // double quote1195OB << "\\\"";1196return;1197case '\\': // backslash1198OB << "\\\\";1199return;1200case '\a': // bell1201OB << "\\a";1202return;1203case '\b': // backspace1204OB << "\\b";1205return;1206case '\f': // form feed1207OB << "\\f";1208return;1209case '\n': // new line1210OB << "\\n";1211return;1212case '\r': // carriage return1213OB << "\\r";1214return;1215case '\t': // tab1216OB << "\\t";1217return;1218case '\v': // vertical tab1219OB << "\\v";1220return;1221default:1222break;1223}12241225if (C > 0x1F && C < 0x7F) {1226// Standard ascii char.1227OB << (char)C;1228return;1229}12301231outputHex(OB, C);1232}12331234static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {1235const uint8_t *End = StringBytes + Length - 1;1236unsigned Count = 0;1237while (Length > 0 && *End == 0) {1238--Length;1239--End;1240++Count;1241}1242return Count;1243}12441245static unsigned countEmbeddedNulls(const uint8_t *StringBytes,1246unsigned Length) {1247unsigned Result = 0;1248for (unsigned I = 0; I < Length; ++I) {1249if (*StringBytes++ == 0)1250++Result;1251}1252return Result;1253}12541255// A mangled (non-wide) string literal stores the total length of the string it1256// refers to (passed in NumBytes), and it contains up to 32 bytes of actual text1257// (passed in StringBytes, NumChars).1258static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,1259uint64_t NumBytes) {1260assert(NumBytes > 0);12611262// If the number of bytes is odd, this is guaranteed to be a char string.1263if (NumBytes % 2 == 1)1264return 1;12651266// All strings can encode at most 32 bytes of data. If it's less than that,1267// then we encoded the entire string. In this case we check for a 1-byte,1268// 2-byte, or 4-byte null terminator.1269if (NumBytes < 32) {1270unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars);1271if (TrailingNulls >= 4 && NumBytes % 4 == 0)1272return 4;1273if (TrailingNulls >= 2)1274return 2;1275return 1;1276}12771278// The whole string was not able to be encoded. Try to look at embedded null1279// terminators to guess. The heuristic is that we count all embedded null1280// terminators. If more than 2/3 are null, it's a char32. If more than 1/31281// are null, it's a char16. Otherwise it's a char8. This obviously isn't1282// perfect and is biased towards languages that have ascii alphabets, but this1283// was always going to be best effort since the encoding is lossy.1284unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars);1285if (Nulls >= 2 * NumChars / 3 && NumBytes % 4 == 0)1286return 4;1287if (Nulls >= NumChars / 3)1288return 2;1289return 1;1290}12911292static unsigned decodeMultiByteChar(const uint8_t *StringBytes,1293unsigned CharIndex, unsigned CharBytes) {1294assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4);1295unsigned Offset = CharIndex * CharBytes;1296unsigned Result = 0;1297StringBytes = StringBytes + Offset;1298for (unsigned I = 0; I < CharBytes; ++I) {1299unsigned C = static_cast<unsigned>(StringBytes[I]);1300Result |= C << (8 * I);1301}1302return Result;1303}13041305FunctionSymbolNode *1306Demangler::demangleVcallThunkNode(std::string_view &MangledName) {1307FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>();1308VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>();1309FSN->Signature = Arena.alloc<ThunkSignatureNode>();1310FSN->Signature->FunctionClass = FC_NoParameterList;13111312FSN->Name = demangleNameScopeChain(MangledName, VTIN);1313if (!Error)1314Error = !consumeFront(MangledName, "$B");1315if (!Error)1316VTIN->OffsetInVTable = demangleUnsigned(MangledName);1317if (!Error)1318Error = !consumeFront(MangledName, 'A');1319if (!Error)1320FSN->Signature->CallConvention = demangleCallingConvention(MangledName);1321return (Error) ? nullptr : FSN;1322}13231324EncodedStringLiteralNode *1325Demangler::demangleStringLiteral(std::string_view &MangledName) {1326// This function uses goto, so declare all variables up front.1327OutputBuffer OB;1328std::string_view CRC;1329uint64_t StringByteSize;1330bool IsWcharT = false;1331bool IsNegative = false;1332size_t CrcEndPos = 0;1333char F;13341335EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();13361337// Prefix indicating the beginning of a string literal1338if (!consumeFront(MangledName, "@_"))1339goto StringLiteralError;1340if (MangledName.empty())1341goto StringLiteralError;13421343// Char Type (regular or wchar_t)1344F = MangledName.front();1345MangledName.remove_prefix(1);1346switch (F) {1347case '1':1348IsWcharT = true;1349DEMANGLE_FALLTHROUGH;1350case '0':1351break;1352default:1353goto StringLiteralError;1354}13551356// Encoded Length1357std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);1358if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1))1359goto StringLiteralError;13601361// CRC 32 (always 8 characters plus a terminator)1362CrcEndPos = MangledName.find('@');1363if (CrcEndPos == std::string_view::npos)1364goto StringLiteralError;1365CRC = MangledName.substr(0, CrcEndPos);1366MangledName.remove_prefix(CrcEndPos + 1);1367if (MangledName.empty())1368goto StringLiteralError;13691370if (IsWcharT) {1371Result->Char = CharKind::Wchar;1372if (StringByteSize > 64)1373Result->IsTruncated = true;13741375while (!consumeFront(MangledName, '@')) {1376if (MangledName.size() < 2)1377goto StringLiteralError;1378wchar_t W = demangleWcharLiteral(MangledName);1379if (StringByteSize != 2 || Result->IsTruncated)1380outputEscapedChar(OB, W);1381StringByteSize -= 2;1382if (Error)1383goto StringLiteralError;1384}1385} else {1386// The max byte length is actually 32, but some compilers mangled strings1387// incorrectly, so we have to assume it can go higher.1388constexpr unsigned MaxStringByteLength = 32 * 4;1389uint8_t StringBytes[MaxStringByteLength];13901391unsigned BytesDecoded = 0;1392while (!consumeFront(MangledName, '@')) {1393if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength)1394goto StringLiteralError;1395StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName);1396}13971398if (StringByteSize > BytesDecoded)1399Result->IsTruncated = true;14001401unsigned CharBytes =1402guessCharByteSize(StringBytes, BytesDecoded, StringByteSize);1403assert(StringByteSize % CharBytes == 0);1404switch (CharBytes) {1405case 1:1406Result->Char = CharKind::Char;1407break;1408case 2:1409Result->Char = CharKind::Char16;1410break;1411case 4:1412Result->Char = CharKind::Char32;1413break;1414default:1415DEMANGLE_UNREACHABLE;1416}1417const unsigned NumChars = BytesDecoded / CharBytes;1418for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {1419unsigned NextChar =1420decodeMultiByteChar(StringBytes, CharIndex, CharBytes);1421if (CharIndex + 1 < NumChars || Result->IsTruncated)1422outputEscapedChar(OB, NextChar);1423}1424}14251426Result->DecodedString = copyString(OB);1427std::free(OB.getBuffer());1428return Result;14291430StringLiteralError:1431Error = true;1432std::free(OB.getBuffer());1433return nullptr;1434}14351436// Returns MangledName's prefix before the first '@', or an error if1437// MangledName contains no '@' or the prefix has length 0.1438std::string_view Demangler::demangleSimpleString(std::string_view &MangledName,1439bool Memorize) {1440std::string_view S;1441for (size_t i = 0; i < MangledName.size(); ++i) {1442if (MangledName[i] != '@')1443continue;1444if (i == 0)1445break;1446S = MangledName.substr(0, i);1447MangledName.remove_prefix(i + 1);14481449if (Memorize)1450memorizeString(S);1451return S;1452}14531454Error = true;1455return {};1456}14571458NamedIdentifierNode *1459Demangler::demangleAnonymousNamespaceName(std::string_view &MangledName) {1460assert(llvm::itanium_demangle::starts_with(MangledName, "?A"));1461consumeFront(MangledName, "?A");14621463NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>();1464Node->Name = "`anonymous namespace'";1465size_t EndPos = MangledName.find('@');1466if (EndPos == std::string_view::npos) {1467Error = true;1468return nullptr;1469}1470std::string_view NamespaceKey = MangledName.substr(0, EndPos);1471memorizeString(NamespaceKey);1472MangledName = MangledName.substr(EndPos + 1);1473return Node;1474}14751476NamedIdentifierNode *1477Demangler::demangleLocallyScopedNamePiece(std::string_view &MangledName) {1478assert(startsWithLocalScopePattern(MangledName));14791480NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>();1481consumeFront(MangledName, '?');1482uint64_t Number = 0;1483bool IsNegative = false;1484std::tie(Number, IsNegative) = demangleNumber(MangledName);1485assert(!IsNegative);14861487// One ? to terminate the number1488consumeFront(MangledName, '?');14891490assert(!Error);1491Node *Scope = parse(MangledName);1492if (Error)1493return nullptr;14941495// Render the parent symbol's name into a buffer.1496OutputBuffer OB;1497OB << '`';1498Scope->output(OB, OF_Default);1499OB << '\'';1500OB << "::`" << Number << "'";15011502Identifier->Name = copyString(OB);1503std::free(OB.getBuffer());1504return Identifier;1505}15061507// Parses a type name in the form of A@B@C@@ which represents C::B::A.1508QualifiedNameNode *1509Demangler::demangleFullyQualifiedTypeName(std::string_view &MangledName) {1510IdentifierNode *Identifier =1511demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);1512if (Error)1513return nullptr;1514assert(Identifier);15151516QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);1517if (Error)1518return nullptr;1519assert(QN);1520return QN;1521}15221523// Parses a symbol name in the form of A@B@C@@ which represents C::B::A.1524// Symbol names have slightly different rules regarding what can appear1525// so we separate out the implementations for flexibility.1526QualifiedNameNode *1527Demangler::demangleFullyQualifiedSymbolName(std::string_view &MangledName) {1528// This is the final component of a symbol name (i.e. the leftmost component1529// of a mangled name. Since the only possible template instantiation that1530// can appear in this context is a function template, and since those are1531// not saved for the purposes of name backreferences, only backref simple1532// names.1533IdentifierNode *Identifier =1534demangleUnqualifiedSymbolName(MangledName, NBB_Simple);1535if (Error)1536return nullptr;15371538QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);1539if (Error)1540return nullptr;15411542if (Identifier->kind() == NodeKind::StructorIdentifier) {1543if (QN->Components->Count < 2) {1544Error = true;1545return nullptr;1546}1547StructorIdentifierNode *SIN =1548static_cast<StructorIdentifierNode *>(Identifier);1549Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2];1550SIN->Class = static_cast<IdentifierNode *>(ClassNode);1551}1552assert(QN);1553return QN;1554}15551556IdentifierNode *1557Demangler::demangleUnqualifiedTypeName(std::string_view &MangledName,1558bool Memorize) {1559// An inner-most name can be a back-reference, because a fully-qualified name1560// (e.g. Scope + Inner) can contain other fully qualified names inside of1561// them (for example template parameters), and these nested parameters can1562// refer to previously mangled types.1563if (startsWithDigit(MangledName))1564return demangleBackRefName(MangledName);15651566if (llvm::itanium_demangle::starts_with(MangledName, "?$"))1567return demangleTemplateInstantiationName(MangledName, NBB_Template);15681569return demangleSimpleName(MangledName, Memorize);1570}15711572IdentifierNode *1573Demangler::demangleUnqualifiedSymbolName(std::string_view &MangledName,1574NameBackrefBehavior NBB) {1575if (startsWithDigit(MangledName))1576return demangleBackRefName(MangledName);1577if (llvm::itanium_demangle::starts_with(MangledName, "?$"))1578return demangleTemplateInstantiationName(MangledName, NBB);1579if (llvm::itanium_demangle::starts_with(MangledName, '?'))1580return demangleFunctionIdentifierCode(MangledName);1581return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0);1582}15831584IdentifierNode *1585Demangler::demangleNameScopePiece(std::string_view &MangledName) {1586if (startsWithDigit(MangledName))1587return demangleBackRefName(MangledName);15881589if (llvm::itanium_demangle::starts_with(MangledName, "?$"))1590return demangleTemplateInstantiationName(MangledName, NBB_Template);15911592if (llvm::itanium_demangle::starts_with(MangledName, "?A"))1593return demangleAnonymousNamespaceName(MangledName);15941595if (startsWithLocalScopePattern(MangledName))1596return demangleLocallyScopedNamePiece(MangledName);15971598return demangleSimpleName(MangledName, /*Memorize=*/true);1599}16001601static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,1602size_t Count) {1603NodeArrayNode *N = Arena.alloc<NodeArrayNode>();1604N->Count = Count;1605N->Nodes = Arena.allocArray<Node *>(Count);1606for (size_t I = 0; I < Count; ++I) {1607N->Nodes[I] = Head->N;1608Head = Head->Next;1609}1610return N;1611}16121613QualifiedNameNode *1614Demangler::demangleNameScopeChain(std::string_view &MangledName,1615IdentifierNode *UnqualifiedName) {1616NodeList *Head = Arena.alloc<NodeList>();16171618Head->N = UnqualifiedName;16191620size_t Count = 1;1621while (!consumeFront(MangledName, "@")) {1622++Count;1623NodeList *NewHead = Arena.alloc<NodeList>();1624NewHead->Next = Head;1625Head = NewHead;16261627if (MangledName.empty()) {1628Error = true;1629return nullptr;1630}16311632assert(!Error);1633IdentifierNode *Elem = demangleNameScopePiece(MangledName);1634if (Error)1635return nullptr;16361637Head->N = Elem;1638}16391640QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();1641QN->Components = nodeListToNodeArray(Arena, Head, Count);1642return QN;1643}16441645FuncClass Demangler::demangleFunctionClass(std::string_view &MangledName) {1646const char F = MangledName.front();1647MangledName.remove_prefix(1);1648switch (F) {1649case '9':1650return FuncClass(FC_ExternC | FC_NoParameterList);1651case 'A':1652return FC_Private;1653case 'B':1654return FuncClass(FC_Private | FC_Far);1655case 'C':1656return FuncClass(FC_Private | FC_Static);1657case 'D':1658return FuncClass(FC_Private | FC_Static | FC_Far);1659case 'E':1660return FuncClass(FC_Private | FC_Virtual);1661case 'F':1662return FuncClass(FC_Private | FC_Virtual | FC_Far);1663case 'G':1664return FuncClass(FC_Private | FC_StaticThisAdjust);1665case 'H':1666return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far);1667case 'I':1668return FuncClass(FC_Protected);1669case 'J':1670return FuncClass(FC_Protected | FC_Far);1671case 'K':1672return FuncClass(FC_Protected | FC_Static);1673case 'L':1674return FuncClass(FC_Protected | FC_Static | FC_Far);1675case 'M':1676return FuncClass(FC_Protected | FC_Virtual);1677case 'N':1678return FuncClass(FC_Protected | FC_Virtual | FC_Far);1679case 'O':1680return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust);1681case 'P':1682return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far);1683case 'Q':1684return FuncClass(FC_Public);1685case 'R':1686return FuncClass(FC_Public | FC_Far);1687case 'S':1688return FuncClass(FC_Public | FC_Static);1689case 'T':1690return FuncClass(FC_Public | FC_Static | FC_Far);1691case 'U':1692return FuncClass(FC_Public | FC_Virtual);1693case 'V':1694return FuncClass(FC_Public | FC_Virtual | FC_Far);1695case 'W':1696return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust);1697case 'X':1698return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far);1699case 'Y':1700return FuncClass(FC_Global);1701case 'Z':1702return FuncClass(FC_Global | FC_Far);1703case '$': {1704FuncClass VFlag = FC_VirtualThisAdjust;1705if (consumeFront(MangledName, 'R'))1706VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx);1707if (MangledName.empty())1708break;1709const char F = MangledName.front();1710MangledName.remove_prefix(1);1711switch (F) {1712case '0':1713return FuncClass(FC_Private | FC_Virtual | VFlag);1714case '1':1715return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far);1716case '2':1717return FuncClass(FC_Protected | FC_Virtual | VFlag);1718case '3':1719return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far);1720case '4':1721return FuncClass(FC_Public | FC_Virtual | VFlag);1722case '5':1723return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far);1724}1725}1726}17271728Error = true;1729return FC_Public;1730}17311732CallingConv1733Demangler::demangleCallingConvention(std::string_view &MangledName) {1734if (MangledName.empty()) {1735Error = true;1736return CallingConv::None;1737}17381739const char F = MangledName.front();1740MangledName.remove_prefix(1);1741switch (F) {1742case 'A':1743case 'B':1744return CallingConv::Cdecl;1745case 'C':1746case 'D':1747return CallingConv::Pascal;1748case 'E':1749case 'F':1750return CallingConv::Thiscall;1751case 'G':1752case 'H':1753return CallingConv::Stdcall;1754case 'I':1755case 'J':1756return CallingConv::Fastcall;1757case 'M':1758case 'N':1759return CallingConv::Clrcall;1760case 'O':1761case 'P':1762return CallingConv::Eabi;1763case 'Q':1764return CallingConv::Vectorcall;1765case 'S':1766return CallingConv::Swift;1767case 'W':1768return CallingConv::SwiftAsync;1769}17701771return CallingConv::None;1772}17731774StorageClass1775Demangler::demangleVariableStorageClass(std::string_view &MangledName) {1776assert(MangledName.front() >= '0' && MangledName.front() <= '4');17771778const char F = MangledName.front();1779MangledName.remove_prefix(1);1780switch (F) {1781case '0':1782return StorageClass::PrivateStatic;1783case '1':1784return StorageClass::ProtectedStatic;1785case '2':1786return StorageClass::PublicStatic;1787case '3':1788return StorageClass::Global;1789case '4':1790return StorageClass::FunctionLocalStatic;1791}1792DEMANGLE_UNREACHABLE;1793}17941795std::pair<Qualifiers, bool>1796Demangler::demangleQualifiers(std::string_view &MangledName) {1797if (MangledName.empty()) {1798Error = true;1799return std::make_pair(Q_None, false);1800}18011802const char F = MangledName.front();1803MangledName.remove_prefix(1);1804switch (F) {1805// Member qualifiers1806case 'Q':1807return std::make_pair(Q_None, true);1808case 'R':1809return std::make_pair(Q_Const, true);1810case 'S':1811return std::make_pair(Q_Volatile, true);1812case 'T':1813return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);1814// Non-Member qualifiers1815case 'A':1816return std::make_pair(Q_None, false);1817case 'B':1818return std::make_pair(Q_Const, false);1819case 'C':1820return std::make_pair(Q_Volatile, false);1821case 'D':1822return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);1823}1824Error = true;1825return std::make_pair(Q_None, false);1826}18271828// <variable-type> ::= <type> <cvr-qualifiers>1829// ::= <type> <pointee-cvr-qualifiers> # pointers, references1830TypeNode *Demangler::demangleType(std::string_view &MangledName,1831QualifierMangleMode QMM) {1832Qualifiers Quals = Q_None;1833bool IsMember = false;1834if (QMM == QualifierMangleMode::Mangle) {1835std::tie(Quals, IsMember) = demangleQualifiers(MangledName);1836} else if (QMM == QualifierMangleMode::Result) {1837if (consumeFront(MangledName, '?'))1838std::tie(Quals, IsMember) = demangleQualifiers(MangledName);1839}18401841if (MangledName.empty()) {1842Error = true;1843return nullptr;1844}18451846TypeNode *Ty = nullptr;1847if (isTagType(MangledName))1848Ty = demangleClassType(MangledName);1849else if (isPointerType(MangledName)) {1850if (isMemberPointer(MangledName, Error))1851Ty = demangleMemberPointerType(MangledName);1852else if (!Error)1853Ty = demanglePointerType(MangledName);1854else1855return nullptr;1856} else if (isArrayType(MangledName))1857Ty = demangleArrayType(MangledName);1858else if (isFunctionType(MangledName)) {1859if (consumeFront(MangledName, "$$A8@@"))1860Ty = demangleFunctionType(MangledName, true);1861else {1862assert(llvm::itanium_demangle::starts_with(MangledName, "$$A6"));1863consumeFront(MangledName, "$$A6");1864Ty = demangleFunctionType(MangledName, false);1865}1866} else if (isCustomType(MangledName)) {1867Ty = demangleCustomType(MangledName);1868} else {1869Ty = demanglePrimitiveType(MangledName);1870}18711872if (!Ty || Error)1873return Ty;1874Ty->Quals = Qualifiers(Ty->Quals | Quals);1875return Ty;1876}18771878bool Demangler::demangleThrowSpecification(std::string_view &MangledName) {1879if (consumeFront(MangledName, "_E"))1880return true;1881if (consumeFront(MangledName, 'Z'))1882return false;18831884Error = true;1885return false;1886}18871888FunctionSignatureNode *1889Demangler::demangleFunctionType(std::string_view &MangledName,1890bool HasThisQuals) {1891FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>();18921893if (HasThisQuals) {1894FTy->Quals = demanglePointerExtQualifiers(MangledName);1895FTy->RefQualifier = demangleFunctionRefQualifier(MangledName);1896FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);1897}18981899// Fields that appear on both member and non-member functions.1900FTy->CallConvention = demangleCallingConvention(MangledName);19011902// <return-type> ::= <type>1903// ::= @ # structors (they have no declared return type)1904bool IsStructor = consumeFront(MangledName, '@');1905if (!IsStructor)1906FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);19071908FTy->Params = demangleFunctionParameterList(MangledName, FTy->IsVariadic);19091910FTy->IsNoexcept = demangleThrowSpecification(MangledName);19111912return FTy;1913}19141915FunctionSymbolNode *1916Demangler::demangleFunctionEncoding(std::string_view &MangledName) {1917FuncClass ExtraFlags = FC_None;1918if (consumeFront(MangledName, "$$J0"))1919ExtraFlags = FC_ExternC;19201921if (MangledName.empty()) {1922Error = true;1923return nullptr;1924}19251926FuncClass FC = demangleFunctionClass(MangledName);1927FC = FuncClass(ExtraFlags | FC);19281929FunctionSignatureNode *FSN = nullptr;1930ThunkSignatureNode *TTN = nullptr;1931if (FC & FC_StaticThisAdjust) {1932TTN = Arena.alloc<ThunkSignatureNode>();1933TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);1934} else if (FC & FC_VirtualThisAdjust) {1935TTN = Arena.alloc<ThunkSignatureNode>();1936if (FC & FC_VirtualThisAdjustEx) {1937TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName);1938TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName);1939}1940TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName);1941TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);1942}19431944if (FC & FC_NoParameterList) {1945// This is an extern "C" function whose full signature hasn't been mangled.1946// This happens when we need to mangle a local symbol inside of an extern1947// "C" function.1948FSN = Arena.alloc<FunctionSignatureNode>();1949} else {1950bool HasThisQuals = !(FC & (FC_Global | FC_Static));1951FSN = demangleFunctionType(MangledName, HasThisQuals);1952}19531954if (Error)1955return nullptr;19561957if (TTN) {1958*static_cast<FunctionSignatureNode *>(TTN) = *FSN;1959FSN = TTN;1960}1961FSN->FunctionClass = FC;19621963FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>();1964Symbol->Signature = FSN;1965return Symbol;1966}19671968CustomTypeNode *Demangler::demangleCustomType(std::string_view &MangledName) {1969assert(llvm::itanium_demangle::starts_with(MangledName, '?'));1970MangledName.remove_prefix(1);19711972CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();1973CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);1974if (!consumeFront(MangledName, '@'))1975Error = true;1976if (Error)1977return nullptr;1978return CTN;1979}19801981// Reads a primitive type.1982PrimitiveTypeNode *1983Demangler::demanglePrimitiveType(std::string_view &MangledName) {1984if (consumeFront(MangledName, "$$T"))1985return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr);19861987const char F = MangledName.front();1988MangledName.remove_prefix(1);1989switch (F) {1990case 'X':1991return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void);1992case 'D':1993return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char);1994case 'C':1995return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar);1996case 'E':1997return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar);1998case 'F':1999return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short);2000case 'G':2001return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort);2002case 'H':2003return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int);2004case 'I':2005return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint);2006case 'J':2007return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long);2008case 'K':2009return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong);2010case 'M':2011return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float);2012case 'N':2013return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double);2014case 'O':2015return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble);2016case '_': {2017if (MangledName.empty()) {2018Error = true;2019return nullptr;2020}2021const char F = MangledName.front();2022MangledName.remove_prefix(1);2023switch (F) {2024case 'N':2025return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool);2026case 'J':2027return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64);2028case 'K':2029return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64);2030case 'W':2031return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar);2032case 'Q':2033return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char8);2034case 'S':2035return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16);2036case 'U':2037return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32);2038}2039break;2040}2041}2042Error = true;2043return nullptr;2044}20452046TagTypeNode *Demangler::demangleClassType(std::string_view &MangledName) {2047TagTypeNode *TT = nullptr;20482049const char F = MangledName.front();2050MangledName.remove_prefix(1);2051switch (F) {2052case 'T':2053TT = Arena.alloc<TagTypeNode>(TagKind::Union);2054break;2055case 'U':2056TT = Arena.alloc<TagTypeNode>(TagKind::Struct);2057break;2058case 'V':2059TT = Arena.alloc<TagTypeNode>(TagKind::Class);2060break;2061case 'W':2062if (!consumeFront(MangledName, '4')) {2063Error = true;2064return nullptr;2065}2066TT = Arena.alloc<TagTypeNode>(TagKind::Enum);2067break;2068default:2069assert(false);2070}20712072TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName);2073return TT;2074}20752076// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>2077// # the E is required for 64-bit non-static pointers2078PointerTypeNode *Demangler::demanglePointerType(std::string_view &MangledName) {2079PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();20802081std::tie(Pointer->Quals, Pointer->Affinity) =2082demanglePointerCVQualifiers(MangledName);20832084if (consumeFront(MangledName, "6")) {2085Pointer->Pointee = demangleFunctionType(MangledName, false);2086return Pointer;2087}20882089Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);2090Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);20912092Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);2093return Pointer;2094}20952096PointerTypeNode *2097Demangler::demangleMemberPointerType(std::string_view &MangledName) {2098PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();20992100std::tie(Pointer->Quals, Pointer->Affinity) =2101demanglePointerCVQualifiers(MangledName);2102assert(Pointer->Affinity == PointerAffinity::Pointer);21032104Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);2105Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);21062107// isMemberPointer() only returns true if there is at least one character2108// after the qualifiers.2109if (consumeFront(MangledName, "8")) {2110Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);2111Pointer->Pointee = demangleFunctionType(MangledName, true);2112} else {2113Qualifiers PointeeQuals = Q_None;2114bool IsMember = false;2115std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);2116assert(IsMember || Error);2117Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);21182119Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);2120if (Pointer->Pointee)2121Pointer->Pointee->Quals = PointeeQuals;2122}21232124return Pointer;2125}21262127Qualifiers2128Demangler::demanglePointerExtQualifiers(std::string_view &MangledName) {2129Qualifiers Quals = Q_None;2130if (consumeFront(MangledName, 'E'))2131Quals = Qualifiers(Quals | Q_Pointer64);2132if (consumeFront(MangledName, 'I'))2133Quals = Qualifiers(Quals | Q_Restrict);2134if (consumeFront(MangledName, 'F'))2135Quals = Qualifiers(Quals | Q_Unaligned);21362137return Quals;2138}21392140ArrayTypeNode *Demangler::demangleArrayType(std::string_view &MangledName) {2141assert(MangledName.front() == 'Y');2142MangledName.remove_prefix(1);21432144uint64_t Rank = 0;2145bool IsNegative = false;2146std::tie(Rank, IsNegative) = demangleNumber(MangledName);2147if (IsNegative || Rank == 0) {2148Error = true;2149return nullptr;2150}21512152ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>();2153NodeList *Head = Arena.alloc<NodeList>();2154NodeList *Tail = Head;21552156for (uint64_t I = 0; I < Rank; ++I) {2157uint64_t D = 0;2158std::tie(D, IsNegative) = demangleNumber(MangledName);2159if (Error || IsNegative) {2160Error = true;2161return nullptr;2162}2163Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative);2164if (I + 1 < Rank) {2165Tail->Next = Arena.alloc<NodeList>();2166Tail = Tail->Next;2167}2168}2169ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank);21702171if (consumeFront(MangledName, "$$C")) {2172bool IsMember = false;2173std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName);2174if (IsMember) {2175Error = true;2176return nullptr;2177}2178}21792180ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);2181return ATy;2182}21832184// Reads a function's parameters.2185NodeArrayNode *2186Demangler::demangleFunctionParameterList(std::string_view &MangledName,2187bool &IsVariadic) {2188// Empty parameter list.2189if (consumeFront(MangledName, 'X'))2190return nullptr;21912192NodeList *Head = Arena.alloc<NodeList>();2193NodeList **Current = &Head;2194size_t Count = 0;2195while (!Error && !llvm::itanium_demangle::starts_with(MangledName, '@') &&2196!llvm::itanium_demangle::starts_with(MangledName, 'Z')) {2197++Count;21982199if (startsWithDigit(MangledName)) {2200size_t N = MangledName[0] - '0';2201if (N >= Backrefs.FunctionParamCount) {2202Error = true;2203return nullptr;2204}2205MangledName.remove_prefix(1);22062207*Current = Arena.alloc<NodeList>();2208(*Current)->N = Backrefs.FunctionParams[N];2209Current = &(*Current)->Next;2210continue;2211}22122213size_t OldSize = MangledName.size();22142215*Current = Arena.alloc<NodeList>();2216TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop);2217if (!TN || Error)2218return nullptr;22192220(*Current)->N = TN;22212222size_t CharsConsumed = OldSize - MangledName.size();2223assert(CharsConsumed != 0);22242225// Single-letter types are ignored for backreferences because memorizing2226// them doesn't save anything.2227if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1)2228Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN;22292230Current = &(*Current)->Next;2231}22322233if (Error)2234return nullptr;22352236NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count);2237// A non-empty parameter list is terminated by either 'Z' (variadic) parameter2238// list or '@' (non variadic). Careful not to consume "@Z", as in that case2239// the following Z could be a throw specifier.2240if (consumeFront(MangledName, '@'))2241return NA;22422243if (consumeFront(MangledName, 'Z')) {2244IsVariadic = true;2245return NA;2246}22472248DEMANGLE_UNREACHABLE;2249}22502251NodeArrayNode *2252Demangler::demangleTemplateParameterList(std::string_view &MangledName) {2253NodeList *Head = nullptr;2254NodeList **Current = &Head;2255size_t Count = 0;22562257while (!llvm::itanium_demangle::starts_with(MangledName, '@')) {2258if (consumeFront(MangledName, "$S") || consumeFront(MangledName, "$$V") ||2259consumeFront(MangledName, "$$$V") || consumeFront(MangledName, "$$Z")) {2260// parameter pack separator2261continue;2262}22632264++Count;22652266// Template parameter lists don't participate in back-referencing.2267*Current = Arena.alloc<NodeList>();22682269NodeList &TP = **Current;22702271// <auto-nttp> ::= $ M <type> <nttp>2272const bool IsAutoNTTP = consumeFront(MangledName, "$M");2273if (IsAutoNTTP) {2274// The deduced type of the auto NTTP parameter isn't printed so2275// we want to ignore the AST created from demangling the type.2276//2277// TODO: Avoid the extra allocations to the bump allocator in this case.2278(void)demangleType(MangledName, QualifierMangleMode::Drop);2279if (Error)2280return nullptr;2281}22822283TemplateParameterReferenceNode *TPRN = nullptr;2284if (consumeFront(MangledName, "$$Y")) {2285// Template alias2286TP.N = demangleFullyQualifiedTypeName(MangledName);2287} else if (consumeFront(MangledName, "$$B")) {2288// Array2289TP.N = demangleType(MangledName, QualifierMangleMode::Drop);2290} else if (consumeFront(MangledName, "$$C")) {2291// Type has qualifiers.2292TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);2293} else if (startsWith(MangledName, "$1", "1", !IsAutoNTTP) ||2294startsWith(MangledName, "$H", "H", !IsAutoNTTP) ||2295startsWith(MangledName, "$I", "I", !IsAutoNTTP) ||2296startsWith(MangledName, "$J", "J", !IsAutoNTTP)) {2297// Pointer to member2298TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();2299TPRN->IsMemberPointer = true;23002301if (!IsAutoNTTP)2302MangledName.remove_prefix(1); // Remove leading '$'23032304// 1 - single inheritance <name>2305// H - multiple inheritance <name> <number>2306// I - virtual inheritance <name> <number> <number>2307// J - unspecified inheritance <name> <number> <number> <number>2308char InheritanceSpecifier = MangledName.front();2309MangledName.remove_prefix(1);2310SymbolNode *S = nullptr;2311if (llvm::itanium_demangle::starts_with(MangledName, '?')) {2312S = parse(MangledName);2313if (Error || !S->Name) {2314Error = true;2315return nullptr;2316}2317memorizeIdentifier(S->Name->getUnqualifiedIdentifier());2318}23192320switch (InheritanceSpecifier) {2321case 'J':2322TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2323demangleSigned(MangledName);2324DEMANGLE_FALLTHROUGH;2325case 'I':2326TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2327demangleSigned(MangledName);2328DEMANGLE_FALLTHROUGH;2329case 'H':2330TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2331demangleSigned(MangledName);2332DEMANGLE_FALLTHROUGH;2333case '1':2334break;2335default:2336DEMANGLE_UNREACHABLE;2337}2338TPRN->Affinity = PointerAffinity::Pointer;2339TPRN->Symbol = S;2340} else if (llvm::itanium_demangle::starts_with(MangledName, "$E?")) {2341consumeFront(MangledName, "$E");2342// Reference to symbol2343TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();2344TPRN->Symbol = parse(MangledName);2345TPRN->Affinity = PointerAffinity::Reference;2346} else if (startsWith(MangledName, "$F", "F", !IsAutoNTTP) ||2347startsWith(MangledName, "$G", "G", !IsAutoNTTP)) {2348TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();23492350// Data member pointer.2351if (!IsAutoNTTP)2352MangledName.remove_prefix(1); // Remove leading '$'2353char InheritanceSpecifier = MangledName.front();2354MangledName.remove_prefix(1);23552356switch (InheritanceSpecifier) {2357case 'G':2358TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2359demangleSigned(MangledName);2360DEMANGLE_FALLTHROUGH;2361case 'F':2362TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2363demangleSigned(MangledName);2364TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =2365demangleSigned(MangledName);2366break;2367default:2368DEMANGLE_UNREACHABLE;2369}2370TPRN->IsMemberPointer = true;23712372} else if (consumeFront(MangledName, "$0", "0", !IsAutoNTTP)) {2373// Integral non-type template parameter2374bool IsNegative = false;2375uint64_t Value = 0;2376std::tie(Value, IsNegative) = demangleNumber(MangledName);23772378TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative);2379} else {2380TP.N = demangleType(MangledName, QualifierMangleMode::Drop);2381}2382if (Error)2383return nullptr;23842385Current = &TP.Next;2386}23872388// The loop above returns nullptr on Error.2389assert(!Error);23902391// Template parameter lists cannot be variadic, so it can only be terminated2392// by @ (as opposed to 'Z' in the function parameter case).2393assert(llvm::itanium_demangle::starts_with(2394MangledName, '@')); // The above loop exits only on '@'.2395consumeFront(MangledName, '@');2396return nodeListToNodeArray(Arena, Head, Count);2397}23982399void Demangler::dumpBackReferences() {2400std::printf("%d function parameter backreferences\n",2401(int)Backrefs.FunctionParamCount);24022403// Create an output stream so we can render each type.2404OutputBuffer OB;2405for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {2406OB.setCurrentPosition(0);24072408TypeNode *T = Backrefs.FunctionParams[I];2409T->output(OB, OF_Default);24102411std::string_view B = OB;2412std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.data());2413}2414std::free(OB.getBuffer());24152416if (Backrefs.FunctionParamCount > 0)2417std::printf("\n");2418std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);2419for (size_t I = 0; I < Backrefs.NamesCount; ++I) {2420std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),2421Backrefs.Names[I]->Name.data());2422}2423if (Backrefs.NamesCount > 0)2424std::printf("\n");2425}24262427std::optional<size_t>2428llvm::getArm64ECInsertionPointInMangledName(std::string_view MangledName) {2429std::string_view ProcessedName{MangledName};24302431// We only support this for MSVC-style C++ symbols.2432if (!consumeFront(ProcessedName, '?'))2433return std::nullopt;24342435// The insertion point is just after the name of the symbol, so parse that to2436// remove it from the processed name.2437Demangler D;2438D.demangleFullyQualifiedSymbolName(ProcessedName);2439if (D.Error)2440return std::nullopt;24412442return MangledName.length() - ProcessedName.length();2443}24442445char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled,2446int *Status, MSDemangleFlags Flags) {2447Demangler D;24482449std::string_view Name{MangledName};2450SymbolNode *AST = D.parse(Name);2451if (!D.Error && NMangled)2452*NMangled = MangledName.size() - Name.size();24532454if (Flags & MSDF_DumpBackrefs)2455D.dumpBackReferences();24562457OutputFlags OF = OF_Default;2458if (Flags & MSDF_NoCallingConvention)2459OF = OutputFlags(OF | OF_NoCallingConvention);2460if (Flags & MSDF_NoAccessSpecifier)2461OF = OutputFlags(OF | OF_NoAccessSpecifier);2462if (Flags & MSDF_NoReturnType)2463OF = OutputFlags(OF | OF_NoReturnType);2464if (Flags & MSDF_NoMemberType)2465OF = OutputFlags(OF | OF_NoMemberType);2466if (Flags & MSDF_NoVariableType)2467OF = OutputFlags(OF | OF_NoVariableType);24682469int InternalStatus = demangle_success;2470char *Buf;2471if (D.Error)2472InternalStatus = demangle_invalid_mangled_name;2473else {2474OutputBuffer OB;2475AST->output(OB, OF);2476OB += '\0';2477Buf = OB.getBuffer();2478}24792480if (Status)2481*Status = InternalStatus;2482return InternalStatus == demangle_success ? Buf : nullptr;2483}248424852486