feat: resolve real module names in HLE debugger (ryubing/ryujinx!147)

See merge request ryubing/ryujinx!147
This commit is contained in:
Alula 2025-09-20 07:05:44 -05:00 committed by LotP
parent 00ff3e6b1b
commit a6cb681f10
2 changed files with 74 additions and 30 deletions

View File

@ -1105,7 +1105,7 @@ namespace Ryujinx.HLE.Debugger
{
var image = images[i];
ulong endAddress = image.BaseAddress + image.Size - 1;
string name = debugger.GetGuessedNsoNameFromIndex(i);
string name = image.Name;
sb.AppendLine($" 0x{image.BaseAddress:x10} - 0x{endAddress:x10} {name}");
}
}

View File

@ -20,6 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public class Image
{
public string Name { get; internal set; }
public ulong BaseAddress { get; }
public ulong Size { get; }
public ulong EndAddress => BaseAddress + Size;
@ -31,6 +32,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
BaseAddress = baseAddress;
Size = size;
Symbols = symbols;
Name = "(unknown)";
}
}
@ -60,7 +62,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
if (!String.IsNullOrEmpty(ThreadName))
{
trace.AppendLine($"Thread ID: {thread.ThreadUid} ({ThreadName})");
} else {
}
else
{
trace.AppendLine($"Thread ID: {thread.ThreadUid}");
}
@ -254,11 +258,66 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
info.SubName = string.Empty;
}
info.ImageName = GetGuessedNsoNameFromIndex(imageIndex);
info.ImageName = image.Name;
return true;
}
private bool GetModuleName(out string moduleName, Image image)
{
moduleName = string.Empty;
var rodataStart = image.BaseAddress + image.Size;
KMemoryInfo roInfo = _owner.MemoryManager.QueryMemory(rodataStart);
if (roInfo.Permission != KMemoryPermission.Read)
{
return false;
}
var rwdataStart = roInfo.Address + roInfo.Size;
try
{
Span<byte> rodataBuf = stackalloc byte[0x208];
_owner.CpuMemory.Read(rodataStart, rodataBuf);
ulong deprecatedRwDataOffset = BitConverter.ToUInt64(rodataBuf);
// no name if using old format
if (image.BaseAddress + deprecatedRwDataOffset == rwdataStart)
{
return false;
}
uint zero = BitConverter.ToUInt32(rodataBuf);
int pathLength = BitConverter.ToInt32(rodataBuf.Slice(4));
if (zero != 0 || pathLength <= 0)
{
// try again with 12 byte offset, 20.0.0+
_owner.CpuMemory.Read(rodataStart + 12, rodataBuf);
zero = BitConverter.ToUInt32(rodataBuf);
pathLength = BitConverter.ToInt32(rodataBuf.Slice(4));
}
if (zero != 0 || pathLength <= 0)
{
return false;
}
pathLength = Math.Min(pathLength, rodataBuf.Length - 8);
var pathBuf = rodataBuf.Slice(8, pathLength);
int lastSlash = pathBuf.LastIndexOfAny(new byte[] { (byte)'\\', (byte)'/' });
moduleName = Encoding.ASCII.GetString(pathBuf.Slice(lastSlash + 1).TrimEnd((byte)0));
return true;
}
catch (InvalidMemoryRegionException)
{
return false;
}
}
private bool AnalyzePointerFromStack(out PointerInfo info, ulong address, KThread thread)
{
info = default;
@ -293,31 +352,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return null;
}
public string GetGuessedNsoNameFromIndex(int index)
{
if ((uint)index > 11)
{
return "???";
}
if (index == 0)
{
return "rtld";
}
else if (index == 1)
{
return "main";
}
else if (index == GetImagesCount() - 1)
{
return "sdk";
}
else
{
return "subsdk" + (index - 2);
}
}
private int GetImagesCount()
{
lock (_images)
@ -329,7 +363,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public List<Image> GetLoadedImages()
{
EnsureLoaded();
lock (_images)
{
return [.. _images];
@ -449,7 +483,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
lock (_images)
{
_images.Add(new Image(textOffset, textSize, symbols.OrderBy(x => x.Value).ToArray()));
var image = new Image(textOffset, textSize, symbols.OrderBy(x => x.Value).ToArray());
string moduleName;
if (!GetModuleName(out moduleName, image))
{
var newIndex = _images.Count;
moduleName = $"(unknown{newIndex})";
}
image.Name = moduleName;
_images.Add(image);
}
}