mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
kern: use variable-count parameter arrays for DebugEvents
This commit is contained in:
parent
db510f96c3
commit
8db22967bf
7 changed files with 125 additions and 98 deletions
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue