LmLogger.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Common.Memory;
  3. using Ryujinx.Horizon.Common;
  4. using Ryujinx.Horizon.LogManager.Types;
  5. using Ryujinx.Horizon.Sdk.Lm;
  6. using Ryujinx.Horizon.Sdk.Sf;
  7. using Ryujinx.Horizon.Sdk.Sf.Hipc;
  8. using System;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.InteropServices;
  11. using System.Text;
  12. namespace Ryujinx.Horizon.LogManager.Ipc
  13. {
  14. partial class LmLogger : ILmLogger
  15. {
  16. private const int MessageLengthLimit = 5000;
  17. private readonly LogService _log;
  18. private readonly ulong _pid;
  19. private LogPacket _logPacket;
  20. public LmLogger(LogService log, ulong pid)
  21. {
  22. _log = log;
  23. _pid = pid;
  24. _logPacket = new LogPacket();
  25. }
  26. [CmifCommand(0)]
  27. public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message)
  28. {
  29. if (!SetProcessId(message, _pid))
  30. {
  31. return Result.Success;
  32. }
  33. if (LogImpl(message))
  34. {
  35. Logger.Guest?.Print(LogClass.ServiceLm, _logPacket.ToString());
  36. _logPacket = new LogPacket();
  37. }
  38. return Result.Success;
  39. }
  40. [CmifCommand(1)] // 3.0.0+
  41. public Result SetDestination(LogDestination destination)
  42. {
  43. _log.LogDestination = destination;
  44. return Result.Success;
  45. }
  46. private static bool SetProcessId(Span<byte> message, ulong processId)
  47. {
  48. ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0];
  49. uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize;
  50. if (expectedMessageSize != (uint)message.Length)
  51. {
  52. Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X}).");
  53. return false;
  54. }
  55. header.ProcessId = processId;
  56. return true;
  57. }
  58. private bool LogImpl(ReadOnlySpan<byte> message)
  59. {
  60. SpanReader reader = new(message);
  61. LogPacketHeader header = reader.Read<LogPacketHeader>();
  62. bool isHeadPacket = (header.Flags & LogPacketFlags.IsHead) != 0;
  63. bool isTailPacket = (header.Flags & LogPacketFlags.IsTail) != 0;
  64. _logPacket.Severity = header.Severity;
  65. while (reader.Length > 0)
  66. {
  67. int type = ReadUleb128(ref reader);
  68. int size = ReadUleb128(ref reader);
  69. LogDataChunkKey key = (LogDataChunkKey)type;
  70. if (key == LogDataChunkKey.Start)
  71. {
  72. reader.Skip(size);
  73. continue;
  74. }
  75. else if (key == LogDataChunkKey.Stop)
  76. {
  77. break;
  78. }
  79. else if (key == LogDataChunkKey.Line)
  80. {
  81. _logPacket.Line = reader.Read<int>();
  82. }
  83. else if (key == LogDataChunkKey.DropCount)
  84. {
  85. _logPacket.DropCount = reader.Read<long>();
  86. }
  87. else if (key == LogDataChunkKey.Time)
  88. {
  89. _logPacket.Time = reader.Read<long>();
  90. }
  91. else if (key == LogDataChunkKey.Message)
  92. {
  93. string text = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  94. if (isHeadPacket && isTailPacket)
  95. {
  96. _logPacket.Message = text;
  97. }
  98. else
  99. {
  100. _logPacket.Message += text;
  101. if (_logPacket.Message.Length >= MessageLengthLimit)
  102. {
  103. isTailPacket = true;
  104. }
  105. }
  106. }
  107. else if (key == LogDataChunkKey.Filename)
  108. {
  109. _logPacket.Filename = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  110. }
  111. else if (key == LogDataChunkKey.Function)
  112. {
  113. _logPacket.Function = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  114. }
  115. else if (key == LogDataChunkKey.Module)
  116. {
  117. _logPacket.Module = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  118. }
  119. else if (key == LogDataChunkKey.Thread)
  120. {
  121. _logPacket.Thread = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  122. }
  123. else if (key == LogDataChunkKey.ProgramName)
  124. {
  125. _logPacket.ProgramName = Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd();
  126. }
  127. }
  128. return isTailPacket;
  129. }
  130. private static int ReadUleb128(ref SpanReader reader)
  131. {
  132. int result = 0;
  133. int count = 0;
  134. byte encoded;
  135. do
  136. {
  137. encoded = reader.Read<byte>();
  138. result += (encoded & 0x7F) << (7 * count);
  139. count++;
  140. } while ((encoded & 0x80) != 0);
  141. return result;
  142. }
  143. }
  144. }