From efebd8f94de03ef5cab63803f0cf37fc39258682 Mon Sep 17 00:00:00 2001
From: jduncanator <1518948+jduncanator@users.noreply.github.com>
Date: Fri, 15 Mar 2019 14:37:54 +1100
Subject: [PATCH] Print Guest Stack Trace in ServiceNotImplemented Exception
 (#650)

* Print Guest Stack Trace in ServiceNotImplemented Exception

* Remove PrintGuestStackTrace

* Print Process Name and PID at the start of guest stack trace
---
 .../ServiceNotImplementedException.cs         | 84 +++++++++++--------
 Ryujinx.HLE/HOS/Ipc/IpcHandler.cs             |  3 +
 .../HOS/Kernel/Process/HleProcessDebugger.cs  | 17 ++--
 .../HOS/Kernel/SupervisorCall/SvcIpc.cs       |  1 +
 Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs   | 14 +++-
 Ryujinx.HLE/HOS/ServiceCtx.cs                 |  4 +
 6 files changed, 76 insertions(+), 47 deletions(-)

diff --git a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs b/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
index d5ea3bbfa1..893ce26e7b 100644
--- a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
+++ b/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
@@ -76,60 +76,70 @@ namespace Ryujinx.HLE.Exceptions
                 }
             }
 
+            sb.AppendLine("Guest Stack Trace:");
+            sb.AppendLine(Context.Thread.GetGuestStackTrace());
+
             // Print buffer information
-            sb.AppendLine("Buffer Information");
-
-            if (Request.PtrBuff.Count > 0)
+            if (Request.PtrBuff.Count > 0 ||
+                Request.SendBuff.Count > 0 ||
+                Request.ReceiveBuff.Count > 0 ||
+                Request.ExchangeBuff.Count > 0 ||
+                Request.RecvListBuff.Count > 0)
             {
-                sb.AppendLine("\tPtrBuff:");
+                sb.AppendLine("Buffer Information:");
 
-                foreach (var buff in Request.PtrBuff)
+                if (Request.PtrBuff.Count > 0)
                 {
-                    sb.AppendLine($"\t[{buff.Index}] Position: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}");
+                    sb.AppendLine("\tPtrBuff:");
+
+                    foreach (var buff in Request.PtrBuff)
+                    {
+                        sb.AppendLine($"\t[{buff.Index}] Position: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}");
+                    }
                 }
-            }
 
-            if (Request.SendBuff.Count > 0)
-            {
-                sb.AppendLine("\tSendBuff:");
-
-                foreach (var buff in Request.SendBuff)
+                if (Request.SendBuff.Count > 0)
                 {
-                    sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    sb.AppendLine("\tSendBuff:");
+
+                    foreach (var buff in Request.SendBuff)
+                    {
+                        sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    }
                 }
-            }
 
-            if (Request.ReceiveBuff.Count > 0)
-            {
-                sb.AppendLine("\tReceiveBuff:");
-
-                foreach (var buff in Request.ReceiveBuff)
+                if (Request.ReceiveBuff.Count > 0)
                 {
-                    sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    sb.AppendLine("\tReceiveBuff:");
+
+                    foreach (var buff in Request.ReceiveBuff)
+                    {
+                        sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    }
                 }
-            }
 
-            if (Request.ExchangeBuff.Count > 0)
-            {
-                sb.AppendLine("\tExchangeBuff:");
-
-                foreach (var buff in Request.ExchangeBuff)
+                if (Request.ExchangeBuff.Count > 0)
                 {
-                    sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    sb.AppendLine("\tExchangeBuff:");
+
+                    foreach (var buff in Request.ExchangeBuff)
+                    {
+                        sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}");
+                    }
                 }
-            }
 
-            if (Request.RecvListBuff.Count > 0)
-            {
-                sb.AppendLine("\tRecvListBuff:");
-
-                foreach (var buff in Request.RecvListBuff)
+                if (Request.RecvListBuff.Count > 0)
                 {
-                    sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}");
-                }
-            }
+                    sb.AppendLine("\tRecvListBuff:");
 
-            sb.AppendLine();
+                    foreach (var buff in Request.RecvListBuff)
+                    {
+                        sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}");
+                    }
+                }
+
+                sb.AppendLine();
+            }
 
             sb.AppendLine("Raw Request Data:");
             sb.Append(HexUtils.HexTable(Request.RawData));
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
index 1eba4b4124..9f087a1a04 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
+++ b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
@@ -2,6 +2,7 @@ using ChocolArm64.Memory;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
 using System.IO;
 
@@ -13,6 +14,7 @@ namespace Ryujinx.HLE.HOS.Ipc
             Switch         device,
             KProcess       process,
             MemoryManager  memory,
+            KThread        thread,
             KClientSession session,
             IpcMessage     request,
             long           cmdPtr)
@@ -36,6 +38,7 @@ namespace Ryujinx.HLE.HOS.Ipc
                             device,
                             process,
                             memory,
+                            thread,
                             session,
                             request,
                             response,
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
index 0268de7d07..d31f95b43e 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
@@ -4,6 +4,7 @@ using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Diagnostics.Demangler;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.Loaders.Elf;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -41,14 +42,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
             _images = new List<Image>();
         }
 
-        public void PrintGuestStackTrace(CpuThreadState threadState)
+        public string GetGuestStackTrace(CpuThreadState threadState)
         {
             EnsureLoaded();
 
             StringBuilder trace = new StringBuilder();
 
-            trace.AppendLine("Guest stack trace:");
-
             void AppendTrace(long address)
             {
                 Image image = GetImage(address, out int imageIndex);
@@ -68,22 +67,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                     string imageName = GetGuessedNsoNameFromIndex(imageIndex);
 
-                    string imageNameAndOffset = $"[{_owner.Name}] {imageName}:0x{offset:x8}";
-
-                    trace.AppendLine($" {imageNameAndOffset} {subName}");
+                    trace.AppendLine($"   {imageName}:0x{offset:x8} {subName}");
                 }
                 else
                 {
-                    trace.AppendLine($" [{_owner.Name}] ??? {subName}");
+                    trace.AppendLine($"   ??? {subName}");
                 }
             }
 
             //TODO: ARM32.
             long framePointer = (long)threadState.X29;
 
+            trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
+
             while (framePointer != 0)
             {
-                if ((framePointer & 7) != 0                  ||
+                if ((framePointer & 7) != 0 ||
                     !_owner.CpuMemory.IsMapped(framePointer) ||
                     !_owner.CpuMemory.IsMapped(framePointer + 8))
                 {
@@ -97,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 framePointer = _owner.CpuMemory.ReadInt64(framePointer);
             }
 
-            Logger.PrintInfo(LogClass.Cpu, trace.ToString());
+            return trace.ToString();
         }
 
         private bool TryGetSubName(Image image, long address, out string name)
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs
index e19d9d2687..eb7595c0a2 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs
@@ -143,6 +143,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
                 _device,
                 _process,
                 _process.CpuMemory,
+                ipcMessage.Thread,
                 ipcMessage.Session,
                 ipcMessage.Message,
                 ipcMessage.MessagePtr);
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index 17e0f3c3bf..ebde34baf1 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -1,10 +1,12 @@
 using ChocolArm64;
 using ChocolArm64.Memory;
+using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 
 namespace Ryujinx.HLE.HOS.Kernel.Threading
 {
@@ -1009,9 +1011,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
             ReleaseAndResume();
         }
 
+        public string GetGuestStackTrace()
+        {
+            return Owner.Debugger.GetGuestStackTrace(Context.ThreadState);
+        }
+
         public void PrintGuestStackTrace()
         {
-            Owner.Debugger.PrintGuestStackTrace(Context.ThreadState);
+            StringBuilder trace = new StringBuilder();
+
+            trace.AppendLine("Guest stack trace:");
+            trace.AppendLine(GetGuestStackTrace());
+
+            Logger.PrintInfo(LogClass.Cpu, trace.ToString());
         }
 
         private void ThreadFinishedHandler(object sender, EventArgs e)
diff --git a/Ryujinx.HLE/HOS/ServiceCtx.cs b/Ryujinx.HLE/HOS/ServiceCtx.cs
index af42d41762..99b2d5afe6 100644
--- a/Ryujinx.HLE/HOS/ServiceCtx.cs
+++ b/Ryujinx.HLE/HOS/ServiceCtx.cs
@@ -2,6 +2,7 @@ using ChocolArm64.Memory;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 using System.IO;
 
 namespace Ryujinx.HLE.HOS
@@ -11,6 +12,7 @@ namespace Ryujinx.HLE.HOS
         public Switch         Device       { get; }
         public KProcess       Process      { get; }
         public MemoryManager  Memory       { get; }
+        public KThread        Thread       { get; }
         public KClientSession Session      { get; }
         public IpcMessage     Request      { get; }
         public IpcMessage     Response     { get; }
@@ -21,6 +23,7 @@ namespace Ryujinx.HLE.HOS
             Switch         device,
             KProcess       process,
             MemoryManager  memory,
+            KThread        thread,
             KClientSession session,
             IpcMessage     request,
             IpcMessage     response,
@@ -30,6 +33,7 @@ namespace Ryujinx.HLE.HOS
             Device       = device;
             Process      = process;
             Memory       = memory;
+            Thread       = thread;
             Session      = session;
             Request      = request;
             Response     = response;