1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 // This file contains the implementation of the Arrowhead stackwalking shim. This shim builds on top of
10 // the public Arrowhead ICD stackwalking API, and it is intended to be backward-compatible with the existing
11 // debuggers using the V2.0 ICD API.
13 // ======================================================================================
16 #include "primitives.h"
18 #if defined(_TARGET_X86_)
19 static const ULONG32 REGISTER_X86_MAX = REGISTER_X86_FPSTACK_7 + 1;
20 static const ULONG32 MAX_MASK_COUNT = (REGISTER_X86_MAX + 7) >> 3;
21 #elif defined(_TARGET_AMD64_)
22 static const ULONG32 REGISTER_AMD64_MAX = REGISTER_AMD64_XMM15 + 1;
23 static const ULONG32 MAX_MASK_COUNT = (REGISTER_AMD64_MAX + 7) >> 3;
26 ShimStackWalk::ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread)
27 : m_pChainEnumList(NULL),
28 m_pFrameEnumList(NULL)
30 // The following assignments increment the ref count.
31 m_pProcess.Assign(pProcess);
32 m_pThread.Assign(pThread);
37 ShimStackWalk::~ShimStackWalk()
42 // ----------------------------------------------------------------------------
43 // ShimStackWalk::Clear
46 // Clear all the memory used by this ShimStackWalk, including the array of frames, the array of chains,
47 // the linked list of ShimChainEnums, and the linked list of ShimFrameEnums.
50 void ShimStackWalk::Clear()
52 // call Release() on each of the ShimChains
53 for (int i = 0; i < m_stackChains.Count(); i++)
55 (*m_stackChains.Get(i))->Neuter();
56 (*m_stackChains.Get(i))->Release();
58 m_stackChains.Clear();
60 // call Release() on each of the ICDFrames
61 for (int i = 0; i < m_stackFrames.Count(); i++)
63 (*m_stackFrames.Get(i))->Release();
65 m_stackFrames.Clear();
67 // call Release() on each of the ShimChainEnums
68 while (m_pChainEnumList != NULL)
70 ShimChainEnum * pCur = m_pChainEnumList;
71 m_pChainEnumList = m_pChainEnumList->GetNext();
76 // call Release() on each of the ShimFrameEnums
77 while (m_pFrameEnumList != NULL)
79 ShimFrameEnum * pCur = m_pFrameEnumList;
80 m_pFrameEnumList = m_pFrameEnumList->GetNext();
85 // release the references
90 //---------------------------------------------------------------------------------------
92 // Helper used by the stackwalker to determine whether a given UM chain should be tracked
93 // during the stackwalk for eventual transmission to the debugger. This function is the
94 // V4 equivalent of Whidbey's code:ShouldSendUMLeafChain (which ran on the LS, from
95 // Debug\EE\frameinfo.cpp).
97 // Note that code:ShouldSendUMLeafChain still exists today (to facilitate some in-process
98 // debugging stackwalks that are still necessary). So consult the comments in
99 // code:ShouldSendUMLeafChain for a more thorough discussion of why we do the checks we
100 // do to decide whether to track the chain.
103 // pswInfo - StackWalkInfo representing the frame in question
106 // nonzero iff the chain should be tracked
109 BOOL ShimStackWalk::ShouldTrackUMChain(StackWalkInfo * pswInfo)
111 _ASSERTE (pswInfo != NULL);
113 // Always track chains for non-leaf UM frames
114 if (!pswInfo->IsLeafFrame())
117 // Sometimes we want to track leaf UM chains, and sometimes we don't. Check all the
118 // reasons not to track the chain, and return FALSE if any of them are hit.
120 CorDebugUserState threadUserState;
121 HRESULT hr = m_pThread->GetUserState(&threadUserState);
124 // ShouldSendUMLeafChain checked IsInWaitSleepJoin which is just USER_WAIT_SLEEP_JOIN
125 if ((threadUserState & USER_WAIT_SLEEP_JOIN) != 0)
128 // This check is the same as Thread::IsUnstarted() from ShouldSendUMLeafChain
129 if ((threadUserState & USER_UNSTARTED) != 0)
132 // This check is the same as Thread::IsDead() from ShouldSendUMLeafChain
133 if ((threadUserState & USER_STOPPED) != 0)
136 // #DacShimSwWorkAround
138 // This part cannot be determined using DBI alone. We must call through to the DAC
139 // because we have no other way to get at TS_Hijacked & TS_SyncSuspended. When the
140 // rearchitecture is complete, this DAC call should be able to go away, and we
141 // should be able to use DBI for all the info we need.
143 // One might think one could avoid the DAC for TS_SyncSuspended by just checking
144 // USER_SUSPENDED, but that won't work. Although USER_SUSPENDED will be returned some
145 // of the time when TS_SyncSuspended is set, that will not be the case when the
146 // debugger must suspend the thread. Example: if the given thread is in the middle of
147 // throwing a managed exception when the debugger breaks in, then TS_SyncSuspended
148 // will be set due to the debugger's breaking, but USER_SUSPENDED will not be set, so
149 // we'll think the UM chain should be tracked, resulting in a stack that differs from
151 if (m_pProcess->IsThreadSuspendedOrHijacked(m_pThread))
157 // ----------------------------------------------------------------------------
158 // ShimStackWalk::Populate
161 // Walk the entire stack and populate the arrays of stack frames and stack chains.
164 void ShimStackWalk::Populate()
168 // query for the ICDThread3 interface
169 RSExtSmartPtr<ICorDebugThread3> pThread3;
170 hr = m_pThread->QueryInterface(IID_ICorDebugThread3, reinterpret_cast<void **>(&pThread3));
173 // create the ICDStackWalk
174 RSExtSmartPtr<ICorDebugStackWalk> pSW;
175 hr = pThread3->CreateStackWalk(&pSW);
178 // structs used to store information during the stackwalk
180 StackWalkInfo swInfo;
182 // use the ICDStackWalk to retrieve the internal frames
183 hr = pThread3->GetActiveInternalFrames(0, &(swInfo.m_cInternalFrames), NULL);
186 // allocate memory for the internal frames
187 if (swInfo.m_cInternalFrames > 0)
189 // allocate memory for the array of RSExtSmartPtrs
190 swInfo.m_ppInternalFrame2.AllocOrThrow(swInfo.m_cInternalFrames);
192 // create a temporary buffer of raw ICDInternalFrame2 to pass to the ICD API
193 NewArrayHolder<ICorDebugInternalFrame2 *> pTmpArray(new ICorDebugInternalFrame2* [swInfo.m_cInternalFrames]);
194 hr = pThread3->GetActiveInternalFrames(swInfo.m_cInternalFrames,
195 &(swInfo.m_cInternalFrames),
199 // transfer the raw array to the RSExtSmartPtr array
200 for (UINT32 i = 0; i < swInfo.m_cInternalFrames; i++)
202 // Assign() increments the ref count
203 swInfo.m_ppInternalFrame2.Assign(i, pTmpArray[i]);
204 pTmpArray[i]->Release();
210 // This is basically how the loop works:
211 // 1) Determine whether we should process the next internal frame or the next stack frame.
212 // 2) If we are skipping frames, the only thing we need to do is to check whether we have reached
214 // 3) Process CHAIN_ENTER_MANAGED/CHAIN_ENTER_UNMANAGED chains
215 // 4) Append the frame to the cache.
216 // 5) Handle other types of chains.
217 // 6) Advance to the next frame.
218 // 7) Check if we should exit the loop.
222 // reset variables used in the loop
223 swInfo.ResetForNextFrame();
225 // retrieve the next stack frame if it's available
226 RSExtSmartPtr<ICorDebugFrame> pFrame;
227 if (!swInfo.ExhaustedAllStackFrames())
229 hr = pSW->GetFrame(&pFrame);
233 // This next clause processes the current frame, regardless of whether it's an internal frame or a
234 // stack frame. Normally, "pFrame != NULL" is a good enough check, except for the case where we
235 // have exhausted all the stack frames but still have internal frames to process.
236 if ((pFrame != NULL) || swInfo.ExhaustedAllStackFrames())
238 // prefetch the internal frame type
239 if (!swInfo.ExhaustedAllInternalFrames())
241 swInfo.m_internalFrameType = GetInternalFrameType(swInfo.GetCurrentInternalFrame());
244 // We cannot have exhausted both the stack frames and the internal frames when we get to here.
245 // We should have exited the loop if we have exhausted both types of frames.
246 if (swInfo.ExhaustedAllStackFrames())
248 swInfo.m_fProcessingInternalFrame = true;
250 else if (swInfo.ExhaustedAllInternalFrames())
252 swInfo.m_fProcessingInternalFrame = false;
256 // check whether we should process the next internal frame or the next stack frame
257 swInfo.m_fProcessingInternalFrame = (CheckInternalFrame(pFrame, &swInfo, pThread3, pSW) == TRUE);
260 // The only thing we do while we are skipping frames is to check whether we have reached the
261 // parent frame, and we only need to check if we are processing a stack frame.
262 if (swInfo.IsSkippingFrame())
264 if (!swInfo.m_fProcessingInternalFrame)
266 // Check whether we have reached the parent frame yet.
267 RSExtSmartPtr<ICorDebugNativeFrame2> pNFrame2;
268 hr = pFrame->QueryInterface(IID_ICorDebugNativeFrame2, reinterpret_cast<void **>(&pNFrame2));
271 BOOL fIsParent = FALSE;
272 hr = swInfo.m_pChildFrame->IsMatchingParentFrame(pNFrame2, &fIsParent);
277 swInfo.m_pChildFrame.Clear();
281 else if(swInfo.m_fProcessingInternalFrame && !chainInfo.m_fLeafNativeContextIsValid &&
282 swInfo.m_internalFrameType == STUBFRAME_M2U)
284 // Filter this frame out entirely
285 // This occurs because InlinedCallFrames get placed inside leaf managed methods.
286 // The frame gets erected before the native call is made and destroyed afterwards
287 // but there is a window in which the debugger could stop where the internal frame
288 // is live but we are executing jitted code. See Dev10 issue 743230
289 // It is quite possible other frames have this same pattern if the debugger were
290 // stopped right at the spot where they are being constructed. And that is
291 // just a facet of the general data structure consistency problems the debugger
296 // Don't add any frame just yet. We need to deal with any unmanaged chain
297 // we are tracking first.
299 // track the current enter-unmanaged chain and/or enter-managed chain
300 TrackUMChain(&chainInfo, &swInfo);
302 if (swInfo.m_fProcessingInternalFrame)
304 // Check if this is a leaf internal frame. If so, check its frame type.
305 // In V2, code:DebuggerWalkStackProc doesn't expose chains derived from leaf internal
306 // frames of type TYPE_INTERNAL. However, V2 still exposes leaf M2U and U2M internal
308 if (swInfo.IsLeafFrame())
310 if (swInfo.m_internalFrameType == STUBFRAME_EXCEPTION)
312 // We need to make sure we don't accidentally send an enter-unmanaged chain
313 // because of the leaf STUBFRAME_EXCEPTION.
314 chainInfo.CancelUMChain();
315 swInfo.m_fSkipChain = true;
319 _ASSERTE(!swInfo.IsSkippingFrame());
320 if (ConvertInternalFrameToDynamicMethod(&swInfo))
322 // We have just converted a STUBFRAME_JIT_COMPILATION to a
323 // STUBFRAME_LIGHTWEIGHT_FUNCTION (or to NULL). Since the latter frame type doesn't
324 // map to any chain in V2, let's skip the chain handling.
325 swInfo.m_fSkipChain = true;
327 // We may have converted to NULL, which means that we are dealing with an IL stub
328 // and we shouldn't expose it.
329 if (swInfo.GetCurrentInternalFrame() != NULL)
331 AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
336 // One more check before we append the internal frame: make sure the frame type is a
337 // V2 frame type first.
338 if (!IsV3FrameType(swInfo.m_internalFrameType))
340 AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
346 if (!chainInfo.m_fNeedEnterManagedChain)
348 // If we have hit any managed stack frame, then we may need to send
349 // an enter-managed chain later. Save the CONTEXT now.
350 SaveChainContext(pSW, &chainInfo, &(chainInfo.m_leafManagedContext));
351 chainInfo.m_fNeedEnterManagedChain = true;
354 // We are processing a stack frame.
355 // Only append the frame if it's NOT a dynamic method.
356 _ASSERTE(!swInfo.IsSkippingFrame());
357 if (ConvertStackFrameToDynamicMethod(pFrame, &swInfo))
359 // We have converted a ICDNativeFrame for an IL method without metadata to an
360 // ICDInternalFrame of type STUBFRAME_LIGHTWEIGHT_FUNCTION (or to NULL).
361 // Fortunately, we don't have to update any state here
362 // (e.g. m_fProcessingInternalFrame) because the rest of the loop doesn't care.
363 if (swInfo.GetCurrentInternalFrame() != NULL)
365 AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
370 AppendFrame(pFrame, &swInfo);
373 // If we have just processed a child frame, we should start skipping.
374 // Get the ICDNativeFrame2 pointer to check.
375 RSExtSmartPtr<ICorDebugNativeFrame2> pNFrame2;
376 hr = pFrame->QueryInterface(IID_ICorDebugNativeFrame2, reinterpret_cast<void **>(&pNFrame2));
379 if (pNFrame2 != NULL)
381 BOOL fIsChild = FALSE;
382 hr = pNFrame2->IsChild(&fIsChild);
387 swInfo.m_pChildFrame.Assign(pNFrame2);
392 } // process the current frame (managed stack frame or internal frame)
394 // We can take care of other types of chains here, but only do so if we are not currently skipping
396 if (!swInfo.IsSkippingFrame())
398 if ((pFrame == NULL) &&
399 !swInfo.ExhaustedAllStackFrames())
401 // We are here because we are processing a native marker stack frame, not because
402 // we have exhausted all the stack frames.
404 // We need to save the CONTEXT to start tracking an unmanaged chain.
405 SaveChainContext(pSW, &chainInfo, &(chainInfo.m_leafNativeContext));
406 chainInfo.m_fLeafNativeContextIsValid = true;
408 // begin tracking UM chain if we're supposed to
409 if (ShouldTrackUMChain(&swInfo))
411 chainInfo.m_reason = CHAIN_ENTER_UNMANAGED;
416 // handle other types of chains
417 if (swInfo.m_fProcessingInternalFrame)
419 if (!swInfo.m_fSkipChain)
421 BOOL fNewChain = FALSE;
423 switch (swInfo.m_internalFrameType)
425 case STUBFRAME_M2U: // fall through
426 case STUBFRAME_U2M: // fall through
427 // These frame types are tracked specially.
430 case STUBFRAME_APPDOMAIN_TRANSITION: // fall through
431 case STUBFRAME_LIGHTWEIGHT_FUNCTION: // fall through
432 case STUBFRAME_INTERNALCALL:
433 // These frame types don't correspond to chains.
436 case STUBFRAME_FUNC_EVAL:
437 chainInfo.m_reason = CHAIN_FUNC_EVAL;
441 case STUBFRAME_CLASS_INIT: // fall through
442 case STUBFRAME_JIT_COMPILATION:
443 // In Whidbey, these two frame types are the same.
444 chainInfo.m_reason = CHAIN_CLASS_INIT;
448 case STUBFRAME_EXCEPTION:
449 chainInfo.m_reason = CHAIN_EXCEPTION_FILTER;
453 case STUBFRAME_SECURITY:
454 chainInfo.m_reason = CHAIN_SECURITY;
459 // We can only reach this case if we have converted an IL stub to NULL.
460 _ASSERTE(swInfo.HasConvertedFrame());
466 chainInfo.m_rootFP = GetFramePointerForChain(swInfo.GetCurrentInternalFrame());
467 AppendChain(&chainInfo, &swInfo);
470 } // chain handling for an internl frame
471 } // chain handling for a managed stack frame or an internal frame
474 // Reset the flag for leaf frame if we have processed any frame. The only case where we should
475 // not reset this flag is if the ICDStackWalk is stopped at a native stack frame on creation.
476 if (swInfo.IsLeafFrame())
478 if (swInfo.m_fProcessingInternalFrame || (pFrame != NULL))
480 swInfo.m_fLeafFrame = false;
484 // advance to the next frame
485 if (swInfo.m_fProcessingInternalFrame)
487 swInfo.m_curInternalFrame += 1;
494 // check for the end of stack condition
495 if (hr == CORDBG_S_AT_END_OF_STACK)
497 // By the time we finish the stackwalk, all child frames should have been matched with their
498 // respective parent frames.
499 _ASSERTE(!swInfo.IsSkippingFrame());
501 swInfo.m_fExhaustedAllStackFrames = true;
505 // Break out of the loop if we have exhausted all the frames.
506 if (swInfo.ExhaustedAllFrames())
512 // top off the stackwalk with a thread start chain
513 chainInfo.m_reason = CHAIN_THREAD_START;
514 chainInfo.m_rootFP = ROOT_MOST_FRAME; // In Whidbey, we actually use the cached stack base value.
515 AppendChain(&chainInfo, &swInfo);
518 // the caller is responsible for addref and release
519 ICorDebugThread * ShimStackWalk::GetThread()
524 // the caller is responsible for addref and release
525 ShimChain * ShimStackWalk::GetChain(UINT32 index)
527 if (index >= (UINT32)(m_stackChains.Count()))
533 return *(m_stackChains.Get((int)index));
537 // the caller is responsible for addref and release
538 ICorDebugFrame * ShimStackWalk::GetFrame(UINT32 index)
540 if (index >= (UINT32)(m_stackFrames.Count()))
546 return *(m_stackFrames.Get((int)index));
550 ULONG ShimStackWalk::GetChainCount()
552 return m_stackChains.Count();
555 ULONG ShimStackWalk::GetFrameCount()
557 return m_stackFrames.Count();
560 RSLock * ShimStackWalk::GetShimLock()
562 return m_pProcess->GetShimLock();
566 // ----------------------------------------------------------------------------
567 // ShimStackWalk::AddChainEnum
570 // Add the specified ShimChainEnum to the head of the linked list of ShimChainEnums on the ShimStackWalk.
573 // * pChainEnum - the ShimChainEnum to be added
576 void ShimStackWalk::AddChainEnum(ShimChainEnum * pChainEnum)
578 pChainEnum->SetNext(m_pChainEnumList);
579 if (m_pChainEnumList != NULL)
581 m_pChainEnumList->Release();
584 m_pChainEnumList = pChainEnum;
585 if (m_pChainEnumList != NULL)
587 m_pChainEnumList->AddRef();
591 // ----------------------------------------------------------------------------
592 // ShimStackWalk::AddFrameEnum
595 // Add the specified ShimFrameEnum to the head of the linked list of ShimFrameEnums on the ShimStackWalk.
598 // * pFrameEnum - the ShimFrameEnum to be added
601 void ShimStackWalk::AddFrameEnum(ShimFrameEnum * pFrameEnum)
603 pFrameEnum->SetNext(m_pFrameEnumList);
604 if (m_pFrameEnumList != NULL)
606 m_pFrameEnumList->Release();
609 m_pFrameEnumList = pFrameEnum;
610 if (m_pFrameEnumList != NULL)
612 m_pFrameEnumList->AddRef();
616 // Return the ICDThread associated with the current ShimStackWalk as a key for ShimStackWalkHashTableTraits.
617 ICorDebugThread * ShimStackWalk::GetKey()
622 // Hash a given ICDThread, which is used as the key for ShimStackWalkHashTableTraits.
624 UINT32 ShimStackWalk::Hash(ICorDebugThread * pThread)
626 // just return the pointer value
627 return (UINT32)(size_t)pThread;
630 // ----------------------------------------------------------------------------
631 // ShimStackWalk::IsLeafFrame
634 // Check whether the specified frame is the leaf frame.
637 // * pFrame - frame to be checked
640 // Return TRUE if the specified frame is the leaf frame.
641 // Return FALSE otherwise.
644 // * The definition of the leaf frame in V2 is the frame at the leaf of the leaf chain.
647 BOOL ShimStackWalk::IsLeafFrame(ICorDebugFrame * pFrame)
649 // check if we have any chain
650 if (GetChainCount() > 0)
652 // check if the leaf chain has any frame
653 if (GetChain(0)->GetLastFrameIndex() > 0)
655 return IsSameFrame(pFrame, GetFrame(0));
661 // ----------------------------------------------------------------------------
662 // ShimStackWalk::IsSameFrame
665 // Given two ICDFrames, check if they refer to the same frame.
666 // This is much more than a pointer comparison. This function actually checks the frame address,
667 // the stack pointer, etc. to make sure if the frames are the same.
670 // * pLeft - frame to be compared
671 // * pRight - frame to be compared
674 // Return TRUE if the two ICDFrames represent the same frame.
677 BOOL ShimStackWalk::IsSameFrame(ICorDebugFrame * pLeft, ICorDebugFrame * pRight)
681 // Quick check #1: If the pointers are the same then the two frames are the same (duh!).
687 RSExtSmartPtr<ICorDebugNativeFrame> pLeftNativeFrame;
688 hr = pLeft->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pLeftNativeFrame));
692 // The left frame is a stack frame.
693 RSExtSmartPtr<ICorDebugNativeFrame> pRightNativeFrame;
694 hr = pRight->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pRightNativeFrame));
698 // The right frame is NOT a stack frame.
703 // Quick check #2: If the IPs are different then the two frames are not the same (duh!).
707 hr = pLeftNativeFrame->GetIP(&leftOffset);
710 hr = pRightNativeFrame->GetIP(&rightOffset);
713 if (leftOffset != rightOffset)
719 CORDB_ADDRESS leftStart;
720 CORDB_ADDRESS leftEnd;
721 CORDB_ADDRESS rightStart;
722 CORDB_ADDRESS rightEnd;
724 hr = pLeftNativeFrame->GetStackRange(&leftStart, &leftEnd);
727 hr = pRightNativeFrame->GetStackRange(&rightStart, &rightEnd);
730 return ((leftStart == rightStart) && (leftEnd == rightEnd));
735 RSExtSmartPtr<ICorDebugInternalFrame2> pLeftInternalFrame2;
736 hr = pLeft->QueryInterface(IID_ICorDebugInternalFrame2,
737 reinterpret_cast<void **>(&pLeftInternalFrame2));
741 // The left frame is an internal frame.
742 RSExtSmartPtr<ICorDebugInternalFrame2> pRightInternalFrame2;
743 hr = pRight->QueryInterface(IID_ICorDebugInternalFrame2,
744 reinterpret_cast<void **>(&pRightInternalFrame2));
752 // The right frame is also an internal frame.
754 // Check the frame address.
755 CORDB_ADDRESS leftFrameAddr;
756 CORDB_ADDRESS rightFrameAddr;
758 hr = pLeftInternalFrame2->GetAddress(&leftFrameAddr);
761 hr = pRightInternalFrame2->GetAddress(&rightFrameAddr);
764 return (leftFrameAddr == rightFrameAddr);
772 // This is the shim implementation of ICDThread::EnumerateChains().
773 void ShimStackWalk::EnumerateChains(ICorDebugChainEnum ** ppChainEnum)
775 NewHolder<ShimChainEnum> pChainEnum(new ShimChainEnum(this, GetShimLock()));
777 *ppChainEnum = pChainEnum;
778 (*ppChainEnum)->AddRef();
779 AddChainEnum(pChainEnum);
781 pChainEnum.SuppressRelease();
784 // This is the shim implementation of ICDThread::GetActiveChain().
785 void ShimStackWalk::GetActiveChain(ICorDebugChain ** ppChain)
787 if (GetChainCount() == 0)
793 *ppChain = static_cast<ICorDebugChain *>(GetChain(0));
794 (*ppChain)->AddRef();
798 // This is the shim implementation of ICDThread::GetActiveFrame().
799 void ShimStackWalk::GetActiveFrame(ICorDebugFrame ** ppFrame)
802 // Make sure two things:
803 // 1) We have at least one frame.
804 // 2) The leaf frame is in the leaf chain, i.e. the leaf chain is not empty.
806 if ((GetFrameCount() == 0) ||
807 (GetChain(0)->GetLastFrameIndex() == 0))
813 *ppFrame = GetFrame(0);
814 (*ppFrame)->AddRef();
818 // This is the shim implementation of ICDThread::GetRegisterSet().
819 void ShimStackWalk::GetActiveRegisterSet(ICorDebugRegisterSet ** ppRegisterSet)
821 _ASSERTE(GetChainCount() != 0);
822 _ASSERTE(GetChain(0) != NULL);
824 // Return the register set of the leaf chain.
825 HRESULT hr = GetChain(0)->GetRegisterSet(ppRegisterSet);
829 // This is the shim implementation of ICDFrame::GetChain().
830 void ShimStackWalk::GetChainForFrame(ICorDebugFrame * pFrame, ICorDebugChain ** ppChain)
832 CORDB_ADDRESS frameStart;
833 CORDB_ADDRESS frameEnd;
834 IfFailThrow(pFrame->GetStackRange(&frameStart, &frameEnd));
836 for (UINT32 i = 0; i < GetChainCount(); i++)
838 ShimChain * pCurChain = GetChain(i);
840 CORDB_ADDRESS chainStart;
841 CORDB_ADDRESS chainEnd;
842 IfFailThrow(pCurChain->GetStackRange(&chainStart, &chainEnd));
844 if ((chainStart <= frameStart) && (frameEnd <= chainEnd))
846 // We need to check the next chain as well since some chains overlap at the boundary.
847 // If the current chain is the last one, no additional checking is required.
848 if (i < (GetChainCount() - 1))
850 ShimChain * pNextChain = GetChain(i + 1);
852 CORDB_ADDRESS nextChainStart;
853 CORDB_ADDRESS nextChainEnd;
854 IfFailThrow(pNextChain->GetStackRange(&nextChainStart, &nextChainEnd));
856 if ((nextChainStart <= frameStart) && (frameEnd <= nextChainEnd))
858 // The frame lies in the stack ranges of two chains. This can only happn at the boundary.
859 if (pCurChain->GetFirstFrameIndex() == pCurChain->GetLastFrameIndex())
861 // Make sure the next chain is not empty.
862 _ASSERTE(pNextChain->GetFirstFrameIndex() != pNextChain->GetLastFrameIndex());
864 // The current chain is empty, so the chain we want is the next one.
865 pCurChain = pNextChain;
867 // If the next chain is empty, then we'll just return the current chain and no additional
868 // work is needed. If the next chain is not empty, then we have more checking to do.
869 else if (pNextChain->GetFirstFrameIndex() != pNextChain->GetLastFrameIndex())
871 // Both chains are non-empty.
872 if (IsSameFrame(GetFrame(pNextChain->GetFirstFrameIndex()), pFrame))
874 // The same frame cannot be in both chains.
875 _ASSERTE(!IsSameFrame(GetFrame(pCurChain->GetLastFrameIndex() - 1), pFrame));
876 pCurChain = pNextChain;
880 _ASSERTE(IsSameFrame(GetFrame(pCurChain->GetLastFrameIndex() - 1), pFrame));
886 *ppChain = static_cast<ICorDebugChain *>(pCurChain);
887 (*ppChain)->AddRef();
893 // This is the shim implementation of ICDFrame::GetCaller().
894 void ShimStackWalk::GetCallerForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCallerFrame)
896 for (UINT32 i = 0; i < GetChainCount(); i++)
898 ShimChain * pCurChain = GetChain(i);
900 for (UINT32 j = pCurChain->GetFirstFrameIndex(); j < pCurChain->GetLastFrameIndex(); j++)
902 if (IsSameFrame(GetFrame(j), pFrame))
904 // Check whether this is the last frame in the chain.
905 UINT32 callerFrameIndex = j + 1;
906 if (callerFrameIndex < pCurChain->GetLastFrameIndex())
908 *ppCallerFrame = static_cast<ICorDebugFrame *>(GetFrame(callerFrameIndex));
909 (*ppCallerFrame)->AddRef();
913 *ppCallerFrame = NULL;
921 // This is the shim implementation of ICDFrame::GetCallee().
922 void ShimStackWalk::GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCalleeFrame)
924 for (UINT32 i = 0; i < GetChainCount(); i++)
926 ShimChain * pCurChain = GetChain(i);
928 for (UINT32 j = pCurChain->GetFirstFrameIndex(); j < pCurChain->GetLastFrameIndex(); j++)
930 if (IsSameFrame(GetFrame(j), pFrame))
932 // Check whether this is the first frame in the chain.
933 if (j > pCurChain->GetFirstFrameIndex())
935 UINT32 calleeFrameIndex = j - 1;
936 *ppCalleeFrame = static_cast<ICorDebugFrame *>(GetFrame(calleeFrameIndex));
937 (*ppCalleeFrame)->AddRef();
941 *ppCalleeFrame = NULL;
949 FramePointer ShimStackWalk::GetFramePointerForChain(DT_CONTEXT * pContext)
951 return FramePointer::MakeFramePointer(CORDbgGetSP(pContext));
954 FramePointer ShimStackWalk::GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2)
956 CORDB_ADDRESS frameAddr;
957 HRESULT hr = pInternalFrame2->GetAddress(&frameAddr);
960 return FramePointer::MakeFramePointer(reinterpret_cast<void *>(frameAddr));
963 CorDebugInternalFrameType ShimStackWalk::GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2)
967 // Retrieve the frame type of the internal frame.
968 RSExtSmartPtr<ICorDebugInternalFrame> pFrame;
969 hr = pFrame2->QueryInterface(IID_ICorDebugInternalFrame, reinterpret_cast<void **>(&pFrame));
972 CorDebugInternalFrameType type;
973 hr = pFrame->GetFrameType(&type);
979 // ----------------------------------------------------------------------------
980 // ShimStackWalk::AppendFrame
983 // Append the specified frame to the array and increment the counter.
986 // * pFrame - the frame to be added
987 // * pStackWalkInfo - contains information of the stackwalk
990 void ShimStackWalk::AppendFrame(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo)
993 ICorDebugFrame ** ppFrame = m_stackFrames.AppendThrowing();
995 // Be careful of the AddRef() below. Once we do the addref, we need to save the pointer and
996 // explicitly release it.
998 (*ppFrame)->AddRef();
1000 pStackWalkInfo->m_cFrame += 1;
1003 // ----------------------------------------------------------------------------
1004 // Refer to comment of the overloaded function.
1007 void ShimStackWalk::AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, StackWalkInfo * pStackWalkInfo)
1009 RSExtSmartPtr<ICorDebugFrame> pFrame;
1010 HRESULT hr = pInternalFrame2->QueryInterface(IID_ICorDebugFrame, reinterpret_cast<void **>(&pFrame));
1013 AppendFrame(pFrame, pStackWalkInfo);
1016 // ----------------------------------------------------------------------------
1017 // ShimStackWalk::AppendChainWorker
1020 // Append the specified chain to the array.
1023 // * pStackWalkInfo - contains information regarding the stackwalk
1024 // * pLeafContext - the leaf CONTEXT of the chain to be added
1025 // * fpRoot - the root boundary of the chain to be added
1026 // * chainReason - the chain reason of the chain to be added
1027 // * fIsManagedChain - whether the chain to be added is managed
1030 void ShimStackWalk::AppendChainWorker(StackWalkInfo * pStackWalkInfo,
1031 DT_CONTEXT * pLeafContext,
1032 FramePointer fpRoot,
1033 CorDebugChainReason chainReason,
1034 BOOL fIsManagedChain)
1036 // first, create the chain
1037 NewHolder<ShimChain> pChain(new ShimChain(this,
1040 pStackWalkInfo->m_cChain,
1041 pStackWalkInfo->m_firstFrameInChain,
1042 pStackWalkInfo->m_cFrame,
1047 // Grow the array and add the newly created chain.
1048 // Once we call AddRef() we own the ShimChain and need to release it.
1049 ShimChain ** ppChain = m_stackChains.AppendThrowing();
1051 (*ppChain)->AddRef();
1053 // update the counters on the StackWalkInfo
1054 pStackWalkInfo->m_cChain += 1;
1055 pStackWalkInfo->m_firstFrameInChain = pStackWalkInfo->m_cFrame;
1057 // If all goes well, suppress the release so that the ShimChain won't go away.
1058 pChain.SuppressRelease();
1061 // ----------------------------------------------------------------------------
1062 // ShimStackWalk::AppendChain
1065 // Append the chain to the array. This function is also smart enough to send an enter-managed chain
1066 // if necessary. In other words, this function may append two chains at the same time.
1069 // * pChainInfo - information on the chain to be added
1070 // * pStackWalkInfo - information regarding the current stackwalk
1073 void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo)
1075 // Check if the chain to be added is managed or not.
1076 BOOL fManagedChain = FALSE;
1077 if ((pChainInfo->m_reason == CHAIN_ENTER_MANAGED) ||
1078 (pChainInfo->m_reason == CHAIN_CLASS_INIT) ||
1079 (pChainInfo->m_reason == CHAIN_SECURITY) ||
1080 (pChainInfo->m_reason == CHAIN_FUNC_EVAL))
1082 fManagedChain = TRUE;
1085 DT_CONTEXT * pChainContext = NULL;
1088 // The chain to be added is managed itself. So we don't need to send an enter-managed chain.
1089 pChainInfo->m_fNeedEnterManagedChain = false;
1090 pChainContext = &(pChainInfo->m_leafManagedContext);
1094 // The chain to be added is unmanaged. Check if we need to send an enter-managed chain.
1095 if (pChainInfo->m_fNeedEnterManagedChain)
1097 // We need to send an extra enter-managed chain.
1098 _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid);
1099 BYTE * sp = reinterpret_cast<BYTE *>(CORDbgGetSP(&(pChainInfo->m_leafNativeContext)));
1100 #if !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_)
1101 // Dev11 324806: on ARM we use the caller's SP for a frame's ending delimiter so we cannot
1102 // subtract 4 bytes from the chain's ending delimiter else the frame might never be in range.
1103 // TODO: revisit overlapping ranges on ARM, it would be nice to make it consistent with the other architectures.
1104 sp -= sizeof(LPVOID);
1106 FramePointer fp = FramePointer::MakeFramePointer(sp);
1108 AppendChainWorker(pStackWalkInfo,
1109 &(pChainInfo->m_leafManagedContext),
1111 CHAIN_ENTER_MANAGED,
1114 pChainInfo->m_fNeedEnterManagedChain = false;
1116 _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid);
1117 pChainContext = &(pChainInfo->m_leafNativeContext);
1120 // Add the actual chain.
1121 AppendChainWorker(pStackWalkInfo,
1123 pChainInfo->m_rootFP,
1124 pChainInfo->m_reason,
1128 // ----------------------------------------------------------------------------
1129 // ShimStackWalk::SaveChainContext
1132 // Save the current CONTEXT on the ICDStackWalk into the specified CONTEXT. Also update the root end
1133 // of the chain on the ChainInfo.
1136 // * pSW - the ICDStackWalk for the current stackwalk
1137 // * pChainInfo - the ChainInfo keeping track of the current chain
1138 // * pContext - the destination CONTEXT
1141 void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext)
1143 HRESULT hr = pSW->GetContext(CONTEXT_FULL,
1146 reinterpret_cast<BYTE *>(pContext));
1149 pChainInfo->m_rootFP = GetFramePointerForChain(pContext);
1152 // ----------------------------------------------------------------------------
1153 // ShimStackWalk::CheckInternalFrame
1156 // Check whether the next frame to be processed should be the next internal frame or the next stack frame.
1159 // * pNextStackFrame - the next stack frame
1160 // * pStackWalkInfo - information regarding the current stackwalk; also contains the next internal frame
1161 // * pThread3 - the thread we are walking
1162 // * pSW - the current stackwalk
1165 // Return TRUE if we should process an internal frame next.
1168 BOOL ShimStackWalk::CheckInternalFrame(ICorDebugFrame * pNextStackFrame,
1169 StackWalkInfo * pStackWalkInfo,
1170 ICorDebugThread3 * pThread3,
1171 ICorDebugStackWalk * pSW)
1173 _ASSERTE(pNextStackFrame != NULL);
1174 _ASSERTE(!pStackWalkInfo->ExhaustedAllInternalFrames());
1176 HRESULT hr = E_FAIL;
1177 BOOL fIsInternalFrameFirst = FALSE;
1179 // Special handling for the case where a managed method contains a M2U internal frame.
1180 // Normally only IL stubs contain M2U internal frames, but we may have inlined pinvoke calls in
1181 // optimized code. In that case, we would have an InlinedCallFrame in a normal managed method on x86.
1182 // On WIN64, we would have a normal NDirectMethodFrame* in a normal managed method.
1183 if (pStackWalkInfo->m_internalFrameType == STUBFRAME_M2U)
1185 // create a temporary ICDStackWalk
1186 RSExtSmartPtr<ICorDebugStackWalk> pTmpSW;
1187 hr = pThread3->CreateStackWalk(&pTmpSW);
1190 // retrieve the current CONTEXT
1192 ctx.ContextFlags = DT_CONTEXT_FULL;
1193 hr = pSW->GetContext(ctx.ContextFlags, sizeof(ctx), NULL, reinterpret_cast<BYTE *>(&ctx));
1196 // set the CONTEXT on the temporary ICDStackWalk
1197 hr = pTmpSW->SetContext(SET_CONTEXT_FLAG_ACTIVE_FRAME, sizeof(ctx), reinterpret_cast<BYTE *>(&ctx));
1200 // unwind the temporary ICDStackWalk by one frame
1201 hr = pTmpSW->Next();
1204 // Unwinding from a managed stack frame will land us either in a managed stack frame or a native
1205 // stack frame. In either case, we have a CONTEXT.
1206 hr = pTmpSW->GetContext(ctx.ContextFlags, sizeof(ctx), NULL, reinterpret_cast<BYTE *>(&ctx));
1209 // Get the SP from the CONTEXT. This is the caller SP.
1210 CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS(CORDbgGetSP(&ctx));
1212 // get the frame address
1213 CORDB_ADDRESS frameAddr = 0;
1214 hr = pStackWalkInfo->GetCurrentInternalFrame()->GetAddress(&frameAddr);
1217 // Compare the frame address with the caller SP of the stack frame for the IL method without metadata.
1218 fIsInternalFrameFirst = (frameAddr < sp);
1222 hr = pStackWalkInfo->GetCurrentInternalFrame()->IsCloserToLeaf(pNextStackFrame, &fIsInternalFrameFirst);
1226 return fIsInternalFrameFirst;
1229 // ----------------------------------------------------------------------------
1230 // ShimStackWalk::ConvertInternalFrameToDynamicMethod
1233 // In V2, PrestubMethodFrames (PMFs) are exposed as one of two things: a chain of type
1234 // CHAIN_CLASS_INIT in most cases, or an internal frame of type STUBFRAME_LIGHTWEIGHT_FUNCTION if
1235 // the method being jitted is a dynamic method. On the other hand, in Arrowhead, we consistently expose
1236 // PMFs as STUBFRAME_JIT_COMPILATION. This function determines if a STUBFRAME_JIT_COMPILATION should
1237 // be exposed, and, if so, how to expose it. In the case where conversion is necessary, this function
1238 // also updates the stackwalk information with the converted frame.
1240 // Here are the rules for conversion:
1241 // 1) If the method being jitted is an IL stub, we set the converted frame to NULL, and we return TRUE.
1242 // 2) If the method being jitted is an LCG method, we set the converted frame to a
1243 // STUBFRAME_LIGHTWEIGHT_FUNCTION, and we return NULL.
1244 // 3) Otherwise, we return FALSE.
1247 // * pStackWalkInfo - information about the current stackwalk
1250 // Return TRUE if a conversion has taken place.
1253 BOOL ShimStackWalk::ConvertInternalFrameToDynamicMethod(StackWalkInfo * pStackWalkInfo)
1255 HRESULT hr = E_FAIL;
1258 RSExtSmartPtr<ICorDebugFrame> pOriginalFrame;
1259 hr = pStackWalkInfo->GetCurrentInternalFrame()->QueryInterface(
1261 reinterpret_cast<void **>(&pOriginalFrame));
1264 // Ask the RS to do the real work.
1265 CordbThread * pThread = static_cast<CordbThread *>(m_pThread.GetValue());
1266 pStackWalkInfo->m_fHasConvertedFrame = (TRUE == pThread->ConvertFrameForILMethodWithoutMetadata(
1268 &(pStackWalkInfo->m_pConvertedInternalFrame2)));
1270 if (pStackWalkInfo->HasConvertedFrame())
1272 // We have a conversion.
1273 if (pStackWalkInfo->GetCurrentInternalFrame() != NULL)
1275 // We have a converted internal frame, so let's update the internal frame type.
1276 RSExtSmartPtr<ICorDebugInternalFrame> pInternalFrame;
1277 hr = pStackWalkInfo->GetCurrentInternalFrame()->QueryInterface(
1278 IID_ICorDebugInternalFrame,
1279 reinterpret_cast<void **>(&pInternalFrame));
1282 hr = pInternalFrame->GetFrameType(&(pStackWalkInfo->m_internalFrameType));
1287 // The method being jitted is an IL stub, so let's not expose it.
1288 pStackWalkInfo->m_internalFrameType = STUBFRAME_NONE;
1292 return pStackWalkInfo->HasConvertedFrame();
1295 // ----------------------------------------------------------------------------
1296 // ShimStackWalk::ConvertInternalFrameToDynamicMethod
1299 // In V2, LCG methods are exposed as internal frames of type STUBFRAME_LIGHTWEIGHT_FUNCTION. However,
1300 // in Arrowhead, LCG methods are exposed as first-class stack frames, not internal frames. Thus,
1301 // the shim needs to convert an ICDNativeFrame for a dynamic method in Arrowhead to an
1302 // ICDInternalFrame of type STUBFRAME_LIGHTWEIGHT_FUNCTION in V2. Furthermore, IL stubs are not exposed
1305 // Here are the rules for conversion:
1306 // 1) If the stack frame is for an IL stub, we set the converted frame to NULL, and we return TRUE.
1307 // 2) If the stack frame is for an LCG method, we set the converted frame to a
1308 // STUBFRAME_LIGHTWEIGHT_FUNCTION, and we return NULL.
1309 // 3) Otherwise, we return FALSE.
1312 // * pFrame - the frame to be checked and converted if necessary
1313 // * pStackWalkInfo - information about the current stackwalk
1316 // Return TRUE if a conversion has taken place.
1319 BOOL ShimStackWalk::ConvertStackFrameToDynamicMethod(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo)
1321 // If this is not a dynamic method (i.e. LCG method or IL stub), then we don't need to do a conversion.
1322 if (!IsILFrameWithoutMetadata(pFrame))
1327 // Ask the RS to do the real work.
1328 CordbThread * pThread = static_cast<CordbThread *>(m_pThread.GetValue());
1329 pStackWalkInfo->m_fHasConvertedFrame = (TRUE == pThread->ConvertFrameForILMethodWithoutMetadata(
1331 &(pStackWalkInfo->m_pConvertedInternalFrame2)));
1333 return pStackWalkInfo->HasConvertedFrame();
1336 // ----------------------------------------------------------------------------
1337 // ShimStackWalk::TrackUMChain
1340 // Keep track of enter-unmanaged chains. Extend or cancel the chain as necesasry.
1343 // * pChainInfo - information on the current chain we are tracking
1344 // * pStackWalkInfo - information regarding the current stackwalk
1347 // * This logic is based on code:TrackUMChain on the LS.
1350 void ShimStackWalk::TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo)
1352 if (!pChainInfo->IsTrackingUMChain())
1354 if (pStackWalkInfo->m_fProcessingInternalFrame)
1356 if (pStackWalkInfo->m_internalFrameType == STUBFRAME_M2U)
1358 // If we hit an M2U frame out in the wild, convert it to an enter-unmanaged chain.
1360 // We can't hit an M2U frame without hitting a native stack frame
1361 // first (we filter those). We should have already saved the CONTEXT.
1362 // So just update the chain reason.
1363 pChainInfo->m_reason = CHAIN_ENTER_UNMANAGED;
1368 BOOL fCreateUMChain = FALSE;
1369 if (pChainInfo->IsTrackingUMChain())
1371 if (pStackWalkInfo->m_fProcessingInternalFrame)
1373 // Extend the root end of the unmanaged chain.
1374 pChainInfo->m_rootFP = GetFramePointerForChain(pStackWalkInfo->GetCurrentInternalFrame());
1376 // Sometimes we may not want to show an UM chain b/c we know it's just
1377 // code inside of mscorwks. (Eg: Funcevals & AD transitions both fall into this category).
1378 // These are perfectly valid UM chains and we could give them if we wanted to.
1379 if ((pStackWalkInfo->m_internalFrameType == STUBFRAME_APPDOMAIN_TRANSITION) ||
1380 (pStackWalkInfo->m_internalFrameType == STUBFRAME_FUNC_EVAL))
1382 pChainInfo->CancelUMChain();
1384 else if (pStackWalkInfo->m_internalFrameType == STUBFRAME_M2U)
1386 // If we hit an M2U frame, then go ahead and dispatch the UM chain now.
1387 // This will likely also be an exit frame.
1388 fCreateUMChain = TRUE;
1390 else if ((pStackWalkInfo->m_internalFrameType == STUBFRAME_CLASS_INIT) ||
1391 (pStackWalkInfo->m_internalFrameType == STUBFRAME_EXCEPTION) ||
1392 (pStackWalkInfo->m_internalFrameType == STUBFRAME_SECURITY) ||
1393 (pStackWalkInfo->m_internalFrameType == STUBFRAME_JIT_COMPILATION))
1395 fCreateUMChain = TRUE;
1400 // If we hit a managed stack frame when we are processing an unmanaged chain, then
1401 // the chain is done.
1402 fCreateUMChain = TRUE;
1408 // check whether we get any stack range
1409 _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid);
1410 FramePointer fpLeaf = GetFramePointerForChain(&(pChainInfo->m_leafNativeContext));
1412 // Don't bother creating an unmanaged chain if the stack range is empty.
1413 if (fpLeaf != pChainInfo->m_rootFP)
1415 AppendChain(pChainInfo, pStackWalkInfo);
1417 pChainInfo->CancelUMChain();
1421 BOOL ShimStackWalk::IsV3FrameType(CorDebugInternalFrameType type)
1423 // These frame types are either new in Arrowhead or not used in V2.
1424 if ((type == STUBFRAME_INTERNALCALL) ||
1425 (type == STUBFRAME_CLASS_INIT) ||
1426 (type == STUBFRAME_EXCEPTION) ||
1427 (type == STUBFRAME_SECURITY) ||
1428 (type == STUBFRAME_JIT_COMPILATION))
1438 // Check whether a stack frame is for a dynamic method. The way to tell is if the stack frame has
1439 // an ICDNativeFrame but no ICDILFrame.
1440 BOOL ShimStackWalk::IsILFrameWithoutMetadata(ICorDebugFrame * pFrame)
1442 HRESULT hr = E_FAIL;
1444 RSExtSmartPtr<ICorDebugNativeFrame> pNativeFrame;
1445 hr = pFrame->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pNativeFrame));
1448 if (pNativeFrame != NULL)
1450 RSExtSmartPtr<ICorDebugILFrame> pILFrame;
1451 hr = pFrame->QueryInterface(IID_ICorDebugILFrame, reinterpret_cast<void **>(&pILFrame));
1453 if (FAILED(hr) || (pILFrame == NULL))
1462 ShimStackWalk::StackWalkInfo::StackWalkInfo()
1465 m_firstFrameInChain(0),
1466 m_cInternalFrames(0),
1467 m_curInternalFrame(0),
1468 m_internalFrameType(STUBFRAME_NONE),
1469 m_fExhaustedAllStackFrames(false),
1470 m_fProcessingInternalFrame(false),
1471 m_fSkipChain(false),
1473 m_fHasConvertedFrame(false)
1475 m_pChildFrame.Assign(NULL);
1476 m_pConvertedInternalFrame2.Assign(NULL);
1479 ShimStackWalk::StackWalkInfo::~StackWalkInfo()
1481 if (m_pChildFrame != NULL)
1483 m_pChildFrame.Clear();
1486 if (m_pConvertedInternalFrame2 != NULL)
1488 m_pConvertedInternalFrame2.Clear();
1491 if (!m_ppInternalFrame2.IsEmpty())
1493 m_ppInternalFrame2.Clear();
1497 void ShimStackWalk::StackWalkInfo::ResetForNextFrame()
1499 m_pConvertedInternalFrame2.Clear();
1500 m_internalFrameType = STUBFRAME_NONE;
1501 m_fProcessingInternalFrame = false;
1502 m_fSkipChain = false;
1503 m_fHasConvertedFrame = false;
1506 // Check whether we have exhausted both internal frames and stack frames.
1507 bool ShimStackWalk::StackWalkInfo::ExhaustedAllFrames()
1509 return (ExhaustedAllStackFrames() && ExhaustedAllInternalFrames());
1512 bool ShimStackWalk::StackWalkInfo::ExhaustedAllStackFrames()
1514 return m_fExhaustedAllStackFrames;
1517 bool ShimStackWalk::StackWalkInfo::ExhaustedAllInternalFrames()
1519 return (m_curInternalFrame == m_cInternalFrames);
1522 ICorDebugInternalFrame2 * ShimStackWalk::StackWalkInfo::GetCurrentInternalFrame()
1524 _ASSERTE(!ExhaustedAllInternalFrames() || HasConvertedFrame());
1526 if (HasConvertedFrame())
1528 return m_pConvertedInternalFrame2;
1532 return m_ppInternalFrame2[m_curInternalFrame];
1536 BOOL ShimStackWalk::StackWalkInfo::IsLeafFrame()
1538 return m_fLeafFrame;
1541 BOOL ShimStackWalk::StackWalkInfo::IsSkippingFrame()
1543 return (m_pChildFrame != NULL);
1546 BOOL ShimStackWalk::StackWalkInfo::HasConvertedFrame()
1548 return m_fHasConvertedFrame;
1552 ShimChain::ShimChain(ShimStackWalk * pSW,
1553 DT_CONTEXT * pContext,
1554 FramePointer fpRoot,
1556 UINT32 frameStartIndex,
1557 UINT32 frameEndIndex,
1558 CorDebugChainReason chainReason,
1561 : m_context(*pContext),
1565 m_chainIndex(chainIndex),
1566 m_frameStartIndex(frameStartIndex),
1567 m_frameEndIndex(frameEndIndex),
1568 m_chainReason(chainReason),
1569 m_fIsManaged(fIsManaged),
1570 m_fIsNeutered(FALSE),
1571 m_pShimLock(pShimLock)
1575 ShimChain::~ShimChain()
1577 _ASSERTE(IsNeutered());
1580 void ShimChain::Neuter()
1582 m_fIsNeutered = TRUE;
1585 BOOL ShimChain::IsNeutered()
1587 return m_fIsNeutered;
1590 ULONG STDMETHODCALLTYPE ShimChain::AddRef()
1592 return InterlockedIncrement((LONG *)&m_refCount);
1595 ULONG STDMETHODCALLTYPE ShimChain::Release()
1597 LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
1598 _ASSERTE(newRefCount >= 0);
1600 if (newRefCount == 0)
1607 HRESULT ShimChain::QueryInterface(REFIID id, void ** pInterface)
1609 if (id == IID_ICorDebugChain)
1611 *pInterface = static_cast<ICorDebugChain *>(this);
1613 else if (id == IID_IUnknown)
1615 *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugChain *>(this));
1620 return E_NOINTERFACE;
1627 // Returns the thread to which this chain belongs.
1628 HRESULT ShimChain::GetThread(ICorDebugThread ** ppThread)
1630 RSLockHolder lockHolder(m_pShimLock);
1631 FAIL_IF_NEUTERED(this);
1632 VALIDATE_POINTER_TO_OBJECT(ppThread, ICorDebugThread **);
1634 *ppThread = m_pStackWalk->GetThread();
1635 (*ppThread)->AddRef();
1640 // Get the range on the stack that this chain matches against.
1641 // pStart is the leafmost; pEnd is the rootmost.
1642 // This is particularly used in interop-debugging to get native stack traces
1643 // for the UM portions of the stack
1644 HRESULT ShimChain::GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd)
1649 THROW_IF_NEUTERED(this);
1651 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pStart, CORDB_ADDRESS *);
1652 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pEnd, CORDB_ADDRESS *);
1654 // Return the leafmost end of the stack range.
1655 // The leafmost end is represented by the register set.
1658 *pStart = PTR_TO_CORDB_ADDRESS(CORDbgGetSP(&m_context));
1661 // Return the rootmost end of the stack range. It is represented by the frame pointer of the chain.
1664 *pEnd = PTR_TO_CORDB_ADDRESS(m_fpRoot.GetSPValue());
1667 EX_CATCH_HRESULT(hr);
1671 HRESULT ShimChain::GetContext(ICorDebugContext ** ppContext)
1676 // Return the next chain which is closer to the root.
1677 // Currently this is just a wrapper over GetNext().
1678 HRESULT ShimChain::GetCaller(ICorDebugChain ** ppChain)
1680 RSLockHolder lockHolder(m_pShimLock);
1681 FAIL_IF_NEUTERED(this);
1682 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1684 return GetNext(ppChain);
1687 // Return the previous chain which is closer to the leaf.
1688 // Currently this is just a wrapper over GetPrevious().
1689 HRESULT ShimChain::GetCallee(ICorDebugChain ** ppChain)
1691 RSLockHolder lockHolder(m_pShimLock);
1692 FAIL_IF_NEUTERED(this);
1693 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1695 return GetPrevious(ppChain);
1698 // Return the previous chain which is closer to the leaf.
1699 HRESULT ShimChain::GetPrevious(ICorDebugChain ** ppChain)
1701 RSLockHolder lockHolder(m_pShimLock);
1702 FAIL_IF_NEUTERED(this);
1703 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1706 if (m_chainIndex != 0)
1708 *ppChain = m_pStackWalk->GetChain(m_chainIndex - 1);
1711 if (*ppChain != NULL)
1713 (*ppChain)->AddRef();
1719 // Return the next chain which is closer to the root.
1720 HRESULT ShimChain::GetNext(ICorDebugChain ** ppChain)
1722 RSLockHolder lockHolder(m_pShimLock);
1723 FAIL_IF_NEUTERED(this);
1724 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1726 *ppChain = m_pStackWalk->GetChain(m_chainIndex + 1);
1727 if (*ppChain != NULL)
1729 (*ppChain)->AddRef();
1735 // Return whether the chain contains frames running managed code.
1736 HRESULT ShimChain::IsManaged(BOOL * pManaged)
1738 RSLockHolder lockHolder(m_pShimLock);
1739 FAIL_IF_NEUTERED(this);
1740 VALIDATE_POINTER_TO_OBJECT(pManaged, BOOL *);
1742 *pManaged = m_fIsManaged;
1747 // Return an enumerator to iterate through the frames contained in this chain.
1748 HRESULT ShimChain::EnumerateFrames(ICorDebugFrameEnum ** ppFrames)
1750 RSLockHolder lockHolder(m_pShimLock);
1751 FAIL_IF_NEUTERED(this);
1752 VALIDATE_POINTER_TO_OBJECT(ppFrames, ICorDebugFrameEnum **);
1757 ShimStackWalk * pSW = GetShimStackWalk();
1758 NewHolder<ShimFrameEnum> pFrameEnum(new ShimFrameEnum(pSW, this, m_frameStartIndex, m_frameEndIndex, m_pShimLock));
1760 *ppFrames = pFrameEnum;
1761 (*ppFrames)->AddRef();
1763 // link the new ShimFramEnum into the list on the ShimStackWalk
1764 pSW->AddFrameEnum(pFrameEnum);
1766 pFrameEnum.SuppressRelease();
1768 EX_CATCH_HRESULT(hr);
1773 // Return an enumerator to iterate through the frames contained in this chain.
1774 // Note that this function will only succeed if the cached stack trace is valid.
1775 HRESULT ShimChain::GetActiveFrame(ICorDebugFrame ** ppFrame)
1777 RSLockHolder lockHolder(m_pShimLock);
1778 FAIL_IF_NEUTERED(this);
1779 VALIDATE_POINTER_TO_OBJECT(ppFrame, ICorDebugFrame **);
1784 // Chains may be empty, so they have no active frame.
1785 if (m_frameStartIndex == m_frameEndIndex)
1791 *ppFrame = m_pStackWalk->GetFrame(m_frameStartIndex);
1792 (*ppFrame)->AddRef();
1798 // Return the register set of the leaf end of the chain
1799 HRESULT ShimChain::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters)
1801 FAIL_IF_NEUTERED(this);
1802 VALIDATE_POINTER_TO_OBJECT(ppRegisters, ICorDebugRegisterSet **);
1807 CordbThread * pThread = static_cast<CordbThread *>(m_pStackWalk->GetThread());
1809 // This is a private hook for calling back into the RS. Alternatively, we could have created a
1810 // ShimRegisterSet, but that's too much work for now.
1811 pThread->CreateCordbRegisterSet(&m_context,
1812 (m_chainIndex == 0),
1816 EX_CATCH_HRESULT(hr);
1820 // Return the chain reason
1821 HRESULT ShimChain::GetReason(CorDebugChainReason * pReason)
1823 RSLockHolder lockHolder(m_pShimLock);
1824 FAIL_IF_NEUTERED(this);
1825 VALIDATE_POINTER_TO_OBJECT(pReason, CorDebugChainReason *);
1827 *pReason = m_chainReason;
1832 ShimStackWalk * ShimChain::GetShimStackWalk()
1834 return m_pStackWalk;
1837 UINT32 ShimChain::GetFirstFrameIndex()
1839 return this->m_frameStartIndex;
1842 UINT32 ShimChain::GetLastFrameIndex()
1844 return this->m_frameEndIndex;
1848 ShimChainEnum::ShimChainEnum(ShimStackWalk * pSW, RSLock * pShimLock)
1849 : m_pStackWalk(pSW),
1851 m_currentChainIndex(0),
1853 m_fIsNeutered(FALSE),
1854 m_pShimLock(pShimLock)
1858 ShimChainEnum::~ShimChainEnum()
1860 _ASSERTE(IsNeutered());
1863 void ShimChainEnum::Neuter()
1870 m_fIsNeutered = TRUE;
1873 BOOL ShimChainEnum::IsNeutered()
1875 return m_fIsNeutered;
1879 ULONG STDMETHODCALLTYPE ShimChainEnum::AddRef()
1881 return InterlockedIncrement((LONG *)&m_refCount);
1884 ULONG STDMETHODCALLTYPE ShimChainEnum::Release()
1886 LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
1887 _ASSERTE(newRefCount >= 0);
1889 if (newRefCount == 0)
1896 HRESULT ShimChainEnum::QueryInterface(REFIID id, void ** ppInterface)
1898 if (id == IID_ICorDebugChainEnum)
1900 *ppInterface = static_cast<ICorDebugChainEnum *>(this);
1902 else if (id == IID_ICorDebugEnum)
1904 *ppInterface = static_cast<ICorDebugEnum *>(static_cast<ICorDebugChainEnum *>(this));
1906 else if (id == IID_IUnknown)
1908 *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugChainEnum *>(this));
1912 *ppInterface = NULL;
1913 return E_NOINTERFACE;
1920 // Skip the specified number of chains.
1921 HRESULT ShimChainEnum::Skip(ULONG celt)
1923 RSLockHolder lockHolder(m_pShimLock);
1924 FAIL_IF_NEUTERED(this);
1926 // increment the index by the specified amount
1927 m_currentChainIndex += celt;
1931 HRESULT ShimChainEnum::Reset()
1933 m_currentChainIndex = 0;
1937 // Clone the chain enumerator and set the new one to the same current chain
1938 HRESULT ShimChainEnum::Clone(ICorDebugEnum ** ppEnum)
1940 RSLockHolder lockHolder(m_pShimLock);
1941 FAIL_IF_NEUTERED(this);
1942 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
1947 NewHolder<ShimChainEnum> pChainEnum(new ShimChainEnum(m_pStackWalk, m_pShimLock));
1949 // set the index in the new enumerator
1950 pChainEnum->m_currentChainIndex = this->m_currentChainIndex;
1952 *ppEnum = pChainEnum;
1953 (*ppEnum)->AddRef();
1954 m_pStackWalk->AddChainEnum(pChainEnum);
1956 pChainEnum.SuppressRelease();
1958 EX_CATCH_HRESULT(hr);
1962 // Return the number of chains on the thread
1963 HRESULT ShimChainEnum::GetCount(ULONG * pcChains)
1965 RSLockHolder lockHolder(m_pShimLock);
1966 FAIL_IF_NEUTERED(this);
1967 VALIDATE_POINTER_TO_OBJECT(pcChains, ULONG *);
1969 *pcChains = m_pStackWalk->GetChainCount();
1973 // Retrieve the next x number of chains on the thread into "chains", where x is specified by "celt".
1974 // "pcChainsFetched" is set to be the actual number of chains retrieved.
1975 // Return S_FALSE if the number of chains actually retrieved is less than the number of chains requested.
1976 HRESULT ShimChainEnum::Next(ULONG cChains, ICorDebugChain * rgpChains[], ULONG * pcChainsFetched)
1978 RSLockHolder lockHolder(m_pShimLock);
1979 FAIL_IF_NEUTERED(this);
1980 VALIDATE_POINTER_TO_OBJECT_ARRAY(rgpChains, ICorDebugChain *, cChains, true, true);
1981 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcChainsFetched, ULONG *);
1983 // if the out parameter is NULL, then we can only return one chain at a time
1984 if ((pcChainsFetched == NULL) && (cChains != 1))
1986 return E_INVALIDARG;
1989 // Check for the trivial case where no chain is actually requested.
1990 // This is probably a user error.
1993 if (pcChainsFetched != NULL)
1995 *pcChainsFetched = 0;
2000 ICorDebugChain ** ppCurrentChain = rgpChains;
2002 while ((m_currentChainIndex < m_pStackWalk->GetChainCount()) &&
2005 *ppCurrentChain = m_pStackWalk->GetChain(m_currentChainIndex);
2006 (*ppCurrentChain)->AddRef();
2008 ppCurrentChain++; // increment the pointer into the buffer
2009 m_currentChainIndex++; // increment the index
2013 // set the number of chains actually returned
2014 if (pcChainsFetched != NULL)
2016 *pcChainsFetched = (ULONG)(ppCurrentChain - rgpChains);
2020 // If we reached the end of the enumeration, but not the end
2021 // of the number of requested items, we return S_FALSE.
2031 ShimChainEnum * ShimChainEnum::GetNext()
2036 void ShimChainEnum::SetNext(ShimChainEnum * pNext)
2038 if (m_pNext != NULL)
2045 if (m_pNext != NULL)
2052 ShimFrameEnum::ShimFrameEnum(ShimStackWalk * pSW,
2054 UINT32 frameStartIndex,
2055 UINT32 frameEndIndex,
2057 : m_pStackWalk(pSW),
2059 m_pShimLock(pShimLock),
2061 m_currentFrameIndex(frameStartIndex),
2062 m_endFrameIndex(frameEndIndex),
2064 m_fIsNeutered(FALSE)
2068 ShimFrameEnum::~ShimFrameEnum()
2070 _ASSERTE(IsNeutered());
2073 void ShimFrameEnum::Neuter()
2080 m_fIsNeutered = TRUE;
2083 BOOL ShimFrameEnum::IsNeutered()
2085 return m_fIsNeutered;
2089 ULONG STDMETHODCALLTYPE ShimFrameEnum::AddRef()
2091 return InterlockedIncrement((LONG *)&m_refCount);
2094 ULONG STDMETHODCALLTYPE ShimFrameEnum::Release()
2096 LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
2097 _ASSERTE(newRefCount >= 0);
2099 if (newRefCount == 0)
2106 HRESULT ShimFrameEnum::QueryInterface(REFIID id, void ** ppInterface)
2108 if (id == IID_ICorDebugFrameEnum)
2110 *ppInterface = static_cast<ICorDebugFrameEnum *>(this);
2112 else if (id == IID_ICorDebugEnum)
2114 *ppInterface = static_cast<ICorDebugEnum *>(static_cast<ICorDebugFrameEnum *>(this));
2116 else if (id == IID_IUnknown)
2118 *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugFrameEnum *>(this));
2122 *ppInterface = NULL;
2123 return E_NOINTERFACE;
2130 // Skip the specified number of chains.
2131 HRESULT ShimFrameEnum::Skip(ULONG celt)
2133 RSLockHolder lockHolder(m_pShimLock);
2134 FAIL_IF_NEUTERED(this);
2136 // increment the index by the specified amount
2137 m_currentFrameIndex += celt;
2141 HRESULT ShimFrameEnum::Reset()
2143 RSLockHolder lockHolder(m_pShimLock);
2144 FAIL_IF_NEUTERED(this);
2146 m_currentFrameIndex = m_pChain->GetFirstFrameIndex();
2150 // Clone the chain enumerator and set the new one to the same current chain
2151 HRESULT ShimFrameEnum::Clone(ICorDebugEnum ** ppEnum)
2153 RSLockHolder lockHolder(m_pShimLock);
2154 FAIL_IF_NEUTERED(this);
2155 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
2160 NewHolder<ShimFrameEnum> pFrameEnum(new ShimFrameEnum(m_pStackWalk,
2162 m_currentFrameIndex,
2166 *ppEnum = pFrameEnum;
2167 (*ppEnum)->AddRef();
2168 m_pStackWalk->AddFrameEnum(pFrameEnum);
2170 pFrameEnum.SuppressRelease();
2172 EX_CATCH_HRESULT(hr);
2177 // Return the number of chains on the thread
2178 HRESULT ShimFrameEnum::GetCount(ULONG * pcFrames)
2180 RSLockHolder lockHolder(m_pShimLock);
2181 FAIL_IF_NEUTERED(this);
2182 VALIDATE_POINTER_TO_OBJECT(pcFrames, ULONG *);
2184 *pcFrames = m_pChain->GetLastFrameIndex() - m_pChain->GetFirstFrameIndex();
2188 // Retrieve the next x number of chains on the thread into "chains", where x is specified by "celt".
2189 // "pcChainsFetched" is set to be the actual number of chains retrieved.
2190 // Return S_FALSE if the number of chains actually retrieved is less than the number of chains requested.
2191 HRESULT ShimFrameEnum::Next(ULONG cFrames, ICorDebugFrame * rgpFrames[], ULONG * pcFramesFetched)
2193 RSLockHolder lockHolder(m_pShimLock);
2194 FAIL_IF_NEUTERED(this);
2195 VALIDATE_POINTER_TO_OBJECT_ARRAY(rgpFrames, ICorDebugFrame *, cFrames, true, true);
2196 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcFramesFetched, ULONG *);
2198 // if the out parameter is NULL, then we can only return one chain at a time
2199 if ((pcFramesFetched == NULL) && (cFrames != 1))
2201 return E_INVALIDARG;
2204 // Check for the trivial case where no chain is actually requested.
2205 // This is probably a user error.
2208 if (pcFramesFetched != NULL)
2210 *pcFramesFetched = 0;
2215 ICorDebugFrame ** ppCurrentFrame = rgpFrames;
2217 while ((m_currentFrameIndex < m_endFrameIndex) &&
2220 *ppCurrentFrame = m_pStackWalk->GetFrame(m_currentFrameIndex);
2221 (*ppCurrentFrame)->AddRef();
2223 ppCurrentFrame++; // increment the pointer into the buffer
2224 m_currentFrameIndex++; // increment the index
2228 // set the number of chains actually returned
2229 if (pcFramesFetched != NULL)
2231 *pcFramesFetched = (ULONG)(ppCurrentFrame - rgpFrames);
2235 // If we reached the end of the enumeration, but not the end
2236 // of the number of requested items, we return S_FALSE.
2246 ShimFrameEnum * ShimFrameEnum::GetNext()
2251 void ShimFrameEnum::SetNext(ShimFrameEnum * pNext)
2253 if (m_pNext != NULL)
2260 if (m_pNext != NULL)