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 @@ -374,6 +374,32 @@ const char *parseTemplate(OutputString *Decl, const char *Mangled, unsigned long Len = -1); + /// Extract and demangle an integer value from a given mangled symbol append + /// it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Type mangled type character in which the type should be + /// represented as + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseInteger(OutputString *Decl, const char *Mangled, char Type); + + /// Extract and demangle any value from a given mangled symbol append it to + /// the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Type mangled type character in which the type should be + /// represented as, if needed + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseValue(OutputString *Decl, const char *Mangled, char Type); + /// The string we are demangling. const char *Str; /// The index of the last back reference. @@ -1517,8 +1543,35 @@ Mangled++; Mangled = parseType(Decl, Mangled); break; + case 'V': /* Value parameter. */ + { + OutputString Name; + char Type; + + /* Peek at the type. */ + Mangled++; + Type = *Mangled; + + if (Type == 'Q') { + /* Value type is a back reference, peek at the real type. */ + const char *Backref; + if (decodeBackref(Mangled, &Backref) == nullptr) + return nullptr; + + Type = *Backref; + } - // TODO: Parse value literals + /* In the few instances where the type is actually desired in + the output, it should precede the value from dlang_value. */ + Name = OutputString(); + Mangled = parseType(&Name, Mangled); + Name.append('\0'); + Name.Ptr--; + + Mangled = parseValue(Decl, Mangled, Type); + Name.free(); + break; + } case 'X': /* Externally mangled parameter. */ { @@ -1583,6 +1636,141 @@ return Mangled; } +const char *Demangler::parseValue(OutputString *Decl, const char *Mangled, + char Type) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + switch (*Mangled) { + // Integral values + case 'N': + Mangled++; + Decl->append('-'); + Mangled = parseInteger(Decl, Mangled, Type); + break; + + case 'i': + Mangled++; + + [[clang::fallthrough]]; + /* There really should always be an `i' before encoded numbers, but there + wasn't in early versions of D2, so this case range must remain for + backwards compatibility */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + Mangled = parseInteger(Decl, Mangled, Type); + break; + + default: + return nullptr; + } + + return Mangled; +} + +const char *Demangler::parseInteger(OutputString *Decl, const char *Mangled, + char Type) { + if (Type == 'a' || Type == 'u' || Type == 'w') { + // Parse character value + char Value[20]; + int Pos = sizeof(Value); + int Width = 0; + unsigned long Val; + + Mangled = decodeNumber(Mangled, &Val); + if (Mangled == nullptr) + return nullptr; + + Decl->append('\''); + + if (Type == 'a' && Val >= 0x20 && Val < 0x7F) { + // Represent as a character literal + Decl->append(static_cast(Val)); + } else { + // Represent as a hexadecimal value + switch (Type) { + case 'a': /* char */ + Decl->append("\\x"); + Width = 2; + break; + case 'u': /* wchar */ + Decl->append("\\u"); + Width = 4; + break; + case 'w': /* dchar */ + Decl->append("\\U"); + Width = 8; + break; + } + + while (Val > 0) { + int Digit = Val % 16; + + if (Digit < 10) + Value[--Pos] = (char)(Digit + '0'); + else + Value[--Pos] = (char)((Digit - 10) + 'a'); + + Val /= 16; + Width--; + } + + for (; Width > 0; Width--) + Value[--Pos] = '0'; + + Decl->append(&(Value[Pos]), sizeof(Value) - Pos); + } + Decl->append('\''); + } else if (Type == 'b') { + // Parse boolean value + unsigned long Val; + + Mangled = decodeNumber(Mangled, &Val); + if (Mangled == nullptr) + return nullptr; + + Decl->append(Val ? "true" : "false"); + } else { + // Parse integer value + const char *NumPtr = Mangled; + size_t Num = 0; + + if (!std::isdigit(*Mangled)) + return nullptr; + + while (std::isdigit(*Mangled)) { + Num++; + Mangled++; + } + Decl->append(NumPtr, Num); + + // Append suffix + switch (Type) { + case 'h': /* ubyte */ + case 't': /* ushort */ + case 'k': /* uint */ + Decl->append('u'); + break; + case 'l': /* long */ + Decl->append('L'); + break; + case 'm': /* ulong */ + Decl->append("uL"); + break; + } + } + + return Mangled; +} + Demangler::Demangler(const char *Mangled) : Str(Mangled), LastBackref(strlen(Mangled)) {} 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 @@ -258,7 +258,27 @@ {"_D8demangle19__T4testS6symbolTaZv", "demangle.test!(symbol, char)"}, {"_D8demangle12__T4testHTaZv", "demangle.test!(char)"}, {"_D8demangle13__T4testTFZaZ6mangleFZv", - "demangle.test!(char() function).mangle()"} + "demangle.test!(char() function).mangle()"}, + {"_D8demangle15__T4testVgi123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVii123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVsi123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVhi123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVki123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVti123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVli123Zv", "demangle.test!(123L)"}, + {"_D8demangle15__T4testVmi123Zv", "demangle.test!(123uL)"}, + {"_D8demangle15__T4testViN123Zv", "demangle.test!(-123)"}, + {"_D8demangle15__T4testVkN123Zv", "demangle.test!(-123u)"}, + {"_D8demangle15__T4testVlN123Zv", "demangle.test!(-123L)"}, + {"_D8demangle15__T4testVmN123Zv", "demangle.test!(-123uL)"}, + {"_D8demangle13__T4testVbi1Zv", "demangle.test!(true)"}, + {"_D8demangle13__T4testVbi0Zv", "demangle.test!(false)"}, + {"_D8demangle14__T4testVai10Zv", "demangle.test!('\\x0a')"}, + {"_D8demangle14__T4testVai32Zv", "demangle.test!(' ')"}, + {"_D8demangle14__T4testVai65Zv", "demangle.test!('A')"}, + {"_D8demangle15__T4testVai126Zv", "demangle.test!('~')"}, + {"_D8demangle16__T4testVui1000Zv", "demangle.test!('\\u03e8')"}, + {"_D8demangle18__T4testVwi100000Zv", "demangle.test!('\\U000186a0')"} }; for (ExpectedVal Val : ExpectedArray) {