HleProcessDebugger.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.HLE.HOS.Diagnostics.Demangler;
  5. using Ryujinx.HLE.Loaders.Elf;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. namespace Ryujinx.HLE.HOS.Kernel
  11. {
  12. class HleProcessDebugger
  13. {
  14. private const int Mod0 = 'M' << 0 | 'O' << 8 | 'D' << 16 | '0' << 24;
  15. private KProcess Owner;
  16. private class Image
  17. {
  18. public long BaseAddress { get; private set; }
  19. public ElfSymbol[] Symbols { get; private set; }
  20. public Image(long BaseAddress, ElfSymbol[] Symbols)
  21. {
  22. this.BaseAddress = BaseAddress;
  23. this.Symbols = Symbols;
  24. }
  25. }
  26. private List<Image> Images;
  27. private int Loaded;
  28. public HleProcessDebugger(KProcess Owner)
  29. {
  30. this.Owner = Owner;
  31. Images = new List<Image>();
  32. }
  33. public void PrintGuestStackTrace(CpuThreadState ThreadState)
  34. {
  35. EnsureLoaded();
  36. StringBuilder Trace = new StringBuilder();
  37. Trace.AppendLine("Guest stack trace:");
  38. void AppendTrace(long Address)
  39. {
  40. Image Image = GetImage(Address, out int ImageIndex);
  41. if (Image == null || !TryGetSubName(Image, Address, out string SubName))
  42. {
  43. SubName = $"Sub{Address:x16}";
  44. }
  45. else if (SubName.StartsWith("_Z"))
  46. {
  47. SubName = Demangler.Parse(SubName);
  48. }
  49. if (Image != null)
  50. {
  51. long Offset = Address - Image.BaseAddress;
  52. string ImageName = GetGuessedNsoNameFromIndex(ImageIndex);
  53. string ImageNameAndOffset = $"[{Owner.Name}] {ImageName}:0x{Offset:x8}";
  54. Trace.AppendLine($" {ImageNameAndOffset} {SubName}");
  55. }
  56. else
  57. {
  58. Trace.AppendLine($" [{Owner.Name}] ??? {SubName}");
  59. }
  60. }
  61. long FramePointer = (long)ThreadState.X29;
  62. while (FramePointer != 0)
  63. {
  64. if ((FramePointer & 7) != 0 ||
  65. !Owner.CpuMemory.IsMapped(FramePointer) ||
  66. !Owner.CpuMemory.IsMapped(FramePointer + 8))
  67. {
  68. break;
  69. }
  70. //Note: This is the return address, we need to subtract one instruction
  71. //worth of bytes to get the branch instruction address.
  72. AppendTrace(Owner.CpuMemory.ReadInt64(FramePointer + 8) - 4);
  73. FramePointer = Owner.CpuMemory.ReadInt64(FramePointer);
  74. }
  75. Logger.PrintInfo(LogClass.Cpu, Trace.ToString());
  76. }
  77. private bool TryGetSubName(Image Image, long Address, out string Name)
  78. {
  79. Address -= Image.BaseAddress;
  80. int Left = 0;
  81. int Right = Image.Symbols.Length - 1;
  82. while (Left <= Right)
  83. {
  84. int Size = Right - Left;
  85. int Middle = Left + (Size >> 1);
  86. ElfSymbol Symbol = Image.Symbols[Middle];
  87. long EndAddr = Symbol.Value + Symbol.Size;
  88. if ((ulong)Address >= (ulong)Symbol.Value && (ulong)Address < (ulong)EndAddr)
  89. {
  90. Name = Symbol.Name;
  91. return true;
  92. }
  93. if ((ulong)Address < (ulong)Symbol.Value)
  94. {
  95. Right = Middle - 1;
  96. }
  97. else
  98. {
  99. Left = Middle + 1;
  100. }
  101. }
  102. Name = null;
  103. return false;
  104. }
  105. private Image GetImage(long Address, out int Index)
  106. {
  107. lock (Images)
  108. {
  109. for (Index = Images.Count - 1; Index >= 0; Index--)
  110. {
  111. if ((ulong)Address >= (ulong)Images[Index].BaseAddress)
  112. {
  113. return Images[Index];
  114. }
  115. }
  116. }
  117. return null;
  118. }
  119. private string GetGuessedNsoNameFromIndex(int Index)
  120. {
  121. if ((uint)Index > 11)
  122. {
  123. return "???";
  124. }
  125. if (Index == 0)
  126. {
  127. return "rtld";
  128. }
  129. else if (Index == 1)
  130. {
  131. return "main";
  132. }
  133. else if (Index == GetImagesCount() - 1)
  134. {
  135. return "sdk";
  136. }
  137. else
  138. {
  139. return "subsdk" + (Index - 2);
  140. }
  141. }
  142. private int GetImagesCount()
  143. {
  144. lock (Images)
  145. {
  146. return Images.Count;
  147. }
  148. }
  149. private void EnsureLoaded()
  150. {
  151. if (Interlocked.CompareExchange(ref Loaded, 1, 0) == 0)
  152. {
  153. ScanMemoryForTextSegments();
  154. }
  155. }
  156. private void ScanMemoryForTextSegments()
  157. {
  158. ulong OldAddress = 0;
  159. ulong Address = 0;
  160. while (Address >= OldAddress)
  161. {
  162. KMemoryInfo Info = Owner.MemoryManager.QueryMemory(Address);
  163. if (Info.State == MemoryState.Reserved)
  164. {
  165. break;
  166. }
  167. if (Info.State == MemoryState.CodeStatic && Info.Permission == MemoryPermission.ReadAndExecute)
  168. {
  169. LoadMod0Symbols(Owner.CpuMemory, (long)Info.Address);
  170. }
  171. OldAddress = Address;
  172. Address = Info.Address + Info.Size;
  173. }
  174. }
  175. private void LoadMod0Symbols(MemoryManager Memory, long TextOffset)
  176. {
  177. long Mod0Offset = TextOffset + Memory.ReadUInt32(TextOffset + 4);
  178. if (Mod0Offset < TextOffset || !Memory.IsMapped(Mod0Offset) || (Mod0Offset & 3) != 0)
  179. {
  180. return;
  181. }
  182. Dictionary<ElfDynamicTag, long> Dynamic = new Dictionary<ElfDynamicTag, long>();
  183. int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
  184. if (Mod0Magic != Mod0)
  185. {
  186. return;
  187. }
  188. long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset;
  189. long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset;
  190. long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset;
  191. long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset;
  192. long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset;
  193. long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset;
  194. while (true)
  195. {
  196. long TagVal = Memory.ReadInt64(DynamicOffset + 0);
  197. long Value = Memory.ReadInt64(DynamicOffset + 8);
  198. DynamicOffset += 0x10;
  199. ElfDynamicTag Tag = (ElfDynamicTag)TagVal;
  200. if (Tag == ElfDynamicTag.DT_NULL)
  201. {
  202. break;
  203. }
  204. Dynamic[Tag] = Value;
  205. }
  206. if (!Dynamic.TryGetValue(ElfDynamicTag.DT_STRTAB, out long StrTab) ||
  207. !Dynamic.TryGetValue(ElfDynamicTag.DT_SYMTAB, out long SymTab) ||
  208. !Dynamic.TryGetValue(ElfDynamicTag.DT_SYMENT, out long SymEntSize))
  209. {
  210. return;
  211. }
  212. long StrTblAddr = TextOffset + StrTab;
  213. long SymTblAddr = TextOffset + SymTab;
  214. List<ElfSymbol> Symbols = new List<ElfSymbol>();
  215. while ((ulong)SymTblAddr < (ulong)StrTblAddr)
  216. {
  217. ElfSymbol Sym = GetSymbol(Memory, SymTblAddr, StrTblAddr);
  218. Symbols.Add(Sym);
  219. SymTblAddr += SymEntSize;
  220. }
  221. lock (Images)
  222. {
  223. Images.Add(new Image(TextOffset, Symbols.OrderBy(x => x.Value).ToArray()));
  224. }
  225. }
  226. private ElfSymbol GetSymbol(MemoryManager Memory, long Address, long StrTblAddr)
  227. {
  228. int NameIndex = Memory.ReadInt32(Address + 0);
  229. int Info = Memory.ReadByte (Address + 4);
  230. int Other = Memory.ReadByte (Address + 5);
  231. int SHIdx = Memory.ReadInt16(Address + 6);
  232. long Value = Memory.ReadInt64(Address + 8);
  233. long Size = Memory.ReadInt64(Address + 16);
  234. string Name = string.Empty;
  235. for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;)
  236. {
  237. Name += (char)Chr;
  238. }
  239. return new ElfSymbol(Name, Info, Other, SHIdx, Value, Size);
  240. }
  241. }
  242. }