| //===--- Demangle.h - Interface to Swift symbol demangling ------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is the public API of the demangler library. |
| // Tools which use the demangler library (like lldb) must include this - and |
| // only this - header file. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_DEMANGLING_DEMANGLE_H |
| #define SWIFT_DEMANGLING_DEMANGLE_H |
| |
| #include <memory> |
| #include <string> |
| #include <cassert> |
| #include <cstdint> |
| #include "llvm/ADT/StringRef.h" |
| #include "swift/Runtime/Config.h" |
| #include "swift/Demangling/NamespaceMacros.h" |
| |
| namespace llvm { |
| class raw_ostream; |
| } |
| |
| namespace swift { |
| namespace Demangle { |
| SWIFT_BEGIN_INLINE_NAMESPACE |
| |
| enum class SymbolicReferenceKind : uint8_t; |
| |
| /// A simple default implementation that assigns letters to type parameters in |
| /// alphabetic order. |
| std::string genericParameterName(uint64_t depth, uint64_t index); |
| |
| /// Display style options for the demangler. |
| struct DemangleOptions { |
| bool SynthesizeSugarOnTypes = false; |
| bool QualifyEntities = true; |
| bool DisplayExtensionContexts = true; |
| bool DisplayUnmangledSuffix = true; |
| bool DisplayModuleNames = true; |
| bool DisplayGenericSpecializations = true; |
| bool DisplayProtocolConformances = true; |
| bool DisplayWhereClauses = true; |
| bool DisplayEntityTypes = true; |
| bool DisplayLocalNameContexts = true; |
| bool ShortenPartialApply = false; |
| bool ShortenThunk = false; |
| bool ShortenValueWitness = false; |
| bool ShortenArchetype = false; |
| bool ShowPrivateDiscriminators = true; |
| bool ShowFunctionArgumentTypes = true; |
| bool DisplayDebuggerGeneratedModule = true; |
| bool DisplayStdlibModule = true; |
| bool DisplayObjCModule = true; |
| bool PrintForTypeName = false; |
| |
| /// If this is nonempty, entities in this module name will not be qualified. |
| llvm::StringRef HidingCurrentModule; |
| /// A function to render generic parameter names. |
| std::function<std::string(uint64_t, uint64_t)> GenericParameterName = |
| genericParameterName; |
| |
| DemangleOptions() {} |
| |
| static DemangleOptions SimplifiedUIDemangleOptions() { |
| auto Opt = DemangleOptions(); |
| Opt.SynthesizeSugarOnTypes = true; |
| Opt.QualifyEntities = true; |
| Opt.DisplayExtensionContexts = false; |
| Opt.DisplayUnmangledSuffix = false; |
| Opt.DisplayModuleNames = false; |
| Opt.DisplayGenericSpecializations = false; |
| Opt.DisplayProtocolConformances = false; |
| Opt.DisplayWhereClauses = false; |
| Opt.DisplayEntityTypes = false; |
| Opt.ShortenPartialApply = true; |
| Opt.ShortenThunk = true; |
| Opt.ShortenValueWitness = true; |
| Opt.ShortenArchetype = true; |
| Opt.ShowPrivateDiscriminators = false; |
| Opt.ShowFunctionArgumentTypes = false; |
| return Opt; |
| }; |
| }; |
| |
| class Node; |
| using NodePointer = Node *; |
| |
| enum class FunctionSigSpecializationParamKind : unsigned { |
| // Option Flags use bits 0-5. This give us 6 bits implying 64 entries to |
| // work with. |
| ConstantPropFunction = 0, |
| ConstantPropGlobal = 1, |
| ConstantPropInteger = 2, |
| ConstantPropFloat = 3, |
| ConstantPropString = 4, |
| ClosureProp = 5, |
| BoxToValue = 6, |
| BoxToStack = 7, |
| |
| // Option Set Flags use bits 6-31. This gives us 26 bits to use for option |
| // flags. |
| Dead = 1 << 6, |
| OwnedToGuaranteed = 1 << 7, |
| SROA = 1 << 8, |
| GuaranteedToOwned = 1 << 9, |
| ExistentialToGeneric = 1 << 10, |
| }; |
| |
| /// The pass that caused the specialization to occur. We use this to make sure |
| /// that two passes that generate similar changes do not yield the same |
| /// mangling. This currently cannot happen, so this is just a safety measure |
| /// that creates separate name spaces. |
| enum class SpecializationPass : uint8_t { |
| AllocBoxToStack, |
| ClosureSpecializer, |
| CapturePromotion, |
| CapturePropagation, |
| FunctionSignatureOpts, |
| GenericSpecializer, |
| }; |
| |
| static inline char encodeSpecializationPass(SpecializationPass Pass) { |
| return char(uint8_t(Pass)) + '0'; |
| } |
| |
| enum class ValueWitnessKind { |
| #define VALUE_WITNESS(MANGLING, NAME) \ |
| NAME, |
| #include "swift/Demangling/ValueWitnessMangling.def" |
| }; |
| |
| enum class Directness { |
| Direct, Indirect |
| }; |
| |
| class NodeFactory; |
| class Context; |
| |
| class Node { |
| public: |
| enum class Kind : uint16_t { |
| #define NODE(ID) ID, |
| #include "swift/Demangling/DemangleNodes.def" |
| }; |
| |
| using IndexType = uint64_t; |
| |
| friend class NodeFactory; |
| |
| private: |
| |
| struct NodeVector { |
| NodePointer *Nodes; |
| uint32_t Number = 0; |
| uint32_t Capacity = 0; |
| }; |
| |
| union { |
| llvm::StringRef Text; |
| IndexType Index; |
| NodePointer InlineChildren[2]; |
| NodeVector Children; |
| }; |
| |
| |
| Kind NodeKind; |
| |
| enum class PayloadKind : uint8_t { |
| None, Text, Index, OneChild, TwoChildren, ManyChildren |
| }; |
| PayloadKind NodePayloadKind; |
| |
| Node(Kind k) |
| : NodeKind(k), NodePayloadKind(PayloadKind::None) { |
| } |
| Node(Kind k, llvm::StringRef t) |
| : NodeKind(k), NodePayloadKind(PayloadKind::Text) { |
| Text = t; |
| } |
| Node(Kind k, IndexType index) |
| : NodeKind(k), NodePayloadKind(PayloadKind::Index) { |
| Index = index; |
| } |
| Node(const Node &) = delete; |
| Node &operator=(const Node &) = delete; |
| |
| public: |
| Kind getKind() const { return NodeKind; } |
| |
| bool hasText() const { return NodePayloadKind == PayloadKind::Text; } |
| llvm::StringRef getText() const { |
| assert(hasText()); |
| return Text; |
| } |
| |
| bool hasIndex() const { return NodePayloadKind == PayloadKind::Index; } |
| uint64_t getIndex() const { |
| assert(hasIndex()); |
| return Index; |
| } |
| |
| using iterator = const NodePointer *; |
| |
| size_t getNumChildren() const; |
| |
| bool hasChildren() const { return getNumChildren() != 0; } |
| |
| iterator begin() const; |
| |
| iterator end() const; |
| |
| NodePointer getFirstChild() const { |
| return getChild(0); |
| } |
| NodePointer getLastChild() const { |
| return getChild(getNumChildren() - 1); |
| } |
| NodePointer getChild(size_t index) const { |
| assert(getNumChildren() > index); |
| return begin()[index]; |
| } |
| |
| // Only to be used by the demangler parsers. |
| void addChild(NodePointer Child, NodeFactory &Factory); |
| // Only to be used by the demangler parsers. |
| void removeChildAt(unsigned Pos); |
| |
| // Reverses the order of children. |
| void reverseChildren(size_t StartingAt = 0); |
| |
| /// Prints the whole node tree in readable form to stderr. |
| /// |
| /// Useful to be called from the debugger. |
| void dump(); |
| }; |
| |
| /// Returns the length of the swift mangling prefix of the \p SymbolName. |
| /// |
| /// Returns 0 if \p SymbolName is not a mangled swift (>= swift 4.x) name. |
| int getManglingPrefixLength(llvm::StringRef mangledName); |
| |
| /// Returns true if \p SymbolName is a mangled swift name. |
| /// |
| /// This does not include the old (<= swift 3.x) mangling prefix "_T". |
| inline bool isMangledName(llvm::StringRef mangledName) { |
| return getManglingPrefixLength(mangledName) != 0; |
| } |
| |
| /// Returns true if the mangledName starts with the swift mangling prefix. |
| /// |
| /// This includes the old (<= swift 3.x) mangling prefix "_T". |
| bool isSwiftSymbol(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangledName starts with the swift mangling prefix. |
| /// |
| /// This includes the old (<= swift 3.x) mangling prefix "_T". |
| bool isSwiftSymbol(const char *mangledName); |
| |
| /// Drops the Swift mangling prefix from the given mangled name, if there is |
| /// one. |
| /// |
| /// This does not include the old (<= swift 3.x) mangling prefix "_T". |
| llvm::StringRef dropSwiftManglingPrefix(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is an alias type name. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isAlias(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is a class type name. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isClass(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is an enum type name. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isEnum(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is a protocol type name. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isProtocol(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is a structure type name. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isStruct(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name is an Objective-C symbol. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isObjCSymbol(llvm::StringRef mangledName); |
| |
| /// Returns true if the mangled name has the old scheme of function type |
| /// mangling where labels are part of the type. |
| /// |
| /// \param mangledName A null-terminated string containing a mangled name. |
| bool isOldFunctionTypeMangling(llvm::StringRef mangledName); |
| |
| class Demangler; |
| |
| /// The demangler context. |
| /// |
| /// It owns the allocated nodes which are created during demangling. |
| /// It is always preferable to use the demangling via this context class as it |
| /// ensures efficient memory management. Especially if demangling is done for |
| /// multiple symbols. Typical usage: |
| /// \code |
| /// Context Ctx; |
| /// for (...) { |
| /// NodePointer Root = Ctx.demangleSymbolAsNode(MangledName); |
| /// // Do something with Root |
| /// Ctx.clear(); // deallocates Root |
| /// } |
| /// \endcode |
| /// Declaring the context out of the loop minimizes the amount of needed memory |
| /// allocations. |
| /// |
| class Context { |
| Demangler *D; |
| |
| friend class Node; |
| |
| public: |
| Context(); |
| |
| ~Context(); |
| |
| /// Demangle the given symbol and return the parse tree. |
| /// |
| /// \param MangledName The mangled symbol string, which start a mangling |
| /// prefix: _T, _T0, $S, _$S. |
| /// |
| /// \returns A parse tree for the demangled string - or a null pointer |
| /// on failure. |
| /// The lifetime of the returned node tree ends with the lifetime of the |
| /// context or with a call of clear(). |
| NodePointer demangleSymbolAsNode(llvm::StringRef MangledName); |
| |
| /// Demangle the given type and return the parse tree. |
| /// |
| /// \param MangledName The mangled symbol string, which start a mangling |
| /// prefix: _T, _T0, $S, _$S. |
| /// |
| /// \returns A parse tree for the demangled string - or a null pointer |
| /// on failure. |
| /// The lifetime of the returned node tree ends with the lifetime of the |
| /// context or with a call of clear(). |
| NodePointer demangleTypeAsNode(llvm::StringRef MangledName); |
| |
| /// Demangle the given symbol and return the readable name. |
| /// |
| /// \param MangledName The mangled symbol string, which start a mangling |
| /// prefix: _T, _T0, $S, _$S. |
| /// |
| /// \returns The demangled string. |
| std::string demangleSymbolAsString( |
| llvm::StringRef MangledName, |
| const DemangleOptions &Options = DemangleOptions()); |
| |
| /// Demangle the given type and return the readable name. |
| /// |
| /// \param MangledName The mangled type string, which does _not_ start with |
| /// a mangling prefix. |
| /// |
| /// \returns The demangled string. |
| std::string |
| demangleTypeAsString(llvm::StringRef MangledName, |
| const DemangleOptions &Options = DemangleOptions()); |
| |
| /// Returns true if the mangledName refers to a thunk function. |
| /// |
| /// Thunk functions are either (ObjC) partial apply forwarder, swift-as-ObjC |
| /// or ObjC-as-swift thunks or allocating init functions. |
| bool isThunkSymbol(llvm::StringRef MangledName); |
| |
| /// Returns the mangled name of the target of a thunk. |
| /// |
| /// \returns Returns the remaining name after removing the thunk mangling |
| /// characters from \p MangledName. If \p MangledName is not a thunk symbol |
| /// or the thunk target cannot be derived from the mangling, an empty string |
| /// is returned. |
| std::string getThunkTarget(llvm::StringRef MangledName); |
| |
| /// Returns true if the \p mangledName refers to a function which conforms to |
| /// the Swift calling convention. |
| /// |
| /// The return value is unspecified if the \p MangledName does not refer to a |
| /// function symbol. |
| bool hasSwiftCallingConvention(llvm::StringRef MangledName); |
| |
| /// Demangle the given symbol and return the module name of the symbol. |
| /// |
| /// \param mangledName The mangled symbol string, which start a mangling |
| /// prefix: _T, _T0, $S, _$S. |
| /// |
| /// \returns The module name. |
| std::string getModuleName(llvm::StringRef mangledName); |
| |
| /// Deallocates all nodes. |
| /// |
| /// The memory which is used for nodes is not freed but recycled for the next |
| /// demangling operation. |
| void clear(); |
| }; |
| |
| /// Standalone utility function to demangle the given symbol as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleSymbolAsString should be used instead. |
| /// \param mangledName The mangled name string pointer. |
| /// \param mangledNameLength The length of the mangledName string. |
| /// \returns The demangled string. |
| std::string |
| demangleSymbolAsString(const char *mangledName, size_t mangledNameLength, |
| const DemangleOptions &options = DemangleOptions()); |
| |
| /// Standalone utility function to demangle the given symbol as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleSymbolAsString should be used instead. |
| /// \param mangledName The mangled name string. |
| /// \returns The demangled string. |
| inline std::string |
| demangleSymbolAsString(const std::string &mangledName, |
| const DemangleOptions &options = DemangleOptions()) { |
| return demangleSymbolAsString(mangledName.data(), mangledName.size(), |
| options); |
| } |
| |
| /// Standalone utility function to demangle the given symbol as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleSymbolAsString should be used instead. |
| /// \param MangledName The mangled name string. |
| /// \returns The demangled string. |
| inline std::string |
| demangleSymbolAsString(llvm::StringRef MangledName, |
| const DemangleOptions &Options = DemangleOptions()) { |
| return demangleSymbolAsString(MangledName.data(), |
| MangledName.size(), Options); |
| } |
| |
| /// Standalone utility function to demangle the given type as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleTypeAsString should be used instead. |
| /// \param mangledName The mangled name string pointer. |
| /// \param mangledNameLength The length of the mangledName string. |
| /// \returns The demangled string. |
| std::string |
| demangleTypeAsString(const char *mangledName, size_t mangledNameLength, |
| const DemangleOptions &options = DemangleOptions()); |
| |
| /// Standalone utility function to demangle the given type as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleTypeAsString should be used instead. |
| /// \param mangledName The mangled name string. |
| /// \returns The demangled string. |
| inline std::string |
| demangleTypeAsString(const std::string &mangledName, |
| const DemangleOptions &options = DemangleOptions()) { |
| return demangleTypeAsString(mangledName.data(), mangledName.size(), options); |
| } |
| |
| /// Standalone utility function to demangle the given type as string. |
| /// |
| /// If performance is an issue when demangling multiple symbols, |
| /// Context::demangleTypeAsString should be used instead. |
| /// \param MangledName The mangled name string. |
| /// \returns The demangled string. |
| inline std::string |
| demangleTypeAsString(llvm::StringRef MangledName, |
| const DemangleOptions &Options = DemangleOptions()) { |
| return demangleTypeAsString(MangledName.data(), |
| MangledName.size(), Options); |
| } |
| |
| |
| enum class OperatorKind { |
| NotOperator, |
| Prefix, |
| Postfix, |
| Infix, |
| }; |
| |
| /// Remangle a demangled parse tree. |
| std::string mangleNode(NodePointer root); |
| |
| using SymbolicResolver = |
| llvm::function_ref<Demangle::NodePointer (SymbolicReferenceKind, |
| const void *)>; |
| |
| /// Remangle a demangled parse tree, using a callback to resolve |
| /// symbolic references. |
| std::string mangleNode(NodePointer root, SymbolicResolver resolver); |
| |
| /// Remangle a demangled parse tree, using a callback to resolve |
| /// symbolic references. |
| /// |
| /// The returned string is owned by \p Factory. This means \p Factory must stay |
| /// alive as long as the returned string is used. |
| llvm::StringRef mangleNode(NodePointer root, SymbolicResolver resolver, |
| NodeFactory &Factory); |
| |
| /// Remangle in the old mangling scheme. |
| /// |
| /// This is only used for objc-runtime names. |
| std::string mangleNodeOld(NodePointer root); |
| |
| /// Remangle in the old mangling scheme. |
| /// |
| /// This is only used for objc-runtime names. |
| /// The returned string is owned by \p Factory. This means \p Factory must stay |
| /// alive as long as the returned string is used. |
| llvm::StringRef mangleNodeOld(NodePointer node, NodeFactory &Factory); |
| |
| /// Remangle in the old mangling scheme and embed the name in "_Tt<name>_". |
| /// |
| /// The returned string is null terminated and owned by \p Factory. This means |
| /// \p Factory must stay alive as long as the returned string is used. |
| const char *mangleNodeAsObjcCString(NodePointer node, NodeFactory &Factory); |
| |
| /// Transform the node structure to a string. |
| /// |
| /// Typical usage: |
| /// \code |
| /// std::string aDemangledName = |
| /// swift::Demangler::nodeToString(aNode) |
| /// \endcode |
| /// |
| /// \param Root A pointer to a parse tree generated by the demangler. |
| /// \param Options An object encapsulating options to use to perform this demangling. |
| /// |
| /// \returns A string representing the demangled name. |
| /// |
| std::string nodeToString(NodePointer Root, |
| const DemangleOptions &Options = DemangleOptions()); |
| |
| /// A class for printing to a std::string. |
| class DemanglerPrinter { |
| public: |
| DemanglerPrinter() = default; |
| |
| DemanglerPrinter &operator<<(llvm::StringRef Value) & { |
| Stream.append(Value.data(), Value.size()); |
| return *this; |
| } |
| |
| DemanglerPrinter &operator<<(char c) & { |
| Stream.push_back(c); |
| return *this; |
| } |
| DemanglerPrinter &operator<<(unsigned long long n) &; |
| DemanglerPrinter &operator<<(long long n) &; |
| DemanglerPrinter &operator<<(unsigned long n) & { |
| return *this << (unsigned long long)n; |
| } |
| DemanglerPrinter &operator<<(long n) & { |
| return *this << (long long)n; |
| } |
| DemanglerPrinter &operator<<(unsigned n) & { |
| return *this << (unsigned long long)n; |
| } |
| DemanglerPrinter &operator<<(int n) & { |
| return *this << (long long)n; |
| } |
| |
| template<typename T> |
| DemanglerPrinter &&operator<<(T &&x) && { |
| return std::move(*this << std::forward<T>(x)); |
| } |
| |
| DemanglerPrinter &writeHex(unsigned long long n) &; |
| |
| std::string &&str() && { return std::move(Stream); } |
| |
| llvm::StringRef getStringRef() const { return Stream; } |
| |
| /// Shrinks the buffer. |
| void resetSize(size_t toPos) { |
| assert(toPos <= Stream.size()); |
| Stream.resize(toPos); |
| } |
| private: |
| std::string Stream; |
| }; |
| |
| /// Returns a the node kind \p k as string. |
| const char *getNodeKindString(swift::Demangle::Node::Kind k); |
| |
| /// Prints the whole node tree \p Root in readable form into a std::string. |
| /// |
| /// Useful for debugging. |
| std::string getNodeTreeAsString(NodePointer Root); |
| |
| bool nodeConsumesGenericArgs(Node *node); |
| |
| bool isSpecialized(Node *node); |
| |
| NodePointer getUnspecialized(Node *node, NodeFactory &Factory); |
| |
| /// Returns true if the node \p kind refers to a context node, e.g. a nominal |
| /// type or a function. |
| bool isContext(Node::Kind kind); |
| |
| /// Returns true if the node \p kind refers to a node which is placed before a |
| /// function node, e.g. a specialization attribute. |
| bool isFunctionAttr(Node::Kind kind); |
| |
| /// Form a StringRef around the mangled name starting at base, if the name may |
| /// contain symbolic references. |
| llvm::StringRef makeSymbolicMangledNameStringRef(const char *base); |
| |
| SWIFT_END_INLINE_NAMESPACE |
| } // end namespace Demangle |
| } // end namespace swift |
| |
| // NB: This function is not used directly in the Swift codebase, but is |
| // exported for Xcode support and is used by the sanitizers. Please coordinate |
| // before changing. |
| // |
| /// Demangles a Swift symbol name. |
| /// |
| /// \param mangledName is the symbol name that needs to be demangled. |
| /// \param mangledNameLength is the length of the string that should be |
| /// demangled. |
| /// \param outputBuffer is the user provided buffer where the demangled name |
| /// will be placed. If nullptr, a new buffer will be malloced. In that case, |
| /// the user of this API is responsible for freeing the returned buffer. |
| /// \param outputBufferSize is the size of the output buffer. If the demangled |
| /// name does not fit into the outputBuffer, the output will be truncated and |
| /// the size will be updated, indicating how large the buffer should be. |
| /// \param flags can be used to select the demangling style. TODO: We should |
| //// define what these will be. |
| /// \returns the demangled name. Returns nullptr if the input String is not a |
| /// Swift mangled name. |
| SWIFT_RUNTIME_EXPORT |
| char *swift_demangle(const char *mangledName, |
| size_t mangledNameLength, |
| char *outputBuffer, |
| size_t *outputBufferSize, |
| uint32_t flags); |
| |
| #endif // SWIFT_DEMANGLING_DEMANGLE_H |