From e339ec0e00905821dbb4fee8e45a2514555f5b0e Mon Sep 17 00:00:00 2001
From: lat9nq <lat9nq@gmail.com>
Date: Mon, 18 Jul 2022 21:36:26 -0400
Subject: [PATCH] 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 | 103 +++++++++++++++--------------------------
 src/yuzu/mini_dump.h   |   3 ++
 2 files changed, 40 insertions(+), 66 deletions(-)

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 <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,
-                                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 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)) {
-        // 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 {
-            std::fprintf(stderr, "MiniDump created: %s\n", file_name);
-        }
-
-        // Close the file
-        CloseHandle(file_handle);
-
-    } else {
-        std::fprintf(stderr, "CreateFile failed. Error: %d\n", GetLastError());
+    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, "MiniDump created: %s\n", file_name);
+    } else {
+        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<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;
         }
-        }
     }
 }
 
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 <windows.h>