public void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null)
        {
            _launchOptions = (UnixShellPortLaunchOptions)options;
            _callback = transportCallback;
            _logger = logger;
            _startRemoteDebuggerCommand = _launchOptions.StartRemoteDebuggerCommand;

            if (_launchOptions.DebuggerMIMode == MIMode.Clrdbg)
            {
                if (!UnixShellPortLaunchOptions.HasSuccessfulPreviousLaunch(_launchOptions))
                {
                    waitLoop?.SetText(MICoreResources.Info_InstallingDebuggerOnRemote);
                    try
                    {
                        Task.Run(() => DownloadAndCopyFileToRemote(_launchOptions.DebuggerInstallationDirectory, _launchOptions.GetClrDbgUrl)).Wait();
                    }
                    catch (Exception e)
                    {
                        // Even if downloading & copying to remote fails, we will still try to invoke the script as it might already exist.
                        string message = String.Format(CultureInfo.CurrentUICulture, MICoreResources.Warning_DownloadingClrDbgToRemote, e.Message);
                        _callback.AppendToInitializationLog(message);
                    }
                }
            }

            _callback.AppendToInitializationLog(string.Format(CultureInfo.CurrentUICulture, MICoreResources.Info_StartingUnixCommand, _startRemoteDebuggerCommand));
            _launchOptions.UnixPort.BeginExecuteAsyncCommand(_startRemoteDebuggerCommand, this, out _asyncCommand);
        }
Example #2
0
 public virtual void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null)
 {
     Logger = logger;
     _callback = transportCallback;
     InitStreams(options, out _reader, out _writer);
     StartThread(GetThreadName());
 }
Example #3
0
 public void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null)
 {
     _bQuit = false;
     _callback = transportCallback;
     _commandEvent = new AutoResetEvent(false);
     _reader = new StreamReader(File.OpenRead(_filename));
     _thread = new Thread(TransportLoop);
     _nextCommand = null;
     _thread.Start();
 }
 public void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null)
 {
     _launchTimeout = ((LocalLaunchOptions)options).ServerLaunchTimeout;
     _serverTransport.Init(transportCallback, options, logger, waitLoop);
     WaitForStart();
     if (!_clientTransport.IsClosed)
     {
         _clientTransport.Init(transportCallback, options, logger, waitLoop);
     }
 }
Example #5
0
        private bool TrySetOperationInternalWithProgress(AsyncProgressOperation op, string text, CancellationTokenSource canTokenSource)
        {
            var waitLoop = new HostWaitLoop(text);

            lock (_eventLock)
            {
                if (_isClosed)
                    throw new ObjectDisposedException("WorkerThread");

                if (_runningOp == null)
                {
                    _runningOpCompleteEvent.Reset();

                    OperationDescriptor runningOp = new OperationDescriptor(new AsyncOperation(() => { return op(waitLoop); }));
                    _runningOp = runningOp;

                    _opSet.Set();

                    waitLoop.Wait(_runningOpCompleteEvent, canTokenSource);

                    Debug.Assert(runningOp.IsComplete, "Why isn't the running op complete?");

                    if (runningOp.ExceptionDispatchInfo != null)
                    {
                        runningOp.ExceptionDispatchInfo.Throw();
                    }

                    return true;
                }
            }

            return false;
        }
Example #6
0
        void IPlatformAppLauncher.SetupForDebugging(out LaunchOptions result)
        {
            if (_launchOptions == null)
            {
                Debug.Fail("Why is SetupForDebugging being called before ParseLaunchOptions?");
                throw new InvalidOperationException();
            }

            ManualResetEvent doneEvent = new ManualResetEvent(false);
            var cancellationTokenSource = new CancellationTokenSource();
            ExceptionDispatchInfo exceptionDispatchInfo = null;
            LaunchOptions localLaunchOptions = null;

            _waitLoop = new HostWaitLoop(LauncherResources.WaitDialogText);

            // Do the work on a worker thread to avoid blocking the UI. Use ThreadPool.QueueUserWorkItem instead
            // of Task.Run to avoid needing to unwrap the AggregateException.
            ThreadPool.QueueUserWorkItem((object o) =>
                {
                    string launchErrorTelemetryResult = null;

                    try
                    {
                        localLaunchOptions = SetupForDebuggingWorker(cancellationTokenSource.Token);
                        launchErrorTelemetryResult = "None";
                    }
                    catch (Exception e)
                    {
                        exceptionDispatchInfo = ExceptionDispatchInfo.Capture(e);
                        if (!(e is OperationCanceledException))
                        {
                            launchErrorTelemetryResult = Telemetry.GetLaunchErrorResultValue(e);
                        }
                    }

                    doneEvent.Set();

                    if (launchErrorTelemetryResult != null)
                    {
                        Telemetry.SendLaunchError(launchErrorTelemetryResult, _targetEngine.ToString());
                    }
                }
            );

            _waitLoop.Wait(doneEvent, cancellationTokenSource);

            if (exceptionDispatchInfo != null)
            {
                exceptionDispatchInfo.Throw();
            }
            if (localLaunchOptions == null)
            {
                Debug.Fail("No result provided? Should be impossible.");
                throw new InvalidOperationException();
            }

            result = localLaunchOptions;
        }
Example #7
0
        public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngineCallback callback, WorkerThread worker, BreakpointManager bpman, AD7Engine engine, HostConfigurationStore configStore, HostWaitLoop waitLoop = null) : base(launchOptions, engine.Logger)
        {
            uint processExitCode = 0;
            _pendingMessages = new StringBuilder(400);
            _worker = worker;
            _breakpointManager = bpman;
            Engine = engine;
            _libraryLoaded = new List<string>();
            _loadOrder = 0;
            MICommandFactory = MICommandFactory.GetInstance(launchOptions.DebuggerMIMode, this);
            _waitDialog = (MICommandFactory.SupportsStopOnDynamicLibLoad() && launchOptions.WaitDynamicLibLoad) ? new HostWaitDialog(ResourceStrings.LoadingSymbolMessage, ResourceStrings.LoadingSymbolCaption) : null;
            Natvis = new Natvis.Natvis(this, launchOptions.ShowDisplayString);

            // we do NOT have real Win32 process IDs, so we use a guid
            AD_PROCESS_ID pid = new AD_PROCESS_ID();
            pid.ProcessIdType = (int)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID;
            pid.guidProcessId = Guid.NewGuid();
            this.Id = pid;

            SourceLineCache = new SourceLineCache(this);

            _callback = callback;
            _moduleList = new List<DebuggedModule>();
            ThreadCache = new ThreadCache(callback, this);
            Disassembly = new Disassembly(this);
            ExceptionManager = new ExceptionManager(MICommandFactory, _worker, _callback, configStore);

            VariablesToDelete = new List<string>();
            this.ActiveVariables = new List<IVariableInformation>();
            _fileTimestampWarnings = new HashSet<Tuple<string, string>>();

            OutputStringEvent += delegate (object o, string message)
            {
                // We can get messages before we have started the process
                // but we can't send them on until it is
                if (_connected)
                {
                    _callback.OnOutputString(message);
                }
                else
                {
                    _pendingMessages.Append(message);
                }
            };

            LibraryLoadEvent += delegate (object o, EventArgs args)
            {
                ResultEventArgs results = args as MICore.Debugger.ResultEventArgs;
                string file = results.Results.TryFindString("host-name");
                if (!string.IsNullOrEmpty(file) && MICommandFactory.SupportsStopOnDynamicLibLoad())
                {
                    _libraryLoaded.Add(file);
                    if (_waitDialog != null)
                    {
                        _waitDialog.ShowWaitDialog(file);
                    }
                }
                else if (this.MICommandFactory.Mode == MIMode.Clrdbg)
                {
                    string id = results.Results.FindString("id");
                    ulong baseAddr = results.Results.FindAddr("base-address");
                    uint size = results.Results.FindUint("size");
                    bool symbolsLoaded = results.Results.FindInt("symbols-loaded") != 0;
                    var module = new DebuggedModule(id, file, baseAddr, size, symbolsLoaded, string.Empty, _loadOrder++);
                    lock (_moduleList)
                    {
                        _moduleList.Add(module);
                    }
                    _callback.OnModuleLoad(module);
                }
                else if (!string.IsNullOrEmpty(file))
                {
                    string addr = results.Results.TryFindString("loaded_addr");
                    if (string.IsNullOrEmpty(addr) || addr == "-")
                    {
                        return; // identifies the exe, not a real load
                    }
                    // generate module 
                    string id = results.Results.TryFindString("name");
                    bool symsLoaded = true;
                    string symPath = null;
                    if (results.Results.Contains("symbols-path"))
                    {
                        symPath = results.Results.FindString("symbols-path");
                        if (string.IsNullOrEmpty(symPath))
                        {
                            symsLoaded = false;
                        }
                    }
                    else
                    {
                        symPath = file;
                    }
                    ulong loadAddr = results.Results.FindAddr("loaded_addr");

                    uint size = results.Results.FindUint("size");
                    if (String.IsNullOrEmpty(id))
                    {
                        id = file;
                    }
                    var module = FindModule(id);
                    if (module == null)
                    {
                        module = new DebuggedModule(id, file, loadAddr, size, symsLoaded, symPath, _loadOrder++);
                        lock (_moduleList)
                        {
                            _moduleList.Add(module);
                        }
                        _callback.OnModuleLoad(module);
                    }
                }
            };

            if (_launchOptions is LocalLaunchOptions)
            {
                LocalLaunchOptions localLaunchOptions = (LocalLaunchOptions)_launchOptions;

                if (!localLaunchOptions.IsValidMiDebuggerPath())
                {
                    throw new Exception(MICoreResources.Error_InvalidMiDebuggerPath);
                }

                if (PlatformUtilities.IsOSX() &&
                    localLaunchOptions.DebuggerMIMode != MIMode.Clrdbg &&
                    localLaunchOptions.DebuggerMIMode != MIMode.Lldb &&
                    !UnixUtilities.IsBinarySigned(localLaunchOptions.MIDebuggerPath))
                {
                    string message = String.Format(CultureInfo.CurrentCulture, ResourceStrings.Warning_DarwinDebuggerUnsigned, localLaunchOptions.MIDebuggerPath);
                    _callback.OnOutputMessage(new OutputMessage(
                        message + Environment.NewLine,
                        enum_MESSAGETYPE.MT_MESSAGEBOX,
                        OutputMessage.Severity.Warning));
                }

                ITransport localTransport = null;
                // For local Linux and OS X launch, use the local Unix transport which creates a new terminal and
                // uses fifos for debugger (e.g., gdb) communication.
                if (this.MICommandFactory.UseExternalConsoleForLocalLaunch(localLaunchOptions) &&
                    (PlatformUtilities.IsLinux() || (PlatformUtilities.IsOSX() && localLaunchOptions.DebuggerMIMode != MIMode.Lldb)))
                {
                    localTransport = new LocalUnixTerminalTransport();

                    // Only need to clear terminal for Linux and OS X local launch
                    _needTerminalReset = (localLaunchOptions.ProcessId == 0 && _launchOptions.DebuggerMIMode == MIMode.Gdb);
                }
                else
                {
                    localTransport = new LocalTransport();
                }

                if (localLaunchOptions.ShouldStartServer())
                {
                    this.Init(
                        new MICore.ClientServerTransport(
                            localTransport,
                            new ServerTransport(killOnClose: true, filterStdout: localLaunchOptions.FilterStdout, filterStderr: localLaunchOptions.FilterStderr)
                        ),
                        _launchOptions);
                }
                else
                {
                    this.Init(localTransport, _launchOptions);
                }

                // Only need to know the debugger pid on Linux and OS X local launch to detect whether
                // the debugger is closed. If the debugger is not running anymore, the response (^exit)
                // to the -gdb-exit command is faked to allow MIEngine to shut down.
                SetDebuggerPid(localTransport.DebuggerPid);
            }
            else if (_launchOptions is PipeLaunchOptions)
            {
                this.Init(new MICore.PipeTransport(), _launchOptions);
            }
            else if (_launchOptions is TcpLaunchOptions)
            {
                this.Init(new MICore.TcpTransport(), _launchOptions);
            }
            else if (_launchOptions is UnixShellPortLaunchOptions)
            {
                this.Init(new MICore.UnixShellPortTransport(), _launchOptions, waitLoop);
            }
            else
            {
                throw new ArgumentOutOfRangeException("LaunchInfo.options");
            }

            MIDebugCommandDispatcher.AddProcess(this);

            // When the debuggee exits, we need to exit the debugger
            ProcessExitEvent += delegate (object o, EventArgs args)
            {
                // NOTE: Exceptions leaked from this method may cause VS to crash, be careful

                ResultEventArgs results = args as MICore.Debugger.ResultEventArgs;

                if (results.Results.Contains("exit-code"))
                {
                    // GDB sometimes returns exit codes, which don't fit into uint, like "030000000472".
                    // And we can't throw from here, because it crashes VS.
                    // Full exit code will still usually be reported in the Output window,
                    // but here let's return "uint.MaxValue" just to indicate that something went wrong.
                    if (!uint.TryParse(results.Results.FindString("exit-code"), out processExitCode))
                    {
                        processExitCode = uint.MaxValue;
                    }
                }

                // quit MI Debugger
                if (!this.IsClosed)
                {
                    _worker.PostOperation(CmdExitAsync);
                }
                else
                {
                    // If we are already closed, make sure that something sends program destroy
                    _callback.OnProcessExit(processExitCode);
                }

                if (_waitDialog != null)
                {
                    _waitDialog.EndWaitDialog();
                }
            };

            // When the debugger exits, we tell AD7 we are done
            DebuggerExitEvent += delegate (object o, EventArgs args)
            {
                // NOTE: Exceptions leaked from this method may cause VS to crash, be careful

                // this is the last AD7 Event we can ever send
                // Also the transport is closed when this returns
                _callback.OnProcessExit(processExitCode);

                Dispose();
            };

            DebuggerAbortedEvent += delegate (object o, DebuggerAbortedEventArgs eventArgs)
            {
                // NOTE: Exceptions leaked from this method may cause VS to crash, be careful

                // The MI debugger process unexpectedly exited.
                _worker.PostOperation(() =>
                    {
                        _engineTelemetry.SendDebuggerAborted(MICommandFactory, GetLastSentCommandName(), eventArgs.ExitCode);

                        // If the MI Debugger exits before we get a resume call, we have no way of sending program destroy. So just let start debugging fail.
                        if (!_connected)
                        {
                            return;
                        }

                        _callback.OnError(string.Concat(eventArgs.Message, " ", ResourceStrings.DebuggingWillAbort));
                        _callback.OnProcessExit(uint.MaxValue);

                        Dispose();
                    });
            };

            ModuleLoadEvent += async delegate (object o, EventArgs args)
            {
                // NOTE: This is an async void method, so make sure exceptions are caught and somehow reported

                if (_needTerminalReset)
                {
                    _needTerminalReset = false;

                    // This is to work around a GDB bug of warning "Failed to set controlling terminal: Operation not permitted"
                    // Reset debuggee terminal after the first module load.
                    await ResetConsole();
                }

                if (this.MICommandFactory.SupportsStopOnDynamicLibLoad() && !_launchOptions.WaitDynamicLibLoad)
                {
                    await CmdAsync("-gdb-set stop-on-solib-events 0", ResultClass.None);
                }

                await this.EnsureModulesLoaded();


                if (_waitDialog != null)
                {
                    _waitDialog.EndWaitDialog();
                }
                if (MICommandFactory.SupportsStopOnDynamicLibLoad())
                {
                    // Do not continue if debugging core dump
                    if (!this.IsCoreDump)
                    {
                        CmdContinueAsync();
                    }
                }
            };

            // When we break we need to gather information
            BreakModeEvent += async delegate (object o, EventArgs args)
            {
                // NOTE: This is an async void method, so make sure exceptions are caught and somehow reported

                StoppingEventArgs results = args as MICore.Debugger.StoppingEventArgs;
                if (_waitDialog != null)
                {
                    _waitDialog.EndWaitDialog();
                }

                if (!this._connected)
                {
                    _initialBreakArgs = results;
                    return;
                }

                try
                {
                    await HandleBreakModeEvent(results, results.AsyncRequest);
                }
                catch (Exception e) when (ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true))
                {
                    if (this.IsStopDebuggingInProgress)
                    {
                        return; // ignore exceptions after the process has exited
                    }

                    string exceptionDescription = EngineUtils.GetExceptionDescription(e);
                    string message = string.Format(CultureInfo.CurrentCulture, MICoreResources.Error_FailedToEnterBreakState, exceptionDescription);
                    _callback.OnError(message);

                    Terminate();
                }
            };

            ErrorEvent += delegate (object o, EventArgs args)
            {
                // NOTE: Exceptions leaked from this method may cause VS to crash, be careful

                ResultEventArgs result = (ResultEventArgs)args;
                _callback.OnError(result.Results.FindString("msg"));
            };

            ThreadCreatedEvent += delegate (object o, EventArgs args)
            {
                ResultEventArgs result = (ResultEventArgs)args;
                ThreadCache.ThreadCreatedEvent(result.Results.FindInt("id"), result.Results.TryFindString("group-id"));
                _childProcessHandler?.ThreadCreatedEvent(result.Results);
            };

            ThreadExitedEvent += delegate (object o, EventArgs args)
            {
                ResultEventArgs result = (ResultEventArgs)args;
                ThreadCache.ThreadExitedEvent(result.Results.FindInt("id"));
            };

            ThreadGroupExitedEvent += delegate (object o, EventArgs args)
            {
                ResultEventArgs result = (ResultEventArgs)args;
                ThreadCache.ThreadGroupExitedEvent(result.Results.FindString("id"));
            };

            MessageEvent += (object o, ResultEventArgs args) =>
            {
                OutputMessage outputMessage = DecodeOutputEvent(args.Results);
                if (outputMessage != null)
                {
                    _callback.OnOutputMessage(outputMessage);
                }
            };

            TelemetryEvent += (object o, ResultEventArgs args) =>
            {
                string eventName;
                KeyValuePair<string, object>[] properties;
                if (_engineTelemetry.DecodeTelemetryEvent(args.Results, out eventName, out properties))
                {
                    HostTelemetry.SendEvent(eventName, properties);
                }
            };

            BreakChangeEvent += _breakpointManager.BreakpointModified;
        }
Example #8
0
        public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token)
        {
            bool success = false;
            Natvis.Initialize(_launchOptions.VisualizerFile);
            int total = 1;

            await this.WaitForConsoleDebuggerInitialize(token);

            try
            {
                await this.MICommandFactory.EnableTargetAsyncOption();
                List<LaunchCommand> commands = GetInitializeCommands();
                _childProcessHandler?.Enable();

                total = commands.Count();
                var i = 0;
                foreach (var command in commands)
                {
                    token.ThrowIfCancellationRequested();
                    waitLoop.SetProgress(total, i++, command.Description);
                    if (command.IsMICommand)
                    {
                        Results results = await CmdAsync(command.CommandText, ResultClass.None);
                        if (results.ResultClass == ResultClass.error)
                        {
                            if (command.FailureHandler != null)
                            {
                                command.FailureHandler(results.FindString("msg"));
                            }
                            else if (!command.IgnoreFailures)
                            {
                                string miError = results.FindString("msg");
                                throw new UnexpectedMIResultException(MICommandFactory.Name, command.CommandText, miError);
                            }
                        }
                        else
                        {
                            if (command.SuccessHandler != null)
                            {
                                command.SuccessHandler(results.ToString());
                            }
                        }
                    }
                    else
                    {
                        string resultString = await ConsoleCmdAsync(command.CommandText, command.IgnoreFailures);
                        if (command.SuccessHandler != null)
                        {
                            command.SuccessHandler(resultString);
                        }
                    }
                }

                success = true;
            }
            finally
            {
                if (!success)
                {
                    Terminate();
                }
            }
            waitLoop.SetProgress(total, total, String.Empty);
            token.ThrowIfCancellationRequested();
        }
Example #9
0
        private HttpResponseMessage CallVcRemote(Uri endpoint, string waitLoopMessage, out string responseBody)
        {
            ManualResetEvent doneEvent = new ManualResetEvent(false);
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            var waitLoop = new HostWaitLoop(waitLoopMessage);
            ExceptionDispatchInfo exceptionDispatchInfo = null;

            HttpResponseMessage response = null;
            string content = null;
            ThreadPool.QueueUserWorkItem(async (object o) =>
            {
                string failureCode = Telemetry.VcRemoteFailureCode.VcRemoteSucces.ToString();

                try
                {
                    response = await this.GetAsync(endpoint, cancellationTokenSource.Token);
                    response.EnsureSuccessStatusCode();

                    content = await response.Content.ReadAsStringAsync();
                }
                catch (HttpRequestException)
                {
                    if (response != null)
                    {
                        if (response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            exceptionDispatchInfo = ExceptionDispatchInfo.Capture(new LauncherException(LauncherResources.Error_Unauthorized));
                            failureCode = Telemetry.VcRemoteFailureCode.VcRemoteUnauthorized.ToString();
                        }
                        else
                        {
                            exceptionDispatchInfo = ExceptionDispatchInfo.Capture(new LauncherException(string.Format(LauncherResources.Error_VcRemoteUnknown, response.StatusCode.ToString())));
                            failureCode = Telemetry.VcRemoteFailureCode.VcRemoteUnkown.ToString();
                        }
                    }
                    else
                    {
                        exceptionDispatchInfo = ExceptionDispatchInfo.Capture(new LauncherException(LauncherResources.Error_UnableToReachServer));
                        failureCode = Telemetry.VcRemoteFailureCode.VcRemoteNoConnection.ToString();
                    }
                }
                catch (TaskCanceledException)
                {
                    //timeout 
                    exceptionDispatchInfo = ExceptionDispatchInfo.Capture(new LauncherException(LauncherResources.Error_UnableToReachServer));
                    failureCode = Telemetry.VcRemoteFailureCode.VcRemoteNoConnection.ToString();
                }
                catch (Exception e)
                {
                    exceptionDispatchInfo = ExceptionDispatchInfo.Capture(e);
                    failureCode = e.GetType().FullName;
                }

                doneEvent.Set();

                Telemetry.SendLaunchError(failureCode, _launchOptions.IOSDebugTarget);
            });

            waitLoop.Wait(doneEvent, cancellationTokenSource);

            if (exceptionDispatchInfo != null)
            {
                exceptionDispatchInfo.Throw();
            }

            if (response == null)
            {
                Debug.Fail("Null resposne? Should be impossible.");
                throw new InvalidOperationException();
            }

            responseBody = content;
            return response;
        }
Example #10
0
        public void Init(ITransport transport, LaunchOptions options, HostWaitLoop waitLoop = null)
        {
            _lastCommandId = 1000;
            _transport = transport;
            FlushBreakStateData();

            _transport.Init(this, options, Logger, waitLoop);
        }