mini_dump: Cleanup and add comments

Removes some unnecessary code.

wip
This commit is contained in:
lat9nq 2022-07-13 12:14:48 -04:00
parent f958cbc737
commit 3dbaafe1f3
3 changed files with 86 additions and 42 deletions

View File

@ -4097,6 +4097,7 @@ int main(int argc, char* argv[]) {
#ifdef YUZU_DBGHELP #ifdef YUZU_DBGHELP
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
if (!is_child && Settings::values.create_crash_dumps.GetValue() && SpawnDebuggee(argv[0], pi)) { if (!is_child && Settings::values.create_crash_dumps.GetValue() && SpawnDebuggee(argv[0], pi)) {
// Delete the config object so that it doesn't save when the program exits
config.reset(nullptr); config.reset(nullptr);
DebugDebuggee(pi); DebugDebuggee(pi);
return 0; return 0;

View File

@ -1,8 +1,8 @@
#include <cstdio> #include <cstdio>
#include <cstring>
#include <ctime> #include <ctime>
#include <filesystem> #include <filesystem>
#include <windows.h> #include <windows.h>
#include "common/logging/log.h"
#include "yuzu/mini_dump.h" #include "yuzu/mini_dump.h"
#include "yuzu/startup_checks.h" #include "yuzu/startup_checks.h"
@ -11,8 +11,6 @@
void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
EXCEPTION_POINTERS* pep) { EXCEPTION_POINTERS* pep) {
LOG_INFO(Core, "called");
char file_name[255]; char file_name[255];
const std::time_t the_time = std::time(nullptr); const std::time_t the_time = std::time(nullptr);
std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time)); std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time));
@ -29,16 +27,50 @@ void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_
dump_type, (pep != 0) ? info : 0, 0, 0); dump_type, (pep != 0) ? info : 0, 0, 0);
if (!write_dump_status) { if (!write_dump_status) {
LOG_ERROR(Core, "MiniDumpWriteDump failed. Error: {}", GetLastError()); std::fprintf(stderr, "MiniDumpWriteDump failed. Error: %d\n", GetLastError());
} else { } else {
LOG_INFO(Core, "Minidump created."); std::fprintf(stderr, "MiniDump created: %s\n", file_name);
} }
// Close the file // Close the file
CloseHandle(file_handle); CloseHandle(file_handle);
} else { } else {
LOG_ERROR(Core, "CreateFile failed. Error: {}", GetLastError()); std::fprintf(stderr, "CreateFile failed. Error: %d\n", GetLastError());
}
}
void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) {
EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
HANDLE thread_handle = OpenThread(THREAD_GET_CONTEXT, false, deb_ev.dwThreadId);
if (thread_handle == nullptr) {
std::fprintf(stderr, "OpenThread failed (%d)\n", GetLastError());
}
// Get child process context
CONTEXT context;
std::memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(thread_handle, &context)) {
std::fprintf(stderr, "GetThreadContext failed (%d)\n", GetLastError());
return;
}
// Create exception pointers for minidump
EXCEPTION_POINTERS ep;
ep.ExceptionRecord = &record;
ep.ContextRecord = &context;
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = deb_ev.dwThreadId;
info.ExceptionPointers = &ep;
info.ClientPointers = false;
CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep);
if (CloseHandle(thread_handle) == 0) {
std::fprintf(stderr, "error: CloseHandle(thread_handle) failed (%d)\n", GetLastError());
} }
} }
@ -68,6 +100,8 @@ bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) {
void DebugDebuggee(PROCESS_INFORMATION& pi) { void DebugDebuggee(PROCESS_INFORMATION& pi) {
DEBUG_EVENT deb_ev; DEBUG_EVENT deb_ev;
const std::time_t start_time = std::time(nullptr);
//~ bool seen_nonzero_thread_exit = false;
while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) { while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) {
const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE); const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE);
@ -87,51 +121,59 @@ void DebugDebuggee(PROCESS_INFORMATION& pi) {
case UNLOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT:
ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE); ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE);
break; break;
case EXCEPTION_DEBUG_EVENT: //~ case EXIT_THREAD_DEBUG_EVENT: {
//~ const DWORD& exit_code = deb_ev.u.ExitThread.dwExitCode;
//~ // Generate a crash dump on the first abnormal thread exit.
//~ // We don't want to generate on every abnormal thread exit since ALL the other
// threads ~ // in the application will follow by exiting with the same code. ~ if
//(!seen_nonzero_thread_exit && exit_code != 0) { ~ seen_nonzero_thread_exit = true; ~
// std::fprintf(stderr, ~ "Creating MiniDump on first non-zero thread exit: code
// 0x%08x\n", ~ exit_code);
//~ DumpFromDebugEvent(deb_ev, pi);
//~ }
//~ ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE);
//~ break;
//~ }
case EXCEPTION_DEBUG_EVENT: {
EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord; EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
const std::time_t now = std::time(nullptr);
const std::time_t delta = now - start_time;
std::fprintf(stderr, "ExceptionCode: 0x%08x %s\n", record.ExceptionCode, if (ExceptionName(record.ExceptionCode) == nullptr) {
ExceptionName(record.ExceptionCode)); int record_count = 0;
EXCEPTION_RECORD* next_record = &deb_ev.u.Exception.ExceptionRecord;
while (next_record != nullptr) {
std::fprintf(stderr,
"[%d] code(%d): 0x%08x\n\tflags: %08x %s\n\taddress: "
"0x%08x\n\tparameters: %d\n",
delta, record_count, next_record->ExceptionCode,
next_record->ExceptionFlags,
next_record->ExceptionFlags == EXCEPTION_NONCONTINUABLE
? "noncontinuable"
: "",
next_record->ExceptionAddress, next_record->NumberParameters);
for (int i = 0; i < static_cast<int>(next_record->NumberParameters); i++) {
std::fprintf(stderr, "\t\t%0d: 0x%08x\n", i,
next_record->ExceptionInformation[i]);
}
record_count++;
next_record = next_record->ExceptionRecord;
}
}
// We want to generate a crash dump if we are seeing the same exception again.
if (!deb_ev.u.Exception.dwFirstChance) { if (!deb_ev.u.Exception.dwFirstChance) {
HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS, false, deb_ev.dwThreadId); std::fprintf(stderr, "Creating MiniDump on ExceptionCode: 0x%08x %s\n",
if (thread_handle == nullptr) { record.ExceptionCode, ExceptionName(record.ExceptionCode));
std::fprintf(stderr, "OpenThread failed (%d)\n", GetLastError()); DumpFromDebugEvent(deb_ev, pi);
}
if (SuspendThread(thread_handle) == (DWORD)-1) {
std::fprintf(stderr, "SuspendThread failed (%d)\n", GetLastError());
}
CONTEXT context;
std::memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(thread_handle, &context)) {
std::fprintf(stderr, "GetThreadContext failed (%d)\n", GetLastError());
break;
}
EXCEPTION_POINTERS ep;
ep.ExceptionRecord = &record;
ep.ContextRecord = &context;
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = deb_ev.dwThreadId;
info.ExceptionPointers = &ep;
info.ClientPointers = false;
CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep);
std::fprintf(stderr, "previous thread suspend count: %d\n",
ResumeThread(thread_handle));
if (CloseHandle(thread_handle) == 0) {
std::fprintf(stderr, "error: CloseHandle(thread_handle) failed (%d)\n",
GetLastError());
}
} }
ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
break; break;
} }
} }
} }
}
const char* ExceptionName(DWORD exception) { const char* ExceptionName(DWORD exception) {
switch (exception) { switch (exception) {

View File

@ -7,6 +7,7 @@
void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
EXCEPTION_POINTERS* pep); EXCEPTION_POINTERS* pep);
void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi);
bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi); bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi);
void DebugDebuggee(PROCESS_INFORMATION& pi); void DebugDebuggee(PROCESS_INFORMATION& pi);
const char* ExceptionName(DWORD exception); const char* ExceptionName(DWORD exception);