Exemple #1
0
        public static async Task <bool> TEST_TracesHaveRelevantEvents()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName}" }
            },
                duringExecution: async(pid) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose)
                });
                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");
                Task readerTask = eventStream.CopyToAsync(memoryStream);

                Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command");
                // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid)
                var message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");

                await Task.Delay(TimeSpan.FromSeconds(2));
                Logger.logger.Log("Stopping EventPipeSession over standard connection");
                EventPipeClient.StopTracing(pid, sessionId);
                await readerTask;
                Logger.logger.Log("Stopped EventPipeSession over standard connection");
            }
                );

            fSuccess &= await subprocessTask;

            memoryStream.Seek(0, SeekOrigin.Begin);
            using var source = new EventPipeEventSource(memoryStream);
            var  parser = new ClrPrivateTraceEventParser(source);
            bool isStartupEventPresent = false;

            parser.StartupEEStartupStart += (eventData) => isStartupEventPresent = true;
            source.Process();

            Logger.logger.Log($"isStartupEventPresent: {isStartupEventPresent}");

            return(isStartupEventPresent && fSuccess);
        }
        /// <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(_processId, message);

            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.Error:
                var hr = BitConverter.ToInt32(response.Payload, 0);
                throw new ServerErrorException($"Profiler attach failed (HRESULT: 0x{hr:X8})");

            case DiagnosticsServerCommandId.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.
        }
        /// <summary>
        /// Initiate a core dump in the target process runtime.
        /// </summary>
        /// <param name="processId">.NET Core process id</param>
        /// <param name="dumpName">Path and file name of core dump</param>
        /// <param name="dumpType">Type of dump</param>
        /// <param name="diagnostics">If true, log to console the dump generation diagnostics</param>
        /// <returns>DiagnosticsServerErrorCode</returns>
        public static int GenerateCoreDump(int processId, string dumpName, DumpType dumpType, bool diagnostics)
        {
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}");
            }

            if (string.IsNullOrEmpty(dumpName))
            {
                throw new ArgumentNullException($"{nameof(dumpName)} required");
            }


            var payload = SerializeCoreDump(dumpName, dumpType, diagnostics);
            var message = new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)DumpCommandId.GenerateCoreDump, payload);

            var response = IpcClient.SendMessage(processId, message);

            var hr = 0;

            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.Error:
            case DiagnosticsServerCommandId.OK:
                hr = BitConverter.ToInt32(response.Payload, 0);
                break;

            default:
                return(-1);
            }

            return(hr);
        }
Exemple #4
0
        public static int Main(string[] args)
        {
            Process currentProcess = Process.GetCurrentProcess();
            int     pid            = currentProcess.Id;

            Logger.logger.Log($"Test PID: {pid}");
            var testEnvPairs = new Dictionary <string, string>
            {
                { "TESTKEY1", "TESTVAL1" },
                { "TESTKEY2", "TESTVAL2" },
                { "TESTKEY3", "__TEST__VAL=;--3" }
            };

            foreach (var(key, val) in testEnvPairs)
            {
                System.Environment.SetEnvironmentVariable(key, val);
            }

            Stream stream = ConnectionHelper.GetStandardTransport(pid);

            // 0x04 = ProcessCommandSet, 0x02 = ProcessInfo
            var processInfoMessage = new IpcMessage(0x04, 0x02);

            Logger.logger.Log($"Wrote: {processInfoMessage}");
            Stream continuationStream = IpcClient.SendMessage(stream, processInfoMessage, out IpcMessage response);

            Logger.logger.Log($"Received: {response}");

            Utils.Assert(response.Header.CommandSet == 0xFF, $"Response must have Server command set. Expected: 0xFF, Received: 0x{response.Header.CommandSet:X2}"); // server
            Utils.Assert(response.Header.CommandId == 0x00, $"Response must have OK command id. Expected: 0x00, Received: 0x{response.Header.CommandId:X2}");        // OK

            UInt32 continuationSizeInBytes = BitConverter.ToUInt32(response.Payload[0..4]);
Exemple #5
0
        public static int Main(string[] args)
        {
            Process currentProcess = Process.GetCurrentProcess();
            int     pid            = currentProcess.Id;

            Logger.logger.Log($"Test PID: {pid}");

            Stream stream = ConnectionHelper.GetStandardTransport(pid);

            // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2
            var processInfoMessage = new IpcMessage(0x04, 0x04);

            Logger.logger.Log($"Wrote: {processInfoMessage}");
            IpcMessage response = IpcClient.SendMessage(stream, processInfoMessage);

            Logger.logger.Log($"Received: <omitted>");

            Utils.Assert(response.Header.CommandSet == 0xFF, $"Response must have Server command set. Expected: 0xFF, Received: 0x{response.Header.CommandSet:X2}"); // server
            Utils.Assert(response.Header.CommandId == 0x00, $"Response must have OK command id. Expected: 0x00, Received: 0x{response.Header.CommandId:X2}");        // OK

            // Parse payload
            // uint64_t ProcessId;
            // GUID RuntimeCookie;
            // LPCWSTR CommandLine;
            // LPCWSTR OS;
            // LPCWSTR Arch;

            int totalSize = response.Payload.Length;

            Logger.logger.Log($"Total size of Payload = {totalSize} bytes");

            // VALIDATE PID
            int    start     = 0;
            int    end       = start + 8 /* sizeof(uint63_t) */;
            UInt64 processId = BitConverter.ToUInt64(response.Payload[start..end]);
        public void SetStartupProfiler(Guid profilerGuid, string profilerPath)
        {
            MethodInfo startupProfiler = typeof(DiagnosticsClient).GetMethod("SetStartupProfiler", BindingFlags.Public);

            if (startupProfiler != null)
            {
                throw new Exception("You updated DiagnosticsClient to a version that supports SetStartupProfiler, please remove this and use the real code.");
            }

            Console.WriteLine("Sending startup profiler message.");

            using (var stream = new MemoryStream())
                using (var writer = new BinaryWriter(stream))
                {
                    writer.Write(profilerGuid.ToByteArray());
                    writer.WriteString(profilerPath);

                    writer.Flush();
                    byte[] payload = stream.ToArray();

                    var message = new IpcMessage(0x03, 0x02, payload);
                    Console.WriteLine($"Sent: {message.ToString()}");
                    IpcMessage response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(_processId), message);
                    Console.WriteLine($"Received: {response.ToString()}");
                }

            Console.WriteLine("Finished sending startup profiler message.");
        }
        private bool disposedValue = false; // To detect redundant calls

        internal EventPipeSession(int processId, IEnumerable <EventPipeProvider> providers, bool requestRundown, int circularBufferMB)
        {
            _processId        = processId;
            _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(processId, message, out var response);
            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.OK:
                _sessionId = BitConverter.ToInt64(response.Payload, 0);
                break;

            case DiagnosticsServerCommandId.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");
            }
        }
Exemple #8
0
        public static int Main(string[] args)
        {
            if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("In RunTest, exiting.");
                return(100);
            }

            string serverName     = ReverseServer.MakeServerAddress();
            Task   backgroundTask = Task.Run(() =>
            {
                ReverseServer server = null;
                try
                {
                    Task task = Task.Run(async() =>
                    {
                        server = new ReverseServer(serverName);
                        using (Stream serverStream = await server.AcceptAsync())
                        {
                            IpcAdvertise advertise = IpcAdvertise.Parse(serverStream);
                            Console.WriteLine($"Got IpcAdvertise: {advertise}");

                            int processId = (int)advertise.ProcessId;

                            // While we are paused in startup send the profiler startup command
                            string profilerPath             = GetProfilerPath();
                            DiagnosticsIPCWorkaround client = new DiagnosticsIPCWorkaround(processId);
                            client.SetStartupProfiler(ReverseStartupProfilerGuid, profilerPath);

                            // Resume runtime message
                            IpcMessage resumeMessage = new IpcMessage(0x04, 0x01);
                            Console.WriteLine($"Sent resume runtime message: {resumeMessage.ToString()}");
                            IpcMessage resumeResponse = IpcClient.SendMessage(serverStream, resumeMessage);
                            Logger.logger.Log($"Received: {resumeResponse.ToString()}");
                        }
                    });

                    task.Wait();
                }
                catch (Exception e)
                {
                    Console.WriteLine($"ReverseServer saw exception {e.Message}");
                    Console.WriteLine(e.StackTrace);


                    Console.WriteLine($"Inner exception {e.InnerException?.Message}");
                    Console.WriteLine(e.InnerException?.StackTrace);
                }
                finally
                {
                    server?.Shutdown();
                }
            });

            return(ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location,
                                          testName: "ReverseStartup",
                                          profilerClsid: Guid.Empty,
                                          profileeOptions: ProfileeOptions.NoStartupAttach | ProfileeOptions.ReverseDiagnosticsMode,
                                          reverseServerName: serverName));
        }
Exemple #9
0
        public static async Task <bool> TEST_CanGetProcessInfo2WhileSuspended()
        {
            bool        fSuccess       = true;
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string>
            {
                { Utils.DiagnosticPortSuspend, "1" }
            },
                duringExecution: (int pid) =>
            {
                Stream stream = ConnectionHelper.GetStandardTransport(pid);

                // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2
                var processInfoMessage = new IpcMessage(0x04, 0x04);
                Logger.logger.Log($"Wrote: {processInfoMessage}");
                IpcMessage response = IpcClient.SendMessage(stream, processInfoMessage);
                Logger.logger.Log($"Received: [{response.Payload.Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
                ProcessInfo2 processInfo2 = ProcessInfo2.TryParse(response.Payload);
                Utils.Assert(String.IsNullOrEmpty(processInfo2.ManagedEntrypointAssemblyName));

                // send resume command on this connection
                var message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(pid), message);
                Logger.logger.Log($"Received: {response.ToString()}");

                return(Task.FromResult(true));
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
Exemple #10
0
        public static async Task <bool> TEST_RuntimeResumesExecutionWithCommand()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var         server         = new ReverseServer(serverName);
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName}" }
            },
                duringExecution: async(_) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());
                // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid)
                var message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
        /// <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 (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}");
            }

            if (string.IsNullOrEmpty(dumpPath))
            {
                throw new ArgumentNullException($"{nameof(dumpPath)} required");
            }

            var payload  = SerializeCoreDump(dumpPath, dumpType, logDumpGeneration);
            var message  = new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)DumpCommandId.GenerateCoreDump, payload);
            var response = IpcClient.SendMessage(_processId, message);
            var hr       = 0;

            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.Error:
                hr = BitConverter.ToInt32(response.Payload, 0);
                throw new ServerErrorException($"Writing dump failed (HRESULT: 0x{hr:X8})");

            case DiagnosticsServerCommandId.OK:
                return;

            default:
                throw new ServerErrorException($"Writing dump failed - server responded with unknown command");
            }
        }
Exemple #12
0
        public static async Task <bool> TEST_DisabledCommandsError()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream1 = new MemoryStream();
            using var memoryStream2 = new MemoryStream();
            using var memoryStream3 = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName}" }
            },
                duringExecution: async(pid) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                Logger.logger.Log($"Send profiler attach Diagnostics IPC Command");
                // send profiler attach command (0x03=ProfilerCommandId, 0x01=attach commandid)
                var message = new IpcMessage(0x03, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");
                if (response.Header.CommandSet != 0xFF && response.Header.CommandId != 0xFF)
                {
                    throw new Exception("Command did not fail!");
                }

                stream    = await server.AcceptAsync();
                advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command");
                // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid)
                message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
        ///<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");
            }
        }
        /// <summary>
        /// Attach a profiler to the target process runtime.
        /// </summary>
        /// <param name="processId">.NET Core process id</param>
        /// <param name="attachTimeout">The timeout (in ms) for the runtime to wait while attempting to attach.</param>
        /// <param name="profilerGuid">CLSID of the profiler to load</param>
        /// <param name="profilerPath">Path to the profiler library on disk</param>
        /// <param name="additionalData">additional data to pass to the profiler on attach</param>
        /// <returns>HRESULT</returns>
        public static int AttachProfiler(int processId, uint attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData)
        {
            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");
            }

            var header = new MessageHeader {
                RequestType = DiagnosticsMessageType.AttachProfiler,
                Pid         = (uint)Process.GetCurrentProcess().Id,
            };

            byte[] serializedConfiguration = SerializeProfilerAttach(attachTimeout, profilerGuid, profilerPath, additionalData);
            var    message = new IpcMessage(DiagnosticsServerCommandSet.Profiler, (byte)ProfilerCommandId.AttachProfiler, serializedConfiguration);

            var response = IpcClient.SendMessage(processId, message);

            var hr = 0;

            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.Error:
            case DiagnosticsServerCommandId.OK:
                hr = BitConverter.ToInt32(response.Payload, 0);
                break;

            default:
                hr = -1;
                break;
            }

            // TODO: 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.
            return(hr);
        }
Exemple #15
0
        /// <summary>
        /// Turn off EventPipe logging session for the specified process Id.
        /// </summary>
        /// <param name="processId">Process Id to turn off logging session.</param>
        /// <param name="sessionId">EventPipe session Id to turn off.</param>
        /// <returns>It returns sessionId if success, otherwise 0.</returns>
        public static ulong StopTracing(int processId, ulong sessionId)
        {
            if (sessionId == 0)
            {
                return(sessionId); // TODO: Throw here instead?
            }
            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(BitConverter.ToUInt64(response.Payload));

            case DiagnosticsServerCommandId.Error:
                return(0);

            default:
                return(0);
            }
        }
Exemple #16
0
        public static async Task <bool> TEST_AdvertiseAndProcessInfoCookiesMatch()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName},nosuspend" }
            },
                duringExecution: async(pid) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                Logger.logger.Log($"Send ProcessInfo Diagnostics IPC Command");
                // send ProcessInfo command (0x04=ProcessCommandSet, 0x00=ProcessInfo commandid)
                var message = new IpcMessage(0x04, 0x00);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");
                ProcessInfo info = ProcessInfo.TryParse(response.Payload);
                Logger.logger.Log($"ProcessInfo: {{ id={info.ProcessId}, cookie={info.RuntimeCookie}, cmdline={info.Commandline}, OS={info.OS}, arch={info.Arch} }}");

                Utils.Assert(info.RuntimeCookie.Equals(advertise.RuntimeInstanceCookie), $"The runtime cookie reported by ProcessInfo and Advertise must match.  ProcessInfo: {info.RuntimeCookie.ToString()}, Advertise: {advertise.RuntimeInstanceCookie.ToString()}");
                Logger.logger.Log($"ProcessInfo and Advertise Cookies are equal");
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
Exemple #17
0
        public static int Main(string[] args)
        {
            if (args.Length >= 1)
            {
                Console.Out.WriteLine("Subprocess started!  Waiting for input...");
                var input = Console.In.ReadLine(); // will block until data is sent across stdin
                Console.Out.WriteLine($"Received '{input}'.  Exiting...");
                return(0);
            }

            var testEnvPairs = new Dictionary <string, string>
            {
                { "TESTKEY1", "TESTVAL1" },
                { "TESTKEY2", "TESTVAL2" },
                { "TESTKEY3", "__TEST__VAL=;--3" }
            };

            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: testEnvPairs,
                duringExecution: (int pid) =>
            {
                Logger.logger.Log($"Test PID: {pid}");

                Stream stream = ConnectionHelper.GetStandardTransport(pid);

                // 0x04 = ProcessCommandSet, 0x02 = ProcessInfo
                var processInfoMessage = new IpcMessage(0x04, 0x02);
                Logger.logger.Log($"Wrote: {processInfoMessage}");
                Stream continuationStream = IpcClient.SendMessage(stream, processInfoMessage, out IpcMessage response);
                Logger.logger.Log($"Received: {response}");

                Utils.Assert(response.Header.CommandSet == 0xFF, $"Response must have Server command set. Expected: 0xFF, Received: 0x{response.Header.CommandSet:X2}"); // server
                Utils.Assert(response.Header.CommandId == 0x00, $"Response must have OK command id. Expected: 0x00, Received: 0x{response.Header.CommandId:X2}");        // OK

                UInt32 continuationSizeInBytes = BitConverter.ToUInt32(response.Payload[0..4]);
                Logger.logger.Log($"continuation size: {continuationSizeInBytes} bytes");
                UInt16 future = BitConverter.ToUInt16(response.Payload[4..]);
Exemple #18
0
        /// <summary>
        /// Start trace collection.
        /// </summary>
        /// <param name="processId">Runtime process to trace</param>
        /// <param name="configuration">buffer size and provider configuration</param>
        /// <param name="sessionId">session id</param>
        /// <returns>Stream</returns>
        public static Stream CollectTracing(int processId, SessionConfiguration configuration, out ulong sessionId)
        {
            sessionId = 0;
            var message = new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.CollectTracing, configuration.Serialize());
            var stream  = IpcClient.SendMessage(processId, message, out var response);

            switch ((DiagnosticsServerCommandId)response.Header.CommandId)
            {
            case DiagnosticsServerCommandId.OK:
                sessionId = BitConverter.ToUInt64(response.Payload);
                break;

            case DiagnosticsServerCommandId.Error:
                // bad...
                var hr = BitConverter.ToInt32(response.Payload);
                throw new Exception($"Session start FAILED 0x{hr:X8}");

            default:
                break;
            }

            return(stream);
        }
        public bool SetEnvironmentVariable(string name, string val)
        {
            MethodInfo setEnvironmentVariable = typeof(DiagnosticsClient).GetMethod("SetEnvironmentVariable", BindingFlags.Public);

            if (setEnvironmentVariable != null)
            {
                throw new Exception("You updated DiagnosticsClient to a version that supports SetEnvironmentVariable, please remove this and use the real code.");
            }

            Console.WriteLine($"Sending SetEnvironmentVariable message name={name} value={val ?? "NULL"}.");

            using (var stream = new MemoryStream())
                using (var writer = new BinaryWriter(stream))
                {
                    writer.WriteString(name);
                    writer.WriteString(val);

                    writer.Flush();
                    byte[] payload = stream.ToArray();

                    var message = new IpcMessage(0x04, 0x03, payload);
                    Console.WriteLine($"Sent: {message.ToString()}");
                    IpcMessage response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(_processId), message);
                    Console.WriteLine($"Received: {response.ToString()}");

                    if (response.Header.CommandSet != 255 || response.Header.CommandId != 0)
                    {
                        Console.WriteLine($"SetEnvironmentVariable failed.");
                        return(false);
                    }
                }

            Console.WriteLine($"Finished sending SetEnvironmentVariable message.");

            return(true);
        }
Exemple #20
0
        public static async Task <bool> TEST_MultipleConnectPortsSuspend()
        {
            bool   fSuccess              = true;
            var    serverAndNames        = new List <(ReverseServer, string)>();
            string dotnetDiagnosticPorts = "";

            for (int i = 0; i < s_NumberOfPorts; i++)
            {
                string serverName = ReverseServer.MakeServerAddress();
                var    server     = new ReverseServer(serverName);
                Logger.logger.Log($"Server {i} address is '{serverName}'");
                serverAndNames.Add((server, serverName));
                dotnetDiagnosticPorts += $"{serverName};";
            }
            Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}");

            var    advertisements = new List <IpcAdvertise>();
            Object sync           = new Object();

            int         subprocessId   = -1;
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string>
            {
                { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts }
            },
                duringExecution: async(int pid) =>
            {
                subprocessId = pid;
                // Create an eventpipe session that will tell us when
                // the EEStartupStarted event happens.  This will tell us
                // the the runtime has been resumed.  This should only happen
                // AFTER all suspend ports have sent the resume command.
                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose),
                    // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the
                    // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent)
                    // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent).
                    // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data
                    // that won't come otherwise.
                    new Provider("Microsoft-DotNETCore-SampleProfiler")
                });
                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");

                var mre = new ManualResetEvent(false);

                Task readerTask = Task.Run(async() =>
                {
                    Logger.logger.Log($"Creating EventPipeEventSource");
                    using var source              = new EventPipeEventSource(eventStream);
                    var parser                    = new ClrPrivateTraceEventParser(source);
                    parser.StartupEEStartupStart += (eventData) => mre.Set();
                    Logger.logger.Log($"Created EventPipeEventSource");
                    Logger.logger.Log($"Starting processing");
                    await Task.Run(() => source.Process());
                    Logger.logger.Log($"Finished processing");
                });

                for (int i = 0; i < s_NumberOfPorts; i++)
                {
                    fSuccess &= !mre.WaitOne(0);
                    Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");
                    var(server, _)         = serverAndNames[i];
                    int serverIndex        = i;
                    Stream stream          = await server.AcceptAsync();
                    IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                    lock (sync)
                        advertisements.Add(advertise);
                    Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}");

                    // send resume command on this connection
                    var message = new IpcMessage(0x04, 0x01);
                    Logger.logger.Log($"Port {serverIndex} sent: {message.ToString()}");
                    IpcMessage response = IpcClient.SendMessage(stream, message);
                    Logger.logger.Log($"Port {serverIndex} received: {response.ToString()}");
                }

                Logger.logger.Log($"Waiting on EEStartupStarted event");
                mre.WaitOne();
                Logger.logger.Log($"Saw EEStartupStarted Event");

                Logger.logger.Log($"Stopping EventPipeSession");
                EventPipeClient.StopTracing(pid, sessionId);
                await readerTask;
                Logger.logger.Log($"Stopped EventPipeSession");

                // runtime should have resumed now
                fSuccess &= mre.WaitOne(0);
                Logger.logger.Log($"Runtime HAS resumed (expects: true): {fSuccess}");
            }
                );


            fSuccess &= await subprocessTask;
            foreach (var(server, _) in serverAndNames)
            {
                server.Shutdown();
            }

            if (advertisements.Count() > 0)
            {
                Guid referenceCookie = advertisements[0].RuntimeInstanceCookie;
                foreach (var adv in advertisements)
                {
                    fSuccess &= (int)adv.ProcessId == subprocessId;
                    fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie);
                }
            }
            else
            {
                fSuccess &= false;
            }

            return(fSuccess);
        }
Exemple #21
0
        public static async Task <bool> TEST_SuspendDefaultPort()
        {
            bool fSuccess = true;

            int         subprocessId   = -1;
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string>
            {
                { Utils.DiagnosticPortSuspend, "1" }
            },
                duringExecution: async(int pid) =>
            {
                subprocessId = pid;
                // Create an eventpipe session that will tell us when
                // the EEStartupStarted event happens.  This will tell us
                // the the runtime has been resumed.  This should only happen
                // AFTER all suspend ports have sent the resume command.
                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose),
                    // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the
                    // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent)
                    // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent).
                    // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data
                    // that won't come otherwise.
                    new Provider("Microsoft-DotNETCore-SampleProfiler")
                });
                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");

                var mre = new ManualResetEvent(false);

                Task readerTask = Task.Run(async() =>
                {
                    Logger.logger.Log($"Creating EventPipeEventSource");
                    using var source              = new EventPipeEventSource(eventStream);
                    var parser                    = new ClrPrivateTraceEventParser(source);
                    parser.StartupEEStartupStart += (eventData) => mre.Set();
                    Logger.logger.Log($"Created EventPipeEventSource");
                    Logger.logger.Log($"Starting processing");
                    await Task.Run(() => source.Process());
                    Logger.logger.Log($"Finished processing");
                });


                fSuccess &= !mre.WaitOne(0);
                Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");

                // send resume command on this connection
                var message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(pid), message);
                Logger.logger.Log($"Received: {response.ToString()}");

                Logger.logger.Log($"Waiting for EEStartupStarted event");
                mre.WaitOne();
                Logger.logger.Log($"Saw EEStartupStarted event!");

                Logger.logger.Log($"Stopping EventPipeSession");
                EventPipeClient.StopTracing(pid, sessionId);
                await readerTask;
                Logger.logger.Log($"Stopped EventPipeSession");

                // runtime should have resumed now
                fSuccess &= mre.WaitOne(0);
                Logger.logger.Log($"Runtime HAS resumed (expects: true): {fSuccess}");
            }
                );


            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
Exemple #22
0
        public static async Task <bool> TEST_MultipleSessionsCanBeStartedWhilepaused()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream1 = new MemoryStream();
            using var memoryStream2 = new MemoryStream();
            using var memoryStream3 = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticsMonitorAddressEnvKey, serverName }
            },
                duringExecution: async(pid) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose)
                });

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream1 = EventPipeClient.CollectTracing(pid, config, out var sessionId1);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId1:x}");
                Task readerTask1 = eventStream1.CopyToAsync(memoryStream1);

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream2 = EventPipeClient.CollectTracing(pid, config, out var sessionId2);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId2:x}");
                Task readerTask2 = eventStream2.CopyToAsync(memoryStream2);

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream3 = EventPipeClient.CollectTracing(pid, config, out var sessionId3);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId3:x}");
                Task readerTask3 = eventStream3.CopyToAsync(memoryStream3);


                Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command");
                // send ResumeRuntime command (0xFF=ServerCommandSet, 0x01=ResumeRuntime commandid)
                var message = new IpcMessage(0xFF, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");

                await Task.Delay(TimeSpan.FromSeconds(2));
                Logger.logger.Log("Stopping EventPipeSession over standard connection");
                EventPipeClient.StopTracing(pid, sessionId1);
                EventPipeClient.StopTracing(pid, sessionId2);
                EventPipeClient.StopTracing(pid, sessionId3);
                await readerTask1;
                await readerTask2;
                await readerTask3;
                Logger.logger.Log("Stopped EventPipeSession over standard connection");
            }
                );

            fSuccess &= await Utils.WaitTillTimeout(subprocessTask, TimeSpan.FromMinutes(1));

            int nStartupEventsSeen = 0;

            memoryStream1.Seek(0, SeekOrigin.Begin);
            using (var source = new EventPipeEventSource(memoryStream1))
            {
                var parser = new ClrPrivateTraceEventParser(source);
                parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++;
                source.Process();
            }

            memoryStream2.Seek(0, SeekOrigin.Begin);
            using (var source = new EventPipeEventSource(memoryStream2))
            {
                var parser = new ClrPrivateTraceEventParser(source);
                parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++;
                source.Process();
            }

            memoryStream3.Seek(0, SeekOrigin.Begin);
            using (var source = new EventPipeEventSource(memoryStream3))
            {
                var parser = new ClrPrivateTraceEventParser(source);
                parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++;
                source.Process();
            }

            Logger.logger.Log($"nStartupEventsSeen: {nStartupEventsSeen}");

            return(nStartupEventsSeen == 3 && fSuccess);
        }
Exemple #23
0
        public static async Task <bool> TEST_ProcessInfoBeforeAndAfterSuspension()
        {
            // This test only applies to platforms where the PAL is used
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return(true);
            }

            // This test only applies to CoreCLR (this checks if we're running on Mono)
            if (Type.GetType("Mono.RuntimeStructs") != null)
            {
                return(true);
            }

            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream1 = new MemoryStream();
            using var memoryStream2 = new MemoryStream();
            using var memoryStream3 = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName}" }
            },
                duringExecution: async(pid) =>
            {
                Process currentProcess = Process.GetCurrentProcess();

                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                Logger.logger.Log($"Get ProcessInfo while process is suspended");
                // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2
                var message = new IpcMessage(0x04, 0x04);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");

                ProcessInfo2 pi2Before = ProcessInfo2.TryParse(response.Payload);
                Utils.Assert(pi2Before.Commandline.Equals(currentProcess.MainModule.FileName), $"Before resuming, the commandline should be the mock value of the host executable path '{currentProcess.MainModule.FileName}'. Observed: '{pi2Before.Commandline}'");

                // recycle
                stream    = await server.AcceptAsync();
                advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                // Start EP session to know when runtime is resumed
                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose),
                    new Provider("Microsoft-DotNETCore-SampleProfiler")
                });
                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");

                TaskCompletionSource <bool> runtimeResumed = new(false, TaskCreationOptions.RunContinuationsAsynchronously);

                var eventPipeTask = Task.Run(() =>
                {
                    Logger.logger.Log("Creating source");
                    using var source              = new EventPipeEventSource(eventStream);
                    var parser                    = new ClrPrivateTraceEventParser(source);
                    parser.StartupEEStartupStart += (_) => runtimeResumed.SetResult(true);
                    source.Process();
                    Logger.logger.Log("stopping processing");
                });

                Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command");
                // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid)
                message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");

                // recycle
                stream    = await server.AcceptAsync();
                advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                // wait a little bit to make sure the runtime of the target is fully up, i.e., g_EEStarted == true
                // on resource constrained CI machines this may not be instantaneous
                Logger.logger.Log($"awaiting resume");
                await Utils.WaitTillTimeout(runtimeResumed.Task, TimeSpan.FromSeconds(10));
                Logger.logger.Log($"resumed");

                // await Task.Delay(TimeSpan.FromSeconds(1));
                Logger.logger.Log("Stopping EventPipeSession over standard connection");
                EventPipeClient.StopTracing(pid, sessionId);
                Logger.logger.Log($"Await reader task");
                await eventPipeTask;
                Logger.logger.Log("Stopped EventPipeSession over standard connection");

                ProcessInfo2 pi2After = default;

                // The timing is not exact. There is a small window after resuming where the mock
                // value is still present. Retry several times to catch it.
                var retryTask = Task.Run(async() =>
                {
                    int i = 0;
                    do
                    {
                        Logger.logger.Log($"Get ProcessInfo after resumption: attempt {i++}");
                        // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2
                        message = new IpcMessage(0x04, 0x04);
                        Logger.logger.Log($"Sent: {message.ToString()}");
                        response = IpcClient.SendMessage(stream, message);
                        Logger.logger.Log($"received: {response.ToString()}");

                        pi2After = ProcessInfo2.TryParse(response.Payload);

                        // recycle
                        stream    = await server.AcceptAsync();
                        advertise = IpcAdvertise.Parse(stream);
                        Logger.logger.Log(advertise.ToString());
                    } while (pi2After.Commandline.Equals(pi2Before.Commandline));
                });

                await Utils.WaitTillTimeout(retryTask, TimeSpan.FromSeconds(10));

                Utils.Assert(!pi2After.Commandline.Equals(pi2Before.Commandline), $"After resuming, the commandline should be the correct value. Observed: Before='{pi2Before.Commandline}' After='{pi2After.Commandline}'");
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
Exemple #24
0
        public static async Task <bool> TEST_CanStartAndStopSessionWhilepaused()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();

            Logger.logger.Log($"Server name is '{serverName}'");
            var server = new ReverseServer(serverName);

            using var memoryStream1 = new MemoryStream();
            using var memoryStream2 = new MemoryStream();
            using var memoryStream3 = new MemoryStream();
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string> {
                { Utils.DiagnosticPortsEnvKey, $"{serverName}" }
            },
                duringExecution: async(pid) =>
            {
                Stream stream          = await server.AcceptAsync();
                IpcAdvertise advertise = IpcAdvertise.Parse(stream);
                Logger.logger.Log(advertise.ToString());

                var config = new SessionConfiguration(
                    circularBufferSizeMB: 1000,
                    format: EventPipeSerializationFormat.NetTrace,
                    providers: new List <Provider> {
                    new Provider("Microsoft-Windows-DotNETRuntime", UInt64.MaxValue, EventLevel.Verbose)
                });

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream1 = EventPipeClient.CollectTracing(pid, config, out var sessionId1);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId1:x}");
                Task readerTask1 = eventStream1.CopyToAsync(memoryStream1);

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream2 = EventPipeClient.CollectTracing(pid, config, out var sessionId2);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId2:x}");
                Task readerTask2 = eventStream2.CopyToAsync(memoryStream2);

                Logger.logger.Log("Starting EventPipeSession over standard connection");
                using Stream eventStream3 = EventPipeClient.CollectTracing(pid, config, out var sessionId3);
                Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId3:x}");
                Task readerTask3 = eventStream3.CopyToAsync(memoryStream3);

                await Task.Delay(TimeSpan.FromSeconds(1));
                Logger.logger.Log("Stopping EventPipeSession over standard connection");
                EventPipeClient.StopTracing(pid, sessionId1);
                EventPipeClient.StopTracing(pid, sessionId2);
                EventPipeClient.StopTracing(pid, sessionId3);
                await readerTask1;
                await readerTask2;
                await readerTask3;
                Logger.logger.Log("Stopped EventPipeSession over standard connection");

                Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command");
                // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid)
                var message = new IpcMessage(0x04, 0x01);
                Logger.logger.Log($"Sent: {message.ToString()}");
                IpcMessage response = IpcClient.SendMessage(stream, message);
                Logger.logger.Log($"received: {response.ToString()}");
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }