diff --git a/src/app/stacktrace_win.h b/src/app/stacktrace_win.h index 55e9494c1..ca86ebd9d 100644 --- a/src/app/stacktrace_win.h +++ b/src/app/stacktrace_win.h @@ -25,6 +25,7 @@ #include #include +#include #include #ifdef __MINGW32__ #include @@ -41,6 +42,9 @@ namespace straceWin #ifdef __MINGW32__ void demangle(QString& str); #endif + + QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr); + bool makeRelativePath(const QString& dir, QString& file); } #ifdef __MINGW32__ @@ -108,6 +112,65 @@ BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVO } +/** +* Cuts off leading 'dir' path from 'file' path, otherwise leaves it unchanged +* returns true if 'dir' is an ancestor of 'file', otherwise - false +*/ +bool straceWin::makeRelativePath(const QString& dir, QString& file) +{ + QString d = QDir::toNativeSeparators(QDir(dir).absolutePath()); + QString f = QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()); + + // append separator at the end of dir + QChar separator = QDir::separator(); + if (!d.isEmpty() && (d[d.length() - 1] != separator)) + d += separator; + + if (f.startsWith(d, Qt::CaseInsensitive)) { + f.remove(0, d.length()); + file.swap(f); + + return true; + } + + return false; +} + +QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr) +{ + IMAGEHLP_LINE64 line = {0}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + DWORD dwDisplacement = 0; + + if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line)) { + QString path(line.FileName); + +#if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH + +#define STACKTRACE_WIN_QUOTE(x) #x +#define STACKTRACE_WIN_STRING(x) STACKTRACE_WIN_QUOTE(x) + + //prune leading project directory path or build target directory path + + bool success = false; +#ifdef STACKTRACE_WIN_PROJECT_PATH + QString projectPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH)); + success = makeRelativePath(projectPath, path); +#endif + +#ifdef STACKTRACE_WIN_MAKEFILE_PATH + if (!success) { + QString targetPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH)); + makeRelativePath(targetPath, path); + } +#endif +#endif + return QString("%1 : %2").arg(path).arg(line.LineNumber); + } + + return QString(); +} + #if defined( _M_IX86 ) && defined(Q_CC_MSVC) // Disable global optimization and ignore /GS waning caused by @@ -221,11 +284,16 @@ const QString straceWin::getBacktrace() fileName = fileName.mid(slashPos + 1); } QString funcName; + QString sourceFile; if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) { funcName = QString(pSymbol->Name); #ifdef __MINGW32__ demangle(funcName); #endif + + // now ihsf.InstructionOffset points to the instruction that follows CALL instuction + // decrease the query address by one byte to point somewhere in the CALL instruction byte sequence + sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1); } else { funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); @@ -248,6 +316,9 @@ const QString straceWin::getBacktrace() .arg(funcName) #ifndef __MINGW32__ .arg(params.join(", ")); + + if (!sourceFile.isEmpty()) + debugLine += QString("[ %1 ]").arg(sourceFile); #else ; #endif @@ -262,6 +333,8 @@ const QString straceWin::getBacktrace() //logStream << "\n\nList of linked Modules:\n"; //EnumModulesContext modulesContext(hProcess, logStream); //SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext); + SymCleanup(hProcess); + logStream << "```"; return log; } diff --git a/src/src.pro b/src/src.pro index 346757a01..914f40400 100644 --- a/src/src.pro +++ b/src/src.pro @@ -33,7 +33,11 @@ nogui { TARGET = qbittorrent } nowebui: DEFINES += DISABLE_WEBUI -strace_win: DEFINES += STACKTRACE_WIN +strace_win { + DEFINES += STACKTRACE_WIN + DEFINES += STACKTRACE_WIN_PROJECT_PATH=$$PWD + DEFINES += STACKTRACE_WIN_MAKEFILE_PATH=$$OUT_PWD +} QT += network xml # Vars