From 8a4bf6a0a817deedda52927a34dda15c262f1958 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Dec 2020 23:44:36 -0800 Subject: [PATCH] kern: add handle table/process/suspend/resume debug --- .../include/mesosphere/kern_k_dump_object.hpp | 6 + .../mesosphere/kern_k_server_session.hpp | 2 + .../kern_k_synchronization_object.hpp | 2 +- .../include/mesosphere/kern_slab_helpers.hpp | 2 +- .../source/arch/arm64/kern_k_debug.cpp | 2 +- .../source/kern_k_dump_object.cpp | 165 ++++++++++++++++-- .../source/kern_k_server_session.cpp | 32 ++++ .../source/kern_k_synchronization_object.cpp | 2 +- .../source/svc/kern_svc_kernel_debug.cpp | 32 ++++ .../include/vapours/svc/svc_types_common.hpp | 6 + 10 files changed, 233 insertions(+), 18 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index 6ef29e216..4113fff1c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -25,4 +25,10 @@ namespace ams::kern::KDumpObject { void DumpThreadCallStack(); void DumpThreadCallStack(u64 thread_id); + void DumpHandle(); + void DumpHandle(u64 process_id); + + void DumpProcess(); + void DumpProcess(u64 process_id); + } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp index 136a5dc6f..12979af04 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp @@ -50,6 +50,8 @@ namespace ams::kern { Result SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); void OnClientClosed(); + + void Dump(); private: bool IsSignaledImpl() const; void CleanupRequests(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp index 953c2fa4f..98dd5fe6e 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp @@ -46,7 +46,7 @@ namespace ams::kern { public: virtual void Finalize() override; virtual bool IsSignaled() const = 0; - virtual void DebugWaiters(); + virtual void DumpWaiters(); }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp index 9f62be183..e665c182d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp @@ -92,7 +92,7 @@ namespace ams::kern { virtual uintptr_t GetPostDestroyArgument() const { return 0; } size_t GetSlabIndex() const { - return s_slab_heap.GetIndex(static_cast(this)); + return s_slab_heap.GetObjectIndex(static_cast(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp index 415e38c65..5efe21b12 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp @@ -646,7 +646,7 @@ namespace ams::kern::arch::arm64 { if (!ReadValue(std::addressof(temp_32), process, base_address + 0x5C)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (temp_32 != 0x94000002) { /* MOD0 */ + if (temp_32 != 0x94000002) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } if (!ReadValue(std::addressof(temp_32), process, base_address + 0x60)) { diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 551b3f374..06fe739c7 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -28,16 +28,16 @@ namespace ams::kern::KDumpObject { 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", + MESOSPHERE_RELEASE_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_RELEASE_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()); + MESOSPHERE_RELEASE_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", + MESOSPHERE_RELEASE_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()); @@ -46,21 +46,93 @@ namespace ams::kern::KDumpObject { void DumpThreadCallStack(KThread *thread) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); KDebug::PrintRegister(thread); KDebug::PrintBacktrace(thread); } else { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); } } + void DumpHandle(const KProcess::ListAccessor &accessor, KProcess *process) { + MESOSPHERE_RELEASE_LOG("Process ID=%lu (%s)\n", process->GetId(), process->GetName()); + + const auto end = accessor.end(); + const auto &handle_table = process->GetHandleTable(); + const size_t max_handles = handle_table.GetMaxCount(); + for (size_t i = 0; i < max_handles; ++i) { + /* Get the object + handle. */ + ams::svc::Handle handle = ams::svc::InvalidHandle; + KScopedAutoObject obj = handle_table.GetObjectByIndex(std::addressof(handle), i); + if (obj.IsNotNull()) { + if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Client=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetClientSession())); + target->Dump(); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Server=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetServerSession())); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwnerProcess(); + const s32 owner_pid = target_owner != nullptr ? static_cast(target_owner->GetId()) : -1; + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d PID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target->GetId()), owner_pid); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target->GetId())); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + /* Find the owner. */ + KProcess *target_owner = nullptr; + for (auto it = accessor.begin(); it != end; ++it) { + if (static_cast(std::addressof(*it))->GetId() == target->GetOwnerProcessId()) { + target_owner = static_cast(std::addressof(*it)); + break; + } + } + + MESOSPHERE_ASSERT(target_owner != nullptr); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Size=%zu KB OwnerPID=%d (%s)\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetSize() / 1_KB, static_cast(target_owner->GetId()), target_owner->GetName()); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwner(); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwner(); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s irq=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetInterruptId()); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + if (KEvent *event = target->GetParent(); event != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Pair=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(event->GetReadableEvent())); + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + if (KEvent *event = target->GetParent(); event != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Pair=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(event->GetWritableEvent())); + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + + if (auto *sync = obj->DynamicCast(); sync != nullptr) { + sync->DumpWaiters(); + } + } + } + + MESOSPHERE_RELEASE_LOG("%zu(max %zu)/%zu used.\n", handle_table.GetCount(), max_handles, handle_table.GetTableSize()); + MESOSPHERE_RELEASE_LOG("\n\n"); + } + + void DumpProcess(KProcess *process) { + MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); + } + } void DumpThread() { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ @@ -73,11 +145,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThread(u64 thread_id) { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ @@ -87,11 +159,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack() { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ @@ -104,11 +176,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack(u64 thread_id) { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ @@ -118,7 +190,72 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpHandle() { + MESOSPHERE_RELEASE_LOG("Dump Handle\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpHandle(accessor, static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpHandle(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Handle\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + /* Lock the list. */ + KProcess::ListAccessor accessor; + DumpHandle(accessor, process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpProcess() { + MESOSPHERE_RELEASE_LOG("Dump Process\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpProcess(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpProcess(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Process\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + DumpProcess(process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); } } diff --git a/libraries/libmesosphere/source/kern_k_server_session.cpp b/libraries/libmesosphere/source/kern_k_server_session.cpp index 712cca8b0..798209d43 100644 --- a/libraries/libmesosphere/source/kern_k_server_session.cpp +++ b/libraries/libmesosphere/source/kern_k_server_session.cpp @@ -1367,4 +1367,36 @@ namespace ams::kern { #pragma GCC pop_options + void KServerSession::Dump() { + MESOSPHERE_ASSERT_THIS(); + + KScopedLightLock lk(this->lock); + { + KScopedSchedulerLock sl; + MESOSPHERE_RELEASE_LOG("Dump Session %p\n", this); + + /* Dump current request. */ + bool has_request = false; + if (this->current_request != nullptr) { + KThread *thread = this->current_request->GetThread(); + const s32 thread_id = thread != nullptr ? static_cast(thread->GetId()) : -1; + MESOSPHERE_RELEASE_LOG(" CurrentReq %p Thread=%p ID=%d\n", this->current_request, thread, thread_id); + has_request = true; + } + + /* Dump all rqeuests in list. */ + for (auto it = this->request_list.begin(); it != this->request_list.end(); ++it) { + KThread *thread = it->GetThread(); + const s32 thread_id = thread != nullptr ? static_cast(thread->GetId()) : -1; + MESOSPHERE_RELEASE_LOG(" Req %p Thread=%p ID=%d\n", this->current_request, thread, thread_id); + has_request = true; + } + + /* If we didn't have any requests, print so. */ + if (!has_request) { + MESOSPHERE_RELEASE_LOG(" None\n"); + } + } + } + } diff --git a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp index bd5938b8e..774d0a60a 100644 --- a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp +++ b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp @@ -148,7 +148,7 @@ namespace ams::kern { } } - void KSynchronizationObject::DebugWaiters() { + void KSynchronizationObject::DumpWaiters() { MESOSPHERE_ASSERT_THIS(); /* If debugging, dump the list of waiters. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 18953df2f..86f9b5e84 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -41,6 +41,38 @@ namespace ams::kern::svc { KDumpObject::DumpThreadCallStack(arg0); } break; + case ams::svc::KernelDebugType_Handle: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpHandle(); + } else { + KDumpObject::DumpHandle(arg0); + } + break; + case ams::svc::KernelDebugType_Process: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpProcess(); + } else { + KDumpObject::DumpProcess(arg0); + } + break; + case ams::svc::KernelDebugType_SuspendProcess: + if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Paused))) { + MESOSPHERE_RELEASE_LOG("Suspend Process ID=%3lu\n", process->GetId()); + } + } + break; + case ams::svc::KernelDebugType_ResumeProcess: + if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Runnable))) { + MESOSPHERE_RELEASE_LOG("Resume Process ID=%3lu\n", process->GetId()); + } + } + break; default: break; } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 64070e9ce..af1b242b4 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -472,6 +472,12 @@ namespace ams::svc { enum KernelDebugType : u32 { KernelDebugType_Thread = 0, KernelDebugType_ThreadCallStack = 1, + + KernelDebugType_Handle = 3, + + KernelDebugType_Process = 7, + KernelDebugType_SuspendProcess = 8, + KernelDebugType_ResumeProcess = 9, }; enum KernelTraceState : u32 {