1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-12-23 18:56:03 +00:00

kern: use variable-count parameter arrays for DebugEvents

This commit is contained in:
Michael Scire 2023-02-21 09:16:15 -07:00 committed by SciresM
parent db510f96c3
commit 8db22967bf
7 changed files with 125 additions and 98 deletions

View file

@ -74,7 +74,7 @@ namespace ams::kern {
return m_process_holder.Get(); return m_process_holder.Get();
} }
private: private:
void PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0); void PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
void EnqueueDebugEventInfo(KEventInfo *info); void EnqueueDebugEventInfo(KEventInfo *info);
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>) template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
@ -85,13 +85,13 @@ namespace ams::kern {
/* NOTE: This is public/virtual override in Nintendo's kernel. */ /* NOTE: This is public/virtual override in Nintendo's kernel. */
void OnFinalizeSynchronizationObject(); void OnFinalizeSynchronizationObject();
private: private:
static Result ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4); static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
public: public:
static Result OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0); static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
static Result OnExitProcess(KProcess *process); static Result OnExitProcess(KProcess *process);
static Result OnTerminateProcess(KProcess *process); static Result OnTerminateProcess(KProcess *process);
static Result OnExitThread(KThread *thread); static Result OnExitThread(KThread *thread);
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 thread_id); static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params);
}; };
} }

View file

@ -38,7 +38,7 @@ namespace ams::kern {
ams::svc::DebugException exception_type; ams::svc::DebugException exception_type;
s32 exception_data_count; s32 exception_data_count;
uintptr_t exception_address; uintptr_t exception_address;
uintptr_t exception_data[4]; uintptr_t exception_data[std::max<size_t>(4, cpu::NumCores)];
}; };
struct InfoSystemCall { struct InfoSystemCall {

View file

@ -229,73 +229,71 @@ namespace ams::kern::arch::arm64 {
{ {
/* Collect additional information based on the ec. */ /* Collect additional information based on the ec. */
ams::svc::DebugException exception; uintptr_t params[3] = {};
uintptr_t param2 = 0;
uintptr_t param3 = 0;
switch (ec) { switch (ec) {
case EsrEc_Unknown: case EsrEc_Unknown:
case EsrEc_IllegalExecution: case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
{ {
exception = ams::svc::DebugException_UndefinedInstruction; params[0] = ams::svc::DebugException_UndefinedInstruction;
param2 = far; params[1] = far;
param3 = data; params[2] = data;
} }
break; break;
case EsrEc_PcAlignmentFault: case EsrEc_PcAlignmentFault:
case EsrEc_SpAlignmentFault: case EsrEc_SpAlignmentFault:
{ {
exception = ams::svc::DebugException_AlignmentFault; params[0] = ams::svc::DebugException_AlignmentFault;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_Svc32: case EsrEc_Svc32:
case EsrEc_Svc64: case EsrEc_Svc64:
{ {
exception = ams::svc::DebugException_UndefinedSystemCall; params[0] = ams::svc::DebugException_UndefinedSystemCall;
param2 = far; params[1] = far;
param3 = (esr & 0xFF); params[2] = (esr & 0xFF);
} }
break; break;
case EsrEc_BreakPointEl0: case EsrEc_BreakPointEl0:
case EsrEc_SoftwareStepEl0: case EsrEc_SoftwareStepEl0:
{ {
exception = ams::svc::DebugException_BreakPoint; params[0] = ams::svc::DebugException_BreakPoint;
param2 = far; params[1] = far;
param3 = ams::svc::BreakPointType_HardwareInstruction; params[2] = ams::svc::BreakPointType_HardwareInstruction;
} }
break; break;
case EsrEc_WatchPointEl0: case EsrEc_WatchPointEl0:
{ {
exception = ams::svc::DebugException_BreakPoint; params[0] = ams::svc::DebugException_BreakPoint;
param2 = far; params[1] = far;
param3 = ams::svc::BreakPointType_HardwareData; params[2] = ams::svc::BreakPointType_HardwareData;
} }
break; break;
case EsrEc_SErrorInterrupt: case EsrEc_SErrorInterrupt:
{ {
exception = ams::svc::DebugException_MemorySystemError; params[0] = ams::svc::DebugException_MemorySystemError;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_InstructionAbortEl0: case EsrEc_InstructionAbortEl0:
{ {
exception = ams::svc::DebugException_InstructionAbort; params[0] = ams::svc::DebugException_InstructionAbort;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_DataAbortEl0: case EsrEc_DataAbortEl0:
default: default:
{ {
exception = ams::svc::DebugException_DataAbort; params[0] = ams::svc::DebugException_DataAbort;
param2 = far; params[1] = far;
} }
break; break;
} }
/* Process the debug event. */ /* Process the debug event. */
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3); Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* If we should stop processing the exception, do so. */ /* If we should stop processing the exception, do so. */
if (svc::ResultStopProcessingException::Includes(result)) { if (svc::ResultStopProcessingException::Includes(result)) {
@ -340,7 +338,7 @@ namespace ams::kern::arch::arm64 {
/* If the SVC is handled, handle it. */ /* If the SVC is handled, handle it. */
if (!svc::ResultNotHandled::Includes(result)) { if (!svc::ResultNotHandled::Includes(result)) {
/* If we successfully enter jit debug, stop processing the exception. */ /* If we successfully enter jit debug, stop processing the exception. */
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) { if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
return; return;
} }
} }
@ -420,58 +418,56 @@ namespace ams::kern::arch::arm64 {
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data)); GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
/* Collect additional information based on the ec. */ /* Collect additional information based on the ec. */
ams::svc::DebugException exception; uintptr_t params[3] = {};
uintptr_t param2 = 0;
uintptr_t param3 = 0;
switch ((esr >> 26) & 0x3F) { switch ((esr >> 26) & 0x3F) {
case EsrEc_Unknown: case EsrEc_Unknown:
case EsrEc_IllegalExecution: case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
{ {
exception = ams::svc::DebugException_UndefinedInstruction; params[0] = ams::svc::DebugException_UndefinedInstruction;
param2 = far; params[1] = far;
param3 = data; params[2] = data;
} }
break; break;
case EsrEc_PcAlignmentFault: case EsrEc_PcAlignmentFault:
case EsrEc_SpAlignmentFault: case EsrEc_SpAlignmentFault:
{ {
exception = ams::svc::DebugException_AlignmentFault; params[0] = ams::svc::DebugException_AlignmentFault;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_Svc32: case EsrEc_Svc32:
case EsrEc_Svc64: case EsrEc_Svc64:
{ {
exception = ams::svc::DebugException_UndefinedSystemCall; params[0] = ams::svc::DebugException_UndefinedSystemCall;
param2 = far; params[1] = far;
param3 = (esr & 0xFF); params[2] = (esr & 0xFF);
} }
break; break;
case EsrEc_SErrorInterrupt: case EsrEc_SErrorInterrupt:
{ {
exception = ams::svc::DebugException_MemorySystemError; params[0] = ams::svc::DebugException_MemorySystemError;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_InstructionAbortEl0: case EsrEc_InstructionAbortEl0:
{ {
exception = ams::svc::DebugException_InstructionAbort; params[0] = ams::svc::DebugException_InstructionAbort;
param2 = far; params[1] = far;
} }
break; break;
case EsrEc_DataAbortEl0: case EsrEc_DataAbortEl0:
default: default:
{ {
exception = ams::svc::DebugException_DataAbort; params[0] = ams::svc::DebugException_DataAbort;
param2 = far; params[1] = far;
} }
break; break;
} }
/* Process the debug event. */ /* Process the debug event. */
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3); Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* If the SVC is handled, handle it. */ /* If the SVC is handled, handle it. */
if (!svc::ResultNotHandled::Includes(result)) { if (!svc::ResultNotHandled::Includes(result)) {
@ -481,7 +477,7 @@ namespace ams::kern::arch::arm64 {
} }
/* If we successfully enter jit debug, restore. */ /* If we successfully enter jit debug, restore. */
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) { if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx)); svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
} }
} }

View file

@ -249,7 +249,8 @@ namespace ams::kern::arch::arm64 {
} }
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) { Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size)); const uintptr_t params[5] = { ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size };
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)));
} }
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \ #define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \

View file

@ -26,7 +26,9 @@ namespace ams::kern::arch::arm64 {
/* Send KDebug event for this thread's creation. */ /* Send KDebug event for this thread's creation. */
{ {
KScopedInterruptEnable ei; KScopedInterruptEnable ei;
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()));
const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) };
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
} }
/* Handle any pending dpc. */ /* Handle any pending dpc. */

View file

@ -289,7 +289,7 @@ namespace ams::kern {
m_old_process_state = target->SetDebugObject(this); m_old_process_state = target->SetDebugObject(this);
/* Send an event for our attaching to the process. */ /* Send an event for our attaching to the process. */
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess); this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess, nullptr, 0);
/* Send events for attaching to each thread in the process. */ /* Send events for attaching to each thread in the process. */
{ {
@ -304,7 +304,8 @@ namespace ams::kern {
it->SetDebugAttached(); it->SetDebugAttached();
/* Send the event. */ /* Send the event. */
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, it->GetId(), GetInteger(it->GetThreadLocalRegionAddress())); const uintptr_t params[2] = { it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()) };
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
} }
} }
} }
@ -315,7 +316,8 @@ namespace ams::kern {
} }
/* Send an exception event to represent our attaching. */ /* Send an exception event to represent our attaching. */
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerAttached); const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerAttached) };
this->PushDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* Signal. */ /* Signal. */
this->NotifyAvailable(); this->NotifyAvailable();
@ -353,22 +355,22 @@ namespace ams::kern {
/* Get the currently active threads. */ /* Get the currently active threads. */
constexpr u64 ThreadIdNoThread = -1ll; constexpr u64 ThreadIdNoThread = -1ll;
constexpr u64 ThreadIdUnknownThread = -2ll; constexpr u64 ThreadIdUnknownThread = -2ll;
u64 thread_ids[cpu::NumCores]; uintptr_t debug_info_params[1 + cpu::NumCores] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerBreak), };
for (size_t i = 0; i < util::size(thread_ids); ++i) { for (size_t i = 0; i < cpu::NumCores; ++i) {
/* Get the currently running thread. */ /* Get the currently running thread. */
KThread *thread = target->GetRunningThread(i); KThread *thread = target->GetRunningThread(i);
/* Check that the thread's idle count is correct. */ /* Check that the thread's idle count is correct. */
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) { if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) { if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
thread_ids[i] = thread->GetId(); debug_info_params[1 + i] = thread->GetId();
} else { } else {
/* We found an unknown thread. */ /* We found an unknown thread. */
thread_ids[i] = ThreadIdUnknownThread; debug_info_params[1 + i] = ThreadIdUnknownThread;
} }
} else { } else {
/* We didn't find a thread. */ /* We didn't find a thread. */
thread_ids[i] = ThreadIdNoThread; debug_info_params[1 + i] = ThreadIdNoThread;
} }
} }
@ -382,11 +384,7 @@ namespace ams::kern {
} }
/* Send an exception event to represent our breaking the process. */ /* Send an exception event to represent our breaking the process. */
/* TODO: How should this be handled in the case of more than 4 physical cores? */ this->PushDebugEvent(ams::svc::DebugEvent_Exception, debug_info_params, util::size(debug_info_params));
static_assert(util::size(thread_ids) <= 4);
[&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerBreak, thread_ids[Ix]...);
}(std::make_index_sequence<util::size(thread_ids)>());
/* Signal. */ /* Signal. */
this->NotifyAvailable(); this->NotifyAvailable();
@ -734,7 +732,7 @@ namespace ams::kern {
R_SUCCEED(); R_SUCCEED();
} }
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 cur_thread_id) { KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, u64 cur_thread_id, const uintptr_t *params, size_t num_params) {
/* Allocate a new event. */ /* Allocate a new event. */
KEventInfo *info = KEventInfo::Allocate(); KEventInfo *info = KEventInfo::Allocate();
@ -749,23 +747,33 @@ namespace ams::kern {
switch (event) { switch (event) {
case ams::svc::DebugEvent_CreateProcess: case ams::svc::DebugEvent_CreateProcess:
{ {
/* ... */ /* Check parameters. */
MESOSPHERE_ASSERT(params == nullptr);
MESOSPHERE_ASSERT(num_params == 0);
} }
break; break;
case ams::svc::DebugEvent_CreateThread: case ams::svc::DebugEvent_CreateThread:
{ {
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 2);
/* Set the thread id. */ /* Set the thread id. */
info->thread_id = param0; info->thread_id = params[0];
/* Set the thread creation info. */ /* Set the thread creation info. */
info->info.create_thread.thread_id = param0; info->info.create_thread.thread_id = params[0];
info->info.create_thread.tls_address = param1; info->info.create_thread.tls_address = params[1];
} }
break; break;
case ams::svc::DebugEvent_ExitProcess: case ams::svc::DebugEvent_ExitProcess:
{ {
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 1);
/* Set the exit reason. */ /* Set the exit reason. */
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(param0); info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(params[0]);
/* Clear the thread id and flags. */ /* Clear the thread id and flags. */
info->thread_id = 0; info->thread_id = 0;
@ -774,30 +782,40 @@ namespace ams::kern {
break; break;
case ams::svc::DebugEvent_ExitThread: case ams::svc::DebugEvent_ExitThread:
{ {
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 2);
/* Set the thread id. */ /* Set the thread id. */
info->thread_id = param0; info->thread_id = params[0];
/* Set the exit reason. */ /* Set the exit reason. */
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(param1); info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(params[1]);
} }
break; break;
case ams::svc::DebugEvent_Exception: case ams::svc::DebugEvent_Exception:
{ {
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params >= 1);
/* Set the thread id. */ /* Set the thread id. */
info->thread_id = cur_thread_id; info->thread_id = cur_thread_id;
/* Set the exception type, and clear the count. */ /* Set the exception type, and clear the count. */
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(param0); info->info.exception.exception_type = static_cast<ams::svc::DebugException>(params[0]);
info->info.exception.exception_data_count = 0; info->info.exception.exception_data_count = 0;
switch (static_cast<ams::svc::DebugException>(param0)) { switch (static_cast<ams::svc::DebugException>(params[0])) {
case ams::svc::DebugException_UndefinedInstruction: case ams::svc::DebugException_UndefinedInstruction:
case ams::svc::DebugException_BreakPoint: case ams::svc::DebugException_BreakPoint:
case ams::svc::DebugException_UndefinedSystemCall: case ams::svc::DebugException_UndefinedSystemCall:
{ {
info->info.exception.exception_address = param1; MESOSPHERE_ASSERT(num_params >= 3);
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1; info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = param2; info->info.exception.exception_data[0] = params[2];
} }
break; break;
case ams::svc::DebugException_DebuggerAttached: case ams::svc::DebugException_DebuggerAttached:
@ -809,12 +827,14 @@ namespace ams::kern {
break; break;
case ams::svc::DebugException_UserBreak: case ams::svc::DebugException_UserBreak:
{ {
info->info.exception.exception_address = param1; MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_data_count = 3; info->info.exception.exception_address = params[1];
info->info.exception.exception_data[0] = param2;
info->info.exception.exception_data[1] = param3; info->info.exception.exception_data_count = 0;
info->info.exception.exception_data[2] = param4; for (size_t i = 2; i < num_params; ++i) {
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
}
} }
break; break;
case ams::svc::DebugException_DebuggerBreak: case ams::svc::DebugException_DebuggerBreak:
@ -823,11 +843,10 @@ namespace ams::kern {
info->info.exception.exception_address = 0; info->info.exception.exception_address = 0;
info->info.exception.exception_data_count = 4; info->info.exception.exception_data_count = 0;
info->info.exception.exception_data[0] = param1; for (size_t i = 1; i < num_params; ++i) {
info->info.exception.exception_data[1] = param2; info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
info->info.exception.exception_data[2] = param3; }
info->info.exception.exception_data[3] = param4;
} }
break; break;
case ams::svc::DebugException_MemorySystemError: case ams::svc::DebugException_MemorySystemError:
@ -840,7 +859,9 @@ namespace ams::kern {
case ams::svc::DebugException_AlignmentFault: case ams::svc::DebugException_AlignmentFault:
default: default:
{ {
info->info.exception.exception_address = param1; MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
} }
break; break;
} }
@ -852,9 +873,9 @@ namespace ams::kern {
return info; return info;
} }
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) { void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
/* Create and enqueue and event. */ /* Create and enqueue and event. */
if (KEventInfo *new_info = CreateDebugEvent(event, param0, param1, param2, param3, param4, GetCurrentThread().GetId()); new_info != nullptr) { if (KEventInfo *new_info = CreateDebugEvent(event, GetCurrentThread().GetId(), params, num_params); new_info != nullptr) {
this->EnqueueDebugEventInfo(new_info); this->EnqueueDebugEventInfo(new_info);
} }
} }
@ -961,7 +982,10 @@ namespace ams::kern {
break; break;
case ams::svc::DebugException_DebuggerBreak: case ams::svc::DebugException_DebuggerBreak:
{ {
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 4); /* TODO: How does this work with non-4 cpu count? */
static_assert(cpu::NumCores <= 4);
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == cpu::NumCores);
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0]; out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1]; out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2]; out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
@ -1075,7 +1099,7 @@ namespace ams::kern {
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated(); return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
} }
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) { Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
/* Get the current process. */ /* Get the current process. */
KProcess *process = GetCurrentProcessPointer(); KProcess *process = GetCurrentProcessPointer();
@ -1117,7 +1141,7 @@ namespace ams::kern {
} }
/* Push the event. */ /* Push the event. */
debug->PushDebugEvent(event, param0, param1, param2, param3, param4); debug->PushDebugEvent(event, params, num_params);
debug->NotifyAvailable(); debug->NotifyAvailable();
/* Set the process as breaked. */ /* Set the process as breaked. */
@ -1153,9 +1177,9 @@ namespace ams::kern {
R_SUCCEED(); R_SUCCEED();
} }
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) { Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) { if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
R_RETURN(ProcessDebugEvent(event, param0, param1, param2, param3, param4)); R_RETURN(ProcessDebugEvent(event, params, num_params));
} }
R_SUCCEED(); R_SUCCEED();
} }
@ -1170,7 +1194,8 @@ namespace ams::kern {
/* Push the event. */ /* Push the event. */
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) { if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_ExitProcess); const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_ExitProcess) };
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
debug->NotifyAvailable(); debug->NotifyAvailable();
} }
} }
@ -1188,7 +1213,8 @@ namespace ams::kern {
/* Push the event. */ /* Push the event. */
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) { if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_TerminateProcess); const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_TerminateProcess) };
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
debug->NotifyAvailable(); debug->NotifyAvailable();
} }
} }
@ -1202,7 +1228,8 @@ namespace ams::kern {
/* Check if we're attached to a debugger. */ /* Check if we're attached to a debugger. */
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
/* If we are, submit the event. */ /* If we are, submit the event. */
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, thread->GetId(), thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread)); const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) };
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
} }
R_SUCCEED(); R_SUCCEED();

View file

@ -1242,7 +1242,8 @@ namespace ams::kern {
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
if (m_is_jit_debug) { if (m_is_jit_debug) {
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3], m_jit_debug_thread_id); const uintptr_t params[5] = { m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3] };
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_thread_id, params, util::size(params));
} else { } else {
return nullptr; return nullptr;
} }