Legends-of-Azeroth-Pandaria-5.4.8

Форк
0
1051 строка · 37.5 Кб
1
/*
2
* This file is part of the Pandaria 5.4.8 Project. See THANKS file for Copyright information
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation; either version 2 of the License, or (at your
7
* option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License along
15
* with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17

18
//==========================================
19
// Matt Pietrek
20
// MSDN Magazine, 2002
21
// FILE: WheatyExceptionReport.CPP
22
//==========================================
23
#include "CompilerDefs.h"
24

25
#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__)
26
#define WIN32_LEAN_AND_MEAN
27
#pragma warning(disable:4996)
28
#pragma warning(disable:4312)
29
#pragma warning(disable:4311)
30
#include <windows.h>
31
#include <tlhelp32.h>
32
#include <stdio.h>
33
#include <tchar.h>
34

35
#include "WheatyExceptionReport.h"
36

37
#include "Common.h"
38
#include "SystemConfig.h"
39
#include "revision.h"
40

41
#define CrashFolder _T("Crashes")
42
#pragma comment(linker, "/DEFAULTLIB:dbghelp.lib")
43

44
inline LPTSTR ErrorMessage(DWORD dw)
45
{
46
    LPVOID lpMsgBuf;
47
    FormatMessage(
48
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
49
        FORMAT_MESSAGE_FROM_SYSTEM,
50
        NULL,
51
        dw,
52
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
53
        (LPTSTR) &lpMsgBuf,
54
        0, NULL);
55
    return (LPTSTR)lpMsgBuf;
56
}
57

58
//============================== Global Variables =============================
59

60
//
61
// Declare the static variables of the WheatyExceptionReport class
62
//
63
TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH];
64
TCHAR WheatyExceptionReport::m_szDumpFileName[MAX_PATH];
65
LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter;
66
HANDLE WheatyExceptionReport::m_hReportFile;
67
HANDLE WheatyExceptionReport::m_hDumpFile;
68
HANDLE WheatyExceptionReport::m_hProcess;
69

70
// Declare global instance of class
71
WheatyExceptionReport g_WheatyExceptionReport;
72

73
//============================== Class Methods =============================
74

75
WheatyExceptionReport::WheatyExceptionReport()             // Constructor
76
{
77
    // Install the unhandled exception filter function
78
    m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter);
79
    m_hProcess = GetCurrentProcess();
80
}
81

82
//============
83
// Destructor
84
//============
85
WheatyExceptionReport::~WheatyExceptionReport()
86
{
87
    if (m_previousFilter)
88
        SetUnhandledExceptionFilter(m_previousFilter);
89
}
90

91
//===========================================================
92
// Entry point where control comes on an unhandled exception
93
//===========================================================
94
LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
95
PEXCEPTION_POINTERS pExceptionInfo)
96
{
97
    TCHAR module_folder_name[MAX_PATH];
98
    GetModuleFileName(0, module_folder_name, MAX_PATH);
99
    TCHAR* pos = _tcsrchr(module_folder_name, '\\');
100
    if (!pos)
101
        return 0;
102
    pos[0] = '\0';
103
    ++pos;
104

105
    TCHAR crash_folder_path[MAX_PATH];
106
    auto n = snprintf(crash_folder_path, MAX_PATH, "%s\\%s", module_folder_name, CrashFolder);
107
    if (n == -1)
108
        return 0;
109
    if (!CreateDirectory(crash_folder_path, NULL))
110
    {
111
        if (GetLastError() != ERROR_ALREADY_EXISTS)
112
            return 0;
113
    }
114

115
    SYSTEMTIME systime;
116
    GetLocalTime(&systime);
117
    sprintf(m_szDumpFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].dmp",
118
        crash_folder_path, _HASH, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
119

120
    sprintf(m_szLogFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].txt",
121
        crash_folder_path, _HASH, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
122

123
    m_hDumpFile = CreateFile(m_szDumpFileName,
124
        GENERIC_WRITE,
125
        0,
126
        0,
127
        OPEN_ALWAYS,
128
        FILE_FLAG_WRITE_THROUGH,
129
        0);
130

131
    m_hReportFile = CreateFile(m_szLogFileName,
132
        GENERIC_WRITE,
133
        0,
134
        0,
135
        OPEN_ALWAYS,
136
        FILE_FLAG_WRITE_THROUGH,
137
        0);
138

139
    if (m_hDumpFile)
140
    {
141
        MINIDUMP_EXCEPTION_INFORMATION info;
142
        info.ClientPointers = FALSE;
143
        info.ExceptionPointers = pExceptionInfo;
144
        info.ThreadId = GetCurrentThreadId();
145

146
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
147
            m_hDumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, 0, 0);
148

149
        CloseHandle(m_hDumpFile);
150
    }
151

152
    if (m_hReportFile)
153
    {
154
        SetFilePointer(m_hReportFile, 0, 0, FILE_END);
155

156
        GenerateExceptionReport(pExceptionInfo);
157

158
        CloseHandle(m_hReportFile);
159
        m_hReportFile = 0;
160
    }
161

162
    if (m_previousFilter)
163
        return m_previousFilter(pExceptionInfo);
164
    else
165
        return EXCEPTION_EXECUTE_HANDLER;/*EXCEPTION_CONTINUE_SEARCH*/
166
}
167

168
BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount)
169
{
170
    if (!sProcessorName)
171
        return FALSE;
172

173
    HKEY hKey;
174
    LONG lRet;
175
    lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
176
        0, KEY_QUERY_VALUE, &hKey);
177
    if (lRet != ERROR_SUCCESS)
178
        return FALSE;
179
    TCHAR szTmp[2048];
180
    DWORD cntBytes = sizeof(szTmp);
181
    lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, NULL,
182
        (LPBYTE)szTmp, &cntBytes);
183
    if (lRet != ERROR_SUCCESS)
184
        return FALSE;
185
    ::RegCloseKey(hKey);
186
    sProcessorName[0] = '\0';
187
    // Skip spaces
188
    TCHAR* psz = szTmp;
189
    while (iswspace(*psz))
190
        ++psz;
191
    _tcsncpy(sProcessorName, psz, maxcount);
192
    return TRUE;
193
}
194

195
BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
196
{
197
    // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
198
    // If that fails, try using the OSVERSIONINFO structure.
199
    OSVERSIONINFOEX osvi = { 0 };
200
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
201
    BOOL bOsVersionInfoEx;
202
    bOsVersionInfoEx = ::GetVersionEx((LPOSVERSIONINFO)(&osvi));
203
    if (!bOsVersionInfoEx)
204
    {
205
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
206
        if (!::GetVersionEx((OSVERSIONINFO*)&osvi))
207
            return FALSE;
208
    }
209
    *szVersion = _T('\0');
210
    TCHAR wszTmp[128];
211
    switch (osvi.dwPlatformId)
212
    {
213
        // Windows NT product family.
214
        case VER_PLATFORM_WIN32_NT:
215
        {
216
        #if WINVER < 0x0500
217
            BYTE suiteMask = osvi.wReserved[0];
218
            BYTE productType = osvi.wReserved[1];
219
        #else
220
            WORD suiteMask = osvi.wSuiteMask;
221
            BYTE productType = osvi.wProductType;
222
        #endif                                          // WINVER < 0x0500
223

224
            // Test for the specific product family.
225
            if (osvi.dwMajorVersion == 6)
226
            {
227
                if (productType == VER_NT_WORKSTATION)
228
                {
229
                    if (osvi.dwMinorVersion == 2)
230
                        _tcsncat(szVersion, _T("Windows 8 "), cntMax);
231
                    else if (osvi.dwMinorVersion == 1)
232
                        _tcsncat(szVersion, _T("Windows 7 "), cntMax);
233
                    else
234
                        _tcsncat(szVersion, _T("Windows Vista "), cntMax);
235
                }
236
                else if (osvi.dwMinorVersion == 2)
237
                    _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
238
                else if (osvi.dwMinorVersion == 1)
239
                    _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
240
                else
241
                    _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
242
            }
243
            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
244
                _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax);
245
            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
246
                _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax);
247
            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
248
                _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax);
249
            else if (osvi.dwMajorVersion <= 4)
250
                _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
251

252
            // Test for specific product on Windows NT 4.0 SP6 and later.
253
            if (bOsVersionInfoEx)
254
            {
255
                // Test for the workstation type.
256
                if (productType == VER_NT_WORKSTATION)
257
                {
258
                    if (osvi.dwMajorVersion == 4)
259
                        _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax);
260
                    else if (suiteMask & VER_SUITE_PERSONAL)
261
                        _tcsncat(szVersion, _T("Home Edition "), cntMax);
262
                    else if (suiteMask & VER_SUITE_EMBEDDEDNT)
263
                        _tcsncat(szVersion, _T("Embedded "), cntMax);
264
                    else
265
                        _tcsncat(szVersion, _T("Professional "), cntMax);
266
                }
267
                // Test for the server type.
268
                else if (productType == VER_NT_SERVER)
269
                {
270
                    if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
271
                    {
272
                        if (suiteMask & VER_SUITE_DATACENTER)
273
                            _tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
274
                        else if (suiteMask & VER_SUITE_ENTERPRISE)
275
                            _tcsncat(szVersion, _T("Enterprise Edition "), cntMax);
276
                        else if (suiteMask == VER_SUITE_BLADE)
277
                            _tcsncat(szVersion, _T("Web Edition "), cntMax);
278
                        else
279
                            _tcsncat(szVersion, _T("Standard Edition "), cntMax);
280
                    }
281
                    else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
282
                    {
283
                        if (suiteMask & VER_SUITE_DATACENTER)
284
                            _tcsncat(szVersion, _T("Datacenter Server "), cntMax);
285
                        else if (suiteMask & VER_SUITE_ENTERPRISE)
286
                            _tcsncat(szVersion, _T("Advanced Server "), cntMax);
287
                        else
288
                            _tcsncat(szVersion, _T("Server "), cntMax);
289
                    }
290
                    else                                        // Windows NT 4.0
291
                    {
292
                        if (suiteMask & VER_SUITE_ENTERPRISE)
293
                            _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax);
294
                        else
295
                            _tcsncat(szVersion, _T("Server 4.0 "), cntMax);
296
                    }
297
                }
298
            }
299

300
            // Display service pack (if any) and build number.
301
            if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0)
302
            {
303
                HKEY hKey;
304
                LONG lRet;
305

306
                // Test for SP6 versus SP6a.
307
                lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey);
308
                if (lRet == ERROR_SUCCESS)
309
                {
310
                    _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"),
311
                        osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
312
                    _tcsncat(szVersion, wszTmp, cntMax);
313
                }
314
                else                                            // Windows NT 4.0 prior to SP6a
315
                {
316
                    _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
317
                        osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
318
                    _tcsncat(szVersion, wszTmp, cntMax);
319
                }
320
                ::RegCloseKey(hKey);
321
            }
322
            else                                                // Windows NT 3.51 and earlier or Windows 2000 and later
323
            {
324
                if (!_tcslen(osvi.szCSDVersion))
325
                    _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"),
326
                        osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
327
                else
328
                    _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
329
                        osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
330
                _tcsncat(szVersion, wszTmp, cntMax);
331
            }
332
            break;
333
        }
334
        default:
335
            _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
336
                osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
337
            _tcsncat(szVersion, wszTmp, cntMax);
338
            break;
339
    }
340

341
    return TRUE;
342
}
343

344
void WheatyExceptionReport::PrintSystemInfo()
345
{
346
    SYSTEM_INFO SystemInfo;
347
    ::GetSystemInfo(&SystemInfo);
348

349
    MEMORYSTATUS MemoryStatus;
350
    MemoryStatus.dwLength = sizeof (MEMORYSTATUS);
351
    ::GlobalMemoryStatus(&MemoryStatus);
352
    TCHAR sString[1024];
353
    _tprintf(_T("//=====================================================\r\n"));
354
    if (_GetProcessorName(sString, countof(sString)))
355
        _tprintf(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
356
            sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
357
    else
358
        _tprintf(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
359
            SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
360

361
    if (_GetWindowsVersion(sString, countof(sString)))
362
        _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
363
    else
364
        _tprintf(_T("\r\n*** Operation System:\r\n<unknown>\r\n"));
365
}
366

367
//===========================================================================
368
void WheatyExceptionReport::printTracesForAllThreads()
369
{
370
  THREADENTRY32 te32;
371

372
  DWORD dwOwnerPID = GetCurrentProcessId();
373
  m_hProcess = GetCurrentProcess();
374
  // Take a snapshot of all running threads
375
  HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
376
  if (hThreadSnap == INVALID_HANDLE_VALUE)
377
    return;
378

379
  // Fill in the size of the structure before using it.
380
  te32.dwSize = sizeof(THREADENTRY32);
381

382
  // Retrieve information about the first thread,
383
  // and exit if unsuccessful
384
  if (!Thread32First(hThreadSnap, &te32))
385
  {
386
    CloseHandle(hThreadSnap);    // Must clean up the
387
                                   //   snapshot object!
388
    return;
389
  }
390

391
  // Now walk the thread list of the system,
392
  // and display information about each thread
393
  // associated with the specified process
394
  do
395
  {
396
    if (te32.th32OwnerProcessID == dwOwnerPID)
397
    {
398
        CONTEXT context;
399
        context.ContextFlags = 0xffffffff;
400
        HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, false, te32.th32ThreadID);
401
        if (threadHandle)
402
        {
403
            if (GetThreadContext(threadHandle, &context))
404
                WriteStackDetails(&context, false, threadHandle);
405
            CloseHandle(threadHandle);
406
        }
407
    }
408
  } while (Thread32Next(hThreadSnap, &te32));
409

410
//  Don't forget to clean up the snapshot object.
411
  CloseHandle(hThreadSnap);
412
}
413

414
//===========================================================================
415
// Open the report file, and write the desired information to it.  Called by
416
// WheatyUnhandledExceptionFilter
417
//===========================================================================
418
void WheatyExceptionReport::GenerateExceptionReport(
419
PEXCEPTION_POINTERS pExceptionInfo)
420
{
421
    SYSTEMTIME systime;
422
    GetLocalTime(&systime);
423

424
    // Start out with a banner
425
    _tprintf(_T("Revision: %s\r\n"), _FULLVERSION);
426
    _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
427
    PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
428

429
    PrintSystemInfo();
430
    // First print information about the type of fault
431
    _tprintf(_T("\r\n//=====================================================\r\n"));
432
    _tprintf(_T("Exception code: %08X %s\r\n"),
433
        pExceptionRecord->ExceptionCode,
434
        GetExceptionString(pExceptionRecord->ExceptionCode));
435

436
    // Now print information about where the fault occured
437
    TCHAR szFaultingModule[MAX_PATH];
438
    DWORD section;
439
    DWORD_PTR offset;
440
    GetLogicalAddress(pExceptionRecord->ExceptionAddress,
441
        szFaultingModule,
442
        sizeof(szFaultingModule),
443
        section, offset);
444

445
#ifdef _M_IX86
446
    _tprintf(_T("Fault address:  %08X %02X:%08X %s\r\n"),
447
        pExceptionRecord->ExceptionAddress,
448
        section, offset, szFaultingModule);
449
#endif
450
#ifdef _M_X64
451
    _tprintf(_T("Fault address:  %016I64X %02X:%016I64X %s\r\n"),
452
        pExceptionRecord->ExceptionAddress,
453
        section, offset, szFaultingModule);
454
#endif
455

456
    PCONTEXT pCtx = pExceptionInfo->ContextRecord;
457

458
    // Show the registers
459
    #ifdef _M_IX86                                          // X86 Only!
460
    _tprintf(_T("\r\nRegisters:\r\n"));
461

462
    _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n"),
463
        pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
464
        pCtx->Esi, pCtx->Edi);
465

466
    _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
467
    _tprintf(_T("SS:ESP:%04X:%08X  EBP:%08X\r\n"),
468
        pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
469
    _tprintf(_T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
470
        pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
471
    _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
472
    #endif
473

474
    #ifdef _M_X64
475
    _tprintf(_T("\r\nRegisters:\r\n"));
476
    _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
477
        _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n"),
478
        pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
479
        pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
480
    _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
481
    _tprintf(_T("SS:RSP:%04X:%016X  RBP:%08X\r\n"),
482
        pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
483
    _tprintf(_T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
484
        pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
485
    _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
486
    #endif
487

488
    SymSetOptions(SYMOPT_DEFERRED_LOADS);
489

490
    // Initialize DbgHelp
491
    if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
492
    {
493
        _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
494
            ErrorMessage(GetLastError()));
495
    }
496

497
    CONTEXT trashableContext = *pCtx;
498

499
    WriteStackDetails(&trashableContext, false, NULL);
500
    printTracesForAllThreads();
501

502
//    #ifdef _M_IX86                                          // X86 Only!
503

504
    _tprintf(_T("========================\r\n"));
505
    _tprintf(_T("Local Variables And Parameters\r\n"));
506

507
    trashableContext = *pCtx;
508
    WriteStackDetails(&trashableContext, true, NULL);
509

510
    _tprintf(_T("========================\r\n"));
511
    _tprintf(_T("Global Variables\r\n"));
512

513
    SymEnumSymbols(GetCurrentProcess(),
514
        (UINT_PTR)GetModuleHandle(szFaultingModule),
515
        0, EnumerateSymbolsCallback, 0);
516
  //  #endif                                                  // X86 Only!
517

518
    SymCleanup(GetCurrentProcess());
519

520
    _tprintf(_T("\r\n"));
521
}
522

523
//======================================================================
524
// Given an exception code, returns a pointer to a static string with a
525
// description of the exception
526
//======================================================================
527
LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode)
528
{
529
    #define EXCEPTION(x) case EXCEPTION_##x: return (LPTSTR)_T(#x);
530

531
    switch (dwCode)
532
    {
533
        EXCEPTION(ACCESS_VIOLATION)
534
            EXCEPTION(DATATYPE_MISALIGNMENT)
535
            EXCEPTION(BREAKPOINT)
536
            EXCEPTION(SINGLE_STEP)
537
            EXCEPTION(ARRAY_BOUNDS_EXCEEDED)
538
            EXCEPTION(FLT_DENORMAL_OPERAND)
539
            EXCEPTION(FLT_DIVIDE_BY_ZERO)
540
            EXCEPTION(FLT_INEXACT_RESULT)
541
            EXCEPTION(FLT_INVALID_OPERATION)
542
            EXCEPTION(FLT_OVERFLOW)
543
            EXCEPTION(FLT_STACK_CHECK)
544
            EXCEPTION(FLT_UNDERFLOW)
545
            EXCEPTION(INT_DIVIDE_BY_ZERO)
546
            EXCEPTION(INT_OVERFLOW)
547
            EXCEPTION(PRIV_INSTRUCTION)
548
            EXCEPTION(IN_PAGE_ERROR)
549
            EXCEPTION(ILLEGAL_INSTRUCTION)
550
            EXCEPTION(NONCONTINUABLE_EXCEPTION)
551
            EXCEPTION(STACK_OVERFLOW)
552
            EXCEPTION(INVALID_DISPOSITION)
553
            EXCEPTION(GUARD_PAGE)
554
            EXCEPTION(INVALID_HANDLE)
555
    }
556

557
    // If not one of the "known" exceptions, try to get the string
558
    // from NTDLL.DLL's message table.
559

560
    static TCHAR szBuffer[512] = { 0 };
561

562
    FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
563
        GetModuleHandle(_T("NTDLL.DLL")),
564
        dwCode, 0, szBuffer, sizeof(szBuffer), 0);
565

566
    return szBuffer;
567
}
568

569
//=============================================================================
570
// Given a linear address, locates the module, section, and offset containing
571
// that address.
572
//
573
// Note: the szModule paramater buffer is an output buffer of length specified
574
// by the len parameter (in characters!)
575
//=============================================================================
576
BOOL WheatyExceptionReport::GetLogicalAddress(
577
PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset)
578
{
579
    MEMORY_BASIC_INFORMATION mbi;
580

581
    if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
582
        return FALSE;
583

584
    DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
585

586
    if (!GetModuleFileName((HMODULE)hMod, szModule, len))
587
        return FALSE;
588

589
    // Point to the DOS header in memory
590
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
591

592
    // From the DOS header, find the NT (PE) header
593
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
594

595
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
596

597
    DWORD_PTR rva = (DWORD_PTR)addr - hMod;                         // RVA is offset from module load address
598

599
    // Iterate through the section table, looking for the one that encompasses
600
    // the linear address.
601
    for (unsigned i = 0;
602
        i < pNtHdr->FileHeader.NumberOfSections;
603
        i++, pSection++)
604
    {
605
        DWORD_PTR sectionStart = pSection->VirtualAddress;
606
        DWORD_PTR sectionEnd = sectionStart
607
            + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
608

609
        // Is the address in this section???
610
        if ((rva >= sectionStart) && (rva <= sectionEnd))
611
        {
612
            // Yes, address is in the section.  Calculate section and offset,
613
            // and store in the "section" & "offset" params, which were
614
            // passed by reference.
615
            section = i+1;
616
            offset = rva - sectionStart;
617
            return TRUE;
618
        }
619
    }
620

621
    return FALSE;                                           // Should never get here!
622
}
623

624
// It contains SYMBOL_INFO structure plus additional
625
// space for the name of the symbol
626
struct CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE
627
{
628
    CSymbolInfoPackage()
629
    {
630
        si.SizeOfStruct = sizeof(SYMBOL_INFO);
631
        si.MaxNameLen   = sizeof(name);
632
    }
633
};
634

635
//============================================================
636
// Walks the stack, and writes the results to the report file
637
//============================================================
638
void WheatyExceptionReport::WriteStackDetails(
639
PCONTEXT pContext,
640
bool bWriteVariables, HANDLE pThreadHandle)                                      // true if local/params should be output
641
{
642
    _tprintf(_T("\r\nCall stack:\r\n"));
643

644
    _tprintf(_T("Address   Frame     Function      SourceFile\r\n"));
645

646
    DWORD dwMachineType = 0;
647
    // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
648

649
    STACKFRAME64 sf;
650
    memset(&sf, 0, sizeof(sf));
651

652
    #ifdef _M_IX86
653
    // Initialize the STACKFRAME structure for the first call.  This is only
654
    // necessary for Intel CPUs, and isn't mentioned in the documentation.
655
    sf.AddrPC.Offset       = pContext->Eip;
656
    sf.AddrPC.Mode         = AddrModeFlat;
657
    sf.AddrStack.Offset    = pContext->Esp;
658
    sf.AddrStack.Mode      = AddrModeFlat;
659
    sf.AddrFrame.Offset    = pContext->Ebp;
660
    sf.AddrFrame.Mode      = AddrModeFlat;
661

662
    dwMachineType = IMAGE_FILE_MACHINE_I386;
663
    #endif
664

665
#ifdef _M_X64
666
    sf.AddrPC.Offset    = pContext->Rip;
667
    sf.AddrPC.Mode = AddrModeFlat;
668
    sf.AddrStack.Offset    = pContext->Rsp;
669
    sf.AddrStack.Mode      = AddrModeFlat;
670
    sf.AddrFrame.Offset    = pContext->Rbp;
671
    sf.AddrFrame.Mode      = AddrModeFlat;
672
    dwMachineType = IMAGE_FILE_MACHINE_AMD64;
673
#endif
674

675
    while (1)
676
    {
677
        // Get the next stack frame
678
        if (! StackWalk64(dwMachineType,
679
            m_hProcess,
680
            pThreadHandle != NULL ? pThreadHandle : GetCurrentThread(),
681
            &sf,
682
            pContext,
683
            0,
684
            SymFunctionTableAccess64,
685
            SymGetModuleBase64,
686
            0))
687
            break;
688
        if (0 == sf.AddrFrame.Offset)                     // Basic sanity check to make sure
689
            break;                                          // the frame is OK.  Bail if not.
690
#ifdef _M_IX86
691
        _tprintf(_T("%08X  %08X  "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
692
#endif
693
#ifdef _M_X64
694
        _tprintf(_T("%016I64X  %016I64X  "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
695
#endif
696

697
        DWORD64 symDisplacement = 0;                        // Displacement of the input address,
698
        // relative to the start of the symbol
699

700
        // Get the name of the function for this stack frame entry
701
        CSymbolInfoPackage sip;
702
        if (SymFromAddr(
703
            m_hProcess,                                     // Process handle of the current process
704
            sf.AddrPC.Offset,                               // Symbol address
705
            &symDisplacement,                               // Address of the variable that will receive the displacement
706
            &sip.si))                                       // Address of the SYMBOL_INFO structure (inside "sip" object)
707
        {
708
            _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement);
709

710
        }
711
        else                                                // No symbol found.  Print out the logical address instead.
712
        {
713
            TCHAR szModule[MAX_PATH] = _T("");
714
            DWORD section = 0;
715
            DWORD_PTR offset = 0;
716

717
            GetLogicalAddress((PVOID)sf.AddrPC.Offset,
718
                szModule, sizeof(szModule), section, offset);
719
#ifdef _M_IX86
720
            _tprintf(_T("%04X:%08X %s"), section, offset, szModule);
721
#endif
722
#ifdef _M_X64
723
            _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule);
724
#endif
725
        }
726

727
        // Get the source line for this stack frame entry
728
        IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE) };
729
        DWORD dwLineDisplacement;
730
        if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset,
731
            &dwLineDisplacement, &lineInfo))
732
        {
733
            _tprintf(_T("  %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
734
        }
735

736
        _tprintf(_T("\r\n"));
737

738
        // Write out the variables, if desired
739
        if (bWriteVariables)
740
        {
741
            // Use SymSetContext to get just the locals/params for this frame
742
            IMAGEHLP_STACK_FRAME imagehlpStackFrame;
743
            imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
744
            SymSetContext(m_hProcess, &imagehlpStackFrame, 0);
745

746
            // Enumerate the locals/parameters
747
            SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf);
748

749
            _tprintf(_T("\r\n"));
750
        }
751
    }
752

753
}
754

755
//////////////////////////////////////////////////////////////////////////////
756
// The function invoked by SymEnumSymbols
757
//////////////////////////////////////////////////////////////////////////////
758

759
BOOL CALLBACK
760
WheatyExceptionReport::EnumerateSymbolsCallback(
761
PSYMBOL_INFO  pSymInfo,
762
ULONG         /*SymbolSize*/,
763
PVOID         UserContext)
764
{
765

766
    char szBuffer[2048];
767

768
    __try
769
    {
770
        if (FormatSymbolValue(pSymInfo, (STACKFRAME*)UserContext,
771
            szBuffer, sizeof(szBuffer)))
772
            _tprintf(_T("\t%s\r\n"), szBuffer);
773
    }
774
    __except(1)
775
    {
776
        _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name);
777
    }
778

779
    return TRUE;
780
}
781

782
//////////////////////////////////////////////////////////////////////////////
783
// Given a SYMBOL_INFO representing a particular variable, displays its
784
// contents.  If it's a user defined type, display the members and their
785
// values.
786
//////////////////////////////////////////////////////////////////////////////
787
bool WheatyExceptionReport::FormatSymbolValue(
788
PSYMBOL_INFO pSym,
789
STACKFRAME * sf,
790
char * pszBuffer,
791
unsigned /*cbBuffer*/)
792
{
793
    char * pszCurrBuffer = pszBuffer;
794

795
    // Indicate if the variable is a local or parameter
796
    if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
797
        pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter ");
798
    else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
799
        pszCurrBuffer += sprintf(pszCurrBuffer, "Local ");
800

801
    // If it's a function, don't do anything.
802
    if (pSym->Tag == 5)                                   // SymTagFunction from CVCONST.H from the DIA SDK
803
        return false;
804

805
    DWORD_PTR pVariable = 0;                                // Will point to the variable's data in memory
806

807
    if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE)
808
    {
809
        // if (pSym->Register == 8)   // EBP is the value 8 (in DBGHELP 5.1)
810
        {                                                   //  This may change!!!
811
            pVariable = sf->AddrFrame.Offset;
812
            pVariable += (DWORD_PTR)pSym->Address;
813
        }
814
        // else
815
        //  return false;
816
    }
817
    else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
818
    {
819
        return false;                                       // Don't try to report register variable
820
    }
821
    else
822
    {
823
        pVariable = (DWORD_PTR)pSym->Address;               // It must be a global variable
824
    }
825

826
    // Determine if the variable is a user defined type (UDT).  IF so, bHandled
827
    // will return true.
828
    bool bHandled;
829
    pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
830
        0, pVariable, bHandled, pSym->Name);
831

832
    if (!bHandled)
833
    {
834
        // The symbol wasn't a UDT, so do basic, stupid formatting of the
835
        // variable.  Based on the size, we're assuming it's a char, WORD, or
836
        // DWORD.
837
        BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
838
        pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
839

840
        // Emit the variable name
841
        pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name);
842

843
        pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
844
            (PVOID)pVariable);
845
    }
846

847
    return true;
848
}
849

850
//////////////////////////////////////////////////////////////////////////////
851
// If it's a user defined type (UDT), recurse through its members until we're
852
// at fundamental types.  When he hit fundamental types, return
853
// bHandled = false, so that FormatSymbolValue() will format them.
854
//////////////////////////////////////////////////////////////////////////////
855
char * WheatyExceptionReport::DumpTypeIndex(
856
char * pszCurrBuffer,
857
DWORD64 modBase,
858
DWORD dwTypeIndex,
859
unsigned nestingLevel,
860
DWORD_PTR offset,
861
bool & bHandled,
862
char* Name)
863
{
864
    bHandled = false;
865

866
    // Get the name of the symbol.  This will either be a Type name (if a UDT),
867
    // or the structure member name.
868
    WCHAR * pwszTypeName;
869
    if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
870
        &pwszTypeName))
871
    {
872
        pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
873
        LocalFree(pwszTypeName);
874
    }
875

876
    // Determine how many children this type has.
877
    DWORD dwChildrenCount = 0;
878
    SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT,
879
        &dwChildrenCount);
880

881
    if (!dwChildrenCount)                                 // If no children, we're done
882
        return pszCurrBuffer;
883

884
    // Prepare to get an array of "TypeIds", representing each of the children.
885
    // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
886
    // TI_FINDCHILDREN_PARAMS struct has.  Use derivation to accomplish this.
887
    struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
888
    {
889
        ULONG   MoreChildIds[1024];
890
        FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);}
891
    } children;
892

893
    children.Count = dwChildrenCount;
894
    children.Start= 0;
895

896
    // Get the array of TypeIds, one for each child type
897
    if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
898
        &children))
899
    {
900
        return pszCurrBuffer;
901
    }
902

903
    // Append a line feed
904
    pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
905

906
    // Iterate through each of the children
907
    for (unsigned i = 0; i < dwChildrenCount; i++)
908
    {
909
        // Add appropriate indentation level (since this routine is recursive)
910
        for (unsigned j = 0; j <= nestingLevel+1; j++)
911
            pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
912

913
        // Recurse for each of the child types
914
        bool bHandled2;
915
        BasicType basicType = GetBasicType(children.ChildId[i], modBase);
916
        pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
917

918
        pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
919
            children.ChildId[i], nestingLevel+1,
920
            offset, bHandled2, Name);
921

922
        // If the child wasn't a UDT, format it appropriately
923
        if (!bHandled2)
924
        {
925
            // Get the offset of the child member, relative to its parent
926
            DWORD dwMemberOffset;
927
            SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
928
                TI_GET_OFFSET, &dwMemberOffset);
929

930
            // Get the real "TypeId" of the child.  We need this for the
931
            // SymGetTypeInfo(TI_GET_TYPEID) call below.
932
            DWORD typeId;
933
            SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
934
                TI_GET_TYPEID, &typeId);
935

936
            // Get the size of the child member
937
            ULONG64 length;
938
            SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
939

940
            // Calculate the address of the member
941
            DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
942

943
            //             BasicType basicType = GetBasicType(children.ChildId[i], modBase);
944
            //
945
            //          pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
946
            //
947
            // Emit the variable name
948
            //          pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", Name);
949

950
            pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType,
951
                length, (PVOID)dwFinalOffset);
952

953
            pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
954
        }
955
    }
956

957
    bHandled = true;
958
    return pszCurrBuffer;
959
}
960

961
char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
962
BasicType basicType,
963
DWORD64 length,
964
PVOID pAddress)
965
{
966
    // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
967
    if (length == 1)
968
        pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress);
969
    else if (length == 2)
970
        pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress);
971
    else if (length == 4)
972
    {
973
        if (basicType == btFloat)
974
        {
975
            pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress);
976
        }
977
        else if (basicType == btChar)
978
        {
979
            if (!IsBadStringPtr(*(PSTR*)pAddress, 32))
980
            {
981
                pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"",
982
                    *(PSTR*)pAddress);
983
            }
984
            else
985
                pszCurrBuffer += sprintf(pszCurrBuffer, " = %X",
986
                    *(PDWORD)pAddress);
987
        }
988
        else
989
            pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress);
990
    }
991
    else if (length == 8)
992
    {
993
        if (basicType == btFloat)
994
        {
995
            pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf",
996
                *(double *)pAddress);
997
        }
998
        else
999
            pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X",
1000
                *(DWORD64*)pAddress);
1001
    }
1002

1003
    return pszCurrBuffer;
1004
}
1005

1006
BasicType
1007
WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)
1008
{
1009
    BasicType basicType;
1010
    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex,
1011
        TI_GET_BASETYPE, &basicType))
1012
    {
1013
        return basicType;
1014
    }
1015

1016
    // Get the real "TypeId" of the child.  We need this for the
1017
    // SymGetTypeInfo(TI_GET_TYPEID) call below.
1018
    DWORD typeId;
1019
    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId))
1020
    {
1021
        if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE,
1022
            &basicType))
1023
        {
1024
            return basicType;
1025
        }
1026
    }
1027

1028
    return btNoType;
1029
}
1030

1031
//============================================================================
1032
// Helper function that writes to the report file, and allows the user to use
1033
// printf style formating
1034
//============================================================================
1035
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
1036
{
1037
    TCHAR szBuff[1024];
1038
    int retValue;
1039
    DWORD cbWritten;
1040
    va_list argptr;
1041

1042
    va_start(argptr, format);
1043
    retValue = vsprintf(szBuff, format, argptr);
1044
    va_end(argptr);
1045

1046
    WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
1047

1048
    return retValue;
1049
}
1050

1051
#endif  // _WIN32
1052

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.