summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2024-02-24 17:45:21 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2024-04-18 15:42:27 +0200
commit1025ff1bf4f6fe60431c16e7ceb73cce2d4b9464 (patch)
tree7ef9e9ed292f8e2093abedb48a0c939d495b7b59
parentcba15d99f0cfd59ccc962f1d40168c4dca17776e (diff)
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>
-rw-r--r--src/corelib/configure.cmake24
-rw-r--r--src/corelib/global/qlogging.cpp75
-rw-r--r--src/corelib/global/qlogging_p.h23
3 files changed, 114 insertions, 8 deletions
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 58329d3b8f..80e6d93193 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -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)
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 71579ca08a..dec16e4a77 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -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.
diff --git a/src/corelib/global/qlogging_p.h b/src/corelib/global/qlogging_p.h
index 9df53333cb..bc331c80c0 100644
--- a/src/corelib/global/qlogging_p.h
+++ b/src/corelib/global/qlogging_p.h
@@ -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)