/// <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 (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 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); } 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); }
/// <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> /// 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> /// 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 (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 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); } 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; }
/// <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; }
/// <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); }