TrinityCore
WheatyExceptionReport.h
Go to the documentation of this file.
1#ifndef _WHEATYEXCEPTIONREPORT_
2#define _WHEATYEXCEPTIONREPORT_
3
4#define _NO_CVCONST_H
5
6#include "Optional.h"
7#include <windows.h>
8#include <winnt.h>
9#include <winternl.h>
10#include <dbghelp.h>
11#include <compare>
12#include <set>
13#include <cstdlib>
14#include <cstdio>
15#include <stack>
16#include <mutex>
17
18#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
19#define WER_MAX_NESTING_LEVEL 4
20#define WER_SMALL_BUFFER_SIZE 1024
21#define WER_LARGE_BUFFER_SIZE WER_SMALL_BUFFER_SIZE * 16
22
23enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
24{
26 btVoid = 1,
27 btChar = 2,
29 btInt = 6,
30 btUInt = 7,
32 btBCD = 9,
33 btBool = 10,
34 btLong = 13,
35 btULong = 14,
37 btDate = 26,
40 btBit = 29,
41 btBSTR = 30,
43
44 // Custom types
45 btStdString = 101
46};
47
48enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK
49{
60};
61
62enum CpuRegister // Stolen from CVCONST.H in the DIA SDK
63{
65
66 //
67 // Register set for the Intel 80x86 and ix86 processor series
68 //
95
96 //
97 // AMD64 registers
98 //
124
125 // Low byte forms of some standard registers
130
131 // 64-bit regular registers
140
141 // 64-bit integer registers with 8-, 16-, and 32-bit forms (B, W, and D)
150
159
168
177
178 //
179 // Register set for ARM64
180 //
182
183 // General purpose 32-bit integer registers
216
217 // General purpose 64-bit integer registers
251};
252
253char const* const rgBaseType[] =
254{
255 "<user defined>", // btNoType = 0,
256 "void", // btVoid = 1,
257 "char",//char* // btChar = 2,
258 "wchar_t*", // btWChar = 3,
259 "signed char",
260 "unsigned char",
261 "int", // btInt = 6,
262 "unsigned int", // btUInt = 7,
263 "float", // btFloat = 8,
264 "<BCD>", // btBCD = 9,
265 "bool", // btBool = 10,
266 "short",
267 "unsigned short",
268 "long", // btLong = 13,
269 "unsigned long", // btULong = 14,
270 "int8",
271 "int16",
272 "int32",
273 "int64",
274 "int128",
275 "uint8",
276 "uint16",
277 "uint32",
278 "uint64",
279 "uint128",
280 "<currency>", // btCurrency = 25,
281 "<date>", // btDate = 26,
282 "VARIANT", // btVariant = 27,
283 "<complex>", // btComplex = 28,
284 "<bit>", // btBit = 29,
285 "BSTR", // btBSTR = 30,
286 "HRESULT" // btHresult = 31
287};
288
290{
291 SymbolPair(DWORD type, DWORD_PTR offset)
292 {
293 _type = type;
294 _offset = offset;
295 }
296
297 bool operator==(SymbolPair const& other) const = default;
298 std::strong_ordering operator<=>(SymbolPair const& other) const = default;
299
300 DWORD _type;
301 DWORD_PTR _offset;
302};
303typedef std::set<SymbolPair> SymbolPairs;
304
306{
307 SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
308
309 std::string ToString();
310
311 bool empty() const
312 {
313 return Value.empty() && !HasChildren;
314 }
315
316 std::string Prefix;
317 std::string Type;
318 std::string Suffix;
319 std::string Name;
320 std::string Value;
321 bool Logged;
323};
324
326{
327 public:
328
331
332 // entry point where control comes on an unhandled exception
333 static LONG WINAPI WheatyUnhandledExceptionFilter(
334 PEXCEPTION_POINTERS pExceptionInfo);
335
336 static void __cdecl WheatyCrtHandler(wchar_t const* expression, wchar_t const* function, wchar_t const* file, unsigned int line, uintptr_t pReserved);
337
338 static void printTracesForAllThreads(bool);
339 private:
340 // where report info is extracted and generated
341 static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo);
342 static void PrintSystemInfo();
343 static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);
344 static BOOL _GetWindowsVersionFromWMI(TCHAR* szVersion, DWORD cntMax);
345 static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount);
346
347 // Helper functions
348 static LPCTSTR GetExceptionString(DWORD dwCode);
349 static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len,
350 DWORD& section, DWORD_PTR& offset);
351
352 static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);
353
355 {
356 LPSTACKFRAME64 sf;
357 PCONTEXT context;
358 };
359
360 static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID);
361
362 static bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext*);
363
364 static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const*, char const*, bool, bool);
365
366 static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0);
367
368 static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
369 static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
370
371 static int __cdecl Log(const TCHAR * format, ...);
372
373 static bool StoreSymbol(DWORD type , DWORD_PTR offset);
374 static void ClearSymbols();
375
376 static Optional<DWORD_PTR> GetIntegerRegisterValue(PCONTEXT context, ULONG registerId);
377
378 // Variables used by the class
379 static TCHAR m_szLogFileName[MAX_PATH];
380 static TCHAR m_szDumpFileName[MAX_PATH];
381 static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
382 static _invalid_parameter_handler m_previousCrtHandler;
383 static FILE* m_hReportFile;
384 static HANDLE m_hDumpFile;
385 static HANDLE m_hProcess;
387 static std::stack<SymbolDetail> symbolDetails;
388 static bool alreadyCrashed;
389 static std::mutex alreadyCrashedLock;
390 typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
392
393 static void PushSymbolDetail();
394 static void PopSymbolDetail();
395 static void PrintSymbolDetail();
396
397};
398
399extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
400#endif // _WHEATYEXCEPTIONREPORT_
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
const size_t bufferSize
Definition: RASession.h:27
char const *const rgBaseType[]
std::set< SymbolPair > SymbolPairs
WheatyExceptionReport g_WheatyExceptionReport
@ CV_ARM64_W29
@ CV_ARM64_W14
@ CV_ARM64_WZR
@ CV_AMD64_DIL
@ CV_ARM64_W15
@ CV_ARM64_X10
@ CV_ARM64_X15
@ CV_AMD64_RSI
@ CV_ARM64_X25
@ CV_AMD64_SPL
@ CV_AMD64_RIP
@ CV_AMD64_EAX
@ CV_AMD64_R13W
@ CV_AMD64_R14D
@ CV_ARM64_X14
@ CV_AMD64_R14W
@ CV_ARM64_IP1
@ CV_AMD64_R10B
@ CV_AMD64_R10D
@ CV_ARM64_X20
@ CV_ARM64_W23
@ CV_REG_EBX
@ CV_AMD64_R15W
@ CV_AMD64_R13
@ CV_ARM64_W21
@ CV_ARM64_W24
@ CV_ARM64_W17
@ CV_AMD64_RBX
@ CV_AMD64_RDI
@ CV_ARM64_W30
@ CV_ARM64_NOREG
@ CV_REG_ESI
@ CV_REG_EIP
@ CV_ARM64_X23
@ CV_AMD64_EBX
@ CV_ARM64_W12
@ CV_AMD64_ESP
@ CV_REG_ECX
@ CV_ARM64_W27
@ CV_AMD64_R14B
@ CV_ARM64_W20
@ CV_ARM64_W19
@ CV_AMD64_ESI
@ CV_REG_EBP
@ CV_REG_EAX
@ CV_AMD64_R13B
@ CV_AMD64_EDX
@ CV_AMD64_R11B
@ CV_AMD64_R15B
@ CV_AMD64_R15
@ CV_AMD64_R14
@ CV_AMD64_R10W
@ CV_AMD64_ECX
@ CV_ARM64_W16
@ CV_ARM64_X13
@ CV_ARM64_X22
@ CV_ARM64_X12
@ CV_ARM64_X26
@ CV_AMD64_R11D
@ CV_AMD64_BPL
@ CV_ARM64_X28
@ CV_AMD64_R12
@ CV_AMD64_R12W
@ CV_ARM64_X24
@ CV_ARM64_X19
@ CV_AMD64_RDX
@ CV_ARM64_X27
@ CV_AMD64_R11
@ CV_REG_EDI
@ CV_ARM64_W28
@ CV_ARM64_W11
@ CV_AMD64_R13D
@ CV_REG_ESP
@ CV_AMD64_R8W
@ CV_ARM64_W22
@ CV_AMD64_RBP
@ CV_AMD64_RAX
@ CV_AMD64_RCX
@ CV_ARM64_W13
@ CV_AMD64_R12D
@ CV_ARM64_W10
@ CV_AMD64_RSP
@ CV_ARM64_X11
@ CV_ARM64_W25
@ CV_AMD64_R9D
@ CV_AMD64_R15D
@ CV_AMD64_EBP
@ CV_ALLREG_VFRAME
@ CV_AMD64_SIL
@ CV_ARM64_W18
@ CV_AMD64_R8D
@ CV_ARM64_W26
@ CV_AMD64_R11W
@ CV_ARM64_X18
@ CV_AMD64_R9B
@ CV_ARM64_X21
@ CV_REG_EDX
@ CV_AMD64_R10
@ CV_ARM64_IP0
@ CV_AMD64_R8B
@ CV_AMD64_R9W
@ CV_AMD64_EDI
@ CV_AMD64_AL
@ CV_AMD64_R12B
@ CV_REG_NONE
@ DataIsUnknown
@ DataIsLocal
@ DataIsStaticMember
@ DataIsGlobal
@ DataIsStaticLocal
@ DataIsMember
@ DataIsObjectPtr
@ DataIsConstant
@ DataIsFileStatic
@ DataIsParam
@ btStdString
@ btCurrency
static LPCTSTR GetExceptionString(DWORD dwCode)
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD &section, DWORD_PTR &offset)
static int __cdecl Log(const TCHAR *format,...)
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID)
static BOOL _GetProcessorName(TCHAR *sProcessorName, DWORD maxcount)
static bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext *)
static SymbolPairs symbols
static void FormatOutputValue(char *pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride=0)
static BOOL _GetWindowsVersionFromWMI(TCHAR *szVersion, DWORD cntMax)
static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const *, char const *, bool, bool)
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
static _invalid_parameter_handler m_previousCrtHandler
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase)
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address)
static std::mutex alreadyCrashedLock
static TCHAR m_szDumpFileName[MAX_PATH]
static pRtlGetVersion RtlGetVersion
static BOOL _GetWindowsVersion(TCHAR *szVersion, DWORD cntMax)
static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle)
NTSTATUS(NTAPI * pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation)
static bool StoreSymbol(DWORD type, DWORD_PTR offset)
static Optional< DWORD_PTR > GetIntegerRegisterValue(PCONTEXT context, ULONG registerId)
static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo)
static void printTracesForAllThreads(bool)
static std::stack< SymbolDetail > symbolDetails
static LONG WINAPI WheatyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
static void __cdecl WheatyCrtHandler(wchar_t const *expression, wchar_t const *function, wchar_t const *file, unsigned int line, uintptr_t pReserved)
static TCHAR m_szLogFileName[MAX_PATH]
std::strong_ordering operator<=>(SymbolPair const &other) const =default
bool operator==(SymbolPair const &other) const =default
SymbolPair(DWORD type, DWORD_PTR offset)