From 75a60a6e2214c4d02988ae3c5196cebb3f52e8d0 Mon Sep 17 00:00:00 2001
From: Lioncash <mathew1800@gmail.com>
Date: Wed, 3 Feb 2021 22:33:27 -0500
Subject: [PATCH] svc: Provide more detailed error logs for svc functions

Allows SVC calls to have much more informative information during error
cases. This also doesn't hide control flow returns from the reader.
---
 src/core/hle/kernel/svc.cpp | 247 +++++++++++++++++++++++++++---------
 1 file changed, 188 insertions(+), 59 deletions(-)

diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index edf208eff..26650a513 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -368,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Get the thread's id.
     *out_thread_id = thread->GetThreadID();
@@ -478,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Cancel the thread's wait.
     thread->WaitCancel();
@@ -496,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
               thread_handle, address, tag);
 
     // Validate the input address.
-    R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
-    R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
+    if (Memory::IsKernelAddress(address)) {
+        LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
+                  address);
+        return ResultInvalidCurrentMemory;
+    }
+    if (!Common::IsAligned(address, sizeof(u32))) {
+        LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
+        return ResultInvalidAddress;
+    }
 
     return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
 }
@@ -512,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
     LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
 
     // Validate the input address.
-    R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
-    R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
+    if (Memory::IsKernelAddress(address)) {
+        LOG_ERROR(Kernel_SVC,
+                  "Attempting to arbitrate an unlock on a kernel address (address={:08X})",
+                  address);
+        return ResultInvalidCurrentMemory;
+    }
+    if (!Common::IsAligned(address, sizeof(u32))) {
+        LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
+        return ResultInvalidAddress;
+    }
 
     return system.Kernel().CurrentProcess()->SignalToAddress(address);
 }
@@ -1025,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
     return UnmapPhysicalMemory(system, addr, size);
 }
 
-constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
-    switch (thread_activity) {
-    case Svc::ThreadActivity::Runnable:
-    case Svc::ThreadActivity::Paused:
-        return true;
-    default:
-        return false;
-    }
-}
-
 /// Sets the thread activity
 static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
-                                    Svc::ThreadActivity thread_activity) {
+                                    ThreadActivity thread_activity) {
     LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
               thread_activity);
 
     // Validate the activity.
-    R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
+    constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
+        return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
+    };
+    if (!IsValidThreadActivity(thread_activity)) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
+                  thread_activity);
+        return ResultInvalidEnumValue;
+    }
 
     // Get the thread from its handle.
     auto& kernel = system.Kernel();
     const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Check that the activity is being set on a non-current thread for the current process.
-    R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
-    R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
+    if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
+        LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
+        return ResultInvalidHandle;
+    }
+    if (thread.get() == GetCurrentThreadPointer(kernel)) {
+        LOG_ERROR(Kernel_SVC, "Thread is busy");
+        return ResultBusy;
+    }
 
     // Set the activity.
-    R_TRY(thread->SetActivity(thread_activity));
+    const auto set_result = thread->SetActivity(thread_activity);
+    if (set_result.IsError()) {
+        LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
+        return set_result;
+    }
 
     return RESULT_SUCCESS;
 }
@@ -1074,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
     const auto* current_process = system.Kernel().CurrentProcess();
     const std::shared_ptr<KThread> thread =
         current_process->GetHandleTable().Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Require the handle be to a non-current thread in the current process.
-    R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
-    R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
-             Svc::ResultBusy);
+    if (thread->GetOwnerProcess() != current_process) {
+        LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
+        return ResultInvalidHandle;
+    }
+    if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
+        LOG_ERROR(Kernel_SVC, "Current thread is busy.");
+        return ResultBusy;
+    }
 
     // Get the thread context.
     std::vector<u8> context;
-    R_TRY(thread->GetThreadContext3(context));
+    const auto context_result = thread->GetThreadContext3(context);
+    if (context_result.IsError()) {
+        LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
+                  context_result.raw);
+        return context_result;
+    }
 
     // Copy the thread context to user space.
     system.Memory().WriteBlock(out_context, context.data(), context.size());
@@ -1102,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
+        return ResultInvalidHandle;
+    }
 
     // Get the thread's priority.
     *out_priority = thread->GetPriority();
@@ -1118,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
     LOG_TRACE(Kernel_SVC, "called");
 
     // Validate the priority.
-    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
-             Svc::ResultInvalidPriority);
+    if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
+        return ResultInvalidPriority;
+    }
 
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
+        return ResultInvalidHandle;
+    }
 
     // Set the thread priority.
     thread->SetBasePriority(priority);
@@ -1440,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
     // Adjust core id, if it's the default magic.
     auto& kernel = system.Kernel();
     auto& process = *kernel.CurrentProcess();
-    if (core_id == Svc::IdealCoreUseProcessValue) {
+    if (core_id == IdealCoreUseProcessValue) {
         core_id = process.GetIdealCoreId();
     }
 
     // Validate arguments.
-    R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
-    R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
+    if (!IsValidCoreId(core_id)) {
+        LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
+        return ResultInvalidCoreId;
+    }
+    if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
+        LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
+        return ResultInvalidCoreId;
+    }
 
-    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
-             Svc::ResultInvalidPriority);
-    R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
+    if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
+        LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
+        return ResultInvalidPriority;
+    }
+    if (!process.CheckThreadPriority(priority)) {
+        LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
+        return ResultInvalidPriority;
+    }
 
     ASSERT(process.GetResourceLimit()->Reserve(
         LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
@@ -1489,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Try to start the thread.
-    R_TRY(thread->Run());
+    const auto run_result = thread->Run();
+    if (run_result.IsError()) {
+        LOG_ERROR(Kernel_SVC,
+                  "Unable to successfuly start thread (thread handle={:08X}, result={})",
+                  thread_handle, run_result.raw);
+        return run_result;
+    }
 
     return RESULT_SUCCESS;
 }
@@ -1553,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
               cv_key, tag, timeout_ns);
 
     // Validate input.
-    R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
-    R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
+    if (Memory::IsKernelAddress(address)) {
+        LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
+        return ResultInvalidCurrentMemory;
+    }
+    if (!Common::IsAligned(address, sizeof(s32))) {
+        LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
+        return ResultInvalidAddress;
+    }
 
     // Convert timeout from nanoseconds to ticks.
     s64 timeout{};
@@ -1629,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
               address, arb_type, value, timeout_ns);
 
     // Validate input.
-    R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
-    R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
-    R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue);
+    if (Memory::IsKernelAddress(address)) {
+        LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
+        return ResultInvalidCurrentMemory;
+    }
+    if (!Common::IsAligned(address, sizeof(s32))) {
+        LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
+        return ResultInvalidAddress;
+    }
+    if (!IsValidArbitrationType(arb_type)) {
+        LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
+        return ResultInvalidEnumValue;
+    }
 
     // Convert timeout from nanoseconds to ticks.
     s64 timeout{};
@@ -1665,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
               address, signal_type, value, count);
 
     // Validate input.
-    R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
-    R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress);
-    R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue);
+    if (Memory::IsKernelAddress(address)) {
+        LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
+        return ResultInvalidCurrentMemory;
+    }
+    if (!Common::IsAligned(address, sizeof(s32))) {
+        LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
+        return ResultInvalidAddress;
+    }
+    if (!IsValidSignalType(signal_type)) {
+        LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
+        return ResultInvalidEnumValue;
+    }
 
     return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
                                                                   count);
@@ -1815,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Get the core mask.
-    R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
+    const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
+    if (result.IsError()) {
+        LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
+        return result;
+    }
 
     return RESULT_SUCCESS;
 }
@@ -1846,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
     } else {
         // Validate the affinity mask.
         const u64 process_core_mask = current_process.GetCoreMask();
-        R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
-                 Svc::ResultInvalidCoreId);
-        R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
+        if ((affinity_mask | process_core_mask) != process_core_mask) {
+            LOG_ERROR(Kernel_SVC,
+                      "Affinity mask does match the process core mask (affinity mask={:016X}, core "
+                      "mask={:016X})",
+                      affinity_mask, process_core_mask);
+            return ResultInvalidCoreId;
+        }
+        if (affinity_mask == 0) {
+            LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
+            return ResultInvalidCombination;
+        }
 
         // Validate the core id.
         if (IsValidCoreId(core_id)) {
-            R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
+            if (((1ULL << core_id) & affinity_mask) == 0) {
+                LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
+                return ResultInvalidCombination;
+            }
         } else {
-            R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
-                     Svc::ResultInvalidCoreId);
+            if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
+                LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
+                return ResultInvalidCoreId;
+            }
         }
     }
 
     // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    R_UNLESS(thread, Svc::ResultInvalidHandle);
+    if (!thread) {
+        LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
+        return ResultInvalidHandle;
+    }
 
     // Set the core mask.
-    R_TRY(thread->SetCoreMask(core_id, affinity_mask));
+    const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
+    if (set_result.IsError()) {
+        LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
+        return set_result;
+    }
 
     return RESULT_SUCCESS;
 }
@@ -1884,7 +2007,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
 
     // Get the writable event.
     auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
-    R_UNLESS(writable_event, Svc::ResultInvalidHandle);
+    if (!writable_event) {
+        LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
+        return ResultInvalidHandle;
+    }
 
     return writable_event->Signal();
 }
@@ -1933,7 +2059,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
 
     // Create a new event.
     const auto event = KEvent::Create(kernel, "CreateEvent");
-    R_UNLESS(event != nullptr, Svc::ResultOutOfResource);
+    if (!event) {
+        LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
+        return ResultOutOfResource;
+    }
 
     // Initialize the event.
     event->Initialize();