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) { QString trace = QString::fromUtf8(strings.data()[0]);
int numberPrinted = 0; QRegularExpressionMatch m = rx.match(trace);
for (int i = 0; i < n && numberPrinted < frameCount; ++i) { if (!m.hasMatch())
QScopedPointer<char*, QScopedPointerPodDeleter> strings(backtrace_symbols(buffer.data() + i, 1)); return {};
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);
// skip the trace from QtCore that are because of the qDebug itself QString library = m.captured(1);
if (!numberPrinted && library.contains(QLatin1String("Qt6Core")) QString function = m.captured(2);
&& (function.isEmpty() || function.contains(QLatin1String("Message"), Qt::CaseInsensitive)
|| function.contains(QLatin1String("QDebug")))) {
continue;
}
if (function.startsWith(QLatin1String("_Z"))) { // skip the trace from QtCore that are because of the qDebug itself
QScopedPointer<char, QScopedPointerPodDeleter> demangled( if (shouldSkipFrame(library, function))
abi::__cxa_demangle(function.toUtf8(), nullptr, nullptr, nullptr)); return {};
if (demangled)
function = QString::fromUtf8(qCleanupFuncinfo(demangled.data()));
}
if (function.isEmpty()) { function = demangled(function);
result.append(QLatin1Char('?') + library + QLatin1Char('?')); return { library, function };
} else { };
result.append(function);
} for (void *&addr : buffer) {
} else { DecodedFrame frame = decodeFrame(addr);
if (numberPrinted == 0) { if (!frame.library.isEmpty()) {
// innermost, unknown frames are usually the logging framework itself if (frame.function.isEmpty())
continue; 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("???")); result.append(QStringLiteral("???"));
}
numberPrinted++;
} }
if (result.size() == frameCount)
break;
} }
return result; return result;
} }