Logging: add support for decoding backtraces using dladdr()

I'm pretty sure that's what backtrace_symbols() uses internally anyway,
so skip the middle-man.

Change-Id: Ic15405335d804bdea761fffd16d4fb2a1b0c2171
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Thiago Macieira 2022-02-18 12:25:22 -08:00
parent 1cad4ed6a1
commit ff2535de5c
2 changed files with 54 additions and 2 deletions

View File

@ -176,6 +176,23 @@ std::filesystem::copy(
"
)
# dladdr
qt_config_compile_test(dladdr
LABEL "dladdr"
LIBRARIES
dl
CODE
"#define _GNU_SOURCE 1
#include <dlfcn.h>
int i = 0;
int main(void)
{
Dl_info info;
dladdr(&i, &info);
return 0;
}"
)
# eventfd
qt_config_compile_test(eventfd
LABEL "eventfd"
@ -543,6 +560,10 @@ qt_feature("cxx17_filesystem" PUBLIC
LABEL "C++17 <filesystem>"
CONDITION TEST_cxx17_filesystem
)
qt_feature("dladdr" PRIVATE
LABEL "dladdr"
CONDITION QT_FEATURE_dlopen AND TEST_dladdr
)
qt_feature("eventfd" PUBLIC
LABEL "eventfd"
CONDITION NOT WASM AND TEST_eventfd

View File

@ -109,6 +109,9 @@ extern char *__progname;
#ifndef QT_BOOTSTRAPPED
#if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace) && QT_CONFIG(regularexpression)
# include <qregularexpression.h>
# if QT_CONFIG(dladdr)
# include <dlfcn.h>
# endif
# include BACKTRACE_HEADER
# include <cxxabi.h>
# define QLOGGING_HAVE_BACKTRACE
@ -1310,12 +1313,17 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
return false;
};
auto demangled = [](QString &function) {
auto demangled = [](auto &function) -> QString {
if (!function.startsWith(QLatin1String("_Z")))
return function;
// we optimize for the case where __cxa_demangle succeeds
QByteArray fn = std::move(function).toUtf8();
auto fn = [&]() {
if constexpr (sizeof(function.at(0)) == 1)
return function.data(); // -> const char *
else
return std::move(function).toUtf8(); // -> QByteArray
}();
QScopedPointer<char, QScopedPointerPodDeleter> demangled;
demangled.reset(abi::__cxa_demangle(fn, nullptr, nullptr, nullptr));
@ -1325,7 +1333,29 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
return QString::fromUtf8(fn); // restore
};
# if QT_CONFIG(dladdr)
// use dladdr() instead of backtrace_symbols()
auto decodeFrame = [&](const void *addr) -> DecodedFrame {
Dl_info info;
if (!dladdr(addr, &info))
return {};
// These are actually UTF-8, so we'll correct below
QLatin1String fn(info.dli_sname);
QLatin1String lib;
if (const char *lastSlash = strrchr(info.dli_fname, '/'))
lib = QLatin1String(lastSlash + 1);
else
lib = QLatin1String(info.dli_fname);
if (shouldSkipFrame(lib, fn))
return {};
QString library = QString::fromUtf8(lib.data(), lib.size());
QString function = demangled(fn);
return { library, function };
};
# else
// The results of backtrace_symbols looks like this:
// /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
// The offset and function name are optional.
@ -1350,6 +1380,7 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
function = demangled(function);
return { library, function };
};
# endif
for (void *&addr : buffer) {
DecodedFrame frame = decodeFrame(addr);