Browse Source

Improve stack trace for windows by including source filenames and line numbers

adaptive-webui-19844
SeigneurSerpent 9 years ago
parent
commit
7398e7f0ad
  1. 73
      src/app/stacktrace_win.h
  2. 6
      src/src.pro

73
src/app/stacktrace_win.h

@ -25,6 +25,7 @@
#include <dbghelp.h> #include <dbghelp.h>
#include <stdio.h> #include <stdio.h>
#include <QDir>
#include <QTextStream> #include <QTextStream>
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <cxxabi.h> #include <cxxabi.h>
@ -41,6 +42,9 @@ namespace straceWin
#ifdef __MINGW32__ #ifdef __MINGW32__
void demangle(QString& str); void demangle(QString& str);
#endif #endif
QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr);
bool makeRelativePath(const QString& dir, QString& file);
} }
#ifdef __MINGW32__ #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) #if defined( _M_IX86 ) && defined(Q_CC_MSVC)
// Disable global optimization and ignore /GS waning caused by // Disable global optimization and ignore /GS waning caused by
@ -221,11 +284,16 @@ const QString straceWin::getBacktrace()
fileName = fileName.mid(slashPos + 1); fileName = fileName.mid(slashPos + 1);
} }
QString funcName; QString funcName;
QString sourceFile;
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) { if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {
funcName = QString(pSymbol->Name); funcName = QString(pSymbol->Name);
#ifdef __MINGW32__ #ifdef __MINGW32__
demangle(funcName); demangle(funcName);
#endif #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 { else {
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
@ -248,6 +316,9 @@ const QString straceWin::getBacktrace()
.arg(funcName) .arg(funcName)
#ifndef __MINGW32__ #ifndef __MINGW32__
.arg(params.join(", ")); .arg(params.join(", "));
if (!sourceFile.isEmpty())
debugLine += QString("[ %1 ]").arg(sourceFile);
#else #else
; ;
#endif #endif
@ -262,6 +333,8 @@ const QString straceWin::getBacktrace()
//logStream << "\n\nList of linked Modules:\n"; //logStream << "\n\nList of linked Modules:\n";
//EnumModulesContext modulesContext(hProcess, logStream); //EnumModulesContext modulesContext(hProcess, logStream);
//SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext); //SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
SymCleanup(hProcess);
logStream << "```"; logStream << "```";
return log; return log;
} }

6
src/src.pro

@ -33,7 +33,11 @@ nogui {
TARGET = qbittorrent TARGET = qbittorrent
} }
nowebui: DEFINES += DISABLE_WEBUI 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 QT += network xml
# Vars # Vars

Loading…
Cancel
Save