From 1282fc4c14bddf99a0c0ce93dc3970b3c1df3f32 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Sat, 5 Dec 2015 23:30:28 +0000 Subject: [PATCH] refs #540 Add the ability to capture the current call stack, and use it in singleShot. --- mkspecs/features/common_pre.prf | 6 +++ src/blackmisc/blackmisc.pro | 2 +- src/blackmisc/stacktrace.cpp | 95 +++++++++++++++++++++++++++++++++ src/blackmisc/stacktrace.h | 26 +++++++++ src/blackmisc/worker.h | 3 ++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/blackmisc/stacktrace.cpp create mode 100644 src/blackmisc/stacktrace.h diff --git a/mkspecs/features/common_pre.prf b/mkspecs/features/common_pre.prf index 23c006466..80cdb5ae5 100644 --- a/mkspecs/features/common_pre.prf +++ b/mkspecs/features/common_pre.prf @@ -86,6 +86,12 @@ win32-g++: QMAKE_CXXFLAGS_DEBUG += -Og equals(WORD_SIZE,64)|!win32: BLACK_CONFIG -= FSX FS9 +################################ +# For BlackMisc::getStackTrace +################################ + +linux-g++: QMAKE_LFLAGS_DEBUG *= -rdynamic + ################################ # Suppress stupid warnings ################################ diff --git a/src/blackmisc/blackmisc.pro b/src/blackmisc/blackmisc.pro index 37aa74995..e1d64aef1 100644 --- a/src/blackmisc/blackmisc.pro +++ b/src/blackmisc/blackmisc.pro @@ -57,7 +57,7 @@ SOURCES += *.cpp \ $$PWD/weather/*.cpp win32 { - LIBS *= -lShell32 + LIBS *= -lShell32 -lDbghelp } DESTDIR = $$DestRoot/lib diff --git a/src/blackmisc/stacktrace.cpp b/src/blackmisc/stacktrace.cpp new file mode 100644 index 000000000..f885ae24c --- /dev/null +++ b/src/blackmisc/stacktrace.cpp @@ -0,0 +1,95 @@ +/* Copyright (C) 2015 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "blackmisc/stacktrace.h" +#include +#include +#if defined(Q_OS_WIN32) +# include +# pragma warning(push) +# pragma warning(disable:4091) +# include +# pragma warning(pop) +#elif defined(Q_CC_GNU) +# include +#endif + +namespace BlackMisc +{ + +#if defined(QT_NO_DEBUG) + QStringList getStackTrace() + { + return { "No stack trace with release build" }; + } +#elif defined(Q_OS_WIN32) + QStringList getStackTrace() + { + static QMutex mutex; + QMutexLocker lock(&mutex); + + auto process = GetCurrentProcess(); + SymInitialize(process, nullptr, true); + + std::array stack; + auto frames = CaptureStackBackTrace(1, static_cast(stack.size()), stack.data(), nullptr); + + struct + { + SYMBOL_INFO info; + std::array name; + } symbol; + symbol.info.MaxNameLen = static_cast(symbol.name.size() - 1); + symbol.info.SizeOfStruct = sizeof(symbol.info); + + QStringList result; + for (int i = 0; i < frames; ++i) + { + DWORD displacement = 0; + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(line); + SymFromAddr(process, reinterpret_cast(stack[i]), nullptr, &symbol.info); + SymGetLineFromAddr64(process, reinterpret_cast(stack[i]), &displacement, &line); + + result.push_back(QString(symbol.info.Name) + " line " + QString::number(line.LineNumber)); + } + return result; + } +#elif defined(Q_CC_GNU) + QStringList getStackTrace() + { + std::array stack; + auto frames = backtrace(stack.data(), stack.size()); + auto *symbols = backtrace_symbols(stack.data(), frames); + + QStringList result; + QString symbol; + char *demangled = nullptr; + size_t size = 0; + for (int i = 0; i < frames; ++i) + { + symbol = symbols[i]; + int end = symbol.indexOf(' '); + if (end > 0) { symbol.truncate(end); } + + demangled = abi::__cxa_demangle(qPrintable(symbol), demangled, &size, nullptr); + result.push_back(demangled); + } + free(symbols); + free(demangled); + return result; + } +#else + QStringList getStackTrace() + { + return { "No stack trace on this platform" }; + } +#endif + +} diff --git a/src/blackmisc/stacktrace.h b/src/blackmisc/stacktrace.h new file mode 100644 index 000000000..e2a0bc342 --- /dev/null +++ b/src/blackmisc/stacktrace.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2015 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_STACKTRACE_H +#define BLACKMISC_STACKTRACE_H + +#include "blackmisc/blackmiscexport.h" +#include + +namespace BlackMisc +{ + /*! + * Returns a stack trace of the current thread of execution as a list of function names. + */ + BLACKMISC_EXPORT QStringList getStackTrace(); +} + +#endif diff --git a/src/blackmisc/worker.h b/src/blackmisc/worker.h index a3b382686..54ace1467 100644 --- a/src/blackmisc/worker.h +++ b/src/blackmisc/worker.h @@ -14,6 +14,7 @@ #include "blackmiscexport.h" #include "variant.h" +#include "stacktrace.h" #include #include #include @@ -53,8 +54,10 @@ namespace BlackMisc auto *timer = new QTimer; timer->setSingleShot(true); timer->moveToThread(target); + auto trace = getStackTrace(); QObject::connect(timer, &QTimer::timeout, [ = ]() { + static_cast(trace); task(); timer->deleteLater(); });