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:
parent
ee7166e176
commit
1cad4ed6a1
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user