aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE
diff options
context:
space:
mode:
authorSomebody Whoisbored <13044396+shadowninja108@users.noreply.github.com>2021-05-20 16:27:16 -0700
committerGitHub <noreply@github.com>2021-05-21 01:27:16 +0200
commit26e5b5acffa28c7fc9b6d13612ef5077fa35c971 (patch)
treecd62311f98d0da1698889d22d3a4a7a27eccd07b /Ryujinx.HLE
parent2c3dab69860e8a7b23cfaba603b3bb31b75a168b (diff)
Extend info printed when guest crashes/breaks execution (#1845)
* Add CPU register printout when guest crashes/breaks execution * Print out registers when undefined instruction is hit * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Fixes after rebase * Address gdkchan's comments Co-authored-by: Ac_K <Acoustik666@gmail.com> Co-authored-by: Mary <me@thog.eu>
Diffstat (limited to 'Ryujinx.HLE')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs190
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs1
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs12
4 files changed, 170 insertions, 35 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
index 5ad33154..627049bc 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
@@ -1,5 +1,6 @@
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.Loaders.Elf;
using Ryujinx.Memory;
using System.Collections.Generic;
@@ -18,12 +19,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private class Image
{
public ulong BaseAddress { get; }
+ public ulong Size { get; }
+ public ulong EndAddress => BaseAddress + Size;
public ElfSymbol[] Symbols { get; }
- public Image(ulong baseAddress, ElfSymbol[] symbols)
+ public Image(ulong baseAddress, ulong size, ElfSymbol[] symbols)
{
BaseAddress = baseAddress;
+ Size = size;
Symbols = symbols;
}
}
@@ -39,41 +43,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_images = new List<Image>();
}
- public string GetGuestStackTrace(ARMeilleure.State.ExecutionContext context)
+ public string GetGuestStackTrace(KThread thread)
{
EnsureLoaded();
+ var context = thread.Context;
+
StringBuilder trace = new StringBuilder();
+ trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
+
void AppendTrace(ulong address)
{
- Image image = GetImage(address, out int imageIndex);
-
- if (image == null || !TryGetSubName(image, address, out string subName))
- {
- subName = $"Sub{address:x16}";
- }
- else if (subName.StartsWith("_Z"))
+ if(AnalyzePointer(out PointerInfo info, address, thread))
{
- subName = Demangler.Parse(subName);
- }
-
- if (image != null)
- {
- ulong offset = address - image.BaseAddress;
-
- string imageName = GetGuessedNsoNameFromIndex(imageIndex);
-
- trace.AppendLine($" {imageName}:0x{offset:x8} {subName}");
+ trace.AppendLine($" 0x{address:x16}\t{info.ImageDisplay}\t{info.SubDisplay}");
}
else
{
- trace.AppendLine($" ??? {subName}");
+ trace.AppendLine($" 0x{address:x16}");
}
}
- trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
-
if (context.IsAarch32)
{
ulong framePointer = context.GetX(11);
@@ -114,7 +105,47 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return trace.ToString();
}
- private bool TryGetSubName(Image image, ulong address, out string name)
+ public string GetCpuRegisterPrintout(KThread thread)
+ {
+ EnsureLoaded();
+
+ var context = thread.Context;
+
+ StringBuilder sb = new StringBuilder();
+
+ string GetReg(int x)
+ {
+ var v = x == 32 ? (ulong)thread.LastPc : context.GetX(x);
+ if (!AnalyzePointer(out PointerInfo info, v, thread))
+ {
+ return $"0x{v:x16}";
+ }
+ else
+ {
+ if (!string.IsNullOrEmpty(info.ImageName))
+ {
+ return $"0x{v:x16} ({info.ImageDisplay})\t=> {info.SubDisplay}";
+ }
+ else
+ {
+ return $"0x{v:x16} ({info.SpDisplay})";
+ }
+ }
+ }
+
+ for (int i = 0; i <= 28; i++)
+ {
+ sb.AppendLine($"\tX[{i:d2}]:\t{GetReg(i)}");
+ }
+ sb.AppendLine($"\tFP:\t{GetReg(29)}");
+ sb.AppendLine($"\tLR:\t{GetReg(30)}");
+ sb.AppendLine($"\tSP:\t{GetReg(31)}");
+ sb.AppendLine($"\tPC:\t{GetReg(32)}");
+
+ return sb.ToString();
+ }
+
+ private bool TryGetSubName(Image image, ulong address, out ElfSymbol symbol)
{
address -= image.BaseAddress;
@@ -127,18 +158,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
int middle = left + (size >> 1);
- ElfSymbol symbol = image.Symbols[middle];
+ symbol = image.Symbols[middle];
ulong endAddr = symbol.Value + symbol.Size;
- if ((ulong)address >= symbol.Value && (ulong)address < endAddr)
+ if (address >= symbol.Value && address < endAddr)
{
- name = symbol.Name;
-
return true;
}
- if ((ulong)address < (ulong)symbol.Value)
+ if (middle + 1 < image.Symbols.Length)
+ {
+ ElfSymbol next = image.Symbols[middle + 1];
+
+ // If our symbol points inbetween two symbols, we can *guess* that it's referring to the first one
+ if (address >= symbol.Value && address < next.Value)
+ {
+ return true;
+ }
+ }
+
+ if (address < symbol.Value)
{
right = middle - 1;
}
@@ -148,18 +188,100 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- name = null;
+ symbol = default;
+
+ return false;
+ }
+
+ struct PointerInfo
+ {
+ public string ImageName;
+ public string SubName;
+
+ public ulong Offset;
+ public ulong SubOffset;
+
+ public string ImageDisplay => $"{ImageName}:0x{Offset:x4}";
+ public string SubDisplay => SubOffset == 0 ? SubName : $"{SubName}:0x{SubOffset:x4}";
+ public string SpDisplay => SubOffset == 0 ? "SP" : $"SP:-0x{SubOffset:x4}";
+ }
+
+ private bool AnalyzePointer(out PointerInfo info, ulong address, KThread thread)
+ {
+ if (AnalyzePointerFromImages(out info, address))
+ {
+ return true;
+ }
+
+ if (AnalyzePointerFromStack(out info, address, thread))
+ {
+ return true;
+ }
return false;
}
+ private bool AnalyzePointerFromImages(out PointerInfo info, ulong address)
+ {
+ info = default;
+
+ Image image = GetImage(address, out int imageIndex);
+
+ if (image == null)
+ {
+ // Value isn't a pointer to a known image...
+ return false;
+ }
+
+ info.Offset = address - image.BaseAddress;
+
+ // Try to find what this pointer is referring to
+ if (TryGetSubName(image, address, out ElfSymbol symbol))
+ {
+ info.SubName = symbol.Name;
+
+ // Demangle string if possible
+ if (info.SubName.StartsWith("_Z"))
+ {
+ info.SubName = Demangler.Parse(info.SubName);
+ }
+ info.SubOffset = info.Offset - symbol.Value;
+ }
+ else
+ {
+ info.SubName = "";
+ }
+
+ info.ImageName = GetGuessedNsoNameFromIndex(imageIndex);
+
+ return true;
+ }
+
+ private bool AnalyzePointerFromStack(out PointerInfo info, ulong address, KThread thread)
+ {
+ info = default;
+
+ ulong sp = thread.Context.GetX(31);
+ var memoryInfo = _owner.MemoryManager.QueryMemory(address);
+ MemoryState memoryState = memoryInfo.State;
+
+ if (!memoryState.HasFlag(MemoryState.Stack)) // Is this pointer within the stack?
+ {
+ return false;
+ }
+
+ info.SubOffset = address - sp;
+
+ return true;
+ }
+
private Image GetImage(ulong address, out int index)
{
lock (_images)
{
for (index = _images.Count - 1; index >= 0; index--)
{
- if (address >= _images[index].BaseAddress)
+ if (address >= _images[index].BaseAddress && address < _images[index].EndAddress)
{
return _images[index];
}
@@ -226,7 +348,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
{
- LoadMod0Symbols(_owner.CpuMemory, info.Address);
+ LoadMod0Symbols(_owner.CpuMemory, info.Address, info.Size);
}
oldAddress = address;
@@ -235,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset)
+ private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset, ulong textSize)
{
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
@@ -315,7 +437,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
lock (_images)
{
- _images.Add(new Image(textOffset, symbols.OrderBy(x => x.Value).ToArray()));
+ _images.Add(new Image(textOffset, textSize, symbols.OrderBy(x => x.Value).ToArray()));
}
}
@@ -351,4 +473,4 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
}
}
-} \ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 15ab82b8..516b53f4 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -1073,6 +1073,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private bool InvalidAccessHandler(ulong va)
{
KernelStatic.GetCurrentThread()?.PrintGuestStackTrace();
+ KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
Logger.Error?.Print(LogClass.Cpu, $"Invalid memory access at virtual address 0x{va:X16}.");
@@ -1082,6 +1083,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
{
KernelStatic.GetCurrentThread().PrintGuestStackTrace();
+ KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
throw new UndefinedInstructionException(e.Address, e.OpCode);
}
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index 238f1226..39161f22 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -1409,6 +1409,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
if ((reason & (1UL << 31)) == 0)
{
currentThread.PrintGuestStackTrace();
+ currentThread.PrintGuestRegisterPrintout();
// As the process is exiting, this is probably caused by emulation termination.
if (currentThread.Owner.State == ProcessState.Exiting)
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index 7ba9e43a..3ea03f16 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -991,7 +991,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public string GetGuestStackTrace()
{
- return Owner.Debugger.GetGuestStackTrace(Context);
+ return Owner.Debugger.GetGuestStackTrace(this);
+ }
+
+ public string GetGuestRegisterPrintout()
+ {
+ return Owner.Debugger.GetCpuRegisterPrintout(this);
}
public void PrintGuestStackTrace()
@@ -999,6 +1004,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Logger.Info?.Print(LogClass.Cpu, $"Guest stack trace:\n{GetGuestStackTrace()}\n");
}
+ public void PrintGuestRegisterPrintout()
+ {
+ Logger.Info?.Print(LogClass.Cpu, $"Guest CPU registers:\n{GetGuestRegisterPrintout()}\n");
+ }
+
public void AddCpuTime(long ticks)
{
Interlocked.Add(ref _totalTimeRunning, ticks);