Index: llvm/include/llvm/Demangle/Demangle.h =================================================================== --- llvm/include/llvm/Demangle/Demangle.h +++ llvm/include/llvm/Demangle/Demangle.h @@ -60,6 +60,9 @@ // Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); +// Demangles a D mangled symbol +char *dlangDemangle(const char *MangledName); + /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. Index: llvm/lib/Demangle/CMakeLists.txt =================================================================== --- llvm/lib/Demangle/CMakeLists.txt +++ llvm/lib/Demangle/CMakeLists.txt @@ -4,6 +4,7 @@ MicrosoftDemangle.cpp MicrosoftDemangleNodes.cpp RustDemangle.cpp + DLangDemangle.cpp ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle" Index: llvm/lib/Demangle/DLangDemangle.cpp =================================================================== --- /dev/null +++ llvm/lib/Demangle/DLangDemangle.cpp @@ -0,0 +1,197 @@ +//===--- DLangDemangle.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a demangler for D programming language as specified in the +/// ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// +// +// Ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/MicrosoftDemangleNodes.h" + +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace { + +/// A mini string-handling class for output strings generated by D demangler +/// +/// \note Beware these aren't required to be '\0' terminated +struct OutputString { + + /// pointer to start of string + char *Buffer; + /// pointer after last character + char *Ptr; + /// pointer after end of allocated space + char *EndPtr; + +public: + /// Constructs a new output string + OutputString(); + + /// Free resources previously allocated to the Buffer + void free(); + + /// Get the current length of the string + int getLength(); + + /// Set a given new length to the string + /// + /// \param Size new length + void setLength(int Size); + + /// Append a given single char to the string + /// + /// \param C char to append + void append(char C); + + /// Append a given input to the string + /// + /// \param Str input string to append + void append(const char *Str); + + /// Append a given input with a specific length to the string + /// + /// \param Str input string to append + /// \param Size length to append from the given input string + void append(const char *Str, size_t Size); + + /// Prepend a given input to the string + /// + /// \param Str input string to prepend + void prepend(const char *Str); + + /// Prepend a given input with a specific length to the string + /// + /// \param Str input string to prepend + /// \param Size length to prepend from the given input string + void prepend(const char *Str, size_t Size); + +private: + /// Allocate more needed space to the Buffer + /// + /// \param Size size of the space needed + void need(size_t Size); +}; + +} // namespace + +void OutputString::need(size_t Size) { + size_t Temp; + + if (Buffer == nullptr) { + if (Size < 32) { + Size = 32; + } + Ptr = Buffer = static_cast(std::malloc(Size)); + EndPtr = Buffer + Size; + } else if (static_cast(EndPtr - Ptr) < Size) { + Temp = Ptr - Buffer; + Size += Temp; + Size *= 2; + Buffer = static_cast(std::realloc(Buffer, Size)); + Ptr = Buffer + Temp; + EndPtr = Buffer + Size; + } +} + +OutputString::OutputString() : Buffer(nullptr), Ptr(nullptr), EndPtr(nullptr) {} + +void OutputString::free() { + if (Buffer != nullptr) { + std::free(Buffer); + Buffer = Ptr = EndPtr = nullptr; + } +} + +int OutputString::getLength() { + if (Ptr == Buffer) { + return 0; + } + return Ptr - Buffer; +} + +void OutputString::setLength(int Size) { + if (Size - getLength() < 0) { + Ptr = Buffer + Size; + } +} + +void OutputString::append(char C) { + need(1); + *Ptr = C; + Ptr++; +} + +void OutputString::append(const char *Str) { append(Str, strlen(Str)); } + +void OutputString::append(const char *Str, size_t Size) { + if (Size != 0) { + need(Size); + std::memcpy(Ptr, Str, Size); + Ptr += Size; + } +} + +void OutputString::prepend(const char *Str) { + if (Str != nullptr && *Str != '\0') { + prepend(Str, strlen(Str)); + } +} + +void OutputString::prepend(const char *Str, size_t Size) { + char *TempBuffer; + + if (Size != 0) { + need(Size); + for (TempBuffer = Ptr - 1; TempBuffer >= Buffer; TempBuffer--) { + TempBuffer[Size] = TempBuffer[0]; + } + std::memcpy(Buffer, Str, Size); + Ptr += Size; + } +} + +char *llvm::dlangDemangle(const char *MangledName) { + OutputString Decl; + char *Demangled = nullptr; + + if (MangledName == nullptr || *MangledName == '\0') + return nullptr; + + if (strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + Decl = OutputString(); + + if (strcmp(MangledName, "_Dmain") == 0) { + Decl.append("D main"); + } + + if (Decl.getLength() > 0) { + Decl.append('\0'); + Decl.Ptr--; + Demangled = Decl.Buffer; + } + + return Demangled; +} + +/* vim: set ts=2 sw=2 expandtab */ Index: llvm/lib/Demangle/Demangle.cpp =================================================================== --- llvm/lib/Demangle/Demangle.cpp +++ llvm/lib/Demangle/Demangle.cpp @@ -24,12 +24,19 @@ MangledName[1] == 'R'; } +static bool isDLangEncoding(const std::string &MangledName) { + return MangledName.size() >= 2 && MangledName[0] == '_' && + MangledName[1] == 'D'; +} + std::string llvm::demangle(const std::string &MangledName) { char *Demangled; if (isItaniumEncoding(MangledName)) Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); else if (isRustEncoding(MangledName)) Demangled = rustDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); + else if (isDLangEncoding(MangledName)) + Demangled = dlangDemangle(MangledName.c_str()); else Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr, nullptr); Index: llvm/unittests/Demangle/CMakeLists.txt =================================================================== --- llvm/unittests/Demangle/CMakeLists.txt +++ llvm/unittests/Demangle/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_unittest(DemangleTests DemangleTest.cpp + DLangDemangleTest.cpp ItaniumDemangleTest.cpp OutputStreamTest.cpp PartialDemangleTest.cpp Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -0,0 +1,34 @@ +//===------------------ DLangDemangleTest.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Testing input ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include + +TEST(DLangDemangle, Success) { + struct ExpectedVal { + const char *Mangled; + const char *Expected; + }; + + ExpectedVal ExpectedArray[] = { + {"_Dmain", "D main"} + }; + + for (ExpectedVal Val : ExpectedArray) { + char *Demangled = llvm::dlangDemangle(Val.Mangled); + EXPECT_STREQ(Demangled, Val.Expected); + std::free(Demangled); + } +}