protected void ProcessRecord(bool callWaitForEventDespiteCurrentStatus) { base.ProcessRecord(); DEBUG_STATUS currentStatus = Debugger.GetExecutionStatus(); LogManager.Trace("ExecutionBaseCommand.ProcessRecord: Current status is {0}.", currentStatus); if (!callWaitForEventDespiteCurrentStatus && (DEBUG_STATUS.BREAK == currentStatus)) { // TODO: This is for attaching to a debugging server. Need to test it. Other cases? // Perhaps this logic should be changed to be more clear? LogManager.Trace("ExecutionBaseCommand: current status is already BREAK; will not call WaitForEvent."); return; // Don't need to call WaitForEvent. } using (InterceptCtrlC()) { // We need to perform the wait on another thread, because we need to "pump" // on this thread, so that debug event callbacks can queue WriteObject calls // to this thread. LogManager.Trace("ExecutionBaseCommand: calling WaitForEvent (on dbgeng thread)."); MsgLoop.Prepare(); Task waitTask = Debugger.WaitForEventAsync(); waitTask.ContinueWith((x) => { MsgLoop.SignalDone(); }); MsgLoop.Run(); Util.Await(waitTask); // in case it threw } // end using( InterceptCtrlC ) } // end ProcessRecord()
private void SetDebugStatus(DEBUG_STATUS status) { int hr = _control.SetExecutionStatus(status); if (hr < 0) { throw new Exception(GetExceptionString("IDebugControl::SetExecutionStatus", hr)); } }
private SimpleEventHandler(DebugUtilities debugUtilities) { _installed = false; _utilities = debugUtilities; SessionIsActive = false; ExecutionStatus = 0; _previousCallbacks = IntPtr.Zero; _breakpointHandler = null; }
} // end BeginProcessing() private async Task _WaitIfNeededAsync() { DEBUG_STATUS execStatus = Debugger.GetExecutionStatus(); if (_StatusRequiresWait(execStatus)) { LogManager.Trace("InvokeDbgExtensionCommand: Current execution status ({0}) indicates that we should enter a wait.", execStatus); await WaitForBreakAsync(); } } // end _WaitIfNeededAsync()
public override int ChangeEngineState(DEBUG_CES flags, UInt64 argument) { if ((flags & DEBUG_CES.EXECUTION_STATUS) != 0) { ExecutionStatus = (((DEBUG_STATUS)argument) & DEBUG_STATUS.MASK); if ((((DEBUG_CES_EXECUTION_STATUS)argument) & DEBUG_CES_EXECUTION_STATUS.INSIDE_WAIT) == 0) { _utilities.DebugClient.ExitDispatch(_utilities.DebugClient); } } return(S_OK); }
private DEBUG_STATUS UpdateStatus(bool force = false) { DEBUG_STATUS status; Control.GetExecutionStatus(out status); if (Status != status) { var args = new StatusChangedEventArgs(Status, status); Status = status; OnStatusChanged(args); } return(Status); }
private void Debugger_StatusChanged(object sender, StatusChangedEventArgs e) { InvokeAsync(() => { if (e.NewStatus == _status) { return; } _status = e.NewStatus; UpdateCommands(); RunRecentExecutableCommand.RaiseCanExecuteChanged(); }); }
} // end BeginProcessing() protected override void ProcessRecord() { var inputCallbacks = Debugger.GetInputCallbacks() as DebugInputCallbacks; if (null != inputCallbacks) { inputCallbacks.UpdateCmdlet(this); } //var outputCallbacks = Debugger.GetOutputCallbacks() as DebugOutputCallbacks; //if( null != outputCallbacks ) // outputCallbacks.UpdateCmdlet( this ); using (var disposer = new ExceptionGuard()) { disposer.Protect(Debugger.SetCurrentCmdlet(this)); disposer.Protect(InterceptCtrlC()); MsgLoop.Prepare(); string actualCommand = string.Join(" ", Command); Task t = Debugger.InvokeDbgEngCommandAsync(actualCommand, OutputPrefix, _ConsumeLine); Task t2 = t.ContinueWith(async(x) => { DEBUG_STATUS execStatus = Debugger.GetExecutionStatus(); if (_StatusRequiresWait(execStatus)) { LogManager.Trace("InvokeDbgExtensionCommand: Current execution status ({0}) indicates that we should enter a wait.", execStatus); await WaitForBreakAsync(); } disposer.Dispose(); SignalDone(); }).Unwrap(); MsgLoop.Run(); Host.UI.WriteLine(); Util.Await(t); // in case it threw Util.Await(t2); // in case it threw } // end using( disposer ) } // end ProcessRecord()
} // end _StatusRequiresWait protected async Task WaitForBreakAsync() { // The actual wait is performed on the dbgeng thread, allowing us to "pump" // "messages" on this thread (so that debug event callbacks can queue // WriteObject calls to this thread). LogManager.Trace("ExecutionBaseCommand.WaitForBreakAsync()"); bool execStatusRequiresWait = true; while (execStatusRequiresWait) { await Debugger.WaitForEventAsync(); DEBUG_STATUS execStatus = Debugger.GetExecutionStatus(); execStatusRequiresWait = _StatusRequiresWait(execStatus); if (execStatusRequiresWait) { LogManager.Trace("Execution status requires an additional wait: {0}", execStatus); } } } // end WaitForBreakNoLoop()
public void Be_Able_To_Continue_Execution_Until_A_Break_Occurs() { var controlMock = new Mock <IDebugControl6>(); var clientMock = new Mock <IDebugClient5>(); var registersMock = new Mock <IDebugRegisters2>(); var systemObjectsMock = new Mock <IDebugSystemObjects>(); var dataSpacesMock = new Mock <IDebugDataSpaces>(); var executeWrapperMock = new Mock <IExecuteWrapper>(); DEBUG_STATUS status = DEBUG_STATUS.GO; int i = 0; controlMock.Setup(control => control.GetExecutionStatus(out status)).Callback(() => { DEBUG_STATUS status2 = DEBUG_STATUS.BREAK; if (i > 0) { controlMock.Setup(control => control.GetExecutionStatus(out status2)); } i++; }); const string Value = @"PEB at 00000041e9154000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No"; executeWrapperMock.Setup(wrapper => wrapper.Execute(It.IsAny <string>())).Returns(Value); var eng = new DebugEngineProxy(controlMock.Object, clientMock.Object, registersMock.Object, systemObjectsMock.Object, dataSpacesMock.Object, executeWrapperMock.Object); eng.RunUntilBreak(); controlMock.Verify(control => control.GetExecutionStatus(out status), Times.Exactly(3)); }
} // end InterceptCtrlC() protected static bool _StatusRequiresWait(DEBUG_STATUS execStatus) { switch (execStatus) { case DEBUG_STATUS.BREAK: case DEBUG_STATUS.NO_DEBUGGEE: case DEBUG_STATUS.RESTART_REQUESTED: return(false); case DEBUG_STATUS.GO: case DEBUG_STATUS.STEP_OVER: case DEBUG_STATUS.STEP_INTO: case DEBUG_STATUS.STEP_BRANCH: case DEBUG_STATUS.REVERSE_GO: case DEBUG_STATUS.REVERSE_STEP_BRANCH: case DEBUG_STATUS.REVERSE_STEP_OVER: case DEBUG_STATUS.REVERSE_STEP_INTO: return(true); case DEBUG_STATUS.OUT_OF_SYNC: case DEBUG_STATUS.TIMEOUT: case DEBUG_STATUS.WAIT_INPUT: Util.Fail(Util.Sprintf("I wonder if I should handle this status here: {0}", execStatus)); return(false); case DEBUG_STATUS.GO_HANDLED: case DEBUG_STATUS.GO_NOT_HANDLED: case DEBUG_STATUS.IGNORE_EVENT: case DEBUG_STATUS.NO_CHANGE: Util.Fail(Util.Sprintf("I don't think I should ever receive this status: {0}", execStatus)); return(false); default: string msg = Util.Sprintf("Unexpected DEBUG_STATUS: {0} ({1}).", execStatus, (int)execStatus); Util.Fail(msg); throw new Exception(msg); } // end switch( execStatus ) } // end _StatusRequiresWait
public void AttachAndExecute() { // Explicitly load app-local dependencies. LoadNative("dbghelp.dll"); LoadNative("symsrv.dll"); LoadNative("dbgeng.dll"); // Attach to the process. using (DataTarget targetProcess = DataTarget.AttachToProcess(_PID, AttachTimeoutInMsec)) { // Create a new debugger wrapper object. Debugger debugger = new Debugger(targetProcess, _Log); // Subscribe to exception handling. debugger.Callbacks.HandleExceptionEvent += HandleException; // Dump symbol information and set high verbosity on symbol output. debugger.Execute(".sympath"); debugger.Execute("!sym noisy"); // Force load the PDB for clr.dll debugger.Execute(".reload /f clr.dll"); // Ensure that the PDB for clr.dll was successfully loaded. We do this by attempting to load one of the required symbols. ulong baseAddress; if (debugger.DebugSymbols.GetSymbolModule("clr!SVR::gc_heap::n_heaps", out baseAddress) != 0) { throw new Exception("CLR symbols are not properly loaded. Please set the symbol path and try again."); } // Load SOS. debugger.Execute(".loadby sos clr"); // Execute find roots, which will throw an exception when we complete the mark phase. debugger.Execute("!FindRoots -gen " + _GenerationToTrigger); // GO! debugger.DebugControl.SetExecutionStatus(DEBUG_STATUS.GO); // Loop until we have captured the right number of dumps, or we are no longer attached // to the debuggee. DEBUG_STATUS debuggerStatus = DEBUG_STATUS.NO_CHANGE; int hr; do { hr = debugger.DebugControl.WaitForEvent(0, WaitForEventTimeoutInMsec); if (hr < 0) { _Log.WriteLine("Failure encountered in WaitForEvent. HR: {0:x}", hr); _EncounteredException = new Exception("Failure encountered in WaitForEvent."); break; } hr = debugger.DebugControl.GetExecutionStatus(out debuggerStatus); if (hr < 0) { _Log.WriteLine("Failure encountered in GetExecutionStatus. HR: {0:x}", hr); _EncounteredException = new Exception("Failure encountered in GetExecutionStatus."); break; } }while ((debuggerStatus != DEBUG_STATUS.NO_DEBUGGEE) && (_EncounteredException == null) && (!_CapturedDump)); // Once we're done, detach the debuggee so that it doesn't get killed. if (debuggerStatus != DEBUG_STATUS.NO_CHANGE) { debugger.DebugClient.DetachProcesses(); } // If we encountered an exception, throw it here. if (_EncounteredException != null) { throw _EncounteredException; } } }
private void SetDebugStatus(DEBUG_STATUS status) { int hr = _control.SetExecutionStatus(status); if (hr < 0) throw new Exception(GetExceptionString("IDebugControl::SetExecutionStatus", hr)); }
public int GetExecutionStatus(out DEBUG_STATUS status) { return(_control.GetExecutionStatus(out status)); }
internal StatusChangedEventArgs(DEBUG_STATUS oldStatus, DEBUG_STATUS newStatus) { OldStatus = oldStatus; NewStatus = newStatus; }