Exemple #1
0
            } // end ChangeDebuggeeState()

            public int ChangeEngineState(DEBUG_CES Flags, ulong Argument)
            {
                LogManager.Trace("ChangeEngineState: {0}, 0x{1:x}", Flags, Argument);
                try
                {
                    var eventArgs = new EngineStateChangedEventArgs(m_debugger, Flags, Argument);
                    if (eventArgs.Flags.HasFlag(DEBUG_CES.EVENT_FILTERS))
                    {
                        // Need to refresh our filters.
                        if (eventArgs.Argument == DbgEventArgs.DEBUG_ANY_ID)
                        {
                            m_debugger._ResetFilters();
                        }
                        else
                        {
                            m_debugger._RefreshSingleFilter((uint)eventArgs.Argument);
                        }
                    }

                    if (eventArgs.Flags.HasFlag(DEBUG_CES.BREAKPOINTS))
                    {
                        // Need to refresh our breakpoints.
                        m_debugger.FixupBpStuff(eventArgs.Argument);
                    }

                    if ((eventArgs.Flags.HasFlag(DEBUG_CES.SYSTEMS)))
                    {
                        // DbgEng doesn't seem to set up its symbol path until you first
                        // attach to something, but it doesn't raise the event saying that
                        // the symbol path has changed when that happens. As a workaround,
                        // we'll dump our cached symbol path here.
                        m_debugger.m_sympath = null;
                        // Another oddity with the symbol path: before attaching to any
                        // system, dbgeng will say that the symbol path is blank. Then,
                        // once it gets attached to something, it will append the value of
                        // the environment variable _NT_SYMBOL_PATH to it.

                        if ((DEBUG_ANY_ID != (uint)eventArgs.Argument))
                        {
                            // We're adding a system. This might be a handy spot to do
                            // something, so I'm leaving the condition here even though I'm
                            // not currently using it.
                            // (this gets traced by the eventArgs constructor)
                        }
                        else
                        {
                            // Removing a system. (this gets traced by the eventArgs
                            // constructor)
                        }
                    }

                    if (eventArgs.Flags.HasFlag(DEBUG_CES.EFFECTIVE_PROCESSOR))
                    {
                        //DbgProvider.ForceRebuildNamespace();
                        LogManager.Trace("Effective processor changed; queueing request to rebuild namespace.");
                        DbgProvider.RequestExecuteBeforeNextPrompt("[MS.Dbg.DbgProvider]::ForceRebuildNamespace()");
                    }

                    if (eventArgs.Flags.HasFlag(DEBUG_CES.EXECUTION_STATUS))
                    {
                        m_executionStatusCookie++;
                    }

                    int retVal = _RaiseEvent(m_debugger.EngineStateChanged, eventArgs);
                    if (_ShouldOutput(retVal, eventArgs))
                    {
                        _PsPipe.WriteObject(eventArgs);
                    }

                    if (DEBUG_CES.EXECUTION_STATUS == Flags)
                    {
                        var  status       = (DEBUG_STATUS)(Argument & (ulong)DEBUG_STATUS.MASK);
                        bool insideWait   = false;
                        bool waitTimedOut = false;
                        if (status != (DEBUG_STATUS)Argument)
                        {
                            insideWait   = 0 != (Argument & (ulong)DEBUG_STATUS_FLAGS.INSIDE_WAIT);
                            waitTimedOut = 0 != (Argument & (ulong)DEBUG_STATUS_FLAGS.WAIT_TIMEOUT);
                        }

                        LogManager.Trace("EXECUTION_STATUS changed. Argument: 0x{0:x} ({1}{2}{3})",
                                         Argument,
                                         status,
                                         insideWait ? " + INSIDE_WAIT" : "",
                                         waitTimedOut ? " + WAIT_TIMEOUT" : "");

                        DbgEngDebugger._GlobalDebugger.DbgEngCookie++;
                        if (0 == ((ulong)DEBUG_STATUS_FLAGS.INSIDE_WAIT & Argument))
                        {
                            // Formerly, we would use this code to signal the currently-
                            // running cmdlet to exit its message loop. The idea was that
                            // there had been problems with more notification events arriving
                            // /after/ WaitForEvent returned. But I can't currently repro
                            // that. (There /are/ some notifications that occur after
                            // WaitForEvent returns, but they are caused by my own actions--
                            // setting assembly options and text aliases.)
                            //
                            // There is also the difference that now I call WaitForEvent on
                            // the dbgeng thread, whereas originally I had been calling it on
                            // a threadpool thread. I'm not sure how that would have made a
                            // difference, though.
                            //
                            // For now, I'm going to get rid of this stuff. It seems fragile
                            // and horribly complicated--I really hope I don't have to bring
                            // it back.
                            //
                            // // TODO: This seems terribly fragile. But I don't see how else to make
                            // // sure we process all callbacks before exiting ProcessRecord. I'm probably
                            // // going to have to add more cases... :(
                            // if( DEBUG_STATUS.BREAK == (DEBUG_STATUS) Argument )
                            // {
                            //     if( _SignalPipeOnBreak )
                            //     {
                            //         LogManager.Trace( "EXECUTION_STATUS is BREAK; signaling pipeline." );
                            //         _PsPipe.SignalDone();
                            //     }
                            //     else
                            //     {
                            //         LogManager.Trace( "EXECUTION_STATUS is BREAK, but we're ignoring it." );
                            //     }
                            // }

                            if (DEBUG_STATUS.NO_DEBUGGEE == (DEBUG_STATUS)Argument)
                            {
                                // We have no target. This might be a handy spot to do
                                // something, so I'm leaving the condition here even
                                // though I'm not currently using it.
                                LogManager.Trace("No debuggee.");
                            }
                        } // end if( inside wait )
                    }     // end if( exec status )

                    return(retVal);
                }
                catch (Exception e)
                {
                    Util.FailFast("Unexpected exception during event callback.", e);
                    return(0);
                }
            } // end ChangeEngineState()
        } // end property Frames


        public IEnumerable <DbgStackFrameInfo> EnumerateStackFrames()
        {
            if (null != m_frames)
            {
                return(m_frames);
            }

            m_frames = new List <DbgStackFrameInfo>();

            bool noException = false;

            try
            {
                return(Debugger.ExecuteOnDbgEngThread(() =>
                {
                    using (new DbgEngContextSaver(Debugger, Context))
                    {
                        WDebugControl dc = (WDebugControl)Debugger.DebuggerInterface;

                        /* TODO: I guess frameOffset doesn't do what I think it does... or maybe I need to file a bug.
                         * //int stride = 64;
                         * int stride = 3;
                         * ulong frameOffset = 0;
                         * int hr = 0;
                         * DEBUG_STACK_FRAME_EX[] frames = new DEBUG_STACK_FRAME_EX[ stride ];
                         * while( true )
                         * {
                         *  uint framesFilled = 0;
                         *  hr = dc.GetStackTraceEx( frameOffset, 0, 0, frames, frames.Length, out framesFilled );
                         *
                         *  CheckHr( hr );
                         *
                         *  if( 0 == framesFilled )
                         *      break;
                         *
                         *  for( int i = 0; i < framesFilled; i++ )
                         *  {
                         *      var newFrame = new StackFrameInfo( Debugger, frames[ i ] );
                         *      m_frames.Add( newFrame );
                         *      //yield return newFrame; hmm, can't mix an iterator with the straight 'return' above
                         *  }
                         *
                         *  frameOffset += 3;
                         * } // while( keep requesting more frames )
                         */

                        DEBUG_STACK_FRAME_EX[] frames;
                        int hr = dc.GetStackTraceEx(0,      // frameOffset
                                                    0,      // stackOffset
                                                    0,      // instructionOffset
                                                    MaxFrameCount,
                                                    out frames);

                        CheckHr(hr);

                        int[] managedFrameIndices;

                        try
                        {
                            managedFrameIndices = new int[Thread.ManagedThreads.Count];
                        }
                        catch (InvalidOperationException ioe)
                        {
                            //
                            // Likely "Mismatched architecture between this process
                            // and the dac." No managed code information for you, sir.
                            //

                            DbgProvider.RequestExecuteBeforeNextPrompt(
                                Util.Sprintf("Write-Warning 'Could not get managed thread/frame information: {0}'",
                                             System.Management.Automation.Language.CodeGeneration.EscapeSingleQuotedStringContent(Util.GetExceptionMessages(ioe))));
                            managedFrameIndices = new int[0];

                            // (and remember not to keep trying to get managed info)
                            Debugger.ClrMdDisabled = true;
                        }

                        foreach (var nativeFrame in frames)
                        {
                            ClrStackFrame managedFrame = null;
                            for (int i = 0; i < managedFrameIndices.Length; i++)
                            {
                                var mThread = Thread.ManagedThreads[i];
                                int mFrameIdx = managedFrameIndices[i];
                                // It's possible that a thread is marked as a managed
                                // thread, but has no stack frames. (I've seen this,
                                // for instance, at the final breakpoint of a managed
                                // app.)
                                if (0 == mThread.StackTrace.Count)
                                {
                                    continue;
                                }

                                if (mFrameIdx >= mThread.StackTrace.Count)
                                {
                                    // We've exhausted the managed frames for this
                                    // particular managed thread.
                                    continue;
                                }

                                var mFrame = mThread.StackTrace[mFrameIdx];
                                while ((0 == mFrame.InstructionPointer) &&
                                       (mFrameIdx < (mThread.StackTrace.Count - 1)))      // still at least one more frame below?
                                {
                                    // It's some sort of "helper" or GC frame or
                                    // something, which we need to skip.
                                    mFrameIdx++;
                                    managedFrameIndices[i] = mFrameIdx;
                                    mFrame = mThread.StackTrace[mFrameIdx];
                                }

                                if (nativeFrame.InstructionOffset == mFrame.InstructionPointer)
                                {
                                    managedFrame = mFrame;
                                    managedFrameIndices[i] += 1;
                                    break;
                                }
                            }

                            var newFrame = new DbgStackFrameInfo(Debugger,
                                                                 m_thread,
                                                                 nativeFrame,
                                                                 managedFrame);
                            m_frames.Add(newFrame);
                        }

                        noException = true;
                        return m_frames;
                    }     // end using( context saver )
                }));
            }
            finally
            {
                if (!noException)
                {
                    m_frames = null; // so we can try again (handy for debugging)
                }
            }
        } // end EnumerateStackFrames()