Improve Windows diagnostics

This commit is contained in:
Brian Nixon 2023-04-10 20:58:13 +01:00
parent 1560a00a01
commit 8e5054248d
5 changed files with 129 additions and 117 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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
);
}