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); }
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()); }
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); } }
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; }
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; }
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; }
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(); }
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; }
public void Init(ITransport transport, LaunchOptions options, HostWaitLoop waitLoop = null) { _lastCommandId = 1000; _transport = transport; FlushBreakStateData(); _transport.Init(this, options, Logger, waitLoop); }