fatal.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <cstring>
  6. #include <ctime>
  7. #include <fmt/chrono.h>
  8. #include "common/file_util.h"
  9. #include "common/logging/log.h"
  10. #include "common/scm_rev.h"
  11. #include "common/swap.h"
  12. #include "core/core.h"
  13. #include "core/hle/ipc_helpers.h"
  14. #include "core/hle/kernel/process.h"
  15. #include "core/hle/service/fatal/fatal.h"
  16. #include "core/hle/service/fatal/fatal_p.h"
  17. #include "core/hle/service/fatal/fatal_u.h"
  18. #include "core/reporter.h"
  19. namespace Service::Fatal {
  20. Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
  21. const char* name)
  22. : ServiceFramework{system_, name}, module{std::move(module_)} {}
  23. Module::Interface::~Interface() = default;
  24. struct FatalInfo {
  25. enum class Architecture : s32 {
  26. AArch64,
  27. AArch32,
  28. };
  29. const char* ArchAsString() const {
  30. return arch == Architecture::AArch64 ? "AArch64" : "AArch32";
  31. }
  32. std::array<u64_le, 31> registers{};
  33. u64_le sp{};
  34. u64_le pc{};
  35. u64_le pstate{};
  36. u64_le afsr0{};
  37. u64_le afsr1{};
  38. u64_le esr{};
  39. u64_le far{};
  40. std::array<u64_le, 32> backtrace{};
  41. u64_le program_entry_point{};
  42. // Bit flags that indicate which registers have been set with values
  43. // for this context. The service itself uses these to determine which
  44. // registers to specifically print out.
  45. u64_le set_flags{};
  46. u32_le backtrace_size{};
  47. Architecture arch{};
  48. u32_le unk10{}; // TODO(ogniK): Is this even used or is it just padding?
  49. };
  50. static_assert(sizeof(FatalInfo) == 0x250, "FatalInfo is an invalid size");
  51. enum class FatalType : u32 {
  52. ErrorReportAndScreen = 0,
  53. ErrorReport = 1,
  54. ErrorScreen = 2,
  55. };
  56. static void GenerateErrorReport(Core::System& system, ResultCode error_code,
  57. const FatalInfo& info) {
  58. const auto title_id = system.CurrentProcess()->GetTitleID();
  59. std::string crash_report = fmt::format(
  60. "Yuzu {}-{} crash report\n"
  61. "Title ID: {:016x}\n"
  62. "Result: 0x{:X} ({:04}-{:04d})\n"
  63. "Set flags: 0x{:16X}\n"
  64. "Program entry point: 0x{:16X}\n"
  65. "\n",
  66. Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
  67. 2000 + static_cast<u32>(error_code.module.Value()),
  68. static_cast<u32>(error_code.description.Value()), info.set_flags, info.program_entry_point);
  69. if (info.backtrace_size != 0x0) {
  70. crash_report += "Registers:\n";
  71. for (size_t i = 0; i < info.registers.size(); i++) {
  72. crash_report +=
  73. fmt::format(" X[{:02d}]: {:016x}\n", i, info.registers[i]);
  74. }
  75. crash_report += fmt::format(" SP: {:016x}\n", info.sp);
  76. crash_report += fmt::format(" PC: {:016x}\n", info.pc);
  77. crash_report += fmt::format(" PSTATE: {:016x}\n", info.pstate);
  78. crash_report += fmt::format(" AFSR0: {:016x}\n", info.afsr0);
  79. crash_report += fmt::format(" AFSR1: {:016x}\n", info.afsr1);
  80. crash_report += fmt::format(" ESR: {:016x}\n", info.esr);
  81. crash_report += fmt::format(" FAR: {:016x}\n", info.far);
  82. crash_report += "\nBacktrace:\n";
  83. for (size_t i = 0; i < info.backtrace_size; i++) {
  84. crash_report +=
  85. fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
  86. }
  87. crash_report += fmt::format("Architecture: {}\n", info.ArchAsString());
  88. crash_report += fmt::format("Unknown 10: 0x{:016x}\n", info.unk10);
  89. }
  90. LOG_ERROR(Service_Fatal, "{}", crash_report);
  91. system.GetReporter().SaveCrashReport(
  92. title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc,
  93. info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace,
  94. info.backtrace_size, info.ArchAsString(), info.unk10);
  95. }
  96. static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type,
  97. const FatalInfo& info) {
  98. LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", fatal_type,
  99. error_code.raw);
  100. switch (fatal_type) {
  101. case FatalType::ErrorReportAndScreen:
  102. GenerateErrorReport(system, error_code, info);
  103. [[fallthrough]];
  104. case FatalType::ErrorScreen:
  105. // Since we have no fatal:u error screen. We should just kill execution instead
  106. ASSERT(false);
  107. break;
  108. // Should not throw a fatal screen but should generate an error report
  109. case FatalType::ErrorReport:
  110. GenerateErrorReport(system, error_code, info);
  111. break;
  112. }
  113. }
  114. void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
  115. LOG_ERROR(Service_Fatal, "called");
  116. IPC::RequestParser rp{ctx};
  117. const auto error_code = rp.Pop<ResultCode>();
  118. ThrowFatalError(system, error_code, FatalType::ErrorScreen, {});
  119. IPC::ResponseBuilder rb{ctx, 2};
  120. rb.Push(RESULT_SUCCESS);
  121. }
  122. void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
  123. LOG_ERROR(Service_Fatal, "called");
  124. IPC::RequestParser rp(ctx);
  125. const auto error_code = rp.Pop<ResultCode>();
  126. const auto fatal_type = rp.PopEnum<FatalType>();
  127. ThrowFatalError(system, error_code, fatal_type,
  128. {}); // No info is passed with ThrowFatalWithPolicy
  129. IPC::ResponseBuilder rb{ctx, 2};
  130. rb.Push(RESULT_SUCCESS);
  131. }
  132. void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) {
  133. LOG_ERROR(Service_Fatal, "called");
  134. IPC::RequestParser rp(ctx);
  135. const auto error_code = rp.Pop<ResultCode>();
  136. const auto fatal_type = rp.PopEnum<FatalType>();
  137. const auto fatal_info = ctx.ReadBuffer();
  138. FatalInfo info{};
  139. ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
  140. std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
  141. ThrowFatalError(system, error_code, fatal_type, info);
  142. IPC::ResponseBuilder rb{ctx, 2};
  143. rb.Push(RESULT_SUCCESS);
  144. }
  145. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  146. auto module = std::make_shared<Module>();
  147. std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
  148. std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
  149. }
  150. } // namespace Service::Fatal