ServiceNotImplementedException.cs
1 using Ryujinx.Common; 2 using Ryujinx.HLE.HOS; 3 using Ryujinx.HLE.HOS.Ipc; 4 using Ryujinx.HLE.HOS.Services; 5 using System; 6 using System.Diagnostics; 7 using System.Linq; 8 using System.Reflection; 9 using System.Runtime.Serialization; 10 using System.Text; 11 12 namespace Ryujinx.HLE.Exceptions 13 { 14 [Serializable] 15 internal class ServiceNotImplementedException : Exception 16 { 17 public IpcService Service { get; } 18 public ServiceCtx Context { get; } 19 public IpcMessage Request { get; } 20 21 public ServiceNotImplementedException(IpcService service, ServiceCtx context) 22 : this(service, context, "The service call is not implemented.") { } 23 24 public ServiceNotImplementedException(IpcService service, ServiceCtx context, string message) : base(message) 25 { 26 Service = service; 27 Context = context; 28 Request = context.Request; 29 } 30 31 public ServiceNotImplementedException(IpcService service, ServiceCtx context, string message, Exception inner) : base(message, inner) 32 { 33 Service = service; 34 Context = context; 35 Request = context.Request; 36 } 37 38 public override string Message 39 { 40 get 41 { 42 return base.Message + Environment.NewLine + Environment.NewLine + BuildMessage(); 43 } 44 } 45 46 private string BuildMessage() 47 { 48 StringBuilder sb = new(); 49 50 // Print the IPC command details (service name, command ID, and handler) 51 (Type callingType, MethodBase callingMethod) = WalkStackTrace(new StackTrace(this)); 52 53 if (callingType != null && callingMethod != null) 54 { 55 // If the type is past 0xF, we are using TIPC 56 var ipcCommands = Request.Type > IpcMessageType.TipcCloseSession ? Service.TipcCommands : Service.CmifCommands; 57 58 // Find the handler for the method called 59 var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value == callingMethod); 60 var ipcCommandId = ipcHandler.Key; 61 var ipcMethod = ipcHandler.Value; 62 63 if (ipcMethod != null) 64 { 65 sb.AppendLine($"Service Command: {Service.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})"); 66 sb.AppendLine(); 67 } 68 } 69 70 sb.AppendLine("Guest Stack Trace:"); 71 sb.AppendLine(Context.Thread.GetGuestStackTrace()); 72 73 // Print buffer information 74 if (Request.PtrBuff.Count > 0 || 75 Request.SendBuff.Count > 0 || 76 Request.ReceiveBuff.Count > 0 || 77 Request.ExchangeBuff.Count > 0 || 78 Request.RecvListBuff.Count > 0) 79 { 80 sb.AppendLine("Buffer Information:"); 81 82 if (Request.PtrBuff.Count > 0) 83 { 84 sb.AppendLine("\tPtrBuff:"); 85 86 foreach (var buff in Request.PtrBuff) 87 { 88 sb.AppendLine($"\t[{buff.Index}] Position: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); 89 } 90 } 91 92 if (Request.SendBuff.Count > 0) 93 { 94 sb.AppendLine("\tSendBuff:"); 95 96 foreach (var buff in Request.SendBuff) 97 { 98 sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); 99 } 100 } 101 102 if (Request.ReceiveBuff.Count > 0) 103 { 104 sb.AppendLine("\tReceiveBuff:"); 105 106 foreach (var buff in Request.ReceiveBuff) 107 { 108 sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); 109 } 110 } 111 112 if (Request.ExchangeBuff.Count > 0) 113 { 114 sb.AppendLine("\tExchangeBuff:"); 115 116 foreach (var buff in Request.ExchangeBuff) 117 { 118 sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); 119 } 120 } 121 122 if (Request.RecvListBuff.Count > 0) 123 { 124 sb.AppendLine("\tRecvListBuff:"); 125 126 foreach (var buff in Request.RecvListBuff) 127 { 128 sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); 129 } 130 } 131 132 sb.AppendLine(); 133 } 134 135 sb.AppendLine("Raw Request Data:"); 136 sb.Append(HexUtils.HexTable(Request.RawData)); 137 138 return sb.ToString(); 139 } 140 141 private static (Type, MethodBase) WalkStackTrace(StackTrace trace) 142 { 143 int i = 0; 144 145 StackFrame frame; 146 147 // Find the IIpcService method that threw this exception 148 while ((frame = trace.GetFrame(i++)) != null) 149 { 150 var method = frame.GetMethod(); 151 var declType = method.DeclaringType; 152 153 if (typeof(IpcService).IsAssignableFrom(declType)) 154 { 155 return (declType, method); 156 } 157 } 158 159 return (null, null); 160 } 161 } 162 }