[*] "Improve" win32 AuDebug

This commit is contained in:
Reece Wilson 2022-06-16 01:27:00 +01:00
parent 942373328c
commit 5aea27d56d
5 changed files with 120 additions and 61 deletions

View File

@ -258,14 +258,37 @@ namespace Aurora
struct FIOConfig struct FIOConfig
{ {
/// You can bypass branding by assigning an empty string to 'defaultBrand' /// You can bypass branding by assigning an empty string to 'defaultBrand'
AuString defaultBrand = "Aurora"; AuString defaultBrand = "Aurora SDK Sample";
}; };
struct DebugConfig struct DebugConfig
{ {
/**
* @brief Precache/initialize symbols for printable stack traces under binaries not intended for shipping to consumers
*/
bool nonshipPrecachesSymbols {true}; bool nonshipPrecachesSymbols {true};
/**
* @brief Activates the internal AddVectoredExceptionHandler handler. Might conflict with DRM and other debugging utilities
*/
bool enableWin32RootExceptionHandler {true}; bool enableWin32RootExceptionHandler {true};
/**
* @brief
*/
bool enableInjectedExceptionHandler {true}; bool enableInjectedExceptionHandler {true};
/**
* @brief Causes a SysPanic
*/
bool isMemoryErrorFatal {false};
/**
* @brief
*/
bool isExceptionThrowFatal {false};
bool printExceptionStackTracesOut {true};
}; };
struct RuntimeStartInfo struct RuntimeStartInfo

View File

@ -237,8 +237,10 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t
try try
{ {
auto trace = AuDebug::GetStackTrace(); auto trace = AuDebug::GetStackTrace();
if (gRuntimeConfig.debug.printExceptionStackTracesOut)
{
AuDebug::ReportSEH(handle, exception, throwInfo, {}, trace, AuDebug::ReportSEH(handle, exception, throwInfo, {}, trace,
[&](const AuString &str) [&](const AuString &str)
{ {
@ -246,6 +248,12 @@ extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *t
AuLogWarn("{}", StringifyStackTrace(trace)); AuLogWarn("{}", StringifyStackTrace(trace));
}); });
} }
else
{
AuDebug::ReportSEH(handle, exception, throwInfo, {}, trace,
[&](const AuString &str) {});
}
}
catch (...) catch (...)
{ {

View File

@ -106,26 +106,53 @@ namespace Aurora::Debug
return (info.Protect & (PAGE_READONLY | PAGE_READWRITE)) != 0; return (info.Protect & (PAGE_READONLY | PAGE_READWRITE)) != 0;
} }
bool InPanic();
static LONG CALLBACK HandleVectorException(_EXCEPTION_POINTERS *ExceptionInfo) static LONG CALLBACK HandleVectorException(_EXCEPTION_POINTERS *ExceptionInfo)
{ {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == DBG_CONTROL_C) if (ExceptionInfo->ExceptionRecord->ExceptionCode == DBG_CONTROL_C)
{ {
Exit::PostLevel(AuThreads::GetThread(), Exit::ETriggerLevel::eSigTerminate); Exit::PostLevel(AuThreads::GetThread(), Exit::ETriggerLevel::eSigTerminate);
return Exit::gHasCanceled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; return AuExchange(Exit::gHasCanceled, false) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
} }
// https://www.youtube.com/embed/w6P03sTzSqM?start=2&autoplay=1
if (ExceptionInfo->ExceptionRecord->ExceptionCode < STATUS_GUARD_PAGE_VIOLATION) if (ExceptionInfo->ExceptionRecord->ExceptionCode < STATUS_GUARD_PAGE_VIOLATION)
{ {
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
#if defined(AU_CFG_ID_SHIP)
// you what?
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
{
SysPanic("");
return EXCEPTION_CONTINUE_EXECUTION;
}
#else
// debugger go brrr
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
{ {
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
auto minimal = gDebugLocked++; #endif
// debug builds can go do something stupid
// QA builds, staging, rel in any form should just give up trying if we're under a panic
#if !defined(AU_CFG_ID_DEBUG)
if (InPanic())
{
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
// something dumb like this mess w hat i had before.
// gave up trying
auto minimal = gDebugLocked++;
if (minimal >= 5) if (minimal >= 5)
{ {
SysPanic("Nested Exception"); SysPanic("Nested Exception");
@ -177,7 +204,6 @@ namespace Aurora::Debug
StackTrace backtrace; StackTrace backtrace;
ParseStack(ExceptionInfo->ContextRecord, backtrace); ParseStack(ExceptionInfo->ContextRecord, backtrace);
#if defined(_AU_USE_EXTENDED_FWD_FACING_DEBUGGING) #if defined(_AU_USE_EXTENDED_FWD_FACING_DEBUGGING)
bool isInternal = true; bool isInternal = true;
#else #else
@ -190,27 +216,30 @@ namespace Aurora::Debug
{ {
// Pre-submit callback -> its showtime // Pre-submit callback -> its showtime
if ((isCritical || isInternal) && (minimal == 0)) if ((isCritical || isInternal) && (minimal == 0))
{
if (gRuntimeConfig.debug.printExceptionStackTracesOut)
{ {
AuLogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, str); AuLogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, str);
AuLogWarn("{}", StringifyStackTrace(backtrace)); AuLogWarn("{}", StringifyStackTrace(backtrace));
} }
}
}); });
} }
try try
{ {
Grug::Arrow empty;
Grug::HurlRaiseProblematicEvent(&empty);
if (isCritical) if (isCritical)
{ {
Telemetry::Mayday(); Telemetry::Mayday();
} }
if (isCritical) if (isCritical || gRuntimeConfig.debug.isExceptionThrowFatal) // exception = literally anything
{ {
PlatformHandleFatal(true); PlatformHandleFatal(true);
} }
Grug::Arrow empty;
Grug::HurlRaiseProblematicEvent(&empty);
} }
catch (...) catch (...)
{ {
@ -314,15 +343,13 @@ namespace Aurora::Debug
{ {
AuString path; AuString path;
HANDLE hFile; HANDLE hFile;
std::wstring wpath;
AuString utf8Path; AuString utf8Path;
MINIDUMP_EXCEPTION_INFORMATION info; MINIDUMP_EXCEPTION_INFORMATION info;
auto ok = AuIOFS::GetProfileDomain(path); auto ok = AuIOFS::GetProfileDomain(path); // < could throw inside
if (!ok) if (!ok)
{ {
AuLogWarn("Couldn't find minidump directory"); path = ".\\";
goto miniMiniDumpOut;
} }
info.ClientPointers = true; info.ClientPointers = true;
@ -336,22 +363,22 @@ namespace Aurora::Debug
MiniDumpWithThreadInfo; MiniDumpWithThreadInfo;
while (wpath.empty()) static std::wstring pathStorage(8192, L' ');
{
try
{
utf8Path = path + "Crashes/" + GetDumpName();
wpath = Locale::ConvertFromUTF8(utf8Path);
}
catch (...)
{
} int index {};
}
AuIOFS::CreateDirectories(utf8Path, true); index += MultiByteToWideChar(CP_UTF8, 0, path.c_str(), path.length(), pathStorage.data() + index, pathStorage.size() - index);
static const std::string crashesSlash = "Crashes\\";
index += MultiByteToWideChar(CP_UTF8, 0, crashesSlash.c_str(), crashesSlash.length(), pathStorage.data() + index, pathStorage.size() - index);
hFile = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); auto dumpName = GetDumpName();;
index += MultiByteToWideChar(CP_UTF8, 0, dumpName.c_str(), dumpName.length(), pathStorage.data() + index, pathStorage.size() - index);
pathStorage.resize(index);
AuIOFS::CreateDirectories(utf8Path, true); // potentially unsafe / could throw inside
hFile = CreateFileW(pathStorage.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != INVALID_HANDLE_VALUE) if (hFile != INVALID_HANDLE_VALUE)
{ {
AuLogWarn("[1] Couldn't open minidump file. Has a debugger locked the .dmp file?"); AuLogWarn("[1] Couldn't open minidump file. Has a debugger locked the .dmp file?");
@ -370,7 +397,7 @@ namespace Aurora::Debug
miniMiniDumpOut: miniMiniDumpOut:
Telemetry::NewBlackBoxEntryMinidump report {}; Telemetry::NewBlackBoxEntryMinidump report {};
report.includesRx = false; report.includesRx = false;
report.resource.path = path; report.resource.path = dumpName; // <COPY
report.resource.type = Telemetry::ENewBlackBoxResourceType::eLocal; report.resource.type = Telemetry::ENewBlackBoxResourceType::eLocal;
Telemetry::ReportDyingBreath(report); Telemetry::ReportDyingBreath(report);
@ -382,7 +409,7 @@ namespace Aurora::Debug
static void CacheInternalBuildSymbols() static void CacheInternalBuildSymbols()
{ {
#if defined(DEBUG) || defined(STAGING) #if defined(AU_CFG_ID_INTERNAL) || defined(AU_CFG_ID_DEBUG)
SymInitialize(GetCurrentProcess(), NULL, TRUE); SymInitialize(GetCurrentProcess(), NULL, TRUE);
#endif #endif
} }
@ -418,6 +445,9 @@ namespace Aurora::Debug
DisableWindowsErrorReporting(); DisableWindowsErrorReporting();
// .. // ..
if (gRuntimeConfig.debug.enableWin32RootExceptionHandler)
{
AddVectoredExceptionHandler(1, HandleVectorException); AddVectoredExceptionHandler(1, HandleVectorException);
} }
} }
}

View File

@ -14,12 +14,13 @@
namespace Aurora::Debug namespace Aurora::Debug
{ {
void PlatformHandleFatal(); void PlatformHandleFatal();
static bool gHandlingFatal = false;
AUKN_SYM void DebugBreak() AUKN_SYM void DebugBreak()
{ {
#if defined(DEBUG) || defined(STAGING) #if defined(AU_CFG_ID_INTERNAL) || defined(AU_CFG_ID_DEBUG)
#if defined(AURORA_PLATFORM_WIN32) #if defined(AURORA_PLATFORM_WIN32)
#if defined(STAGING) #if defined(AU_CFG_ID_INTERNAL)
if (IsDebuggerPresent()) if (IsDebuggerPresent())
#endif #endif
{ {
@ -38,35 +39,27 @@ namespace Aurora::Debug
#endif #endif
} }
bool InPanic()
{
return gHandlingFatal;
}
AUKN_SYM void Panic() AUKN_SYM void Panic()
{ {
// //
static bool handlingFatal = false; if (gHandlingFatal)
if (AuExchange(handlingFatal, true))
{ {
goto failFast; goto failFast;
} }
#if defined(AU_CFG_ID_DEBUG)
DebugBreak(); DebugBreak();
#endif
try if (AuExchange(gHandlingFatal, true))
{ {
CheckErrors(); goto failFast;
} }
catch (...)
{
}
try
{
Grug::GrugFlushFlushs();
}
catch (...)
{
}
try try
{ {
@ -78,12 +71,14 @@ namespace Aurora::Debug
} }
static bool panicSingleshot = false; failFast:
if (AuExchange(panicSingleshot, true))
static bool runPlatformFastFailOnce {};
if (!AuExchange(runPlatformFastFailOnce, true))
{ {
try try
{ {
Telemetry::Mayday(); Debug::PlatformHandleFatal(true);
} }
catch (...) catch (...)
{ {
@ -91,7 +86,6 @@ namespace Aurora::Debug
} }
} }
failFast:
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
__fastfail('FCKD'); __fastfail('FCKD');
#else #else

View File

@ -7,3 +7,7 @@
***/ ***/
#pragma once #pragma once
namespace Aurora::Debug
{
bool InPanic();
}