예제 #1
0
파일: SOS.cs 프로젝트: mikkelbu/diagnostics
    private async Task RunTest(TestConfiguration config, string testName, string debuggeeName, string scriptName, string debuggeeArguments = null, bool useCreateDump = true)
    {
        SkipIfArm(config);

        // Live
        using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments))
        {
            await runner.RunScript(scriptName);
        }

        // Generate a crash dump.
        if (IsCreateDumpConfig(config))
        {
            await SOSRunner.CreateDump(config, Output, testName, debuggeeName, debuggeeArguments, useCreateDump);
        }

        // Test against a crash dump.
        if (IsOpenDumpConfig(config))
        {
            // With cdb (Windows) or lldb (Linux or OSX)
            using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments, SOSRunner.Options.LoadDump))
            {
                await runner.RunScript(scriptName);
            }

            // With the dotnet-dump analyze tool
            if (OS.Kind == OSKind.Linux)
            {
                using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments, SOSRunner.Options.LoadDumpWithDotNetDump))
                {
                    await runner.RunScript(scriptName);
                }
            }
        }
    }
예제 #2
0
파일: SOS.cs 프로젝트: cshung/diagnostics
    private async Task RunTest(string scriptName, bool testLive = true, bool testDump = true, SOSRunner.TestInformation information = null)
    {
        information.OutputHelper = Output;

        if (testLive)
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.Live))
            {
                await runner.RunScript(scriptName);
            }
        }

        if (testDump)
        {
            string dumpName = null;

            // Create and test dumps on OSX or Alpine only if the runtime is 6.0 or greater
            if (!(OS.Kind == OSKind.OSX || OS.IsAlpine) || information.TestConfiguration.RuntimeFrameworkVersionMajor > 5)
            {
                // Generate a crash dump.
                if (information.DebuggeeDumpOutputRootDir != null)
                {
                    dumpName = await SOSRunner.CreateDump(information);
                }

                // Test against a crash dump.
                if (information.DebuggeeDumpInputRootDir != null)
                {
                    // With cdb (Windows) or lldb (Linux)
                    using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDump))
                    {
                        await runner.RunScript(scriptName);
                    }

                    // Using the dotnet-dump analyze tool if the path exists in the config file.
                    // TODO: dotnet-dump currently doesn't support macho core dumps that the MacOS createdump generates
                    if (information.TestConfiguration.DotNetDumpPath() != null && OS.Kind != OSKind.OSX)
                    {
                        // Don't test dotnet-dump on triage dumps when running on desktop CLR.
                        if (information.TestConfiguration.IsNETCore || information.DumpType != SOSRunner.DumpType.Triage)
                        {
                            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDumpWithDotNetDump))
                            {
                                await runner.RunScript(scriptName);
                            }
                        }
                    }
                }

                // Test the crash report json file
                if (dumpName != null && information.TestCrashReport)
                {
                    TestCrashReport(dumpName, information);
                }
            }
        }
    }
예제 #3
0
    private async Task RunTest(string scriptName, bool testLive = true, bool testDump = true, SOSRunner.TestInformation information = null)
    {
        information.OutputHelper = Output;

        if (testLive && !SOSRunner.IsAlpine())
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.Live))
            {
                await runner.RunScript(scriptName);
            }
        }

        if (testDump)
        {
            // Create and test dumps on OSX only if the runtime is 6.0 or greater
            // TODO: reenable for 5.0 when the MacOS createdump fixes make it into a service release (https://github.com/dotnet/diagnostics/issues/1749)
            if (OS.Kind != OSKind.OSX || information.TestConfiguration.RuntimeFrameworkVersionMajor > 5)
            {
                // Generate a crash dump.
                if (information.TestConfiguration.DebuggeeDumpOutputRootDir() != null)
                {
                    if (information.DumpGenerator == SOSRunner.DumpGenerator.NativeDebugger && SOSRunner.IsAlpine())
                    {
                        throw new SkipTestException("lldb tests not supported on Alpine");
                    }
                    await SOSRunner.CreateDump(information);
                }

                // Test against a crash dump.
                if (information.TestConfiguration.DebuggeeDumpInputRootDir() != null)
                {
                    if (!SOSRunner.IsAlpine())
                    {
                        // With cdb (Windows) or lldb (Linux)
                        using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDump))
                        {
                            await runner.RunScript(scriptName);
                        }
                    }

                    // Using the dotnet-dump analyze tool if the path exists in the config file.
                    // TODO: dotnet-dump currently doesn't support macho core dumps that the MacOS createdump generates
                    if (information.TestConfiguration.DotNetDumpPath() != null && OS.Kind != OSKind.OSX)
                    {
                        // Don't test dotnet-dump on triage dumps when running on desktop CLR.
                        if (information.TestConfiguration.IsNETCore || information.DumpType != SOSRunner.DumpType.Triage)
                        {
                            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDumpWithDotNetDump))
                            {
                                await runner.RunScript(scriptName);
                            }
                        }
                    }
                }
            }
        }
    }
예제 #4
0
파일: SOS.cs 프로젝트: brianrob/diagnostics
 public async Task GCTests(TestConfiguration config)
 {
     // Live only
     SkipIfArm(config);
     using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName: "SOS.GCTests", debuggeeName: "GCWhere"))
     {
         await runner.RunScript("GCTests.script");
     }
 }
예제 #5
0
    private async Task RunTest(string scriptName, bool testLive = true, bool testDump = true, SOSRunner.TestInformation information = null)
    {
        information.OutputHelper = Output;

        if (testLive && !SOSRunner.IsAlpine())
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.Live))
            {
                await runner.RunScript(scriptName);
            }
        }

        if (testDump)
        {
            // Create and test dumps on OSX only if the runtime is 5.0 or greater
            if (OS.Kind != OSKind.OSX || information.TestConfiguration.RuntimeFrameworkVersionMajor >= 5)
            {
                // Generate a crash dump.
                if (information.TestConfiguration.DebuggeeDumpOutputRootDir() != null)
                {
                    if (information.DumpGenerator == SOSRunner.DumpGenerator.NativeDebugger && SOSRunner.IsAlpine())
                    {
                        throw new SkipTestException("lldb tests not supported on Alpine");
                    }
                    await SOSRunner.CreateDump(information);
                }

                // Test against a crash dump.
                if (information.TestConfiguration.DebuggeeDumpInputRootDir() != null)
                {
                    if (!SOSRunner.IsAlpine() && OS.Kind != OSKind.OSX)
                    {
                        // With cdb (Windows) or lldb (Linux)
                        using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDump))
                        {
                            await runner.RunScript(scriptName);
                        }
                    }

                    // Using the dotnet-dump analyze tool if the path exists in the config file.
                    if (information.TestConfiguration.DotNetDumpPath() != null)
                    {
                        // Don't test dotnet-dump on triage dumps when running on desktop CLR.
                        if (information.TestConfiguration.IsNETCore || information.DumpType != SOSRunner.DumpType.Triage)
                        {
                            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDumpWithDotNetDump))
                            {
                                await runner.RunScript(scriptName);
                            }
                        }
                    }
                }
            }
        }
    }
예제 #6
0
파일: SOS.cs 프로젝트: Maoni0/diagnostics
    private async Task RunTest(string scriptName, SOSRunner.TestInformation information)
    {
        information.OutputHelper = Output;

        if (information.TestLive)
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.Live))
            {
                await runner.RunScript(scriptName);
            }
        }

        if (information.TestDump)
        {
            string dumpName = null;

            // Generate a crash dump.
            if (information.DebuggeeDumpOutputRootDir != null)
            {
                dumpName = await SOSRunner.CreateDump(information);
            }

            // Test against a crash dump.
            if (information.DebuggeeDumpInputRootDir != null)
            {
                // With cdb (Windows) or lldb (Linux)
                using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDump))
                {
                    await runner.RunScript(scriptName);
                }

                // Using the dotnet-dump analyze tool if the path exists in the config file.
                if (information.TestConfiguration.DotNetDumpPath() != null)
                {
                    // Don't test dotnet-dump on triage dumps when running on desktop CLR.
                    if (information.TestConfiguration.IsNETCore || information.DumpType != SOSRunner.DumpType.Triage)
                    {
                        using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDumpWithDotNetDump))
                        {
                            await runner.RunScript(scriptName);
                        }
                    }
                }
            }

            // Test the crash report json file
            if (dumpName != null && information.TestCrashReport)
            {
                TestCrashReport(dumpName, information);
            }
        }
    }
예제 #7
0
파일: SOS.cs 프로젝트: tmds/diagnostics
 public async Task GCTests(TestConfiguration config)
 {
     // Live only
     SkipIfArm(config);
     if (SOSRunner.IsAlpine())
     {
         throw new SkipTestException("lldb tests not supported on Alpine");
     }
     using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName: "SOS.GCTests", debuggeeName: "GCWhere"))
     {
         await runner.RunScript("GCTests.script");
     }
 }
예제 #8
0
파일: SOS.cs 프로젝트: ziyasal/diagnostics
    private async Task RunTest(string scriptName, bool testLive = true, bool testDump = true, SOSRunner.TestInformation information = null)
    {
        information.OutputHelper = Output;

        if (testLive && !SOSRunner.IsAlpine())
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.Live))
            {
                await runner.RunScript(scriptName);
            }
        }

        if (testDump)
        {
            // Generate a crash dump.
            if (information.TestConfiguration.DebuggeeDumpOutputRootDir() != null)
            {
                if (information.DumpGenerator == SOSRunner.DumpGenerator.NativeDebugger && SOSRunner.IsAlpine())
                {
                    throw new SkipTestException("lldb tests not supported on Alpine");
                }
                await SOSRunner.CreateDump(information);
            }

            // Test against a crash dump.
            if (information.TestConfiguration.DebuggeeDumpInputRootDir() != null)
            {
                if (!SOSRunner.IsAlpine())
                {
                    // With cdb (Windows) or lldb (Linux or OSX)
                    using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDump))
                    {
                        await runner.RunScript(scriptName);
                    }
                }

                // With the dotnet-dump analyze tool
                if (information.TestConfiguration.DotNetDumpPath() != null)
                {
                    using (SOSRunner runner = await SOSRunner.StartDebugger(information, SOSRunner.DebuggerAction.LoadDumpWithDotNetDump))
                    {
                        await runner.RunScript(scriptName);
                    }
                }
            }
        }
    }
예제 #9
0
파일: SOS.cs 프로젝트: tmds/diagnostics
    private async Task RunTest(TestConfiguration config, string testName, string debuggeeName, string scriptName, string debuggeeArguments = null, bool useCreateDump = true)
    {
        SkipIfArm(config);

        if (!SOSRunner.IsAlpine())
        {
            // Live
            using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments))
            {
                await runner.RunScript(scriptName);
            }
        }

        // Generate a crash dump.
        if (IsCreateDumpConfig(config))
        {
            if (!useCreateDump && SOSRunner.IsAlpine())
            {
                throw new SkipTestException("lldb tests not supported on Alpine");
            }
            await SOSRunner.CreateDump(config, Output, testName, debuggeeName, debuggeeArguments, useCreateDump);
        }

        // Test against a crash dump.
        if (IsOpenDumpConfig(config))
        {
            if (!SOSRunner.IsAlpine())
            {
                // With cdb (Windows) or lldb (Linux or OSX)
                using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments, SOSRunner.Options.LoadDump))
                {
                    await runner.RunScript(scriptName);
                }
            }

            // With the dotnet-dump analyze tool
            if (config.DotNetDumpPath() != null)
            {
                using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments, SOSRunner.Options.LoadDumpWithDotNetDump))
                {
                    await runner.RunScript(scriptName);
                }
            }
        }
    }
예제 #10
0
파일: SOS.cs 프로젝트: brianrob/diagnostics
    private async Task RunTest(TestConfiguration config, string testName, string debuggeeName, string scriptName, string debuggeeArguments = null, bool useCreateDump = true)
    {
        SkipIfArm(config);

        // Live
        using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments))
        {
            await runner.RunScript(scriptName);
        }

        // Against a crash dump.
        if (IsCreateDumpConfig(config))
        {
            await SOSRunner.CreateDump(config, Output, testName, debuggeeName, debuggeeArguments, useCreateDump);
        }

        if (IsOpenDumpConfig(config))
        {
            using (SOSRunner runner = await SOSRunner.StartDebugger(config, Output, testName, debuggeeName, debuggeeArguments, loadDump: true))
            {
                await runner.RunScript(scriptName);
            }
        }
    }
예제 #11
0
    public async Task LLDBPluginTests(TestConfiguration config)
    {
        if (OS.Kind == OSKind.Windows || config.IsDesktop || config.RuntimeFrameworkVersionMajor == 1 || SOSRunner.IsAlpine())
        {
            throw new SkipTestException("lldb plugin tests not supported on Windows, Alpine Linux or .NET Core 1.1");
        }
        string testName = "SOS." + nameof(LLDBPluginTests);

        TestRunner.OutputHelper outputHelper = null;
        try
        {
            // Setup the logging from the options in the config file
            outputHelper = TestRunner.ConfigureLogging(config, Output, testName);

            outputHelper.WriteLine("Starting {0}", testName);
            outputHelper.WriteLine("{");

            string program = "/usr/bin/python";
            if (!File.Exists(program))
            {
                throw new ArgumentException($"{program} does not exists");
            }
            var    arguments   = new StringBuilder();
            string repoRootDir = TestConfiguration.MakeCanonicalPath(config.AllSettings["RepoRootDir"]);

            // Get test python script path
            string scriptDir = Path.Combine(repoRootDir, "src", "SOS", "lldbplugin.tests");
            arguments.Append(Path.Combine(scriptDir, "test_libsosplugin.py"));
            arguments.Append(" ");

            // Get lldb path
            arguments.AppendFormat("--lldb {0} ", Environment.GetEnvironmentVariable("LLDB_PATH") ?? throw new ArgumentException("LLDB_PATH environment variable not set"));

            // Add dotnet host program and arguments
            arguments.Append("--host \"");
            arguments.Append(config.HostExe);
            arguments.Append(" ");
            if (!string.IsNullOrWhiteSpace(config.HostArgs))
            {
                arguments.Append(config.HostArgs);
                arguments.Append(" ");
            }
            arguments.Append("\" ");

            // Add lldb plugin path
            arguments.AppendFormat("--plugin {0} ", config.SOSPath() ?? throw new ArgumentException("SOSPath config not set"));

            // Add log directory
            string logFileDir = Path.Combine(config.LogDirPath, config.RuntimeFrameworkVersion);
            Directory.CreateDirectory(logFileDir);
            arguments.AppendFormat("--logfiledir {0} ", logFileDir);

            // Add test debuggee assembly
            string testDebuggee = Path.Combine(repoRootDir, "artifacts", "bin", "TestDebuggee", config.TargetConfiguration, config.BuildProjectFramework, "TestDebuggee.dll");
            arguments.AppendFormat("--assembly {0}", testDebuggee);

            // Create the python script process runner
            ProcessRunner processRunner = new ProcessRunner(program, arguments.ToString()).
                                          WithLog(new TestRunner.TestLogger(outputHelper.IndentedOutput)).
                                          WithTimeout(TimeSpan.FromMinutes(10)).
                                          WithExpectedExitCode(0).
                                          WithWorkingDirectory(scriptDir).
                                          // Turn on stress logging so the dumplog and histinit commands pass
                                          WithEnvironmentVariable("COMPlus_LogFacility", "0xffffffbf").
                                          WithEnvironmentVariable("COMPlus_LogLevel", "6").
                                          WithEnvironmentVariable("COMPlus_StressLog", "1").
                                          WithEnvironmentVariable("COMPlus_StressLogSize", "65536");

            // Start the process runner
            processRunner.Start();

            // Wait for the debuggee to finish
            await processRunner.WaitForExit();
        }
        catch (Exception ex)
        {
            // Log the exception
            outputHelper?.WriteLine(ex.ToString());
            throw;
        }
        finally
        {
            outputHelper?.WriteLine("}");
            outputHelper?.Dispose();
        }
    }
예제 #12
0
    /// <summary>
    /// Run a debuggee and create a dump.
    /// </summary>
    /// <param name="config">test configuration</param>
    /// <param name="output">output instance</param>
    /// <param name="testName">name of test</param>
    /// <param name="debuggeeName">debuggee name</param>
    /// <param name="debuggeeArguments">optional args to pass to debuggee</param>
    /// <param name="useCreateDump">if true, use "createdump" to generate core dump</param>
    public static async Task CreateDump(TestConfiguration config, ITestOutputHelper output, string testName, string debuggeeName,
                                        string debuggeeArguments = null, bool useCreateDump = true)
    {
        Directory.CreateDirectory(config.DebuggeeDumpOutputRootDir());

        if (!config.CreateDumpExists || !useCreateDump || config.GenerateDumpWithLLDB() || config.GenerateDumpWithGDB())
        {
            using (SOSRunner runner = await SOSRunner.StartDebugger(config, output, testName, debuggeeName, debuggeeArguments, Options.GenerateDump))
            {
                try
                {
                    await runner.LoadSosExtension();

                    string command = null;
                    switch (runner.Debugger)
                    {
                    case SOSRunner.NativeDebugger.Cdb:
                        await runner.ContinueExecution();

                        // On desktop create triage dump. On .NET Core, create full dump.
                        command = config.IsDesktop ? ".dump /o /mshuRp %DUMP_NAME%" : ".dump /o /ma %DUMP_NAME%";
                        break;

                    case SOSRunner.NativeDebugger.Gdb:
                        command = "generate-core-file %DUMP_NAME%";
                        break;

                    case SOSRunner.NativeDebugger.Lldb:
                        await runner.ContinueExecution();

                        command = "sos CreateDump %DUMP_NAME%";
                        break;

                    default:
                        throw new Exception(runner.Debugger.ToString() + " does not support creating dumps");
                    }

                    await runner.RunCommand(command);

                    await runner.QuitDebugger();
                }
                catch (Exception ex)
                {
                    runner.WriteLine(ex.ToString());
                    throw;
                }
            }
        }
        else
        {
            TestRunner.OutputHelper outputHelper = null;
            try
            {
                // Setup the logging from the options in the config file
                outputHelper = TestRunner.ConfigureLogging(config, output, testName);

                // Restore and build the debuggee. The debuggee name is lower cased because the
                // source directory name has been lowercased by the build system.
                DebuggeeConfiguration debuggeeConfig = await DebuggeeCompiler.Execute(config, debuggeeName, outputHelper);

                outputHelper.WriteLine("Starting {0}", testName);
                outputHelper.WriteLine("{");

                // Get the full debuggee launch command line (includes the host if required)
                string exePath   = debuggeeConfig.BinaryExePath;
                var    arguments = new StringBuilder();
                if (!string.IsNullOrWhiteSpace(config.HostExe))
                {
                    exePath = config.HostExe;
                    if (!string.IsNullOrWhiteSpace(config.HostArgs))
                    {
                        arguments.Append(config.HostArgs);
                        arguments.Append(" ");
                    }
                    arguments.Append(debuggeeConfig.BinaryExePath);
                }
                if (!string.IsNullOrWhiteSpace(debuggeeArguments))
                {
                    arguments.Append(" ");
                    arguments.Append(debuggeeArguments);
                }

                // Run the debuggee with the createdump environment variables set to generate a coredump on unhandled exception
                var           testLogger    = new TestRunner.TestLogger(outputHelper.IndentedOutput);
                var           variables     = GenerateVariables(config, debuggeeConfig, Options.GenerateDump);
                ProcessRunner processRunner = new ProcessRunner(exePath, ReplaceVariables(variables, arguments.ToString())).
                                              WithLog(testLogger).
                                              WithTimeout(TimeSpan.FromMinutes(5)).
                                              WithEnvironmentVariable("COMPlus_DbgEnableMiniDump", "1").
                                              WithEnvironmentVariable("COMPlus_DbgMiniDumpName", ReplaceVariables(variables, "%DUMP_NAME%"));

                processRunner.Start();

                // Wait for the debuggee to finish
                await processRunner.WaitForExit();
            }
            catch (Exception ex)
            {
                // Log the exception
                outputHelper?.WriteLine(ex.ToString());
                throw;
            }
            finally
            {
                outputHelper?.WriteLine("}");
                outputHelper?.Dispose();
            }
        }
    }
예제 #13
0
    /// <summary>
    /// Start a debuggee under a native debugger returning a sos runner instance.
    /// </summary>
    /// <param name="config">test configuration</param>
    /// <param name="output">output instance</param>
    /// <param name="testName">name of test</param>
    /// <param name="debuggeeName">debuggee name</param>
    /// <param name="debuggeeArguments">optional args to pass to debuggee</param>
    /// <param name="options">dump options</param>
    /// <returns>sos runner instance</returns>
    public static async Task <SOSRunner> StartDebugger(TestConfiguration config, ITestOutputHelper output, string testName, string debuggeeName,
                                                       string debuggeeArguments = null, Options options = Options.None)
    {
        TestRunner.OutputHelper outputHelper = null;
        SOSRunner sosRunner = null;

        // Figure out which native debugger to use
        NativeDebugger debugger = GetNativeDebuggerToUse(config, options);

        try
        {
            // Setup the logging from the options in the config file
            outputHelper = TestRunner.ConfigureLogging(config, output, testName);

            // Restore and build the debuggee.
            DebuggeeConfiguration debuggeeConfig = await DebuggeeCompiler.Execute(config, debuggeeName, outputHelper);

            outputHelper.WriteLine("SOSRunner processing {0}", testName);
            outputHelper.WriteLine("{");

            var variables    = GenerateVariables(config, debuggeeConfig, options);
            var scriptLogger = new ScriptLogger(debugger, outputHelper.IndentedOutput);

            if (options == Options.LoadDump || options == Options.LoadDumpWithDotNetDump)
            {
                if (!variables.TryGetValue("%DUMP_NAME%", out string dumpName) || !File.Exists(dumpName))
                {
                    throw new FileNotFoundException($"Dump file does not exist: {dumpName ?? ""}");
                }
            }

            // Get the full debuggee launch command line (includes the host if required)
            var debuggeeCommandLine = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(config.HostExe))
            {
                debuggeeCommandLine.Append(config.HostExe);
                debuggeeCommandLine.Append(" ");
                if (!string.IsNullOrWhiteSpace(config.HostArgs))
                {
                    debuggeeCommandLine.Append(config.HostArgs);
                    debuggeeCommandLine.Append(" ");
                }
            }
            debuggeeCommandLine.Append(debuggeeConfig.BinaryExePath);
            if (!string.IsNullOrWhiteSpace(debuggeeArguments))
            {
                debuggeeCommandLine.Append(" ");
                debuggeeCommandLine.Append(debuggeeArguments);
            }

            // Get the native debugger path
            string debuggerPath = GetNativeDebuggerPath(debugger, config);
            if (string.IsNullOrWhiteSpace(debuggerPath) || !File.Exists(debuggerPath))
            {
                throw new FileNotFoundException($"Native debugger path not set or does not exist: {debuggerPath}");
            }

            // Get the debugger arguments and commands to run initially
            List <string> initialCommands = new List <string>();
            var           arguments       = new StringBuilder();

            switch (debugger)
            {
            case NativeDebugger.Cdb:
                string helperExtension = config.CDBHelperExtension();
                if (string.IsNullOrWhiteSpace(helperExtension) || !File.Exists(helperExtension))
                {
                    throw new ArgumentException($"CDB helper script path not set or does not exist: {helperExtension}");
                }
                arguments.AppendFormat(@"-c "".load {0}""", helperExtension);

                if (options == Options.LoadDump)
                {
                    arguments.Append(" -z %DUMP_NAME%");
                }
                else
                {
                    arguments.AppendFormat(" -Gsins {0}", debuggeeCommandLine);

                    // disable stopping on integer divide-by-zero and integer overflow exceptions
                    initialCommands.Add("sxd dz");
                    initialCommands.Add("sxd iov");
                }
                initialCommands.Add(".sympath %DEBUG_ROOT%");
                initialCommands.Add(".extpath " + Path.GetDirectoryName(config.SOSPath()));

                // Add the path to runtime so cdb/sos can find mscordbi.
                string runtimeSymbolsPath = config.RuntimeSymbolsPath;
                if (runtimeSymbolsPath != null)
                {
                    initialCommands.Add(".sympath+ " + runtimeSymbolsPath);
                }
                // Turn off warnings that can happen in the middle of a command's output
                initialCommands.Add(".outmask- 4");
                break;

            case NativeDebugger.Lldb:
                // Get the lldb python script file path necessary to capture the output of commands
                // by printing a prompt after all the command output is printed.
                string lldbHelperScript = config.LLDBHelperScript();
                if (string.IsNullOrWhiteSpace(lldbHelperScript) || !File.Exists(lldbHelperScript))
                {
                    throw new ArgumentException("LLDB helper script path not set or does not exist: " + lldbHelperScript);
                }
                arguments.AppendFormat(@"--no-lldbinit -o ""settings set interpreter.prompt-on-quit false"" -o ""command script import {0}"" -o ""version""", lldbHelperScript);

                // Load the dump or launch the debuggee process
                if (options == Options.LoadDump)
                {
                    initialCommands.Add($@"target create --core ""%DUMP_NAME%"" ""{config.HostExe}""");
                }
                else
                {
                    var sb = new StringBuilder("settings set -- target.run-args");
                    if (!string.IsNullOrWhiteSpace(config.HostArgs))
                    {
                        string[] args = ReplaceVariables(variables, config.HostArgs).Trim().Split(' ');
                        foreach (string arg in args)
                        {
                            sb.AppendFormat(@" ""{0}""", arg);
                        }
                    }
                    sb.AppendFormat(@" ""{0}""", debuggeeConfig.BinaryExePath);
                    if (!string.IsNullOrWhiteSpace(debuggeeArguments))
                    {
                        string[] args = ReplaceVariables(variables, debuggeeArguments).Trim().Split(' ');
                        foreach (string arg in args)
                        {
                            sb.AppendFormat(@" ""{0}""", arg);
                        }
                    }
                    initialCommands.Add($@"target create ""{config.HostExe}""");
                    initialCommands.Add(sb.ToString());
                    initialCommands.Add("process launch -s");

                    // .NET Core 1.1 or less don't catch stack overflow and abort so need to catch SIGSEGV
                    if (config.StackOverflowSIGSEGV)
                    {
                        initialCommands.Add("process handle -s true -n true -p true SIGSEGV");
                    }
                    else
                    {
                        initialCommands.Add("process handle -s false -n false -p true SIGSEGV");
                    }
                    initialCommands.Add("process handle -s false -n false -p true SIGFPE");
                    initialCommands.Add("process handle -s true -n true -p true SIGABRT");
                }
                break;

            case NativeDebugger.Gdb:
                if (options == Options.LoadDump || options == Options.LoadDumpWithDotNetDump)
                {
                    throw new ArgumentException("GDB not meant for loading core dumps");
                }
                arguments.AppendFormat("--args {0}", debuggeeCommandLine);

                // .NET Core 1.1 or less don't catch stack overflow and abort so need to catch SIGSEGV
                if (config.StackOverflowSIGSEGV)
                {
                    initialCommands.Add("handle SIGSEGV stop print");
                }
                else
                {
                    initialCommands.Add("handle SIGSEGV nostop noprint");
                }
                initialCommands.Add("handle SIGFPE nostop noprint");
                initialCommands.Add("handle SIGABRT stop print");
                initialCommands.Add("set startup-with-shell off");
                initialCommands.Add("set use-coredump-filter on");
                initialCommands.Add("run");
                break;

            case NativeDebugger.DotNetDump:
                if (options != Options.LoadDumpWithDotNetDump)
                {
                    throw new ArgumentException($"{options} not supported for dotnet-dump testing");
                }
                if (string.IsNullOrWhiteSpace(config.HostExe))
                {
                    throw new ArgumentException("No HostExe in configuration");
                }
                arguments.Append(debuggerPath);
                arguments.Append(@" analyze %DUMP_NAME%");
                debuggerPath = config.HostExe;
                break;
            }

            // Create the native debugger process running
            ProcessRunner processRunner = new ProcessRunner(debuggerPath, ReplaceVariables(variables, arguments.ToString())).
                                          WithLog(scriptLogger).
                                          WithTimeout(TimeSpan.FromMinutes(10));

            // Create the sos runner instance
            sosRunner = new SOSRunner(debugger, config, outputHelper, variables, scriptLogger, processRunner, options == Options.LoadDump || options == Options.LoadDumpWithDotNetDump);

            // Start the native debugger
            processRunner.Start();

            // Set the coredump_filter flags on the gdb process so the coredump it
            // takes of the target process contains everything the tests need.
            if (debugger == NativeDebugger.Gdb)
            {
                initialCommands.Insert(0, string.Format("shell echo 0x3F > /proc/{0}/coredump_filter", processRunner.ProcessId));
            }

            // Execute the initial debugger commands
            await sosRunner.RunCommands(initialCommands);

            return(sosRunner);
        }
        catch (Exception ex)
        {
            // Log the exception
            outputHelper?.WriteLine(ex.ToString());

            // The runner needs to kill the process and dispose of the file logger
            sosRunner?.Dispose();

            // The file logging output helper needs to be disposed to close the file
            outputHelper?.Dispose();
            throw;
        }
    }