diff --git a/llvm/lib/Demangle/DLangDemangle.cpp b/llvm/lib/Demangle/DLangDemangle.cpp --- a/llvm/lib/Demangle/DLangDemangle.cpp +++ b/llvm/lib/Demangle/DLangDemangle.cpp @@ -105,6 +105,17 @@ /// \see https://dlang.org/spec/abi.html#IdentifierBackRef . const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled); + /// Extract and demangle backreferenced type from a given mangled symbol + /// and append it to the output string. + /// + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#TypeBackRef . + const char *parseTypeBackref(const char *Mangled); + /// Check whether it is the beginning of a symbol name. /// /// \param Mangled string to extract the symbol name. @@ -162,6 +173,8 @@ /// The string we are demangling. const char *Str; + /// The index of the last back reference. + int LastBackref; }; } // namespace @@ -276,6 +289,39 @@ return Mangled; } +const char *Demangler::parseTypeBackref(const char *Mangled) { + // A type back reference always points to a letter. + // TypeBackRef: + // Q NumberBackRef + // ^ + const char *Backref; + + // If we appear to be moving backwards through the mangle string, then + // bail as this may be a recursive back reference. + if (Mangled - Str >= LastBackref) + return nullptr; + + int SaveRefPos = LastBackref; + LastBackref = Mangled - Str; + + // Get position of the back reference. + Mangled = decodeBackref(Mangled, Backref); + + // Can't decode back reference. + if (Backref == nullptr) + return nullptr; + + // TODO: Add support for function type back references. + Backref = parseType(Backref); + + LastBackref = SaveRefPos; + + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + bool Demangler::isSymbolName(const char *Mangled) { long Ret; const char *Qref = Mangled; @@ -423,7 +469,10 @@ return Mangled; // TODO: Add support for the rest of the basic types. - // TODO: Parse back referenced types. + + // Back referenced type. + case 'Q': + return parseTypeBackref(Mangled); default: // unhandled. return nullptr; @@ -487,7 +536,8 @@ return Mangled; } -Demangler::Demangler(const char *Mangled) : Str(Mangled) {} +Demangler::Demangler(const char *Mangled) + : Str(Mangled), LastBackref(strlen(Mangled)) {} const char *Demangler::parseMangle(OutputBuffer *Demangled) { return parseMangle(Demangled, this->Str); diff --git a/llvm/unittests/Demangle/DLangDemangleTest.cpp b/llvm/unittests/Demangle/DLangDemangleTest.cpp --- a/llvm/unittests/Demangle/DLangDemangleTest.cpp +++ b/llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -63,4 +63,13 @@ std::make_pair("_D8demangle3ABCQa1ai", nullptr), // invalid symbol back reference (recursive). std::make_pair("_D8demangleQDXXXXXXXXXXXXx", - nullptr))); // overflow back reference position. + nullptr), // overflow back reference position. + std::make_pair( + "_D8demangle4ABCi1aQd", + "demangle.ABCi.a"), // type back reference: `Qd` is a back reference + // for position 4, counting from `d` char, so + // decoding it points to `i`. + std::make_pair("_D8demangle3fooQXXXx", + nullptr), // invalid type back reference position. + std::make_pair("_D8demangle5recurQa", + nullptr))); // invalid type back reference (recursive).