/// <returns>
/// An EventPipeSession object representing the EventPipe session that just started.
/// </returns>
- public EventPipeSession StartEventPipeSession(IEnumerable<EventPipeProvider> providers, bool requestRundown=true, int circularBufferMB=256)
+ public EventPipeSession StartEventPipeSession(IEnumerable<EventPipeProvider> providers, bool requestRundown = true, int circularBufferMB = 256)
{
return new EventPipeSession(_endpoint, providers, requestRundown, circularBufferMB);
}
/// <returns>
/// An EventPipeSession object representing the EventPipe session that just started.
/// </returns>
- public EventPipeSession StartEventPipeSession(EventPipeProvider provider, bool requestRundown=true, int circularBufferMB=256)
+ public EventPipeSession StartEventPipeSession(EventPipeProvider provider, bool requestRundown = true, int circularBufferMB = 256)
{
return new EventPipeSession(_endpoint, new[] { provider }, requestRundown, circularBufferMB);
}
/// <param name="dumpType">Type of the dump to be generated</param>
/// <param name="dumpPath">Full path to the dump to be generated. By default it is /tmp/coredump.{pid}</param>
/// <param name="logDumpGeneration">When set to true, display the dump generation debug log to the console.</param>
- public void WriteDump(DumpType dumpType, string dumpPath, bool logDumpGeneration=false)
+ public void WriteDump(DumpType dumpType, string dumpPath, bool logDumpGeneration = false)
{
if (string.IsNullOrEmpty(dumpPath))
throw new ArgumentNullException($"{nameof(dumpPath)} required");
- byte[] payload = SerializeCoreDump(dumpPath, dumpType, logDumpGeneration);
+ byte[] payload = SerializePayload(dumpPath, (uint)dumpType, logDumpGeneration);
IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)DumpCommandId.GenerateCoreDump, payload);
IpcMessage response = IpcClient.SendMessage(_endpoint, message);
switch ((DiagnosticsServerResponseId)response.Header.CommandId)
/// <param name="profilerGuid">Guid for the profiler to be attached</param>
/// <param name="profilerPath">Path to the profiler to be attached</param>
/// <param name="additionalData">Additional data to be passed to the profiler</param>
- public void AttachProfiler(TimeSpan attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData=null)
+ public void AttachProfiler(TimeSpan attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData = null)
{
if (profilerGuid == null || profilerGuid == Guid.Empty)
{
throw new ArgumentException($"{nameof(profilerPath)} must be non-null");
}
- byte[] serializedConfiguration = SerializeProfilerAttach((uint)attachTimeout.TotalSeconds, profilerGuid, profilerPath, additionalData);
+ byte[] serializedConfiguration = SerializePayload((uint)attachTimeout.TotalSeconds, profilerGuid, profilerPath, additionalData);
var message = new IpcMessage(DiagnosticsServerCommandSet.Profiler, (byte)ProfilerCommandId.AttachProfiler, serializedConfiguration);
var response = IpcClient.SendMessage(_endpoint, message);
switch ((DiagnosticsServerResponseId)response.Header.CommandId)
uint hr = BitConverter.ToUInt32(response.Payload, 0);
if (hr == (uint)DiagnosticsIpcError.UnknownCommand)
{
- throw new UnsupportedCommandException("The target runtime does not support profiler attach");
+ throw new UnsupportedCommandException("The target runtime does not support profiler attach");
}
if (hr == (uint)DiagnosticsIpcError.ProfilerAlreadyActive)
{
// runtime timeout or respect attachTimeout as one total duration.
}
- internal void ResumeRuntime()
+ /// <summary>
+ /// Set a profiler as the startup profiler. It is only valid to issue this command
+ /// while the runtime is paused in the "reverse server" mode.
+ /// </summary>
+ /// <param name="profilerGuid">Guid for the profiler to be attached</param>
+ /// <param name="profilerPath">Path to the profiler to be attached</param>
+ public void SetStartupProfiler(Guid profilerGuid, string profilerPath)
{
- IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ResumeRuntime);
+ if (profilerGuid == null || profilerGuid == Guid.Empty)
+ {
+ throw new ArgumentException($"{nameof(profilerGuid)} must be a valid Guid");
+ }
+
+ if (String.IsNullOrEmpty(profilerPath))
+ {
+ throw new ArgumentException($"{nameof(profilerPath)} must be non-null");
+ }
+
+ byte[] serializedConfiguration = SerializePayload(profilerGuid, profilerPath);
+ var message = new IpcMessage(DiagnosticsServerCommandSet.Profiler, (byte)ProfilerCommandId.StartupProfiler, serializedConfiguration);
var response = IpcClient.SendMessage(_endpoint, message);
switch ((DiagnosticsServerResponseId)response.Header.CommandId)
{
case DiagnosticsServerResponseId.Error:
- // Try fallback for Preview 7 and Preview 8
- ResumeRuntimeFallback();
- //var hr = BitConverter.ToInt32(response.Payload, 0);
- //throw new ServerErrorException($"Resume runtime failed (HRESULT: 0x{hr:X8})");
- return;
+ uint hr = BitConverter.ToUInt32(response.Payload, 0);
+ if (hr == (uint)DiagnosticsIpcError.UnknownCommand)
+ {
+ throw new UnsupportedCommandException("The target runtime does not support the ProfilerStartup command.");
+ }
+ else if (hr == (uint)DiagnosticsIpcError.InvalidArgument)
+ {
+ throw new ServerErrorException("The runtime must be suspended to issue the SetStartupProfiler command.");
+ }
+
+ throw new ServerErrorException($"Profiler startup failed (HRESULT: 0x{hr:X8})");
case DiagnosticsServerResponseId.OK:
return;
default:
- throw new ServerErrorException($"Resume runtime failed - server responded with unknown command");
+ throw new ServerErrorException($"Profiler startup failed - server responded with unknown command");
}
}
- // Fallback command for .NET 5 Preview 7 and Preview 8
- internal void ResumeRuntimeFallback()
+ /// <summary>
+ /// Tell the runtime to resume execution after being paused for "reverse server" mode.
+ /// </summary>
+ public void ResumeRuntime()
{
- IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Server, (byte)DiagnosticServerCommandId.ResumeRuntime);
+ IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ResumeRuntime);
var response = IpcClient.SendMessage(_endpoint, message);
switch ((DiagnosticsServerResponseId)response.Header.CommandId)
{
case DiagnosticsServerResponseId.Error:
- var hr = BitConverter.ToInt32(response.Payload, 0);
- throw new ServerErrorException($"Resume runtime failed (HRESULT: 0x{hr:X8})");
+ // Try fallback for Preview 7 and Preview 8
+ ResumeRuntimeFallback();
+ return;
case DiagnosticsServerResponseId.OK:
return;
default:
}
}
- internal ProcessInfo GetProcessInfo()
+ /// <summary>
+ /// Set an environment variable in the target process.
+ /// </summary>
+ /// <param name="name">The name of the environment variable to set.</param>
+ /// <param name="value">The value of the environment variable to set.</param>
+ public void SetEnvironmentVariable(string name, string value)
{
- IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo);
+ if (String.IsNullOrEmpty(name))
+ {
+ throw new ArgumentException($"{nameof(name)} must be non-null.");
+ }
+
+ byte[] serializedConfiguration = SerializePayload(name, value);
+ var message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.SetEnvironmentVariable, serializedConfiguration);
var response = IpcClient.SendMessage(_endpoint, message);
switch ((DiagnosticsServerResponseId)response.Header.CommandId)
{
case DiagnosticsServerResponseId.Error:
- var hr = BitConverter.ToInt32(response.Payload, 0);
- throw new ServerErrorException($"Get process info failed (HRESULT: 0x{hr:X8})");
+ uint hr = BitConverter.ToUInt32(response.Payload, 0);
+ if (hr == (uint)DiagnosticsIpcError.UnknownCommand)
+ {
+ throw new UnsupportedCommandException("The target runtime does not support the SetEnvironmentVariable command.");
+ }
+
+ throw new ServerErrorException($"SetEnvironmentVariable failed (HRESULT: 0x{hr:X8})");
case DiagnosticsServerResponseId.OK:
- return ProcessInfo.Parse(response.Payload);
+ return;
default:
- throw new ServerErrorException($"Get process info failed - server responded with unknown command");
+ throw new ServerErrorException($"SetEnvironmentVariable failed - server responded with unknown command");
}
}
- public Dictionary<string,string> GetProcessEnvironment()
+ /// <summary>
+ /// Gets all environement variables and their values from the target process.
+ /// </summary>
+ /// <returns>A dictionary containing all of the environment variables defined in the target process.</returns>
+ public Dictionary<string, string> GetProcessEnvironment()
{
var message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessEnvironment);
Stream continuation = IpcClient.SendMessage(_endpoint, message, out IpcMessage response);
throw new ServerErrorException($"Get process environment failed (HRESULT: 0x{hr:X8})");
case DiagnosticsServerResponseId.OK:
ProcessEnvironmentHelper helper = ProcessEnvironmentHelper.Parse(response.Payload);
- Task<Dictionary<string,string>> envTask = helper.ReadEnvironmentAsync(continuation);
+ Task<Dictionary<string, string>> envTask = helper.ReadEnvironmentAsync(continuation);
envTask.Wait();
return envTask.Result;
default:
return GetAllPublishedProcesses().Distinct();
}
- private static byte[] SerializeCoreDump(string dumpName, DumpType dumpType, bool diagnostics)
+
+ // Fallback command for .NET 5 Preview 7 and Preview 8
+ internal void ResumeRuntimeFallback()
+ {
+ IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Server, (byte)DiagnosticServerCommandId.ResumeRuntime);
+ var response = IpcClient.SendMessage(_endpoint, message);
+ switch ((DiagnosticsServerResponseId)response.Header.CommandId)
+ {
+ case DiagnosticsServerResponseId.Error:
+ var hr = BitConverter.ToInt32(response.Payload, 0);
+ throw new ServerErrorException($"Resume runtime failed (HRESULT: 0x{hr:X8})");
+ case DiagnosticsServerResponseId.OK:
+ return;
+ default:
+ throw new ServerErrorException($"Resume runtime failed - server responded with unknown command");
+ }
+ }
+
+ internal ProcessInfo GetProcessInfo()
+ {
+ IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo);
+ var response = IpcClient.SendMessage(_endpoint, message);
+ switch ((DiagnosticsServerResponseId)response.Header.CommandId)
+ {
+ case DiagnosticsServerResponseId.Error:
+ var hr = BitConverter.ToInt32(response.Payload, 0);
+ throw new ServerErrorException($"Get process info failed (HRESULT: 0x{hr:X8})");
+ case DiagnosticsServerResponseId.OK:
+ return ProcessInfo.Parse(response.Payload);
+ default:
+ throw new ServerErrorException($"Get process info failed - server responded with unknown command");
+ }
+ }
+
+ private static byte[] SerializePayload<T>(T arg)
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
- writer.WriteString(dumpName);
- writer.Write((uint)dumpType);
- writer.Write((uint)(diagnostics ? 1 : 0));
+ SerializePayloadArgument(arg, writer);
writer.Flush();
return stream.ToArray();
}
}
- private static byte[] SerializeProfilerAttach(uint attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData)
+ private static byte[] SerializePayload<T1, T2>(T1 arg1, T2 arg2)
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
- writer.Write(attachTimeout);
- writer.Write(profilerGuid.ToByteArray());
- writer.WriteString(profilerPath);
+ SerializePayloadArgument(arg1, writer);
+ SerializePayloadArgument(arg2, writer);
- if (additionalData == null)
- {
- writer.Write(0);
- }
- else
- {
- writer.Write(additionalData.Length);
- writer.Write(additionalData);
- }
+ writer.Flush();
+ return stream.ToArray();
+ }
+ }
+
+ private static byte[] SerializePayload<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ SerializePayloadArgument(arg1, writer);
+ SerializePayloadArgument(arg2, writer);
+ SerializePayloadArgument(arg3, writer);
writer.Flush();
return stream.ToArray();
}
}
+
+ private static byte[] SerializePayload<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ SerializePayloadArgument(arg1, writer);
+ SerializePayloadArgument(arg2, writer);
+ SerializePayloadArgument(arg3, writer);
+ SerializePayloadArgument(arg4, writer);
+
+ writer.Flush();
+ return stream.ToArray();
+ }
+ }
+
+ private static void SerializePayloadArgument<T>(T obj, BinaryWriter writer)
+ {
+ if (typeof(T) == typeof(string))
+ {
+ writer.WriteString((string)((object)obj));
+ }
+ else if (typeof(T) == typeof(int))
+ {
+ writer.Write((int)((object)obj));
+ }
+ else if (typeof(T) == typeof(uint))
+ {
+ writer.Write((uint)((object)obj));
+ }
+ else if (typeof(T) == typeof(bool))
+ {
+ bool bValue = (bool)((object)obj);
+ uint uiValue = bValue ? 1 : 0;
+ writer.Write(uiValue);
+ }
+ else
+ {
+ throw new ArgumentException($"Type {obj.GetType()} is not supported in SerializePayloadArgument, please add it.");
+ }
+ }
}
}