svc_exception.cpp 5.2 KB

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