diff options
Diffstat (limited to 'src/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs')
| -rw-r--r-- | src/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs b/src/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs new file mode 100644 index 00000000..e930bdd7 --- /dev/null +++ b/src/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs @@ -0,0 +1,176 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.LogManager.Types; +using Ryujinx.Horizon.Sdk.Lm; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.LogManager.Ipc +{ + partial class LmLogger : ILmLogger + { + private const int MessageLengthLimit = 5000; + + private readonly LogService _log; + private readonly ulong _pid; + + private LogPacket _logPacket; + + public LmLogger(LogService log, ulong pid) + { + _log = log; + _pid = pid; + + _logPacket = new LogPacket(); + } + + [CmifCommand(0)] + public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message) + { + if (!SetProcessId(message, _pid)) + { + return Result.Success; + } + + if (LogImpl(message)) + { + Logger.Guest?.Print(LogClass.ServiceLm, _logPacket.ToString()); + + _logPacket = new LogPacket(); + } + + return Result.Success; + } + + [CmifCommand(1)] // 3.0.0+ + public Result SetDestination(LogDestination destination) + { + _log.LogDestination = destination; + + return Result.Success; + } + + private static bool SetProcessId(Span<byte> message, ulong processId) + { + ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0]; + + uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize; + if (expectedMessageSize != (uint)message.Length) + { + Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X})."); + + return false; + } + + header.ProcessId = processId; + + return true; + } + + private bool LogImpl(ReadOnlySpan<byte> message) + { + SpanReader reader = new(message); + LogPacketHeader header = reader.Read<LogPacketHeader>(); + + bool isHeadPacket = (header.Flags & LogPacketFlags.IsHead) != 0; + bool isTailPacket = (header.Flags & LogPacketFlags.IsTail) != 0; + + _logPacket.Severity = header.Severity; + + while (reader.Length > 0) + { + int type = ReadUleb128(ref reader); + int size = ReadUleb128(ref reader); + + LogDataChunkKey key = (LogDataChunkKey)type; + + if (key == LogDataChunkKey.Start) + { + reader.Skip(size); + + continue; + } + else if (key == LogDataChunkKey.Stop) + { + break; + } + else if (key == LogDataChunkKey.Line) + { + _logPacket.Line = reader.Read<int>(); + } + else if (key == LogDataChunkKey.DropCount) + { + _logPacket.DropCount = reader.Read<long>(); + } + else if (key == LogDataChunkKey.Time) + { + _logPacket.Time = reader.Read<long>(); + } + else if (key == LogDataChunkKey.Message) + { + string text = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + + if (isHeadPacket && isTailPacket) + { + _logPacket.Message = text; + } + else + { + _logPacket.Message += text; + + if (_logPacket.Message.Length >= MessageLengthLimit) + { + isTailPacket = true; + } + } + } + else if (key == LogDataChunkKey.Filename) + { + _logPacket.Filename = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + } + else if (key == LogDataChunkKey.Function) + { + _logPacket.Function = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + } + else if (key == LogDataChunkKey.Module) + { + _logPacket.Module = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + } + else if (key == LogDataChunkKey.Thread) + { + _logPacket.Thread = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + } + else if (key == LogDataChunkKey.ProgramName) + { + _logPacket.ProgramName = Encoding.UTF8.GetString(reader.GetSpanSafe(size)).TrimEnd(); + } + } + + return isTailPacket; + } + + private static int ReadUleb128(ref SpanReader reader) + { + int result = 0; + int count = 0; + + byte encoded; + + do + { + encoded = reader.Read<byte>(); + + result += (encoded & 0x7F) << (7 * count); + + count++; + } while ((encoded & 0x80) != 0); + + return result; + } + } +}
\ No newline at end of file |
