Example #1
0
        private int Continue(IDebugThread2 pThread)
        {
            ThrowIfDisposed();

            if (_firstContinue)
            {
                _firstContinue = false;
            }
            else
            {
                // If _sentContinue is true, then this is a dummy Continue issued to notify the
                // debugger that user has explicitly entered something at the Browse prompt, and
                // we don't actually need to issue the command to R debugger.

                Func <CancellationToken, Task> continueMethod = null;
                lock (_browseLock) {
                    if (_sentContinue != true)
                    {
                        _sentContinue  = true;
                        continueMethod = ct => DebugSession.ContinueAsync(ct);
                    }
                }

                if (continueMethod != null)
                {
                    TaskExtensions.RunSynchronouslyOnUIThread(continueMethod);
                }
            }

            return(VSConstants.S_OK);
        }
Example #2
0
        internal DebugStackFrame(DebugSession session, int index, DebugStackFrame callingFrame, JObject jFrame, DebugStackFrame fallbackFrame = null)
        {
            Session      = session;
            Index        = index;
            CallingFrame = callingFrame;

            FileName   = jFrame.Value <string>("filename");
            LineNumber = jFrame.Value <int?>("line_number");
            Call       = jFrame.Value <string>("call");
            IsGlobal   = jFrame.Value <bool?>("is_global") ?? false;

            var match = _doTraceRegex.Match(Call);

            if (match.Success)
            {
                FrameKind = DebugStackFrameKind.DoTrace;
            }

            if (fallbackFrame != null)
            {
                // If we still don't have the filename and line number, use those from the fallback frame.
                // This happens during breakpoint hit processing after the context is unwound from within
                // .doTrace back to the function that called it - because we no longer have .doTrace call,
                // we don't have the file/line information that came from it. But DebugSession will have
                // stashed it away when it had it, and then pass it as a fallback frame if index matches.
                FileName   = FileName ?? fallbackFrame.FileName;
                LineNumber = LineNumber ?? fallbackFrame.LineNumber;
            }
        }
Example #3
0
 int IDebugEngine2.CauseBreak()
 {
     ThrowIfDisposed();
     DebugSession.BreakAsync()
     .SilenceException <MessageTransportException>()
     .DoNotWait();
     return(VSConstants.S_OK);
 }
Example #4
0
        int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 pCallback, enum_ATTACH_REASON dwReason)
        {
            ThrowIfDisposed();

            if (rgpPrograms.Length != 1)
            {
                throw new ArgumentException("Zero or more than one programs", "rgpPrograms");
            }

            _program = rgpPrograms[0] as RDebugPortSupplier.DebugProgram;
            if (_program == null)
            {
                throw new ArgumentException("rgpPrograms[0] must be an " + nameof(RDebugPortSupplier.DebugProgram), "rgpPrograms");
            }

            Marshal.ThrowExceptionForHR(_program.GetProgramId(out _programId));

            _events      = pCallback;
            DebugSession = TaskExtensions.RunSynchronouslyOnUIThread(ct => _program.Session.TraceExecutionAsync(ct));
            MainThread   = new AD7Thread(this);
            IsConnected  = true;

            // Enable breakpoint instrumentation.
            TaskExtensions.RunSynchronouslyOnUIThread(ct => DebugSession.EnableBreakpointsAsync(true, ct));

            // Send notification after acquiring the session - we need it in case there were any breakpoints pending before
            // the attach, in which case we'll immediately get breakpoint creation requests as soon as we send these, and
            // we will need the session to process them.
            AD7EngineCreateEvent.Send(this);
            AD7ProgramCreateEvent.Send(this);
            Send(new AD7LoadCompleteEvent(), AD7LoadCompleteEvent.IID);

            // Register event handlers after notifying VS that debug engine has loaded. This order is important because
            // we may get a Browse event immediately, and we want to raise a breakpoint notification in response to that
            // to pause the debugger - but it will be ignored unless the engine has reported its creation.
            // Also, AfterRequest must be registered before Browse, so that we never get in a situation where we get
            // Browse but not AfterRequest that follows it because of a race between raising and registration.
            DebugSession.Session.AfterRequest += RSession_AfterRequest;
            DebugSession.Session.Disconnected += RSession_Disconnected;

            // If we're already at the Browse prompt, registering the handler will result in its immediate invocation.
            // We want to handle that fully before we process any following AfterRequest event to avoid concurrency issues
            // where we pause and never resume, so hold the lock while adding the handler.
            lock (_browseLock) {
                DebugSession.Browse += Session_Browse;
            }

            return(VSConstants.S_OK);
        }
Example #5
0
        int IDebugProgram2.Step(IDebugThread2 pThread, enum_STEPKIND sk, enum_STEPUNIT Step)
        {
            ThrowIfDisposed();

            Task <bool> step;

            switch (sk)
            {
            case enum_STEPKIND.STEP_OVER:
                step = DebugSession.StepOverAsync();
                break;

            case enum_STEPKIND.STEP_INTO:
                step = DebugSession.StepIntoAsync();
                break;

            case enum_STEPKIND.STEP_OUT:
                goto default;

            //    step = DebugSession.StepOutAsync();
            //    break;
            default:
                return(VSConstants.E_NOTIMPL);
            }

            step.ContinueWith(t => {
                // If step was interrupted midway (e.g. by a breakpoint), we have already reported breakpoint
                // hit event, and so we must not report step complete. Note that interrupting is not the same
                // as canceling, and if step was canceled, we must report step completion.

                bool completed = true;
                try {
                    completed = t.GetAwaiter().GetResult();
                } catch (OperationCanceledException) {
                } catch (MessageTransportException) {
                }

                if (completed)
                {
                    Send(new AD7SteppingCompleteEvent(), AD7SteppingCompleteEvent.IID);
                }
            });

            return(VSConstants.S_OK);
        }
Example #6
0
        int IDebugProgram2.Detach()
        {
            ThrowIfDisposed();

            try {
                // Queue disabling breakpoint instrumentation, but do not wait for it to complete -
                // if there's currently some code running, this may take a while, so just detach and
                // let breakpoints be taken care of later.
                DebugSession.EnableBreakpointsAsync(false)
                .SilenceException <MessageTransportException>()
                .DoNotWait();
            } finally {
                // Detach should never fail, even if something above didn't work.
                DestroyProgram();
            }

            return(VSConstants.S_OK);
        }
Example #7
0
 internal DebugBreakpoint(DebugSession session, DebugBreakpointLocation location)
 {
     Session  = session;
     Location = location;
 }
Example #8
0
 int IDebugProgram3.ExecuteOnThread(IDebugThread2 pThread)
 {
     ThrowIfDisposed();
     DebugSession.CancelStep();
     return(Continue(pThread));
 }