private void OnStartDebuggingFailed(Exception exception) { Logger.Flush(); SendStartDebuggingError(exception); Dispose(); }
public void Send(string cmd) { _logger?.WriteLine("<-" + cmd); _logger?.Flush(); _asyncCommand.WriteLine(cmd); }
private void TransportLoop() { try { while (!_bQuit) { string line = GetLine(); if (line == null) { break; } line = line.TrimEnd(); Logger?.WriteLine("->" + line); Logger?.Flush(); try { if (_filterStdout) { line = FilterLine(line); } if (!String.IsNullOrWhiteSpace(line) && !line.StartsWith("-", StringComparison.Ordinal)) { _callback.OnStdOutLine(line); } } catch (ObjectDisposedException) { Debug.Assert(_bQuit); break; } } if (!_bQuit) { OnReadStreamAborted(); } } finally { lock (_locker) { _bQuit = true; _streamReadCancellationTokenSource.Dispose(); // If we are shutting down without notice from the debugger (e.g., the terminal // where the debugger was hosted was closed), at this point it's possible that // there is a thread blocked doing a read() syscall. ForceDisposeStreamReader(_reader); try { _writer.Dispose(); } catch { // This can fail flush side effects if the debugger goes down. When this happens we don't want // to crash OpenDebugAD7/VS. Stack: // System.IO.UnixFileStream.WriteNative(Byte[] array, Int32 offset, Int32 count) // System.IO.UnixFileStream.FlushWriteBuffer() // System.IO.UnixFileStream.Dispose(Boolean disposing) // System.IO.FileStream.Dispose(Boolean disposing) // System.IO.Stream.Close() // System.IO.StreamWriter.Dispose(Boolean disposing) // System.IO.TextWriter.Dispose() } } } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_pollThread == null); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); Debug.Assert(_ad7ProgramId == Guid.Empty); // Check if the logger was enabled late. Logger.LoadMIDebugLogger(_configStore); process = null; _engineCallback = new EngineCallback(this, ad7Callback); Exception exception; try { // Note: LaunchOptions.GetInstance can be an expensive operation and may push a wait message loop LaunchOptions launchOptions = LaunchOptions.GetInstance(_configStore, exe, args, dir, options, _engineCallback, TargetEngine.Native, Logger); // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(Logger); var cancellationTokenSource = new CancellationTokenSource(); using (cancellationTokenSource) { _pollThread.RunOperation(ResourceStrings.InitializingDebugger, cancellationTokenSource, (HostWaitLoop waitLoop) => { try { _debuggedProcess = new DebuggedProcess(true, launchOptions, _engineCallback, _pollThread, _breakpointManager, this, _configStore); } finally { // If there is an exception from the DebuggeedProcess constructor, it is our responsibility to dispose the DeviceAppLauncher, // otherwise the DebuggedProcess object takes ownership. if (_debuggedProcess == null && launchOptions.DeviceAppLauncher != null) { launchOptions.DeviceAppLauncher.Dispose(); } } _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; return(_debuggedProcess.Initialize(waitLoop, cancellationTokenSource.Token)); }); } EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process)); return(Constants.S_OK); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { exception = e; // Return from the catch block so that we can let the exception unwind - the stack can get kind of big } // If we just return the exception as an HRESULT, we will loose our message, so we instead send up an error event, and then // return E_ABORT. Logger.Flush(); SendStartDebuggingError(exception); Dispose(); return(Constants.E_ABORT); }