Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/shared/minidump.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/shared/minidump.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,251 @@ +#include "shared.h" +#include <imagehlp.h> + +#ifdef _M_ARM64EC +typedef ARM64EC_NT_CONTEXT myCONTEXT; +#else +typedef CONTEXT myCONTEXT; +#endif +struct DumpState { + int state; + myCONTEXT*context; +}; + +__declspec(noinline) static bool safeRead(volatile const void* addr, size_t& dest) +{ + __try { + dest = *(const volatile size_t*)addr; + return true; + } + __except (1) { + return false; + } +} + +__declspec(noinline) static bool safeTestReadAccess(volatile const void* addr) +{ + size_t dummy; + return safeRead(addr, dummy); +} + +#if defined(_M_ARM64) || defined(_M_ARM64EC) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->X0; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->X1; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->X2; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->X3; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->X4; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->X5; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->X6; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->X7; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->X8; ds->state++; break; + case 9: CallbackOutput->MemoryBase = ds->context->X9; ds->state++; break; + case 10: CallbackOutput->MemoryBase = ds->context->X10; ds->state++; break; + case 11: CallbackOutput->MemoryBase = ds->context->X11; ds->state++; break; + case 12: CallbackOutput->MemoryBase = ds->context->X12; ds->state++; break; +#ifndef _M_ARM64EC + case 13: CallbackOutput->MemoryBase = ds->context->X13; ds->state++; break; + case 14: CallbackOutput->MemoryBase = ds->context->X14; ds->state++; break; + case 15: CallbackOutput->MemoryBase = ds->context->X15; ds->state++; break; + case 16: CallbackOutput->MemoryBase = ds->context->X16; ds->state++; break; + case 17: CallbackOutput->MemoryBase = ds->context->X17; ds->state++; break; + case 18: CallbackOutput->MemoryBase = ds->context->X18; ds->state++; break; + case 19: CallbackOutput->MemoryBase = ds->context->X19; ds->state++; break; + case 20: CallbackOutput->MemoryBase = ds->context->X20; ds->state++; break; + case 21: CallbackOutput->MemoryBase = ds->context->X21; ds->state++; break; + case 22: CallbackOutput->MemoryBase = ds->context->X22; ds->state++; break; + case 23: CallbackOutput->MemoryBase = ds->context->X23; ds->state++; break; + case 24: CallbackOutput->MemoryBase = ds->context->X24; ds->state++; break; + case 25: CallbackOutput->MemoryBase = ds->context->X25; ds->state++; break; + case 26: CallbackOutput->MemoryBase = ds->context->X26; ds->state++; break; + case 27: CallbackOutput->MemoryBase = ds->context->X27; ds->state++; break; + case 28: CallbackOutput->MemoryBase = ds->context->X28; ds->state++; break; +#endif + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Sp & ~7) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#elif defined(_M_IX86) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->Eax; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->Ebx; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->Ecx; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->Edx; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->Esi; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->Edi; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->Ebp; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->Esp; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->Eip; ds->state++; break; + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Esp & ~3) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#elif defined(_M_X64) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->Rax; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->Rbx; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->Rcx; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->Rdx; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->Rsi; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->Rdi; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->Rsp; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->Rbp; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->R8; ds->state++; break; + case 9: CallbackOutput->MemoryBase = ds->context->R9; ds->state++; break; + case 10: CallbackOutput->MemoryBase = ds->context->R10; ds->state++; break; + case 11: CallbackOutput->MemoryBase = ds->context->R11; ds->state++; break; + case 12: CallbackOutput->MemoryBase = ds->context->R12; ds->state++; break; + case 13: CallbackOutput->MemoryBase = ds->context->R13; ds->state++; break; + case 14: CallbackOutput->MemoryBase = ds->context->R14; ds->state++; break; + case 15: CallbackOutput->MemoryBase = ds->context->R15; ds->state++; break; + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Rsp & ~7) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#endif // _M_X64 + + + + +BOOL WriteMiniDumpHelper(HANDLE hDump, LPEXCEPTION_POINTERS param) { + MINIDUMP_EXCEPTION_INFORMATION exception = {}; + exception.ThreadId = GetCurrentThreadId(); + exception.ExceptionPointers = param; + exception.ClientPointers = FALSE; + DumpState ds; + ds.state = 0; + ds.context = reinterpret_cast<myCONTEXT*>(param->ContextRecord); + MINIDUMP_CALLBACK_INFORMATION mci; + mci.CallbackRoutine = &MiniDumpCallback; + mci.CallbackParam = (void*)&ds; + return MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDump, (MINIDUMP_TYPE)(MiniDumpWithUnloadedModules), &exception, NULL, &mci); +}
