TrinityCore
Loading...
Searching...
No Matches
WheatyExceptionReport.h
Go to the documentation of this file.
1#ifndef _WHEATYEXCEPTIONREPORT_
2#define _WHEATYEXCEPTIONREPORT_
3
4#include "Define.h"
5#include "Optional.h"
6#include <Windows.h>
7#include <dbghelp.h>
8#include <winnt.h>
9#include <winternl.h>
10#include <compare>
11#include <set>
12#include <stack>
13#include <string>
14#include <cstdio>
15#include <cstdlib>
16
17#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
18#define WER_MAX_NESTING_LEVEL 4
19#define WER_SMALL_BUFFER_SIZE 1024
20#define WER_LARGE_BUFFER_SIZE WER_SMALL_BUFFER_SIZE * 16
21
22enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
23{
25 btVoid = 1,
26 btChar = 2,
28 btInt = 6,
29 btUInt = 7,
31 btBCD = 9,
32 btBool = 10,
33 btLong = 13,
34 btULong = 14,
36 btDate = 26,
39 btBit = 29,
40 btBSTR = 30,
42 btChar16 = 32, // char16_t
43 btChar32 = 33, // char32_t
44 btChar8 = 34, // char8_t
46
47 // Custom types
48 btStdString = 101
49};
50
64
113
114enum CpuRegister // Stolen from CVCONST.H in the DIA SDK
115{
117
118 //
119 // Register set for the Intel 80x86 and ix86 processor series
120 //
147
148 //
149 // AMD64 registers
150 //
176
177 // Low byte forms of some standard registers
182
183 // 64-bit regular registers
192
193 // 64-bit integer registers with 8-, 16-, and 32-bit forms (B, W, and D)
202
211
220
229
230 //
231 // Register set for ARM64
232 //
234
235 // General purpose 32-bit integer registers
268
269 // General purpose 64-bit integer registers
303};
304
305char const* const rgBaseType[] =
306{
307 "<user defined>", // btNoType = 0,
308 "void", // btVoid = 1,
309 "char",//char* // btChar = 2,
310 "wchar_t*", // btWChar = 3,
311 "signed char",
312 "unsigned char",
313 "int", // btInt = 6,
314 "unsigned int", // btUInt = 7,
315 "float", // btFloat = 8,
316 "<BCD>", // btBCD = 9,
317 "bool", // btBool = 10,
318 "short",
319 "unsigned short",
320 "long", // btLong = 13,
321 "unsigned long", // btULong = 14,
322 "int8",
323 "int16",
324 "int32",
325 "int64",
326 "int128",
327 "uint8",
328 "uint16",
329 "uint32",
330 "uint64",
331 "uint128",
332 "<currency>", // btCurrency = 25,
333 "<date>", // btDate = 26,
334 "VARIANT", // btVariant = 27,
335 "<complex>", // btComplex = 28,
336 "<bit>", // btBit = 29,
337 "BSTR", // btBSTR = 30,
338 "HRESULT", // btHresult = 31
339 "char16_t",
340 "char32_t",
341 "char8_t",
342 "<vector>"
343};
344
346{
347 SymbolPair(DWORD type, DWORD_PTR offset)
348 {
349 _type = type;
350 _offset = offset;
351 }
352
353 bool operator==(SymbolPair const& other) const = default;
354 std::strong_ordering operator<=>(SymbolPair const& other) const = default;
355
356 DWORD _type;
357 DWORD_PTR _offset;
358};
359typedef std::set<SymbolPair> SymbolPairs;
360
362{
363 SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
364
365 bool empty() const
366 {
367 return Value.empty() && !HasChildren;
368 }
369
370 std::string Prefix;
371 std::string Type;
372 std::string Suffix;
373 std::string Name;
374 std::string Value;
375 bool Logged;
377};
378
380{
381 public:
382
389
390 // entry point where control comes on an unhandled exception
391 static LONG WINAPI WheatyUnhandledExceptionFilter(
392 PEXCEPTION_POINTERS pExceptionInfo);
393
394 LONG UnhandledExceptionFilterImpl(PEXCEPTION_POINTERS pExceptionInfo) noexcept;
395
396 static void __cdecl WheatyCrtHandler(wchar_t const* expression, wchar_t const* function, wchar_t const* file, unsigned int line, uintptr_t pReserved);
397
398 void printTracesForAllThreads(bool bWriteVariables);
399 private:
400 // where report info is extracted and generated
401 void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo);
402 void PrintSystemInfo();
403 BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);
404 static BOOL _GetWindowsVersionFromWMI(TCHAR* szVersion, DWORD cntMax) noexcept;
405 static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount);
406
407 // Helper functions
408 static LPCTSTR GetExceptionString(DWORD dwCode);
409 static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len,
410 DWORD& section, DWORD_PTR& offset);
411
412 void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);
413
414 static BOOL GetSymbolFromAddress(HANDLE hProcess, DWORD64 Address, ULONG InlineContext, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
415 static BOOL GetSymbolLineFromAddress(HANDLE hProcess, DWORD64 qwAddr, ULONG InlineContext, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64);
416
423
424 static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID);
425
426 bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext*);
427
428 void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const*, char const*, bool, bool);
429
430 template <typename T>
431 void FormatOutputValueNumeric(char* buffer, size_t bufferSize, char const* format, LPCVOID address);
432
433 void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0);
434
435 BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase) const;
436
437 template <typename T> requires (std::is_scalar_v<T>)
438 Optional<T> DereferenceUnsafePointer(LPCVOID address);
439
440 int Log(const TCHAR * format, ...);
441
442 bool StoreSymbol(DWORD type , DWORD_PTR offset);
443 void ClearSymbols();
444
445 static Optional<DWORD_PTR> GetIntegerRegisterValue(PCONTEXT context, ULONG registerId);
446
447 // Variables used by the class
449 static constexpr SIZE_T m_tempPathBufferChars = 0x8000;
450 LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
451 _invalid_parameter_handler m_previousCrtHandler;
454 HANDLE m_process;
456 std::stack<SymbolDetail> m_symbolDetails;
459 typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
460 pRtlGetVersion RtlGetVersion;
461
462 SymbolDetail& PushSymbolDetail();
463 void PopSymbolDetail();
464 void PrintSymbolDetail();
465};
466
467#define INIT_CRASH_HANDLER() \
468 __pragma(warning(push)) \
469 __pragma(warning(disable:4073)) /* C4073: initializers put in library initialization area */ \
470 __pragma(init_seg(lib)) \
471 WheatyExceptionReport g_WheatyExceptionReport; \
472 __pragma(warning(pop))
473
474#endif // _WHEATYEXCEPTIONREPORT_
#define TC_COMMON_API
Definition Define.h:99
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
const size_t bufferSize
Definition RASession.h:28
char const *const rgBaseType[]
std::set< SymbolPair > SymbolPairs
@ CV_ALLREG_VFRAME
@ SymTagArrayType
@ SymTagFunction
@ SymTagVTableShape
@ SymTagCallSite
@ SymTagFunctionArgType
@ SymTagInlineSite
@ SymTagPointerType
@ SymTagFuncDebugEnd
@ SymTagAnnotation
@ SymTagCoffGroup
@ SymTagBaseInterface
@ SymTagCompilandEnv
@ SymTagCustomType
@ SymTagPublicSymbol
@ SymTagCompilandDetails
@ SymTagFuncDebugStart
@ SymTagTypedef
@ SymTagBaseType
@ SymTagHeapAllocationSite
@ SymTagMatrixType
@ SymTagManagedType
@ SymTagTaggedUnionCase
@ SymTagDimension
@ SymTagFunctionType
@ SymTagCompiland
@ SymTagBaseClass
@ SymTagUsingNamespace
@ SymTagVectorType
@ DataIsUnknown
@ DataIsStaticMember
@ DataIsStaticLocal
@ DataIsObjectPtr
@ DataIsConstant
@ DataIsFileStatic
Definition Log.h:52
WheatyExceptionReport(WheatyExceptionReport &&)=delete
WheatyExceptionReport(WheatyExceptionReport const &)=delete
LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
_invalid_parameter_handler m_previousCrtHandler
WheatyExceptionReport & operator=(WheatyExceptionReport const &)=delete
WheatyExceptionReport & operator=(WheatyExceptionReport &&)=delete
std::stack< SymbolDetail > m_symbolDetails
std::strong_ordering operator<=>(SymbolPair const &other) const =default
bool operator==(SymbolPair const &other) const =default
SymbolPair(DWORD type, DWORD_PTR offset)