mirror of https://github.com/BOINC/boinc.git
Improve Windows diagnostics
This commit is contained in:
parent
1560a00a01
commit
8e5054248d
|
@ -115,29 +115,33 @@ static void* libhandle;
|
|||
// library this function will write whatever trace information it can and
|
||||
// then throw a breakpoint exception to dump all the rest of the useful
|
||||
// information.
|
||||
void boinc_catch_signal_invalid_parameter(
|
||||
static void boinc_catch_signal_invalid_parameter(
|
||||
const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t /* pReserved */
|
||||
) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"ERROR: Invalid parameter detected in function %s. File: %s Line: %d\n",
|
||||
function,
|
||||
file,
|
||||
line
|
||||
);
|
||||
fprintf(
|
||||
stderr,
|
||||
"ERROR: Expression: %s\n",
|
||||
expression
|
||||
);
|
||||
if (function && file && expression) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"ERROR: Invalid parameter detected in function %S. File: %S Line: %d\n",
|
||||
function,
|
||||
file,
|
||||
line
|
||||
);
|
||||
fprintf(
|
||||
stderr,
|
||||
"ERROR: Expression: %S\n",
|
||||
expression
|
||||
);
|
||||
} else {
|
||||
fputs("ERROR: Invalid parameter detected in CRT function\n", stderr);
|
||||
}
|
||||
|
||||
// Cause a Debug Breakpoint.
|
||||
DebugBreak();
|
||||
// Cause a Debug Breakpoint.
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
// Override default terminate and abort functions, call DebugBreak instead.
|
||||
//
|
||||
void boinc_term_func() {
|
||||
static void boinc_term_func() {
|
||||
|
||||
// Cause a Debug Breakpoint.
|
||||
DebugBreak();
|
||||
|
@ -496,7 +500,7 @@ int diagnostics_init(
|
|||
// that for future use.
|
||||
lReturnValue = RegOpenKeyEx(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
|
||||
TEXT("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
|
||||
0,
|
||||
KEY_READ,
|
||||
&hkSetupHive
|
||||
|
@ -505,9 +509,9 @@ int diagnostics_init(
|
|||
// How large does our buffer need to be?
|
||||
dwSize = sizeof(boinc_install_dir);
|
||||
|
||||
lReturnValue = RegQueryValueEx(
|
||||
lReturnValue = RegQueryValueExA(
|
||||
hkSetupHive,
|
||||
_T("INSTALLDIR"),
|
||||
"INSTALLDIR",
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)&boinc_install_dir,
|
||||
|
@ -623,13 +627,8 @@ char* diagnostics_get_symstore() {
|
|||
|
||||
// store the location of the symbol store.
|
||||
//
|
||||
int diagnostics_set_symstore(char* project_symstore) {
|
||||
if (!strlen(symstore)) {
|
||||
int buffer_used = snprintf(symstore, sizeof(symstore), "%s", project_symstore);
|
||||
if ((sizeof(symstore) == buffer_used) || (-1 == buffer_used)) {
|
||||
symstore[sizeof(symstore)-1] = '\0';
|
||||
}
|
||||
}
|
||||
int diagnostics_set_symstore(const char* project_symstore) {
|
||||
strlcpy(symstore, project_symstore, sizeof(symstore));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
// Copyright (C) 2023 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -99,7 +99,7 @@ extern int diagnostics_is_flag_set(int flags);
|
|||
extern char* diagnostics_get_boinc_dir(void);
|
||||
extern char* diagnostics_get_boinc_install_dir(void);
|
||||
extern char* diagnostics_get_symstore(void);
|
||||
extern int diagnostics_set_symstore(char* symstore);
|
||||
extern int diagnostics_set_symstore(const char* symstore);
|
||||
extern int diagnostics_is_proxy_enabled(void);
|
||||
extern char* diagnostics_get_proxy(void);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
// Copyright (C) 2023 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -114,9 +114,9 @@ struct BOINC_THREADLISTENTRY {
|
|||
DWORD thread_id;
|
||||
HANDLE thread_handle;
|
||||
BOOL crash_suspend_exempt;
|
||||
FLOAT crash_kernel_time;
|
||||
FLOAT crash_user_time;
|
||||
FLOAT crash_wait_time;
|
||||
double crash_kernel_time;
|
||||
double crash_user_time;
|
||||
ULONG crash_wait_time;
|
||||
INT crash_priority;
|
||||
INT crash_base_priority;
|
||||
INT crash_state;
|
||||
|
@ -136,7 +136,7 @@ int diagnostics_init_thread_entry(BOINC_THREADLISTENTRY *entry) {
|
|||
entry->crash_suspend_exempt = FALSE;
|
||||
entry->crash_kernel_time = 0.0;
|
||||
entry->crash_user_time = 0.0;
|
||||
entry->crash_wait_time = 0.0;
|
||||
entry->crash_wait_time = 0;
|
||||
entry->crash_priority = 0;
|
||||
entry->crash_base_priority = 0;
|
||||
entry->crash_state = 0;
|
||||
|
@ -252,10 +252,10 @@ int diagnostics_get_process_information(PVOID* ppBuffer, PULONG pcbBuffer) {
|
|||
);
|
||||
|
||||
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
HeapFree(hHeap, (DWORD)NULL, *ppBuffer);
|
||||
HeapFree(hHeap, 0, *ppBuffer);
|
||||
*pcbBuffer *= 2;
|
||||
} else if (!NT_SUCCESS(Status)) {
|
||||
HeapFree(hHeap, (DWORD)NULL, *ppBuffer);
|
||||
HeapFree(hHeap, 0, *ppBuffer);
|
||||
retval = Status;
|
||||
}
|
||||
} while (Status == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
@ -303,9 +303,9 @@ int diagnostics_update_thread_list() {
|
|||
pThreadEntry = diagnostics_find_thread_entry((DWORD)(uintptr_t)pThread->ClientId.UniqueThread);
|
||||
|
||||
if (pThreadEntry) {
|
||||
pThreadEntry->crash_kernel_time = (FLOAT)pThread->KernelTime.QuadPart;
|
||||
pThreadEntry->crash_user_time = (FLOAT)pThread->UserTime.QuadPart;
|
||||
pThreadEntry->crash_wait_time = (FLOAT)pThread->WaitTime;
|
||||
pThreadEntry->crash_kernel_time = pThread->KernelTime.QuadPart / 10000000.0;
|
||||
pThreadEntry->crash_user_time = pThread->UserTime.QuadPart / 10000000.0;
|
||||
pThreadEntry->crash_wait_time = pThread->WaitTime;
|
||||
pThreadEntry->crash_priority = pThread->Priority;
|
||||
pThreadEntry->crash_base_priority = pThread->BasePriority;
|
||||
pThreadEntry->crash_state = pThread->State;
|
||||
|
@ -321,9 +321,9 @@ int diagnostics_update_thread_list() {
|
|||
diagnostics_init_thread_entry(pThreadEntry);
|
||||
pThreadEntry->thread_id = (DWORD)(uintptr_t)(pThread->ClientId.UniqueThread);
|
||||
pThreadEntry->thread_handle = hThread;
|
||||
pThreadEntry->crash_kernel_time = (FLOAT)pThread->KernelTime.QuadPart;
|
||||
pThreadEntry->crash_user_time = (FLOAT)pThread->UserTime.QuadPart;
|
||||
pThreadEntry->crash_wait_time = (FLOAT)pThread->WaitTime;
|
||||
pThreadEntry->crash_kernel_time = pThread->KernelTime.QuadPart / 10000000.0;
|
||||
pThreadEntry->crash_user_time = pThread->UserTime.QuadPart / 10000000.0;
|
||||
pThreadEntry->crash_wait_time = pThread->WaitTime;
|
||||
pThreadEntry->crash_priority = pThread->Priority;
|
||||
pThreadEntry->crash_base_priority = pThread->BasePriority;
|
||||
pThreadEntry->crash_state = pThread->State;
|
||||
|
@ -342,7 +342,7 @@ int diagnostics_update_thread_list() {
|
|||
|
||||
// Release resources
|
||||
if (hThreadListSync) ReleaseMutex(hThreadListSync);
|
||||
if (pBuffer) HeapFree(GetProcessHeap(), (DWORD)NULL, pBuffer);
|
||||
if (pBuffer) HeapFree(GetProcessHeap(), 0, pBuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ int diagnostics_is_thread_exempt_suspend(long thread_id) {
|
|||
|
||||
|
||||
// Set the current thread's crash message.
|
||||
int diagnostics_set_thread_crash_message(char* message) {
|
||||
int diagnostics_set_thread_crash_message(const char* message) {
|
||||
HANDLE hThread;
|
||||
BOINC_THREADLISTENTRY *pThreadEntry = NULL;
|
||||
|
||||
|
@ -650,7 +650,7 @@ int diagnostics_init_message_monitor() {
|
|||
diagnostics_monitor_messages.clear();
|
||||
|
||||
// Check the registry to see if we are allowed to capture debugger messages.
|
||||
// Apparently many audio and visual payback programs dump serious
|
||||
// Apparently many audio and visual playback programs dump serious
|
||||
// amounts of data to the debugger viewport even on a release build.
|
||||
// When this feature is enabled it slows down the replay of DVDs and CDs
|
||||
// such that they become jerky and unpleasent to watch or listen too.
|
||||
|
@ -836,7 +836,7 @@ UINT WINAPI diagnostics_message_monitor(LPVOID /* lpParameter */) {
|
|||
HANDLE hEvents[2];
|
||||
|
||||
// Make sure this thread doesn't get suspended during
|
||||
// a crash dump, the DBGHELP library is pretty verbose.
|
||||
// a crash dump: the DBGHELP library is pretty verbose.
|
||||
// Suspending this thread will cause a deadlock.
|
||||
diagnostics_set_thread_exempt_suspend();
|
||||
|
||||
|
@ -1115,6 +1115,7 @@ int diagnostics_init_unhandled_exception_monitor() {
|
|||
// Wait until the exception monitor is ready for business.
|
||||
//
|
||||
WaitForSingleObject(hExceptionMonitorStartedEvent, INFINITE);
|
||||
CloseHandle(hExceptionMonitorStartedEvent);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1271,10 +1272,10 @@ int diagnostics_dump_process_information() {
|
|||
fprintf(
|
||||
stderr,
|
||||
"- I/O Operations Counters -\n"
|
||||
"Read: %d, Write: %d, Other %d\n"
|
||||
"Read: %llu, Write: %llu, Other %llu\n"
|
||||
"\n"
|
||||
"- I/O Transfers Counters -\n"
|
||||
"Read: %d, Write: %d, Other %d\n"
|
||||
"Read: %llu, Write: %llu, Other %llu\n"
|
||||
"\n",
|
||||
diagnostics_process.io_counters.ReadOperationCount,
|
||||
diagnostics_process.io_counters.WriteOperationCount,
|
||||
|
@ -1288,17 +1289,17 @@ int diagnostics_dump_process_information() {
|
|||
fprintf(
|
||||
stderr,
|
||||
"- Paged Pool Usage -\n"
|
||||
"QuotaPagedPoolUsage: %d, QuotaPeakPagedPoolUsage: %d\n"
|
||||
"QuotaNonPagedPoolUsage: %d, QuotaPeakNonPagedPoolUsage: %d\n"
|
||||
"QuotaPagedPoolUsage: %zu, QuotaPeakPagedPoolUsage: %zu\n"
|
||||
"QuotaNonPagedPoolUsage: %zu, QuotaPeakNonPagedPoolUsage: %zu\n"
|
||||
"\n"
|
||||
"- Virtual Memory Usage -\n"
|
||||
"VirtualSize: %d, PeakVirtualSize: %d\n"
|
||||
"VirtualSize: %zu, PeakVirtualSize: %zu\n"
|
||||
"\n"
|
||||
"- Pagefile Usage -\n"
|
||||
"PagefileUsage: %d, PeakPagefileUsage: %d\n"
|
||||
"PagefileUsage: %zu, PeakPagefileUsage: %zu\n"
|
||||
"\n"
|
||||
"- Working Set Size -\n"
|
||||
"WorkingSetSize: %d, PeakWorkingSetSize: %d, PageFaultCount: %d\n"
|
||||
"WorkingSetSize: %zu, PeakWorkingSetSize: %zu, PageFaultCount: %lu\n"
|
||||
"\n",
|
||||
diagnostics_process.vm_counters.QuotaPagedPoolUsage,
|
||||
diagnostics_process.vm_counters.QuotaPeakPagedPoolUsage,
|
||||
|
@ -1325,14 +1326,12 @@ int diagnostics_dump_thread_information(BOINC_THREADLISTENTRY *pThreadEntry) {
|
|||
if (pThreadEntry->crash_state == StateWait) {
|
||||
strStatusExtra += "Wait Reason: ";
|
||||
strStatusExtra += diagnostics_format_thread_wait_reason(pThreadEntry->crash_wait_reason);
|
||||
strStatusExtra += ", ";
|
||||
} else {
|
||||
strStatusExtra += "Base Priority: ";
|
||||
strStatusExtra += diagnostics_format_thread_priority(pThreadEntry->crash_base_priority);
|
||||
strStatusExtra += ", ";
|
||||
strStatusExtra += "Priority: ";
|
||||
strStatusExtra += diagnostics_format_thread_priority(pThreadEntry->crash_priority);
|
||||
strStatusExtra += ", ";
|
||||
}
|
||||
|
||||
fprintf(
|
||||
|
@ -1340,9 +1339,9 @@ int diagnostics_dump_thread_information(BOINC_THREADLISTENTRY *pThreadEntry) {
|
|||
"*** Dump of thread ID %d (state: %s): ***\n\n"
|
||||
"- Information -\n"
|
||||
"Status: %s, "
|
||||
"Kernel Time: %f, "
|
||||
"User Time: %f, "
|
||||
"Wait Time: %f\n"
|
||||
"Kernel Time: %.3f, "
|
||||
"User Time: %.3f, "
|
||||
"Wait Time: %lu\n"
|
||||
"\n",
|
||||
pThreadEntry->thread_id,
|
||||
diagnostics_format_thread_state(pThreadEntry->crash_state),
|
||||
|
@ -1358,7 +1357,7 @@ int diagnostics_dump_thread_information(BOINC_THREADLISTENTRY *pThreadEntry) {
|
|||
|
||||
// Provide a generic way to format exceptions
|
||||
//
|
||||
int diagnostics_dump_generic_exception(char* exception_desc, DWORD exception_code, PVOID exception_address) {
|
||||
int diagnostics_dump_generic_exception(const char* exception_desc, DWORD exception_code, PVOID exception_address) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Reason: %s (0x%x) at address 0x%p\n\n",
|
||||
|
@ -1411,23 +1410,29 @@ int diagnostics_dump_exception_record(PEXCEPTION_POINTERS pExPtrs) {
|
|||
fprintf(stderr, "%s\n\n", windows_format_error_string(exception_code, message, sizeof(message)));
|
||||
break;
|
||||
case 0xE06D7363:
|
||||
diagnostics_dump_generic_exception("Out Of Memory (C++ Exception)", exception_code, exception_address);
|
||||
diagnostics_dump_generic_exception("(C++ Exception)", exception_code, exception_address);
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
safe_strcpy(status, "Access Violation");
|
||||
safe_strcpy(substatus, "");
|
||||
if (pExPtrs->ExceptionRecord->NumberParameters == 2) {
|
||||
switch(pExPtrs->ExceptionRecord->ExceptionInformation[0]) {
|
||||
case 0: // read attempt
|
||||
case EXCEPTION_READ_FAULT:
|
||||
snprintf(substatus, sizeof(substatus),
|
||||
"read attempt to address 0x%8.8X",
|
||||
pExPtrs->ExceptionRecord->ExceptionInformation[1]
|
||||
"read attempt from address 0x%p",
|
||||
(void*)pExPtrs->ExceptionRecord->ExceptionInformation[1]
|
||||
);
|
||||
break;
|
||||
case 1: // write attempt
|
||||
case EXCEPTION_WRITE_FAULT:
|
||||
snprintf(substatus, sizeof(substatus),
|
||||
"write attempt to address 0x%8.8X",
|
||||
pExPtrs->ExceptionRecord->ExceptionInformation[1]
|
||||
"write attempt to address 0x%p",
|
||||
(void*)pExPtrs->ExceptionRecord->ExceptionInformation[1]
|
||||
);
|
||||
break;
|
||||
case EXCEPTION_EXECUTE_FAULT:
|
||||
snprintf(substatus, sizeof(substatus),
|
||||
"execute attempt at address 0x%p",
|
||||
(void*)pExPtrs->ExceptionRecord->ExceptionInformation[1]
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -1570,7 +1575,7 @@ UINT WINAPI diagnostics_unhandled_exception_monitor(LPVOID /* lpParameter */) {
|
|||
// hExceptionQuitEvent was signaled.
|
||||
case WAIT_OBJECT_0 + 0:
|
||||
|
||||
// We are shutting down so lets cleanup and exit.
|
||||
// We are shutting down, so let's clean up and exit.
|
||||
bContinue = false;
|
||||
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
// Copyright (C) 2023 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -29,28 +29,15 @@ typedef LONG KPRIORITY;
|
|||
//MinGW-W64 defines this struct in its own header
|
||||
#if !defined(HAVE_CLIENT_ID) && !defined(__MINGW32__) && _MSC_VER <= 1800
|
||||
typedef struct _CLIENT_ID {
|
||||
DWORD UniqueProcess;
|
||||
DWORD UniqueThread;
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID;
|
||||
#endif
|
||||
|
||||
//MinGW-W64 defines this struct in its own header
|
||||
#if !defined(HAVE_VM_COUNTERS) && !defined(__MINGW32__)
|
||||
// https://learn.microsoft.com/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation
|
||||
typedef struct _VM_COUNTERS {
|
||||
#ifdef _WIN64
|
||||
// the following was inferred by painful reverse engineering
|
||||
SIZE_T PeakVirtualSize; // not actually
|
||||
SIZE_T PageFaultCount;
|
||||
SIZE_T PeakWorkingSetSize;
|
||||
SIZE_T WorkingSetSize;
|
||||
SIZE_T QuotaPeakPagedPoolUsage;
|
||||
SIZE_T QuotaPagedPoolUsage;
|
||||
SIZE_T QuotaPeakNonPagedPoolUsage;
|
||||
SIZE_T QuotaNonPagedPoolUsage;
|
||||
SIZE_T PagefileUsage;
|
||||
SIZE_T PeakPagefileUsage;
|
||||
SIZE_T VirtualSize; // not actually
|
||||
#else
|
||||
SIZE_T PeakVirtualSize;
|
||||
SIZE_T VirtualSize;
|
||||
ULONG PageFaultCount;
|
||||
|
@ -62,7 +49,7 @@ typedef struct _VM_COUNTERS {
|
|||
SIZE_T QuotaNonPagedPoolUsage;
|
||||
SIZE_T PagefileUsage;
|
||||
SIZE_T PeakPagefileUsage;
|
||||
#endif
|
||||
SIZE_T PrivatePageCount;
|
||||
} VM_COUNTERS;
|
||||
#endif
|
||||
|
||||
|
@ -98,13 +85,14 @@ typedef struct _SYSTEM_PROCESSES {
|
|||
ULONG ProcessId;
|
||||
ULONG pad2;
|
||||
ULONG InheritedFromProcessId;
|
||||
ULONG pad3, pad4, pad5;
|
||||
ULONG pad3;
|
||||
#else
|
||||
ULONG ProcessId;
|
||||
ULONG InheritedFromProcessId;
|
||||
#endif
|
||||
ULONG HandleCount;
|
||||
ULONG Reserved2[2];
|
||||
ULONG SessionId;
|
||||
PVOID Reserved3;
|
||||
VM_COUNTERS VmCounters;
|
||||
IO_COUNTERS IoCounters;
|
||||
SYSTEM_THREADS Threads[1];
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
*
|
||||
*//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Altered by BOINC
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "boinc_win.h"
|
||||
|
@ -52,6 +53,11 @@
|
|||
#include "stackwalker_win.h"
|
||||
#include "stackwalker_imports.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#define ADDR_XDIG "16"
|
||||
#else
|
||||
#define ADDR_XDIG "8"
|
||||
#endif
|
||||
|
||||
// Link to dbghelp.dll and version.dll dynamically at runtime so we
|
||||
// can be specific about which version we are getting and where
|
||||
|
@ -282,7 +288,7 @@ BOOL CALLBACK SymEnumerateModulesProc64(LPCSTR /* ModuleName */, DWORD64 BaseOfD
|
|||
|
||||
// Version specified as part of the root record.
|
||||
if (pVQV(lpData, "\\", (LPVOID*)&pFileInfo, &uiVarSize)) {
|
||||
snprintf(szVersionInfo, sizeof(szVersionInfo), "%d.%d.%d.%d",
|
||||
snprintf(szVersionInfo, sizeof(szVersionInfo), "%u.%u.%u.%u",
|
||||
HIWORD(pFileInfo->dwFileVersionMS),
|
||||
LOWORD(pFileInfo->dwFileVersionMS),
|
||||
HIWORD(pFileInfo->dwFileVersionLS),
|
||||
|
@ -295,7 +301,7 @@ BOOL CALLBACK SymEnumerateModulesProc64(LPCSTR /* ModuleName */, DWORD64 BaseOfD
|
|||
lpTranslate[0].wCodePage
|
||||
);
|
||||
if (pVQV(lpData, szQuery, &lpVar, &uiVarSize)) {
|
||||
uiVarSize = snprintf(szCompanyName, sizeof(szCompanyName), "%s", lpVar);
|
||||
uiVarSize = snprintf(szCompanyName, sizeof(szCompanyName), "%s", (char*)lpVar);
|
||||
if ((sizeof(szCompanyName) == uiVarSize) || (-1 == uiVarSize)) {
|
||||
szCompanyName[255] = '\0';
|
||||
}
|
||||
|
@ -309,7 +315,7 @@ BOOL CALLBACK SymEnumerateModulesProc64(LPCSTR /* ModuleName */, DWORD64 BaseOfD
|
|||
lpTranslate[0].wCodePage
|
||||
);
|
||||
if (pVQV(lpData, szQuery, &lpVar, &uiVarSize)) {
|
||||
uiVarSize = snprintf(szProductName, sizeof(szProductName), "%s", lpVar);
|
||||
uiVarSize = snprintf(szProductName, sizeof(szProductName), "%s", (char*)lpVar);
|
||||
if ((sizeof(szProductName) == uiVarSize) || (-1 == uiVarSize)) {
|
||||
szProductName[255] = '\0';
|
||||
}
|
||||
|
@ -323,7 +329,7 @@ BOOL CALLBACK SymEnumerateModulesProc64(LPCSTR /* ModuleName */, DWORD64 BaseOfD
|
|||
lpTranslate[0].wCodePage
|
||||
);
|
||||
if (pVQV(lpData, szQuery, &lpVar, &uiVarSize)) {
|
||||
uiVarSize = snprintf(szFileVersion, sizeof(szFileVersion), "%s", lpVar);
|
||||
uiVarSize = snprintf(szFileVersion, sizeof(szFileVersion), "%s", (char*)lpVar);
|
||||
if ((sizeof(szFileVersion) == uiVarSize) || (-1 == uiVarSize)) {
|
||||
szFileVersion[255] = '\0';
|
||||
}
|
||||
|
@ -335,20 +341,20 @@ BOOL CALLBACK SymEnumerateModulesProc64(LPCSTR /* ModuleName */, DWORD64 BaseOfD
|
|||
lpTranslate[0].wCodePage
|
||||
);
|
||||
if (pVQV(lpData, szQuery, &lpVar, &uiVarSize)) {
|
||||
uiVarSize = snprintf(szProductVersion, sizeof(szProductVersion), "%s", lpVar);
|
||||
uiVarSize = snprintf(szProductVersion, sizeof(szProductVersion), "%s", (char*)lpVar);
|
||||
if ((sizeof(szProductVersion) == uiVarSize) || (-1 == uiVarSize)) {
|
||||
szProductVersion[255] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
free(lpData);
|
||||
}
|
||||
free(lpData);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "ModLoad: ");
|
||||
fprintf(stderr, "%.16x " , Module.BaseOfImage);
|
||||
fprintf(stderr, "%.16x " , Module.ImageSize);
|
||||
fprintf(stderr, "%." ADDR_XDIG "llx-" , Module.BaseOfImage);
|
||||
fprintf(stderr, "%." ADDR_XDIG "llx " , Module.BaseOfImage + Module.ImageSize);
|
||||
fprintf(stderr, "%s " , Module.LoadedImageName);
|
||||
if (bFileVersionSupported && bFileVersionRetrieved) {
|
||||
fprintf(stderr, "(%s) " , szVersionInfo);
|
||||
|
@ -658,7 +664,7 @@ int DebuggerDisplayDiagnostics()
|
|||
// Here the Stackwalk-Part begins.
|
||||
// Some of the code is from an example from a book
|
||||
// But I couldn't find the reference anymore... sorry...
|
||||
// If someone knowns, please let me know...
|
||||
// If someone knows, please let me know...
|
||||
// #################################################################################
|
||||
// #################################################################################
|
||||
|
||||
|
@ -729,15 +735,15 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
// Dump the Context data
|
||||
#if defined(_WIN64) && defined(_M_X64)
|
||||
fprintf(stderr,
|
||||
"rax=%.16x rbx=%.16x rcx=%.16x rdx=%.16x rsi=%.16x rdi=%.16x\n",
|
||||
"rax=%.16llx rbx=%.16llx rcx=%.16llx rdx=%.16llx rsi=%.16llx rdi=%.16llx\n",
|
||||
Context.Rax, Context.Rbx, Context.Rcx, Context.Rdx, Context.Rsi, Context.Rdi
|
||||
);
|
||||
fprintf(stderr,
|
||||
"r8=%.16x r9=%.16x r10=%.16x r11=%.16x r12=%.16x r13=%.16x\n",
|
||||
" r8=%.16llx r9=%.16llx r10=%.16llx r11=%.16llx r12=%.16llx r13=%.16llx\n",
|
||||
Context.R8, Context.R9, Context.R10, Context.R11, Context.R12, Context.R13
|
||||
);
|
||||
fprintf(stderr,
|
||||
"r14=%.16x r15=%.16x rip=%.16x rsp=%.16x rbp=%.16x\n",
|
||||
"r14=%.16llx r15=%.16llx rip=%.16llx rsp=%.16llx rbp=%.16llx\n",
|
||||
Context.R14, Context.R15, Context.Rip, Context.Rsp, Context.Rbp
|
||||
);
|
||||
fprintf(stderr,
|
||||
|
@ -761,7 +767,11 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
|
||||
// Stack Header
|
||||
fprintf(stderr, "- Callstack -\n");
|
||||
#ifdef _WIN64
|
||||
fprintf(stderr, "ChildRBP RetAddr Args to Child\n");
|
||||
#else
|
||||
fprintf(stderr, "ChildEBP RetAddr Args to Child\n");
|
||||
#endif
|
||||
fflush( stderr );
|
||||
|
||||
|
||||
|
@ -822,6 +832,13 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
break;
|
||||
}
|
||||
|
||||
BOOL isSymbolValid = FALSE;
|
||||
BOOL isLineValid = FALSE;
|
||||
BOOL isModuleValid = FALSE;
|
||||
BOOL isUndNameValid = FALSE;
|
||||
szMsgSymFromAddr[0] = '\0';
|
||||
szMsgSymGetLineFromAddr[0] = '\0';
|
||||
szMsgSymGetModuleInfo[0] = '\0';
|
||||
if ( StackFrame.AddrPC.Offset == 0 )
|
||||
{
|
||||
// Special case: If we are here, we have no valid callstack entry!
|
||||
|
@ -832,7 +849,8 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
// show procedure info (SymFromAddr())
|
||||
undName[0] = 0;
|
||||
offsetFromSymbol = 0;
|
||||
if ( !pSFA( g_hProcess, StackFrame.AddrPC.Offset, &offsetFromSymbol, pSymbol ) )
|
||||
isSymbolValid = pSFA( g_hProcess, StackFrame.AddrPC.Offset, &offsetFromSymbol, pSymbol );
|
||||
if ( !isSymbolValid )
|
||||
{
|
||||
if ( gle != 487 )
|
||||
{
|
||||
|
@ -847,12 +865,13 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
else
|
||||
{
|
||||
// UnDecorateSymbolName()
|
||||
pUDSN( pSymbol->Name, undName, MAX_SYM_NAME, UNDNAME_NAME_ONLY );
|
||||
isUndNameValid = pUDSN( pSymbol->Name, undName, MAX_SYM_NAME, UNDNAME_NAME_ONLY ) > 0;
|
||||
}
|
||||
|
||||
// show line number info (SymGetLineFromAddr())
|
||||
offsetFromLine = 0;
|
||||
if ( !pSGLFA( g_hProcess, StackFrame.AddrPC.Offset, &offsetFromLine, &Line ) )
|
||||
isLineValid = pSGLFA( g_hProcess, StackFrame.AddrPC.Offset, &offsetFromLine, &Line );
|
||||
if ( !isLineValid )
|
||||
{
|
||||
if ( (gle != 487) && (frameNum > 0) )
|
||||
{
|
||||
|
@ -866,7 +885,8 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
}
|
||||
|
||||
// show module info (SymGetModuleInfo())
|
||||
if ( !pSGMI( g_hProcess, StackFrame.AddrPC.Offset, &Module ) )
|
||||
isModuleValid = pSGMI( g_hProcess, StackFrame.AddrPC.Offset, &Module );
|
||||
if ( !isModuleValid )
|
||||
{
|
||||
snprintf(
|
||||
szMsgSymGetModuleInfo,
|
||||
|
@ -878,19 +898,19 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
} // we seem to have a valid PC
|
||||
|
||||
|
||||
fprintf(stderr, "%.8x ", StackFrame.AddrFrame.Offset);
|
||||
fprintf(stderr, "%.8x ", StackFrame.AddrReturn.Offset);
|
||||
fprintf(stderr, "%.8x ", StackFrame.Params[0]);
|
||||
fprintf(stderr, "%.8x ", StackFrame.Params[1]);
|
||||
fprintf(stderr, "%.8x ", StackFrame.Params[2]);
|
||||
fprintf(stderr, "%.8x ", StackFrame.Params[3]);
|
||||
fprintf(stderr, "%s", Module.ModuleName);
|
||||
fprintf(stderr, "!%s+", undName);
|
||||
fprintf(stderr, "0x%x ", offsetFromLine);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.AddrFrame.Offset);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.AddrReturn.Offset);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.Params[0]);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.Params[1]);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.Params[2]);
|
||||
fprintf(stderr, "%." ADDR_XDIG "zx ", (ULONG_PTR)StackFrame.Params[3]);
|
||||
fprintf(stderr, "%s!", isModuleValid ? Module.ModuleName : "???");
|
||||
fprintf(stderr, "%s", isUndNameValid ? undName : isSymbolValid ? pSymbol->Name : "???");
|
||||
if (isSymbolValid) fprintf(stderr, "+0x%llx", offsetFromSymbol);
|
||||
fputc(' ', stderr);
|
||||
|
||||
if (Line.LineNumber) {
|
||||
fprintf(stderr, "(%s:%lu) ", Line.FileName, Line.LineNumber);
|
||||
}
|
||||
if (isLineValid) fprintf(stderr, "(%s:%lu)", Line.FileName, Line.LineNumber);
|
||||
fputc(' ', stderr);
|
||||
|
||||
if (StackFrame.FuncTableEntry) {
|
||||
// FPO Data
|
||||
|
@ -908,14 +928,14 @@ static void ShowStackRM(HANDLE hThread, CONTEXT& Context)
|
|||
}
|
||||
}
|
||||
|
||||
if (strlen(szMsgSymFromAddr) || strlen(szMsgSymGetLineFromAddr) || strlen(szMsgSymGetModuleInfo)) {
|
||||
if (szMsgSymFromAddr[0] || szMsgSymGetLineFromAddr[0] || szMsgSymGetModuleInfo[0]) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s %s %s Address = '%.8x'",
|
||||
"%s %s %s Address = '%." ADDR_XDIG "zx'",
|
||||
szMsgSymFromAddr,
|
||||
szMsgSymGetLineFromAddr,
|
||||
szMsgSymGetModuleInfo,
|
||||
StackFrame.AddrPC.Offset
|
||||
(ULONG_PTR)StackFrame.AddrPC.Offset
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue