/* 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. 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 #include #include #include #include #include #include #if defined(Q_CC_MSVC) # include # pragma warning(push) # pragma warning(disable:4091) # include # pragma warning(pop) #elif defined(Q_OS_WIN) && defined (Q_CC_GNU) # include # include #elif defined(Q_CC_GNU) # include # include # include #endif namespace BlackMisc { #if defined(QT_DEBUG) QStringList getStackTrace() { return getStackTraceAlways(); } #else QStringList getStackTrace() { return { "No stack trace with release build" }; } #endif #if defined(Q_OS_WIN32) QStringList getStackTraceAlways() { static QMutex mutex; QMutexLocker lock(&mutex); static std::once_flag flag; std::call_once(flag, [] { SymInitialize(GetCurrentProcess(), nullptr, true); std::atexit([] { SymCleanup(GetCurrentProcess()); }); }); auto process = GetCurrentProcess(); SymRefreshModuleList(process); 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(QLatin1String(symbol.info.Name) % u" line " % QString::number(line.LineNumber)); } return result; } #elif defined(Q_CC_GNU) QStringList getStackTraceAlways() { std::array stack; auto frames = backtrace(stack.data(), stack.size()); auto *symbols = backtrace_symbols(stack.data(), frames); QStringList result; char *demangled = nullptr; size_t size = 0; for (int i = 0; i < frames; ++i) { // Using C string functions to avoid unnecessary dynamic memory allocation auto *basename = std::strrchr(symbols[i], '/'); if (! basename) { continue; } basename++; auto *symbol = std::strchr(basename, '('); if (! symbol) { continue; } auto *basenameEnd = symbol++; auto *end = std::strrchr(symbol, ')'); if (! end) { continue; } auto *offset = std::strrchr(symbol, '+'); auto *symbolEnd = offset ? offset++ : end; auto *temp = demangled; // avoid leaking memory if __cxa_demangle returns nullptr demangled = abi::__cxa_demangle(QByteArray(symbol, symbolEnd - symbol).constData(), demangled, &size, nullptr); if (demangled) { result.push_back(QLatin1String(demangled) % u' ' % u'(' % QLatin1String(basename, basenameEnd - basename) % u' ' % QLatin1String(symbol, end - symbol) % u')'); } else { result.push_back(u'(' % QLatin1String(basename, basenameEnd - basename) % u' ' % QLatin1String(symbol, end - symbol) % u')'); demangled = temp; } } free(symbols); free(demangled); return result; } #else // cppcheck-suppress unusedFunction QStringList getStackTraceAlways() { return { "No stack trace on this platform" }; } #endif }