public StackChain(Debugger debugger, CorChain chain) { debugger.Dispatcher.VerifyAccess(); this.debugger = debugger; this.chain = chain; this.hashCode = chain.GetHashCode(); this.isManaged = chain.IsManaged; this.reason = (ChainReason)chain.Reason; this.stackStart = chain.StackStart; this.stackEnd = chain.StackEnd; }
/// <summary> /// The function should parse the native part of the stack and fill the m_frameCache with the /// corresponding frames from the native chain. Further it should return the top-most frame in the chain. /// </summary> /// <param name="chain">the native chain on the stack</param> /// <returns>First frame from the native chain or null if there are no frames</returns> protected virtual MDbgFrame FillAndGetLeafFrameFromNativeChain(CorChain chain) { Debug.Assert(chain != null); Debug.Assert(!chain.IsManaged); // StackWalkers that support interop callstacks would want to fill the list of frames and return // topmost native frame from that chain. return(null); }
/// <summary> /// Finds the leaf-most frame in the stack. /// </summary> /// <returns>the top-most frame in the stack</returns> protected MDbgFrame ReturnLeafFrame() { MDbgFrame leafFrame = null; CorChain c = null; try { c = Thread.CorThread.ActiveChain; } catch (COMException ce) { // Sometimes we cannot get the callstack. For example, the thread // may not be scheduled yet (CORDBG_E_THREAD_NOT_SCHEDULED), // or the CLR may be corrupt (CORDBG_E_BAD_THREAD_STATE). // In either case, we'll ignore the problem and return an empty callstack. // Debug.Assert(ce.ErrorCode == (int) HResult.CORDBG_E_BAD_THREAD_STATE || // ce.ErrorCode == (int) HResult.CORDBG_E_THREAD_NOT_SCHEDULED); DI.log.error("intenal MDbg error: Debug.Assert(ce.ErrorCode == (int) HResult.CORDBG_E_BAD_THREAD_STATE || ce.ErrorCode == (int) HResult.CORDBG_E_THREAD_NOT_SCHEDULED);"); DI.log.ex(ce); } if (c != null) { if (!c.IsManaged) { leafFrame = FillAndGetLeafFrameFromNativeChain(c); } if (leafFrame == null) { // if we still have no frame, we'll get one from the managed code. while (c != null && (!c.IsManaged || (c.IsManaged && c.ActiveFrame == null)) ) { c = c.Caller; } if (c == null) { leafFrame = null; } else { Debug.Assert(c != null && c.IsManaged); leafFrame = new MDbgILFrame(Thread, c.ActiveFrame); } } } else { leafFrame = null; } return(leafFrame); }
void CheckTimestamp( ) { if (evalTimestamp != CorDebuggerSession.EvaluationTimestamp) { thread = null; frame = null; corEval = null; activeChain = null; } }
/// <summary> /// Creates a new V2 StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> public IEnumerable <MDbgFrame> EnumerateFrames(MDbgThread thread) { // To do stackwalking using V2 ICorDebug, we enumerate through the chains, // and then enumerate each frame in every chain CorChain chain = null; try { chain = thread.CorThread.ActiveChain; } catch (System.Runtime.InteropServices.COMException ce) { // Sometimes we cannot get the callstack. For example, the thread // may not be scheduled yet (CORDBG_E_THREAD_NOT_SCHEDULED), // or the debuggee may be corrupt (CORDBG_E_BAD_THREAD_STATE). // In either case, we'll ignore the problem and return an empty callstack. Debug.Assert(ce.ErrorCode == (int)HResult.CORDBG_E_BAD_THREAD_STATE || ce.ErrorCode == (int)HResult.CORDBG_E_THREAD_NOT_SCHEDULED); } while (chain != null) { if (chain.IsManaged) { // Enumerate managed frames // A chain may have 0 managed frames. CorFrame f = chain.ActiveFrame; while (f != null) { MDbgFrame frame = new MDbgILFrame(thread, f); f = f.Caller; yield return(frame); } } else { // ICorDebug doesn't unwind unmanaged frames. Need to let a native-debug component handle that. foreach (MDbgFrame frame in UnwindNativeFrames(thread, chain)) { yield return(frame); } } // Move to next chain chain = chain.Caller; } }
/// <summary> /// Unwind unmanaged frames within an native chain. /// </summary> /// <param name="thread">thread containing chain</param> /// <param name="nativeChain">a native CorChain</param> /// <returns>enumeration of MDbgFrames for the native frames</returns> /// <remarks>ICorDebug stackwalking only unwinds managed chains. /// A derived class can override this function to provide native stacktracing.</remarks> protected virtual IEnumerable <MDbgFrame> UnwindNativeFrames(MDbgThread thread, CorChain nativeChain) { Debug.Assert(!nativeChain.IsManaged); // Base class can't unwind unmanaged chains. // A derived class can override and provide native stack unwinding. // Use: // 1) chain.RegisterSet to get the starting context. // 2) chain.GetStackRange(out start, out end); to get the stackrange to unwind to // 3) a native unwinder (such as DbgHelp.dll) to actually do the native stack unwinding. yield break; }
/// <summary> /// A function that returns the new MdbgFrame. The function is expected to be overriden by derived implementations. /// </summary> /// <param name="index">0 based index from top of the stack</param> /// <returns>frame from the stack</returns> protected override MDbgFrame GetFrameImpl(int index) { if (index < FrameCache.Count) { return(FrameCache[index]); } MDbgFrame frameToReturn; if (index == 0) { // special case the first frame frameToReturn = ReturnLeafFrame(); } else { // use recursion... MDbgFrame prevFrame = GetFrameImpl(index - 1); if (prevFrame == null) { throw new ArgumentException(); } frameToReturn = GetFrameCaller(prevFrame); if (frameToReturn == null) { // we need to get the next frame from the following chain CorChain chain = GetFrameChain(prevFrame); Debug.Assert(chain != null); // 1. find next chain while (true) { chain = chain.Caller; if (chain == null) { break; } if (chain.IsManaged) { CorFrame f = chain.ActiveFrame; if (f != null) { frameToReturn = new MDbgILFrame(Thread, f); break; } } else { frameToReturn = FillAndGetLeafFrameFromNativeChain(chain); if (frameToReturn != null) { break; } } } } } // store and return frameToReturn if (frameToReturn != null) { Debug.Assert(FrameCache.Count >= index); if (FrameCache.Count == index) { FrameCache.Add(frameToReturn); } else { Debug.Assert(FrameCache[index] == frameToReturn, "List of frames pre-filled with incorrect frame"); } } return(frameToReturn); }