Example #1
0
        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);
        }
Example #2
0
 public static void AsyncErrorImpl(EngineCallback engineCallback, IVariableInformation var, IDebugProperty2 error)
 {
     Task.Run(() =>
     {
         engineCallback.OnExpressionEvaluationComplete(var, error);
     });
 }
Example #3
0
        // 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));
            }
        }
Example #4
0
        private void Dispose()
        {
            WorkerThread    pollThread      = _pollThread;
            DebuggedProcess debuggedProcess = _debuggedProcess;

            _engineCallback  = null;
            _debuggedProcess = null;
            _pollThread      = null;
            _ad7ProgramId    = Guid.Empty;

            debuggedProcess?.Close();
            pollThread?.Close();
        }
Example #5
0
        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;
        }
Example #6
0
        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;
            }
        }
Example #7
0
        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;
        }
Example #8
0
        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();
            }
        }
Example #9
0
        // 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);
        }
Example #10
0
        // 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);
        }
Example #11
0
        private void Dispose()
        {
            WorkerThread pollThread = _pollThread;
            DebuggedProcess debuggedProcess = _debuggedProcess;

            _engineCallback = null;
            _debuggedProcess = null;
            _pollThread = null;
            _ad7ProgramId = Guid.Empty;

            debuggedProcess?.Close();
            pollThread?.Close();
        }
Example #12
0
        // 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;
        }
Example #13
0
        // 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);
            }
        }
Example #14
0
        // 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);
        }
Example #15
0
        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();
        }