From e339ec0e00905821dbb4fee8e45a2514555f5b0e Mon Sep 17 00:00:00 2001 From: lat9nq Date: Mon, 18 Jul 2022 21:36:26 -0400 Subject: mini_dump: Check for debugger before spawning a child mini_dump: Clean up mini_dump: Fix MSVC error mini_dump: Silence MSVC warning C4700 Zero initialize deb_ev. mini_dump: Add license info --- src/yuzu/mini_dump.cpp | 97 ++++++++++++++++++-------------------------------- src/yuzu/mini_dump.h | 3 ++ 2 files changed, 37 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp index e60456d9b..b25067c10 100644 --- a/src/yuzu/mini_dump.cpp +++ b/src/yuzu/mini_dump.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + #include #include #include @@ -16,28 +19,28 @@ void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_ std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time)); // Open the file - HANDLE file_handle = CreateFile(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - - if ((file_handle != nullptr) && (file_handle != INVALID_HANDLE_VALUE)) { - // Create the minidump - const MINIDUMP_TYPE dump_type = MiniDumpNormal; + HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle, - dump_type, (pep != 0) ? info : 0, 0, 0); + if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) { + std::fprintf(stderr, "CreateFileA failed. Error: %d\n", GetLastError()); + return; + } - if (!write_dump_status) { - std::fprintf(stderr, "MiniDumpWriteDump failed. Error: %d\n", GetLastError()); - } else { - std::fprintf(stderr, "MiniDump created: %s\n", file_name); - } + // Create the minidump + const MINIDUMP_TYPE dump_type = MiniDumpNormal; - // Close the file - CloseHandle(file_handle); + const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle, + dump_type, (pep != 0) ? info : 0, 0, 0); + if (write_dump_status) { + std::fprintf(stderr, "MiniDump created: %s\n", file_name); } else { - std::fprintf(stderr, "CreateFile failed. Error: %d\n", GetLastError()); + std::fprintf(stderr, "MiniDumpWriteDump failed. Error: %d\n", GetLastError()); } + + // Close the file + CloseHandle(file_handle); } void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) { @@ -77,13 +80,13 @@ void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) { bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) { std::memset(&pi, 0, sizeof(pi)); - if (!SpawnChild(arg0, &pi, 0)) { - std::fprintf(stderr, "warning: continuing without crash dumps\n"); + // Don't debug if we are already being debugged + if (IsDebuggerPresent()) { return false; } - // Don't debug if we are already being debugged - if (IsDebuggerPresent()) { + if (!SpawnChild(arg0, &pi, 0)) { + std::fprintf(stderr, "warning: continuing without crash dumps\n"); return false; } @@ -100,8 +103,7 @@ 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; + std::memset(&deb_ev, 0, sizeof(deb_ev)); while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) { const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE); @@ -119,59 +121,28 @@ void DebugDebuggee(PROCESS_INFORMATION& pi) { case LOAD_DLL_DEBUG_EVENT: case RIP_EVENT: case UNLOAD_DLL_DEBUG_EVENT: + // Continue on all other debug events ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE); break; - //~ 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: { + case EXCEPTION_DEBUG_EVENT: EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord; - 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(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); } + + // Continue without handling the exception. + // Lets the debuggee use its own exception handler. + // - If one does not exist, we will see the exception once more where we make a minidump + // for. Then when it reaches here again, yuzu will probably crash. + // - DBG_CONTINUE on an exception that the debuggee does not handle can set us up for an + // infinite loop of exceptions. 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 f6f5dc2c7..2052e5248 100644 --- a/src/yuzu/mini_dump.h +++ b/src/yuzu/mini_dump.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once #include -- cgit v1.2.3