svc_exception.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/core.h"
  4. #include "core/debugger/debugger.h"
  5. #include "core/hle/kernel/k_thread.h"
  6. #include "core/hle/kernel/svc.h"
  7. #include "core/hle/kernel/svc_types.h"
  8. #include "core/memory.h"
  9. #include "core/reporter.h"
  10. namespace Kernel::Svc {
  11. /// Break program execution
  12. void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
  13. BreakReason break_reason =
  14. reason & static_cast<BreakReason>(~BreakReason::NotificationOnlyFlag);
  15. bool notification_only = True(reason & BreakReason::NotificationOnlyFlag);
  16. bool has_dumped_buffer{};
  17. std::vector<u8> debug_buffer;
  18. const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
  19. if (sz == 0 || addr == 0 || has_dumped_buffer) {
  20. return;
  21. }
  22. auto& memory = system.Memory();
  23. // This typically is an error code so we're going to assume this is the case
  24. if (sz == sizeof(u32)) {
  25. LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
  26. } else {
  27. // We don't know what's in here so we'll hexdump it
  28. debug_buffer.resize(sz);
  29. memory.ReadBlock(addr, debug_buffer.data(), sz);
  30. std::string hexdump;
  31. for (std::size_t i = 0; i < debug_buffer.size(); i++) {
  32. hexdump += fmt::format("{:02X} ", debug_buffer[i]);
  33. if (i != 0 && i % 16 == 0) {
  34. hexdump += '\n';
  35. }
  36. }
  37. LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
  38. }
  39. has_dumped_buffer = true;
  40. };
  41. switch (break_reason) {
  42. case BreakReason::Panic:
  43. LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
  44. info2);
  45. handle_debug_buffer(info1, info2);
  46. break;
  47. case BreakReason::Assert:
  48. LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
  49. info1, info2);
  50. handle_debug_buffer(info1, info2);
  51. break;
  52. case BreakReason::User:
  53. LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
  54. handle_debug_buffer(info1, info2);
  55. break;
  56. case BreakReason::PreLoadDll:
  57. LOG_INFO(Debug_Emulated,
  58. "Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
  59. info2);
  60. break;
  61. case BreakReason::PostLoadDll:
  62. LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
  63. info2);
  64. break;
  65. case BreakReason::PreUnloadDll:
  66. LOG_INFO(Debug_Emulated,
  67. "Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
  68. info2);
  69. break;
  70. case BreakReason::PostUnloadDll:
  71. LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
  72. info1, info2);
  73. break;
  74. case BreakReason::CppException:
  75. LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
  76. break;
  77. default:
  78. LOG_WARNING(
  79. Debug_Emulated,
  80. "Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
  81. reason, info1, info2);
  82. handle_debug_buffer(info1, info2);
  83. break;
  84. }
  85. system.GetReporter().SaveSvcBreakReport(
  86. static_cast<u32>(reason), notification_only, info1, info2,
  87. has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
  88. if (!notification_only) {
  89. LOG_CRITICAL(
  90. Debug_Emulated,
  91. "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
  92. reason, info1, info2);
  93. handle_debug_buffer(info1, info2);
  94. auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
  95. const auto thread_processor_id = current_thread->GetActiveCore();
  96. system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
  97. }
  98. if (system.DebuggerEnabled()) {
  99. auto* thread = system.Kernel().GetCurrentEmuThread();
  100. system.GetDebugger().NotifyThreadStopped(thread);
  101. thread->RequestSuspend(Kernel::SuspendType::Debug);
  102. }
  103. }
  104. void ReturnFromException(Core::System& system, Result result) {
  105. UNIMPLEMENTED();
  106. }
  107. void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size) {
  108. Break(system, break_reason, arg, size);
  109. }
  110. void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size) {
  111. Break(system, break_reason, arg, size);
  112. }
  113. void ReturnFromException64(Core::System& system, Result result) {
  114. ReturnFromException(system, result);
  115. }
  116. void ReturnFromException64From32(Core::System& system, Result result) {
  117. ReturnFromException(system, result);
  118. }
  119. } // namespace Kernel::Svc