kern: SvcBreakDebugProcess, SvcTerminateDebugProcess

This commit is contained in:
Michael Scire 2020-07-30 22:18:19 -07:00 committed by SciresM
parent b88e09de5b
commit 4c3c910774
3 changed files with 152 additions and 4 deletions

View file

@ -38,6 +38,8 @@ namespace ams::kern {
void Initialize();
Result Attach(KProcess *process);
Result BreakProcess();
Result TerminateProcess();
Result ContinueDebug(const u32 flags, const u64 *thread_ids, size_t num_thread_ids);

View file

@ -341,6 +341,124 @@ namespace ams::kern {
return ResultSuccess();
}
Result KDebugBase::BreakProcess() {
/* Get the attached process. */
KScopedAutoObject target = this->GetProcess();
R_UNLESS(target.IsNotNull(), svc::ResultProcessTerminated());
/* Lock both ourselves, the target process, and the scheduler. */
KScopedLightLock state_lk(target->GetStateLock());
KScopedLightLock list_lk(target->GetListLock());
KScopedLightLock this_lk(this->lock);
KScopedSchedulerLock sl;
/* Check that we're still attached to the process, and that it's not terminated. */
/* NOTE: Here Nintendo only checks that this->process is not nullptr. */
R_UNLESS(this->process == target.GetPointerUnsafe(), svc::ResultProcessTerminated());
R_UNLESS(!target->IsTerminated(), svc::ResultProcessTerminated());
/* Get the currently active threads. */
constexpr u64 ThreadIdNoThread = -1ll;
constexpr u64 ThreadIdUnknownThread = -2ll;
u64 thread_ids[cpu::NumCores];
for (size_t i = 0; i < util::size(thread_ids); ++i) {
/* Get the currently running thread. */
KThread *thread = target->GetRunningThread(i);
/* Check that the thread's idle count is correct. */
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
thread_ids[i] = thread->GetId();
} else {
/* We found an unknown thread. */
thread_ids[i] = ThreadIdUnknownThread;
}
} else {
/* We didn't find a thread. */
thread_ids[i] = ThreadIdNoThread;
}
}
/* Suspend all the threads in the process. */
{
auto end = target->GetThreadList().end();
for (auto it = target->GetThreadList().begin(); it != end; ++it) {
/* Request that we suspend the thread. */
it->RequestSuspend(KThread::SuspendType_Debug);
}
}
/* Send an exception event to represent our breaking the process. */
static_assert(util::size(thread_ids) >= 4);
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerBreak, thread_ids[0], thread_ids[1], thread_ids[2], thread_ids[3]);
/* Signal. */
this->NotifyAvailable();
/* Set the process as breaked. */
target->SetDebugBreak();
return ResultSuccess();
}
Result KDebugBase::TerminateProcess() {
/* Get the attached process. If we don't have one, we have nothing to do. */
KScopedAutoObject target = this->GetProcess();
R_SUCCEED_IF(target.IsNull());
/* Detach from the process. */
{
/* Lock both ourselves and the target process. */
KScopedLightLock state_lk(target->GetStateLock());
KScopedLightLock list_lk(target->GetListLock());
KScopedLightLock this_lk(this->lock);
/* Check that we still have our process. */
if (this->process != nullptr) {
/* Check that our process is the one we got earlier. */
MESOSPHERE_ASSERT(this->process == target.GetPointerUnsafe());
/* Lock the scheduler. */
KScopedSchedulerLock sl;
/* Get the process's state. */
const KProcess::State state = target->GetState();
/* Check that the process is in a state where we can terminate it. */
R_UNLESS(state != KProcess::State_Created, svc::ResultInvalidState());
R_UNLESS(state != KProcess::State_CreatedAttached, svc::ResultInvalidState());
/* Decide on a new state for the process. */
KProcess::State new_state;
if (state == KProcess::State_RunningAttached) {
/* If the process is running, transition it accordingly. */
new_state = KProcess::State_Running;
} else if (state == KProcess::State_DebugBreak) {
/* If the process is debug breaked, transition it accordingly. */
new_state = KProcess::State_Crashed;
} else {
/* Otherwise, don't transition. */
new_state = state;
}
/* Detach from the process. */
target->ClearDebugObject(new_state);
this->process = nullptr;
/* Clear our continue flags. */
this->continue_flags = 0;
}
}
/* Close the reference we held to the process while we were attached to it. */
target->Close();
/* Terminate the process. */
target->Terminate();
return ResultSuccess();
}
Result KDebugBase::ContinueDebug(const u32 flags, const u64 *thread_ids, size_t num_thread_ids) {
/* Get the attached process. */
KScopedAutoObject target = this->GetProcess();

View file

@ -62,6 +62,34 @@ namespace ams::kern::svc {
return ResultSuccess();
}
Result BreakDebugProcess(ams::svc::Handle debug_handle) {
/* Only allow invoking the svc on development hardware. */
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
/* Get the debug object. */
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
/* Break the process. */
R_TRY(debug->BreakProcess());
return ResultSuccess();
}
Result TerminateDebugProcess(ams::svc::Handle debug_handle) {
/* Only allow invoking the svc on development hardware. */
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
/* Get the debug object. */
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
/* Terminate the process. */
R_TRY(debug->TerminateProcess());
return ResultSuccess();
}
template<typename EventInfoType>
Result GetDebugEvent(KUserPointer<EventInfoType *> out_info, ams::svc::Handle debug_handle) {
/* Get the debug object. */
@ -227,11 +255,11 @@ namespace ams::kern::svc {
}
Result BreakDebugProcess64(ams::svc::Handle debug_handle) {
MESOSPHERE_PANIC("Stubbed SvcBreakDebugProcess64 was called.");
return BreakDebugProcess(debug_handle);
}
Result TerminateDebugProcess64(ams::svc::Handle debug_handle) {
MESOSPHERE_PANIC("Stubbed SvcTerminateDebugProcess64 was called.");
return TerminateDebugProcess(debug_handle);
}
Result GetDebugEvent64(KUserPointer<ams::svc::lp64::DebugEventInfo *> out_info, ams::svc::Handle debug_handle) {
@ -281,11 +309,11 @@ namespace ams::kern::svc {
}
Result BreakDebugProcess64From32(ams::svc::Handle debug_handle) {
MESOSPHERE_PANIC("Stubbed SvcBreakDebugProcess64From32 was called.");
return BreakDebugProcess(debug_handle);
}
Result TerminateDebugProcess64From32(ams::svc::Handle debug_handle) {
MESOSPHERE_PANIC("Stubbed SvcTerminateDebugProcess64From32 was called.");
return TerminateDebugProcess(debug_handle);
}
Result GetDebugEvent64From32(KUserPointer<ams::svc::ilp32::DebugEventInfo *> out_info, ams::svc::Handle debug_handle) {