diff options
author | Lieven Hey <lieven.hey@kdab.com> | 2021-09-15 14:57:23 +0200 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2022-06-08 20:17:56 +0000 |
commit | e50bc913563e445888f08de03007ff91bcd5dd1e (patch) | |
tree | bef0a5d27399ca21c7e10ff172671948de7b44c0 | |
parent | f2e019928c5f6449724319f08bd5f0d8a1532ad1 (diff) |
add support for d symbol demangling
I added a system that simplifies adding new demanglers and provides a
fast path when demangling symbols
Change-Id: Ie5ca43632b53e41c0a4214772193af09ca4593cc
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | app/CMakeLists.txt | 1 | ||||
-rw-r--r-- | app/demangler.cpp | 79 | ||||
-rw-r--r-- | app/demangler.h | 44 | ||||
-rw-r--r-- | app/perfdwarfdiecache.cpp | 32 | ||||
-rw-r--r-- | cmake/FindLibDDemangle.cmake | 22 | ||||
-rw-r--r-- | tests/auto/perfdata/perfdata.pro | 6 | ||||
-rw-r--r-- | tests/auto/perfdata/perfdata.qbs | 2 |
8 files changed, 163 insertions, 30 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d379096..3038294 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,5 +15,12 @@ set_package_properties(LibRustcDemangle PROPERTIES URL "https://github.com/alexcrichton/rustc-demangle" TYPE RUNTIME) +find_package(LibDDemangle) +set_package_properties(LibDDemangle PROPERTIES + DESCRIPTION "Demangling for D symbols, written in D." + PURPOSE "Demangling of D symbols" + URL "https://github.com/lievenhey/d_demangler" + TYPE RUNTIME) + add_subdirectory(app) add_subdirectory(tests) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 6efe84b..4107a11 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -22,6 +22,7 @@ add_qtc_library(perfparser_lib STATIC perftracingdata.cpp perftracingdata.h perfdwarfdiecache.cpp perfdwarfdiecache.h perfeucompat.h + demangler.cpp demangler.h ) if (Zstd_FOUND) diff --git a/app/demangler.cpp b/app/demangler.cpp new file mode 100644 index 0000000..ce9d630 --- /dev/null +++ b/app/demangler.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Lieven Hey <lieven.hey@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Enterprise Perf Profiler Add-on. +** +** GNU General Public License Usage +** This file may be used under the terms of the GNU General Public License +** version 3 as published by the Free Software Foundation and appearing in +** the file LICENSE.GPLv3 included in the packaging of this file. Please +** review the following information to ensure the GNU General Public License +** requirements will be met: https://www.gnu.org/licenses/gpl.html. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "demangler.h" + +#include <QLibrary> +#include <QDebug> + +/* Demangler specification + * int demangler(const char* mangledSymbol, char* demangledBuffer, size_t bufferSize) + * + * size_t is platform dependent (4 bytes on 32 bit, 8 bytes on 64 bit) + * */ + +namespace { +bool startsWith(const char* string, const QByteArray& prefix) { + return strcmp(string, prefix.constData()) == 0; +} +} + +Demangler::Demangler() +{ + loadDemangleLib(QStringLiteral("rustc_demangle"), "rustc_demangle", QByteArrayLiteral("_R")); + loadDemangleLib(QStringLiteral("d_demangle"), "demangle_symbol", QByteArrayLiteral("_D")); +} + +bool Demangler::demangle(const char *mangledSymbol, char *demangleBuffer, size_t demangleBufferLength) +{ + // fast path, some languages (like rust since 1.37 or d) share a common prefix + // try these first + for (const auto& demangler : m_demanglers) { + if (startsWith(mangledSymbol, demangler.prefix)) { + if (demangler.demangler(mangledSymbol, demangleBuffer, demangleBufferLength)) { + return true; + } + } + } + + for (const auto& demangler : m_demanglers) { + if (demangler.demangler(mangledSymbol, demangleBuffer, demangleBufferLength)) { + return true; + } + } + return false; +} + +void Demangler::loadDemangleLib(const QString &name, const char* function, const QByteArray& prefix) +{ + QLibrary lib(name); + if (!lib.load()) { + qDebug() << QStringLiteral("failed to load %1 library").arg(name) + << lib.errorString(); + return; + } + const auto rawSymbol = lib.resolve(function); + if (!rawSymbol) { + qDebug() << QStringLiteral("failed to resolve %1 function in library").arg(function) + << lib.fileName() << lib.errorString(); + return; + } + + m_demanglers.push_back({prefix, reinterpret_cast<Demangler::demangler_t>(rawSymbol)}); +} diff --git a/app/demangler.h b/app/demangler.h new file mode 100644 index 0000000..edb1244 --- /dev/null +++ b/app/demangler.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Lieven Hey <lieven.hey@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Enterprise Perf Profiler Add-on. +** +** GNU General Public License Usage +** This file may be used under the terms of the GNU General Public License +** version 3 as published by the Free Software Foundation and appearing in +** the file LICENSE.GPLv3 included in the packaging of this file. Please +** review the following information to ensure the GNU General Public License +** requirements will be met: https://www.gnu.org/licenses/gpl.html. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef DEMANGLER_H +#define DEMANGLER_H + +#include <QVector> + +class Demangler +{ +public: + Demangler(); + + bool demangle(const char* mangledSymbol, char* demangleBuffer, size_t demangleBufferLength); + +private: + void loadDemangleLib(const QString& name, const char* function, const QByteArray& prefix); + + using demangler_t = int (*) (const char*, char *, size_t); + struct DemangleInfo { + QByteArray prefix; + demangler_t demangler; + }; + + QVector<DemangleInfo> m_demanglers; +}; + +#endif // DEMANGLER_H diff --git a/app/perfdwarfdiecache.cpp b/app/perfdwarfdiecache.cpp index dfc6f90..6f9243f 100644 --- a/app/perfdwarfdiecache.cpp +++ b/app/perfdwarfdiecache.cpp @@ -24,35 +24,9 @@ #include <dwarf.h> -#include <QLibrary> -#include <QDebug> +#include "demangler.h" namespace { -bool rustc_demangle(const char *symbol, char *buffer, size_t bufferSize) -{ - using demangler_t = int (*) (const char*, char *, size_t); - static const auto demangler = []() -> demangler_t { - QLibrary lib(QStringLiteral("rustc_demangle")); - if (!lib.load()) { - qDebug() << "failed to load rustc_demangle library, rust demangling support is not available." - << lib.errorString(); - return nullptr; - } - const auto rawSymbol = lib.resolve("rustc_demangle"); - if (!rawSymbol) { - qDebug() << "failed to resolve rustc_demangle function in library" - << lib.fileName() << lib.errorString(); - return nullptr; - } - return reinterpret_cast<demangler_t>(rawSymbol); - }(); - - if (demangler) - return demangler(symbol, buffer, bufferSize); - else - return false; -} - enum class WalkResult { Recurse, @@ -252,9 +226,11 @@ QByteArray demangle(const QByteArray &mangledName) } else { static size_t demangleBufferLength = 1024; static char *demangleBuffer = reinterpret_cast<char *>(eu_compat_malloc(demangleBufferLength)); + static Demangler demangler; - if (rustc_demangle(mangledName.constData(), demangleBuffer, demangleBufferLength)) + if (demangler.demangle(mangledName, demangleBuffer, demangleBufferLength)) { return demangleBuffer; + } // Require GNU v3 ABI by the "_Z" prefix. if (mangledName[0] == '_' && mangledName[1] == 'Z') { diff --git a/cmake/FindLibDDemangle.cmake b/cmake/FindLibDDemangle.cmake new file mode 100644 index 0000000..04f0ecc --- /dev/null +++ b/cmake/FindLibDDemangle.cmake @@ -0,0 +1,22 @@ +if (LIBD_DEMANGLE_LIBRARIES) + set (LibDDemangle_FIND_QUIETLY TRUE) +endif() + +find_library(LIBD_DEMANGLE_LIBRARIES + NAMES + d_demangle + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ENV LIBRARY_PATH + ENV LD_LIBRARY_PATH) + +include (FindPackageHandleStandardArgs) + +# handle the QUIETLY and REQUIRED arguments and set LIBRUSTC_DEMANGLE_FOUND to TRUE if all listed variables are TRUE +find_package_handle_standard_args(LibDDemangle DEFAULT_MSG + LIBD_DEMANGLE_LIBRARIES) + +mark_as_advanced(LIBD_DEMANGLE_LIBRARIES) diff --git a/tests/auto/perfdata/perfdata.pro b/tests/auto/perfdata/perfdata.pro index 145ed79..2e32aa6 100644 --- a/tests/auto/perfdata/perfdata.pro +++ b/tests/auto/perfdata/perfdata.pro @@ -24,7 +24,8 @@ SOURCES += \ ../../../app/perfsymboltable.cpp \ ../../../app/perftracingdata.cpp \ ../../../app/perfunwind.cpp \ - ../../../app/perfdwarfdiecache.cpp + ../../../app/perfdwarfdiecache.cpp \ + ../../../app/demangle.cpp HEADERS += \ ../../../app/perfaddresscache.h \ @@ -39,7 +40,8 @@ HEADERS += \ ../../../app/perfsymboltable.h \ ../../../app/perftracingdata.h \ ../../../app/perfunwind.h \ - ../../../app/perfdwarfdiecache.h + ../../../app/perfdwarfdiecache.h \ + ../../../app/demangle.h RESOURCES += \ perfdata.qrc diff --git a/tests/auto/perfdata/perfdata.qbs b/tests/auto/perfdata/perfdata.qbs index ef9bb3d..033a0a3 100644 --- a/tests/auto/perfdata/perfdata.qbs +++ b/tests/auto/perfdata/perfdata.qbs @@ -37,5 +37,7 @@ QtcAutotest { "../../../app/perftracingdata.h", "../../../app/perfunwind.cpp", "../../../app/perfunwind.h", + "../../../app/demangle.cpp", + "../../../app/demangle.h" ] } |