From 1cad4ed6a1f3e5f091f7bf1cb9998383d226a4b2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 18 Feb 2022 11:34:30 -0800 Subject: [PATCH] Logging: reorganize the backtrace code for simplicity and readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also removed the Qt::CaseInsensitive searching, which was slow. Change-Id: Ic15405335d804bdea761fffd16d4f863847c360b Reviewed-by: Tor Arne Vestbø --- src/corelib/global/qlogging.cpp | 102 +++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 11a43f73efc..8eaade62474 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1283,10 +1283,49 @@ __attribute__((optimize("omit-frame-pointer"))) #endif static QStringList backtraceFramesForLogMessage(int frameCount) { + struct DecodedFrame { + QString library; + QString function; + }; + QStringList result; if (frameCount == 0) return result; + QVarLengthArray buffer(TypicalBacktraceFrameCount + frameCount); + int n = backtrace(buffer.data(), buffer.size()); + if (n <= 0) + return result; + buffer.resize(n); + + auto shouldSkipFrame = [&result](const auto &library, const auto &function) { + if (!result.isEmpty() || !library.contains(QLatin1String("Qt6Core"))) + return false; + if (function.isEmpty()) + return true; + if (function.contains(QLatin1String("6QDebug"))) + return true; + if (function.contains(QLatin1String("Message")) || function.contains(QLatin1String("_message"))) + return true; + return false; + }; + + auto demangled = [](QString &function) { + if (!function.startsWith(QLatin1String("_Z"))) + return function; + + // we optimize for the case where __cxa_demangle succeeds + QByteArray fn = std::move(function).toUtf8(); + QScopedPointer demangled; + demangled.reset(abi::__cxa_demangle(fn, nullptr, nullptr, nullptr)); + + if (demangled) + return QString::fromUtf8(qCleanupFuncinfo(demangled.data())); + else + return QString::fromUtf8(fn); // restore + }; + + // The results of backtrace_symbols looks like this: // /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] // The offset and function name are optional. @@ -1294,46 +1333,39 @@ static QStringList backtraceFramesForLogMessage(int frameCount) // This code is protected by QMessagePattern::mutex so it is thread safe on all compilers static const QRegularExpression rx(QStringLiteral("^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$")); - QVarLengthArray buffer(TypicalBacktraceFrameCount + frameCount); - int n = backtrace(buffer.data(), buffer.size()); - if (n > 0) { - int numberPrinted = 0; - for (int i = 0; i < n && numberPrinted < frameCount; ++i) { - QScopedPointer strings(backtrace_symbols(buffer.data() + i, 1)); - QString trace = QString::fromUtf8(strings.data()[0]); - QRegularExpressionMatch m = rx.match(trace); - if (m.hasMatch()) { - QString library = m.captured(1); - QString function = m.captured(2); + auto decodeFrame = [&](void *&addr) -> DecodedFrame { + QScopedPointer strings(backtrace_symbols(&addr, 1)); + QString trace = QString::fromUtf8(strings.data()[0]); + QRegularExpressionMatch m = rx.match(trace); + if (!m.hasMatch()) + return {}; - // skip the trace from QtCore that are because of the qDebug itself - if (!numberPrinted && library.contains(QLatin1String("Qt6Core")) - && (function.isEmpty() || function.contains(QLatin1String("Message"), Qt::CaseInsensitive) - || function.contains(QLatin1String("QDebug")))) { - continue; - } + QString library = m.captured(1); + QString function = m.captured(2); - if (function.startsWith(QLatin1String("_Z"))) { - QScopedPointer demangled( - abi::__cxa_demangle(function.toUtf8(), nullptr, nullptr, nullptr)); - if (demangled) - function = QString::fromUtf8(qCleanupFuncinfo(demangled.data())); - } + // skip the trace from QtCore that are because of the qDebug itself + if (shouldSkipFrame(library, function)) + return {}; - if (function.isEmpty()) { - result.append(QLatin1Char('?') + library + QLatin1Char('?')); - } else { - result.append(function); - } - } else { - if (numberPrinted == 0) { - // innermost, unknown frames are usually the logging framework itself - continue; - } + function = demangled(function); + return { library, function }; + }; + + for (void *&addr : buffer) { + DecodedFrame frame = decodeFrame(addr); + if (!frame.library.isEmpty()) { + if (frame.function.isEmpty()) + result.append(QLatin1Char('?') + frame.library + QLatin1Char('?')); + else + result.append(frame.function); + } else { + // innermost, unknown frames are usually the logging framework itself + if (!result.isEmpty()) result.append(QStringLiteral("???")); - } - numberPrinted++; } + + if (result.size() == frameCount) + break; } return result; }