//===--- Remangle.cpp - Swift re-mangling from a demangling tree ----------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the remangler, which turns a demangling parse // tree back into a mangled string. This is useful for tools which // want to extract subtrees from mangled strings. // //===----------------------------------------------------------------------===// #include "swift/Basic/Demangle.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/Punycode.h" #include "swift/Basic/Range.h" #include "swift/Basic/UUID.h" #include "swift/Strings.h" #include "llvm/ADT/StringRef.h" #include #include #include #include using namespace swift; using namespace Demangle; [[noreturn]] static void unreachable(const char *Message) { fprintf(stderr, "fatal error: %s\n", Message); std::abort(); } /// Translate the given operator character into its mangled form. /// /// Current operator characters: @/=-+*%<>!&|^~ and the special operator '..' static char mangleOperatorChar(char op) { switch (op) { case '&': return 'a'; // 'and' case '@': return 'c'; // 'commercial at sign' case '/': return 'd'; // 'divide' case '=': return 'e'; // 'equal' case '>': return 'g'; // 'greater' case '<': return 'l'; // 'less' case '*': return 'm'; // 'multiply' case '!': return 'n'; // 'negate' case '|': return 'o'; // 'or' case '+': return 'p'; // 'plus' case '?': return 'q'; // 'question' case '%': return 'r'; // 'remainder' case '-': return 's'; // 'subtract' case '~': return 't'; // 'tilde' case '^': return 'x'; // 'xor' case '.': return 'z'; // 'zperiod' (the z is silent) default: return op; } } static bool isNonAscii(StringRef str) { for (unsigned char c : str) { if (c >= 0x80) return true; } return false; } static char mangleOperatorKind(OperatorKind operatorKind) { switch (operatorKind) { case OperatorKind::NotOperator: unreachable("invalid"); case OperatorKind::Infix: return 'i'; case OperatorKind::Prefix: return 'p'; case OperatorKind::Postfix: return 'P'; } unreachable("invalid"); } static void mangleIdentifier(StringRef ident, OperatorKind operatorKind, bool usePunycode, DemanglerPrinter &out) { std::string punycodeBuf; if (usePunycode) { // If the identifier contains non-ASCII character, we mangle // with an initial X and Punycode the identifier string. if (isNonAscii(ident)) { out << 'X'; Punycode::encodePunycodeUTF8(ident, punycodeBuf); ident = punycodeBuf; } } // Mangle normal identifiers as // count identifier-char+ // where the count is the number of characters in the identifier, // and where individual identifier characters represent themselves. if (operatorKind == OperatorKind::NotOperator) { out << ident.size() << ident; return; } // Mangle operator identifiers as // operator ::= 'o' operator-fixity count operator-char+ // operator-fixity ::= 'p' // prefix // operator-fixity ::= 'P' // postfix // operator-fixity ::= 'i' // infix // where the count is the number of characters in the operator, // and where the individual operator characters are translated. out << 'o' << mangleOperatorKind(operatorKind); // Mangle ASCII operators directly. out << ident.size(); for (char ch : ident) { out << mangleOperatorChar(ch); } } void Demangle::mangleIdentifier(const char *data, size_t length, OperatorKind operatorKind, std::string &out, bool usePunycode) { DemanglerPrinter printer(out); return ::mangleIdentifier(StringRef(data, length), operatorKind, usePunycode, printer); } namespace { struct DeepHasher { size_t value = 0; void combine(size_t newValue) { value = 33 * value + newValue; } void hash(Node *node) { combine((size_t) node->getKind()); if (node->hasIndex()) { combine(node->getIndex()); } else if (node->hasText()) { StringRef text = node->getText(); for (char c : text) { combine((unsigned char) c); } } for (const auto &child : *node) { hash(child.get()); } } }; } static size_t deepHash(Node *node) { DeepHasher hasher; hasher.hash(node); return hasher.value; } static bool deepEquals(Node *lhs, Node *rhs) { if (lhs->getKind() != rhs->getKind()) return false; if (lhs->hasIndex()) { if (!rhs->hasIndex()) return false; if (lhs->getIndex() != rhs->getIndex()) return false; } else if (lhs->hasText()) { if (!rhs->hasText()) return false; if (lhs->getText() != rhs->getText()) return false; } else if (rhs->hasIndex() || rhs->hasText()) { return false; } if (lhs->getNumChildren() != rhs->getNumChildren()) return false; for (auto li = lhs->begin(), ri = lhs->begin(), le = lhs->end(); li != le; ++li, ++ri) { if (!deepEquals(li->get(), ri->get())) return false; } return true; } namespace { struct SubstitutionEntry { Node *TheNode; size_t StoredHash; // Note that the constructor leaves this uninitialized. struct Hasher { size_t operator()(const SubstitutionEntry &entry) const { return entry.StoredHash; } }; friend bool operator==(const SubstitutionEntry &lhs, const SubstitutionEntry &rhs) { return (lhs.StoredHash == rhs.StoredHash && deepEquals(lhs.TheNode, lhs.TheNode)); } }; class Remangler { struct ArchetypeInfo { Node::IndexType Index; Node::IndexType AbsoluteDepth; }; DemanglerPrinter &Out; std::unordered_map Archetypes; unsigned AbsoluteArchetypeDepth = 0; std::unordered_map Substitutions; public: Remangler(DemanglerPrinter &out) : Out(out) {} class EntityContext { Remangler &R; unsigned SavedAbsoluteDepth; bool AsContext = false; public: EntityContext(Remangler &R) : R(R), SavedAbsoluteDepth(R.AbsoluteArchetypeDepth) { } ~EntityContext() { assert(R.AbsoluteArchetypeDepth >= SavedAbsoluteDepth); R.AbsoluteArchetypeDepth = SavedAbsoluteDepth; } bool isAsContext() const { return AsContext; } class ManglingContextRAII { EntityContext &Ctx; bool SavedValue; public: ManglingContextRAII(EntityContext &ctx) : Ctx(ctx), SavedValue(ctx.AsContext) { ctx.AsContext = true; } ~ManglingContextRAII() { Ctx.AsContext = SavedValue; } }; }; void mangle(Node *node) { switch (node->getKind()) { #define NODE(ID) case Node::Kind::ID: return mangle##ID(node); #include "swift/Basic/DemangleNodes.def" } unreachable("bad demangling tree node"); } #define NODE(ID) \ void mangle##ID(Node *node); #define CONTEXT_NODE(ID) \ void mangle##ID(Node *node); \ void mangle##ID(Node *node, EntityContext &ctx); #include "swift/Basic/DemangleNodes.def" void mangleIndex(Node::IndexType index); void mangleIdentifier(StringRef name, OperatorKind operatorKind); void mangleChildNodes(Node *node) { mangleNodes(node->begin(), node->end()); } void mangleNodes(Node::iterator i, Node::iterator e) { for (; i != e; ++i) { mangle(i->get()); } } void mangleSingleChildNode(Node *node) { assert(node->getNumChildren() == 1); mangle(node->begin()->get()); } void mangleChildNode(Node *node, unsigned index) { assert(index < node->getNumChildren()); mangle(node->begin()[index].get()); } void mangleSimpleEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx); void mangleNamedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx); void mangleTypedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx); void mangleNamedAndTypedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx); void mangleNominalType(Node *node, char basicKind, EntityContext &ctx); void mangleProtocolWithoutPrefix(Node *node); void mangleProtocolListWithoutPrefix(Node *node); void mangleEntityContext(Node *node, EntityContext &ctx); void mangleEntityType(Node *node, EntityContext &ctx); void mangleEntityGenericType(Node *node, EntityContext &ctx); void mangleGenerics(Node *node, EntityContext &ctx); bool trySubstitution(Node *node, SubstitutionEntry &entry); void addSubstitution(const SubstitutionEntry &entry); void resetSubstitutions(); void mangleDependentGenericParamIndex(Node *node); void mangleConstrainedType(Node *node); }; } #define NODE(ID) #define CONTEXT_NODE(ID) \ void Remangler::mangle##ID(Node *node) { \ EntityContext ctx(*this); \ mangle##ID(node, ctx); \ } #include "swift/Basic/DemangleNodes.def" /// Reset the currently-active set of substitutions. This is useful /// when part of the mangling is done independently, e.g. when an /// optimization pass modifies a pass. void Remangler::resetSubstitutions() { Substitutions.clear(); } bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry) { auto isInSwiftModule = [](Node *node) -> bool { auto context = node->begin()->get(); return (context->getKind() == Node::Kind::Module && context->getText() == STDLIB_NAME); }; // Look for known substitutions. switch (node->getKind()) { #define SUCCESS_IF_IS(VALUE, EXPECTED, SUBSTITUTION) \ do { \ if ((VALUE) == (EXPECTED)) { \ Out << SUBSTITUTION; \ return true; \ } \ } while (0) #define SUCCESS_IF_TEXT_IS(EXPECTED, SUBSTITUTION) \ SUCCESS_IF_IS(node->getText(), EXPECTED, SUBSTITUTION) #define SUCCESS_IF_DECLNAME_IS(EXPECTED, SUBSTITUTION) \ SUCCESS_IF_IS(node->getChild(1)->getText(), EXPECTED, SUBSTITUTION) case Node::Kind::Module: SUCCESS_IF_TEXT_IS(STDLIB_NAME, "s"); SUCCESS_IF_TEXT_IS(MANGLING_MODULE_OBJC, "So"); SUCCESS_IF_TEXT_IS(MANGLING_MODULE_C, "SC"); break; case Node::Kind::Structure: if (isInSwiftModule(node)) { SUCCESS_IF_DECLNAME_IS("Array", "Sa"); SUCCESS_IF_DECLNAME_IS("Bool", "Sb"); SUCCESS_IF_DECLNAME_IS("UnicodeScalar", "Sc"); SUCCESS_IF_DECLNAME_IS("Double", "Sd"); SUCCESS_IF_DECLNAME_IS("Float", "Sf"); SUCCESS_IF_DECLNAME_IS("Int", "Si"); SUCCESS_IF_DECLNAME_IS("UnsafePointer", "SP"); SUCCESS_IF_DECLNAME_IS("UnsafeMutablePointer", "Sp"); SUCCESS_IF_DECLNAME_IS("UnsafeBufferPointer", "SR"); SUCCESS_IF_DECLNAME_IS("UnsafeMutableBufferPointer", "Sr"); SUCCESS_IF_DECLNAME_IS("String", "SS"); SUCCESS_IF_DECLNAME_IS("UInt", "Su"); } break; case Node::Kind::Enum: if (isInSwiftModule(node)) { SUCCESS_IF_DECLNAME_IS("Optional", "Sq"); SUCCESS_IF_DECLNAME_IS("ImplicitlyUnwrappedOptional", "SQ"); } break; default: break; #undef SUCCESS_IF_DECLNAME_IS #undef SUCCESS_IF_TEXT_IS #undef SUCCESS_IF_IS } // Go ahead and initialize the substitution entry. entry.TheNode = node; entry.StoredHash = deepHash(node); auto it = Substitutions.find(entry); if (it == Substitutions.end()) return false; Out << 'S'; mangleIndex(it->second); return true; } void Remangler::addSubstitution(const SubstitutionEntry &entry) { auto result = Substitutions.insert({entry, Substitutions.size()}); assert(result.second); (void) result; } void Remangler::mangleIdentifier(Node *node) { mangleIdentifier(node->getText(), OperatorKind::NotOperator); } void Remangler::manglePrefixOperator(Node *node) { mangleIdentifier(node->getText(), OperatorKind::Prefix); } void Remangler::manglePostfixOperator(Node *node) { mangleIdentifier(node->getText(), OperatorKind::Postfix); } void Remangler::mangleInfixOperator(Node *node) { mangleIdentifier(node->getText(), OperatorKind::Infix); } void Remangler::mangleIdentifier(StringRef ident, OperatorKind operatorKind) { ::mangleIdentifier(ident, operatorKind, /*usePunycode*/ true, Out); } void Remangler::mangleNumber(Node *node) { mangleIndex(node->getIndex()); } void Remangler::mangleIndex(Node::IndexType value) { if (value == 0) { Out << '_'; } else { Out << (value - 1) << '_'; } } void Remangler::mangleGlobal(Node *node) { Out << "_T"; mangleChildNodes(node); } void Remangler::mangleSuffix(Node *node) { // Just add the suffix back on. Out << node->getText(); } void Remangler::mangleGenericSpecialization(Node *node) { Out << "TSg"; mangleChildNodes(node); // GenericSpecializationParams // Specializations are just prepended to already-mangled names. resetSubstitutions(); // Start another mangled name. Out << "__T"; } void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) { Out << "TSr"; mangleChildNodes(node); // GenericSpecializationParams // Specializations are just prepended to already-mangled names. resetSubstitutions(); // Start another mangled name. Out << "__T"; } void Remangler::mangleGenericSpecializationParam(Node *node) { // Should be a type followed by a series of protocol conformances. mangleChildNodes(node); Out << '_'; } void Remangler::mangleFunctionSignatureSpecialization(Node *node) { Out << "TSf"; mangleChildNodes(node); // FunctionSignatureSpecializationParams // Specializations are just prepended to already-mangled names. resetSubstitutions(); // Start another mangled name. Out << "__T"; } void Remangler::mangleSpecializationPassID(Node *node) { Out << node->getIndex(); } void Remangler::mangleFunctionSignatureSpecializationParam(Node *node) { if (!node->hasChildren()) { Out << "n_"; return; } // The first child is always a kind that specifies the type of param that we // have. NodePointer firstChild = node->getChild(0); unsigned kindValue = firstChild->getIndex(); auto kind = FunctionSigSpecializationParamKind(kindValue); switch (kind) { case FunctionSigSpecializationParamKind::ConstantPropFunction: Out << "cpfr"; mangleIdentifier(node->getChild(1).get()); Out << '_'; return; case FunctionSigSpecializationParamKind::ConstantPropGlobal: Out << "cpg"; mangleIdentifier(node->getChild(1).get()); Out << '_'; return; case FunctionSigSpecializationParamKind::ConstantPropInteger: Out << "cpi" << node->getChild(1)->getText() << '_'; return; case FunctionSigSpecializationParamKind::ConstantPropFloat: Out << "cpfl" << node->getChild(1)->getText() << '_'; return; case FunctionSigSpecializationParamKind::ConstantPropString: { Out << "cpse"; StringRef encodingStr = node->getChild(1)->getText(); if (encodingStr == "u8") Out << '0'; else if (encodingStr == "u16") Out << '1'; else unreachable("Unknown encoding"); Out << 'v'; mangleIdentifier(node->getChild(2).get()); Out << '_'; return; } case FunctionSigSpecializationParamKind::ClosureProp: Out << "cl"; mangleIdentifier(node->getChild(1).get()); for (unsigned i = 2, e = node->getNumChildren(); i != e; ++i) { mangleType(node->getChild(i).get()); } Out << '_'; return; case FunctionSigSpecializationParamKind::BoxToValue: Out << "i_"; return; case FunctionSigSpecializationParamKind::BoxToStack: Out << "k_"; return; default: if (kindValue & unsigned(FunctionSigSpecializationParamKind::Dead)) Out << 'd'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) Out << 'g'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::SROA)) Out << 's'; Out << '_'; return; } } void Remangler::mangleFunctionSignatureSpecializationParamPayload(Node *node) { // This should never be called since mangling parameter payloads require // knowing what the parameter kind is. unreachable("This should never be called"); } void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) { // This should never be called since mangling parameter kinds have influence // on the payloads. unreachable("This should never be called"); } void Remangler::mangleProtocolConformance(Node *node) { // type, protocol name, context assert(node->getNumChildren() == 3); mangleChildNode(node, 0); mangleProtocolWithoutPrefix(node->begin()[1].get()); mangleChildNode(node, 2); } void Remangler::mangleObjCAttribute(Node *node) { Out << "To"; } void Remangler::mangleNonObjCAttribute(Node *node) { Out << "TO"; } void Remangler::mangleDirectMethodReferenceAttribute(Node *node) { Out << "Td"; } void Remangler::mangleDynamicAttribute(Node *node) { Out << "TD"; } void Remangler::mangleVTableAttribute(Node *node) { Out << "TV"; } void Remangler::mangleGenericTypeMetadataPattern(Node *node) { Out << "MP"; mangleSingleChildNode(node); // type } void Remangler::mangleTypeMetadataAccessFunction(Node *node) { Out << "Ma"; mangleSingleChildNode(node); // type } void Remangler::mangleTypeMetadataLazyCache(Node *node) { Out << "ML"; mangleSingleChildNode(node); // type } void Remangler::mangleMetaclass(Node *node) { Out << "Mm"; mangleSingleChildNode(node); // type } void Remangler::mangleNominalTypeDescriptor(Node *node) { Out << "Mn"; mangleSingleChildNode(node); // type } void Remangler::mangleTypeMetadata(Node *node) { Out << "M"; mangleSingleChildNode(node); // type } void Remangler::mangleFullTypeMetadata(Node *node) { Out << "Mf"; mangleChildNodes(node); // type } void Remangler::mangleProtocolDescriptor(Node *node) { Out << "Mp"; mangleProtocolWithoutPrefix(node->begin()[0].get()); } void Remangler::manglePartialApplyForwarder(Node *node) { Out << "PA__T"; mangleSingleChildNode(node); // global } void Remangler::manglePartialApplyObjCForwarder(Node *node) { Out << "PAo__T"; mangleSingleChildNode(node); // global } void Remangler::mangleDirectness(Node *node) { auto getChar = [](Directness d) -> char { switch (d) { case Directness::Direct: return 'd'; case Directness::Indirect: return 'i'; } unreachable("bad directness kind"); }; Out << getChar(Directness(node->getIndex())); } void Remangler::mangleValueWitness(Node *node) { auto getString = [](ValueWitnessKind kind) -> StringRef { switch (kind) { case ValueWitnessKind::AllocateBuffer: return "al"; case ValueWitnessKind::AssignWithCopy: return "ca"; case ValueWitnessKind::AssignWithTake: return "ta"; case ValueWitnessKind::DeallocateBuffer: return "de"; case ValueWitnessKind::Destroy: return "xx"; case ValueWitnessKind::DestroyBuffer: return "XX"; case ValueWitnessKind::InitializeBufferWithCopyOfBuffer: return "CP"; case ValueWitnessKind::InitializeBufferWithCopy: return "Cp"; case ValueWitnessKind::InitializeWithCopy: return "cp"; case ValueWitnessKind::InitializeBufferWithTake: return "Tk"; case ValueWitnessKind::InitializeWithTake: return "tk"; case ValueWitnessKind::ProjectBuffer: return "pr"; case ValueWitnessKind::InitializeBufferWithTakeOfBuffer: return "TK"; case ValueWitnessKind::DestroyArray: return "Xx"; case ValueWitnessKind::InitializeArrayWithCopy: return "Cc"; case ValueWitnessKind::InitializeArrayWithTakeFrontToBack: return "Tt"; case ValueWitnessKind::InitializeArrayWithTakeBackToFront: return "tT"; case ValueWitnessKind::StoreExtraInhabitant: return "xs"; case ValueWitnessKind::GetExtraInhabitantIndex: return "xg"; case ValueWitnessKind::GetEnumTag: return "ug"; case ValueWitnessKind::DestructiveProjectEnumData: return "up"; } unreachable("bad value witness kind"); }; Out << 'w' << getString(ValueWitnessKind(node->getIndex())); mangleSingleChildNode(node); // type } void Remangler::mangleValueWitnessTable(Node *node) { Out << "WV"; mangleSingleChildNode(node); // type } void Remangler::mangleWitnessTableOffset(Node *node) { Out << "Wo"; mangleSingleChildNode(node); // entity } void Remangler::mangleThrowsAnnotation(Node *node) { Out << "z"; } void Remangler::mangleFieldOffset(Node *node) { Out << "Wv"; mangleChildNodes(node); // directness, entity } void Remangler::mangleProtocolWitnessTable(Node *node) { Out << "WP"; mangleSingleChildNode(node); // protocol conformance } void Remangler::mangleGenericProtocolWitnessTable(Node *node) { Out << "WG"; mangleSingleChildNode(node); // protocol conformance } void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction( Node *node) { Out << "WI"; mangleSingleChildNode(node); // protocol conformance } void Remangler::mangleProtocolWitnessTableAccessor(Node *node) { Out << "Wa"; mangleSingleChildNode(node); // protocol conformance } void Remangler::mangleLazyProtocolWitnessTableAccessor(Node *node) { Out << "Wl"; mangleChildNodes(node); // type, protocol conformance } void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) { Out << "WL"; mangleChildNodes(node); // type, protocol conformance } void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) { Out << "Wt"; mangleChildNodes(node); // protocol conformance, identifier } void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) { Out << "WT"; assert(node->getNumChildren() == 3); mangleChildNode(node, 0); // protocol conformance mangleChildNode(node, 1); // identifier mangleProtocolWithoutPrefix(node->begin()[2].get()); // type } void Remangler::mangleReabstractionThunkHelper(Node *node) { Out << "TR"; if (node->getNumChildren() == 3) Out << 'G'; mangleChildNodes(node); // generic signature?, type, type } void Remangler::mangleReabstractionThunk(Node *node) { Out << "Tr"; if (node->getNumChildren() == 3) Out << 'G'; mangleChildNodes(node); // generic signature?, type, type } void Remangler::mangleProtocolWitness(Node *node) { Out << "TW"; mangleChildNodes(node); // protocol conformance, entity } void Remangler::mangleFunction(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "", ctx); } void Remangler::mangleVariable(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'v', "", ctx); } void Remangler::mangleSubscript(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'i', "", ctx); } void Remangler::mangleInitializer(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'I', "i", ctx); } void Remangler::mangleDefaultArgumentInitializer(Node *node, EntityContext &ctx) { mangleNamedEntity(node, 'I', "A", ctx); } void Remangler::mangleDeallocator(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'F', "D", ctx); } void Remangler::mangleDestructor(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'F', "d", ctx); } void Remangler::mangleAllocator(Node *node, EntityContext &ctx) { mangleTypedEntity(node, 'F', "C", ctx); } void Remangler::mangleConstructor(Node *node, EntityContext &ctx) { mangleTypedEntity(node, 'F', "c", ctx); } void Remangler::mangleIVarInitializer(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'F', "e", ctx); } void Remangler::mangleIVarDestroyer(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'F', "E", ctx); } void Remangler::mangleGetter(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "g", ctx); } void Remangler::mangleGlobalGetter(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "G", ctx); } void Remangler::mangleSetter(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "s", ctx); } void Remangler::mangleMaterializeForSet(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "m", ctx); } void Remangler::mangleWillSet(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "w", ctx); } void Remangler::mangleDidSet(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "W", ctx); } void Remangler::mangleOwningMutableAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "aO", ctx); } void Remangler::mangleNativeOwningMutableAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "ao", ctx); } void Remangler::mangleNativePinningMutableAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "ap", ctx); } void Remangler::mangleUnsafeMutableAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "au", ctx); } void Remangler::mangleOwningAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "lO", ctx); } void Remangler::mangleNativeOwningAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "lo", ctx); } void Remangler::mangleNativePinningAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "lp", ctx); } void Remangler::mangleUnsafeAddressor(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "lu", ctx); } void Remangler::mangleExplicitClosure(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "U", ctx); // name is index } void Remangler::mangleImplicitClosure(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "u", ctx); // name is index } void Remangler::mangleStatic(Node *node, EntityContext &ctx) { Out << 'Z'; mangleEntityContext(node->getChild(0).get(), ctx); } void Remangler::mangleSimpleEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx) { assert(node->getNumChildren() == 1); Out << basicKind; mangleEntityContext(node->begin()[0].get(), ctx); Out << entityKind; } void Remangler::mangleNamedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx) { assert(node->getNumChildren() == 2); if (basicKind != '\0') Out << basicKind; mangleEntityContext(node->begin()[0].get(), ctx); Out << entityKind; mangleChildNode(node, 1); // decl name / index } void Remangler::mangleTypedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx) { assert(node->getNumChildren() == 2); Out << basicKind; mangleEntityContext(node->begin()[0].get(), ctx); Out << entityKind; mangleEntityType(node->begin()[1].get(), ctx); } void Remangler::mangleNamedAndTypedEntity(Node *node, char basicKind, StringRef entityKind, EntityContext &ctx) { assert(node->getNumChildren() == 3); Out << basicKind; mangleEntityContext(node->begin()[0].get(), ctx); Out << entityKind; mangleChildNode(node, 1); // decl name / index mangleEntityType(node->begin()[2].get(), ctx); } void Remangler::mangleEntityContext(Node *node, EntityContext &ctx) { // Remember that we're mangling a context. EntityContext::ManglingContextRAII raii(ctx); switch (node->getKind()) { #define NODE(ID) \ case Node::Kind::ID: #define CONTEXT_NODE(ID) #include "swift/Basic/DemangleNodes.def" unreachable("not a context node"); #define NODE(ID) #define CONTEXT_NODE(ID) \ case Node::Kind::ID: \ return mangle##ID(node, ctx); #include "swift/Basic/DemangleNodes.def" } unreachable("bad node kind"); } void Remangler::mangleEntityType(Node *node, EntityContext &ctx) { assert(node->getKind() == Node::Kind::Type); assert(node->getNumChildren() == 1); node = node->begin()[0].get(); // Expand certain kinds of type within the entity context. switch (node->getKind()) { case Node::Kind::GenericType: mangleEntityGenericType(node, ctx); return; case Node::Kind::FunctionType: case Node::Kind::UncurriedFunctionType: { Out << (node->getKind() == Node::Kind::FunctionType ? 'F' : 'f'); unsigned inputIndex = node->getNumChildren() - 2; assert(inputIndex <= 1); for (unsigned i = 0; i <= inputIndex; ++i) mangle(node->begin()[i].get()); auto returnType = node->begin()[inputIndex+1].get(); assert(returnType->getKind() == Node::Kind::ReturnType); assert(returnType->getNumChildren() == 1); mangleEntityType(returnType->begin()[0].get(), ctx); return; } default: mangle(node); return; } } void Remangler::mangleLocalDeclName(Node *node) { Out << 'L'; mangleChildNodes(node); // index, identifier } void Remangler::manglePrivateDeclName(Node *node) { Out << 'P'; mangleChildNodes(node); // identifier, identifier } void Remangler::mangleTypeMangling(Node *node) { Out << 't'; mangleSingleChildNode(node); // type } void Remangler::mangleType(Node *node) { mangleSingleChildNode(node); } template static bool stripPrefix(StringRef &string, const char (&data)[N]) { constexpr size_t prefixLength = N - 1; if (!string.startswith(StringRef(data, prefixLength))) return false; string = string.drop_front(prefixLength); return true; } void Remangler::mangleBuiltinTypeName(Node *node) { Out << 'B'; StringRef text = node->getText(); if (text == "Builtin.BridgeObject") { Out << 'b'; } else if (text == "Builtin.UnsafeValueBuffer") { Out << 'B'; } else if (text == "Builtin.UnknownObject") { Out << 'O'; } else if (text == "Builtin.NativeObject") { Out << 'o'; } else if (text == "Builtin.RawPointer") { Out << 'p'; } else if (text == "Builtin.Word") { Out << 'w'; } else if (stripPrefix(text, "Builtin.Int")) { Out << 'i' << text << '_'; } else if (stripPrefix(text, "Builtin.Float")) { Out << 'f' << text << '_'; } else if (stripPrefix(text, "Builtin.Vec")) { auto split = text.split('x'); Out << 'v' << split.first << 'B'; if (split.second == "RawPointer") { Out << 'p'; } else if (stripPrefix(split.second, "Float")) { Out << 'f' << split.second << '_'; } else if (stripPrefix(split.second, "Int")) { Out << 'i' << split.second << '_'; } else { unreachable("unexpected builtin vector type"); } } else { unreachable("unexpected builtin type"); } } void Remangler::mangleTypeAlias(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; Out << 'a'; mangleChildNodes(node); // context, identifier addSubstitution(entry); } void Remangler::mangleFunctionType(Node *node) { Out << 'F'; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleUncurriedFunctionType(Node *node) { Out << 'f'; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleObjCBlock(Node *node) { Out << 'b'; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleCFunctionPointer(Node *node) { Out << 'c'; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleAutoClosureType(Node *node) { Out << 'K'; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleThinFunctionType(Node *node) { Out << "Xf"; mangleChildNodes(node); // argument tuple, result type } void Remangler::mangleArgumentTuple(Node *node) { mangleSingleChildNode(node); } void Remangler::mangleReturnType(Node *node) { mangleSingleChildNode(node); } void Remangler::mangleImplFunctionType(Node *node) { Out << "XF"; auto i = node->begin(), e = node->end(); if (i != e && i->get()->getKind() == Node::Kind::ImplConvention) { StringRef text = (i++)->get()->getText(); if (text == "@callee_unowned") { Out << 'd'; } else if (text == "@callee_guaranteed") { Out << 'g'; } else if (text == "@callee_owned") { Out << 'o'; } else { unreachable("bad callee convention"); } } else { Out << 't'; } for (; i != e && i->get()->getKind() == Node::Kind::ImplFunctionAttribute; ++i) { mangle(i->get()); // impl function attribute } EntityContext ctx(*this); if (i != e && i->get()->getKind() == Node::Kind::Generics) { mangleGenerics((i++)->get(), ctx); } Out << '_'; for (; i != e && i->get()->getKind() == Node::Kind::ImplParameter; ++i) { mangleImplParameter(i->get()); } Out << '_'; mangleNodes(i, e); // impl results Out << '_'; } void Remangler::mangleImplFunctionAttribute(Node *node) { StringRef text = node->getText(); if (text == "@convention(block)") { Out << "Cb"; } else if (text == "@convention(c)") { Out << "Cc"; } else if (text == "@convention(method)") { Out << "Cm"; } else if (text == "@convention(objc_method)") { Out << "CO"; } else if (text == "@convention(witness_method)") { Out << "Cw"; } else if (text == "@noreturn") { Out << "CN"; } else { unreachable("bad impl-function-attribute"); } } void Remangler::mangleImplParameter(Node *node) { assert(node->getNumChildren() == 2); mangleChildNodes(node); // impl convention, type } void Remangler::mangleImplErrorResult(Node *node) { assert(node->getNumChildren() == 2); Out << 'z'; mangleChildNodes(node); // impl convention, type } void Remangler::mangleImplResult(Node *node) { assert(node->getNumChildren() == 2); mangleChildNodes(node); // impl convention, type } void Remangler::mangleImplConvention(Node *node) { assert(node->getKind() == Node::Kind::ImplConvention); StringRef text = node->getText(); if (text == "@autoreleased") { Out << 'a'; } else if (text == "@unowned") { Out << 'd'; } else if (text == "@unowned_inner_pointer") { Out << 'd'; // only in results } else if (text == "@guaranteed") { Out << 'g'; } else if (text == "@deallocating") { Out << 'e'; } else if (text == "@in") { Out << 'i'; // only in parameters } else if (text == "@out") { Out << 'i'; // only in results } else if (text == "@inout") { Out << 'l'; } else if (text == "@owned") { Out << 'o'; } else { unreachable("invalid impl convention"); } } void Remangler::mangleDynamicSelf(Node *node) { Out << 'D'; mangleSingleChildNode(node); // type } void Remangler::mangleErrorType(Node *node) { Out << "ERR"; } void Remangler::mangleSILBoxType(Node *node) { Out << 'X' << 'b'; mangleSingleChildNode(node); } void Remangler::mangleMetatype(Node *node) { if (node->getNumChildren() == 1) { Out << 'M'; mangleSingleChildNode(node); // type } else { assert(node->getNumChildren() == 2); Out << "XM"; mangleChildNodes(node); // metatype representation, type } } void Remangler::mangleExistentialMetatype(Node *node) { if (node->getNumChildren() == 1) { Out << "PM"; mangleSingleChildNode(node); // type } else { assert(node->getNumChildren() == 2); Out << "XPM"; mangleChildNodes(node); // metatype representation, type } } void Remangler::mangleMetatypeRepresentation(Node *node) { StringRef text = node->getText(); if (text == "@thin") { Out << 't'; } else if (text == "@thick") { Out << 'T'; } else if (text == "@objc_metatype") { Out << 'o'; } else { unreachable("bad metatype representation"); } } void Remangler::mangleProtocolList(Node *node) { // In its usual use as a type, this gets a prefix 'P'. Out << 'P'; mangleProtocolListWithoutPrefix(node); } void Remangler::mangleProtocolListWithoutPrefix(Node *node) { assert(node->getKind() == Node::Kind::ProtocolList); assert(node->getNumChildren() == 1); auto typeList = node->begin()[0].get(); assert(typeList->getKind() == Node::Kind::TypeList); for (auto &child : *typeList) { mangleProtocolWithoutPrefix(child.get()); } Out << '_'; } void Remangler::mangleUnowned(Node *node) { Out << "Xo"; mangleSingleChildNode(node); // type } void Remangler::mangleUnmanaged(Node *node) { Out << "Xu"; mangleSingleChildNode(node); // type } void Remangler::mangleWeak(Node *node) { Out << "Xw"; mangleSingleChildNode(node); // type } void Remangler::mangleInOut(Node *node) { Out << 'R'; mangleSingleChildNode(node); // type } void Remangler::mangleNonVariadicTuple(Node *node) { Out << 'T'; mangleChildNodes(node); // tuple elements Out << '_'; } void Remangler::mangleVariadicTuple(Node *node) { Out << 't'; mangleChildNodes(node); // tuple elements Out << '_'; } void Remangler::mangleTupleElement(Node *node) { mangleChildNodes(node); // tuple element name?, type } void Remangler::mangleTupleElementName(Node *node) { mangleIdentifier(node->getText(), OperatorKind::NotOperator); } void Remangler::mangleDependentGenericType(Node *node) { Out << 'u'; mangleChildNodes(node); // generic signature, type } void Remangler::mangleGenericType(Node *node) { EntityContext ctx(*this); mangleEntityGenericType(node, ctx); } void Remangler::mangleEntityGenericType(Node *node, EntityContext &ctx) { assert(node->getKind() == Node::Kind::GenericType); Out << 'U'; assert(node->getNumChildren() == 2); mangleGenerics(node->begin()[0].get(), ctx); mangleEntityType(node->begin()[1].get(), ctx); } void Remangler::mangleDependentGenericSignature(Node *node) { auto i = node->begin(), e = node->end(); // If there's only one generic param, mangle nothing. if (node->getNumChildren() >= 1 && node->getChild(0)->getKind() == Node::Kind::DependentGenericParamCount && node->getChild(0)->getIndex() == 1 && (node->getNumChildren() == 1 || node->getChild(1)->getKind() != Node::Kind::DependentGenericParamCount)) { ++i; goto mangle_requirements; } // Remangle generic params. for (; i != e && i->get()->getKind() == Node::Kind::DependentGenericParamCount; ++i) { auto count = i->get(); if (count->getIndex() > 0) mangleIndex(count->getIndex() - 1); else Out << 'z'; } mangle_requirements: if (i == e) { // no generic requirements Out << 'r'; return; } Out << 'R'; mangleNodes(i, e); // generic requirements Out << 'r'; } void Remangler::mangleDependentGenericParamCount(Node *node) { unreachable("handled inline in DependentGenericSignature"); } void Remangler::mangleDependentGenericConformanceRequirement(Node *node) { mangleConstrainedType(node->getChild(0).get()); // If the constraint represents a protocol, use the shorter mangling. if (node->getNumChildren() == 2 && node->getChild(1)->getKind() == Node::Kind::Type && node->getChild(1)->getNumChildren() == 1 && node->getChild(1)->getChild(0)->getKind() == Node::Kind::Protocol) { mangleProtocolWithoutPrefix(node->getChild(1)->getChild(0).get()); return; } mangle(node->getChild(1).get()); } void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) { mangleConstrainedType(node->getChild(0).get()); Out << 'z'; mangle(node->getChild(1).get()); } void Remangler::mangleConstrainedType(Node *node) { if (node->getFirstChild()->getKind() == Node::Kind::DependentGenericParamType) { // Can be mangled without an introducer. mangleDependentGenericParamIndex(node->getFirstChild().get()); } else { mangle(node); } } void Remangler::mangleGenerics(Node *node) { unreachable("found independent generics node?"); } void Remangler::mangleGenerics(Node *node, EntityContext &ctx) { assert(node->getKind() == Node::Kind::Generics); unsigned absoluteDepth = ++AbsoluteArchetypeDepth; auto i = node->begin(), e = node->end(); unsigned index = 0; for (; i != e && i->get()->getKind() == Node::Kind::Archetype; ++i) { auto child = i->get(); Archetypes[child->getText()] = ArchetypeInfo{index++, absoluteDepth}; mangle(child); // archetype } if (i != e) { Out << 'U'; mangleNodes(i, e); // associated types Out << '_'; } else { Out << '_'; } } void Remangler::mangleArchetype(Node *node) { if (node->hasChildren()) { assert(node->getNumChildren() == 1); mangleProtocolListWithoutPrefix(node->begin()->get()); } else { Out << '_'; } } void Remangler::mangleAssociatedType(Node *node) { if (node->hasChildren()) { assert(node->getNumChildren() == 1); mangleProtocolListWithoutPrefix(node->begin()->get()); } else { Out << '_'; } } void Remangler::mangleSelfTypeRef(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; Out << "QP"; assert(node->getNumChildren() == 1); mangleProtocolWithoutPrefix(node->begin()[0].get()); addSubstitution(entry); } void Remangler::mangleArchetypeRef(Node *node) { Node::IndexType relativeDepth = node->getChild(0)->getIndex(); Node::IndexType index = node->getChild(1)->getIndex(); Out << 'Q'; if (relativeDepth != 0) { Out << 'd'; mangleIndex(relativeDepth - 1); } mangleIndex(index); } void Remangler::mangleQualifiedArchetype(Node *node) { Out << "Qq"; mangleChildNodes(node); // index, declcontext } void Remangler::mangleDeclContext(Node *node) { mangleSingleChildNode(node); } void Remangler::mangleExtension(Node *node, EntityContext &ctx) { assert(node->getNumChildren() == 2 || node->getNumChildren() == 3); if (node->getNumChildren() == 3) { Out << 'e'; } else { Out << 'E'; } mangleEntityContext(node->begin()[0].get(), ctx); // module if (node->getNumChildren() == 3) { mangleDependentGenericSignature(node->begin()[2].get()); // generic sig } mangleEntityContext(node->begin()[1].get(), ctx); // context } void Remangler::mangleModule(Node *node, EntityContext &ctx) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; // Module types get an M prefix, but module contexts don't. if (!ctx.isAsContext()) Out << 'M'; mangleIdentifier(node->getText(), OperatorKind::NotOperator); addSubstitution(entry); } void Remangler::mangleAssociatedTypeRef(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; Out << "Q"; mangleChildNodes(node); // type, identifier addSubstitution(entry); } void Remangler::mangleDependentMemberType(Node *node) { std::vector members; Node *base = node; do { members.push_back(base); base = base->getFirstChild()->getFirstChild().get(); } while (base->getKind() == Node::Kind::DependentMemberType); assert(base->getKind() == Node::Kind::DependentGenericParamType && "dependent members not based on a generic param are non-canonical" " and shouldn't need remangling"); assert(members.size() >= 1); if (members.size() == 1) { Out << 'w'; mangleDependentGenericParamIndex(base); mangle(members[0]->getChild(1).get()); } else { Out << 'W'; mangleDependentGenericParamIndex(base); for (auto *member : reversed(members)) { mangle(member->getChild(1).get()); } Out << '_'; } } void Remangler::mangleDependentAssociatedTypeRef(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; if (node->getNumChildren() > 0) { Out << 'P'; mangleProtocolWithoutPrefix(node->getFirstChild().get()); } mangleIdentifier(node); addSubstitution(entry); } void Remangler::mangleDependentGenericParamIndex(Node *node) { auto depth = node->getChild(0)->getIndex(); auto index = node->getChild(1)->getIndex(); if (depth != 0) { Out << 'd'; mangleIndex(depth - 1); mangleIndex(index); return; } if (index != 0) { mangleIndex(index - 1); return; } // depth == index == 0 Out << 'x'; } void Remangler::mangleDependentGenericParamType(Node *node) { if (node->getChild(0)->getIndex() == 0 && node->getChild(1)->getIndex() == 0) { Out << 'x'; return; } Out << 'q'; mangleDependentGenericParamIndex(node); } void Remangler::mangleIndex(Node *node) { mangleIndex(node->getIndex()); } void Remangler::mangleProtocol(Node *node, EntityContext &ctx) { mangleNominalType(node, 'P', ctx); } void Remangler::mangleProtocolWithoutPrefix(Node *node) { if (node->getKind() == Node::Kind::Type) { assert(node->getNumChildren() == 1); node = node->begin()[0].get(); } assert(node->getKind() == Node::Kind::Protocol); EntityContext ctx(*this); mangleNominalType(node, '\0', ctx); } void Remangler::mangleStructure(Node *node, EntityContext &ctx) { mangleNominalType(node, 'V', ctx); } void Remangler::mangleEnum(Node *node, EntityContext &ctx) { mangleNominalType(node, 'O', ctx); } void Remangler::mangleClass(Node *node, EntityContext &ctx) { mangleNominalType(node, 'C', ctx); } void Remangler::mangleNominalType(Node *node, char kind, EntityContext &ctx) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; mangleNamedEntity(node, kind, "", ctx); addSubstitution(entry); } void Remangler::mangleBoundGenericClass(Node *node) { Out << 'G'; mangleChildNodes(node); // type, type list } void Remangler::mangleBoundGenericStructure(Node *node) { Out << 'G'; mangleChildNodes(node); // type, type list } void Remangler::mangleBoundGenericEnum(Node *node) { Out << 'G'; mangleChildNodes(node); // type, type list } void Remangler::mangleTypeList(Node *node) { mangleChildNodes(node); // all types Out << '_'; } /// The top-level interface to the remangler. std::string Demangle::mangleNode(const NodePointer &node) { if (!node) return ""; std::string str; DemanglerPrinter printer(str); Remangler(printer).mangle(node.get()); return str; }