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
This commit is contained in:
		| @@ -1,3 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include <cstdio> | ||||
| #include <cstring> | ||||
| #include <ctime> | ||||
| @@ -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, | ||||
|     HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, | ||||
|                                      CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | ||||
|  | ||||
|     if ((file_handle != nullptr) && (file_handle != INVALID_HANDLE_VALUE)) { | ||||
|     if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) { | ||||
|         std::fprintf(stderr, "CreateFileA failed. Error: %d\n", GetLastError()); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Create the minidump | ||||
|     const MINIDUMP_TYPE dump_type = MiniDumpNormal; | ||||
|  | ||||
|     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, "MiniDumpWriteDump failed. Error: %d\n", GetLastError()); | ||||
|         } else { | ||||
|     if (write_dump_status) { | ||||
|         std::fprintf(stderr, "MiniDump created: %s\n", file_name); | ||||
|     } else { | ||||
|         std::fprintf(stderr, "MiniDumpWriteDump failed. Error: %d\n", GetLastError()); | ||||
|     } | ||||
|  | ||||
|     // Close the file | ||||
|     CloseHandle(file_handle); | ||||
|  | ||||
|     } else { | ||||
|         std::fprintf(stderr, "CreateFile failed. Error: %d\n", GetLastError()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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,60 +121,29 @@ 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<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); | ||||
|             } | ||||
|  | ||||
|             // 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; | ||||
|         } | ||||
|     } | ||||
|     } | ||||
| } | ||||
|  | ||||
| const char* ExceptionName(DWORD exception) { | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <windows.h> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user