internal static async Task <EventPipeSession> StartAsync(IpcEndpoint endpoint, IEnumerable <EventPipeProvider> providers, bool requestRundown, int circularBufferMB, CancellationToken cancellationToken) { IpcMessage requestMessage = CreateStartMessage(providers, requestRundown, circularBufferMB); IpcResponse?response = await IpcClient.SendMessageGetContinuationAsync(endpoint, requestMessage, cancellationToken).ConfigureAwait(false); return(CreateSessionFromResponse(endpoint, ref response, nameof(StartAsync))); }
/// <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) { 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: 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; default: throw new ServerErrorException($"SetEnvironmentVariable failed - server responded with unknown command"); } }
/// <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 request = CreateSetEnvironmentVariableMessage(name, value); IpcMessage response = IpcClient.SendMessage(_endpoint, request); ValidateResponseMessage(response, nameof(SetEnvironmentVariable)); }
internal async Task AttachProfilerAsync(TimeSpan attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData, CancellationToken token) { IpcMessage request = CreateAttachProfilerMessage(attachTimeout, profilerGuid, profilerPath, additionalData); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); ValidateResponseMessage(response, nameof(AttachProfilerAsync)); }
internal async Task SetStartupProfilerAsync(Guid profilerGuid, string profilerPath, CancellationToken token) { IpcMessage request = CreateSetStartupProfilerMessage(profilerGuid, profilerPath); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); ValidateResponseMessage(response, nameof(SetStartupProfilerAsync), ValidateResponseOptions.InvalidArgumentIsRequiresSuspension); }
/// <summary> /// Trigger a core dump generation. /// </summary> /// <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> /// <param name="token">The token to monitor for cancellation requests.</param> internal async Task WriteDumpAsync(DumpType dumpType, string dumpPath, bool logDumpGeneration, CancellationToken token) { IpcMessage request = CreateWriteDumpMessage(dumpType, dumpPath, logDumpGeneration); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); ValidateResponseMessage(response, nameof(WriteDumpAsync)); }
/// <summary> /// Set a profiler as the startup profiler. It is only valid to issue this command /// while the runtime is paused at startup. /// </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 request = CreateSetStartupProfilerMessage(profilerGuid, profilerPath); IpcMessage response = IpcClient.SendMessage(_endpoint, request); ValidateResponseMessage(response, nameof(SetStartupProfiler), ValidateResponseOptions.InvalidArgumentIsRequiresSuspension); }
/// <summary> /// Trigger a core dump generation. /// </summary> /// <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) { if (string.IsNullOrEmpty(dumpPath)) { throw new ArgumentNullException($"{nameof(dumpPath)} required"); } byte[] payload = SerializeCoreDump(dumpPath, dumpType, logDumpGeneration); IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)DumpCommandId.GenerateCoreDump, payload); IpcMessage response = IpcClient.SendMessage(_endpoint, message); switch ((DiagnosticsServerResponseId)response.Header.CommandId) { case DiagnosticsServerResponseId.Error: uint hr = BitConverter.ToUInt32(response.Payload, 0); if (hr == (uint)DiagnosticsIpcError.UnknownCommand) { throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}"); } throw new ServerErrorException($"Writing dump failed (HRESULT: 0x{hr:X8})"); case DiagnosticsServerResponseId.OK: return; default: throw new ServerErrorException($"Writing dump failed - server responded with unknown command"); } }
internal async Task ResumeRuntimeAsync(CancellationToken token) { IpcMessage request = CreateResumeRuntimeMessage(); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); ValidateResponseMessage(response, nameof(ResumeRuntimeAsync)); }
/// <summary> /// Attach a profiler. /// </summary> /// <param name="attachTimeout">Timeout for attaching the profiler</param> /// <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) { 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 = SerializeProfilerAttach((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) { case DiagnosticsServerResponseId.Error: var hr = BitConverter.ToInt32(response.Payload, 0); throw new ServerErrorException($"Profiler attach failed (HRESULT: 0x{hr:X8})"); case DiagnosticsServerResponseId.OK: return; default: throw new ServerErrorException($"Profiler attach failed - server responded with unknown command"); } // The call to set up the pipe and send the message operates on a different timeout than attachTimeout, which is for the runtime. // We should eventually have a configurable timeout for the message passing, potentially either separately from the // runtime timeout or respect attachTimeout as one total duration. }
internal async Task SetEnvironmentVariableAsync(string name, string value, CancellationToken token) { IpcMessage request = CreateSetEnvironmentVariableMessage(name, value); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); ValidateResponseMessage(response, nameof(SetEnvironmentVariableAsync)); }
private bool disposedValue = false; // To detect redundant calls internal EventPipeSession(IpcEndpoint endpoint, IEnumerable <EventPipeProvider> providers, bool requestRundown, int circularBufferMB) { _endpoint = endpoint; _providers = providers; _requestRundown = requestRundown; _circularBufferMB = circularBufferMB; var config = new EventPipeSessionConfiguration(circularBufferMB, EventPipeSerializationFormat.NetTrace, providers, requestRundown); var message = new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.CollectTracing2, config.SerializeV2()); EventStream = IpcClient.SendMessage(endpoint, message, out var response); switch ((DiagnosticsServerResponseId)response.Header.CommandId) { case DiagnosticsServerResponseId.OK: _sessionId = BitConverter.ToInt64(response.Payload, 0); break; case DiagnosticsServerResponseId.Error: var hr = BitConverter.ToInt32(response.Payload, 0); throw new ServerErrorException($"EventPipe session start failed (HRESULT: 0x{hr:X8})"); default: throw new ServerErrorException($"EventPipe session start failed - Server responded with unknown command"); } }
///<summary> /// Stops the given session ///</summary> public void Stop() { Debug.Assert(_sessionId > 0); byte[] payload = BitConverter.GetBytes(_sessionId); IpcMessage response; try { response = IpcClient.SendMessage(_endpoint, new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.StopTracing, payload)); } // On non-abrupt exits (i.e. the target process has already exited and pipe is gone, sending Stop command will fail). catch (IOException) { throw new ServerNotAvailableException("Could not send Stop command. The target process may have exited."); } switch ((DiagnosticsServerResponseId)response.Header.CommandId) { case DiagnosticsServerResponseId.OK: return; case DiagnosticsServerResponseId.Error: var hr = BitConverter.ToInt32(response.Payload, 0); throw new ServerErrorException($"EventPipe session stop failed (HRESULT: 0x{hr:X8})"); default: throw new ServerErrorException($"EventPipe session stop failed - Server responded with unknown command"); } }
internal static EventPipeSession Start(IpcEndpoint endpoint, IEnumerable <EventPipeProvider> providers, bool requestRundown, int circularBufferMB) { IpcMessage requestMessage = CreateStartMessage(providers, requestRundown, circularBufferMB); IpcResponse?response = IpcClient.SendMessageGetContinuation(endpoint, requestMessage); return(CreateSessionFromResponse(endpoint, ref response, nameof(Start))); }
/// <summary> /// Tell the runtime to resume execution after being paused at startup. /// </summary> public void ResumeRuntime() { IpcMessage request = CreateResumeRuntimeMessage(); IpcMessage response = IpcClient.SendMessage(_endpoint, request); ValidateResponseMessage(response, nameof(ResumeRuntime)); }
/// <summary> /// Trigger a core dump generation. /// </summary> /// <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) { IpcMessage request = CreateWriteDumpMessage(dumpType, dumpPath, logDumpGeneration); IpcMessage response = IpcClient.SendMessage(_endpoint, request); ValidateResponseMessage(response, nameof(WriteDump)); }
/// <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() { IpcMessage message = CreateProcessEnvironmentMessage(); using IpcResponse response = IpcClient.SendMessageGetContinuation(_endpoint, message); ValidateResponseMessage(response.Message, nameof(GetProcessEnvironmentAsync)); ProcessEnvironmentHelper helper = ProcessEnvironmentHelper.Parse(response.Message.Payload); return(helper.ReadEnvironment(response.Continuation)); }
/// <summary> /// Attach a profiler. /// </summary> /// <param name="attachTimeout">Timeout for attaching the profiler</param> /// <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) { IpcMessage request = CreateAttachProfilerMessage(attachTimeout, profilerGuid, profilerPath, additionalData); IpcMessage response = IpcClient.SendMessage(_endpoint, request); ValidateResponseMessage(response, nameof(AttachProfiler)); // The call to set up the pipe and send the message operates on a different timeout than attachTimeout, which is for the runtime. // We should eventually have a configurable timeout for the message passing, potentially either separately from the // runtime timeout or respect attachTimeout as one total duration. }
internal async Task <Dictionary <string, string> > GetProcessEnvironmentAsync(CancellationToken token) { IpcMessage message = CreateProcessEnvironmentMessage(); using IpcResponse response = await IpcClient.SendMessageGetContinuationAsync(_endpoint, message, token).ConfigureAwait(false); ValidateResponseMessage(response.Message, nameof(GetProcessEnvironmentAsync)); ProcessEnvironmentHelper helper = ProcessEnvironmentHelper.Parse(response.Message.Payload); return(await helper.ReadEnvironmentAsync(response.Continuation, token).ConfigureAwait(false)); }
/// <summary> /// Trigger a core dump generation. /// </summary> /// <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="flags">logging and crash report flags. On runtimes less than 6.0, only LoggingEnabled is supported.</param> public void WriteDump(DumpType dumpType, string dumpPath, WriteDumpFlags flags) { IpcMessage request = CreateWriteDumpMessage2(dumpType, dumpPath, flags); IpcMessage response = IpcClient.SendMessage(_endpoint, request); if (!ValidateResponseMessage(response, nameof(WriteDump), ValidateResponseOptions.UnknownCommandReturnsFalse)) { if ((flags & ~WriteDumpFlags.LoggingEnabled) != 0) { throw new ArgumentException($"Only {nameof(WriteDumpFlags.LoggingEnabled)} flag is supported by this runtime version", nameof(flags)); } WriteDump(dumpType, dumpPath, logDumpGeneration: (flags & WriteDumpFlags.LoggingEnabled) != 0); } }
/// <summary> /// Trigger a core dump generation. /// </summary> /// <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="flags">logging and crash report flags. On runtimes less than 6.0, only LoggingEnabled is supported.</param> /// <param name="token">The token to monitor for cancellation requests.</param> public async Task WriteDumpAsync(DumpType dumpType, string dumpPath, WriteDumpFlags flags, CancellationToken token) { IpcMessage request = CreateWriteDumpMessage2(dumpType, dumpPath, flags); IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false); if (!ValidateResponseMessage(response, nameof(WriteDumpAsync), ValidateResponseOptions.UnknownCommandReturnsFalse)) { if ((flags & ~WriteDumpFlags.LoggingEnabled) != 0) { throw new ArgumentException($"Only {nameof(WriteDumpFlags.LoggingEnabled)} flag is supported by this runtime version", nameof(flags)); } await WriteDumpAsync(dumpType, dumpPath, logDumpGeneration : (flags & WriteDumpFlags.LoggingEnabled) != 0, token); } }
public async Task StopAsync(CancellationToken cancellationToken) { if (TryCreateStopMessage(out IpcMessage requestMessage)) { try { IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, requestMessage, cancellationToken).ConfigureAwait(false); DiagnosticsClient.ValidateResponseMessage(response, nameof(StopAsync)); } // On non-abrupt exits (i.e. the target process has already exited and pipe is gone, sending Stop command will fail). catch (IOException) { throw new ServerNotAvailableException("Could not send Stop command. The target process may have exited."); } } }
///<summary> /// Stops the given session ///</summary> public void Stop() { if (TryCreateStopMessage(out IpcMessage requestMessage)) { try { IpcMessage response = IpcClient.SendMessage(_endpoint, requestMessage); DiagnosticsClient.ValidateResponseMessage(response, nameof(Stop)); } // On non-abrupt exits (i.e. the target process has already exited and pipe is gone, sending Stop command will fail). catch (IOException) { throw new ServerNotAvailableException("Could not send Stop command. The target process may have exited."); } } }
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"); } }
// 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"); } }
/// <summary> /// Tell the runtime to resume execution after being paused for "reverse server" mode. /// </summary> public void ResumeRuntime() { IpcMessage message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ResumeRuntime); var response = IpcClient.SendMessage(_endpoint, message); switch ((DiagnosticsServerResponseId)response.Header.CommandId) { case DiagnosticsServerResponseId.Error: // Try fallback for Preview 7 and Preview 8 ResumeRuntimeFallback(); return; case DiagnosticsServerResponseId.OK: return; default: throw new ServerErrorException($"Resume runtime failed - server responded with unknown command"); } }
///<summary> /// Stops the given session ///</summary> public void Stop() { Debug.Assert(_sessionId > 0); byte[] payload = BitConverter.GetBytes(_sessionId); var response = IpcClient.SendMessage(_processId, new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.StopTracing, payload)); switch ((DiagnosticsServerCommandId)response.Header.CommandId) { case DiagnosticsServerCommandId.OK: return; case DiagnosticsServerCommandId.Error: var hr = BitConverter.ToInt32(response.Payload, 0); throw new ServerErrorException($"EventPipe session stop failed (HRESULT: 0x{hr:X8})"); default: throw new ServerErrorException($"EventPipe session stop failed - Server responded with unknown command"); } }
public Dictionary <string, string> GetProcessEnvironment() { var message = new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessEnvironment); Stream continuation = IpcClient.SendMessage(_endpoint, message, out IpcMessage response); switch ((DiagnosticsServerResponseId)response.Header.CommandId) { case DiagnosticsServerResponseId.Error: int hr = BitConverter.ToInt32(response.Payload, 0); 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); envTask.Wait(); return(envTask.Result); default: throw new ServerErrorException($"Get process environment failed - server responded with unknown command"); } }
/// <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) { 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: 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($"Profiler startup failed - server responded with unknown command"); } }
/// <summary> /// Checks that the client is able to communicate with target process over diagnostic transport. /// </summary> /// <returns> /// True if client is able to communicate with target process; otherwise, false. /// </returns> public bool CheckTransport() { return(IpcClient.CheckTransport(_processId)); }