|
@@ -1,6 +1,7 @@
|
|
|
using ChocolArm64;
|
|
using ChocolArm64;
|
|
|
using ChocolArm64.Events;
|
|
using ChocolArm64.Events;
|
|
|
using ChocolArm64.Memory;
|
|
using ChocolArm64.Memory;
|
|
|
|
|
+using ChocolArm64.State;
|
|
|
using Ryujinx.Core.Loaders;
|
|
using Ryujinx.Core.Loaders;
|
|
|
using Ryujinx.Core.Loaders.Executables;
|
|
using Ryujinx.Core.Loaders.Executables;
|
|
|
using Ryujinx.Core.OsHle.Exceptions;
|
|
using Ryujinx.Core.OsHle.Exceptions;
|
|
@@ -10,6 +11,7 @@ using Ryujinx.Core.OsHle.Services.Nv;
|
|
|
using System;
|
|
using System;
|
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Concurrent;
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
|
|
+using System.Text;
|
|
|
|
|
|
|
|
namespace Ryujinx.Core.OsHle
|
|
namespace Ryujinx.Core.OsHle
|
|
|
{
|
|
{
|
|
@@ -47,9 +49,11 @@ namespace Ryujinx.Core.OsHle
|
|
|
|
|
|
|
|
private ConcurrentDictionary<long, KThread> Threads;
|
|
private ConcurrentDictionary<long, KThread> Threads;
|
|
|
|
|
|
|
|
|
|
+ private KThread MainThread;
|
|
|
|
|
+
|
|
|
private List<Executable> Executables;
|
|
private List<Executable> Executables;
|
|
|
|
|
|
|
|
- private KThread MainThread;
|
|
|
|
|
|
|
+ private Dictionary<long, string> SymbolTable;
|
|
|
|
|
|
|
|
private long ImageBase;
|
|
private long ImageBase;
|
|
|
|
|
|
|
@@ -121,6 +125,8 @@ namespace Ryujinx.Core.OsHle
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ MakeSymbolTable();
|
|
|
|
|
+
|
|
|
MapRWMemRegion(
|
|
MapRWMemRegion(
|
|
|
MemoryRegions.MainStackAddress,
|
|
MemoryRegions.MainStackAddress,
|
|
|
MemoryRegions.MainStackSize,
|
|
MemoryRegions.MainStackSize,
|
|
@@ -227,20 +233,23 @@ namespace Ryujinx.Core.OsHle
|
|
|
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
|
|
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private ATranslator GetTranslator()
|
|
|
|
|
|
|
+ private void MakeSymbolTable()
|
|
|
{
|
|
{
|
|
|
- if (Translator == null)
|
|
|
|
|
- {
|
|
|
|
|
- Dictionary<long, string> SymbolTable = new Dictionary<long, string>();
|
|
|
|
|
|
|
+ SymbolTable = new Dictionary<long, string>();
|
|
|
|
|
|
|
|
- foreach (Executable Exe in Executables)
|
|
|
|
|
|
|
+ foreach (Executable Exe in Executables)
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
|
|
|
{
|
|
{
|
|
|
- foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
|
|
|
|
|
- {
|
|
|
|
|
- SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ private ATranslator GetTranslator()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (Translator == null)
|
|
|
|
|
+ {
|
|
|
Translator = new ATranslator(SymbolTable);
|
|
Translator = new ATranslator(SymbolTable);
|
|
|
|
|
|
|
|
Translator.CpuTrace += CpuTraceHandler;
|
|
Translator.CpuTrace += CpuTraceHandler;
|
|
@@ -249,6 +258,16 @@ namespace Ryujinx.Core.OsHle
|
|
|
return Translator;
|
|
return Translator;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public void EnableCpuTracing()
|
|
|
|
|
+ {
|
|
|
|
|
+ Translator.EnableCpuTrace = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void DisableCpuTracing()
|
|
|
|
|
+ {
|
|
|
|
|
+ Translator.EnableCpuTrace = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
|
|
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
|
|
|
{
|
|
{
|
|
|
string NsoName = string.Empty;
|
|
string NsoName = string.Empty;
|
|
@@ -263,17 +282,47 @@ namespace Ryujinx.Core.OsHle
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Logging.Trace(LogClass.Loader, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
|
|
|
|
|
|
|
+ Logging.Trace(LogClass.CPU, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public void EnableCpuTracing()
|
|
|
|
|
|
|
+ public void PrintStackTrace(AThreadState ThreadState)
|
|
|
{
|
|
{
|
|
|
- Translator.EnableCpuTrace = true;
|
|
|
|
|
|
|
+ long[] Positions = ThreadState.GetCallStack();
|
|
|
|
|
+
|
|
|
|
|
+ StringBuilder Trace = new StringBuilder();
|
|
|
|
|
+
|
|
|
|
|
+ Trace.AppendLine("Guest stack trace:");
|
|
|
|
|
+
|
|
|
|
|
+ foreach (long Position in Positions)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!SymbolTable.TryGetValue(Position, out string SubName))
|
|
|
|
|
+ {
|
|
|
|
|
+ SubName = $"Sub{Position:x16}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Trace.AppendLine(" " + SubName + " (" + GetNsoNameAndAddress(Position) + ")");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Logging.Trace(LogClass.CPU, Trace.ToString());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public void DisableCpuTracing()
|
|
|
|
|
|
|
+ private string GetNsoNameAndAddress(long Position)
|
|
|
{
|
|
{
|
|
|
- Translator.EnableCpuTrace = false;
|
|
|
|
|
|
|
+ string Name = string.Empty;
|
|
|
|
|
+
|
|
|
|
|
+ for (int Index = Executables.Count - 1; Index >= 0; Index--)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (Position >= Executables[Index].ImageBase)
|
|
|
|
|
+ {
|
|
|
|
|
+ long Offset = Position - Executables[Index].ImageBase;
|
|
|
|
|
+
|
|
|
|
|
+ Name = $"{Executables[Index].Name}:{Offset:x8}";
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Name;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private int GetFreeTlsSlot(AThread Thread)
|
|
private int GetFreeTlsSlot(AThread Thread)
|