From 8e5054248d1bc3529d08fc2fb53e9a392b06b650 Mon Sep 17 00:00:00 2001 From: Brian Nixon Date: Mon, 10 Apr 2023 20:58:13 +0100 Subject: [PATCH] Improve Windows diagnostics --- lib/diagnostics.cpp | 51 +++++++++++++------------ lib/diagnostics.h | 4 +- lib/diagnostics_win.cpp | 81 +++++++++++++++++++++------------------- lib/diagnostics_win.h | 28 ++++---------- lib/stackwalker_win.cpp | 82 +++++++++++++++++++++++++---------------- 5 files changed, 129 insertions(+), 117 deletions(-) diff --git a/lib/diagnostics.cpp b/lib/diagnostics.cpp index 25a79389b8..c3a53eeb6a 100644 --- a/lib/diagnostics.cpp +++ b/lib/diagnostics.cpp @@ -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; } diff --git a/lib/diagnostics.h b/lib/diagnostics.h index 8cc69c9442..80235ecf7c 100644 --- a/lib/diagnostics.h +++ b/lib/diagnostics.h @@ -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); diff --git a/lib/diagnostics_win.cpp b/lib/diagnostics_win.cpp index 014b5bdbf7..ae4792c0c3 100644 --- a/lib/diagnostics_win.cpp +++ b/lib/diagnostics_win.cpp @@ -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; diff --git a/lib/diagnostics_win.h b/lib/diagnostics_win.h index ac90d338e1..96163cc35e 100644 --- a/lib/diagnostics_win.h +++ b/lib/diagnostics_win.h @@ -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]; diff --git a/lib/stackwalker_win.cpp b/lib/stackwalker_win.cpp index aa488a498a..6bb0d3e1f7 100644 --- a/lib/stackwalker_win.cpp +++ b/lib/stackwalker_win.cpp @@ -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 ); }