private async Task ProcessBrowsePromptWorker(IRSessionInteraction inter) { var frames = await Session.TracebackAsync(); // If there's .doTrace(rtvs:::breakpoint) anywhere on the stack, we're inside the internal machinery // that triggered Browse> prompt when hitting a breakpoint. We need to step out of it until we're // back at the frame where the breakpoint was actually set, so that those internal frames do not show // on the call stack, and further stepping does not try to step through them. // Since browserSetDebug-based step out is not reliable in the presence of loops, we'll just keep // stepping over with "n" until we're all the way out. Every step will trigger a new prompt, and // we will come back to this method again. var doTraceFrame = frames.FirstOrDefault(frame => IsDoTrace(frame)); if (doTraceFrame != null) { await inter.RespondAsync(Invariant($"n\n")); return; } IReadOnlyCollection <RBreakpoint> breakpointsHit = null; var lastFrame = frames.LastOrDefault(); if (lastFrame != null) { // Report breakpoints first, so that by the time step completion is reported, all actions associated // with breakpoints (e.g. printing messages for tracepoints) have already been completed. if (lastFrame.FileName != null && lastFrame.LineNumber != null) { var location = new RSourceLocation(lastFrame.FileName, lastFrame.LineNumber.Value); RBreakpoint bp; if (_breakpoints.TryGetValue(location, out bp)) { bp.RaiseBreakpointHit(); breakpointsHit = Enumerable.Repeat(bp, bp.UseCount).ToArray(); } } } bool isStepCompleted = false; if (_stepTcs != null) { var stepTcs = _stepTcs; _stepTcs = null; stepTcs.TrySetResult(breakpointsHit == null || breakpointsHit.Count == 0); isStepCompleted = true; } EventHandler <RBrowseEventArgs> browse; lock (_browseLock) { browse = _browse; } var eventArgs = new RBrowseEventArgs(inter, isStepCompleted, breakpointsHit); _currentBrowseEventArgs = eventArgs; browse?.Invoke(this, eventArgs); }
private void RSession_AfterRequest(object sender, RAfterRequestEventArgs e) { _currentBrowseEventArgs = null; }
private async Task ProcessBrowsePromptWorker(IRSessionInteraction inter) { var frames = await Session.TracebackAsync(); // If there's .doTrace(rtvs:::breakpoint) anywhere on the stack, we're inside the internal machinery // that triggered Browse> prompt when hitting a breakpoint. We need to step out of it until we're // back at the frame where the breakpoint was actually set, so that those internal frames do not show // on the call stack, and further stepping does not try to step through them. // Since browserSetDebug-based step out is not reliable in the presence of loops, we'll just keep // stepping over with "n" until we're all the way out. Every step will trigger a new prompt, and // we will come back to this method again. var doTraceFrame = frames.FirstOrDefault(frame => IsDoTrace(frame)); if (doTraceFrame != null) { await inter.RespondAsync(Invariant($"n\n")); return; } IReadOnlyCollection<RBreakpoint> breakpointsHit = null; var lastFrame = frames.LastOrDefault(); if (lastFrame != null) { // Report breakpoints first, so that by the time step completion is reported, all actions associated // with breakpoints (e.g. printing messages for tracepoints) have already been completed. if (lastFrame.FileName != null && lastFrame.LineNumber != null) { var location = new RSourceLocation(lastFrame.FileName, lastFrame.LineNumber.Value); RBreakpoint bp; if (_breakpoints.TryGetValue(location, out bp)) { bp.RaiseBreakpointHit(); breakpointsHit = Enumerable.Repeat(bp, bp.UseCount).ToArray(); } } } bool isStepCompleted = false; if (_stepTcs != null) { var stepTcs = _stepTcs; _stepTcs = null; stepTcs.TrySetResult(breakpointsHit == null || breakpointsHit.Count == 0); isStepCompleted = true; } EventHandler<RBrowseEventArgs> browse; lock (_browseLock) { browse = _browse; } var eventArgs = new RBrowseEventArgs(inter, isStepCompleted, breakpointsHit); _currentBrowseEventArgs = eventArgs; browse?.Invoke(this, eventArgs); }
private void Session_AfterRequest(object sender, RAfterRequestEventArgs e) { bool? sentContinue; lock (_browseLock) { var browseEventArgs = _currentBrowseEventArgs; if (browseEventArgs == null || browseEventArgs.Context.Contexts != e.Contexts) { // This AfterRequest does not correspond to a Browse prompt, or at least not one // that we have seen before (and paused on), so there's nothing to do. return; } _currentBrowseEventArgs = null; sentContinue = _sentContinue; _sentContinue = true; } if (sentContinue == false) { // User has explicitly typed something at the Browse prompt, so tell the debugger that // we're moving on by issuing a dummy Continue request to switch it to the running state. var vsShell = (IVsUIShell)Package.GetGlobalService(typeof(SVsUIShell)); Guid group = VSConstants.GUID_VSStandardCommandSet97; object arg = null; var ex = Marshal.GetExceptionForHR(vsShell.PostExecCommand(ref group, (uint)VSConstants.VSStd97CmdID.Start, 0, ref arg)); Trace.Assert(ex == null); } }
private void Tracer_Browse(object sender, RBrowseEventArgs e) { lock (_browseLock) { _currentBrowseEventArgs = e; _sentContinue = false; } // If we hit a breakpoint or completed a step, we have already reported the stop from the corresponding handlers. // Otherwise, this is just a random Browse prompt, so raise a dummy breakpoint event with no breakpoints to stop. if (e.BreakpointsHit.Count == 0 && !e.HasStepCompleted) { var bps = new AD7BoundBreakpointEnum(new IDebugBoundBreakpoint2[0]); var evt = new AD7BreakpointEvent(bps); Send(evt, AD7BreakpointEvent.IID); } }