diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp index a1ac5e53d..2e1708c25 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp @@ -38,6 +38,8 @@ namespace ams::kern { void Initialize(); Result Attach(KProcess *process); + KScopedAutoObject GetProcess(); + Result QueryMemoryInfo(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, KProcessAddress address); Result ReadMemory(KProcessAddress buffer, KProcessAddress address, size_t size); Result WriteMemory(KProcessAddress buffer, KProcessAddress address, size_t size); @@ -49,8 +51,6 @@ namespace ams::kern { /* TODO: This is a placeholder definition. */ private: - KScopedAutoObject GetProcess(); - 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 EnqueueDebugEventInfo(KEventInfo *info); public: diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index f27434cbb..846530829 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -324,6 +324,8 @@ namespace ams::kern { return this->address_arbiter.WaitForAddress(address, arb_type, value, timeout); } + Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count); + static KProcess *GetProcessFromId(u64 process_id); static Result GetProcessList(s32 *out_num_processes, ams::kern::svc::KUserPointer out_process_ids, s32 max_out_count); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index c439df057..c1578c967 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -515,6 +515,8 @@ namespace ams::kern { return ConditionVariableThreadTreeTraits::IsValid(); } + static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count); + using ConditionVariableThreadTreeType = ConditionVariableThreadTree; }; static_assert(alignof(KThread) == 0x10); diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 4a1ee3572..7a836f1e4 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -924,6 +924,33 @@ namespace ams::kern { return ResultSuccess(); } + Result KProcess::GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count) { + /* Lock the list. */ + KScopedLightLock lk(this->list_lock); + + /* Iterate over the list. */ + s32 count = 0; + auto end = this->GetThreadList().end(); + for (auto it = this->GetThreadList().begin(); it != end; ++it) { + /* If we're within array bounds, write the id. */ + if (count < max_out_count) { + /* Get the thread id. */ + KThread *thread = std::addressof(*it); + const u64 id = thread->GetId(); + + /* Copy the id to userland. */ + R_TRY(out_thread_ids.CopyArrayElementFrom(std::addressof(id), count)); + } + + /* Increment the count. */ + ++count; + } + + /* We successfully iterated the list. */ + *out_num_threads = count; + return ResultSuccess(); + } + KProcess::State KProcess::SetDebugObject(void *debug_object) { /* Attaching should only happen to non-null objects while the scheduler is locked. */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index d12637b64..2198779de 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -1189,4 +1189,31 @@ namespace ams::kern { return std::addressof(this->GetContext()); } + Result KThread::GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count) { + /* Lock the list. */ + KThread::ListAccessor accessor; + const auto end = accessor.end(); + + /* Iterate over the list. */ + s32 count = 0; + for (auto it = accessor.begin(); it != end; ++it) { + /* If we're within array bounds, write the id. */ + if (count < max_out_count) { + /* Get the thread id. */ + KThread *thread = static_cast(std::addressof(*it)); + const u64 id = thread->GetId(); + + /* Copy the id to userland. */ + R_TRY(out_thread_ids.CopyArrayElementFrom(std::addressof(id), count)); + } + + /* Increment the count. */ + ++count; + } + + /* We successfully iterated the list. */ + *out_num_threads = count; + return ResultSuccess(); + } + } diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp index 07f1426b4..e7a3136f6 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp @@ -214,6 +214,44 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result GetThreadList(int32_t *out_num_threads, KUserPointer out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { + /* Validate that the out count is valid. */ + R_UNLESS((0 <= max_out_count && max_out_count <= static_cast(std::numeric_limits::max() / sizeof(u64))), svc::ResultOutOfRange()); + + /* Validate that the pointer is in range. */ + if (max_out_count > 0) { + R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); + } + + if (debug_handle == ams::svc::InvalidHandle) { + /* If passed invalid handle, we should return the global thread list. */ + return KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count); + } else { + /* Get the handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Try to get as a debug object. */ + KScopedAutoObject debug = handle_table.GetObject(debug_handle); + if (debug.IsNotNull()) { + /* Get the debug object's process. */ + KScopedAutoObject process = debug->GetProcess(); + R_UNLESS(process.IsNotNull(), svc::ResultProcessTerminated()); + + /* Get the thread list. */ + R_TRY(process->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); + } else { + /* Try to get as a process. */ + KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle(debug_handle); + R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the thread list. */ + R_TRY(process->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); + } + } + + return ResultSuccess(); + } + } /* ============================= 64 ABI ============================= */ @@ -254,20 +292,12 @@ namespace ams::kern::svc { return GetThreadId(out_thread_id, thread_handle); } - Result GetDebugFutureThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, uint64_t *thread_id, ams::svc::Handle debug_handle, int64_t ns) { - MESOSPHERE_PANIC("Stubbed SvcGetDebugFutureThreadInfo64 was called."); - } - - Result GetLastThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { - MESOSPHERE_PANIC("Stubbed SvcGetLastThreadInfo64 was called."); - } - Result GetThreadContext364(KUserPointer out_context, ams::svc::Handle thread_handle) { return GetThreadContext3(out_context, thread_handle); } Result GetThreadList64(int32_t *out_num_threads, KUserPointer out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { - MESOSPHERE_PANIC("Stubbed SvcGetThreadList64 was called."); + return GetThreadList(out_num_threads, out_thread_ids, max_out_count, debug_handle); } /* ============================= 64From32 ABI ============================= */ @@ -308,20 +338,12 @@ namespace ams::kern::svc { return GetThreadId(out_thread_id, thread_handle); } - Result GetDebugFutureThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, uint64_t *thread_id, ams::svc::Handle debug_handle, int64_t ns) { - MESOSPHERE_PANIC("Stubbed SvcGetDebugFutureThreadInfo64From32 was called."); - } - - Result GetLastThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { - MESOSPHERE_PANIC("Stubbed SvcGetLastThreadInfo64From32 was called."); - } - Result GetThreadContext364From32(KUserPointer out_context, ams::svc::Handle thread_handle) { return GetThreadContext3(out_context, thread_handle); } Result GetThreadList64From32(int32_t *out_num_threads, KUserPointer out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { - MESOSPHERE_PANIC("Stubbed SvcGetThreadList64From32 was called."); + return GetThreadList(out_num_threads, out_thread_ids, max_out_count, debug_handle); } }