sdlprocdump: store context and exception record in minidump

This commit is contained in:
Anonymous Maarten 2024-07-05 21:06:05 +02:00
parent 0fa74d8aa8
commit be43dec798
1 changed files with 48 additions and 36 deletions

View File

@ -181,10 +181,11 @@ static const char *get_simple_basename(const char *path) {
return path; return path;
} }
static void write_minidump(const char *child_file_path, const LPPROCESS_INFORMATION process_information, DWORD dwThreadId) { static void write_minidump(const char *child_file_path, const LPPROCESS_INFORMATION process_information, DWORD dwThreadId, PEXCEPTION_RECORD exception_record, PCONTEXT context) {
BOOL success; BOOL success;
char dump_file_path[MAX_PATH]; char dump_file_path[MAX_PATH];
char child_file_name[64]; char child_file_name[64];
EXCEPTION_POINTERS exception_pointers;
HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFile = INVALID_HANDLE_VALUE;
HMODULE dbghelp_module = NULL; HMODULE dbghelp_module = NULL;
MINIDUMP_EXCEPTION_INFORMATION minidump_exception_information; MINIDUMP_EXCEPTION_INFORMATION minidump_exception_information;
@ -221,8 +222,11 @@ static void write_minidump(const char *child_file_path, const LPPROCESS_INFORMAT
printf_windows_message("Failed to open file for minidump"); printf_windows_message("Failed to open file for minidump");
goto post_dump; goto post_dump;
} }
memset(&exception_pointers, 0, sizeof(exception_pointers));
exception_pointers.ContextRecord = context;
exception_pointers.ExceptionRecord = exception_record;
minidump_exception_information.ClientPointers = FALSE; minidump_exception_information.ClientPointers = FALSE;
minidump_exception_information.ExceptionPointers = FALSE; minidump_exception_information.ExceptionPointers = &exception_pointers;
minidump_exception_information.ThreadId = dwThreadId; minidump_exception_information.ThreadId = dwThreadId;
success = dyn_dbghelp.pMiniDumpWriteDump( success = dyn_dbghelp.pMiniDumpWriteDump(
process_information->hProcess, /* HANDLE hProcess */ process_information->hProcess, /* HANDLE hProcess */
@ -244,11 +248,13 @@ post_dump:
} }
} }
static void print_stacktrace(const LPPROCESS_INFORMATION process_information, LPVOID address) { static void print_stacktrace(const LPPROCESS_INFORMATION process_information, PCONTEXT context, LPVOID address) {
STACKFRAME64 stack_frame; STACKFRAME64 stack_frame;
CONTEXT context;
HANDLE thread_handle = NULL;
if (!context) {
printf_message("Cannot create a stacktrace without a context");
return;
}
if (!dyn_dbghelp.pStackWalk64) { if (!dyn_dbghelp.pStackWalk64) {
printf_message("Cannot find StackWalk64 in dbghelp.dll: no stacktrace"); printf_message("Cannot find StackWalk64 in dbghelp.dll: no stacktrace");
return; return;
@ -274,19 +280,6 @@ static void print_stacktrace(const LPPROCESS_INFORMATION process_information, LP
return; return;
} }
thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, process_information->dwThreadId);
if (!thread_handle) {
printf_windows_message("OpenThread failed: no stacktrace");
goto cleanup;
}
memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(thread_handle, &context)) {
printf_windows_message("GetThreadContext failed: no stacktrace");
goto cleanup;
}
if (!dyn_dbghelp.pSymRefreshModuleList || !dyn_dbghelp.pSymRefreshModuleList(process_information->hProcess)) { if (!dyn_dbghelp.pSymRefreshModuleList || !dyn_dbghelp.pSymRefreshModuleList(process_information->hProcess)) {
printf_windows_message("SymRefreshModuleList failed: maybe no stacktrace"); printf_windows_message("SymRefreshModuleList failed: maybe no stacktrace");
} }
@ -299,24 +292,24 @@ static void print_stacktrace(const LPPROCESS_INFORMATION process_information, LP
#if defined(SDLPROCDUMP_CPU_X86) #if defined(SDLPROCDUMP_CPU_X86)
DWORD machine_type = IMAGE_FILE_MACHINE_I386; DWORD machine_type = IMAGE_FILE_MACHINE_I386;
stack_frame.AddrFrame.Offset = context.Ebp; stack_frame.AddrFrame.Offset = context->Ebp;
stack_frame.AddrStack.Offset = context.Esp; stack_frame.AddrStack.Offset = context->Esp;
stack_frame.AddrPC.Offset = context.Eip; stack_frame.AddrPC.Offset = context->Eip;
#elif defined(SDLPROCDUMP_CPU_X64) #elif defined(SDLPROCDUMP_CPU_X64)
DWORD machine_type = IMAGE_FILE_MACHINE_AMD64; DWORD machine_type = IMAGE_FILE_MACHINE_AMD64;
stack_frame.AddrFrame.Offset = context.Rbp; stack_frame.AddrFrame.Offset = context->Rbp;
stack_frame.AddrStack.Offset = context.Rsp; stack_frame.AddrStack.Offset = context->Rsp;
stack_frame.AddrPC.Offset = context.Rip; stack_frame.AddrPC.Offset = context->Rip;
#elif defined(SDLPROCDUMP_CPU_ARM32) #elif defined(SDLPROCDUMP_CPU_ARM32)
DWORD machine_type = IMAGE_FILE_MACHINE_ARM; DWORD machine_type = IMAGE_FILE_MACHINE_ARM;
stack_frame.AddrFrame.Offset = context.Lr; stack_frame.AddrFrame.Offset = context->Lr;
stack_frame.AddrStack.Offset = context.Sp; stack_frame.AddrStack.Offset = context->Sp;
stack_frame.AddrPC.Offset = context.Pc; stack_frame.AddrPC.Offset = context->Pc;
#elif defined(SDLPROCDUMP_CPU_ARM64) #elif defined(SDLPROCDUMP_CPU_ARM64)
DWORD machine_type = IMAGE_FILE_MACHINE_ARM64; DWORD machine_type = IMAGE_FILE_MACHINE_ARM64;
stack_frame.AddrFrame.Offset = context.Fp; stack_frame.AddrFrame.Offset = context->Fp;
stack_frame.AddrStack.Offset = context.Sp; stack_frame.AddrStack.Offset = context->Sp;
stack_frame.AddrPC.Offset = context.Pc; stack_frame.AddrPC.Offset = context->Pc;
#endif #endif
while (dyn_dbghelp.pStackWalk64(machine_type, /* DWORD MachineType */ while (dyn_dbghelp.pStackWalk64(machine_type, /* DWORD MachineType */
process_information->hProcess, /* HANDLE hProcess */ process_information->hProcess, /* HANDLE hProcess */
@ -374,12 +367,26 @@ static void print_stacktrace(const LPPROCESS_INFORMATION process_information, LP
} }
printf_message("%s!%s+0x%x %s %s", image_file_name, symbol_name, dwDisplacement, file_name, line_number); printf_message("%s!%s+0x%x %s %s", image_file_name, symbol_name, dwDisplacement, file_name, line_number);
} }
}
cleanup: static PCONTEXT FillInThreadContext(LPPROCESS_INFORMATION process_information, PCONTEXT context_buffer) {
if (thread_handle) { HANDLE thread_handle = NULL;
CloseHandle(thread_handle);
thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, process_information->dwThreadId);
if (!thread_handle) {
printf_windows_message("OpenThread failed: no stacktrace");
return NULL;
} }
return;
memset(context_buffer, 0, sizeof(*context_buffer));
context_buffer->ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(thread_handle, context_buffer)) {
printf_windows_message("GetThreadContext failed: no stacktrace");
CloseHandle(thread_handle);
return NULL;
}
CloseHandle(thread_handle);
return context_buffer;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -454,6 +461,9 @@ int main(int argc, char *argv[]) {
switch (event.dwDebugEventCode) { switch (event.dwDebugEventCode) {
case EXCEPTION_DEBUG_EVENT: case EXCEPTION_DEBUG_EVENT:
if (IsFatalExceptionCode(event.u.Exception.ExceptionRecord.ExceptionCode) || (event.u.Exception.ExceptionRecord.ExceptionFlags & EXCEPTION_NONCONTINUABLE)) { if (IsFatalExceptionCode(event.u.Exception.ExceptionRecord.ExceptionCode) || (event.u.Exception.ExceptionRecord.ExceptionFlags & EXCEPTION_NONCONTINUABLE)) {
CONTEXT context_buffer;
PCONTEXT context;
printf_message("EXCEPTION_DEBUG_EVENT"); printf_message("EXCEPTION_DEBUG_EVENT");
printf_message(" ExceptionCode: 0x%08lx (%s)", printf_message(" ExceptionCode: 0x%08lx (%s)",
event.u.Exception.ExceptionRecord.ExceptionCode, event.u.Exception.ExceptionRecord.ExceptionCode,
@ -463,10 +473,12 @@ int main(int argc, char *argv[]) {
printf_message(" ExceptionAddress: 0x%08lx", printf_message(" ExceptionAddress: 0x%08lx",
event.u.Exception.ExceptionRecord.ExceptionAddress); event.u.Exception.ExceptionRecord.ExceptionAddress);
printf_message(" (Non-continuable exception debug event)"); printf_message(" (Non-continuable exception debug event)");
write_minidump(argv[1], &process_information, event.dwThreadId);
context = FillInThreadContext(&process_information, &context_buffer);
write_minidump(argv[1], &process_information, event.dwThreadId, &event.u.Exception.ExceptionRecord, context);
printf_message(""); printf_message("");
#ifdef SDLPROCDUMP_PRINTSTACK #ifdef SDLPROCDUMP_PRINTSTACK
print_stacktrace(&process_information, event.u.Exception.ExceptionRecord.ExceptionAddress); print_stacktrace(&process_information, event.u.Exception.ExceptionRecord.ExceptionAddress, context);
#else #else
printf_message("No support for printing stacktrack for current architecture"); printf_message("No support for printing stacktrack for current architecture");
#endif #endif