Local snapshot for Docker build (includes mod-ale)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Errors.h"
|
||||
#include "Duration.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
/**
|
||||
@file Errors.cpp
|
||||
|
||||
@brief This file contains definitions of functions used for reporting critical application errors
|
||||
|
||||
It is very important that (std::)abort is NEVER called in place of *((volatile int*)nullptr) = 0;
|
||||
Calling abort() on Windows does not invoke unhandled exception filters - a mechanism used by WheatyExceptionReport
|
||||
to log crashes. exit(1) calls here are for static analysis tools to indicate that calling functions defined in this file
|
||||
terminates the application.
|
||||
*/
|
||||
|
||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||
#include <Windows.h>
|
||||
#define Crash(message) \
|
||||
ULONG_PTR execeptionArgs[] = { reinterpret_cast<ULONG_PTR>(strdup(message)), reinterpret_cast<ULONG_PTR>(_ReturnAddress()) }; \
|
||||
RaiseException(EXCEPTION_ASSERTION_FAILURE, 0, 2, execeptionArgs);
|
||||
#else
|
||||
// should be easily accessible in gdb
|
||||
extern "C" { char const* AcoreAssertionFailedMessage = nullptr; }
|
||||
#define Crash(message) \
|
||||
AcoreAssertionFailedMessage = strdup(message); \
|
||||
*((volatile int*)nullptr) = 0; \
|
||||
exit(1);
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @name MakeMessage
|
||||
* @brief Make message for display erros
|
||||
* @param messageType Message type (ASSERTION FAILED, FATAL ERROR, ERROR) end etc
|
||||
* @param file Path to file
|
||||
* @param line Line number in file
|
||||
* @param function Functionn name
|
||||
* @param message Condition to string format
|
||||
* @param fmtMessage [optional] Display format message after condition
|
||||
* @param debugInfo [optional] Display debug info
|
||||
*/
|
||||
inline std::string MakeMessage(std::string_view messageType, std::string_view file, uint32 line, std::string_view function,
|
||||
std::string_view message, std::string_view fmtMessage = {}, std::string_view debugInfo = {})
|
||||
{
|
||||
std::string msg = Acore::StringFormat("\n>> {}\n\n# Location: {}:{}\n# Function: {}\n# Condition: {}\n", messageType, file, line, function, message);
|
||||
|
||||
if (!fmtMessage.empty())
|
||||
{
|
||||
msg.append(Acore::StringFormat("# Message: {}\n", fmtMessage));
|
||||
}
|
||||
|
||||
if (!debugInfo.empty())
|
||||
{
|
||||
msg.append(Acore::StringFormat("\n# Debug info: {}\n", debugInfo));
|
||||
}
|
||||
|
||||
return Acore::StringFormat(
|
||||
"#{0:-^{2}}#\n"
|
||||
" {1: ^{2}} \n"
|
||||
"#{0:-^{2}}#\n", "", msg, 70);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name MakeAbortMessage
|
||||
* @brief Make message for display erros
|
||||
* @param file Path to file
|
||||
* @param line Line number in file
|
||||
* @param function Functionn name
|
||||
* @param fmtMessage [optional] Display format message after condition
|
||||
*/
|
||||
inline std::string MakeAbortMessage(std::string_view file, uint32 line, std::string_view function, std::string_view fmtMessage = {})
|
||||
{
|
||||
std::string msg = Acore::StringFormat("\n>> ABORTED\n\n# Location '{}:{}'\n# Function '{}'\n", file, line, function);
|
||||
|
||||
if (!fmtMessage.empty())
|
||||
{
|
||||
msg.append(Acore::StringFormat("# Message '{}'\n", fmtMessage));
|
||||
}
|
||||
|
||||
return Acore::StringFormat(
|
||||
"\n#{0:-^{2}}#\n"
|
||||
" {1: ^{2}} \n"
|
||||
"#{0:-^{2}}#\n", "", msg, 70);
|
||||
}
|
||||
}
|
||||
|
||||
void Acore::Assert(std::string_view file, uint32 line, std::string_view function, std::string_view debugInfo, std::string_view message, std::string_view fmtMessage /*= {}*/)
|
||||
{
|
||||
std::string formattedMessage = MakeMessage("ASSERTION FAILED", file, line, function, message, fmtMessage, debugInfo);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
fflush(stderr);
|
||||
Crash(formattedMessage.c_str());
|
||||
}
|
||||
|
||||
void Acore::Fatal(std::string_view file, uint32 line, std::string_view function, std::string_view message, std::string_view fmtMessage /*= {}*/)
|
||||
{
|
||||
std::string formattedMessage = MakeMessage("FATAL ERROR", file, line, function, message, fmtMessage);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
fflush(stderr);
|
||||
std::this_thread::sleep_for(10s);
|
||||
Crash(formattedMessage.c_str());
|
||||
}
|
||||
|
||||
void Acore::Error(std::string_view file, uint32 line, std::string_view function, std::string_view message)
|
||||
{
|
||||
std::string formattedMessage = MakeMessage("ERROR", file, line, function, message);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
fflush(stderr);
|
||||
std::this_thread::sleep_for(10s);
|
||||
Crash(formattedMessage.c_str());
|
||||
}
|
||||
|
||||
void Acore::Warning(std::string_view file, uint32 line, std::string_view function, std::string_view message)
|
||||
{
|
||||
std::string formattedMessage = MakeMessage("WARNING", file, line, function, message);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
}
|
||||
|
||||
void Acore::Abort(std::string_view file, uint32 line, std::string_view function, std::string_view fmtMessage /*= {}*/)
|
||||
{
|
||||
std::string formattedMessage = MakeAbortMessage(file, line, function, fmtMessage);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
fflush(stderr);
|
||||
std::this_thread::sleep_for(10s);
|
||||
Crash(formattedMessage.c_str());
|
||||
}
|
||||
|
||||
void Acore::AbortHandler(int sigval)
|
||||
{
|
||||
// nothing useful to log here, no way to pass args
|
||||
std::string formattedMessage = StringFormat("Caught signal {}\n", sigval);
|
||||
fmt::print(stderr, "{}", formattedMessage);
|
||||
fflush(stderr);
|
||||
Crash(formattedMessage.c_str());
|
||||
}
|
||||
|
||||
std::string GetDebugInfo()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ACORE_ERRORS_H_
|
||||
#define _ACORE_ERRORS_H_
|
||||
|
||||
#include "StringFormat.h"
|
||||
|
||||
namespace Acore
|
||||
{
|
||||
// Default function
|
||||
[[noreturn]] AC_COMMON_API void Assert(std::string_view file, uint32 line, std::string_view function, std::string_view debugInfo, std::string_view message, std::string_view fmtMessage = {});
|
||||
[[noreturn]] AC_COMMON_API void Fatal(std::string_view file, uint32 line, std::string_view function, std::string_view message, std::string_view fmtMessage = {});
|
||||
[[noreturn]] AC_COMMON_API void Error(std::string_view file, uint32 line, std::string_view function, std::string_view message);
|
||||
[[noreturn]] AC_COMMON_API void Abort(std::string_view file, uint32 line, std::string_view function, std::string_view fmtMessage = {});
|
||||
|
||||
template<typename... Args>
|
||||
AC_COMMON_API inline void Assert(std::string_view file, uint32 line, std::string_view function, std::string_view debugInfo, std::string_view message, std::string_view fmt, Args&&... args)
|
||||
{
|
||||
Assert(file, line, function, debugInfo, message, StringFormat(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
AC_COMMON_API inline void Fatal(std::string_view file, uint32 line, std::string_view function, std::string_view message, std::string_view fmt, Args&&... args)
|
||||
{
|
||||
Fatal(file, line, function, message, StringFormat(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
AC_COMMON_API inline void Abort(std::string_view file, uint32 line, std::string_view function, std::string_view fmt, Args&&... args)
|
||||
{
|
||||
Abort(file, line, function, StringFormat(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
AC_COMMON_API void Warning(std::string_view file, uint32 line, std::string_view function, std::string_view message);
|
||||
|
||||
[[noreturn]] AC_COMMON_API void AbortHandler(int sigval);
|
||||
|
||||
} // namespace Acore
|
||||
|
||||
AC_COMMON_API std::string GetDebugInfo();
|
||||
|
||||
#define WPAssert(cond, ...) do { if (!(cond)) Acore::Assert(__FILE__, __LINE__, __FUNCTION__, GetDebugInfo(), #cond, ##__VA_ARGS__); } while(0)
|
||||
#define WPAssert_NODEBUGINFO(cond) do { if (!(cond)) Acore::Assert(__FILE__, __LINE__, __FUNCTION__, "", #cond); } while(0)
|
||||
#define WPFatal(cond, ...) do { if (!(cond)) Acore::Fatal(__FILE__, __LINE__, __FUNCTION__, #cond, ##__VA_ARGS__); } while(0)
|
||||
#define WPError(cond, msg) do { if (!(cond)) Acore::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0)
|
||||
#define WPWarning(cond, msg) do { if (!(cond)) Acore::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0)
|
||||
#define WPAbort(...) do { Acore::Abort(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); } while(0)
|
||||
|
||||
#ifdef PERFORMANCE_PROFILING
|
||||
#define ASSERT(cond, ...) ((void)0)
|
||||
#define ASSERT_NODEBUGINFO(cond, ...) ((void)0)
|
||||
#else
|
||||
#define ASSERT WPAssert
|
||||
#define ASSERT_NODEBUGINFO WPAssert_NODEBUGINFO
|
||||
#endif
|
||||
|
||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||
#define EXCEPTION_ASSERTION_FAILURE 0xC0000420L
|
||||
#endif
|
||||
|
||||
#define ABORT WPAbort
|
||||
|
||||
template <typename T>
|
||||
inline T* ASSERT_NOTNULL_IMPL(T* pointer, std::string_view expr)
|
||||
{
|
||||
ASSERT(pointer, "{}", expr);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
#define ASSERT_NOTNULL(pointer) ASSERT_NOTNULL_IMPL(pointer, #pointer)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,202 @@
|
||||
#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, std::size_t bufferSize, std::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_
|
||||
Reference in New Issue
Block a user