mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-06-28 00:16:23 +02:00
gdb: Show thread names
Reference: d8a37b4b71/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp
This commit is contained in:
parent
db22c3af25
commit
22957b9140
2 changed files with 151 additions and 6 deletions
|
@ -34,6 +34,8 @@ namespace Ryujinx.HLE.Debugger
|
||||||
private ulong? cThread;
|
private ulong? cThread;
|
||||||
private ulong? gThread;
|
private ulong? gThread;
|
||||||
|
|
||||||
|
private string previousThreadListXml = "";
|
||||||
|
|
||||||
public Debugger(Switch device, ushort port)
|
public Debugger(Switch device, ushort port)
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
|
@ -368,7 +370,7 @@ namespace Ryujinx.HLE.Debugger
|
||||||
|
|
||||||
if (ss.ConsumePrefix("Supported:") || ss.ConsumeRemaining("Supported"))
|
if (ss.ConsumePrefix("Supported:") || ss.ConsumeRemaining("Supported"))
|
||||||
{
|
{
|
||||||
Reply("PacketSize=10000;qXfer:features:read+");
|
Reply("PacketSize=10000;qXfer:features:read+;qXfer:threads:read+");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,10 +406,43 @@ namespace Ryujinx.HLE.Debugger
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ss.ConsumePrefix("Xfer:threads:read:"))
|
||||||
|
{
|
||||||
|
ss.ReadUntil(':');
|
||||||
|
ulong offset = ss.ReadUntilAsHex(',');
|
||||||
|
ulong len = ss.ReadRemainingAsHex();
|
||||||
|
|
||||||
|
var data = "";
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
data = previousThreadListXml;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
previousThreadListXml = data = GetThreadListXml();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= (ulong)data.Length)
|
||||||
|
{
|
||||||
|
Reply("l");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= (ulong)data.Length - offset)
|
||||||
|
{
|
||||||
|
Reply("l" + ToBinaryFormat(data.Substring((int)offset)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Reply("m" + ToBinaryFormat(data.Substring((int)offset, (int)len)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ss.ConsumePrefix("Xfer:features:read:"))
|
if (ss.ConsumePrefix("Xfer:features:read:"))
|
||||||
{
|
{
|
||||||
string feature = ss.ReadUntil(':');
|
string feature = ss.ReadUntil(':');
|
||||||
ulong addr = ss.ReadUntilAsHex(',');
|
ulong offset = ss.ReadUntilAsHex(',');
|
||||||
ulong len = ss.ReadRemainingAsHex();
|
ulong len = ss.ReadRemainingAsHex();
|
||||||
|
|
||||||
if (feature == "target.xml")
|
if (feature == "target.xml")
|
||||||
|
@ -418,20 +453,20 @@ namespace Ryujinx.HLE.Debugger
|
||||||
string data;
|
string data;
|
||||||
if (RegisterInformation.Features.TryGetValue(feature, out data))
|
if (RegisterInformation.Features.TryGetValue(feature, out data))
|
||||||
{
|
{
|
||||||
if (addr >= (ulong)data.Length)
|
if (offset >= (ulong)data.Length)
|
||||||
{
|
{
|
||||||
Reply("l");
|
Reply("l");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= (ulong)data.Length - addr)
|
if (len >= (ulong)data.Length - offset)
|
||||||
{
|
{
|
||||||
Reply("l" + ToBinaryFormat(data.Substring((int)addr)));
|
Reply("l" + ToBinaryFormat(data.Substring((int)offset)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Reply("m" + ToBinaryFormat(data.Substring((int)addr, (int)len)));
|
Reply("m" + ToBinaryFormat(data.Substring((int)offset, (int)len)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,6 +504,21 @@ namespace Ryujinx.HLE.Debugger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetThreadListXml()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("<?xml version=\"1.0\"?><threads>\n");
|
||||||
|
|
||||||
|
foreach (var thread in GetThreads())
|
||||||
|
{
|
||||||
|
string threadName = System.Security.SecurityElement.Escape(thread.GetThreadName());
|
||||||
|
sb.Append($"<thread id=\"{thread.ThreadUid:x}\" name=\"{threadName}\" />\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("</threads>");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
void CommandQuery()
|
void CommandQuery()
|
||||||
{
|
{
|
||||||
// GDB is performing initial contact. Stop everything.
|
// GDB is performing initial contact. Stop everything.
|
||||||
|
|
|
@ -5,9 +5,11 @@ using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
@ -17,6 +19,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
private const int TlsUserDisableCountOffset = 0x100;
|
private const int TlsUserDisableCountOffset = 0x100;
|
||||||
private const int TlsUserInterruptFlagOffset = 0x102;
|
private const int TlsUserInterruptFlagOffset = 0x102;
|
||||||
|
|
||||||
|
// Tls -> ThreadType
|
||||||
|
private const int TlsThreadTypeOffsetAArch64 = 0x1F8;
|
||||||
|
private const int TlsThreadTypeOffsetAArch32 = 0x1FC;
|
||||||
|
|
||||||
|
// Tls -> ThreadType -> Version
|
||||||
|
private const int TlsThreadTypeVersionOffsetAArch64 = 0x46;
|
||||||
|
private const int TlsThreadTypeVersionOffsetAArch32 = 0x26;
|
||||||
|
|
||||||
|
// Tls -> ThreadType (Version 0) -> ThreadNamePointer
|
||||||
|
private const int TlsThreadTypeVersion0ThreadNamePointerOffsetAArch64 = 0x1A8;
|
||||||
|
private const int TlsThreadTypeVersion0ThreadNamePointerOffsetAArch32 = 0xE8;
|
||||||
|
|
||||||
|
// Tls -> ThreadType (Version 1) -> ThreadNamePointer
|
||||||
|
private const int TlsThreadTypeThreadNamePointerOffsetAArch64 = 0x1A0;
|
||||||
|
private const int TlsThreadTypeThreadNamePointerOffsetAArch32 = 0xE4;
|
||||||
|
|
||||||
|
|
||||||
public const int MaxWaitSyncObjects = 64;
|
public const int MaxWaitSyncObjects = 64;
|
||||||
|
|
||||||
private ManualResetEvent _schedulerWaitEvent;
|
private ManualResetEvent _schedulerWaitEvent;
|
||||||
|
@ -1439,5 +1458,81 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
{
|
{
|
||||||
Owner.CpuMemory.Write<ushort>(_tlsAddress + TlsUserInterruptFlagOffset, 0);
|
Owner.CpuMemory.Write<ushort>(_tlsAddress + TlsUserInterruptFlagOffset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetThreadName()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ulong threadNamePtr = 0;
|
||||||
|
if (Context.IsAarch32)
|
||||||
|
{
|
||||||
|
uint threadTypePtr32 = Owner.CpuMemory.Read<uint>(_tlsAddress + TlsThreadTypeOffsetAArch32);
|
||||||
|
if (threadTypePtr32 == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort version = Owner.CpuMemory.Read<ushort>(threadTypePtr32 + TlsThreadTypeVersionOffsetAArch32);
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case 0x0000:
|
||||||
|
case 0xFFFF:
|
||||||
|
threadNamePtr = Owner.CpuMemory.Read<uint>(threadTypePtr32 + TlsThreadTypeVersion0ThreadNamePointerOffsetAArch32);
|
||||||
|
break;
|
||||||
|
case 0x0001:
|
||||||
|
threadNamePtr = Owner.CpuMemory.Read<uint>(threadTypePtr32 + TlsThreadTypeThreadNamePointerOffsetAArch32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger.Warning?.Print(LogClass.Kernel, $"Unknown ThreadType struct version: {version}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong threadTypePtr64 = Owner.CpuMemory.Read<ulong>(_tlsAddress + TlsThreadTypeOffsetAArch64);
|
||||||
|
if (threadTypePtr64 == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort version = Owner.CpuMemory.Read<ushort>(threadTypePtr64 + TlsThreadTypeVersionOffsetAArch64);
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case 0x0000:
|
||||||
|
case 0xFFFF:
|
||||||
|
threadNamePtr = Owner.CpuMemory.Read<ulong>(threadTypePtr64 + TlsThreadTypeVersion0ThreadNamePointerOffsetAArch64);
|
||||||
|
break;
|
||||||
|
case 0x0001:
|
||||||
|
threadNamePtr = Owner.CpuMemory.Read<ulong>(threadTypePtr64 + TlsThreadTypeThreadNamePointerOffsetAArch64);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger.Warning?.Print(LogClass.Kernel, $"Unknown ThreadType struct version: {version}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threadNamePtr == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte> nameBytes = new();
|
||||||
|
for (int i = 0; i < 0x20; i++)
|
||||||
|
{
|
||||||
|
byte b = Owner.CpuMemory.Read<byte>(threadNamePtr + (ulong)i);
|
||||||
|
if (b == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nameBytes.Add(b);
|
||||||
|
}
|
||||||
|
return Encoding.UTF8.GetString(nameBytes.ToArray());
|
||||||
|
|
||||||
|
} catch (InvalidMemoryRegionException)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Kernel, "Failed to get thread name.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue