diff options
| -rwxr-xr-x | .ci/scripts/clang/docker.sh | 1 | ||||
| -rwxr-xr-x | .ci/scripts/linux/docker.sh | 1 | ||||
| -rwxr-xr-x | .ci/scripts/windows/docker.sh | 1 | ||||
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 24 | ||||
| -rw-r--r-- | externals/CMakeLists.txt | 102 | ||||
| m--------- | externals/breakpad | 0 | ||||
| m--------- | externals/dynarmic | 0 | ||||
| -rw-r--r-- | src/common/fs/fs_paths.h | 1 | ||||
| -rw-r--r-- | src/common/fs/path_util.cpp | 1 | ||||
| -rw-r--r-- | src/common/fs/path_util.h | 1 | ||||
| -rw-r--r-- | src/common/settings.h | 1 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | src/yuzu/breakpad.cpp | 77 | ||||
| -rw-r--r-- | src/yuzu/breakpad.h | 10 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_debug.cpp | 18 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_debug.ui | 7 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 19 | ||||
| -rw-r--r-- | src/yuzu/mini_dump.cpp | 202 | ||||
| -rw-r--r-- | src/yuzu/mini_dump.h | 19 | ||||
| -rw-r--r-- | vcpkg.json | 4 |
21 files changed, 221 insertions, 281 deletions
diff --git a/.ci/scripts/clang/docker.sh b/.ci/scripts/clang/docker.sh index 51769545e..f878e24e1 100755 --- a/.ci/scripts/clang/docker.sh +++ b/.ci/scripts/clang/docker.sh | |||
| @@ -19,6 +19,7 @@ cmake .. \ | |||
| 19 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ | 19 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ |
| 20 | -DENABLE_QT_TRANSLATION=ON \ | 20 | -DENABLE_QT_TRANSLATION=ON \ |
| 21 | -DUSE_DISCORD_PRESENCE=ON \ | 21 | -DUSE_DISCORD_PRESENCE=ON \ |
| 22 | -DYUZU_CRASH_DUMPS=ON \ | ||
| 22 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ | 23 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ |
| 23 | -DYUZU_USE_BUNDLED_FFMPEG=ON \ | 24 | -DYUZU_USE_BUNDLED_FFMPEG=ON \ |
| 24 | -GNinja | 25 | -GNinja |
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index a16577b27..7bba01d62 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh | |||
| @@ -23,6 +23,7 @@ cmake .. \ | |||
| 23 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ | 23 | -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ |
| 24 | -DYUZU_USE_BUNDLED_FFMPEG=ON \ | 24 | -DYUZU_USE_BUNDLED_FFMPEG=ON \ |
| 25 | -DYUZU_ENABLE_LTO=ON \ | 25 | -DYUZU_ENABLE_LTO=ON \ |
| 26 | -DYUZU_CRASH_DUMPS=ON \ | ||
| 26 | -GNinja | 27 | -GNinja |
| 27 | 28 | ||
| 28 | ninja | 29 | ninja |
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index 45f75c874..44023600d 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh | |||
| @@ -17,7 +17,6 @@ cmake .. \ | |||
| 17 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ | 17 | -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ |
| 18 | -DENABLE_QT_TRANSLATION=ON \ | 18 | -DENABLE_QT_TRANSLATION=ON \ |
| 19 | -DUSE_CCACHE=ON \ | 19 | -DUSE_CCACHE=ON \ |
| 20 | -DYUZU_CRASH_DUMPS=ON \ | ||
| 21 | -DYUZU_USE_BUNDLED_SDL2=OFF \ | 20 | -DYUZU_USE_BUNDLED_SDL2=OFF \ |
| 22 | -DYUZU_USE_EXTERNAL_SDL2=OFF \ | 21 | -DYUZU_USE_EXTERNAL_SDL2=OFF \ |
| 23 | -DYUZU_TESTS=OFF \ | 22 | -DYUZU_TESTS=OFF \ |
diff --git a/.gitmodules b/.gitmodules index 361f4845b..fdddb0d3a 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -58,3 +58,6 @@ | |||
| 58 | [submodule "VulkanMemoryAllocator"] | 58 | [submodule "VulkanMemoryAllocator"] |
| 59 | path = externals/VulkanMemoryAllocator | 59 | path = externals/VulkanMemoryAllocator |
| 60 | url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git | 60 | url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git |
| 61 | [submodule "breakpad"] | ||
| 62 | path = externals/breakpad | ||
| 63 | url = https://github.com/yuzu-emu/breakpad.git | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 150c78d64..9c35e0946 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -52,7 +52,7 @@ option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" | |||
| 52 | 52 | ||
| 53 | CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF) | 53 | CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF) |
| 54 | 54 | ||
| 55 | CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF) | 55 | CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) |
| 56 | 56 | ||
| 57 | option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") | 57 | option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") |
| 58 | 58 | ||
| @@ -139,9 +139,6 @@ if (YUZU_USE_BUNDLED_VCPKG) | |||
| 139 | if (YUZU_TESTS) | 139 | if (YUZU_TESTS) |
| 140 | list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") | 140 | list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") |
| 141 | endif() | 141 | endif() |
| 142 | if (YUZU_CRASH_DUMPS) | ||
| 143 | list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp") | ||
| 144 | endif() | ||
| 145 | if (ENABLE_WEB_SERVICE) | 142 | if (ENABLE_WEB_SERVICE) |
| 146 | list(APPEND VCPKG_MANIFEST_FEATURES "web-service") | 143 | list(APPEND VCPKG_MANIFEST_FEATURES "web-service") |
| 147 | endif() | 144 | endif() |
| @@ -551,6 +548,18 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) | |||
| 551 | find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS}) | 548 | find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS}) |
| 552 | endif() | 549 | endif() |
| 553 | 550 | ||
| 551 | if (WIN32 AND YUZU_CRASH_DUMPS) | ||
| 552 | set(BREAKPAD_VER "breakpad-c89f9dd") | ||
| 553 | download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX) | ||
| 554 | |||
| 555 | set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include") | ||
| 556 | set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib") | ||
| 557 | |||
| 558 | add_library(libbreakpad_client INTERFACE IMPORTED) | ||
| 559 | target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}") | ||
| 560 | target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}") | ||
| 561 | endif() | ||
| 562 | |||
| 554 | # Prefer the -pthread flag on Linux. | 563 | # Prefer the -pthread flag on Linux. |
| 555 | set(THREADS_PREFER_PTHREAD_FLAG ON) | 564 | set(THREADS_PREFER_PTHREAD_FLAG ON) |
| 556 | find_package(Threads REQUIRED) | 565 | find_package(Threads REQUIRED) |
| @@ -570,13 +579,6 @@ elseif (WIN32) | |||
| 570 | # PSAPI is the Process Status API | 579 | # PSAPI is the Process Status API |
| 571 | set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) | 580 | set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) |
| 572 | endif() | 581 | endif() |
| 573 | |||
| 574 | if (YUZU_CRASH_DUMPS) | ||
| 575 | find_library(DBGHELP_LIBRARY dbghelp) | ||
| 576 | if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND") | ||
| 577 | message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found") | ||
| 578 | endif() | ||
| 579 | endif() | ||
| 580 | elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") | 582 | elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") |
| 581 | set(PLATFORM_LIBRARIES rt) | 583 | set(PLATFORM_LIBRARIES rt) |
| 582 | endif() | 584 | endif() |
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 6e5bfbba6..61baabb03 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -189,3 +189,105 @@ if (ANDROID) | |||
| 189 | add_subdirectory(libadrenotools) | 189 | add_subdirectory(libadrenotools) |
| 190 | endif() | 190 | endif() |
| 191 | endif() | 191 | endif() |
| 192 | |||
| 193 | # Breakpad | ||
| 194 | # https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt | ||
| 195 | if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) | ||
| 196 | set(BREAKPAD_WIN32_DEFINES | ||
| 197 | NOMINMAX | ||
| 198 | UNICODE | ||
| 199 | WIN32_LEAN_AND_MEAN | ||
| 200 | _CRT_SECURE_NO_WARNINGS | ||
| 201 | _CRT_SECURE_NO_DEPRECATE | ||
| 202 | _CRT_NONSTDC_NO_DEPRECATE | ||
| 203 | ) | ||
| 204 | |||
| 205 | # libbreakpad | ||
| 206 | add_library(libbreakpad STATIC) | ||
| 207 | file(GLOB_RECURSE LIBBREAKPAD_SOURCES breakpad/src/processor/*.cc) | ||
| 208 | file(GLOB_RECURSE LIBDISASM_SOURCES breakpad/src/third_party/libdisasm/*.c) | ||
| 209 | list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "_unittest|_selftest|synth_minidump|/tests|/testdata|/solaris|microdump_stackwalk|minidump_dump|minidump_stackwalk") | ||
| 210 | if (WIN32) | ||
| 211 | list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/mac|/android") | ||
| 212 | target_compile_definitions(libbreakpad PRIVATE ${BREAKPAD_WIN32_DEFINES}) | ||
| 213 | target_include_directories(libbreakpad PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include") | ||
| 214 | elseif (APPLE) | ||
| 215 | list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/windows|/android") | ||
| 216 | else() | ||
| 217 | list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/mac|/windows|/android") | ||
| 218 | endif() | ||
| 219 | target_sources(libbreakpad PRIVATE ${LIBBREAKPAD_SOURCES} ${LIBDISASM_SOURCES}) | ||
| 220 | target_include_directories(libbreakpad | ||
| 221 | PUBLIC | ||
| 222 | ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src | ||
| 223 | ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src/third_party/libdisasm | ||
| 224 | ) | ||
| 225 | |||
| 226 | # libbreakpad_client | ||
| 227 | add_library(libbreakpad_client STATIC) | ||
| 228 | file(GLOB LIBBREAKPAD_COMMON_SOURCES breakpad/src/common/*.cc breakpad/src/common/*.c breakpad/src/client/*.cc) | ||
| 229 | |||
| 230 | if (WIN32) | ||
| 231 | file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/windows/*.cc breakpad/src/common/windows/*.cc) | ||
| 232 | list(FILTER LIBBREAKPAD_COMMON_SOURCES EXCLUDE REGEX "language.cc|path_helper.cc|stabs_to_module.cc|stabs_reader.cc|minidump_file_writer.cc") | ||
| 233 | target_include_directories(libbreakpad_client PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include") | ||
| 234 | target_compile_definitions(libbreakpad_client PRIVATE ${BREAKPAD_WIN32_DEFINES}) | ||
| 235 | elseif (APPLE) | ||
| 236 | target_compile_definitions(libbreakpad_client PRIVATE HAVE_MACH_O_NLIST_H) | ||
| 237 | file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/mac/*.cc breakpad/src/common/mac/*.cc) | ||
| 238 | list(APPEND LIBBREAKPAD_CLIENT_SOURCES breakpad/src/common/mac/MachIPC.mm) | ||
| 239 | else() | ||
| 240 | target_compile_definitions(libbreakpad_client PUBLIC -DHAVE_A_OUT_H) | ||
| 241 | file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/linux/*.cc breakpad/src/common/linux/*.cc) | ||
| 242 | endif() | ||
| 243 | list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${LIBBREAKPAD_COMMON_SOURCES}) | ||
| 244 | list(FILTER LIBBREAKPAD_CLIENT_SOURCES EXCLUDE REGEX "/sender|/tests|/unittests|/testcases|_unittest|_test") | ||
| 245 | target_sources(libbreakpad_client PRIVATE ${LIBBREAKPAD_CLIENT_SOURCES}) | ||
| 246 | target_include_directories(libbreakpad_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src) | ||
| 247 | |||
| 248 | if (WIN32) | ||
| 249 | target_link_libraries(libbreakpad_client PRIVATE wininet.lib) | ||
| 250 | elseif (APPLE) | ||
| 251 | find_library(CoreFoundation_FRAMEWORK CoreFoundation) | ||
| 252 | target_link_libraries(libbreakpad_client PRIVATE ${CoreFoundation_FRAMEWORK}) | ||
| 253 | else() | ||
| 254 | find_library(PTHREAD_LIBRARIES pthread) | ||
| 255 | target_compile_definitions(libbreakpad_client PRIVATE HAVE_GETCONTEXT=1) | ||
| 256 | if (PTHREAD_LIBRARIES) | ||
| 257 | target_link_libraries(libbreakpad_client PRIVATE ${PTHREAD_LIBRARIES}) | ||
| 258 | endif() | ||
| 259 | endif() | ||
| 260 | |||
| 261 | # Host tools for symbol processing | ||
| 262 | if (LINUX) | ||
| 263 | find_package(ZLIB REQUIRED) | ||
| 264 | |||
| 265 | add_executable(minidump_stackwalk breakpad/src/processor/minidump_stackwalk.cc) | ||
| 266 | target_link_libraries(minidump_stackwalk PRIVATE libbreakpad libbreakpad_client) | ||
| 267 | |||
| 268 | add_executable(dump_syms | ||
| 269 | breakpad/src/common/dwarf_cfi_to_module.cc | ||
| 270 | breakpad/src/common/dwarf_cu_to_module.cc | ||
| 271 | breakpad/src/common/dwarf_line_to_module.cc | ||
| 272 | breakpad/src/common/dwarf_range_list_handler.cc | ||
| 273 | breakpad/src/common/language.cc | ||
| 274 | breakpad/src/common/module.cc | ||
| 275 | breakpad/src/common/path_helper.cc | ||
| 276 | breakpad/src/common/stabs_reader.cc | ||
| 277 | breakpad/src/common/stabs_to_module.cc | ||
| 278 | breakpad/src/common/dwarf/bytereader.cc | ||
| 279 | breakpad/src/common/dwarf/dwarf2diehandler.cc | ||
| 280 | breakpad/src/common/dwarf/dwarf2reader.cc | ||
| 281 | breakpad/src/common/dwarf/elf_reader.cc | ||
| 282 | breakpad/src/common/linux/crc32.cc | ||
| 283 | breakpad/src/common/linux/dump_symbols.cc | ||
| 284 | breakpad/src/common/linux/elf_symbols_to_module.cc | ||
| 285 | breakpad/src/common/linux/elfutils.cc | ||
| 286 | breakpad/src/common/linux/file_id.cc | ||
| 287 | breakpad/src/common/linux/linux_libc_support.cc | ||
| 288 | breakpad/src/common/linux/memory_mapped_file.cc | ||
| 289 | breakpad/src/common/linux/safe_readlink.cc | ||
| 290 | breakpad/src/tools/linux/dump_syms/dump_syms.cc) | ||
| 291 | target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB) | ||
| 292 | endif() | ||
| 293 | endif() | ||
diff --git a/externals/breakpad b/externals/breakpad new file mode 160000 | |||
| Subproject c89f9dddc793f19910ef06c13e4fd240da4e7a5 | |||
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 7da378033a7764f955516f75194856d87bbcd7a | Subproject 0df09e2f6b61c2d7ad2f2053d4f020a5c33e037 | ||
diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h index 441c8af97..bcf447089 100644 --- a/src/common/fs/fs_paths.h +++ b/src/common/fs/fs_paths.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #define AMIIBO_DIR "amiibo" | 13 | #define AMIIBO_DIR "amiibo" |
| 14 | #define CACHE_DIR "cache" | 14 | #define CACHE_DIR "cache" |
| 15 | #define CONFIG_DIR "config" | 15 | #define CONFIG_DIR "config" |
| 16 | #define CRASH_DUMPS_DIR "crash_dumps" | ||
| 16 | #define DUMP_DIR "dump" | 17 | #define DUMP_DIR "dump" |
| 17 | #define KEYS_DIR "keys" | 18 | #define KEYS_DIR "keys" |
| 18 | #define LOAD_DIR "load" | 19 | #define LOAD_DIR "load" |
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 0abd81a45..0c4c88cde 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp | |||
| @@ -119,6 +119,7 @@ public: | |||
| 119 | GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR); | 119 | GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR); |
| 120 | GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache); | 120 | GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache); |
| 121 | GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config); | 121 | GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config); |
| 122 | GenerateYuzuPath(YuzuPath::CrashDumpsDir, yuzu_path / CRASH_DUMPS_DIR); | ||
| 122 | GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR); | 123 | GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR); |
| 123 | GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR); | 124 | GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR); |
| 124 | GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR); | 125 | GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR); |
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index 63801c924..2874ea738 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h | |||
| @@ -15,6 +15,7 @@ enum class YuzuPath { | |||
| 15 | AmiiboDir, // Where Amiibo backups are stored. | 15 | AmiiboDir, // Where Amiibo backups are stored. |
| 16 | CacheDir, // Where cached filesystem data is stored. | 16 | CacheDir, // Where cached filesystem data is stored. |
| 17 | ConfigDir, // Where config files are stored. | 17 | ConfigDir, // Where config files are stored. |
| 18 | CrashDumpsDir, // Where crash dumps are stored. | ||
| 18 | DumpDir, // Where dumped data is stored. | 19 | DumpDir, // Where dumped data is stored. |
| 19 | KeysDir, // Where key files are stored. | 20 | KeysDir, // Where key files are stored. |
| 20 | LoadDir, // Where cheat/mod files are stored. | 21 | LoadDir, // Where cheat/mod files are stored. |
diff --git a/src/common/settings.h b/src/common/settings.h index 236e33bee..9317075f7 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -505,7 +505,6 @@ struct Values { | |||
| 505 | linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false}; | 505 | linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false}; |
| 506 | Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers", | 506 | Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers", |
| 507 | Category::Debugging}; | 507 | Category::Debugging}; |
| 508 | Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging}; | ||
| 509 | Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging}; | 508 | Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging}; |
| 510 | 509 | ||
| 511 | // Miscellaneous | 510 | // Miscellaneous |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 34208ed74..33e1fb663 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -227,14 +227,14 @@ add_executable(yuzu | |||
| 227 | yuzu.rc | 227 | yuzu.rc |
| 228 | ) | 228 | ) |
| 229 | 229 | ||
| 230 | if (WIN32 AND YUZU_CRASH_DUMPS) | 230 | if (YUZU_CRASH_DUMPS) |
| 231 | target_sources(yuzu PRIVATE | 231 | target_sources(yuzu PRIVATE |
| 232 | mini_dump.cpp | 232 | breakpad.cpp |
| 233 | mini_dump.h | 233 | breakpad.h |
| 234 | ) | 234 | ) |
| 235 | 235 | ||
| 236 | target_link_libraries(yuzu PRIVATE ${DBGHELP_LIBRARY}) | 236 | target_link_libraries(yuzu PRIVATE libbreakpad_client) |
| 237 | target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP) | 237 | target_compile_definitions(yuzu PRIVATE YUZU_CRASH_DUMPS) |
| 238 | endif() | 238 | endif() |
| 239 | 239 | ||
| 240 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | 240 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") |
diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp new file mode 100644 index 000000000..0f6a71ab0 --- /dev/null +++ b/src/yuzu/breakpad.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <ranges> | ||
| 6 | |||
| 7 | #if defined(_WIN32) | ||
| 8 | #include <client/windows/handler/exception_handler.h> | ||
| 9 | #elif defined(__linux__) | ||
| 10 | #include <client/linux/handler/exception_handler.h> | ||
| 11 | #else | ||
| 12 | #error Minidump creation not supported on this platform | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "common/fs/fs_paths.h" | ||
| 16 | #include "common/fs/path_util.h" | ||
| 17 | #include "yuzu/breakpad.h" | ||
| 18 | |||
| 19 | namespace Breakpad { | ||
| 20 | |||
| 21 | static void PruneDumpDirectory(const std::filesystem::path& dump_path) { | ||
| 22 | // Code in this function should be exception-safe. | ||
| 23 | struct Entry { | ||
| 24 | std::filesystem::path path; | ||
| 25 | std::filesystem::file_time_type last_write_time; | ||
| 26 | }; | ||
| 27 | std::vector<Entry> existing_dumps; | ||
| 28 | |||
| 29 | // Get existing entries. | ||
| 30 | std::error_code ec; | ||
| 31 | std::filesystem::directory_iterator dir(dump_path, ec); | ||
| 32 | for (auto& entry : dir) { | ||
| 33 | if (entry.is_regular_file()) { | ||
| 34 | existing_dumps.push_back(Entry{ | ||
| 35 | .path = entry.path(), | ||
| 36 | .last_write_time = entry.last_write_time(ec), | ||
| 37 | }); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // Sort descending by creation date. | ||
| 42 | std::ranges::stable_sort(existing_dumps, [](const auto& a, const auto& b) { | ||
| 43 | return a.last_write_time > b.last_write_time; | ||
| 44 | }); | ||
| 45 | |||
| 46 | // Delete older dumps. | ||
| 47 | for (size_t i = 5; i < existing_dumps.size(); i++) { | ||
| 48 | std::filesystem::remove(existing_dumps[i].path, ec); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | #if defined(__linux__) | ||
| 53 | [[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, | ||
| 54 | bool succeeded) { | ||
| 55 | // Prevent time- and space-consuming core dumps from being generated, as we have | ||
| 56 | // already generated a minidump and a core file will not be useful anyway. | ||
| 57 | _exit(1); | ||
| 58 | } | ||
| 59 | #endif | ||
| 60 | |||
| 61 | void InstallCrashHandler() { | ||
| 62 | // Write crash dumps to profile directory. | ||
| 63 | const auto dump_path = GetYuzuPath(Common::FS::YuzuPath::CrashDumpsDir); | ||
| 64 | PruneDumpDirectory(dump_path); | ||
| 65 | |||
| 66 | #if defined(_WIN32) | ||
| 67 | // TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API. | ||
| 68 | static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr, | ||
| 69 | google_breakpad::ExceptionHandler::HANDLER_ALL}; | ||
| 70 | #elif defined(__linux__) | ||
| 71 | static google_breakpad::MinidumpDescriptor descriptor{dump_path}; | ||
| 72 | static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback, | ||
| 73 | nullptr, true, -1}; | ||
| 74 | #endif | ||
| 75 | } | ||
| 76 | |||
| 77 | } // namespace Breakpad | ||
diff --git a/src/yuzu/breakpad.h b/src/yuzu/breakpad.h new file mode 100644 index 000000000..0f911aa9c --- /dev/null +++ b/src/yuzu/breakpad.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace Breakpad { | ||
| 7 | |||
| 8 | void InstallCrashHandler(); | ||
| 9 | |||
| 10 | } | ||
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index b22fda746..ef421c754 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -27,16 +27,6 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) | |||
| 27 | 27 | ||
| 28 | connect(ui->toggle_gdbstub, &QCheckBox::toggled, | 28 | connect(ui->toggle_gdbstub, &QCheckBox::toggled, |
| 29 | [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); }); | 29 | [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); }); |
| 30 | |||
| 31 | connect(ui->create_crash_dumps, &QCheckBox::stateChanged, [&](int) { | ||
| 32 | if (crash_dump_warning_shown) { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | QMessageBox::warning(this, tr("Restart Required"), | ||
| 36 | tr("yuzu is required to restart in order to apply this setting."), | ||
| 37 | QMessageBox::Ok, QMessageBox::Ok); | ||
| 38 | crash_dump_warning_shown = true; | ||
| 39 | }); | ||
| 40 | } | 30 | } |
| 41 | 31 | ||
| 42 | ConfigureDebug::~ConfigureDebug() = default; | 32 | ConfigureDebug::~ConfigureDebug() = default; |
| @@ -89,13 +79,6 @@ void ConfigureDebug::SetConfiguration() { | |||
| 89 | ui->disable_web_applet->setEnabled(false); | 79 | ui->disable_web_applet->setEnabled(false); |
| 90 | ui->disable_web_applet->setText(tr("Web applet not compiled")); | 80 | ui->disable_web_applet->setText(tr("Web applet not compiled")); |
| 91 | #endif | 81 | #endif |
| 92 | |||
| 93 | #ifdef YUZU_DBGHELP | ||
| 94 | ui->create_crash_dumps->setChecked(Settings::values.create_crash_dumps.GetValue()); | ||
| 95 | #else | ||
| 96 | ui->create_crash_dumps->setEnabled(false); | ||
| 97 | ui->create_crash_dumps->setText(tr("MiniDump creation not compiled")); | ||
| 98 | #endif | ||
| 99 | } | 82 | } |
| 100 | 83 | ||
| 101 | void ConfigureDebug::ApplyConfiguration() { | 84 | void ConfigureDebug::ApplyConfiguration() { |
| @@ -107,7 +90,6 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 107 | Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked(); | 90 | Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked(); |
| 108 | Settings::values.reporting_services = ui->reporting_services->isChecked(); | 91 | Settings::values.reporting_services = ui->reporting_services->isChecked(); |
| 109 | Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked(); | 92 | Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked(); |
| 110 | Settings::values.create_crash_dumps = ui->create_crash_dumps->isChecked(); | ||
| 111 | Settings::values.quest_flag = ui->quest_flag->isChecked(); | 93 | Settings::values.quest_flag = ui->quest_flag->isChecked(); |
| 112 | Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); | 94 | Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); |
| 113 | Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); | 95 | Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 66b8b7459..76fe98924 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -471,13 +471,6 @@ | |||
| 471 | </property> | 471 | </property> |
| 472 | </widget> | 472 | </widget> |
| 473 | </item> | 473 | </item> |
| 474 | <item row="4" column="0"> | ||
| 475 | <widget class="QCheckBox" name="create_crash_dumps"> | ||
| 476 | <property name="text"> | ||
| 477 | <string>Create Minidump After Crash</string> | ||
| 478 | </property> | ||
| 479 | </widget> | ||
| 480 | </item> | ||
| 481 | <item row="3" column="0"> | 474 | <item row="3" column="0"> |
| 482 | <widget class="QCheckBox" name="dump_audio_commands"> | 475 | <widget class="QCheckBox" name="dump_audio_commands"> |
| 483 | <property name="toolTip"> | 476 | <property name="toolTip"> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 816d804c4..7cc11ae3b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -159,8 +159,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 159 | #include "yuzu/util/clickable_label.h" | 159 | #include "yuzu/util/clickable_label.h" |
| 160 | #include "yuzu/vk_device_info.h" | 160 | #include "yuzu/vk_device_info.h" |
| 161 | 161 | ||
| 162 | #ifdef YUZU_DBGHELP | 162 | #ifdef YUZU_CRASH_DUMPS |
| 163 | #include "yuzu/mini_dump.h" | 163 | #include "yuzu/breakpad.h" |
| 164 | #endif | 164 | #endif |
| 165 | 165 | ||
| 166 | using namespace Common::Literals; | 166 | using namespace Common::Literals; |
| @@ -5187,22 +5187,15 @@ int main(int argc, char* argv[]) { | |||
| 5187 | return 0; | 5187 | return 0; |
| 5188 | } | 5188 | } |
| 5189 | 5189 | ||
| 5190 | #ifdef YUZU_DBGHELP | ||
| 5191 | PROCESS_INFORMATION pi; | ||
| 5192 | if (!is_child && Settings::values.create_crash_dumps.GetValue() && | ||
| 5193 | MiniDump::SpawnDebuggee(argv[0], pi)) { | ||
| 5194 | // Delete the config object so that it doesn't save when the program exits | ||
| 5195 | config.reset(nullptr); | ||
| 5196 | MiniDump::DebugDebuggee(pi); | ||
| 5197 | return 0; | ||
| 5198 | } | ||
| 5199 | #endif | ||
| 5200 | |||
| 5201 | if (StartupChecks(argv[0], &has_broken_vulkan, | 5190 | if (StartupChecks(argv[0], &has_broken_vulkan, |
| 5202 | Settings::values.perform_vulkan_check.GetValue())) { | 5191 | Settings::values.perform_vulkan_check.GetValue())) { |
| 5203 | return 0; | 5192 | return 0; |
| 5204 | } | 5193 | } |
| 5205 | 5194 | ||
| 5195 | #ifdef YUZU_CRASH_DUMPS | ||
| 5196 | Breakpad::InstallCrashHandler(); | ||
| 5197 | #endif | ||
| 5198 | |||
| 5206 | Common::DetachedTasks detached_tasks; | 5199 | Common::DetachedTasks detached_tasks; |
| 5207 | MicroProfileOnThreadCreate("Frontend"); | 5200 | MicroProfileOnThreadCreate("Frontend"); |
| 5208 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 5201 | SCOPE_EXIT({ MicroProfileShutdown(); }); |
diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp deleted file mode 100644 index a34dc6a9c..000000000 --- a/src/yuzu/mini_dump.cpp +++ /dev/null | |||
| @@ -1,202 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cstdio> | ||
| 5 | #include <cstring> | ||
| 6 | #include <ctime> | ||
| 7 | #include <filesystem> | ||
| 8 | #include <fmt/format.h> | ||
| 9 | #include <windows.h> | ||
| 10 | #include "yuzu/mini_dump.h" | ||
| 11 | #include "yuzu/startup_checks.h" | ||
| 12 | |||
| 13 | // dbghelp.h must be included after windows.h | ||
| 14 | #include <dbghelp.h> | ||
| 15 | |||
| 16 | namespace MiniDump { | ||
| 17 | |||
| 18 | void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, | ||
| 19 | EXCEPTION_POINTERS* pep) { | ||
| 20 | char file_name[255]; | ||
| 21 | const std::time_t the_time = std::time(nullptr); | ||
| 22 | std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time)); | ||
| 23 | |||
| 24 | // Open the file | ||
| 25 | HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, | ||
| 26 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | ||
| 27 | |||
| 28 | if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) { | ||
| 29 | fmt::print(stderr, "CreateFileA failed. Error: {}", GetLastError()); | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | // Create the minidump | ||
| 34 | const MINIDUMP_TYPE dump_type = MiniDumpNormal; | ||
| 35 | |||
| 36 | const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle, | ||
| 37 | dump_type, (pep != 0) ? info : 0, 0, 0); | ||
| 38 | |||
| 39 | if (write_dump_status) { | ||
| 40 | fmt::print(stderr, "MiniDump created: {}", file_name); | ||
| 41 | } else { | ||
| 42 | fmt::print(stderr, "MiniDumpWriteDump failed. Error: {}", GetLastError()); | ||
| 43 | } | ||
| 44 | |||
| 45 | // Close the file | ||
| 46 | CloseHandle(file_handle); | ||
| 47 | } | ||
| 48 | |||
| 49 | void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) { | ||
| 50 | EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord; | ||
| 51 | |||
| 52 | HANDLE thread_handle = OpenThread(THREAD_GET_CONTEXT, false, deb_ev.dwThreadId); | ||
| 53 | if (thread_handle == nullptr) { | ||
| 54 | fmt::print(stderr, "OpenThread failed ({})", GetLastError()); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | // Get child process context | ||
| 59 | CONTEXT context = {}; | ||
| 60 | context.ContextFlags = CONTEXT_ALL; | ||
| 61 | if (!GetThreadContext(thread_handle, &context)) { | ||
| 62 | fmt::print(stderr, "GetThreadContext failed ({})", GetLastError()); | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | |||
| 66 | // Create exception pointers for minidump | ||
| 67 | EXCEPTION_POINTERS ep; | ||
| 68 | ep.ExceptionRecord = &record; | ||
| 69 | ep.ContextRecord = &context; | ||
| 70 | |||
| 71 | MINIDUMP_EXCEPTION_INFORMATION info; | ||
| 72 | info.ThreadId = deb_ev.dwThreadId; | ||
| 73 | info.ExceptionPointers = &ep; | ||
| 74 | info.ClientPointers = false; | ||
| 75 | |||
| 76 | CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep); | ||
| 77 | |||
| 78 | if (CloseHandle(thread_handle) == 0) { | ||
| 79 | fmt::print(stderr, "error: CloseHandle(thread_handle) failed ({})", GetLastError()); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) { | ||
| 84 | std::memset(&pi, 0, sizeof(pi)); | ||
| 85 | |||
| 86 | // Don't debug if we are already being debugged | ||
| 87 | if (IsDebuggerPresent()) { | ||
| 88 | return false; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (!SpawnChild(arg0, &pi, 0)) { | ||
| 92 | fmt::print(stderr, "warning: continuing without crash dumps"); | ||
| 93 | return false; | ||
| 94 | } | ||
| 95 | |||
| 96 | const bool can_debug = DebugActiveProcess(pi.dwProcessId); | ||
| 97 | if (!can_debug) { | ||
| 98 | fmt::print(stderr, | ||
| 99 | "warning: DebugActiveProcess failed ({}), continuing without crash dumps", | ||
| 100 | GetLastError()); | ||
| 101 | return false; | ||
| 102 | } | ||
| 103 | |||
| 104 | return true; | ||
| 105 | } | ||
| 106 | |||
| 107 | static const char* ExceptionName(DWORD exception) { | ||
| 108 | switch (exception) { | ||
| 109 | case EXCEPTION_ACCESS_VIOLATION: | ||
| 110 | return "EXCEPTION_ACCESS_VIOLATION"; | ||
| 111 | case EXCEPTION_DATATYPE_MISALIGNMENT: | ||
| 112 | return "EXCEPTION_DATATYPE_MISALIGNMENT"; | ||
| 113 | case EXCEPTION_BREAKPOINT: | ||
| 114 | return "EXCEPTION_BREAKPOINT"; | ||
| 115 | case EXCEPTION_SINGLE_STEP: | ||
| 116 | return "EXCEPTION_SINGLE_STEP"; | ||
| 117 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||
| 118 | return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; | ||
| 119 | case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
| 120 | return "EXCEPTION_FLT_DENORMAL_OPERAND"; | ||
| 121 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
| 122 | return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; | ||
| 123 | case EXCEPTION_FLT_INEXACT_RESULT: | ||
| 124 | return "EXCEPTION_FLT_INEXACT_RESULT"; | ||
| 125 | case EXCEPTION_FLT_INVALID_OPERATION: | ||
| 126 | return "EXCEPTION_FLT_INVALID_OPERATION"; | ||
| 127 | case EXCEPTION_FLT_OVERFLOW: | ||
| 128 | return "EXCEPTION_FLT_OVERFLOW"; | ||
| 129 | case EXCEPTION_FLT_STACK_CHECK: | ||
| 130 | return "EXCEPTION_FLT_STACK_CHECK"; | ||
| 131 | case EXCEPTION_FLT_UNDERFLOW: | ||
| 132 | return "EXCEPTION_FLT_UNDERFLOW"; | ||
| 133 | case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||
| 134 | return "EXCEPTION_INT_DIVIDE_BY_ZERO"; | ||
| 135 | case EXCEPTION_INT_OVERFLOW: | ||
| 136 | return "EXCEPTION_INT_OVERFLOW"; | ||
| 137 | case EXCEPTION_PRIV_INSTRUCTION: | ||
| 138 | return "EXCEPTION_PRIV_INSTRUCTION"; | ||
| 139 | case EXCEPTION_IN_PAGE_ERROR: | ||
| 140 | return "EXCEPTION_IN_PAGE_ERROR"; | ||
| 141 | case EXCEPTION_ILLEGAL_INSTRUCTION: | ||
| 142 | return "EXCEPTION_ILLEGAL_INSTRUCTION"; | ||
| 143 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: | ||
| 144 | return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; | ||
| 145 | case EXCEPTION_STACK_OVERFLOW: | ||
| 146 | return "EXCEPTION_STACK_OVERFLOW"; | ||
| 147 | case EXCEPTION_INVALID_DISPOSITION: | ||
| 148 | return "EXCEPTION_INVALID_DISPOSITION"; | ||
| 149 | case EXCEPTION_GUARD_PAGE: | ||
| 150 | return "EXCEPTION_GUARD_PAGE"; | ||
| 151 | case EXCEPTION_INVALID_HANDLE: | ||
| 152 | return "EXCEPTION_INVALID_HANDLE"; | ||
| 153 | default: | ||
| 154 | return "unknown exception type"; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | void DebugDebuggee(PROCESS_INFORMATION& pi) { | ||
| 159 | DEBUG_EVENT deb_ev = {}; | ||
| 160 | |||
| 161 | while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) { | ||
| 162 | const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE); | ||
| 163 | if (!wait_success) { | ||
| 164 | fmt::print(stderr, "error: WaitForDebugEvent failed ({})", GetLastError()); | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | |||
| 168 | switch (deb_ev.dwDebugEventCode) { | ||
| 169 | case OUTPUT_DEBUG_STRING_EVENT: | ||
| 170 | case CREATE_PROCESS_DEBUG_EVENT: | ||
| 171 | case CREATE_THREAD_DEBUG_EVENT: | ||
| 172 | case EXIT_PROCESS_DEBUG_EVENT: | ||
| 173 | case EXIT_THREAD_DEBUG_EVENT: | ||
| 174 | case LOAD_DLL_DEBUG_EVENT: | ||
| 175 | case RIP_EVENT: | ||
| 176 | case UNLOAD_DLL_DEBUG_EVENT: | ||
| 177 | // Continue on all other debug events | ||
| 178 | ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE); | ||
| 179 | break; | ||
| 180 | case EXCEPTION_DEBUG_EVENT: | ||
| 181 | EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord; | ||
| 182 | |||
| 183 | // We want to generate a crash dump if we are seeing the same exception again. | ||
| 184 | if (!deb_ev.u.Exception.dwFirstChance) { | ||
| 185 | fmt::print(stderr, "Creating MiniDump on ExceptionCode: 0x{:08x} {}\n", | ||
| 186 | record.ExceptionCode, ExceptionName(record.ExceptionCode)); | ||
| 187 | DumpFromDebugEvent(deb_ev, pi); | ||
| 188 | } | ||
| 189 | |||
| 190 | // Continue without handling the exception. | ||
| 191 | // Lets the debuggee use its own exception handler. | ||
| 192 | // - If one does not exist, we will see the exception once more where we make a minidump | ||
| 193 | // for. Then when it reaches here again, yuzu will probably crash. | ||
| 194 | // - DBG_CONTINUE on an exception that the debuggee does not handle can set us up for an | ||
| 195 | // infinite loop of exceptions. | ||
| 196 | ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | } // namespace MiniDump | ||
diff --git a/src/yuzu/mini_dump.h b/src/yuzu/mini_dump.h deleted file mode 100644 index d6b6cca84..000000000 --- a/src/yuzu/mini_dump.h +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <windows.h> | ||
| 7 | |||
| 8 | #include <dbghelp.h> | ||
| 9 | |||
| 10 | namespace MiniDump { | ||
| 11 | |||
| 12 | void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, | ||
| 13 | EXCEPTION_POINTERS* pep); | ||
| 14 | |||
| 15 | void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi); | ||
| 16 | bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi); | ||
| 17 | void DebugDebuggee(PROCESS_INFORMATION& pi); | ||
| 18 | |||
| 19 | } // namespace MiniDump | ||
diff --git a/vcpkg.json b/vcpkg.json index 203fc9708..da4e9edb9 100644 --- a/vcpkg.json +++ b/vcpkg.json | |||
| @@ -33,10 +33,6 @@ | |||
| 33 | "description": "Compile tests", | 33 | "description": "Compile tests", |
| 34 | "dependencies": [ "catch2" ] | 34 | "dependencies": [ "catch2" ] |
| 35 | }, | 35 | }, |
| 36 | "dbghelp": { | ||
| 37 | "description": "Compile Windows crash dump (Minidump) support", | ||
| 38 | "dependencies": [ "dbghelp" ] | ||
| 39 | }, | ||
| 40 | "web-service": { | 36 | "web-service": { |
| 41 | "description": "Enable web services (telemetry, etc.)", | 37 | "description": "Enable web services (telemetry, etc.)", |
| 42 | "dependencies": [ | 38 | "dependencies": [ |