diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp index 5000f7626..fd11a4795 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp @@ -42,6 +42,10 @@ namespace ams::kern { constexpr const KPort *GetParent() const { return this->parent; } + ALWAYS_INLINE s32 GetNumSessions() const { return this->num_sessions; } + ALWAYS_INLINE s32 GetPeakSessions() const { return this->peak_sessions; } + ALWAYS_INLINE s32 GetMaxSessions() const { return this->max_sessions; } + bool IsLight() const; /* Overridden virtual functions. */ diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index 4113fff1c..376d22518 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -31,4 +31,7 @@ namespace ams::kern::KDumpObject { void DumpProcess(); void DumpProcess(u64 process_id); + void DumpPort(); + void DumpPort(u64 process_id); + } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp index b67f81e3a..a278391ca 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp @@ -71,6 +71,8 @@ namespace ams::kern { KServerSession &GetServerSession() { return this->server; } const KClientSession &GetClientSession() const { return this->client; } const KServerSession &GetServerSession() const { return this->server; } + + const KClientPort *GetParent() const { return this->port; } }; } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 06fe739c7..96f35a196 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -129,6 +129,81 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); } + void DumpPort(const KProcess::ListAccessor &accessor, KProcess *process) { + MESOSPHERE_RELEASE_LOG("Dump Port 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.IsNull()) { + continue; + } + + /* Process the object as a port. */ + if (auto *server = obj->DynamicCast(); server != nullptr) { + const KClientPort *client = std::addressof(server->GetParent()->GetClientPort()); + const uintptr_t port_name = server->GetParent()->GetName(); + + /* Get the port name. */ + char name[9] = {}; + { + /* Find the client port process. */ + KScopedAutoObject client_port_process; + { + for (auto it = accessor.begin(); it != end && client_port_process.IsNull(); ++it) { + KProcess *cur = static_cast(std::addressof(*it)); + for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { + ams::svc::Handle cur_h = ams::svc::InvalidHandle; + KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); + if (cur_o.IsNotNull()) { + if (cur_o.GetPointerUnsafe() == client) { + client_port_process = cur; + break; + } + } + } + } + } + + /* Read the port name. */ + if (client_port_process.IsNotNull()) { + if (R_FAILED(client_port_process->GetPageTable().CopyMemoryFromLinearToKernel(KProcessAddress(name), 8, port_name, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { + std::memset(name, 0, sizeof(name)); + } + for (size_t i = 0; i < 8 && name[i] != 0; i++) { + if (name[i] > 0x7F) { + std::memset(name, 0, sizeof(name)); + break; + } + } + } + MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Max=%3d Peak=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetMaxSessions(), client->GetPeakSessions()); + + /* Identify any sessions. */ + { + for (auto it = accessor.begin(); it != end && client_port_process.IsNull(); ++it) { + KProcess *cur = static_cast(std::addressof(*it)); + for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { + ams::svc::Handle cur_h = ams::svc::InvalidHandle; + KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); + if (cur_o.IsNull()) { + continue; + } + if (auto *session = cur_o->DynamicCast(); session != nullptr && session->GetParent()->GetParent() == client) { + MESOSPHERE_RELEASE_LOG(" Client %p Server %p %-12s: PID=%3lu\n", session, std::addressof(session->GetParent()->GetServerSession()), cur->GetName(), cur->GetId()); + } + } + } + } + } + } + } + } + } void DumpThread() { @@ -258,4 +333,38 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n"); } + void DumpPort() { + MESOSPHERE_RELEASE_LOG("Dump Port\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpPort(accessor, static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpPort(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Port\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; + DumpPort(accessor, process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + } diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 86f9b5e84..632d7a9cf 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -73,6 +73,13 @@ namespace ams::kern::svc { } } break; + case ams::svc::KernelDebugType_Port: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpPort(); + } else { + KDumpObject::DumpPort(arg0); + } + 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 af1b242b4..5b4d14e26 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -470,14 +470,15 @@ namespace ams::svc { }; enum KernelDebugType : u32 { - KernelDebugType_Thread = 0, - KernelDebugType_ThreadCallStack = 1, + KernelDebugType_Thread = 0, + KernelDebugType_ThreadCallStack = 1, - KernelDebugType_Handle = 3, + KernelDebugType_Handle = 3, - KernelDebugType_Process = 7, - KernelDebugType_SuspendProcess = 8, - KernelDebugType_ResumeProcess = 9, + KernelDebugType_Process = 7, + KernelDebugType_SuspendProcess = 8, + KernelDebugType_ResumeProcess = 9, + KernelDebugType_Port = 10, }; enum KernelTraceState : u32 {