mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-10 07:06:34 +00:00
kern: add debug thread dump
This commit is contained in:
parent
abd7ad2720
commit
bcc7eed037
8 changed files with 158 additions and 8 deletions
|
@ -54,6 +54,7 @@
|
||||||
#include <mesosphere/kern_kernel.hpp>
|
#include <mesosphere/kern_kernel.hpp>
|
||||||
#include <mesosphere/kern_k_page_table_manager.hpp>
|
#include <mesosphere/kern_k_page_table_manager.hpp>
|
||||||
#include <mesosphere/kern_select_page_table.hpp>
|
#include <mesosphere/kern_select_page_table.hpp>
|
||||||
|
#include <mesosphere/kern_k_dump_object.hpp>
|
||||||
|
|
||||||
/* Miscellaneous objects. */
|
/* Miscellaneous objects. */
|
||||||
#include <mesosphere/kern_k_shared_memory_info.hpp>
|
#include <mesosphere/kern_k_shared_memory_info.hpp>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
|
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
|
||||||
#define MESOSPHERE_ENABLE_ASSERTIONS
|
#define MESOSPHERE_ENABLE_ASSERTIONS
|
||||||
#define MESOSPHERE_ENABLE_DEBUG_PRINT
|
#define MESOSPHERE_ENABLE_DEBUG_PRINT
|
||||||
|
#define MESOSPHERE_ENABLE_KERNEL_STACK_USAGE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define MESOSPHERE_BUILD_FOR_TRACING
|
//#define MESOSPHERE_BUILD_FOR_TRACING
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <mesosphere/kern_common.hpp>
|
||||||
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
|
|
||||||
|
namespace ams::kern::KDumpObject {
|
||||||
|
|
||||||
|
void DumpThread();
|
||||||
|
void DumpThread(u64 thread_id);
|
||||||
|
|
||||||
|
}
|
|
@ -533,6 +533,7 @@ namespace ams::kern {
|
||||||
return this->termination_requested || this->GetRawState() == ThreadState_Terminated;
|
return this->termination_requested || this->GetRawState() == ThreadState_Terminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetKernelStackUsage() const;
|
||||||
public:
|
public:
|
||||||
/* Overridden parent functions. */
|
/* Overridden parent functions. */
|
||||||
virtual u64 GetId() const override final { return this->GetThreadId(); }
|
virtual u64 GetId() const override final { return this->GetThreadId(); }
|
||||||
|
|
80
libraries/libmesosphere/source/kern_k_dump_object.cpp
Normal file
80
libraries/libmesosphere/source/kern_k_dump_object.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <mesosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::kern::KDumpObject {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr const char * const ThreadStates[] = {
|
||||||
|
[KThread::ThreadState_Initialized] = "Initialized",
|
||||||
|
[KThread::ThreadState_Waiting] = "Waiting",
|
||||||
|
[KThread::ThreadState_Runnable] = "Runnable",
|
||||||
|
[KThread::ThreadState_Terminated] = "Terminated",
|
||||||
|
};
|
||||||
|
|
||||||
|
void DumpThread(KThread *thread) {
|
||||||
|
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) {
|
||||||
|
MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n",
|
||||||
|
thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()],
|
||||||
|
thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(),
|
||||||
|
thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask());
|
||||||
|
|
||||||
|
MESOSPHERE_LOG(" State: 0x%04x Suspend: 0x%04x Dpc: 0x%x\n", thread->GetRawState(), thread->GetSuspendFlags(), thread->GetDpc());
|
||||||
|
|
||||||
|
MESOSPHERE_LOG(" TLS: %p (%p)\n", GetVoidPointer(thread->GetThreadLocalRegionAddress()), thread->GetThreadLocalRegionHeapAddress());
|
||||||
|
} else {
|
||||||
|
MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n",
|
||||||
|
thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()],
|
||||||
|
thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(),
|
||||||
|
thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumpThread() {
|
||||||
|
MESOSPHERE_LOG("Dump Thread\n");
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Lock the list. */
|
||||||
|
KThread::ListAccessor accessor;
|
||||||
|
const auto end = accessor.end();
|
||||||
|
|
||||||
|
/* Dump each thread. */
|
||||||
|
for (auto it = accessor.begin(); it != end; ++it) {
|
||||||
|
DumpThread(static_cast<KThread *>(std::addressof(*it)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MESOSPHERE_LOG("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumpThread(u64 thread_id) {
|
||||||
|
MESOSPHERE_LOG("Dump Thread\n");
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Find and dump the target thread. */
|
||||||
|
if (KThread *thread = KThread::GetThreadFromId(thread_id); thread != nullptr) {
|
||||||
|
ON_SCOPE_EXIT { thread->Close(); };
|
||||||
|
DumpThread(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MESOSPHERE_LOG("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,15 @@ namespace ams::kern {
|
||||||
return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast;
|
return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitializeKernelStack(uintptr_t stack_top) {
|
||||||
|
#if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE)
|
||||||
|
const uintptr_t stack_bottom = stack_top - PageSize;
|
||||||
|
std::memset(reinterpret_cast<void *>(stack_bottom), 0xCC, PageSize - sizeof(KThread::StackParameters));
|
||||||
|
#else
|
||||||
|
MESOSPHERE_UNUSED(stack_top);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CleanupKernelStack(uintptr_t stack_top) {
|
void CleanupKernelStack(uintptr_t stack_top) {
|
||||||
const uintptr_t stack_bottom = stack_top - PageSize;
|
const uintptr_t stack_bottom = stack_top - PageSize;
|
||||||
|
|
||||||
|
@ -153,6 +162,11 @@ namespace ams::kern {
|
||||||
this->resource_limit_release_hint = 0;
|
this->resource_limit_release_hint = 0;
|
||||||
this->cpu_time = 0;
|
this->cpu_time = 0;
|
||||||
|
|
||||||
|
/* Setup our kernel stack. */
|
||||||
|
if (type != ThreadType_Main) {
|
||||||
|
InitializeKernelStack(reinterpret_cast<uintptr_t>(kern_stack_top));
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear our stack parameters. */
|
/* Clear our stack parameters. */
|
||||||
std::memset(static_cast<void *>(std::addressof(this->GetStackParameters())), 0, sizeof(StackParameters));
|
std::memset(static_cast<void *>(std::addressof(this->GetStackParameters())), 0, sizeof(StackParameters));
|
||||||
|
|
||||||
|
@ -803,6 +817,26 @@ namespace ams::kern {
|
||||||
KScheduler::OnThreadStateChanged(this, old_state);
|
KScheduler::OnThreadStateChanged(this, old_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t KThread::GetKernelStackUsage() const {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
MESOSPHERE_ASSERT(this->kernel_stack_top != nullptr);
|
||||||
|
|
||||||
|
#if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE)
|
||||||
|
const u8 *stack = static_cast<const u8 *>(this->kernel_stack_top) - PageSize;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < PageSize; ++i) {
|
||||||
|
if (stack[i] != 0xCC) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PageSize - i;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Result KThread::SetActivity(ams::svc::ThreadActivity activity) {
|
Result KThread::SetActivity(ams::svc::ThreadActivity activity) {
|
||||||
/* Lock ourselves. */
|
/* Lock ourselves. */
|
||||||
KScopedLightLock lk(this->activity_pause_lock);
|
KScopedLightLock lk(this->activity_pause_lock);
|
||||||
|
|
|
@ -22,19 +22,27 @@ namespace ams::kern::svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void KernelDebug(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) {
|
void KernelDebug(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) {
|
||||||
#ifdef ATMOSPHERE_BUILD_FOR_DEBUGGING
|
MESOSPHERE_UNUSED(kern_debug_type, arg0, arg1, arg2);
|
||||||
|
|
||||||
|
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
|
||||||
{
|
{
|
||||||
/* TODO: Implement Kernel Debugging. */
|
switch (kern_debug_type) {
|
||||||
}
|
case ams::svc::KernelDebugType_Thread:
|
||||||
#else
|
if (arg0 == static_cast<u64>(-1)) {
|
||||||
{
|
KDumpObject::DumpThread();
|
||||||
MESOSPHERE_UNUSED(kern_debug_type, arg0, arg1, arg2);
|
} else {
|
||||||
|
KDumpObject::DumpThread(arg0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeKernelTraceState(ams::svc::KernelTraceState kern_trace_state) {
|
void ChangeKernelTraceState(ams::svc::KernelTraceState kern_trace_state) {
|
||||||
#ifdef ATMOSPHERE_BUILD_FOR_DEBUGGING
|
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
|
||||||
{
|
{
|
||||||
switch (kern_trace_state) {
|
switch (kern_trace_state) {
|
||||||
case ams::svc::KernelTraceState_Enabled:
|
case ams::svc::KernelTraceState_Enabled:
|
||||||
|
|
|
@ -470,7 +470,7 @@ namespace ams::svc {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KernelDebugType : u32 {
|
enum KernelDebugType : u32 {
|
||||||
/* TODO */
|
KernelDebugType_Thread = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KernelTraceState : u32 {
|
enum KernelTraceState : u32 {
|
||||||
|
|
Loading…
Reference in a new issue