Mercurial > foo_out_sdl
view 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 source
#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); }
