public void AsyncEval(IDebugEventCallback2 pExprCallback) { EngineCallback engineCallback; if (pExprCallback != null) { engineCallback = new EngineCallback(_engine, pExprCallback); } else { engineCallback = _engine.Callback; } Task evalTask = Task.Run(async() => { await Eval(); }); Action <Task> onComplete = (Task t) => { engineCallback.OnExpressionEvaluationComplete(this); }; evalTask.ContinueWith(onComplete, TaskContinuationOptions.ExecuteSynchronously); }
public static void AsyncErrorImpl(EngineCallback engineCallback, IVariableInformation var, IDebugProperty2 error) { Task.Run(() => { engineCallback.OnExpressionEvaluationComplete(var, error); }); }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { AD_PROCESS_ID processId = EngineUtils.GetProcessId(rgpPrograms[0]); EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(); _engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread _pollThread.RunOperation(new Operation(delegate { throw new NotImplementedException(); })); _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; } else { if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { Debug.Fail("Asked to attach to a process while we are debugging"); return(Constants.E_FAIL); } } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); this.ProgramCreateEventSent = true; return(Constants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
private void Dispose() { WorkerThread pollThread = _pollThread; DebuggedProcess debuggedProcess = _debuggedProcess; _engineCallback = null; _debuggedProcess = null; _pollThread = null; _ad7ProgramId = Guid.Empty; debuggedProcess?.Close(); pollThread?.Close(); }
public DebuggedProcess(AD7Engine engine, IPAddress ipAddress, EngineCallback callback) { _engine = engine; _ipAddress = ipAddress; Instance = this; // 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; _callback = callback; }
private void Dispose(bool isDisposing) { _debuggedProcess?.Close(); _pollThread?.Close(); (_unixPort as IDebugPortCleanup)?.Clean(); if (isDisposing) { _engineCallback = null; _debuggedProcess = null; _pollThread = null; _ad7ProgramId = Guid.Empty; _unixPort = null; } }
public DebuggedProcess(AD7Engine engine, DebugOptions debugOptions, EngineCallback callback) { _engine = engine; _debugOptions = debugOptions; _ipAddress = debugOptions.GetHostIP(); _debugPort = debugOptions.GetMonoDebugPort(); Instance = this; // 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; _callback = callback; }
private void Dispose() { WorkerThread pollThread = _pollThread; DebuggedProcess debuggedProcess = _debuggedProcess; _engineCallback = null; _debuggedProcess = null; _pollThread = null; _ad7ProgramId = Guid.Empty; if (debuggedProcess != null) { debuggedProcess.Close(); } if (pollThread != null) { pollThread.Close(); } }
// 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 { bool noDebug = launchFlags.HasFlag(enum_LAUNCH_FLAGS.LAUNCH_NODEBUG); // Note: LaunchOptions.GetInstance can be an expensive operation and may push a wait message loop LaunchOptions launchOptions = LaunchOptions.GetInstance(_configStore, exe, args, dir, options, noDebug, _engineCallback, TargetEngine.Native, Logger); StartDebugging(launchOptions); 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 lose our message, so we instead send up an error event, and then // return E_ABORT. OnStartDebuggingFailed(exception); return(Constants.E_ABORT); }
// Attach the debug engine to a program. public int Attach(IDebugProgram2[] portProgramArray, IDebugProgramNode2[] programNodeArray, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } IDebugProgram2 portProgram = portProgramArray[0]; Exception exception = null; try { IDebugProcess2 process; EngineUtils.RequireOk(portProgram.GetProcess(out process)); AD_PROCESS_ID processId = EngineUtils.GetProcessId(process); EngineUtils.RequireOk(portProgram.GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_pollThread == null) { if (processId.ProcessIdType != (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM) { Debug.Fail("Invalid process to attach to"); throw new ArgumentException(); } IDebugPort2 port; EngineUtils.RequireOk(process.GetPort(out port)); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); _engineCallback = new EngineCallback(this, ad7Callback); LaunchOptions launchOptions = CreateAttachLaunchOptions(processId.dwProcessId, port); StartDebugging(launchOptions); } else { if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { Debug.Fail("Asked to attach to a process while we are debugging"); return(Constants.E_FAIL); } } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); this.ProgramCreateEventSent = true; return(Constants.S_OK); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { exception = e; } // If we just return the exception as an HRESULT, we will lose our message, so we instead send up an error event, and // return that the attach was canceled OnStartDebuggingFailed(exception); return(AD7_HRESULT.E_ATTACH_USER_CANCELED); }
// 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; }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { AD_PROCESS_ID processId = EngineUtils.GetProcessId(rgpPrograms[0]); EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(Logger); _engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread _pollThread.RunOperation(new Operation(delegate { throw new NotImplementedException(); })); _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; } else { if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { Debug.Fail("Asked to attach to a process while we are debugging"); return Constants.E_FAIL; } } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); this.ProgramCreateEventSent = true; return Constants.S_OK; } catch (MIException e) { return e.HResult; } catch (Exception e) when (ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { return EngineUtils.UnexpectedException(e); } }
// 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); 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(_registryRoot, exe, args, dir, options, _engineCallback); // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(); var cancellationTokenSource = new CancellationTokenSource(); using (cancellationTokenSource) { _pollThread.RunOperation(ResourceStrings.InitializingDebugger, cancellationTokenSource, (MICore.WaitLoop waitLoop) => { try { _debuggedProcess = new DebuggedProcess(true, launchOptions, _engineCallback, _pollThread, _breakpointManager, this); } 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) { 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); }
private void Dispose() { WorkerThread pollThread = _pollThread; DebuggedProcess debuggedProcess = _debuggedProcess; _engineCallback = null; _debuggedProcess = null; _pollThread = null; _ad7ProgramId = Guid.Empty; if(debuggedProcess != null) debuggedProcess.Close(); if(pollThread != null) pollThread.Close(); }