Chocobo1
3 years ago
committed by
GitHub
11 changed files with 122 additions and 534 deletions
@ -0,0 +1,36 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2022 Mike Tzou (Chocobo1) |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "stacktrace.h" |
||||||
|
|
||||||
|
#include <boost/stacktrace.hpp> |
||||||
|
|
||||||
|
std::string getStacktrace() |
||||||
|
{ |
||||||
|
return boost::stacktrace::to_string(boost::stacktrace::stacktrace()); |
||||||
|
} |
@ -1,116 +1,33 @@ |
|||||||
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
|
/*
|
||||||
// published under the WTFPL v2.0
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2022 Mike Tzou (Chocobo1) |
||||||
#ifndef _STACKTRACE_H_ |
* |
||||||
#define _STACKTRACE_H_ |
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
#include <stdio.h> |
* as published by the Free Software Foundation; either version 2 |
||||||
#include <stdlib.h> |
* of the License, or (at your option) any later version. |
||||||
#include <execinfo.h> |
* |
||||||
#include <cxxabi.h> |
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
#include <vector> |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
/** Print a demangled stack backtrace of the caller function to FILE* out. */ |
* |
||||||
static inline void print_stacktrace(FILE *out = stderr, const int max_frames = 63) |
* You should have received a copy of the GNU General Public License |
||||||
{ |
* along with this program; if not, write to the Free Software |
||||||
fprintf(out, "Stack trace:\n"); |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
// storage array for stack trace address data
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
std::vector<void *> addrlist(max_frames + 1); |
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
// retrieve current stack addresses
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
int addrlen = backtrace(addrlist.data(), addrlist.size()); |
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
if (addrlen == 0) |
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
{ |
* exception statement from your version. |
||||||
fprintf(out, " <empty, possibly corrupt>\n"); |
*/ |
||||||
return; |
|
||||||
} |
#pragma once |
||||||
|
|
||||||
// resolve addresses into strings containing "filename(function+address)",
|
#include <string> |
||||||
// this array must be free()-ed
|
|
||||||
char * *symbollist = backtrace_symbols(addrlist.data(), addrlen); |
std::string getStacktrace(); |
||||||
|
|
||||||
// allocate string which will be filled with the demangled function name
|
|
||||||
size_t funcnamesize = 256; |
|
||||||
char *funcname = static_cast<char *>(malloc(funcnamesize)); |
|
||||||
|
|
||||||
int functionNamesFound = 0; |
|
||||||
// iterate over the returned symbol lines. skip the first, it is the
|
|
||||||
// address of this function.
|
|
||||||
for (int i = 2; i < addrlen; i++) |
|
||||||
{ |
|
||||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0; |
|
||||||
|
|
||||||
// find parentheses and +address offset surrounding the mangled name:
|
|
||||||
// ./module(function+0x15c) [0x8048a6d]
|
|
||||||
// fprintf(out, "%s TT\n", symbollist[i]);
|
|
||||||
for (char *p = symbollist[i]; *p; ++p) |
|
||||||
{ |
|
||||||
if (*p == '(') |
|
||||||
{ |
|
||||||
begin_name = p; |
|
||||||
} |
|
||||||
else if (*p == '+') |
|
||||||
{ |
|
||||||
begin_offset = p; |
|
||||||
} |
|
||||||
else if ((*p == ')') && begin_offset) |
|
||||||
{ |
|
||||||
end_offset = p; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (begin_name && begin_offset && end_offset |
|
||||||
&& (begin_name < begin_offset)) |
|
||||||
{ |
|
||||||
*begin_name++ = '\0'; |
|
||||||
*begin_offset++ = '\0'; |
|
||||||
*end_offset = '\0'; |
|
||||||
|
|
||||||
// mangled name is now in [begin_name, begin_offset) and caller
|
|
||||||
// offset in [begin_offset, end_offset). now apply
|
|
||||||
// __cxa_demangle():
|
|
||||||
|
|
||||||
int status; |
|
||||||
char *ret = abi::__cxa_demangle(begin_name, |
|
||||||
funcname, &funcnamesize, &status); |
|
||||||
if (status == 0) |
|
||||||
{ |
|
||||||
funcname = ret; // use possibly realloc()-ed string
|
|
||||||
fprintf(out, " %s : %s+%s %s\n", |
|
||||||
symbollist[i], funcname, begin_offset, ++end_offset); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
// demangling failed. Output function name as a C function with
|
|
||||||
// no arguments.
|
|
||||||
fprintf(out, " %s : %s()+%s %s\n", |
|
||||||
symbollist[i], begin_name, begin_offset, ++end_offset); |
|
||||||
} |
|
||||||
++functionNamesFound; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
// couldn't parse the line? print the whole line.
|
|
||||||
fprintf(out, " %s\n", symbollist[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!functionNamesFound) |
|
||||||
{ |
|
||||||
fprintf(out, "There were no function names found in the stack trace\n." |
|
||||||
"Seems like debug symbols are not installed, and the stack trace is useless.\n"); |
|
||||||
} |
|
||||||
if (functionNamesFound < addrlen - 2) |
|
||||||
{ |
|
||||||
fprintf(out, "Consider installing debug symbols for packages containing files with empty" |
|
||||||
" function names (i.e. empty braces \"()\") to make your stack trace more useful\n"); |
|
||||||
} |
|
||||||
free(funcname); |
|
||||||
free(symbollist); |
|
||||||
} |
|
||||||
|
|
||||||
#endif // _STACKTRACE_H_
|
|
||||||
|
@ -1,360 +0,0 @@ |
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2005-09 by the Quassel Project * |
|
||||||
* devel@quassel-irc.org * |
|
||||||
* * |
|
||||||
* This program is free software; you can redistribute it and/or modify * |
|
||||||
* it under the terms of the GNU General Public License as published by * |
|
||||||
* the Free Software Foundation; either version 2 of the License, or * |
|
||||||
* (at your option) version 3. * |
|
||||||
* * |
|
||||||
* This program is distributed in the hope that it will be useful, * |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|
||||||
* GNU General Public License for more details. * |
|
||||||
* * |
|
||||||
* You should have received a copy of the GNU General Public License * |
|
||||||
* along with this program; if not, write to the * |
|
||||||
* Free Software Foundation, Inc., * |
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
|
||||||
***************************************************************************/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <windows.h> |
|
||||||
#include <dbghelp.h> |
|
||||||
#include <stdio.h> |
|
||||||
|
|
||||||
#include <QCoreApplication> |
|
||||||
#include <QDir> |
|
||||||
#include <QTextStream> |
|
||||||
#ifdef __MINGW32__ |
|
||||||
#include <cxxabi.h> |
|
||||||
#endif |
|
||||||
|
|
||||||
#include "base/global.h" |
|
||||||
|
|
||||||
namespace straceWin |
|
||||||
{ |
|
||||||
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME&, const STACKFRAME64&); |
|
||||||
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID); |
|
||||||
BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID); |
|
||||||
const QString getBacktrace(); |
|
||||||
struct EnumModulesContext; |
|
||||||
// Also works for MinGW64
|
|
||||||
#ifdef __MINGW32__ |
|
||||||
void demangle(QString& str); |
|
||||||
#endif |
|
||||||
|
|
||||||
QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr); |
|
||||||
bool makeRelativePath(const QString& dir, QString& file); |
|
||||||
} |
|
||||||
|
|
||||||
#ifdef __MINGW32__ |
|
||||||
void straceWin::demangle(QString& str) |
|
||||||
{ |
|
||||||
char const* inStr = qPrintable(u"_" + str); // Really need that underline or demangling will fail
|
|
||||||
int status = 0; |
|
||||||
size_t outSz = 0; |
|
||||||
char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status); |
|
||||||
if (status == 0) |
|
||||||
{ |
|
||||||
str = QString::fromLocal8Bit(demangled_name); |
|
||||||
if (outSz > 0) |
|
||||||
free(demangled_name); |
|
||||||
} |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
void straceWin::loadHelpStackFrame(IMAGEHLP_STACK_FRAME& ihsf, const STACKFRAME64& stackFrame) |
|
||||||
{ |
|
||||||
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); |
|
||||||
ihsf.InstructionOffset = stackFrame.AddrPC.Offset; |
|
||||||
ihsf.FrameOffset = stackFrame.AddrFrame.Offset; |
|
||||||
} |
|
||||||
|
|
||||||
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) |
|
||||||
{ |
|
||||||
Q_UNUSED(size) |
|
||||||
auto params = static_cast<QStringList *>(user); |
|
||||||
if (symInfo->Flags & SYMFLAG_PARAMETER) |
|
||||||
params->append(QString::fromUtf8(symInfo->Name)); |
|
||||||
return TRUE; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
struct straceWin::EnumModulesContext |
|
||||||
{ |
|
||||||
HANDLE hProcess; |
|
||||||
QTextStream& stream; |
|
||||||
EnumModulesContext(HANDLE hProcess, QTextStream& stream): hProcess(hProcess), stream(stream) {} |
|
||||||
}; |
|
||||||
|
|
||||||
BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) |
|
||||||
{ |
|
||||||
Q_UNUSED(ModuleName) |
|
||||||
IMAGEHLP_MODULE64 mod; |
|
||||||
auto context = static_cast<EnumModulesContext *>(UserContext); |
|
||||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
|
||||||
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) |
|
||||||
{ |
|
||||||
QString moduleBase = u"0x%1"_qs.arg(BaseOfDll, 16, 16, QChar(u'0')); |
|
||||||
QString line = u"%1 %2 Image: %3"_qs |
|
||||||
.arg(QString::fromUtf8(mod.ModuleName), -25) |
|
||||||
.arg(moduleBase, -13) |
|
||||||
.arg(QString::fromUtf8(mod.LoadedImageName)); |
|
||||||
context->stream << line << '\n'; |
|
||||||
|
|
||||||
const auto pdbName = QString::fromUtf8(mod.LoadedPdbName); |
|
||||||
if(!pdbName.isEmpty()) |
|
||||||
{ |
|
||||||
QString line2 = u"%1 %2"_qs |
|
||||||
.arg(u""_qs, 35) |
|
||||||
.arg(pdbName); |
|
||||||
context->stream << line2 << '\n'; |
|
||||||
} |
|
||||||
} |
|
||||||
return TRUE; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {}; |
|
||||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
|
||||||
DWORD dwDisplacement = 0; |
|
||||||
|
|
||||||
if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line)) |
|
||||||
{ |
|
||||||
auto path = QString::fromUtf8(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 |
|
||||||
const auto projectPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH)); |
|
||||||
success = makeRelativePath(projectPath, path); |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef STACKTRACE_WIN_MAKEFILE_PATH |
|
||||||
if (!success) |
|
||||||
{ |
|
||||||
const auto targetPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH)); |
|
||||||
makeRelativePath(targetPath, path); |
|
||||||
} |
|
||||||
#endif |
|
||||||
#endif |
|
||||||
return u"%1 : %2"_qs.arg(path).arg(line.LineNumber); |
|
||||||
} |
|
||||||
|
|
||||||
return QString(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
#if defined( _M_IX86 ) && defined(Q_CC_MSVC) |
|
||||||
// Disable global optimization and ignore /GS waning caused by
|
|
||||||
// inline assembly.
|
|
||||||
// not needed with mingw cause we can tell mingw which registers we use
|
|
||||||
#pragma optimize("g", off) |
|
||||||
#pragma warning(push) |
|
||||||
#pragma warning(disable : 4748) |
|
||||||
#endif |
|
||||||
const QString straceWin::getBacktrace() |
|
||||||
{ |
|
||||||
DWORD MachineType; |
|
||||||
CONTEXT Context; |
|
||||||
STACKFRAME64 StackFrame; |
|
||||||
|
|
||||||
#ifdef _M_IX86 |
|
||||||
ZeroMemory(&Context, sizeof(CONTEXT)); |
|
||||||
Context.ContextFlags = CONTEXT_CONTROL; |
|
||||||
|
|
||||||
|
|
||||||
#ifdef __MINGW32__ |
|
||||||
asm ("Label:\n\t" |
|
||||||
"movl %%ebp,%0;\n\t" |
|
||||||
"movl %%esp,%1;\n\t" |
|
||||||
"movl $Label,%%eax;\n\t" |
|
||||||
"movl %%eax,%2;\n\t" |
|
||||||
: "=r" (Context.Ebp),"=r" (Context.Esp),"=r" (Context.Eip) |
|
||||||
: //no input
|
|
||||||
: "eax"); |
|
||||||
#else |
|
||||||
_asm |
|
||||||
{ |
|
||||||
Label: |
|
||||||
mov [Context.Ebp], ebp; |
|
||||||
mov [Context.Esp], esp; |
|
||||||
mov eax, [Label]; |
|
||||||
mov [Context.Eip], eax; |
|
||||||
} |
|
||||||
#endif |
|
||||||
#else |
|
||||||
RtlCaptureContext(&Context); |
|
||||||
#endif |
|
||||||
|
|
||||||
ZeroMemory(&StackFrame, sizeof(STACKFRAME64)); |
|
||||||
#ifdef _M_IX86 |
|
||||||
MachineType = IMAGE_FILE_MACHINE_I386; |
|
||||||
StackFrame.AddrPC.Offset = Context.Eip; |
|
||||||
StackFrame.AddrPC.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrFrame.Offset = Context.Ebp; |
|
||||||
StackFrame.AddrFrame.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrStack.Offset = Context.Esp; |
|
||||||
StackFrame.AddrStack.Mode = AddrModeFlat; |
|
||||||
#elif _M_X64 |
|
||||||
MachineType = IMAGE_FILE_MACHINE_AMD64; |
|
||||||
StackFrame.AddrPC.Offset = Context.Rip; |
|
||||||
StackFrame.AddrPC.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrFrame.Offset = Context.Rsp; |
|
||||||
StackFrame.AddrFrame.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrStack.Offset = Context.Rsp; |
|
||||||
StackFrame.AddrStack.Mode = AddrModeFlat; |
|
||||||
#elif _M_IA64 |
|
||||||
MachineType = IMAGE_FILE_MACHINE_IA64; |
|
||||||
StackFrame.AddrPC.Offset = Context.StIIP; |
|
||||||
StackFrame.AddrPC.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrFrame.Offset = Context.IntSp; |
|
||||||
StackFrame.AddrFrame.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrBStore.Offset = Context.RsBSP; |
|
||||||
StackFrame.AddrBStore.Mode = AddrModeFlat; |
|
||||||
StackFrame.AddrStack.Offset = Context.IntSp; |
|
||||||
StackFrame.AddrStack.Mode = AddrModeFlat; |
|
||||||
#else |
|
||||||
#error "Unsupported platform" |
|
||||||
#endif |
|
||||||
|
|
||||||
QString log; |
|
||||||
QTextStream logStream(&log); |
|
||||||
logStream << "```\n"; |
|
||||||
|
|
||||||
const std::wstring appPath = QCoreApplication::applicationDirPath().toStdWString(); |
|
||||||
HANDLE hProcess = GetCurrentProcess(); |
|
||||||
HANDLE hThread = GetCurrentThread(); |
|
||||||
SymInitializeW(hProcess, appPath.c_str(), TRUE); |
|
||||||
|
|
||||||
DWORD64 dwDisplacement; |
|
||||||
|
|
||||||
ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
|
||||||
MAX_SYM_NAME * sizeof(TCHAR) + |
|
||||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
|
||||||
auto pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer); |
|
||||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
|
||||||
pSymbol->MaxNameLen = MAX_SYM_NAME; |
|
||||||
|
|
||||||
IMAGEHLP_MODULE64 mod; |
|
||||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
|
||||||
|
|
||||||
IMAGEHLP_STACK_FRAME ihsf; |
|
||||||
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); |
|
||||||
|
|
||||||
int i = 0; |
|
||||||
|
|
||||||
while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) |
|
||||||
{ |
|
||||||
if(i == 128) |
|
||||||
break; |
|
||||||
|
|
||||||
loadHelpStackFrame(ihsf, StackFrame); |
|
||||||
if(StackFrame.AddrPC.Offset != 0) |
|
||||||
{ // Valid frame.
|
|
||||||
|
|
||||||
auto fileName = u"???"_qs; |
|
||||||
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) |
|
||||||
{ |
|
||||||
fileName = QString::fromUtf8(mod.ImageName); |
|
||||||
int slashPos = fileName.lastIndexOf(u'\\'); |
|
||||||
if(slashPos != -1) |
|
||||||
fileName = fileName.mid(slashPos + 1); |
|
||||||
} |
|
||||||
QString funcName; |
|
||||||
QString sourceFile; |
|
||||||
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) |
|
||||||
{ |
|
||||||
funcName = QString::fromUtf8(pSymbol->Name); |
|
||||||
#ifdef __MINGW32__ |
|
||||||
demangle(funcName); |
|
||||||
#endif |
|
||||||
|
|
||||||
// now ihsf.InstructionOffset points to the instruction that follows CALL instruction
|
|
||||||
// decrease the query address by one byte to point somewhere in the CALL instruction byte sequence
|
|
||||||
sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
funcName = u"0x%1"_qs.arg(ihsf.InstructionOffset, 8, 16, QChar(u'0')); |
|
||||||
} |
|
||||||
SymSetContext(hProcess, &ihsf, NULL); |
|
||||||
#ifndef __MINGW32__ |
|
||||||
QStringList params; |
|
||||||
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); |
|
||||||
#endif |
|
||||||
|
|
||||||
QString insOffset = u"0x%1"_qs.arg(ihsf.InstructionOffset, 16, 16, QChar(u'0')); |
|
||||||
auto formatLine = u"#%1 %2 %3 %4"_qs; |
|
||||||
#ifndef __MINGW32__ |
|
||||||
formatLine += u"(%5)"_qs; |
|
||||||
#endif |
|
||||||
QString debugLine = formatLine |
|
||||||
.arg(i, 3, 10) |
|
||||||
.arg(fileName, -20) |
|
||||||
.arg(insOffset, -11) |
|
||||||
.arg(funcName) |
|
||||||
#ifndef __MINGW32__ |
|
||||||
.arg(params.join(u", ")); |
|
||||||
|
|
||||||
if (!sourceFile.isEmpty()) |
|
||||||
debugLine += u"[ %1 ]"_qs.arg(sourceFile); |
|
||||||
#else |
|
||||||
; |
|
||||||
#endif |
|
||||||
logStream << debugLine << '\n'; |
|
||||||
i++; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
break; // we're at the end.
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//logStream << "\n\nList of linked Modules:\n";
|
|
||||||
//EnumModulesContext modulesContext(hProcess, logStream);
|
|
||||||
//SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
|
|
||||||
SymCleanup(hProcess); |
|
||||||
|
|
||||||
logStream << "```"; |
|
||||||
return log; |
|
||||||
} |
|
||||||
#if defined(_M_IX86) && defined(Q_CC_MSVC) |
|
||||||
#pragma warning(pop) |
|
||||||
#pragma optimize("g", on) |
|
||||||
#endif |
|
Loading…
Reference in new issue