Skip to content

Commit

Permalink
add support for d symbol demangling
Browse files Browse the repository at this point in the history
I added a system that simplifies adding new demanglers and provides a
fast path when demangling symbols

Change-Id: Ie5ca43632b53e41c0a4214772193af09ca4593cc
Reviewed-by: Ulf Hermann <[email protected]>
  • Loading branch information
lievenhey authored and milianw committed Jun 8, 2022
1 parent f2e0199 commit e50bc91
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 30 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
79 changes: 79 additions & 0 deletions app/demangler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected], author Lieven Hey <[email protected]>
** 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)});
}
44 changes: 44 additions & 0 deletions app/demangler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/****************************************************************************
**
** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected], author Lieven Hey <[email protected]>
** 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
32 changes: 4 additions & 28 deletions app/perfdwarfdiecache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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') {
Expand Down
22 changes: 22 additions & 0 deletions cmake/FindLibDDemangle.cmake
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 4 additions & 2 deletions tests/auto/perfdata/perfdata.pro
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/auto/perfdata/perfdata.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@ QtcAutotest {
"../../../app/perftracingdata.h",
"../../../app/perfunwind.cpp",
"../../../app/perfunwind.h",
"../../../app/demangle.cpp",
"../../../app/demangle.h"
]
}

0 comments on commit e50bc91

Please sign in to comment.