/// <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)
        {
            bool fHasEvent;

            if (IntPtr.Size == sizeof(Int32))
            {
                var event32 = new DebugEvent32();
                fHasEvent = NativeMethods.WaitForDebugEvent32(ref event32, timeout);
                if (fHasEvent)
                {
                    return(NativeEvent.Build(this, ref event32.header, ref event32.union));
                }
            }
            else
            {
                var 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>
        /// 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)
        {
            // If it's already handled, nothing left to do
            if (m_fLoaderBreakpointReceived)
            {
                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
            var 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;
            m_fLoaderBreakpointReceived = true;
        }
        /// <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);
        }
        /// <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)
        {
            // If it's already handled, nothing left to do
            if (m_fLoaderBreakpointReceived)
            {
                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
            var 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;
            m_fLoaderBreakpointReceived = true;
        }
Exemplo n.º 6
0
        /// <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;
        }