[+] AuBitsToLower, AuBitsToHigher (returns half of an input word)
[+] AuPopCnt [+] NormalizePath, GetFileFromPath, GetDirectoryFromPath, GoUpToSeparator [*] Fix Version Helpers again [*] Fix registry locale memory check under read registry in SWInfo [*] Breakout portable process code away from evil win32 code [*] .dynlib -> .dylib under macos
This commit is contained in:
parent
fbd437d3d4
commit
d7c6d66fad
@ -38,6 +38,10 @@ namespace Aurora::IO::FS
|
||||
|
||||
AUKN_SYM bool Copy(const AuString &src, const AuString &dest);
|
||||
|
||||
AUKN_SYM bool NormalizePath(AuString &out, const AuString &in);
|
||||
AUKN_SYM bool GetFileFromPath(AuString &out, const AuString &path);
|
||||
AUKN_SYM bool GetDirectoryFromPath(AuString &out, const AuString &path);
|
||||
AUKN_SYM bool GoUpToSeparator(AuString &out, const AuString &path);
|
||||
}
|
||||
|
||||
#include "IFileStream.hpp"
|
||||
|
@ -14,7 +14,6 @@ namespace Aurora::Telemetry
|
||||
eSpecsMetadata,
|
||||
eMessage,
|
||||
eStackWarning,
|
||||
eWinCxxException,
|
||||
eAccessViolation,
|
||||
eAssertion,
|
||||
ePanic,
|
||||
@ -37,6 +36,7 @@ namespace Aurora::Telemetry
|
||||
|
||||
struct NewBlockBoxEntryStackReport
|
||||
{
|
||||
AuString str;
|
||||
Debug::StackTrace backtrace;
|
||||
AuUInt32 fenceId;
|
||||
};
|
||||
@ -70,13 +70,6 @@ namespace Aurora::Telemetry
|
||||
NewBlockBoxEntryStackReport stack;
|
||||
};
|
||||
|
||||
struct NewBlockBoxEntryWin32CxxException
|
||||
{
|
||||
NewBlockBoxEntryStackReport stack;
|
||||
AuString str;
|
||||
AuUInt32 fenceId;
|
||||
};
|
||||
|
||||
struct NewBlockboxEntryBasicMessage
|
||||
{
|
||||
Console::ConsoleMessage message;
|
||||
@ -154,7 +147,6 @@ namespace Aurora::Telemetry
|
||||
NewBlockboxEntryMessage message;
|
||||
NewBlockboxEntryMessage assertion;
|
||||
NewBlockBoxEntryStackReport stack;
|
||||
NewBlockBoxEntryWin32CxxException wincxx;
|
||||
NewBlockboxEntryBasicMessage log;
|
||||
NewBlockboxEntryBasicMessage panic;
|
||||
NewBlockBoxEntryMemoryViolation violation;
|
||||
|
@ -737,7 +737,110 @@ static auline bool AuBitScanForward(AuUInt8 &index, T value)
|
||||
return success;
|
||||
}
|
||||
|
||||
// TODO: AuPopCnt
|
||||
template<typename T>
|
||||
struct AuHalfWord
|
||||
{
|
||||
using ReturnType_t = AuConditional_t<AuIsSame_v<T, AuUInt64>, AuUInt32, AuConditional_t<AuIsSame_v<T, AuUInt32>, AuUInt32, AuConditional_t<AuIsSame_v<T, AuUInt16>, AuUInt8, AuFalseType>>>;
|
||||
|
||||
static ReturnType_t ToLower(T in)
|
||||
{
|
||||
if constexpr (AuIsSame_v<T, AuUInt64>)
|
||||
{
|
||||
return in & AuUInt64(0xFFFFFFFF);
|
||||
}
|
||||
else if constexpr (AuIsSame_v<T, AuUInt32>)
|
||||
{
|
||||
return in & 0xFFFF;
|
||||
}
|
||||
else if constexpr (AuIsSame_v<T, AuUInt16>)
|
||||
{
|
||||
return in & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static ReturnType_t ToHigher(T in)
|
||||
{
|
||||
if constexpr (AuIsSame_v<T, AuUInt64>)
|
||||
{
|
||||
return (in >> AuUInt64(32)) & AuUInt64(0xFFFFFFFF);
|
||||
}
|
||||
else if constexpr (AuIsSame_v<T, AuUInt32>)
|
||||
{
|
||||
return (in >> 16) & 0xFFFF;
|
||||
}
|
||||
else if constexpr (AuIsSame_v<T, AuUInt16>)
|
||||
{
|
||||
return (in >> 8) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static auto AuBitsToLower(T in)
|
||||
{
|
||||
return AuHalfWord<T>::ToLower(in);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto AuBitsToHigher(T in)
|
||||
{
|
||||
return AuHalfWord<T>::ToHigher(in);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static AuUInt8 AuPopCnt(T in)
|
||||
{
|
||||
#if defined(AURORA_COMPILER_MSVC)
|
||||
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)
|
||||
if constexpr (sizeof(T) == sizeof(AuUInt64))
|
||||
return _mm_popcnt_u64(in);
|
||||
else if constexpr (sizeof(T) < sizeof(AuUInt32))
|
||||
return __popcnt(in);
|
||||
else if constexpr (sizeof(T) <= sizeof(AuUInt16))
|
||||
return __popcnt16(in);
|
||||
#endif
|
||||
#else
|
||||
if constexpr (sizeof(T) == sizeof(unsigned long long))
|
||||
return __builtin_popcountll(static_cast<unsigned long long>(value));
|
||||
else if constexpr (sizeof(T) == sizeof(unsigned long))
|
||||
return __builtin_popcountl(static_cast<unsigned long>(value));
|
||||
else if constexpr (sizeof(T) == sizeof(unsigned int))
|
||||
return __builtin_popcount(static_cast<unsigned int>(value));
|
||||
#endif
|
||||
|
||||
#if defined(AU_CPU_ENDIAN_LITTLE)
|
||||
if constexpr (sizeof(T) == sizeof(AuUInt64))
|
||||
{
|
||||
AuUInt64 m1 = 0x5555555555555555ll;
|
||||
AuUInt64 m2 = 0x3333333333333333ll;
|
||||
AuUInt64 m4 = 0x0F0F0F0F0F0F0F0Fll;
|
||||
AuUInt64 h01 = 0x0101010101010101ll;
|
||||
|
||||
in -= (in >> 1) & m1;
|
||||
in = (in & m2) + ((in >> 2) & m2);
|
||||
in = (in + (in >> 4)) & m4;
|
||||
|
||||
return (in * h01) >> 56;
|
||||
}
|
||||
else if constexpr (sizeof(T) == sizeof(AuUInt32))
|
||||
{
|
||||
in = in - ((in >> 1) & 0x55555555);
|
||||
in = (in & 0x33333333) + ((in >> 2) & 0x33333333);
|
||||
return (((in + (in >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO: AuBitScanReverse
|
||||
|
||||
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_ARM)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <Source/Telemetry/Telemetry.hpp>
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
#endif
|
||||
|
||||
@ -394,5 +395,9 @@ namespace Aurora::Debug
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
InitWin32();
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
InitNT();
|
||||
#endif
|
||||
}
|
||||
}
|
@ -31,6 +31,6 @@ namespace Aurora::Debug
|
||||
AuOptional<AuUInt32> TryFetchCError();
|
||||
|
||||
void CheckErrors();
|
||||
|
||||
void PlatformHandleFatal(bool fatal);
|
||||
void InitDebug();
|
||||
}
|
||||
|
244
Source/Debug/ExceptionWatcher.NT.cpp
Normal file
244
Source/Debug/ExceptionWatcher.NT.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: ExceptionWatcher.NT.cpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include <ehdata.h>
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
#include "Stack.Win32.hpp"
|
||||
#endif
|
||||
|
||||
#include "Debug.hpp"
|
||||
#include <Source/Telemetry/Telemetry.hpp>
|
||||
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
static std::string kStringRawName = typeid(std::string).raw_name();
|
||||
|
||||
static bool IsReadable(const void *address)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
|
||||
if (!VirtualQuery(address, &info, sizeof(info)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!info.BaseAddress)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info.Protect & (PAGE_READONLY | PAGE_READWRITE)) != 0;
|
||||
}
|
||||
|
||||
AuString ReportSEH(HMODULE handle, void *exception, const void *throwInfo, const AuFunction<AuString()> &resolveFallback, const StackTrace &trace, const AuFunction<void(const AuString &)> &prereport)
|
||||
{
|
||||
AuString message;
|
||||
|
||||
if (handle && handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
try
|
||||
{
|
||||
const ThrowInfo *pthrowInfo = reinterpret_cast<const ThrowInfo *>(throwInfo);
|
||||
auto attribs = pthrowInfo->attributes;
|
||||
|
||||
const auto catchableTypeArray = reinterpret_cast<const CatchableTypeArray *>(reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(pthrowInfo->pCatchableTypeArray));
|
||||
|
||||
AuString suffix;
|
||||
for (int i = 0; i < catchableTypeArray->nCatchableTypes; i++)
|
||||
{
|
||||
const auto type = reinterpret_cast<CatchableType *> (reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(catchableTypeArray->arrayOfCatchableTypes[i]));
|
||||
const auto descriptor = reinterpret_cast<std::type_info *> (reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(type->pType));
|
||||
|
||||
|
||||
message += (i == 0 ? "" : AuString(", ")) + descriptor->name(); // __std_type_info_name
|
||||
|
||||
if (_strnicmp(descriptor->raw_name(), ".?AVException@", 15 - 1) == 0)
|
||||
{
|
||||
auto exception2 = reinterpret_cast<std::exception *>(exception);
|
||||
auto wptr = exception2->what();
|
||||
if (wptr)
|
||||
{
|
||||
suffix = wptr;
|
||||
}
|
||||
}
|
||||
else if (_strnicmp(descriptor->raw_name(), ".PEAD", 5) == 0)
|
||||
{
|
||||
auto possibleStringPointer = reinterpret_cast<const char **>(exception);
|
||||
if (IsReadable(possibleStringPointer))
|
||||
{
|
||||
auto string = *possibleStringPointer;
|
||||
if (IsReadable(string) && (strnlen(string, 4096) < 1024))
|
||||
{
|
||||
suffix = string;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_strnicmp(descriptor->raw_name(), kStringRawName.data(), kStringRawName.size()) == 0)
|
||||
{
|
||||
auto possibleStdStringPointer = reinterpret_cast<std::string *>(exception);
|
||||
if (IsReadable(possibleStdStringPointer))
|
||||
{
|
||||
suffix = *possibleStdStringPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix.size())
|
||||
{
|
||||
message += AuString("\r\n ") + suffix;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (message.find("invalid sto") != AuString::npos) return message;
|
||||
|
||||
try
|
||||
{
|
||||
if (message.empty() && resolveFallback)
|
||||
{
|
||||
message = resolveFallback();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (prereport)
|
||||
{
|
||||
prereport(message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Telemetry::NewBlockboxEntry entry;
|
||||
entry.type = Telemetry::ENewBlackBoxEntry::eStackWarning;
|
||||
entry.stack.fenceId = ReportStackTrace(trace, message);
|
||||
entry.stack.backtrace = trace;
|
||||
Telemetry::Report(entry);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
static void HandleFatal(bool fatal, _EXCEPTION_POINTERS *pExceptionInfo)
|
||||
{
|
||||
static bool handlingFatal = false;
|
||||
|
||||
if (std::exchange(handlingFatal, true))
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(INTERNAL)
|
||||
if (!fatal)
|
||||
{
|
||||
if (IsDebuggerPresent()) __debugbreak();
|
||||
else BlackboxReport(pExceptionInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveMinidump(pExceptionInfo);
|
||||
}
|
||||
#else
|
||||
BlackboxReport(pExceptionInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformHandleFatal(bool fatal)
|
||||
{
|
||||
_EXCEPTION_POINTERS ptrs;
|
||||
StackTrace ret;
|
||||
CONTEXT ctx;
|
||||
|
||||
if (!GetThreadContext(GetCurrentThread(), &ctx))
|
||||
{
|
||||
Debug::Panic();
|
||||
}
|
||||
|
||||
ptrs.ExceptionRecord = {};
|
||||
ptrs.ContextRecord = &ctx;
|
||||
HandleFatal(fatal, &ptrs);
|
||||
}
|
||||
|
||||
void InitNT()
|
||||
{
|
||||
SetUnhandledExceptionFilter([](_EXCEPTION_POINTERS *pExceptionInfo) -> LONG
|
||||
{
|
||||
AuLogWarn("Handling fatal NT err exception...");
|
||||
HandleFatal(true, pExceptionInfo);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static thread_local AuUInt tlsThrowCounter;
|
||||
|
||||
extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *throwInfo, void *caller)
|
||||
{
|
||||
if (!throwInfo) return;
|
||||
if (!exception) return;
|
||||
|
||||
HMODULE handle = 0;
|
||||
|
||||
if (_EH_RELATIVE_TYPEINFO)
|
||||
{
|
||||
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCSTR>(caller), reinterpret_cast<HMODULE *>(&handle)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// we will probably overflow for a bit if an inner try catch borks up somewhere
|
||||
if ((tlsThrowCounter++) == 7)
|
||||
{
|
||||
tlsThrowCounter--;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
auto trace = AuDebug::GetStackTrace();
|
||||
AuDebug::ReportSEH(handle, exception, throwInfo, {}, trace,
|
||||
[&](const AuString &str)
|
||||
{
|
||||
AuLogWarn("Local MSVC Exception: 0x{:x}, {}", exception, str.c_str());
|
||||
AuLogWarn("{}", StringifyStackTrace(trace));
|
||||
});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
tlsThrowCounter--;
|
||||
}
|
17
Source/Debug/ExceptionWatcher.NT.hpp
Normal file
17
Source/Debug/ExceptionWatcher.NT.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: ExceptionWatcher.NT.hpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
AuString ReportSEH(HMODULE handle, void *exception, const void *throwInfo, const AuFunction<AuString()> &resolveFallback, const StackTrace &trace, const AuFunction<void(const AuString &)> &prereport);
|
||||
|
||||
void InitNT();
|
||||
}
|
||||
|
||||
extern "C" AUKN_SYM void __stdcall _ReportMSVCSEH(void *exception, const void *throwInfo, void *caller);
|
@ -5,3 +5,6 @@
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Debug.hpp"
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
#include "Stack.Win32.hpp"
|
||||
|
||||
#include <Source/Process/ProcessMap.Win32.hpp>
|
||||
#include <Source/Telemetry/Telemetry.hpp>
|
||||
@ -20,116 +22,12 @@
|
||||
#include <ehdata.h>
|
||||
|
||||
#include <Source/Process/ProcessMap.hpp>
|
||||
#include <Source/IO/FS/FS.hpp>
|
||||
|
||||
static thread_local int gDebugLocked = 0;
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
static AuUInt GetImageBase(HMODULE mod)
|
||||
{
|
||||
if (!mod)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mod == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cache = Process::GetFromModuleCache(reinterpret_cast<AuUInt>(mod));
|
||||
if (!cache.moduleMeta)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cache.moduleMeta->origVa;
|
||||
}
|
||||
|
||||
static void ParseStack(CONTEXT *ctx, StackTrace &backTrace)
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME + 1) * sizeof(char)] = { 0 };
|
||||
AuString backTraceBuffer;
|
||||
HMODULE hModule;
|
||||
DWORD64 displacement = 0;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
STACKFRAME64 stack = { 0 };
|
||||
CONTEXT cpy = *ctx;
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
|
||||
#if defined(AURORA_ARCH_X64)
|
||||
stack.AddrPC.Offset = ctx->Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = ctx->Rsp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = ctx->Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#elif defined(AURORA_ARCH_XX86)
|
||||
stack.AddrPC.Offset = ctx->Eip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = ctx->Esp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = ctx->Ebp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
for (ULONG frame = 0; ; frame++)
|
||||
{
|
||||
StackTraceEntry frameCurrent;
|
||||
|
||||
auto result = StackWalk64
|
||||
(
|
||||
#if defined(AURORA_ARCH_X64)
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
#else
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
#endif
|
||||
INVALID_HANDLE_VALUE,
|
||||
INVALID_HANDLE_VALUE,
|
||||
&stack,
|
||||
&cpy,
|
||||
NULL,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
frameCurrent.address = stack.AddrPC.Offset;
|
||||
frameCurrent.relAddress = frameCurrent.address;
|
||||
|
||||
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)(stack.AddrPC.Offset), &hModule))
|
||||
{
|
||||
if (hModule != NULL)
|
||||
{
|
||||
frameCurrent.module = Process::ModuleToPath(hModule);
|
||||
frameCurrent.relAddress = frameCurrent.relAddress - reinterpret_cast<AuUInt>(hModule) + GetImageBase(hModule);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(STAGING)
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD disp;
|
||||
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, &line))
|
||||
{
|
||||
frameCurrent.file = AuMakeTuple(line.FileName, line.LineNumber, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
backTrace.push_back(frameCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
#define EXCEPTION_ENTRY(n) {n, #n}
|
||||
static const AuHashMap<DWORD, AuString> kExceptionTable
|
||||
{
|
||||
@ -202,174 +100,268 @@ namespace Aurora::Debug
|
||||
return (info.Protect & (PAGE_READONLY | PAGE_READWRITE)) != 0;
|
||||
}
|
||||
|
||||
static LONG HandleVectorException(_EXCEPTION_POINTERS *ExceptionInfo)
|
||||
{
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode < STATUS_GUARD_PAGE_VIOLATION)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
||||
auto minimal = gDebugLocked++;
|
||||
|
||||
if (minimal >= 5)
|
||||
{
|
||||
SysPanic("Nested Exception");
|
||||
}
|
||||
|
||||
bool cxxThrow = ExceptionInfo->ExceptionRecord->ExceptionInformation[0] == EH_MAGIC_NUMBER1;
|
||||
bool cxxThrowPure = ExceptionInfo->ExceptionRecord->ExceptionInformation[0] == EH_PURE_MAGIC_NUMBER1;
|
||||
|
||||
void *exception {};
|
||||
HMODULE handle {};
|
||||
ThrowInfo *pThrowInfo {};
|
||||
|
||||
if ((ExceptionInfo->ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER) &&
|
||||
(ExceptionInfo->ExceptionRecord->NumberParameters >= 4) &&
|
||||
((cxxThrow) ||
|
||||
(cxxThrowPure))
|
||||
)
|
||||
{
|
||||
pThrowInfo = reinterpret_cast<ThrowInfo *>(ExceptionInfo->ExceptionRecord->ExceptionInformation[2]);
|
||||
|
||||
if (pThrowInfo)
|
||||
{
|
||||
auto attribs = pThrowInfo->attributes;
|
||||
|
||||
if (_EH_RELATIVE_TYPEINFO)
|
||||
{
|
||||
handle = reinterpret_cast<HMODULE>(ExceptionInfo->ExceptionRecord->ExceptionInformation[3]);
|
||||
}
|
||||
|
||||
exception = reinterpret_cast<void *>(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool isCritical = AuTryFind(kExceptionFatalTable, ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||
|
||||
auto handleNoCppObject = [&]() -> AuString
|
||||
{
|
||||
const AuString *msg;
|
||||
if (AuTryFind(kExceptionTable, ExceptionInfo->ExceptionRecord->ExceptionCode, msg))
|
||||
{
|
||||
return *msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AuToString(ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||
}
|
||||
};
|
||||
|
||||
StackTrace backtrace;
|
||||
ParseStack(ExceptionInfo->ContextRecord, backtrace);
|
||||
|
||||
|
||||
#if defined(STAGING) || defined(DEBUG)
|
||||
bool isInternal = true;
|
||||
#else
|
||||
bool isInternal = false;
|
||||
#endif
|
||||
|
||||
ReportSEH(handle, exception, pThrowInfo, handleNoCppObject, backtrace, [&](const AuString &str)
|
||||
{
|
||||
// Pre-submit callback -> its showtime
|
||||
if ((isCritical || isInternal) && (minimal == 0))
|
||||
{
|
||||
AuLogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, str);
|
||||
AuLogWarn("{}", StringifyStackTrace(backtrace));
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
if (isCritical)
|
||||
{
|
||||
Telemetry::Mayday();
|
||||
}
|
||||
|
||||
if (isCritical)
|
||||
{
|
||||
PlatformHandleFatal(true);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
gDebugLocked = 0;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
static AuString GetDumpName()
|
||||
{
|
||||
AuString exeName;
|
||||
try
|
||||
{
|
||||
Process::GetProcName(exeName);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto tm = Time::ToCivilTime(Time::CurrentClockMS());
|
||||
return fmt::format("{}-{}-{}T{}-{}-{}Z_{}.dmp", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
exeName);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return "errordate.dmp";
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(INTERNAL)
|
||||
void SaveMinidump(_EXCEPTION_POINTERS *ExceptionInfo)
|
||||
{
|
||||
bool ok {};
|
||||
MINIDUMP_EXCEPTION_INFORMATION info;
|
||||
info.ThreadId = GetCurrentThreadId();
|
||||
|
||||
info.ClientPointers = ExceptionInfo != nullptr;
|
||||
info.ExceptionPointers = ExceptionInfo;
|
||||
|
||||
static const DWORD flags = MiniDumpWithFullMemory |
|
||||
MiniDumpWithFullMemoryInfo |
|
||||
MiniDumpWithHandleData |
|
||||
MiniDumpWithUnloadedModules |
|
||||
MiniDumpWithThreadInfo;
|
||||
|
||||
std::wstring path;
|
||||
while (path.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
path = Locale::ConvertFromUTF8(AuIOFS::NormalizePathRet("./Logs/Crashes/" + GetDumpName()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto hFile = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
AuLogWarn("Couldn't open minidump file. Has a debugger locked the .dmp file?");
|
||||
goto miniDumpOut;
|
||||
}
|
||||
|
||||
ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
|
||||
if (!ok)
|
||||
{
|
||||
AuLogWarn("Couldn't write minidump");
|
||||
goto miniDumpOut;
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
miniDumpOut:
|
||||
|
||||
try
|
||||
{
|
||||
AuDebug::PrintError();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
__debugbreak();
|
||||
|
||||
__fastfail('fokd');
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlackboxReport(_EXCEPTION_POINTERS *ExceptionInfo)
|
||||
{
|
||||
AuString path;
|
||||
HANDLE hFile;
|
||||
std::wstring wpath;
|
||||
MINIDUMP_EXCEPTION_INFORMATION info;
|
||||
|
||||
auto ok = AuIOFS::GetProfileDomain(path);
|
||||
if (!ok)
|
||||
{
|
||||
AuLogWarn("Couldn't find minidump directory");
|
||||
goto miniMiniDumpOut;
|
||||
}
|
||||
|
||||
info.ClientPointers = true;
|
||||
info.ThreadId = GetCurrentThreadId();
|
||||
info.ExceptionPointers = ExceptionInfo;
|
||||
|
||||
static const DWORD flags = MiniDumpWithDataSegs |
|
||||
MiniDumpWithFullMemoryInfo |
|
||||
MiniDumpWithHandleData |
|
||||
MiniDumpWithUnloadedModules |
|
||||
MiniDumpWithThreadInfo;
|
||||
|
||||
|
||||
while (wpath.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
wpath = Locale::ConvertFromUTF8(path + "Crashes/" + GetDumpName());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
hFile = CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
AuLogWarn("[1] Couldn't open minidump file. Has a debugger locked the .dmp file?");
|
||||
goto miniMiniDumpOut;
|
||||
}
|
||||
|
||||
ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
|
||||
if (!ok)
|
||||
{
|
||||
AuLogWarn("Couldn't write minidump");
|
||||
goto miniMiniDumpOut;
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
miniMiniDumpOut:
|
||||
Telemetry::NewBlackBoxEntryMinidump report {};
|
||||
report.includesRx = false;
|
||||
report.resource.path = path;
|
||||
report.resource.type = Telemetry::ENewBlackBoxResourceType::eLocal;
|
||||
Telemetry::ReportDyingBreath(report);
|
||||
|
||||
__fastfail('fokd');
|
||||
}
|
||||
|
||||
void InitWin32()
|
||||
{
|
||||
static AuString kStringRawName = typeid(AuString).raw_name();
|
||||
|
||||
|
||||
#if defined(DEBUG) || defined(STAGING)
|
||||
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||
#endif
|
||||
|
||||
// This is really gross :(
|
||||
AddVectoredExceptionHandler(1,
|
||||
[](_EXCEPTION_POINTERS *ExceptionInfo) -> LONG
|
||||
{
|
||||
Telemetry::NewBlockboxEntry entry;
|
||||
entry.type = Telemetry::ENewBlackBoxEntry::eWinCxxException;
|
||||
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode < STATUS_GUARD_PAGE_VIOLATION)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
auto minimal = gDebugLocked++;
|
||||
|
||||
if (minimal >= 5)
|
||||
{
|
||||
SysPanic("Nested Exception");
|
||||
}
|
||||
|
||||
bool cxxThrow = ExceptionInfo->ExceptionRecord->ExceptionInformation[0] == EH_MAGIC_NUMBER1;
|
||||
bool cxxThrowPure = ExceptionInfo->ExceptionRecord->ExceptionInformation[0] == EH_PURE_MAGIC_NUMBER1;
|
||||
|
||||
if ((ExceptionInfo->ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER) &&
|
||||
(ExceptionInfo->ExceptionRecord->NumberParameters >= 4) &&
|
||||
((cxxThrow) ||
|
||||
(cxxThrowPure))
|
||||
)
|
||||
{
|
||||
HMODULE handle {};
|
||||
auto *throwInfo = reinterpret_cast<ThrowInfo *>(ExceptionInfo->ExceptionRecord->ExceptionInformation[2]);
|
||||
|
||||
if (throwInfo)
|
||||
{
|
||||
auto attribs = throwInfo->attributes;
|
||||
|
||||
if (_EH_RELATIVE_TYPEINFO)
|
||||
{
|
||||
handle = reinterpret_cast<HMODULE>(ExceptionInfo->ExceptionRecord->ExceptionInformation[3]);
|
||||
}
|
||||
|
||||
const auto catchableTypeArray = reinterpret_cast<const CatchableTypeArray*>(reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(throwInfo->pCatchableTypeArray));
|
||||
|
||||
AuString suffix;
|
||||
|
||||
for (int i = 0; i < catchableTypeArray->nCatchableTypes; i++)
|
||||
{
|
||||
const auto type = reinterpret_cast<CatchableType *> (reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(catchableTypeArray->arrayOfCatchableTypes[i]));
|
||||
const auto descriptor = reinterpret_cast<std::type_info *> (reinterpret_cast<AuUInt>(handle) + static_cast<AuUInt>(type->pType));
|
||||
|
||||
entry.wincxx.str += (i == 0 ? "" : AuString(", ")) + descriptor->name(); // __std_type_info_name
|
||||
|
||||
if (strnicmp(descriptor->raw_name(), ".?AVException@", AuArraySize(".?AVException@") - 1) == 0)
|
||||
{
|
||||
auto exception = reinterpret_cast<std::exception *>(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
|
||||
auto wptr = exception->what();
|
||||
if (wptr)
|
||||
{
|
||||
suffix = wptr;
|
||||
}
|
||||
}
|
||||
else if (strncmp(descriptor->raw_name(), ".PEAD", AuArraySize(".PEAD")) == 0)
|
||||
{
|
||||
auto possibleStringPointer = reinterpret_cast<const char **>(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
|
||||
if (IsReadable(possibleStringPointer))
|
||||
{
|
||||
auto string = *possibleStringPointer;
|
||||
if (IsReadable(string) && (strnlen(string, 4096) < 1024))
|
||||
{
|
||||
suffix = string;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strncmp(descriptor->raw_name(), kStringRawName.data(), kStringRawName.size()) == 0)
|
||||
{
|
||||
auto possibleStdStringPointer = reinterpret_cast<AuString *>(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
|
||||
if (IsReadable(possibleStdStringPointer))
|
||||
{
|
||||
auto string = *possibleStdStringPointer;
|
||||
suffix = string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix.size())
|
||||
{
|
||||
entry.wincxx.str += AuString("\r\n ") + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isCritical = AuTryFind(kExceptionFatalTable, ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||
if (entry.wincxx.str.empty())
|
||||
{
|
||||
const AuString *msg;
|
||||
if (AuTryFind(kExceptionTable, ExceptionInfo->ExceptionRecord->ExceptionCode, msg))
|
||||
{
|
||||
entry.wincxx.str = *msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.wincxx.str = AuToString(ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry.wincxx.str.find("invalid sto") != std::string::npos)
|
||||
{
|
||||
gDebugLocked = 0;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (minimal < 2)
|
||||
{
|
||||
ParseStack(ExceptionInfo->ContextRecord, entry.wincxx.stack.backtrace);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
entry.wincxx.fenceId = ReportStackTrace(entry.wincxx.stack.backtrace, entry.wincxx.str);
|
||||
|
||||
#if defined(STAGING) || defined(DEBUG)
|
||||
bool isInternal = true;
|
||||
#else
|
||||
bool isInternal = false;
|
||||
#endif
|
||||
|
||||
if ((isCritical || isInternal) && (minimal == 0))
|
||||
{
|
||||
AuLogWarn("NT Exception: 0x{:x}, {}", ExceptionInfo->ExceptionRecord->ExceptionCode, entry.wincxx.str);
|
||||
AuLogWarn("{}", StringifyStackTrace(entry.wincxx.stack.backtrace));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Telemetry::Report(entry);
|
||||
|
||||
if (isCritical)
|
||||
{
|
||||
Telemetry::Mayday();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
gDebugLocked = 0;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
});
|
||||
AddVectoredExceptionHandler(1, HandleVectorException);
|
||||
}
|
||||
}
|
@ -10,4 +10,9 @@
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
void InitWin32();
|
||||
|
||||
#if defined(DEBUG) || defined(INTERNAL)
|
||||
void SaveMinidump(_EXCEPTION_POINTERS *ExceptionInfo);
|
||||
#endif
|
||||
void BlackboxReport(_EXCEPTION_POINTERS *ExceptionInfo);
|
||||
}
|
@ -13,6 +13,8 @@
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
void PlatformHandleFatal();
|
||||
|
||||
AUKN_SYM void DebugBreak()
|
||||
{
|
||||
#if defined(DEBUG) || defined(STAGING)
|
||||
|
8
Source/Debug/Stack.Android.cpp
Normal file
8
Source/Debug/Stack.Android.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Android.cpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
|
9
Source/Debug/Stack.Android.hpp
Normal file
9
Source/Debug/Stack.Android.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Android.hpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
7
Source/Debug/Stack.Unix.cpp
Normal file
7
Source/Debug/Stack.Unix.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Unix.cpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
9
Source/Debug/Stack.Unix.hpp
Normal file
9
Source/Debug/Stack.Unix.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Unix.hpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
131
Source/Debug/Stack.Win32.cpp
Normal file
131
Source/Debug/Stack.Win32.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Win32.cpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Stack.hpp"
|
||||
#include "Stack.Win32.hpp"
|
||||
#include <Dbghelp.h>
|
||||
#include <Source/Process/ProcessMap.hpp>
|
||||
#include <Source/Process/ProcessMap.Win32.hpp>
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
static AuUInt GetImageBase(HMODULE mod)
|
||||
{
|
||||
if (!mod)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mod == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cache = Process::GetFromModuleCache(reinterpret_cast<AuUInt>(mod));
|
||||
if (!cache.moduleMeta)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cache.moduleMeta->origVa;
|
||||
}
|
||||
|
||||
void ParseStack(CONTEXT *ctx, StackTrace &backTrace)
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME + 1) * sizeof(char)] = { 0 };
|
||||
AuString backTraceBuffer;
|
||||
HMODULE hModule;
|
||||
DWORD64 displacement = 0;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
STACKFRAME64 stack = { 0 };
|
||||
CONTEXT cpy = *ctx;
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
|
||||
#if defined(AURORA_ARCH_X64)
|
||||
stack.AddrPC.Offset = ctx->Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = ctx->Rsp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = ctx->Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#elif defined(AURORA_ARCH_X86)
|
||||
stack.AddrPC.Offset = ctx->Eip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = ctx->Esp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = ctx->Ebp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
for (ULONG frame = 0; ; frame++)
|
||||
{
|
||||
StackTraceEntry frameCurrent;
|
||||
|
||||
auto result = StackWalk64
|
||||
(
|
||||
#if defined(AURORA_ARCH_X64)
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
#else
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
#endif
|
||||
INVALID_HANDLE_VALUE,
|
||||
INVALID_HANDLE_VALUE,
|
||||
&stack,
|
||||
&cpy,
|
||||
NULL,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
frameCurrent.address = stack.AddrPC.Offset;
|
||||
frameCurrent.relAddress = frameCurrent.address;
|
||||
|
||||
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)(stack.AddrPC.Offset), &hModule))
|
||||
{
|
||||
if (hModule != NULL)
|
||||
{
|
||||
frameCurrent.module = Process::ModuleToPath(hModule);
|
||||
frameCurrent.relAddress = frameCurrent.relAddress - reinterpret_cast<AuUInt>(hModule) + GetImageBase(hModule);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(STAGING)
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD disp;
|
||||
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, &line))
|
||||
{
|
||||
frameCurrent.file = AuMakeTuple(line.FileName, line.LineNumber, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
backTrace.push_back(frameCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
StackTrace PlatformWalkCallStack()
|
||||
{
|
||||
StackTrace ret;
|
||||
CONTEXT ctx;
|
||||
if (!GetThreadContext(GetCurrentThread(), &ctx)) return {};
|
||||
ParseStack(&ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
15
Source/Debug/Stack.Win32.hpp
Normal file
15
Source/Debug/Stack.Win32.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.Win32.hpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
void ParseStack(CONTEXT *ctx, StackTrace &backTrace);
|
||||
|
||||
StackTrace PlatformWalkCallStack();
|
||||
}
|
9
Source/Debug/Stack.hpp
Normal file
9
Source/Debug/Stack.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Stack.hpp
|
||||
Date: 2022-1-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
@ -242,4 +242,128 @@ namespace Aurora::IO::FS
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
AUKN_SYM bool NormalizePath(AuString &out, const AuString &in)
|
||||
{
|
||||
try
|
||||
{
|
||||
out = NormalizePathRet(in);
|
||||
return out.size();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static AuUInt GetLastSplitterIndex(const AuString &path)
|
||||
{
|
||||
AuUInt indexA {}, indexB {};
|
||||
|
||||
auto a = path.find_last_of('\\');
|
||||
if (a != AuString::npos) indexA = a;
|
||||
|
||||
auto b = path.find_last_of('/');
|
||||
if (b != AuString::npos) indexB = b;
|
||||
|
||||
return AuMax(a, b);
|
||||
}
|
||||
|
||||
AUKN_SYM bool GetFileFromPath(AuString &out, const AuString &path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
if (path[path.size() - 1] == '.') return false;
|
||||
|
||||
AuUInt max = GetLastSplitterIndex(path);
|
||||
if (max == path.size()) return false;
|
||||
|
||||
out = path.substr(max + 1);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM bool GetDirectoryFromPath(AuString &out, const AuString &path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
if (path[path.size() - 1] == '.')
|
||||
{
|
||||
if (path.size() > 2 && (path[path.size() - 2] == '\\' || path[path.size() - 2] == '/'))
|
||||
{
|
||||
out = path.substr(0, path.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuUInt max = GetLastSplitterIndex(path);
|
||||
if (!max)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (max == path.size())
|
||||
{
|
||||
out = path;
|
||||
return true;
|
||||
}
|
||||
|
||||
out = path.substr(0, max + 1);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM bool GoUpToSeparator(AuString &out, const AuString &path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
if (path[path.size() - 1] == '.')
|
||||
{
|
||||
if (path.size() > 2 && (path[path.size() - 2] == '\\' || path[path.size() - 2] == '/'))
|
||||
{
|
||||
out = path.substr(0, path.size() - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuUInt max = GetLastSplitterIndex(path);
|
||||
if (!max)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (max == path.size())
|
||||
{
|
||||
out = path.substr(0, max - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
out = path.substr(0, max);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ namespace Aurora::Process
|
||||
return ".so";
|
||||
case Build::EPlatform::ePlatformAppleMacOS:
|
||||
case Build::EPlatform::ePlatformIos:
|
||||
return ".dynlib";
|
||||
return ".dylib";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ namespace Aurora::SWInfo
|
||||
}
|
||||
|
||||
strValue = Locale::ConvertFromWChar(in.data(), in.size());
|
||||
return strValue.size() == in.size();
|
||||
return strValue.size();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -23,74 +23,74 @@ namespace Aurora::SWInfo
|
||||
static AuUInt16 kWinVerWinBlue = 0x0603;
|
||||
static AuUInt16 kWinVerWin10 = 0x0A00;
|
||||
|
||||
static bool IsWindowsVersionOrGreater(AuUInt16 major, AuUInt16 ignored, AuUInt16 sp)
|
||||
static bool IsWindowsVersionOrGreater(AuUInt8 major, AuUInt8 minor, AuUInt16 sp)
|
||||
{
|
||||
auto &info = GetPlatformInfo();
|
||||
return info.ePlatform == Build::EPlatform::ePlatformWin32 && info.uKernelMajor >= major && info.uUserlandMinor >= sp;
|
||||
return info.ePlatform == Build::EPlatform::ePlatformWin32 && info.uKernelMajor >= major && info.uKernelMinor >= minor && info.uUserlandMinor >= sp;
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsXPOrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWinXP, kWinVerWinXP, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWinXP), AuBitsToLower(kWinVerWinXP), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsXPSP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWinXP, kWinVerWinXP, 1);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWinXP), AuBitsToLower(kWinVerWinXP), 1);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsXPSP2OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWinXP, kWinVerWinXP, 2);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWinXP), AuBitsToLower(kWinVerWinXP), 2);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsXPSP3OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWinXP, kWinVerWinXP, 3);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWinXP), AuBitsToLower(kWinVerWinXP), 3);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsVistaOrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerVista, kWinVerVista, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerVista), AuBitsToLower(kWinVerVista), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsVistaSP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerVista, kWinVerVista, 1);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerVista), AuBitsToLower(kWinVerVista), 1);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindowsVistaSP2OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerVista, kWinVerVista, 2);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerVista), AuBitsToLower(kWinVerVista), 2);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows7OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWin7, kWinVerWin7, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWin7), AuBitsToLower(kWinVerWin7), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows7SP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWin7, kWinVerWin7, 1);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWin7), AuBitsToLower(kWinVerWin7), 1);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows8OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWin8, kWinVerWin8, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWin8), AuBitsToLower(kWinVerWin8), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows8Point1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWinBlue, kWinVerWinBlue, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWinBlue), AuBitsToLower(kWinVerWinBlue), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows10OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWin10, kWinVerWin10, 0);
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWin10), AuBitsToLower(kWinVerWin10), 0);
|
||||
}
|
||||
|
||||
AUKN_SYM bool IsWindows11OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(kWinVerWin10, kWinVerWin10, 0) && GetPlatformInfo().uKernelPatch >= 22000;
|
||||
return IsWindowsVersionOrGreater(AuBitsToHigher(kWinVerWin10), AuBitsToLower(kWinVerWin10), 0) && GetPlatformInfo().uKernelPatch >= 22000;
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#include <Source/Debug/Debug.hpp>
|
||||
#include "Telemetry.hpp"
|
||||
|
||||
|
||||
namespace Aurora::Telemetry
|
||||
{
|
||||
static AuThreadPrimitives::CriticalSectionUnique_t gGroupLock;
|
||||
@ -53,6 +54,11 @@ namespace Aurora::Telemetry
|
||||
|
||||
}
|
||||
|
||||
void ReportDyingBreath(Telemetry::NewBlackBoxEntryMinidump &entry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ReportSysInfo()
|
||||
{
|
||||
|
||||
@ -64,8 +70,11 @@ namespace Aurora::Telemetry
|
||||
ReportSysInfo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
AUKN_SYM void Mayday()
|
||||
{
|
||||
|
||||
Debug::CheckErrors();
|
||||
Debug::PlatformHandleFatal(false);
|
||||
}
|
||||
}
|
@ -18,5 +18,6 @@ namespace Aurora::Telemetry
|
||||
void InsertBackTrace(AuUInt32 fence);
|
||||
void ReportSysInfo();
|
||||
void Report(Telemetry::NewBlockboxEntry &entry);
|
||||
void ReportDyingBreath(Telemetry::NewBlackBoxEntryMinidump &entry);
|
||||
void Init();
|
||||
}
|
@ -53,7 +53,6 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (atomicRelease_)
|
||||
|
@ -7,14 +7,13 @@
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace Aurora::Threading::Threads
|
||||
{
|
||||
AuPair<bool, AuUInt> /*success, oshandle*/ SpawnThread(const AuFunction<void()> &entrypoint, const AuString &debugString, AuUInt32 staskSize = 0);
|
||||
}
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
#include "SpawnThread.NT.hpp"
|
||||
#include "SpawnThread.NT.hpp"
|
||||
#elif defined(AURORA_IS_UNIX_DERIVED)
|
||||
#include "SpawnThread.Unix.hpp"
|
||||
#include "SpawnThread.Unix.hpp"
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user