|
|
|
@ -1,22 +1,22 @@
@@ -1,22 +1,22 @@
|
|
|
|
|
/***************************************************************************
|
|
|
|
|
* 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. * |
|
|
|
|
***************************************************************************/ |
|
|
|
|
* 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. * |
|
|
|
|
***************************************************************************/ |
|
|
|
|
|
|
|
|
|
#include <windows.h> |
|
|
|
|
#include <dbghelp.h> |
|
|
|
@ -24,72 +24,77 @@
@@ -24,72 +24,77 @@
|
|
|
|
|
|
|
|
|
|
#include <QTextStream> |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
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) { |
|
|
|
|
QStringList *params = (QStringList *)user; |
|
|
|
|
if(symInfo->Flags & SYMFLAG_PARAMETER) { |
|
|
|
|
params->append(symInfo->Name); |
|
|
|
|
} |
|
|
|
|
return TRUE; |
|
|
|
|
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) |
|
|
|
|
{ |
|
|
|
|
QStringList* params = (QStringList*)user; |
|
|
|
|
if (symInfo->Flags & SYMFLAG_PARAMETER) |
|
|
|
|
params->append(symInfo->Name); |
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct straceWin::EnumModulesContext { |
|
|
|
|
HANDLE hProcess; |
|
|
|
|
QTextStream &stream; |
|
|
|
|
EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {} |
|
|
|
|
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) { |
|
|
|
|
IMAGEHLP_MODULE64 mod; |
|
|
|
|
EnumModulesContext *context = (EnumModulesContext *)UserContext; |
|
|
|
|
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
|
|
|
|
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) { |
|
|
|
|
QString moduleBase = QString("0x%1").arg(BaseOfDll, 8, 16, QLatin1Char('0')); |
|
|
|
|
QString line = QString("%1 %2 Image: %3") |
|
|
|
|
.arg(mod.ModuleName, -14) |
|
|
|
|
.arg(moduleBase, -13) |
|
|
|
|
.arg(mod.LoadedImageName); |
|
|
|
|
context->stream << line << '\n'; |
|
|
|
|
|
|
|
|
|
QString pdbName(mod.LoadedPdbName); |
|
|
|
|
if(!pdbName.isEmpty()) { |
|
|
|
|
QString line2 = QString("%1 %2") |
|
|
|
|
.arg("", 35) |
|
|
|
|
.arg(pdbName); |
|
|
|
|
context->stream << line2 << '\n'; |
|
|
|
|
BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) |
|
|
|
|
{ |
|
|
|
|
IMAGEHLP_MODULE64 mod; |
|
|
|
|
EnumModulesContext* context = (EnumModulesContext*)UserContext; |
|
|
|
|
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
|
|
|
|
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) { |
|
|
|
|
QString moduleBase = QString("0x%1").arg(BaseOfDll, 8, 16, QLatin1Char('0')); |
|
|
|
|
QString line = QString("%1 %2 Image: %3") |
|
|
|
|
.arg(mod.ModuleName, -14) |
|
|
|
|
.arg(moduleBase, -13) |
|
|
|
|
.arg(mod.LoadedImageName); |
|
|
|
|
context->stream << line << '\n'; |
|
|
|
|
|
|
|
|
|
QString pdbName(mod.LoadedPdbName); |
|
|
|
|
if(!pdbName.isEmpty()) { |
|
|
|
|
QString line2 = QString("%1 %2") |
|
|
|
|
.arg("", 35) |
|
|
|
|
.arg(pdbName); |
|
|
|
|
context->stream << line2 << '\n'; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return TRUE; |
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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) |
|
|
|
|
// 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; |
|
|
|
|
const QString straceWin::getBacktrace() |
|
|
|
|
{ |
|
|
|
|
DWORD MachineType; |
|
|
|
|
CONTEXT Context; |
|
|
|
|
STACKFRAME64 StackFrame; |
|
|
|
|
|
|
|
|
|
#ifdef _M_IX86 |
|
|
|
|
ZeroMemory(&Context, sizeof(CONTEXT)); |
|
|
|
@ -97,127 +102,128 @@ const QString straceWin::getBacktrace() {
@@ -97,127 +102,128 @@ const QString straceWin::getBacktrace() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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"); |
|
|
|
|
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; |
|
|
|
|
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)); |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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" |
|
|
|
|
#error "Unsupported platform" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
QString log; |
|
|
|
|
QTextStream logStream(&log); |
|
|
|
|
logStream << "```\n"; |
|
|
|
|
|
|
|
|
|
HANDLE hProcess = GetCurrentProcess(); |
|
|
|
|
HANDLE hThread = GetCurrentThread(); |
|
|
|
|
SymInitialize(hProcess, NULL, TRUE); |
|
|
|
|
|
|
|
|
|
DWORD64 dwDisplacement; |
|
|
|
|
|
|
|
|
|
ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
|
|
|
|
MAX_SYM_NAME*sizeof(TCHAR) + |
|
|
|
|
sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
|
|
|
|
PSYMBOL_INFO pSymbol = (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.
|
|
|
|
|
|
|
|
|
|
QString fileName("???"); |
|
|
|
|
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) { |
|
|
|
|
fileName = QString(mod.ImageName); |
|
|
|
|
int slashPos = fileName.lastIndexOf('\\'); |
|
|
|
|
if(slashPos != -1) |
|
|
|
|
fileName = fileName.mid(slashPos + 1); |
|
|
|
|
} |
|
|
|
|
QString funcName; |
|
|
|
|
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) { |
|
|
|
|
funcName = QString(pSymbol->Name); |
|
|
|
|
} else { |
|
|
|
|
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
|
|
|
|
} |
|
|
|
|
QStringList params; |
|
|
|
|
SymSetContext(hProcess, &ihsf, NULL); |
|
|
|
|
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); |
|
|
|
|
|
|
|
|
|
QString insOffset = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
|
|
|
|
QString debugLine = QString("#%1 %2 %3 %4(%5)") |
|
|
|
|
.arg(i, 3, 10) |
|
|
|
|
.arg(fileName, -20) |
|
|
|
|
.arg(insOffset, -11) |
|
|
|
|
.arg(funcName) |
|
|
|
|
.arg(params.join(", ")); |
|
|
|
|
logStream << debugLine << '\n'; |
|
|
|
|
i++; |
|
|
|
|
} else { |
|
|
|
|
break; // we're at the end.
|
|
|
|
|
QString log; |
|
|
|
|
QTextStream logStream(&log); |
|
|
|
|
logStream << "```\n"; |
|
|
|
|
|
|
|
|
|
HANDLE hProcess = GetCurrentProcess(); |
|
|
|
|
HANDLE hThread = GetCurrentThread(); |
|
|
|
|
SymInitialize(hProcess, NULL, TRUE); |
|
|
|
|
|
|
|
|
|
DWORD64 dwDisplacement; |
|
|
|
|
|
|
|
|
|
ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
|
|
|
|
MAX_SYM_NAME * sizeof(TCHAR) + |
|
|
|
|
sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
|
|
|
|
PSYMBOL_INFO pSymbol = (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.
|
|
|
|
|
|
|
|
|
|
QString fileName("???"); |
|
|
|
|
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) { |
|
|
|
|
fileName = QString(mod.ImageName); |
|
|
|
|
int slashPos = fileName.lastIndexOf('\\'); |
|
|
|
|
if(slashPos != -1) |
|
|
|
|
fileName = fileName.mid(slashPos + 1); |
|
|
|
|
} |
|
|
|
|
QString funcName; |
|
|
|
|
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) |
|
|
|
|
funcName = QString(pSymbol->Name); |
|
|
|
|
else |
|
|
|
|
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
|
|
|
|
QStringList params; |
|
|
|
|
SymSetContext(hProcess, &ihsf, NULL); |
|
|
|
|
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); |
|
|
|
|
|
|
|
|
|
QString insOffset = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
|
|
|
|
QString debugLine = QString("#%1 %2 %3 %4(%5)") |
|
|
|
|
.arg(i, 3, 10) |
|
|
|
|
.arg(fileName, -20) |
|
|
|
|
.arg(insOffset, -11) |
|
|
|
|
.arg(funcName) |
|
|
|
|
.arg(params.join(", ")); |
|
|
|
|
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); |
|
|
|
|
logStream << "```"; |
|
|
|
|
return log; |
|
|
|
|
logStream << "\n\nList of linked Modules:\n"; |
|
|
|
|
EnumModulesContext modulesContext(hProcess, logStream); |
|
|
|
|
SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext); |
|
|
|
|
logStream << "```"; |
|
|
|
|
return log; |
|
|
|
|
} |
|
|
|
|
#if defined(_M_IX86) && defined(Q_CC_MSVC) |
|
|
|
|
#pragma warning(pop) |
|
|
|
|
#pragma optimize("g", on) |
|
|
|
|
#pragma warning(pop) |
|
|
|
|
#pragma optimize("g", on) |
|
|
|
|
#endif |
|
|
|
|