Files
azerothcore-wotlk/src/common/Debugging/WheatyExceptionReport.h

203 lines
6.4 KiB
C++

#ifndef _WHEATYEXCEPTIONREPORT_
#define _WHEATYEXCEPTIONREPORT_
#if AC_PLATFORM == AC_PLATFORM_WINDOWS && !defined(__MINGW32__)
#include <dbghelp.h>
#include <mutex>
#include <set>
#include <stack>
#include <stdlib.h>
#include <winnt.h>
#include <winternl.h>
#define countof _countof
#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
#define WER_MAX_NESTING_LEVEL 4
#define WER_SMALL_BUFFER_SIZE 1024
#define WER_LARGE_BUFFER_SIZE WER_SMALL_BUFFER_SIZE * 16
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
{
btNoType = 0,
btVoid = 1,
btChar = 2,
btWChar = 3,
btInt = 6,
btUInt = 7,
btFloat = 8,
btBCD = 9,
btBool = 10,
btLong = 13,
btULong = 14,
btCurrency = 25,
btDate = 26,
btVariant = 27,
btComplex = 28,
btBit = 29,
btBSTR = 30,
btHresult = 31,
// Custom types
btStdString = 101
};
enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK
{
DataIsUnknown,
DataIsLocal,
DataIsStaticLocal,
DataIsParam,
DataIsObjectPtr,
DataIsFileStatic,
DataIsGlobal,
DataIsMember,
DataIsStaticMember,
DataIsConstant
};
char const* const rgBaseType[] =
{
"<user defined>", // btNoType = 0,
"void", // btVoid = 1,
"char",//char* // btChar = 2,
"wchar_t*", // btWChar = 3,
"signed char",
"unsigned char",
"int", // btInt = 6,
"unsigned int", // btUInt = 7,
"float", // btFloat = 8,
"<BCD>", // btBCD = 9,
"bool", // btBool = 10,
"short",
"unsigned short",
"long", // btLong = 13,
"unsigned long", // btULong = 14,
"int8",
"int16",
"int32",
"int64",
"int128",
"uint8",
"uint16",
"uint32",
"uint64",
"uint128",
"<currency>", // btCurrency = 25,
"<date>", // btDate = 26,
"VARIANT", // btVariant = 27,
"<complex>", // btComplex = 28,
"<bit>", // btBit = 29,
"BSTR", // btBSTR = 30,
"HRESULT" // btHresult = 31
};
struct SymbolPair
{
SymbolPair(DWORD type, DWORD_PTR offset)
{
_type = type;
_offset = offset;
}
bool operator<(SymbolPair const& other) const
{
return _offset < other._offset ||
(_offset == other._offset && _type < other._type);
}
DWORD _type;
DWORD_PTR _offset;
};
typedef std::set<SymbolPair> SymbolPairs;
struct SymbolDetail
{
SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
std::string ToString();
bool empty() const
{
return Value.empty() && !HasChildren;
}
std::string Prefix;
std::string Type;
std::string Suffix;
std::string Name;
std::string Value;
bool Logged;
bool HasChildren;
};
class WheatyExceptionReport
{
public:
WheatyExceptionReport();
~WheatyExceptionReport();
// entry point where control comes on an unhandled exception
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 void printTracesForAllThreads(bool);
private:
// where report info is extracted and generated
static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo);
static void PrintSystemInfo();
static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);
static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount);
// Helper functions
static LPTSTR GetExceptionString(DWORD dwCode);
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len,
DWORD& section, DWORD_PTR& offset);
static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID);
static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64*);
static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool&, char const*, char*, bool, bool);
static void FormatOutputValue(char* pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl Log(const TCHAR* format, ...);
static int __cdecl StackLog(const TCHAR* format, va_list argptr);
static int __cdecl HeapLog(const TCHAR* format, va_list argptr);
static bool StoreSymbol(DWORD type, DWORD_PTR offset);
static void ClearSymbols();
// Variables used by the class
static TCHAR m_szLogFileName[MAX_PATH];
static TCHAR m_szDumpFileName[MAX_PATH];
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
static _invalid_parameter_handler m_previousCrtHandler;
static HANDLE m_hReportFile;
static HANDLE m_hDumpFile;
static HANDLE m_hProcess;
static SymbolPairs symbols;
static std::stack<SymbolDetail> symbolDetails;
static bool stackOverflowException;
static bool alreadyCrashed;
static std::mutex alreadyCrashedLock;
typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
static pRtlGetVersion RtlGetVersion;
static void PushSymbolDetail();
static void PopSymbolDetail();
static void PrintSymbolDetail();
};
extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
#endif // _WIN32
#endif // _WHEATYEXCEPTIONREPORT_