Пример #1
0
        private void HangDump(int processId, string tempDirectory, DumpTypeOption dumpType, string targetFramework, Action <string> logWarning = null)
        {
            this.wasHangDumped = true;

            var processName = this.processHelper.GetProcessName(processId);

            EqtTrace.Info($"ProcessDumpUtility.HangDump: Creating {dumpType.ToString().ToLowerInvariant()} dump of process {processName} ({processId}) into temporary path '{tempDirectory}'.");

            this.hangDumpDirectory = tempDirectory;

            // oh how ugly this is, but the whole infra above this starts with initializing the logger in Initialize
            // the logger needs to pass around 2 parameters, so I am just passing it around as callback instead
            this.hangDumperFactory.LogWarning = logWarning;
            var dumper = this.hangDumperFactory.Create(targetFramework);

            try
            {
                dumper.Dump(processId, tempDirectory, dumpType);
            }
            catch (Exception ex)
            {
                EqtTrace.Error($"Blame: Failed with error {ex}.");
                throw;
            }
        }
Пример #2
0
        public void Dump(int processId, string outputFile, DumpTypeOption type)
        {
            var client = new DiagnosticsClient(processId);

            // Connecting the dump generation logging to verbose output to avoid changing the interfaces again
            // before we test this on some big repo.
            client.WriteDump(type == DumpTypeOption.Full ? DumpType.Full : DumpType.Normal, outputFile, logDumpGeneration: EqtTrace.IsVerboseEnabled);
        }
Пример #3
0
        internal static void CollectDump(Process process, string outputFile, DumpTypeOption type)
        {
            // Open the file for writing
            using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
            {
                NativeMethods.MINIDUMP_EXCEPTION_INFORMATION exceptionInfo = default(NativeMethods.MINIDUMP_EXCEPTION_INFORMATION);

                NativeMethods.MINIDUMP_TYPE dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpNormal;
                switch (type)
                {
                case DumpTypeOption.Full:
                    dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemory |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                    break;

                case DumpTypeOption.WithHeap:
                    dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithPrivateReadWriteMemory |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                               NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                    break;

                case DumpTypeOption.Mini:
                    dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo;
                    break;
                }

                // Retry the write dump on ERROR_PARTIAL_COPY
                for (int i = 0; i < 5; i++)
                {
                    // Dump the process!
                    if (NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, dumpType, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero))
                    {
                        break;
                    }
                    else
                    {
                        int err = Marshal.GetHRForLastWin32Error();
                        if (err != NativeMethods.ERROR_PARTIAL_COPY)
                        {
                            Marshal.ThrowExceptionForHR(err);
                        }
                    }
                }
            }
        }
Пример #4
0
        private void CrashDump(int processId, string tempDirectory, DumpTypeOption dumpType, string targetFramework)
        {
            var processName = this.processHelper.GetProcessName(processId);

            EqtTrace.Info($"ProcessDumpUtility.CrashDump: Creating {dumpType.ToString().ToLowerInvariant()} dump of process {processName} ({processId}) into temporary path '{tempDirectory}'.");
            this.crashDumpDirectory = tempDirectory;

            this.crashDumper = this.crashDumperFactory.Create(targetFramework);
            ConsoleOutput.Instance.Information(false, $"Blame: Attaching crash dump utility to process {processName} ({processId}).");
            this.crashDumper.AttachToTargetProcess(processId, tempDirectory, dumpType);
        }
        /// <inheritdoc/>
        public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType, bool collectAlways)
        {
            var process    = Process.GetProcessById(processId);
            var outputFile = Path.Combine(outputDirectory, $"{process.ProcessName}_{process.Id}_{DateTime.Now:yyyyMMddTHHmmss}_crashdump.dmp");

            EqtTrace.Info($"ProcDumpCrashDumper.AttachToTargetProcess: Attaching to process '{processId}' to dump into '{outputFile}'.");

            // Procdump will append .dmp at the end of the dump file. We generate this internally so it is rather a safety check.
            if (!outputFile.EndsWith(".dmp", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("Procdump crash dump file must end with .dmp extension.");
            }

            if (!this.TryGetProcDumpExecutable(processId, out var procDumpPath))
            {
                var err = $"{procDumpPath} could not be found, please set PROCDUMP_PATH environment variable to a directory that contains {procDumpPath} executable, or make sure that the executable is available on PATH.";
                ConsoleOutput.Instance.Warning(false, err);
                EqtTrace.Error($"ProcDumpCrashDumper.AttachToTargetProcess: {err}");
                return;
            }

            this.tempDirectory = Path.GetDirectoryName(outputFile);
            this.dumpFileName  = Path.GetFileNameWithoutExtension(outputFile);

            string procDumpArgs = new ProcDumpArgsBuilder().BuildTriggerBasedProcDumpArgs(
                processId,
                this.dumpFileName,
                ProcDumpExceptionsList,
                isFullDump: dumpType == DumpTypeOption.Full,
                collectAlways: collectAlways);

            EqtTrace.Info($"ProcDumpCrashDumper.AttachToTargetProcess: Running ProcDump with arguments: '{procDumpArgs}'.");
            this.procDumpProcess = this.processHelper.LaunchProcess(
                procDumpPath,
                procDumpArgs,
                this.tempDirectory,
                null,
                null,
                null,
                this.OutputReceivedCallback) as Process;

            EqtTrace.Info($"ProcDumpCrashDumper.AttachToTargetProcess: ProcDump started as process with id '{this.procDumpProcess.Id}'.");
        }
Пример #6
0
            internal static Task CollectDumpAsync(Process process, string outputFile, DumpTypeOption type)
            {
                // We can't do this "asynchronously" so just Task.Run it. It shouldn't be "long-running" so this is fairly safe.
                return(Task.Run(() =>
                {
                    // Open the file for writing
                    using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                    {
                        var exceptionInfo = new NativeMethods.MINIDUMP_EXCEPTION_INFORMATION();
                        var dumpType = type == DumpTypeOption.Mini ? NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo :
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithPrivateReadWriteMemory |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;

                        // Dump the process!
                        if (!NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, dumpType, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero))
                        {
                            int err = Marshal.GetHRForLastWin32Error();
                            Marshal.ThrowExceptionForHR(err);
                        }
                    }
                }));
            }
Пример #7
0
        private void CrashDump(int processId, string dumpFileGuid, string tempDirectory, DumpTypeOption dumpType, string targetFramework)
        {
            var dumpPath = this.GetDumpPath(processId, dumpFileGuid, tempDirectory, isHangDump: false, out var processName);

            EqtTrace.Info($"ProcessDumpUtility.CrashDump: Creating {dumpType.ToString().ToLowerInvariant()} dump of process {processName} ({processId}) into temporary path '{dumpPath}'.");
            this.crashDumpPath = dumpPath;

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                throw new NotSupportedException($"Operating system {RuntimeInformation.OSDescription} is not supported for crash dumps.");
            }

            this.crashDumper = this.crashDumperFactory.Create(targetFramework);
            ConsoleOutput.Instance.Information(false, $"Blame: Attaching crash dump utility to process {processName} ({processId}).");
            this.crashDumper.AttachToTargetProcess(processId, dumpPath, dumpType);
        }
Пример #8
0
        public void Dump(int processId, string outputDirectory, DumpTypeOption type)
        {
            var process     = Process.GetProcessById(processId);
            var processTree = process.GetProcessTree().Where(p => p.Process.ProcessName != "conhost" && p.Process.ProcessName != "WerFault").ToList();

            if (processTree.Count > 1)
            {
                var tree = processTree.OrderBy(t => t.Level);
                EqtTrace.Verbose("WindowsHangDumper.Dump: Dumping this process tree (from bottom):");
                foreach (var p in tree)
                {
                    EqtTrace.Verbose($"WindowsHangDumper.Dump: {new string(' ', p.Level)}{(p.Level != 0 ? " +" : " >-")} {p.Process.Id} - {p.Process.ProcessName}");
                }

                // logging warning separately to avoid interleving the messages in the log which make this tree unreadable
                this.logWarning(Resources.Resources.DumpingTree);
                foreach (var p in tree)
                {
                    this.logWarning($"{new string(' ', p.Level)}{(p.Level != 0 ? "+-" : ">")} {p.Process.Id} - {p.Process.ProcessName}");
                }
            }
            else
            {
                EqtTrace.Verbose($"NetClientHangDumper.Dump: Dumping {process.Id} - {process.ProcessName}.");
                var message = string.Format(CultureInfo.CurrentUICulture, Resources.Resources.Dumping, process.Id, process.ProcessName);
                this.logWarning(message);
            }

            var bottomUpTree = processTree.OrderByDescending(t => t.Level).Select(t => t.Process);

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                foreach (var p in bottomUpTree)
                {
                    try
                    {
                        p.Suspend();
                    }
                    catch (Exception ex)
                    {
                        EqtTrace.Error($"WindowsHangDumper.Dump: Error suspending process {p.Id} - {p.ProcessName}: {ex}.");
                    }
                }
            }

            foreach (var p in bottomUpTree)
            {
                try
                {
                    var outputFile = Path.Combine(outputDirectory, $"{p.ProcessName}_{p.Id}_{DateTime.Now:yyyyMMddTHHmmss}_hangdump.dmp");
                    CollectDump(p, outputFile, type);
                }
                catch (Exception ex)
                {
                    EqtTrace.Error($"WindowsHangDumper.Dump: Error dumping process {p.Id} - {p.ProcessName}: {ex}.");
                }

                try
                {
                    EqtTrace.Verbose($"WindowsHangDumper.Dump: Killing process {p.Id} - {p.ProcessName}.");
                    p.Kill();
                }
                catch (Exception ex)
                {
                    EqtTrace.Error($"WindowsHangDumper.Dump: Error killing process {p.Id} - {p.ProcessName}: {ex}.");
                }
            }
        }
Пример #9
0
        public int Collect(int processId, bool diag, DumpTypeOption type)
        {
            try
            {
                // Build timestamp based file path
                string timestamp = $"{DateTime.Now:yyyyMMdd_HHmmss}";
                var    output    = Path.Combine(Directory.GetCurrentDirectory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"dump_{timestamp}.dmp" : $"core_{timestamp}");
                // Make sure the dump path is NOT relative. This path could be sent to the runtime
                // process on Linux which may have a different current directory.
                output = Path.GetFullPath(output);

                // Display the type of dump and dump path
                string dumpTypeMessage = null;
                switch (type)
                {
                case DumpTypeOption.Full:
                    dumpTypeMessage = "full";
                    break;

                case DumpTypeOption.Heap:
                    dumpTypeMessage = "dump with heap";
                    break;

                case DumpTypeOption.Mini:
                    dumpTypeMessage = "dump";
                    break;
                }
                Console.WriteLine($"Writing {dumpTypeMessage} to {output}");

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    // Get the process
                    Process process = Process.GetProcessById(processId);
                    Windows.CollectDump(process, output, type);
                }
                else
                {
                    var client = new DiagnosticsClient(processId);

                    DumpType dumpType = DumpType.Normal;
                    switch (type)
                    {
                    case DumpTypeOption.Full:
                        dumpType = DumpType.Full;
                        break;

                    case DumpTypeOption.Heap:
                        dumpType = DumpType.WithHeap;
                        break;

                    case DumpTypeOption.Mini:
                        dumpType = DumpType.Normal;
                        break;
                    }

                    // Send the command to the runtime to initiate the core dump
                    client.WriteDump(dumpType, output, diag);
                }
            }
            catch (Exception ex) when
                (ex is FileNotFoundException ||
                ex is DirectoryNotFoundException ||
                ex is UnauthorizedAccessException ||
                ex is PlatformNotSupportedException ||
                ex is UnsupportedCommandException ||
                ex is InvalidDataException ||
                ex is InvalidOperationException ||
                ex is NotSupportedException ||
                ex is DiagnosticsClientException)
            {
                Console.Error.WriteLine($"{ex.Message}");
                return(1);
            }

            Console.WriteLine($"Complete");
            return(0);
        }
Пример #10
0
            private static Task <int> CreateDumpAsync(string exePath, string fileName, int processId, DumpTypeOption type)
            {
                string dumpType   = type == DumpTypeOption.Mini ? "--normal" : "--withheap";
                var    tcs        = new TaskCompletionSource <int>();
                var    createdump = new Process()
                {
                    StartInfo = new ProcessStartInfo()
                    {
                        FileName  = exePath,
                        Arguments = $"--name {fileName} {dumpType} {processId}",
                    },
                    EnableRaisingEvents = true,
                };

                createdump.Exited += (s, a) => tcs.TrySetResult(createdump.ExitCode);
                createdump.Start();
                return(tcs.Task);
            }
Пример #11
0
 public void Dump(int processId, string outputFile, DumpTypeOption type)
 {
     Process.Start("kill", $"-s SIGTRAP {processId}");
 }
Пример #12
0
            internal static Task CollectDumpAsync(Process process, string outputFile, DumpTypeOption type)
            {
                // We can't do this "asynchronously" so just Task.Run it. It shouldn't be "long-running" so this is fairly safe.
                return(Task.Run(() =>
                {
                    // Open the file for writing
                    using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                    {
                        var exceptionInfo = new NativeMethods.MINIDUMP_EXCEPTION_INFORMATION();

                        NativeMethods.MINIDUMP_TYPE dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpNormal;
                        switch (type)
                        {
                        case DumpTypeOption.Full:
                            dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemory |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                            break;

                        case DumpTypeOption.Heap:
                            dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithPrivateReadWriteMemory |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                                       NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                            break;

                        case DumpTypeOption.Mini:
                            dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo;
                            break;
                        }

                        // Retry the write dump on ERROR_PARTIAL_COPY
                        for (int i = 0; i < 5; i++)
                        {
                            // Dump the process!
                            if (NativeMethods.MiniDumpWriteDump(process.Handle, (uint)process.Id, stream.SafeFileHandle, dumpType, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero))
                            {
                                break;
                            }
                            else
                            {
                                int err = Marshal.GetHRForLastWin32Error();
                                if (err != NativeMethods.ERROR_PARTIAL_COPY)
                                {
                                    Marshal.ThrowExceptionForHR(err);
                                }
                            }
                        }
                    }
                }));
            }
Пример #13
0
        public void Dump(int processId, string outputFile, DumpTypeOption type)
        {
            var process = Process.GetProcessById(processId);

            CollectDump(process, outputFile, type);
        }
Пример #14
0
        public int Collect(int processId, string outputFilePath, DumpTypeOption type)
        {
            try
            {
                // Make sure the dump path is NOT relative. This path could be sent to the runtime
                // process on Linux which may have a different current directory.
                outputFilePath = Path.GetFullPath(outputFilePath);

                // Display the type of dump and dump path
                string dumpTypeMessage = null;
                switch (type)
                {
                case DumpTypeOption.Full:
                    dumpTypeMessage = "full";
                    break;

                case DumpTypeOption.Heap:
                    dumpTypeMessage = "dump with heap";
                    break;

                case DumpTypeOption.Mini:
                    dumpTypeMessage = "dump";
                    break;
                }

                Log.Info($"Writing {dumpTypeMessage} to {outputFilePath}");

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    // Get the process
                    Process process = Process.GetProcessById(processId);

                    Windows.CollectDump(process, outputFilePath, type);
                }
                else
                {
                    var client = new DiagnosticsClient(processId);

                    DumpType dumpType = DumpType.Normal;
                    switch (type)
                    {
                    case DumpTypeOption.Full:
                        dumpType = DumpType.Full;
                        break;

                    case DumpTypeOption.Heap:
                        dumpType = DumpType.WithHeap;
                        break;

                    case DumpTypeOption.Mini:
                        dumpType = DumpType.Normal;
                        break;
                    }

                    // Send the command to the runtime to initiate the core dump
                    client.WriteDump(dumpType, outputFilePath, logDumpGeneration: false);
                }
            }
            catch (Exception ex) when
                (ex is FileNotFoundException ||
                ex is DirectoryNotFoundException ||
                ex is UnauthorizedAccessException ||
                ex is PlatformNotSupportedException ||
                ex is InvalidDataException ||
                ex is InvalidOperationException ||
                ex is NotSupportedException ||
                ex is DiagnosticsClientException)
            {
                Log.Error(ex);
                return(1);
            }

            Log.Info($"Dump complete");
            return(0);
        }
Пример #15
0
        public void Dump(int processId, string outputFile, DumpTypeOption type)
        {
            var client = new DiagnosticsClient(processId);

            client.WriteDump(type == DumpTypeOption.Full ? DumpType.Full : DumpType.Normal, outputFile);
        }
Пример #16
0
        public int Collect(IConsole console, int processId, string output, bool diag, bool crashreport, DumpTypeOption type, string name)
        {
            Console.WriteLine(name);
            if (name != null)
            {
                if (processId != 0)
                {
                    Console.WriteLine("Can only specify either --name or --process-id option.");
                    return(0);
                }
                processId = CommandUtils.FindProcessIdWithName(name);
                if (processId < 0)
                {
                    return(0);
                }
            }

            if (processId == 0)
            {
                console.Error.WriteLine("ProcessId is required.");
                return(1);
            }

            try
            {
                if (output == null)
                {
                    // Build timestamp based file path
                    string timestamp = $"{DateTime.Now:yyyyMMdd_HHmmss}";
                    output = Path.Combine(Directory.GetCurrentDirectory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"dump_{timestamp}.dmp" : $"core_{timestamp}");
                }
                // Make sure the dump path is NOT relative. This path could be sent to the runtime
                // process on Linux which may have a different current directory.
                output = Path.GetFullPath(output);

                // Display the type of dump and dump path
                string dumpTypeMessage = null;
                switch (type)
                {
                case DumpTypeOption.Full:
                    dumpTypeMessage = "full";
                    break;

                case DumpTypeOption.Heap:
                    dumpTypeMessage = "dump with heap";
                    break;

                case DumpTypeOption.Mini:
                    dumpTypeMessage = "dump";
                    break;
                }
                console.Out.WriteLine($"Writing {dumpTypeMessage} to {output}");

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    if (crashreport)
                    {
                        Console.WriteLine("Crash reports not supported on Windows.");
                        return(0);
                    }

                    Windows.CollectDump(processId, output, type);
                }
                else
                {
                    var client = new DiagnosticsClient(processId);

                    DumpType dumpType = DumpType.Normal;
                    switch (type)
                    {
                    case DumpTypeOption.Full:
                        dumpType = DumpType.Full;
                        break;

                    case DumpTypeOption.Heap:
                        dumpType = DumpType.WithHeap;
                        break;

                    case DumpTypeOption.Mini:
                        dumpType = DumpType.Normal;
                        break;

                    case DumpTypeOption.Triage:
                        dumpType = DumpType.Triage;
                        break;
                    }

                    WriteDumpFlags flags = WriteDumpFlags.None;
                    if (diag)
                    {
                        flags |= WriteDumpFlags.LoggingEnabled;
                    }
                    if (crashreport)
                    {
                        flags |= WriteDumpFlags.CrashReportEnabled;
                    }
                    // Send the command to the runtime to initiate the core dump
                    client.WriteDump(dumpType, output, flags);
                }
            }
            catch (Exception ex) when
                (ex is FileNotFoundException ||
                ex is ArgumentException ||
                ex is DirectoryNotFoundException ||
                ex is UnauthorizedAccessException ||
                ex is PlatformNotSupportedException ||
                ex is UnsupportedCommandException ||
                ex is InvalidDataException ||
                ex is InvalidOperationException ||
                ex is NotSupportedException ||
                ex is DiagnosticsClientException)
            {
                console.Error.WriteLine($"{ex.Message}");
                return(1);
            }

            console.Out.WriteLine($"Complete");
            return(0);
        }
Пример #17
0
        public async Task <int> Collect(CommandLineApplication cmd, int processId, string output, bool diag, DumpTypeOption type)
        {
            if (processId == 0)
            {
                return(cmd.ExitWithError("ProcessId is required."));
            }

            try
            {
                if (output == null)
                {
                    // Build timestamp based file path
                    string timestamp = $"{DateTime.Now:yyyyMMdd_HHmmss}";
                    output = Path.Combine(Directory.GetCurrentDirectory(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"dump_{processId}_{timestamp}.dmp" : $"core_{processId}_{timestamp}");
                }
                // Make sure the dump path is NOT relative. This path could be sent to the runtime
                // process on Linux which may have a different current directory.
                output = Path.GetFullPath(output);

                // Display the type of dump and dump path
                string dumpTypeMessage = type == DumpTypeOption.Mini ? "minidump" : "minidump with heap";
                cmd.Out.WriteLine($"Writing {dumpTypeMessage} to {output}");

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    // Get the process
                    Process process = Process.GetProcessById(processId);

                    await Windows.CollectDumpAsync(process, output, type);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    var      client   = new DiagnosticsClient(processId);
                    DumpType dumpType = type == DumpTypeOption.Heap ? DumpType.WithHeap : DumpType.Normal;

                    // Send the command to the runtime to initiate the core dump
                    client.WriteDump(dumpType, output, diag);
                }
                else
                {
                    throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}");
                }
            }
            catch (Exception ex) when
                (ex is FileNotFoundException ||
                ex is DirectoryNotFoundException ||
                ex is UnauthorizedAccessException ||
                ex is PlatformNotSupportedException ||
                ex is InvalidDataException ||
                ex is InvalidOperationException ||
                ex is NotSupportedException ||
                ex is DiagnosticsClientException)
            {
                return(cmd.ExitWithError($"{ex.Message}"));
            }

            cmd.Out.WriteLine($"Complete");
            return(0);
        }
Пример #18
0
        private void HangDump(int processId, string dumpFileGuid, string tempDirectory, DumpTypeOption dumpType, string targetFramework)
        {
            this.wasHangDumped = true;

            // the below format is extremely ugly maybe we can use:

            // https://github.com/microsoft/testfx/issues/678
            // which will order the files correctly gives more info when transported out of
            // the context of the run, and keeps the file name unique-enough for our purposes"
            // $"{processName}_{processId}_{dumpFileGuid}_hangdump.dmp"
            // var dumpFileName = $"crash_{processName}_{DateTime.Now:yyyyMMddTHHmmss}_{processId}.dmp";
            // var dumpFileName = $"{prefix}_{processName}_{DateTime.Now:yyyyMMddTHHmmss}_{processId}.dmp";
            var dumpPath = this.GetDumpPath(processId, dumpFileGuid, tempDirectory, isHangDump: true, out var processName);

            EqtTrace.Info($"ProcessDumpUtility.HangDump: Creating {dumpType.ToString().ToLowerInvariant()} dump of process {processName} ({processId}) into temporary path '{dumpPath}'.");
            this.hangDumpPath = dumpPath;

            var dumper = this.hangDumperFactory.Create(targetFramework);

            try
            {
                ConsoleOutput.Instance.Information(false, $"Blame: Creating hang dump of process {processName} ({processId}).");
                dumper.Dump(processId, dumpPath, dumpType);
                EqtTrace.Info($"ProcessDumpUtility.HangDump: Process {processName} ({processId}) was dumped into temporary path '{dumpPath}'.");
            }
            catch (Exception ex)
            {
                EqtTrace.Error($"Blame: Failed with error {ex}.");
                throw;
            }
        }
Пример #19
0
            internal static void CollectDump(int processId, string outputFile, DumpTypeOption type)
            {
                // The managed Process (via Process.GetProcessById) type can not be used to get the handle for a process that is in the middle of exiting such
                // that it has set an exit code, but not actually exited. This is because for compat reasons the Process class will throw in these circumstances.
                using SafeProcessHandle processHandle = NativeMethods.OpenProcess(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_VM_READ, false, processId);
                if (processHandle.IsInvalid)
                {
                    throw new ArgumentException($"Invalid process id {processId} error: {Marshal.GetLastWin32Error()}");
                }

                // Open the file for writing
                using (var stream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                {
                    NativeMethods.MINIDUMP_TYPE dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpNormal;
                    switch (type)
                    {
                    case DumpTypeOption.Full:
                        dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemory |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                        break;

                    case DumpTypeOption.Heap:
                        dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpWithPrivateReadWriteMemory |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithTokenInformation;
                        break;

                    case DumpTypeOption.Mini:
                        dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpNormal |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithDataSegs |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithThreadInfo;
                        break;

                    case DumpTypeOption.Triage:
                        dumpType = NativeMethods.MINIDUMP_TYPE.MiniDumpFilterTriage |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpIgnoreInaccessibleMemory |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithoutOptionalData |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithProcessThreadData |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpFilterModulePaths |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithUnloadedModules |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpFilterMemory |
                                   NativeMethods.MINIDUMP_TYPE.MiniDumpWithHandleData;
                        break;
                    }

                    // Retry the write dump on ERROR_PARTIAL_COPY
                    for (int i = 0; i < 5; i++)
                    {
                        // Dump the process!
                        if (NativeMethods.MiniDumpWriteDump(processHandle.DangerousGetHandle(), (uint)processId, stream.SafeFileHandle, dumpType, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
                        {
                            break;
                        }
                        else
                        {
                            int err = Marshal.GetHRForLastWin32Error();
                            if (err != NativeMethods.ERROR_PARTIAL_COPY)
                            {
                                Marshal.ThrowExceptionForHR(err);
                            }
                        }
                    }
                }
            }
Пример #20
0
        public void Dump(int processId, string outputDirectory, DumpTypeOption type)
        {
            var process     = Process.GetProcessById(processId);
            var processTree = process.GetProcessTree();

            if (EqtTrace.IsVerboseEnabled)
            {
                if (processTree.Count > 1)
                {
                    EqtTrace.Verbose("NetClientHangDumper.Dump: Dumping this process tree (from bottom):");
                    ConsoleOutput.Instance.Information(false, "Blame: Dumping this process tree (from bottom):");

                    foreach (var p in processTree.OrderBy(t => t.Level))
                    {
                        EqtTrace.Verbose($"NetClientHangDumper.Dump: {(p.Level != 0 ? " + " : " > ")}{new string('-', p.Level)} {p.Process.Id} - {p.Process.ProcessName}");
                        ConsoleOutput.Instance.Information(false, $"Blame: {(p.Level != 0 ? " + " : " > ")}{new string('-', p.Level)} {p.Process.Id} - {p.Process.ProcessName}");
                    }
                }
                else
                {
                    EqtTrace.Verbose($"NetClientHangDumper.Dump: Dumping {process.Id} - {process.ProcessName}.");
                    ConsoleOutput.Instance.Information(false, $"Blame: Dumping {process.Id} - {process.ProcessName}");
                }
            }

            var bottomUpTree = processTree.OrderByDescending(t => t.Level).Select(t => t.Process);

            // Do not suspend processes with NetClient dumper it stops the diagnostic thread running in
            // them and hang dump request will get stuck forever, because the process is not co-operating.
            // Instead we start one task per dump asynchronously, and hope that the parent process will start dumping
            // before the child process is done dumping. This way if the parent is waiting for the children to exit,
            // we will be dumping it before it observes the child exiting and we get a more accurate results. If we did not
            // do this, then parent that is awaiting child might exit before we get to dumping it.
            var tasks   = new List <Task>();
            var timeout = new CancellationTokenSource();

            timeout.CancelAfter(TimeSpan.FromMinutes(5));
            foreach (var p in bottomUpTree)
            {
                tasks.Add(Task.Run(
                              () =>
                {
                    try
                    {
                        var outputFile = Path.Combine(outputDirectory, $"{p.ProcessName}_{p.Id}_{DateTime.Now:yyyyMMddTHHmmss}_hangdump.dmp");
                        EqtTrace.Verbose($"NetClientHangDumper.CollectDump: Selected dump type {type}. Dumping {process.Id} - {process.ProcessName} in {outputFile}. ");

                        var client = new DiagnosticsClient(p.Id);

                        // Connecting the dump generation logging to verbose output to avoid changing the interfaces again -> EqtTrace.IsVerboseEnabled
                        // before we test this on some big repo.
                        client.WriteDump(type == DumpTypeOption.Full ? DumpType.Full : DumpType.Normal, outputFile, logDumpGeneration: false);
                    }
                    catch (Exception ex)
                    {
                        EqtTrace.Error($"NetClientHangDumper.Dump: Error dumping process {p.Id} - {p.ProcessName}: {ex}.");
                    }
                }, timeout.Token));
            }

            try
            {
                Task.WhenAll(tasks).GetAwaiter().GetResult();
            }
            catch (TaskCanceledException)
            {
                EqtTrace.Error($"NetClientHangDumper.Dump: Hang dump timed out.");
            }

            foreach (var p in bottomUpTree)
            {
                try
                {
                    EqtTrace.Verbose($"NetClientHangDumper.Dump: Killing process {p.Id} - {p.ProcessName}.");
                    p.Kill();
                }
                catch (Exception ex)
                {
                    EqtTrace.Error($"NetClientHangDumper.Dump: Error killing process {p.Id} - {p.ProcessName}: {ex}.");
                }
            }
        }
Пример #21
0
 public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType)
 {
     // we don't need to do anything directly here, we setup the env variables
     // in the dumper configuration, including the path
 }
Пример #22
0
            internal static async Task CollectDumpAsync(Process process, string fileName, DumpTypeOption type)
            {
                // We don't work on WSL :(
                string ostype = await File.ReadAllTextAsync("/proc/sys/kernel/osrelease");

                if (ostype.Contains("Microsoft"))
                {
                    throw new PlatformNotSupportedException("Cannot collect memory dumps from Windows Subsystem for Linux.");
                }

                // First step is to find the .NET runtime. To do this we look for coreclr.so
                ProcessModule coreclr = process.Modules.Cast <ProcessModule>().FirstOrDefault(m => string.Equals(m.ModuleName, "libcoreclr.so"));

                if (coreclr == null)
                {
                    throw new NotSupportedException("Unable to locate .NET runtime associated with this process!");
                }

                // Find createdump next to that file
                string runtimeDirectory = Path.GetDirectoryName(coreclr.FileName);
                string createDumpPath   = Path.Combine(runtimeDirectory, "createdump");

                if (!File.Exists(createDumpPath))
                {
                    throw new NotSupportedException($"Unable to locate 'createdump' tool in '{runtimeDirectory}'");
                }

                // Create the dump
                int exitCode = await CreateDumpAsync(createDumpPath, fileName, process.Id, type);

                if (exitCode != 0)
                {
                    throw new InvalidOperationException($"createdump exited with non-zero exit code: {exitCode}");
                }
            }