/// <summary> /// Waits for a debug event from any of the processes in the wait set. /// </summary> /// <param name="timeout">timeout in milliseconds to wait. If 0, checks for a debug event and returns immediately</param> /// <returns>Null if no event is available</returns> /// <remarks>Debug events should be continued by calling ContinueEvent. The debuggee is completely stopped when a /// debug event is dispatched and until it is continued.</remarks> public NativeEvent WaitForDebugEvent(int timeout) { EnsureIsOnWin32EventThread(); bool fHasEvent; if (IntPtr.Size == sizeof(Int32)) { DebugEvent32 event32 = new DebugEvent32(); fHasEvent = NativeMethods.WaitForDebugEvent32(ref event32, timeout); if (fHasEvent) { return(NativeEvent.Build(this, ref event32.header, ref event32.union)); } } else { DebugEvent64 event64 = new DebugEvent64(); fHasEvent = NativeMethods.WaitForDebugEvent64(ref event64, timeout); if (fHasEvent) { return(NativeEvent.Build(this, ref event64.header, ref event64.union)); } } // Not having an event could be a timeout, or it could be a real failure. // Empirically, timeout produces GetLastError()=121 (ERROR_SEM_TIMEOUT), but MSDN doesn't spec that, so // we don't want to rely on it. So if we don't have an event, just return NULL and // don't try to probe any further. return(null); }
/// <summary> /// Continue a debug event previously gotten by WaitForDebugEvent /// </summary> /// <param name="nativeEvent"></param> /// <remarks>Can't continue a debug event if we just detached from the process</remarks> public void ContinueEvent(NativeEvent nativeEvent) { if (nativeEvent == null) { throw new ArgumentNullException("nativeEvent"); } if (nativeEvent.ContinueStatus == NativeMethods.ContinueStatus.CONTINUED) { throw new ArgumentException("event was already continued", "nativeEvent"); } if (nativeEvent.Pipeline != this) { throw new ArgumentException("event does not belong to this pipeline"); } // Verify that the process for this event is still connected to our pipeline. // The lookup will throw if the process detached or was terminated. NativeDbgProcess proc = nativeEvent.Process; Debug.Assert(proc.Id == nativeEvent.ProcessId); nativeEvent.DoCleanupForContinue(); bool fContinueOk = NativeMethods.ContinueDebugEvent((uint)nativeEvent.ProcessId, (uint)nativeEvent.ThreadId, nativeEvent.ContinueStatus); if (!fContinueOk) { int err = Marshal.GetLastWin32Error(); throw new InvalidOperationException("Continue failed on process " + nativeEvent.ProcessId + " error=" + err); } // Mark as continued so that we don't accidentally continue again. nativeEvent.ContinueStatus = NativeMethods.ContinueStatus.CONTINUED; }
/// <summary> /// Check if the event is the Loader Breakpoint, and if so, deal with it. /// </summary> /// <param name="nativeEvent">event</param> /// <remarks>Loader breakpoint is generally the first breakpoint event</remarks> public void HandleIfLoaderBreakpoint(NativeEvent nativeEvent, ref bool loaderBreakpointReceived) { // If it's already handled, nothing left to do if (loaderBreakpointReceived) { return; } // On x86, x64, we can just clear the exception. // This is even more complex on IA64, we have to actually skip it. IA64 is not yet implemented. // Loader Breakpoint is an exception event ExceptionNativeEvent e = nativeEvent as ExceptionNativeEvent; if (e == null) { return; } // and it's a breakpoint if (e.ExceptionCode != ExceptionCode.STATUS_BREAKPOINT) { return; } e.ContinueStatus = NativeMethods.ContinueStatus.DBG_CONTINUE; loaderBreakpointReceived = true; return; }
/// <summary> /// Wait forever for a debug event from a process. /// </summary> /// <returns>event</returns> /// <exception cref="System.InvalidOperationException">throws on failure. Since this waits forever, not having a debug event means we must have hit some error </exception> /// <seealso cref="WaitForDebugEvent"/> /// <remarks> /// All pipeline functions must be called on the same thread. /// </remarks> public NativeEvent WaitForDebugEventInfinite() { // Ensure that we're debugging at least 1 process before we wait forever. if (m_processes.Count == 0) { throw new InvalidOperationException("Pipeline is not debugging any processes. Waiting for a debug event will hang."); } // Pass -1 to timeout to wait forever NativeEvent nativeEvent = WaitForDebugEvent(-1); if (nativeEvent == null) { throw new InvalidOperationException("WaitForDebugEvent failed for non-timeout reason"); } return(nativeEvent); }