コード例 #1
0
        public override void InitStreams(LaunchOptions options, out StreamReader reader, out StreamWriter writer)
        {
            LocalLaunchOptions localOptions  = (LocalLaunchOptions)options;
            string             miDebuggerDir = System.IO.Path.GetDirectoryName(localOptions.MIDebuggerPath);

            Process proc = new Process();

            proc.StartInfo.FileName         = localOptions.MIDebuggerPath;
            proc.StartInfo.Arguments        = "--interpreter=mi";
            proc.StartInfo.WorkingDirectory = miDebuggerDir;

            // On Windows, GDB locally requires that the directory be on the PATH, being the working directory isn't good enough
            if (PlatformUtilities.IsWindows() &&
                options.DebuggerMIMode == MIMode.Gdb)
            {
                string path = proc.StartInfo.GetEnvironmentVariable("PATH");
                path = (string.IsNullOrEmpty(path) ? miDebuggerDir : path + ";" + miDebuggerDir);
                proc.StartInfo.SetEnvironmentVariable("PATH", path);
            }

            foreach (EnvironmentEntry entry in localOptions.Environment)
            {
                proc.StartInfo.SetEnvironmentVariable(entry.Name, entry.Value);
            }

            InitProcess(proc, out reader, out writer);
        }
コード例 #2
0
        public override void InitStreams(LaunchOptions options, out StreamReader reader, out StreamWriter writer)
        {
            LocalLaunchOptions localOptions  = (LocalLaunchOptions)options;
            string             miDebuggerDir = System.IO.Path.GetDirectoryName(localOptions.MIDebuggerPath);

            Process proc = new Process();

            proc.StartInfo.FileName  = localOptions.MIDebuggerPath;
            proc.StartInfo.Arguments = localOptions.GetMiDebuggerArgs();

            // LLDB has the -environment-cd mi command that is used to set the working dir for gdb/clrdbg, but it doesn't work.
            // So, set lldb's working dir to the user's requested folder before launch.
            proc.StartInfo.WorkingDirectory = options.DebuggerMIMode == MIMode.Lldb ? options.WorkingDirectory : miDebuggerDir;

            // On Windows, GDB locally requires that the directory be on the PATH, being the working directory isn't good enough
            if (PlatformUtilities.IsWindows() &&
                options.DebuggerMIMode == MIMode.Gdb)
            {
                string path = proc.StartInfo.GetEnvironmentVariable("PATH");
                path = (string.IsNullOrEmpty(path) ? miDebuggerDir : path + ";" + miDebuggerDir);
                proc.StartInfo.SetEnvironmentVariable("PATH", path);
            }

            // Only pass the environment to launch clrdbg. For other modes, there are commands that set the environment variables
            // directly for the debuggee.
            if (options.DebuggerMIMode == MIMode.Clrdbg)
            {
                foreach (EnvironmentEntry entry in localOptions.Environment)
                {
                    proc.StartInfo.SetEnvironmentVariable(entry.Name, entry.Value);
                }
            }

            InitProcess(proc, out reader, out writer);
        }
コード例 #3
0
        private void LaunchSuccess(int?pid)
        {
            if (_pidReader != null)
            {
                int           shellPid;
                Task <string> readShellPidTask = _pidReader.ReadLineAsync();
                if (readShellPidTask.Wait(TimeSpan.FromSeconds(10)))
                {
                    shellPid = int.Parse(readShellPidTask.Result, CultureInfo.InvariantCulture);
                    // Used for testing
                    Logger?.WriteLine(string.Concat("ShellPid=", shellPid));
                }
                else
                {
                    // Something is wrong because we didn't get the pid of shell
                    ForceDisposeStreamReader(_pidReader);
                    Close();
                    throw new TimeoutException(string.Format(CultureInfo.CurrentCulture, MICoreResources.Error_RunInTerminalFailure, MICoreResources.Error_TimeoutWaitingForConnection));
                }

                if (!PlatformUtilities.IsWindows())
                {
                    _shellProcessMonitor = new ProcessMonitor(shellPid);
                    _shellProcessMonitor.ProcessExited += ShellExited;
                    _shellProcessMonitor.Start();
                }
                else
                {
                    Process shellProcess = Process.GetProcessById(shellPid);
                    shellProcess.EnableRaisingEvents = true;
                    shellProcess.Exited += ShellExited;
                }

                Task <string> readDebuggerPidTask = _pidReader.ReadLineAsync();
                try
                {
                    readDebuggerPidTask.Wait(_streamReadPidCancellationTokenSource.Token);
                    _debuggerPid = int.Parse(readDebuggerPidTask.Result, CultureInfo.InvariantCulture);
                }
                catch (OperationCanceledException)
                {
                    // Something is wrong because we didn't get the pid of the debugger
                    ForceDisposeStreamReader(_pidReader);
                    Close();
                    throw new OperationCanceledException(string.Format(CultureInfo.CurrentCulture, MICoreResources.Error_RunInTerminalFailure, MICoreResources.Error_UnableToEstablishConnectionToLauncher));
                }
            }

            if (debuggerPidCallback != null)
            {
                debuggerPidCallback(_debuggerPid);
            }
        }
コード例 #4
0
ファイル: LocalTransport.cs プロジェクト: optikos/MIEngine
        public override void InitStreams(LaunchOptions options, out StreamReader reader, out StreamWriter writer)
        {
            LocalLaunchOptions localOptions  = (LocalLaunchOptions)options;
            string             miDebuggerDir = System.IO.Path.GetDirectoryName(localOptions.MIDebuggerPath);

            Process proc = new Process();

            proc.StartInfo.FileName  = localOptions.MIDebuggerPath;
            proc.StartInfo.Arguments = localOptions.GetMiDebuggerArgs();

            // LLDB has the -environment-cd mi command that is used to set the working dir for gdb, but it doesn't work.
            // So, set lldb's working dir to the user's requested folder before launch.
            proc.StartInfo.WorkingDirectory = options.DebuggerMIMode == MIMode.Lldb ? options.WorkingDirectory : miDebuggerDir;

            // On Windows, GDB locally requires that the directory be on the PATH, being the working directory isn't good enough
            if (PlatformUtilities.IsWindows() &&
                options.DebuggerMIMode == MIMode.Gdb)
            {
                string path = proc.StartInfo.GetEnvironmentVariable("PATH");
                path = (string.IsNullOrEmpty(path) ? miDebuggerDir : path + ";" + miDebuggerDir);
                proc.StartInfo.SetEnvironmentVariable("PATH", path);
            }

            // Allow to execute custom commands before launching debugger.
            // For ex., instructing GDB not to break for certain signals
            if (options.DebuggerMIMode == MIMode.Gdb && !string.IsNullOrWhiteSpace(options.WorkingDirectory))
            {
                var gdbInitFile = Path.Combine(options.WorkingDirectory, ".gdbinit");
                if (File.Exists(gdbInitFile))
                {
                    proc.StartInfo.Arguments += " -x \"" + gdbInitFile + "\"";
                }
            }

            InitProcess(proc, out reader, out writer);
        }
コード例 #5
0
        public override async void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null)
        {
            LocalLaunchOptions localOptions = options as LocalLaunchOptions;

            Encoding encNoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

            string        commandPipeName;
            string        outputPipeName;
            string        pidPipeName;
            List <string> cmdArgs = new List <string>();

            string windowtitle = FormattableString.Invariant($"cppdbg: {Path.GetFileName(options.ExePath)}");

            if (PlatformUtilities.IsWindows())
            {
                // Create Windows Named pipes
                commandPipeName = Utilities.GetMIEngineTemporaryFilename("In");
                outputPipeName  = Utilities.GetMIEngineTemporaryFilename("Out");
                pidPipeName     = Utilities.GetMIEngineTemporaryFilename("Pid");
                string errorPipeName = Utilities.GetMIEngineTemporaryFilename("Error");

                NamedPipeServerStream inputToDebugger    = new NamedPipeServerStream(commandPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
                NamedPipeServerStream outputFromDebugger = new NamedPipeServerStream(outputPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte);
                NamedPipeServerStream errorFromDebugger  = new NamedPipeServerStream(errorPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte);
                NamedPipeServerStream pidPipe            = new NamedPipeServerStream(pidPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte);

                _pidReader = new StreamReader(pidPipe, encNoBom, false, UnixUtilities.StreamBufferSize);

                string thisModulePath = typeof(RunInTerminalTransport).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName;
                string launchCommand  = Path.Combine(Path.GetDirectoryName(thisModulePath), "WindowsDebugLauncher.exe");

                if (!File.Exists(launchCommand))
                {
                    string errorMessage = string.Format(CultureInfo.CurrentCulture, MICoreResources.Error_InternalFileMissing, launchCommand);
                    transportCallback.OnStdErrorLine(errorMessage);
                    transportCallback.OnDebuggerProcessExit(null);
                    return;
                }

                cmdArgs.Add(launchCommand);
                cmdArgs.Add("--stdin=" + commandPipeName);
                cmdArgs.Add("--stdout=" + outputPipeName);
                cmdArgs.Add("--stderr=" + errorPipeName);
                cmdArgs.Add("--pid=" + pidPipeName);
                cmdArgs.Add("--dbgExe=" + localOptions.MIDebuggerPath);
                cmdArgs.Add(localOptions.GetMiDebuggerArgs());

                _waitForConnection = Task.WhenAll(
                    inputToDebugger.WaitForConnectionAsync(),
                    outputFromDebugger.WaitForConnectionAsync(),
                    errorFromDebugger.WaitForConnectionAsync(),
                    pidPipe.WaitForConnectionAsync());

                _commandStream = new StreamWriter(inputToDebugger, encNoBom);
                _outputStream  = new StreamReader(outputFromDebugger, encNoBom, false, UnixUtilities.StreamBufferSize);
                _errorStream   = new StreamReader(errorFromDebugger, encNoBom, false, UnixUtilities.StreamBufferSize);
            }
            else
            {
                // Do Linux style pipes
                commandPipeName = UnixUtilities.MakeFifo(identifier: "In", logger: logger);
                outputPipeName  = UnixUtilities.MakeFifo(identifier: "Out", logger: logger);
                pidPipeName     = UnixUtilities.MakeFifo(identifier: "Pid", logger: logger);

                // Create filestreams
                FileStream stdInStream  = new FileStream(commandPipeName, FileMode.Open);
                FileStream stdOutStream = new FileStream(outputPipeName, FileMode.Open);
                _pidReader = new StreamReader(new FileStream(pidPipeName, FileMode.Open), encNoBom, false, UnixUtilities.StreamBufferSize);

                string debuggerCmd = UnixUtilities.GetDebuggerCommand(localOptions);

                // Default working directory is next to the app
                string debuggeeDir;
                if (Path.IsPathRooted(options.ExePath) && File.Exists(options.ExePath))
                {
                    debuggeeDir = Path.GetDirectoryName(options.ExePath);
                }
                else
                {
                    // If we don't know where the app is, default to HOME, and if we somehow can't get that, go with the root directory.
                    debuggeeDir = Environment.GetEnvironmentVariable("HOME");
                    if (string.IsNullOrEmpty(debuggeeDir))
                    {
                        debuggeeDir = "/";
                    }
                }

                string dbgCmdScript          = Path.Combine(Path.GetTempPath(), Utilities.GetMIEngineTemporaryFilename(identifier: "Cmd"));
                string launchDebuggerCommand = UnixUtilities.LaunchLocalDebuggerCommand(
                    debuggeeDir,
                    commandPipeName,
                    outputPipeName,
                    pidPipeName,
                    dbgCmdScript,
                    debuggerCmd,
                    localOptions.GetMiDebuggerArgs());

                logger?.WriteTextBlock("DbgCmd:", launchDebuggerCommand);

                using (FileStream dbgCmdStream = new FileStream(dbgCmdScript, FileMode.CreateNew))
                    using (StreamWriter dbgCmdWriter = new StreamWriter(dbgCmdStream, encNoBom)
                    {
                        AutoFlush = true
                    })
                    {
                        dbgCmdWriter.WriteLine("#!/bin/sh");
                        dbgCmdWriter.Write(launchDebuggerCommand);
                        dbgCmdWriter.Flush();
                    }

                if (PlatformUtilities.IsOSX())
                {
                    string osxLaunchScript = GetOSXLaunchScript();

                    // Call osascript with a path to the AppleScript. The apple script takes 2 parameters: a title for the terminal and the launch script.
                    cmdArgs.Add("/usr/bin/osascript");
                    cmdArgs.Add(osxLaunchScript);
                    cmdArgs.Add(FormattableString.Invariant($"\"{windowtitle}\""));
                    cmdArgs.Add(FormattableString.Invariant($"sh {dbgCmdScript} ;")); // needs a semicolon because this command is running through the launchscript.
                }
                else
                {
                    cmdArgs.Add("sh");
                    cmdArgs.Add(dbgCmdScript);
                }

                _outputStream  = new StreamReader(stdOutStream, encNoBom, false, UnixUtilities.StreamBufferSize);
                _commandStream = new StreamWriter(stdInStream, encNoBom);
            }

            RunInTerminalLauncher launcher = new RunInTerminalLauncher(windowtitle, localOptions.Environment);

            launcher.Launch(
                cmdArgs,
                localOptions.UseExternalConsole,
                LaunchSuccess,
                (error) =>
            {
                transportCallback.OnStdErrorLine(error);
                throw new InvalidOperationException(error);
            },
                logger);
            logger?.WriteLine("Wait for connection completion.");

            if (_waitForConnection != null)
            {
                // Add a timeout for waiting for connection - 20 seconds
                Task  waitOrTimeout = Task.WhenAny(_waitForConnection, Task.Delay(20000));
                await waitOrTimeout;
                if (waitOrTimeout.Status != TaskStatus.RanToCompletion)
                {
                    string errorMessage = String.Format(CultureInfo.CurrentCulture, MICoreResources.Error_DebuggerInitializeFailed_NoStdErr, "WindowsDebugLauncher.exe");
                    transportCallback.OnStdErrorLine(errorMessage);
                    transportCallback.OnDebuggerProcessExit(null);
                    return;
                }
            }

            base.Init(transportCallback, options, logger, waitLoop);
        }