diff options
author | lat9nq <lat9nq@gmail.com> | 2022-07-13 18:14:48 +0200 |
---|---|---|
committer | lat9nq <lat9nq@gmail.com> | 2022-09-05 03:36:05 +0200 |
commit | 3dbaafe1f3364db2721a3318e0cde66fa0c81a5e (patch) | |
tree | a5384cb6a2566728ba8daa95817dafe68c6fd5e8 /src | |
parent | yuzu: Use a debugger to generate minidumps (diff) | |
download | yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar.gz yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar.bz2 yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar.lz yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar.xz yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.tar.zst yuzu-3dbaafe1f3364db2721a3318e0cde66fa0c81a5e.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/yuzu/main.cpp | 1 | ||||
-rw-r--r-- | src/yuzu/mini_dump.cpp | 128 | ||||
-rw-r--r-- | src/yuzu/mini_dump.h | 1 |
3 files changed, 87 insertions, 43 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index ca3f4da70..ff59c64c3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4097,6 +4097,7 @@ int main(int argc, char* argv[]) { #ifdef YUZU_DBGHELP PROCESS_INFORMATION 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); DebugDebuggee(pi); return 0; diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp index ad8a4f607..e60456d9b 100644 --- a/src/yuzu/mini_dump.cpp +++ b/src/yuzu/mini_dump.cpp @@ -1,8 +1,8 @@ #include <cstdio> +#include <cstring> #include <ctime> #include <filesystem> #include <windows.h> -#include "common/logging/log.h" #include "yuzu/mini_dump.h" #include "yuzu/startup_checks.h" @@ -11,8 +11,6 @@ void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, EXCEPTION_POINTERS* pep) { - LOG_INFO(Core, "called"); - char file_name[255]; 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)); @@ -29,16 +27,50 @@ void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_ dump_type, (pep != 0) ? info : 0, 0, 0); if (!write_dump_status) { - LOG_ERROR(Core, "MiniDumpWriteDump failed. Error: {}", GetLastError()); + std::fprintf(stderr, "MiniDumpWriteDump failed. Error: %d\n", GetLastError()); } else { - LOG_INFO(Core, "Minidump created."); + std::fprintf(stderr, "MiniDump created: %s\n", file_name); } // Close the file CloseHandle(file_handle); } 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) { 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) { const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE); @@ -87,49 +121,57 @@ void DebugDebuggee(PROCESS_INFORMATION& pi) { case UNLOAD_DLL_DEBUG_EVENT: ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE); 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; - - std::fprintf(stderr, "ExceptionCode: 0x%08x %s\n", record.ExceptionCode, - ExceptionName(record.ExceptionCode)); - if (!deb_ev.u.Exception.dwFirstChance) { - HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS, false, deb_ev.dwThreadId); - if (thread_handle == nullptr) { - std::fprintf(stderr, "OpenThread failed (%d)\n", GetLastError()); - } - 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()); + const std::time_t now = std::time(nullptr); + const std::time_t delta = now - start_time; + + if (ExceptionName(record.ExceptionCode) == nullptr) { + 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) { + std::fprintf(stderr, "Creating MiniDump on ExceptionCode: 0x%08x %s\n", + record.ExceptionCode, ExceptionName(record.ExceptionCode)); + DumpFromDebugEvent(deb_ev, pi); + } ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); break; } + } } } diff --git a/src/yuzu/mini_dump.h b/src/yuzu/mini_dump.h index 59ba615e4..f6f5dc2c7 100644 --- a/src/yuzu/mini_dump.h +++ b/src/yuzu/mini_dump.h @@ -7,6 +7,7 @@ void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, EXCEPTION_POINTERS* pep); +void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi); bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi); void DebugDebuggee(PROCESS_INFORMATION& pi); const char* ExceptionName(DWORD exception); |