Logging: reorganize the backtrace code for simplicity and readability

Also removed the Qt::CaseInsensitive searching, which was slow.

Change-Id: Ic15405335d804bdea761fffd16d4f863847c360b
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Thiago Macieira 2022-02-18 11:34:30 -08:00
parent ee7166e176
commit 1cad4ed6a1

View File

@ -1283,10 +1283,49 @@ __attribute__((optimize("omit-frame-pointer")))
#endif #endif
static QStringList backtraceFramesForLogMessage(int frameCount) static QStringList backtraceFramesForLogMessage(int frameCount)
{ {
struct DecodedFrame {
QString library;
QString function;
};
QStringList result; QStringList result;
if (frameCount == 0) if (frameCount == 0)
return result; return result;
QVarLengthArray<void *, 32> 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<char, QScopedPointerPodDeleter> 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: // The results of backtrace_symbols looks like this:
// /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] // /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
// The offset and function name are optional. // 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 // 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]*\\]$")); static const QRegularExpression rx(QStringLiteral("^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
QVarLengthArray<void *, 32> buffer(TypicalBacktraceFrameCount + frameCount); auto decodeFrame = [&](void *&addr) -> DecodedFrame {
int n = backtrace(buffer.data(), buffer.size()); QScopedPointer<char*, QScopedPointerPodDeleter> strings(backtrace_symbols(&addr, 1));
if (n > 0) {
int numberPrinted = 0;
for (int i = 0; i < n && numberPrinted < frameCount; ++i) {
QScopedPointer<char*, QScopedPointerPodDeleter> strings(backtrace_symbols(buffer.data() + i, 1));
QString trace = QString::fromUtf8(strings.data()[0]); QString trace = QString::fromUtf8(strings.data()[0]);
QRegularExpressionMatch m = rx.match(trace); QRegularExpressionMatch m = rx.match(trace);
if (m.hasMatch()) { if (!m.hasMatch())
return {};
QString library = m.captured(1); QString library = m.captured(1);
QString function = m.captured(2); QString function = m.captured(2);
// skip the trace from QtCore that are because of the qDebug itself // skip the trace from QtCore that are because of the qDebug itself
if (!numberPrinted && library.contains(QLatin1String("Qt6Core")) if (shouldSkipFrame(library, function))
&& (function.isEmpty() || function.contains(QLatin1String("Message"), Qt::CaseInsensitive) return {};
|| function.contains(QLatin1String("QDebug")))) {
continue;
}
if (function.startsWith(QLatin1String("_Z"))) { function = demangled(function);
QScopedPointer<char, QScopedPointerPodDeleter> demangled( return { library, function };
abi::__cxa_demangle(function.toUtf8(), nullptr, nullptr, nullptr)); };
if (demangled)
function = QString::fromUtf8(qCleanupFuncinfo(demangled.data()));
}
if (function.isEmpty()) { for (void *&addr : buffer) {
result.append(QLatin1Char('?') + library + QLatin1Char('?')); DecodedFrame frame = decodeFrame(addr);
if (!frame.library.isEmpty()) {
if (frame.function.isEmpty())
result.append(QLatin1Char('?') + frame.library + QLatin1Char('?'));
else
result.append(frame.function);
} else { } else {
result.append(function);
}
} else {
if (numberPrinted == 0) {
// innermost, unknown frames are usually the logging framework itself // innermost, unknown frames are usually the logging framework itself
continue; if (!result.isEmpty())
}
result.append(QStringLiteral("???")); result.append(QStringLiteral("???"));
} }
numberPrinted++;
} if (result.size() == frameCount)
break;
} }
return result; return result;
} }