From 6b6358178e90d1e66c9ac2f05f9e01d5725e508f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 22 Aug 2022 15:36:42 +0200 Subject: [PATCH] Utils: print assert backtrace on windows Change-Id: Ifd9753b22641547c16fb6843dc7a3cf5f5b7c86e Reviewed-by: Christian Stenger Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Alessandro Portale --- src/libs/utils/CMakeLists.txt | 8 ++ src/libs/utils/qtcassert.cpp | 77 +++++++++++++++++++ src/libs/utils/utils.qbs | 2 + src/tools/processlauncher/CMakeLists.txt | 8 ++ src/tools/processlauncher/processlauncher.qbs | 4 +- src/tools/sdktool/CMakeLists.txt | 7 ++ src/tools/sdktool/sdktoollib.qbs | 6 +- 7 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index fa1d3611740..59987e82705 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -217,6 +217,14 @@ extend_qtc_library(Utils mimeutils.cpp ) +if (MSVC) + find_library(DbgHelpLib dbghelp) +endif() + +extend_qtc_library(Utils CONDITION MSVC + DEPENDS ${DbgHelpLib} +) + extend_qtc_library(Utils CONDITION WIN32 SOURCES touchbar/touchbar.cpp diff --git a/src/libs/utils/qtcassert.cpp b/src/libs/utils/qtcassert.cpp index 90a1de81780..2f63a3d295c 100644 --- a/src/libs/utils/qtcassert.cpp +++ b/src/libs/utils/qtcassert.cpp @@ -5,11 +5,20 @@ #include #include +#include #if defined(Q_OS_UNIX) #include #include #include +#elif defined(_MSC_VER) +#ifdef QTCREATOR_PCH_H +#define CALLBACK WINAPI +#define OUT +#define IN +#endif +#include +#include #endif namespace Utils { @@ -26,6 +35,74 @@ void dumpBacktrace(int maxdepth) for (int i = 0; i < size; ++i) qDebug() << "0x" + QByteArray::number(quintptr(bt[i]), 16) << lines[i]; free(lines); +#elif defined(_MSC_VER) + DWORD machineType; +#if defined(Q_OS_WIN64) + machineType = IMAGE_FILE_MACHINE_AMD64; +#else + return; +#endif + static QMutex mutex; + mutex.lock(); + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + CONTEXT ctx; + RtlCaptureContext(&ctx); + STACKFRAME64 frame; + memset(&frame, 0, sizeof(STACKFRAME64)); +#if defined(Q_OS_WIN64) + frame.AddrPC.Offset = ctx.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = ctx.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = ctx.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; +#endif + int depth = 0; + + static bool symbolsInitialized = false; + if (!symbolsInitialized) { + SymInitialize(process, NULL, TRUE); + SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + symbolsInitialized = true; + } + + while (StackWalk64(machineType, + process, + thread, + &frame, + &ctx, + NULL, + &SymFunctionTableAccess64, + &SymGetModuleBase64, + NULL)) { + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 displacement = 0; + if (!SymFromAddr(process, frame.AddrPC.Offset, &displacement, pSymbol)) + break; + + DWORD symDisplacement = 0; + IMAGEHLP_LINE64 lineInfo; + SymSetOptions(SYMOPT_LOAD_LINES); + + QString out = QString("%1: 0x%2 at %3") + .arg(depth) + .arg(QString::number(pSymbol->Address, 16)) + .arg(QString::fromLatin1(&pSymbol->Name[0], pSymbol->NameLen)); + if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &symDisplacement, &lineInfo)) { + out.append(QString(" at %3:%4") + .arg(QString::fromLatin1(lineInfo.FileName), + QString::number(lineInfo.LineNumber))); + } + qDebug() << out; + if (++depth == maxdepth) + break; + } + mutex.unlock(); #endif } diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index fba84763a55..8da82286b10 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -17,6 +17,8 @@ Project { libs.push("user32", "iphlpapi", "ws2_32", "shell32", "ole32"); if (qbs.toolchainType === "mingw") libs.push("uuid"); + else if (qbs.toolchainType === "msvc") + libs.push("dbghelp"); } else if (qbs.targetOS.contains("unix")) { if (!qbs.targetOS.contains("macos")) libs.push("X11"); diff --git a/src/tools/processlauncher/CMakeLists.txt b/src/tools/processlauncher/CMakeLists.txt index 3777b7d2dda..25b3b461ee2 100644 --- a/src/tools/processlauncher/CMakeLists.txt +++ b/src/tools/processlauncher/CMakeLists.txt @@ -22,3 +22,11 @@ add_qtc_executable(qtcreator_processlauncher ${UTILSDIR}/singleton.cpp ${UTILSDIR}/singleton.h ) + +if (MSVC) + find_library(DbgHelpLib dbghelp) +endif() + +extend_qtc_executable(qtcreator_processlauncher CONDITION MSVC + DEPENDS ${DbgHelpLib} +) diff --git a/src/tools/processlauncher/processlauncher.qbs b/src/tools/processlauncher/processlauncher.qbs index d52add65583..f56ff489cb5 100644 --- a/src/tools/processlauncher/processlauncher.qbs +++ b/src/tools/processlauncher/processlauncher.qbs @@ -11,7 +11,9 @@ QtcTool { Properties { condition: qbs.targetOS.contains("windows") - cpp.dynamicLibraries: "user32" + cpp.dynamicLibraries: { + return qbs.toolchainType === "msvc" ? ["user32", "dbghelp"] : ["user32"]; + } } files: [ diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt index aebe6836e0f..050940aca96 100644 --- a/src/tools/sdktool/CMakeLists.txt +++ b/src/tools/sdktool/CMakeLists.txt @@ -90,6 +90,13 @@ extend_qtc_library(sdktoolLib CONDITION APPLE ${FWFoundation} ) +if (MSVC) + find_library(DbgHelpLib dbghelp) +endif() + +extend_qtc_library(sdktoolLib CONDITION MSVC + DEPENDS ${DbgHelpLib} +) extend_qtc_library(sdktoolLib CONDITION WIN32 PUBLIC_DEPENDS user32 iphlpapi ws2_32 shell32 diff --git a/src/tools/sdktool/sdktoollib.qbs b/src/tools/sdktool/sdktoollib.qbs index 520bcb7197f..4352c1f6c06 100644 --- a/src/tools/sdktool/sdktoollib.qbs +++ b/src/tools/sdktool/sdktoollib.qbs @@ -24,8 +24,12 @@ QtcLibrary { return defines; } cpp.dynamicLibraries: { + var libs = []; if (qbs.targetOS.contains("windows")) - return ["user32", "shell32"] + libs.push("user32", "shell32"); + if (qbs.toolchainType === "msvc") + libs.push("dbghelp"); + return libs; } Properties { condition: qbs.targetOS.contains("macos")