breakpad.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <ranges>
  5. #if defined(_WIN32)
  6. #include <client/windows/handler/exception_handler.h>
  7. #elif defined(__linux__)
  8. #include <client/linux/handler/exception_handler.h>
  9. #else
  10. #error Minidump creation not supported on this platform
  11. #endif
  12. #include "common/fs/fs_paths.h"
  13. #include "common/fs/path_util.h"
  14. #include "yuzu/breakpad.h"
  15. namespace Breakpad {
  16. static void PruneDumpDirectory(const std::filesystem::path& dump_path) {
  17. // Code in this function should be exception-safe.
  18. struct Entry {
  19. std::filesystem::path path;
  20. std::filesystem::file_time_type last_write_time;
  21. };
  22. std::vector<Entry> existing_dumps;
  23. // Get existing entries.
  24. std::error_code ec;
  25. std::filesystem::directory_iterator dir(dump_path, ec);
  26. for (auto& entry : dir) {
  27. if (entry.is_regular_file()) {
  28. existing_dumps.push_back(Entry{
  29. .path = entry.path(),
  30. .last_write_time = entry.last_write_time(ec),
  31. });
  32. }
  33. }
  34. // Sort descending by creation date.
  35. std::ranges::stable_sort(existing_dumps, [](const auto& a, const auto& b) {
  36. return a.last_write_time > b.last_write_time;
  37. });
  38. // Delete older dumps.
  39. for (size_t i = 5; i < existing_dumps.size(); i++) {
  40. std::filesystem::remove(existing_dumps[i].path, ec);
  41. }
  42. }
  43. #if defined(__linux__)
  44. [[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context,
  45. bool succeeded) {
  46. // Prevent time- and space-consuming core dumps from being generated, as we have
  47. // already generated a minidump and a core file will not be useful anyway.
  48. _exit(1);
  49. }
  50. #endif
  51. void InstallCrashHandler() {
  52. // Write crash dumps to profile directory.
  53. const auto dump_path = GetYuzuPath(Common::FS::YuzuPath::CrashDumpsDir);
  54. PruneDumpDirectory(dump_path);
  55. #if defined(_WIN32)
  56. // TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API.
  57. static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr,
  58. google_breakpad::ExceptionHandler::HANDLER_ALL};
  59. #elif defined(__linux__)
  60. static google_breakpad::MinidumpDescriptor descriptor{dump_path};
  61. static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback,
  62. nullptr, true, -1};
  63. #endif
  64. }
  65. } // namespace Breakpad