QLogging: enable %{backtrace} support via <stacktrace>
C++23 gave us a standardized way to gather backtraces, so we can use it to add cross-platform support for %{backtrace}. Guard the feature via a compile test; at the moment, this is enabled it on MSVC only. GCC has experimental support (requires linking against libstdc++exp), so it will still fail the test. [ChangeLog][QtCore][QDebug] Support for the %{backtrace} expansion has been extended to the platforms supporting C++23's <stacktrace> header (such as MSVC 2022 >= 17.4). Change-Id: I04d58a193384a61e4f8e6fef78286d4bad98a025 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
cba15d99f0
commit
1025ff1bf4
@ -411,6 +411,25 @@ int main(void)
|
||||
}
|
||||
")
|
||||
|
||||
# <stacktrace>
|
||||
qt_config_compile_test(cxx23_stacktrace
|
||||
LABEL "C++23 <stacktrace> support"
|
||||
CODE
|
||||
"#include <stacktrace>
|
||||
#if !defined(__cpp_lib_stacktrace)
|
||||
#error
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* BEGIN TEST: */
|
||||
const auto backtrace = std::stacktrace::current();
|
||||
/* END TEST: */
|
||||
}
|
||||
"
|
||||
CXX_STANDARD 23
|
||||
)
|
||||
|
||||
#### Features
|
||||
|
||||
qt_feature("clock-gettime" PRIVATE
|
||||
@ -600,6 +619,10 @@ qt_feature("backtrace" PRIVATE
|
||||
LABEL "backtrace"
|
||||
CONDITION UNIX AND QT_FEATURE_regularexpression AND WrapBacktrace_FOUND
|
||||
)
|
||||
qt_feature("cxx23_stacktrace" PRIVATE
|
||||
LABEL "C++23 <stacktrace>"
|
||||
CONDITION TEST_cxx23_stacktrace AND QT_FEATURE_cxx2b
|
||||
)
|
||||
qt_feature("sharedmemory" PUBLIC
|
||||
SECTION "Kernel"
|
||||
LABEL "QSharedMemory"
|
||||
@ -876,6 +899,7 @@ qt_feature("openssl-hash" PRIVATE
|
||||
|
||||
qt_configure_add_summary_section(NAME "Qt Core")
|
||||
qt_configure_add_summary_entry(ARGS "backtrace")
|
||||
qt_configure_add_summary_entry(ARGS "cxx23_stacktrace")
|
||||
qt_configure_add_summary_entry(ARGS "doubleconversion")
|
||||
qt_configure_add_summary_entry(ARGS "system-doubleconversion")
|
||||
qt_configure_add_summary_entry(ARGS "forkfd_pidfd" CONDITION LINUX)
|
||||
|
@ -69,17 +69,19 @@
|
||||
extern char *__progname;
|
||||
#endif
|
||||
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace) && QT_CONFIG(regularexpression)
|
||||
#ifdef QLOGGING_HAVE_BACKTRACE
|
||||
# include <qregularexpression.h>
|
||||
#endif
|
||||
|
||||
#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
|
||||
# if QT_CONFIG(dladdr)
|
||||
# include <dlfcn.h>
|
||||
# endif
|
||||
# include BACKTRACE_HEADER
|
||||
# include <cxxabi.h>
|
||||
# define QLOGGING_HAVE_BACKTRACE
|
||||
#endif
|
||||
#endif // QLOGGING_USE_EXECINFO_BACKTRACE
|
||||
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
|
||||
# include <sys/syscall.h>
|
||||
|
||||
@ -1343,6 +1345,52 @@ void QMessagePattern::setPattern(const QString &pattern)
|
||||
Unfortunately, we can't know for sure if it has been.
|
||||
*/
|
||||
static constexpr int TypicalBacktraceFrameCount = 3;
|
||||
static constexpr const char *QtCoreLibraryName = "Qt" QT_STRINGIFY(QT_VERSION_MAJOR) "Core";
|
||||
|
||||
#if defined(QLOGGING_USE_STD_BACKTRACE)
|
||||
Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
|
||||
{
|
||||
assert(frameCount >= 0);
|
||||
backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
|
||||
}
|
||||
|
||||
static QStringList
|
||||
backtraceFramesForLogMessage(int frameCount,
|
||||
const QInternalMessageLogContext::BacktraceStorage &buffer)
|
||||
{
|
||||
QStringList result;
|
||||
result.reserve(buffer.size());
|
||||
|
||||
const auto shouldSkipFrame = [](QByteArrayView description)
|
||||
{
|
||||
#if defined(_MSVC_STL_VERSION)
|
||||
const auto libraryNameEnd = description.indexOf('!');
|
||||
if (libraryNameEnd != -1) {
|
||||
const auto libraryName = description.first(libraryNameEnd);
|
||||
if (!libraryName.contains(QtCoreLibraryName))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (description.contains("populateBacktrace"))
|
||||
return true;
|
||||
if (description.contains("QInternalMessageLogContext"))
|
||||
return true;
|
||||
if (description.contains("~QDebug"))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for (const auto &entry : buffer) {
|
||||
const std::string description = entry.description();
|
||||
if (result.isEmpty() && shouldSkipFrame(description))
|
||||
continue;
|
||||
result.append(QString::fromStdString(description));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
|
||||
|
||||
Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
|
||||
{
|
||||
@ -1369,7 +1417,7 @@ backtraceFramesForLogMessage(int frameCount,
|
||||
return result;
|
||||
|
||||
auto shouldSkipFrame = [&result](const auto &library, const auto &function) {
|
||||
if (!result.isEmpty() || !library.contains("Qt6Core"_L1))
|
||||
if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
|
||||
return false;
|
||||
if (function.isEmpty())
|
||||
return true;
|
||||
@ -1476,6 +1524,9 @@ backtraceFramesForLogMessage(int frameCount,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
#error "Internal error: backtrace enabled, but no way to gather backtraces available"
|
||||
#endif // QLOGGING_USE_..._BACKTRACE
|
||||
|
||||
static QString formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,
|
||||
const QMessageLogContext &ctx)
|
||||
@ -2213,8 +2264,18 @@ void qErrnoWarning(int code, const char *msg, ...)
|
||||
specified by the optional \c depth parameter (defaults to 5), and separated by the optional
|
||||
\c separator parameter (defaults to "|").
|
||||
|
||||
This expansion is available only on some platforms (currently only platfoms using glibc).
|
||||
Names are only known for exported functions. If you want to see the name of every function
|
||||
This expansion is available only on some platforms:
|
||||
|
||||
\list
|
||||
\li platforms using glibc;
|
||||
\li platforms shipping C++23's \c{<stacktrace>} header (requires compiling Qt in C++23 mode).
|
||||
\endlist
|
||||
|
||||
Depending on the platform, there are some restrictions on the function
|
||||
names printed by this expansion.
|
||||
|
||||
On some platforms,
|
||||
names are only known for exported functions. If you want to see the name of every function
|
||||
in your application, make sure your application is compiled and linked with \c{-rdynamic},
|
||||
or an equivalent of it.
|
||||
|
||||
|
@ -18,7 +18,20 @@
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include "qlogging.h"
|
||||
#include "qloggingcategory.h"
|
||||
#include "qvarlengtharray.h"
|
||||
|
||||
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(regularexpression)
|
||||
# if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace)
|
||||
# include <optional>
|
||||
# include "qvarlengtharray.h"
|
||||
# define QLOGGING_USE_EXECINFO_BACKTRACE
|
||||
# define QLOGGING_HAVE_BACKTRACE
|
||||
# elif QT_CONFIG(cxx23_stacktrace)
|
||||
# include <optional>
|
||||
# include <stacktrace>
|
||||
# define QLOGGING_USE_STD_BACKTRACE
|
||||
# define QLOGGING_HAVE_BACKTRACE
|
||||
# endif
|
||||
#endif // QT_BOOTSTRAPPED
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -32,7 +45,15 @@ class QInternalMessageLogContext : public QMessageLogContext
|
||||
{
|
||||
public:
|
||||
static constexpr int DefaultBacktraceDepth = 32;
|
||||
|
||||
#if defined(QLOGGING_USE_EXECINFO_BACKTRACE)
|
||||
using BacktraceStorage = QVarLengthArray<void *, DefaultBacktraceDepth>;
|
||||
#elif defined(QLOGGING_USE_STD_BACKTRACE)
|
||||
using BacktraceStorage = std::stacktrace;
|
||||
#else
|
||||
using BacktraceStorage = bool; // dummy
|
||||
#endif
|
||||
|
||||
std::optional<BacktraceStorage> backtrace;
|
||||
|
||||
Q_ALWAYS_INLINE QInternalMessageLogContext(const QMessageLogContext &logContext)
|
||||
|
Loading…
x
Reference in New Issue
Block a user