Merge pull request #10656 from hseok-oh/ryujit/fix_10654
[platform/upstream/coreclr.git] / src / debug / di / shimstackwalk.cpp
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.
4 //
5 // ShimStackWalk.cpp
6 // 
7
8 //
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.
12 // 
13 // ======================================================================================
14
15 #include "stdafx.h"
16 #include "primitives.h"
17
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;
24 #endif
25
26 ShimStackWalk::ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread)
27   : m_pChainEnumList(NULL),
28     m_pFrameEnumList(NULL)
29 {
30     // The following assignments increment the ref count.
31     m_pProcess.Assign(pProcess);
32     m_pThread.Assign(pThread);
33
34     Populate();
35 }
36
37 ShimStackWalk::~ShimStackWalk()
38 {
39     Clear();
40 }
41
42 // ----------------------------------------------------------------------------
43 // ShimStackWalk::Clear
44 //
45 // Description: 
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.
48 //
49
50 void ShimStackWalk::Clear()
51 {
52     // call Release() on each of the ShimChains
53     for (int i = 0; i < m_stackChains.Count(); i++)
54     {
55         (*m_stackChains.Get(i))->Neuter();
56         (*m_stackChains.Get(i))->Release();
57     }
58     m_stackChains.Clear();
59
60     // call Release() on each of the ICDFrames
61     for (int i = 0; i < m_stackFrames.Count(); i++)
62     {
63         (*m_stackFrames.Get(i))->Release();
64     }
65     m_stackFrames.Clear();
66
67     // call Release() on each of the ShimChainEnums
68     while (m_pChainEnumList != NULL)
69     {
70         ShimChainEnum * pCur =  m_pChainEnumList;
71         m_pChainEnumList = m_pChainEnumList->GetNext();
72         pCur->Neuter();
73         pCur->Release();
74     }
75
76     // call Release() on each of the ShimFrameEnums
77     while (m_pFrameEnumList != NULL)
78     {
79         ShimFrameEnum * pCur =  m_pFrameEnumList;
80         m_pFrameEnumList = m_pFrameEnumList->GetNext();
81         pCur->Neuter();
82         pCur->Release();
83     }
84
85     // release the references
86     m_pProcess.Clear();
87     m_pThread.Clear();
88 }
89
90 //---------------------------------------------------------------------------------------
91 //
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).
96 // 
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.
101 //
102 // Arguments:
103 //    pswInfo - StackWalkInfo representing the frame in question
104 //
105 // Return Value:
106 //     nonzero iff the chain should be tracked
107 //
108
109 BOOL ShimStackWalk::ShouldTrackUMChain(StackWalkInfo * pswInfo)
110 {
111     _ASSERTE (pswInfo != NULL);
112     
113     // Always track chains for non-leaf UM frames
114     if (!pswInfo->IsLeafFrame())
115         return TRUE;
116
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.
119
120     CorDebugUserState threadUserState;
121     HRESULT hr = m_pThread->GetUserState(&threadUserState);
122     IfFailThrow(hr);
123
124     // ShouldSendUMLeafChain checked IsInWaitSleepJoin which is just USER_WAIT_SLEEP_JOIN
125     if ((threadUserState & USER_WAIT_SLEEP_JOIN) != 0)
126         return FALSE;
127
128     // This check is the same as Thread::IsUnstarted() from ShouldSendUMLeafChain
129     if ((threadUserState & USER_UNSTARTED) != 0)
130         return FALSE;
131     
132     // This check is the same as Thread::IsDead() from ShouldSendUMLeafChain
133     if ((threadUserState & USER_STOPPED) != 0)
134         return FALSE;
135
136     // #DacShimSwWorkAround
137     // 
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.
142     // 
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
150     // Whidbey.
151     if (m_pProcess->IsThreadSuspendedOrHijacked(m_pThread))
152         return FALSE;
153
154     return TRUE;
155 }
156
157 // ----------------------------------------------------------------------------
158 // ShimStackWalk::Populate
159 //
160 // Description: 
161 //    Walk the entire stack and populate the arrays of stack frames and stack chains.
162 //
163
164 void ShimStackWalk::Populate()
165 {
166     HRESULT hr = S_OK;
167
168     // query for the ICDThread3 interface
169     RSExtSmartPtr<ICorDebugThread3> pThread3;
170     hr = m_pThread->QueryInterface(IID_ICorDebugThread3, reinterpret_cast<void **>(&pThread3));
171     IfFailThrow(hr);
172
173     // create the ICDStackWalk
174     RSExtSmartPtr<ICorDebugStackWalk> pSW;
175     hr = pThread3->CreateStackWalk(&pSW);
176     IfFailThrow(hr);
177
178     // structs used to store information during the stackwalk
179     ChainInfo     chainInfo;
180     StackWalkInfo swInfo;
181
182     // use the ICDStackWalk to retrieve the internal frames
183     hr = pThread3->GetActiveInternalFrames(0, &(swInfo.m_cInternalFrames), NULL);
184     IfFailThrow(hr);
185
186     // allocate memory for the internal frames
187     if (swInfo.m_cInternalFrames > 0)
188     {
189         // allocate memory for the array of RSExtSmartPtrs
190         swInfo.m_ppInternalFrame2.AllocOrThrow(swInfo.m_cInternalFrames);
191
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), 
196                                                pTmpArray);
197         IfFailThrow(hr);
198
199         // transfer the raw array to the RSExtSmartPtr array
200         for (UINT32 i = 0; i < swInfo.m_cInternalFrames; i++)
201         {
202             // Assign() increments the ref count
203             swInfo.m_ppInternalFrame2.Assign(i, pTmpArray[i]);
204             pTmpArray[i]->Release();
205         }
206         pTmpArray.Clear();
207     }
208
209     //
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
213     //         the parent frame.
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.
219     // 
220     while (true)
221     {
222         // reset variables used in the loop
223         swInfo.ResetForNextFrame();
224
225         // retrieve the next stack frame if it's available
226         RSExtSmartPtr<ICorDebugFrame> pFrame;
227         if (!swInfo.ExhaustedAllStackFrames())
228         {
229             hr = pSW->GetFrame(&pFrame);
230             IfFailThrow(hr);
231         }
232
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())
237         {
238             // prefetch the internal frame type
239             if (!swInfo.ExhaustedAllInternalFrames())
240             {
241                 swInfo.m_internalFrameType = GetInternalFrameType(swInfo.GetCurrentInternalFrame());
242             }
243
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())
247             {
248                 swInfo.m_fProcessingInternalFrame = true;
249             }
250             else if (swInfo.ExhaustedAllInternalFrames())
251             {
252                 swInfo.m_fProcessingInternalFrame = false;
253             }
254             else
255             {
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);
258             }
259
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())
263             {
264                 if (!swInfo.m_fProcessingInternalFrame)
265                 {
266                     // Check whether we have reached the parent frame yet.
267                     RSExtSmartPtr<ICorDebugNativeFrame2> pNFrame2;
268                     hr = pFrame->QueryInterface(IID_ICorDebugNativeFrame2, reinterpret_cast<void **>(&pNFrame2));
269                     IfFailThrow(hr);
270
271                     BOOL fIsParent = FALSE;
272                     hr = swInfo.m_pChildFrame->IsMatchingParentFrame(pNFrame2, &fIsParent);
273                     IfFailThrow(hr);
274
275                     if (fIsParent)
276                     {
277                         swInfo.m_pChildFrame.Clear();
278                     }
279                 }
280             }
281             else if(swInfo.m_fProcessingInternalFrame && !chainInfo.m_fLeafNativeContextIsValid &&
282                 swInfo.m_internalFrameType == STUBFRAME_M2U)
283             {
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
292                 // will always face
293             }
294             else
295             {
296                 // Don't add any frame just yet.  We need to deal with any unmanaged chain 
297                 // we are tracking first.
298
299                 // track the current enter-unmanaged chain and/or enter-managed chain
300                 TrackUMChain(&chainInfo, &swInfo);
301
302                 if (swInfo.m_fProcessingInternalFrame)
303                 {
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 
307                     // frames.
308                     if (swInfo.IsLeafFrame())
309                     {
310                         if (swInfo.m_internalFrameType == STUBFRAME_EXCEPTION)
311                         {
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;
316                         }
317                     }
318
319                     _ASSERTE(!swInfo.IsSkippingFrame());
320                     if (ConvertInternalFrameToDynamicMethod(&swInfo))
321                     {
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;
326
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)
330                         {
331                             AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
332                         }
333                     }
334                     else
335                     {
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))
339                         {
340                             AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
341                         }
342                     }
343                 }
344                 else
345                 {
346                     if (!chainInfo.m_fNeedEnterManagedChain)
347                     {
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;
352                     }
353
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))
358                     {
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)
364                         {
365                             AppendFrame(swInfo.GetCurrentInternalFrame(), &swInfo);
366                         }
367                     }
368                     else
369                     {
370                         AppendFrame(pFrame, &swInfo);
371                     }
372
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));
377                     IfFailThrow(hr);
378
379                     if (pNFrame2 != NULL)
380                     {
381                         BOOL fIsChild = FALSE;
382                         hr = pNFrame2->IsChild(&fIsChild);
383                         IfFailThrow(hr);
384
385                         if (fIsChild)
386                         {
387                             swInfo.m_pChildFrame.Assign(pNFrame2);
388                         }
389                     }
390                 }
391             }
392         }  // process the current frame (managed stack frame or internal frame)
393
394         // We can take care of other types of chains here, but only do so if we are not currently skipping 
395         // child frames.
396         if (!swInfo.IsSkippingFrame())
397         {
398             if ((pFrame == NULL) && 
399                 !swInfo.ExhaustedAllStackFrames())
400             { 
401                 // We are here because we are processing a native marker stack frame, not because
402                 // we have exhausted all the stack frames.
403
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;
407
408                 // begin tracking UM chain if we're supposed to
409                 if (ShouldTrackUMChain(&swInfo)) 
410                 {
411                     chainInfo.m_reason = CHAIN_ENTER_UNMANAGED;
412                 }
413             }
414             else
415             {
416                 // handle other types of chains
417                 if (swInfo.m_fProcessingInternalFrame)
418                 {
419                     if (!swInfo.m_fSkipChain)
420                     {
421                         BOOL fNewChain = FALSE;
422
423                         switch (swInfo.m_internalFrameType)
424                         {
425                             case STUBFRAME_M2U:                     // fall through
426                             case STUBFRAME_U2M:                     // fall through
427                                 // These frame types are tracked specially.
428                                 break;
429
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.
434                                 break;
435
436                             case STUBFRAME_FUNC_EVAL:
437                                 chainInfo.m_reason = CHAIN_FUNC_EVAL;
438                                 fNewChain = TRUE;
439                                 break;
440
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;
445                                 fNewChain = TRUE;
446                                 break;
447
448                             case STUBFRAME_EXCEPTION:
449                                 chainInfo.m_reason = CHAIN_EXCEPTION_FILTER;
450                                 fNewChain = TRUE;
451                                 break;
452
453                             case STUBFRAME_SECURITY:
454                                 chainInfo.m_reason = CHAIN_SECURITY;
455                                 fNewChain = TRUE;
456                                 break;
457
458                             default:
459                                 // We can only reach this case if we have converted an IL stub to NULL.
460                                 _ASSERTE(swInfo.HasConvertedFrame());
461                                 break;
462                         }
463
464                         if (fNewChain)
465                         {
466                             chainInfo.m_rootFP = GetFramePointerForChain(swInfo.GetCurrentInternalFrame());
467                             AppendChain(&chainInfo, &swInfo);
468                         }
469                     }
470                 } // chain handling for an internl frame
471             } // chain handling for a managed stack frame or an internal frame
472         } // chain handling
473
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())
477         {
478             if (swInfo.m_fProcessingInternalFrame || (pFrame != NULL))
479             {
480                 swInfo.m_fLeafFrame = false;
481             }
482         }
483
484         // advance to the next frame
485         if (swInfo.m_fProcessingInternalFrame)
486         {
487             swInfo.m_curInternalFrame += 1;
488         }
489         else
490         {
491             hr = pSW->Next();
492             IfFailThrow(hr);
493
494             // check for the end of stack condition
495             if (hr == CORDBG_S_AT_END_OF_STACK)
496             {
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());
500
501                 swInfo.m_fExhaustedAllStackFrames = true;
502             }
503         }
504
505         // Break out of the loop if we have exhausted all the frames.
506         if (swInfo.ExhaustedAllFrames())
507         {
508             break;
509         }
510     }
511
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);
516 }
517
518 // the caller is responsible for addref and release
519 ICorDebugThread * ShimStackWalk::GetThread()
520 {
521     return m_pThread;
522 }
523
524 // the caller is responsible for addref and release
525 ShimChain * ShimStackWalk::GetChain(UINT32 index)
526 {
527     if (index >= (UINT32)(m_stackChains.Count()))
528     {
529         return NULL;
530     }
531     else
532     {
533         return *(m_stackChains.Get((int)index));
534     }
535 }
536
537 // the caller is responsible for addref and release
538 ICorDebugFrame * ShimStackWalk::GetFrame(UINT32 index)
539 {
540     if (index >= (UINT32)(m_stackFrames.Count()))
541     {
542         return NULL;
543     }
544     else
545     {
546         return *(m_stackFrames.Get((int)index));
547     }
548 }
549
550 ULONG ShimStackWalk::GetChainCount()
551 {
552     return m_stackChains.Count();
553 }
554
555 ULONG ShimStackWalk::GetFrameCount()
556 {
557     return m_stackFrames.Count();
558 }
559
560 RSLock * ShimStackWalk::GetShimLock()
561 {
562     return m_pProcess->GetShimLock();
563 }
564
565
566 // ----------------------------------------------------------------------------
567 // ShimStackWalk::AddChainEnum
568 //
569 // Description: 
570 //    Add the specified ShimChainEnum to the head of the linked list of ShimChainEnums on the ShimStackWalk.
571 //
572 // Arguments:
573 //    * pChainEnum - the ShimChainEnum to be added
574 //
575
576 void ShimStackWalk::AddChainEnum(ShimChainEnum * pChainEnum)
577 {
578     pChainEnum->SetNext(m_pChainEnumList);
579     if (m_pChainEnumList != NULL)
580     {
581         m_pChainEnumList->Release();
582     }
583
584     m_pChainEnumList = pChainEnum;
585     if (m_pChainEnumList != NULL)
586     {
587         m_pChainEnumList->AddRef();
588     }
589 }
590
591 // ----------------------------------------------------------------------------
592 // ShimStackWalk::AddFrameEnum
593 //
594 // Description: 
595 //    Add the specified ShimFrameEnum to the head of the linked list of ShimFrameEnums on the ShimStackWalk.
596 //
597 // Arguments:
598 //    * pFrameEnum - the ShimFrameEnum to be added
599 //
600
601 void ShimStackWalk::AddFrameEnum(ShimFrameEnum * pFrameEnum)
602 {
603     pFrameEnum->SetNext(m_pFrameEnumList);
604     if (m_pFrameEnumList != NULL)
605     {
606         m_pFrameEnumList->Release();
607     }
608
609     m_pFrameEnumList = pFrameEnum;
610     if (m_pFrameEnumList != NULL)
611     {
612         m_pFrameEnumList->AddRef();
613     }
614 }
615
616 // Return the ICDThread associated with the current ShimStackWalk as a key for ShimStackWalkHashTableTraits.
617 ICorDebugThread * ShimStackWalk::GetKey()
618 {
619     return m_pThread;
620 }
621
622 // Hash a given ICDThread, which is used as the key for ShimStackWalkHashTableTraits.
623 //static 
624 UINT32 ShimStackWalk::Hash(ICorDebugThread * pThread)
625 {
626     // just return the pointer value
627     return (UINT32)(size_t)pThread;
628 }
629
630 // ----------------------------------------------------------------------------
631 // ShimStackWalk::IsLeafFrame
632 //
633 // Description: 
634 //    Check whether the specified frame is the leaf frame.
635 //
636 // Arguments:
637 //    * pFrame - frame to be checked
638 //
639 // Return Value:
640 //    Return TRUE if the specified frame is the leaf frame.
641 //    Return FALSE otherwise.
642 //
643 // Notes:
644 //    * The definition of the leaf frame in V2 is the frame at the leaf of the leaf chain.
645 //
646
647 BOOL ShimStackWalk::IsLeafFrame(ICorDebugFrame * pFrame)
648 {
649     // check if we have any chain
650     if (GetChainCount() > 0)
651     {
652         // check if the leaf chain has any frame
653         if (GetChain(0)->GetLastFrameIndex() > 0)
654         {
655             return IsSameFrame(pFrame, GetFrame(0));
656         }
657     }
658     return FALSE;
659 }
660
661 // ----------------------------------------------------------------------------
662 // ShimStackWalk::IsSameFrame
663 //
664 // Description: 
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.
668 //
669 // Arguments:
670 //    * pLeft  - frame to be compared
671 //    * pRight - frame to be compared
672 //
673 // Return Value:
674 //    Return TRUE if the two ICDFrames represent the same frame.
675 //
676
677 BOOL ShimStackWalk::IsSameFrame(ICorDebugFrame * pLeft, ICorDebugFrame * pRight)
678 {
679     HRESULT hr = E_FAIL;
680
681     // Quick check #1: If the pointers are the same then the two frames are the same (duh!).
682     if (pLeft == pRight)
683     {
684         return TRUE;
685     }
686
687     RSExtSmartPtr<ICorDebugNativeFrame> pLeftNativeFrame;
688     hr = pLeft->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pLeftNativeFrame));
689
690     if (SUCCEEDED(hr))
691     {
692         // The left frame is a stack frame.
693         RSExtSmartPtr<ICorDebugNativeFrame> pRightNativeFrame;
694         hr = pRight->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pRightNativeFrame));
695
696         if (FAILED(hr))
697         {
698             // The right frame is NOT a stack frame.
699             return FALSE;
700         }
701         else
702         {
703             // Quick check #2: If the IPs are different then the two frames are not the same (duh!).
704             ULONG32 leftOffset;
705             ULONG32 rightOffset;
706
707             hr = pLeftNativeFrame->GetIP(&leftOffset);
708             IfFailThrow(hr);
709
710             hr = pRightNativeFrame->GetIP(&rightOffset);
711             IfFailThrow(hr);
712
713             if (leftOffset != rightOffset)
714             {
715                 return FALSE;
716             }
717
718             // real check
719             CORDB_ADDRESS leftStart;
720             CORDB_ADDRESS leftEnd;
721             CORDB_ADDRESS rightStart;
722             CORDB_ADDRESS rightEnd;
723
724             hr = pLeftNativeFrame->GetStackRange(&leftStart, &leftEnd);
725             IfFailThrow(hr);
726
727             hr = pRightNativeFrame->GetStackRange(&rightStart, &rightEnd);
728             IfFailThrow(hr);
729
730             return ((leftStart == rightStart) && (leftEnd == rightEnd));
731         }
732     }
733     else
734     {
735         RSExtSmartPtr<ICorDebugInternalFrame2> pLeftInternalFrame2;
736         hr = pLeft->QueryInterface(IID_ICorDebugInternalFrame2, 
737                                    reinterpret_cast<void **>(&pLeftInternalFrame2));
738
739         if (SUCCEEDED(hr))
740         {
741             // The left frame is an internal frame.
742             RSExtSmartPtr<ICorDebugInternalFrame2> pRightInternalFrame2;
743             hr = pRight->QueryInterface(IID_ICorDebugInternalFrame2,  
744                                         reinterpret_cast<void **>(&pRightInternalFrame2));
745
746             if (FAILED(hr))
747             {
748                 return FALSE;
749             }
750             else
751             {
752                 // The right frame is also an internal frame.
753
754                 // Check the frame address.
755                 CORDB_ADDRESS leftFrameAddr;
756                 CORDB_ADDRESS rightFrameAddr;
757
758                 hr = pLeftInternalFrame2->GetAddress(&leftFrameAddr);
759                 IfFailThrow(hr);
760
761                 hr = pRightInternalFrame2->GetAddress(&rightFrameAddr);
762                 IfFailThrow(hr);
763
764                 return (leftFrameAddr == rightFrameAddr);
765             }
766         }
767
768         return FALSE;
769     }
770 }
771
772 // This is the shim implementation of ICDThread::EnumerateChains().
773 void ShimStackWalk::EnumerateChains(ICorDebugChainEnum ** ppChainEnum)
774 {
775     NewHolder<ShimChainEnum> pChainEnum(new ShimChainEnum(this, GetShimLock()));
776
777     *ppChainEnum = pChainEnum;
778     (*ppChainEnum)->AddRef();
779     AddChainEnum(pChainEnum);
780
781     pChainEnum.SuppressRelease();
782 }
783
784 // This is the shim implementation of ICDThread::GetActiveChain().
785 void ShimStackWalk::GetActiveChain(ICorDebugChain ** ppChain)
786 {
787     if (GetChainCount() == 0)
788     {
789         *ppChain = NULL;
790     }
791     else
792     {
793         *ppChain = static_cast<ICorDebugChain *>(GetChain(0));
794         (*ppChain)->AddRef();
795     }
796 }
797
798 // This is the shim implementation of ICDThread::GetActiveFrame().
799 void ShimStackWalk::GetActiveFrame(ICorDebugFrame ** ppFrame)
800 {
801     //
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.
805     //     
806     if ((GetFrameCount() == 0) ||
807         (GetChain(0)->GetLastFrameIndex() == 0))
808     {
809         *ppFrame = NULL;
810     }
811     else
812     {
813         *ppFrame = GetFrame(0);
814         (*ppFrame)->AddRef();
815     }
816 }
817
818 // This is the shim implementation of ICDThread::GetRegisterSet().
819 void ShimStackWalk::GetActiveRegisterSet(ICorDebugRegisterSet ** ppRegisterSet)
820 {
821     _ASSERTE(GetChainCount() != 0);
822     _ASSERTE(GetChain(0) != NULL);
823
824     // Return the register set of the leaf chain.
825     HRESULT hr = GetChain(0)->GetRegisterSet(ppRegisterSet);
826     IfFailThrow(hr);
827 }
828
829 // This is the shim implementation of ICDFrame::GetChain().
830 void ShimStackWalk::GetChainForFrame(ICorDebugFrame * pFrame, ICorDebugChain ** ppChain)
831 {
832     CORDB_ADDRESS frameStart;
833     CORDB_ADDRESS frameEnd;
834     IfFailThrow(pFrame->GetStackRange(&frameStart, &frameEnd));
835
836     for (UINT32 i = 0; i < GetChainCount(); i++)
837     {
838         ShimChain * pCurChain = GetChain(i);
839
840         CORDB_ADDRESS chainStart;
841         CORDB_ADDRESS chainEnd;
842         IfFailThrow(pCurChain->GetStackRange(&chainStart, &chainEnd));
843
844         if ((chainStart <= frameStart) && (frameEnd <= chainEnd))
845         {
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))
849             {
850                 ShimChain * pNextChain = GetChain(i + 1);
851
852                 CORDB_ADDRESS nextChainStart;
853                 CORDB_ADDRESS nextChainEnd;
854                 IfFailThrow(pNextChain->GetStackRange(&nextChainStart, &nextChainEnd));
855
856                 if ((nextChainStart <= frameStart) && (frameEnd <= nextChainEnd))
857                 {
858                     // The frame lies in the stack ranges of two chains.  This can only happn at the boundary.
859                     if (pCurChain->GetFirstFrameIndex() == pCurChain->GetLastFrameIndex())
860                     {
861                         // Make sure the next chain is not empty.
862                         _ASSERTE(pNextChain->GetFirstFrameIndex() != pNextChain->GetLastFrameIndex());
863
864                         // The current chain is empty, so the chain we want is the next one.
865                         pCurChain = pNextChain;
866                     }
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())
870                     {
871                         // Both chains are non-empty.
872                         if (IsSameFrame(GetFrame(pNextChain->GetFirstFrameIndex()), pFrame))
873                         {
874                             // The same frame cannot be in both chains.
875                             _ASSERTE(!IsSameFrame(GetFrame(pCurChain->GetLastFrameIndex() - 1), pFrame));
876                             pCurChain = pNextChain;
877                         }
878                         else
879                         {
880                             _ASSERTE(IsSameFrame(GetFrame(pCurChain->GetLastFrameIndex() - 1), pFrame));
881                         }
882                     }
883                 }
884             }
885
886             *ppChain = static_cast<ICorDebugChain *>(pCurChain);
887             (*ppChain)->AddRef();
888             return;
889         }
890     }
891 }
892
893 // This is the shim implementation of ICDFrame::GetCaller().
894 void ShimStackWalk::GetCallerForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCallerFrame)
895 {
896     for (UINT32 i = 0; i < GetChainCount(); i++)
897     {
898         ShimChain * pCurChain = GetChain(i);
899
900         for (UINT32 j = pCurChain->GetFirstFrameIndex(); j < pCurChain->GetLastFrameIndex(); j++)
901         {
902             if (IsSameFrame(GetFrame(j), pFrame))
903             {
904                 // Check whether this is the last frame in the chain.
905                 UINT32 callerFrameIndex = j + 1;
906                 if (callerFrameIndex < pCurChain->GetLastFrameIndex())
907                 {
908                     *ppCallerFrame = static_cast<ICorDebugFrame *>(GetFrame(callerFrameIndex));
909                     (*ppCallerFrame)->AddRef();
910                 }
911                 else
912                 {
913                     *ppCallerFrame = NULL;
914                 }
915                 return;
916             }
917         }
918     }
919 }
920
921 // This is the shim implementation of ICDFrame::GetCallee().
922 void ShimStackWalk::GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCalleeFrame)
923 {
924     for (UINT32 i = 0; i < GetChainCount(); i++)
925     {
926         ShimChain * pCurChain = GetChain(i);
927
928         for (UINT32 j = pCurChain->GetFirstFrameIndex(); j < pCurChain->GetLastFrameIndex(); j++)
929         {
930             if (IsSameFrame(GetFrame(j), pFrame))
931             {
932                 // Check whether this is the first frame in the chain.
933                 if (j > pCurChain->GetFirstFrameIndex())
934                 {
935                     UINT32 calleeFrameIndex = j - 1;
936                     *ppCalleeFrame = static_cast<ICorDebugFrame *>(GetFrame(calleeFrameIndex));
937                     (*ppCalleeFrame)->AddRef();
938                 }
939                 else
940                 {
941                     *ppCalleeFrame = NULL;
942                 }
943                 return;
944             }
945         }
946     }
947 }
948
949 FramePointer ShimStackWalk::GetFramePointerForChain(DT_CONTEXT * pContext)
950 {
951     return FramePointer::MakeFramePointer(CORDbgGetSP(pContext));
952 }
953
954 FramePointer ShimStackWalk::GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2)
955 {
956     CORDB_ADDRESS frameAddr;
957     HRESULT hr = pInternalFrame2->GetAddress(&frameAddr);
958     IfFailThrow(hr);
959
960     return FramePointer::MakeFramePointer(reinterpret_cast<void *>(frameAddr));
961 }
962
963 CorDebugInternalFrameType ShimStackWalk::GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2)
964 {
965     HRESULT hr = E_FAIL;
966
967     // Retrieve the frame type of the internal frame.
968     RSExtSmartPtr<ICorDebugInternalFrame> pFrame;
969     hr = pFrame2->QueryInterface(IID_ICorDebugInternalFrame, reinterpret_cast<void **>(&pFrame));
970     IfFailThrow(hr);
971
972     CorDebugInternalFrameType type;
973     hr = pFrame->GetFrameType(&type);
974     IfFailThrow(hr);
975
976     return type;
977 }
978
979 // ----------------------------------------------------------------------------
980 // ShimStackWalk::AppendFrame
981 //
982 // Description: 
983 //    Append the specified frame to the array and increment the counter.
984 //
985 // Arguments:
986 //    * pFrame         - the frame to be added
987 //    * pStackWalkInfo - contains information of the stackwalk
988 //
989
990 void ShimStackWalk::AppendFrame(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo)
991 {
992     // grow the 
993     ICorDebugFrame ** ppFrame = m_stackFrames.AppendThrowing();
994
995     // Be careful of the AddRef() below.  Once we do the addref, we need to save the pointer and 
996     // explicitly release it.
997     *ppFrame = pFrame;
998     (*ppFrame)->AddRef();
999
1000     pStackWalkInfo->m_cFrame += 1;
1001 }
1002
1003 // ----------------------------------------------------------------------------
1004 // Refer to comment of the overloaded function.
1005 //
1006
1007 void ShimStackWalk::AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, StackWalkInfo * pStackWalkInfo)
1008 {
1009     RSExtSmartPtr<ICorDebugFrame> pFrame;
1010     HRESULT hr = pInternalFrame2->QueryInterface(IID_ICorDebugFrame, reinterpret_cast<void **>(&pFrame));
1011     IfFailThrow(hr);
1012
1013     AppendFrame(pFrame, pStackWalkInfo);
1014 }
1015
1016 // ----------------------------------------------------------------------------
1017 // ShimStackWalk::AppendChainWorker
1018 //
1019 // Description: 
1020 //    Append the specified chain to the array.
1021 //
1022 // Arguments:
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
1028 //
1029
1030 void ShimStackWalk::AppendChainWorker(StackWalkInfo *     pStackWalkInfo,
1031                                       DT_CONTEXT *        pLeafContext,
1032                                       FramePointer        fpRoot,
1033                                       CorDebugChainReason chainReason,
1034                                       BOOL                fIsManagedChain)
1035 {
1036     // first, create the chain
1037     NewHolder<ShimChain> pChain(new ShimChain(this, 
1038                                               pLeafContext,
1039                                               fpRoot,
1040                                               pStackWalkInfo->m_cChain,
1041                                               pStackWalkInfo->m_firstFrameInChain, 
1042                                               pStackWalkInfo->m_cFrame, 
1043                                               chainReason,
1044                                               fIsManagedChain,
1045                                               GetShimLock()));
1046
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();
1050     *ppChain = pChain;
1051     (*ppChain)->AddRef();
1052
1053     // update the counters on the StackWalkInfo
1054     pStackWalkInfo->m_cChain += 1;
1055     pStackWalkInfo->m_firstFrameInChain = pStackWalkInfo->m_cFrame;
1056
1057     // If all goes well, suppress the release so that the ShimChain won't go away.
1058     pChain.SuppressRelease();
1059 }
1060
1061 // ----------------------------------------------------------------------------
1062 // ShimStackWalk::AppendChain
1063 //
1064 // Description: 
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.
1067 //
1068 // Arguments:
1069 //    * pChainInfo     - information on the chain to be added
1070 //    * pStackWalkInfo - information regarding the current stackwalk
1071 //    
1072
1073 void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo)
1074 {
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))
1081     {
1082         fManagedChain = TRUE;
1083     }
1084
1085     DT_CONTEXT * pChainContext = NULL;
1086     if (fManagedChain)
1087     {
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);
1091     }
1092     else
1093     {
1094         // The chain to be added is unmanaged.  Check if we need to send an enter-managed chain.
1095         if (pChainInfo->m_fNeedEnterManagedChain)
1096         {
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);
1105 #endif
1106             FramePointer fp = FramePointer::MakeFramePointer(sp);
1107
1108             AppendChainWorker(pStackWalkInfo, 
1109                               &(pChainInfo->m_leafManagedContext), 
1110                               fp, 
1111                               CHAIN_ENTER_MANAGED, 
1112                               TRUE);
1113             
1114             pChainInfo->m_fNeedEnterManagedChain = false;
1115         }
1116         _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid);
1117         pChainContext = &(pChainInfo->m_leafNativeContext);
1118     }
1119
1120     // Add the actual chain.
1121     AppendChainWorker(pStackWalkInfo, 
1122                       pChainContext,
1123                       pChainInfo->m_rootFP, 
1124                       pChainInfo->m_reason, 
1125                       fManagedChain);
1126 }
1127
1128 // ----------------------------------------------------------------------------
1129 // ShimStackWalk::SaveChainContext
1130 //
1131 // Description: 
1132 //    Save the current CONTEXT on the ICDStackWalk into the specified CONTEXT.  Also update the root end
1133 //    of the chain on the ChainInfo.
1134 //
1135 // Arguments:
1136 //    * pSW        - the ICDStackWalk for the current stackwalk
1137 //    * pChainInfo - the ChainInfo keeping track of the current chain
1138 //    * pContext   - the destination CONTEXT
1139 //
1140
1141 void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext)
1142 {
1143     HRESULT hr = pSW->GetContext(CONTEXT_FULL, 
1144                                  sizeof(*pContext),
1145                                  NULL, 
1146                                  reinterpret_cast<BYTE *>(pContext));
1147     IfFailThrow(hr);
1148
1149     pChainInfo->m_rootFP = GetFramePointerForChain(pContext);
1150 }
1151
1152 // ----------------------------------------------------------------------------
1153 // ShimStackWalk::CheckInternalFrame
1154 //
1155 // Description: 
1156 //    Check whether the next frame to be processed should be the next internal frame or the next stack frame.
1157 //
1158 // Arguments:
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
1163 //
1164 // Return Value:
1165 //    Return TRUE if we should process an internal frame next.
1166 //
1167
1168 BOOL ShimStackWalk::CheckInternalFrame(ICorDebugFrame *     pNextStackFrame,
1169                                        StackWalkInfo *      pStackWalkInfo,
1170                                        ICorDebugThread3 *   pThread3,
1171                                        ICorDebugStackWalk * pSW)
1172 {
1173     _ASSERTE(pNextStackFrame != NULL);
1174     _ASSERTE(!pStackWalkInfo->ExhaustedAllInternalFrames());
1175
1176     HRESULT hr = E_FAIL;
1177     BOOL fIsInternalFrameFirst = FALSE;
1178
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)
1184     {
1185         // create a temporary ICDStackWalk 
1186         RSExtSmartPtr<ICorDebugStackWalk> pTmpSW;
1187         hr = pThread3->CreateStackWalk(&pTmpSW);
1188         IfFailThrow(hr);
1189
1190         // retrieve the current CONTEXT
1191         DT_CONTEXT ctx;
1192         ctx.ContextFlags = DT_CONTEXT_FULL;
1193         hr = pSW->GetContext(ctx.ContextFlags, sizeof(ctx), NULL, reinterpret_cast<BYTE *>(&ctx));
1194         IfFailThrow(hr);
1195
1196         // set the CONTEXT on the temporary ICDStackWalk
1197         hr = pTmpSW->SetContext(SET_CONTEXT_FLAG_ACTIVE_FRAME, sizeof(ctx), reinterpret_cast<BYTE *>(&ctx));
1198         IfFailThrow(hr);
1199
1200         // unwind the temporary ICDStackWalk by one frame
1201         hr = pTmpSW->Next();
1202         IfFailThrow(hr);
1203
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));
1207         IfFailThrow(hr);
1208
1209         // Get the SP from the CONTEXT.  This is the caller SP.
1210         CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS(CORDbgGetSP(&ctx));
1211
1212         // get the frame address
1213         CORDB_ADDRESS frameAddr = 0;
1214         hr = pStackWalkInfo->GetCurrentInternalFrame()->GetAddress(&frameAddr);
1215         IfFailThrow(hr);
1216
1217         // Compare the frame address with the caller SP of the stack frame for the IL method without metadata.
1218         fIsInternalFrameFirst = (frameAddr < sp);
1219     }
1220     else
1221     {
1222         hr = pStackWalkInfo->GetCurrentInternalFrame()->IsCloserToLeaf(pNextStackFrame, &fIsInternalFrameFirst);
1223         IfFailThrow(hr);
1224     }
1225
1226     return fIsInternalFrameFirst;
1227 }
1228
1229 // ----------------------------------------------------------------------------
1230 // ShimStackWalk::ConvertInternalFrameToDynamicMethod
1231 //
1232 // Description: 
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.
1239 //    
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.
1245 //
1246 // Arguments:
1247 //    * pStackWalkInfo - information about the current stackwalk
1248 //
1249 // Return Value:
1250 //    Return TRUE if a conversion has taken place.  
1251 //
1252
1253 BOOL ShimStackWalk::ConvertInternalFrameToDynamicMethod(StackWalkInfo * pStackWalkInfo)
1254 {
1255     HRESULT hr = E_FAIL;
1256
1257     // QI for ICDFrame
1258     RSExtSmartPtr<ICorDebugFrame> pOriginalFrame;
1259     hr = pStackWalkInfo->GetCurrentInternalFrame()->QueryInterface(
1260         IID_ICorDebugFrame, 
1261         reinterpret_cast<void **>(&pOriginalFrame));
1262     IfFailThrow(hr);
1263
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(
1267         pOriginalFrame, 
1268         &(pStackWalkInfo->m_pConvertedInternalFrame2)));
1269
1270     if (pStackWalkInfo->HasConvertedFrame())
1271     {
1272         // We have a conversion.
1273         if (pStackWalkInfo->GetCurrentInternalFrame() != NULL)
1274         {
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));
1280             IfFailThrow(hr);
1281
1282             hr = pInternalFrame->GetFrameType(&(pStackWalkInfo->m_internalFrameType));
1283             IfFailThrow(hr);
1284         }
1285         else
1286         {
1287             // The method being jitted is an IL stub, so let's not expose it.
1288             pStackWalkInfo->m_internalFrameType = STUBFRAME_NONE;
1289         }
1290     }
1291
1292     return pStackWalkInfo->HasConvertedFrame();
1293 }
1294
1295 // ----------------------------------------------------------------------------
1296 // ShimStackWalk::ConvertInternalFrameToDynamicMethod
1297 //
1298 // Description: 
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
1303 //    in V2 at all.
1304 //    
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.
1310 //
1311 // Arguments:
1312 //    * pFrame         - the frame to be checked and converted if necessary
1313 //    * pStackWalkInfo - information about the current stackwalk
1314 //
1315 // Return Value:
1316 //    Return TRUE if a conversion has taken place.  
1317 //
1318
1319 BOOL ShimStackWalk::ConvertStackFrameToDynamicMethod(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo)
1320 {
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))
1323     {
1324         return FALSE;
1325     }
1326
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(
1330         pFrame, 
1331         &(pStackWalkInfo->m_pConvertedInternalFrame2)));
1332
1333     return pStackWalkInfo->HasConvertedFrame();
1334 }
1335
1336 // ----------------------------------------------------------------------------
1337 // ShimStackWalk::TrackUMChain
1338 //
1339 // Description: 
1340 //    Keep track of enter-unmanaged chains.  Extend or cancel the chain as necesasry.
1341 //
1342 // Arguments:
1343 //    * pChainInfo     - information on the current chain we are tracking
1344 //    * pStackWalkInfo - information regarding the current stackwalk
1345 //    
1346 // Notes:
1347 //    * This logic is based on code:TrackUMChain on the LS.
1348 //
1349
1350 void ShimStackWalk::TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo)
1351 {
1352     if (!pChainInfo->IsTrackingUMChain())
1353     {
1354         if (pStackWalkInfo->m_fProcessingInternalFrame)
1355         {
1356             if (pStackWalkInfo->m_internalFrameType == STUBFRAME_M2U)
1357             {
1358                 // If we hit an M2U frame out in the wild, convert it to an enter-unmanaged chain.
1359
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;
1364             }
1365         }
1366     }
1367
1368     BOOL fCreateUMChain = FALSE;
1369     if (pChainInfo->IsTrackingUMChain())
1370     {
1371         if (pStackWalkInfo->m_fProcessingInternalFrame)
1372         {
1373             // Extend the root end of the unmanaged chain.
1374             pChainInfo->m_rootFP = GetFramePointerForChain(pStackWalkInfo->GetCurrentInternalFrame());
1375
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))
1381             {
1382                 pChainInfo->CancelUMChain();
1383             }
1384             else if (pStackWalkInfo->m_internalFrameType == STUBFRAME_M2U)
1385             {
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;
1389             }
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))
1394             {
1395                 fCreateUMChain = TRUE;
1396             }
1397         }
1398         else
1399         {
1400             // If we hit a managed stack frame when we are processing an unmanaged chain, then
1401             // the chain is done.
1402             fCreateUMChain = TRUE;
1403         }
1404     }
1405
1406     if (fCreateUMChain)
1407     {
1408         // check whether we get any stack range
1409         _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid);
1410         FramePointer fpLeaf = GetFramePointerForChain(&(pChainInfo->m_leafNativeContext));
1411
1412         // Don't bother creating an unmanaged chain if the stack range is empty.
1413         if (fpLeaf != pChainInfo->m_rootFP)
1414         {
1415             AppendChain(pChainInfo, pStackWalkInfo);
1416         }
1417         pChainInfo->CancelUMChain();
1418     }
1419 }
1420
1421 BOOL ShimStackWalk::IsV3FrameType(CorDebugInternalFrameType type)
1422 {
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))
1429     {
1430         return TRUE;
1431     }
1432     else
1433     {
1434         return FALSE;
1435     }
1436 }
1437
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)
1441 {
1442     HRESULT hr = E_FAIL;
1443
1444     RSExtSmartPtr<ICorDebugNativeFrame> pNativeFrame;
1445     hr = pFrame->QueryInterface(IID_ICorDebugNativeFrame, reinterpret_cast<void **>(&pNativeFrame));
1446     IfFailThrow(hr);
1447
1448     if (pNativeFrame != NULL)
1449     {
1450         RSExtSmartPtr<ICorDebugILFrame> pILFrame;
1451         hr = pFrame->QueryInterface(IID_ICorDebugILFrame, reinterpret_cast<void **>(&pILFrame));
1452
1453         if (FAILED(hr) || (pILFrame == NULL))
1454         {
1455             return TRUE;
1456         }
1457     }
1458
1459     return FALSE;
1460 }
1461
1462 ShimStackWalk::StackWalkInfo::StackWalkInfo()
1463   : m_cChain(0),
1464     m_cFrame(0),
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),
1472     m_fLeafFrame(true),
1473     m_fHasConvertedFrame(false)
1474 {
1475     m_pChildFrame.Assign(NULL);
1476     m_pConvertedInternalFrame2.Assign(NULL);
1477 }
1478
1479 ShimStackWalk::StackWalkInfo::~StackWalkInfo()
1480 {
1481     if (m_pChildFrame != NULL)
1482     {
1483         m_pChildFrame.Clear();
1484     }
1485     
1486     if (m_pConvertedInternalFrame2 != NULL)
1487     {
1488         m_pConvertedInternalFrame2.Clear();
1489     }
1490
1491     if (!m_ppInternalFrame2.IsEmpty())
1492     {
1493         m_ppInternalFrame2.Clear();
1494     }
1495 }
1496
1497 void ShimStackWalk::StackWalkInfo::ResetForNextFrame()
1498 {
1499     m_pConvertedInternalFrame2.Clear();
1500     m_internalFrameType = STUBFRAME_NONE;
1501     m_fProcessingInternalFrame = false;
1502     m_fSkipChain = false;
1503     m_fHasConvertedFrame = false;
1504 }
1505
1506 // Check whether we have exhausted both internal frames and stack frames.
1507 bool ShimStackWalk::StackWalkInfo::ExhaustedAllFrames() 
1508
1509     return (ExhaustedAllStackFrames() && ExhaustedAllInternalFrames());
1510 }
1511
1512 bool ShimStackWalk::StackWalkInfo::ExhaustedAllStackFrames() 
1513
1514     return m_fExhaustedAllStackFrames;
1515 }
1516
1517 bool ShimStackWalk::StackWalkInfo::ExhaustedAllInternalFrames() 
1518
1519     return (m_curInternalFrame == m_cInternalFrames); 
1520 }
1521
1522 ICorDebugInternalFrame2 * ShimStackWalk::StackWalkInfo::GetCurrentInternalFrame()
1523 {
1524     _ASSERTE(!ExhaustedAllInternalFrames() || HasConvertedFrame());
1525
1526     if (HasConvertedFrame())
1527     {
1528         return m_pConvertedInternalFrame2;
1529     }
1530     else
1531     {
1532         return m_ppInternalFrame2[m_curInternalFrame];
1533     }
1534 }
1535
1536 BOOL ShimStackWalk::StackWalkInfo::IsLeafFrame()
1537 {
1538     return m_fLeafFrame;
1539 }
1540
1541 BOOL ShimStackWalk::StackWalkInfo::IsSkippingFrame()
1542 {
1543     return (m_pChildFrame != NULL);
1544 }
1545
1546 BOOL ShimStackWalk::StackWalkInfo::HasConvertedFrame()
1547 {
1548     return m_fHasConvertedFrame;
1549 }
1550
1551
1552 ShimChain::ShimChain(ShimStackWalk *     pSW,
1553                      DT_CONTEXT *        pContext,
1554                      FramePointer        fpRoot,
1555                      UINT32              chainIndex,
1556                      UINT32              frameStartIndex,
1557                      UINT32              frameEndIndex,
1558                      CorDebugChainReason chainReason,
1559                      BOOL                fIsManaged,
1560                      RSLock *            pShimLock)
1561   : m_context(*pContext),
1562     m_fpRoot(fpRoot),
1563     m_pStackWalk(pSW),
1564     m_refCount(0),
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)
1572 {
1573 }
1574
1575 ShimChain::~ShimChain()
1576 {
1577     _ASSERTE(IsNeutered());
1578 }
1579
1580 void ShimChain::Neuter()
1581 {
1582     m_fIsNeutered = TRUE;
1583 }
1584
1585 BOOL ShimChain::IsNeutered()
1586 {
1587     return m_fIsNeutered;
1588 }
1589
1590 ULONG STDMETHODCALLTYPE ShimChain::AddRef()
1591 {
1592     return InterlockedIncrement((LONG *)&m_refCount);
1593 }
1594
1595 ULONG STDMETHODCALLTYPE ShimChain::Release()
1596 {
1597     LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
1598     _ASSERTE(newRefCount >= 0);
1599
1600     if (newRefCount == 0)
1601     {
1602         delete this;
1603     }
1604     return newRefCount;
1605 }
1606
1607 HRESULT ShimChain::QueryInterface(REFIID id, void ** pInterface)
1608 {
1609     if (id == IID_ICorDebugChain)
1610     {
1611         *pInterface = static_cast<ICorDebugChain *>(this);
1612     }
1613     else if (id == IID_IUnknown)
1614     {
1615         *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugChain *>(this));
1616     }
1617     else
1618     {
1619         *pInterface = NULL;
1620         return E_NOINTERFACE;
1621     }
1622
1623     AddRef();
1624     return S_OK;
1625 }
1626
1627 // Returns the thread to which this chain belongs.
1628 HRESULT ShimChain::GetThread(ICorDebugThread ** ppThread)
1629 {
1630     RSLockHolder lockHolder(m_pShimLock);
1631     FAIL_IF_NEUTERED(this);
1632     VALIDATE_POINTER_TO_OBJECT(ppThread, ICorDebugThread **);
1633
1634     *ppThread = m_pStackWalk->GetThread();
1635     (*ppThread)->AddRef();
1636
1637     return S_OK;
1638 }
1639
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)
1645 {
1646     HRESULT hr = S_OK;
1647     EX_TRY
1648     {
1649         THROW_IF_NEUTERED(this);
1650
1651         VALIDATE_POINTER_TO_OBJECT_OR_NULL(pStart, CORDB_ADDRESS *);
1652         VALIDATE_POINTER_TO_OBJECT_OR_NULL(pEnd, CORDB_ADDRESS *);
1653
1654         // Return the leafmost end of the stack range.
1655         // The leafmost end is represented by the register set.
1656         if (pStart)
1657         {
1658             *pStart = PTR_TO_CORDB_ADDRESS(CORDbgGetSP(&m_context));
1659         }
1660
1661         // Return the rootmost end of the stack range.  It is represented by the frame pointer of the chain.
1662         if (pEnd)
1663         {
1664             *pEnd = PTR_TO_CORDB_ADDRESS(m_fpRoot.GetSPValue());
1665         }
1666     }
1667     EX_CATCH_HRESULT(hr);
1668     return hr;
1669 }
1670
1671 HRESULT ShimChain::GetContext(ICorDebugContext ** ppContext)
1672 {
1673     return E_NOTIMPL;
1674 }
1675
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)
1679 {
1680     RSLockHolder lockHolder(m_pShimLock);
1681     FAIL_IF_NEUTERED(this);
1682     VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1683
1684     return GetNext(ppChain);
1685 }
1686
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)
1690 {
1691     RSLockHolder lockHolder(m_pShimLock);
1692     FAIL_IF_NEUTERED(this);
1693     VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1694
1695     return GetPrevious(ppChain);
1696 }
1697
1698 // Return the previous chain which is closer to the leaf.
1699 HRESULT ShimChain::GetPrevious(ICorDebugChain ** ppChain)
1700 {
1701     RSLockHolder lockHolder(m_pShimLock);
1702     FAIL_IF_NEUTERED(this);
1703     VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1704
1705     *ppChain = NULL;
1706     if (m_chainIndex != 0)
1707     {
1708         *ppChain = m_pStackWalk->GetChain(m_chainIndex - 1);
1709     }
1710
1711     if (*ppChain != NULL)
1712     {
1713         (*ppChain)->AddRef();
1714     }
1715
1716     return S_OK;
1717 }
1718
1719 // Return the next chain which is closer to the root.
1720 HRESULT ShimChain::GetNext(ICorDebugChain ** ppChain)
1721 {
1722     RSLockHolder lockHolder(m_pShimLock);
1723     FAIL_IF_NEUTERED(this);
1724     VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1725
1726     *ppChain = m_pStackWalk->GetChain(m_chainIndex + 1);
1727     if (*ppChain != NULL)
1728     {
1729         (*ppChain)->AddRef();
1730     }
1731
1732     return S_OK;
1733 }
1734
1735 // Return whether the chain contains frames running managed code.
1736 HRESULT ShimChain::IsManaged(BOOL * pManaged)
1737 {
1738     RSLockHolder lockHolder(m_pShimLock);
1739     FAIL_IF_NEUTERED(this);
1740     VALIDATE_POINTER_TO_OBJECT(pManaged, BOOL *);
1741
1742     *pManaged = m_fIsManaged;
1743
1744     return S_OK;
1745 }
1746
1747 // Return an enumerator to iterate through the frames contained in this chain.
1748 HRESULT ShimChain::EnumerateFrames(ICorDebugFrameEnum ** ppFrames)
1749 {
1750     RSLockHolder lockHolder(m_pShimLock);
1751     FAIL_IF_NEUTERED(this);
1752     VALIDATE_POINTER_TO_OBJECT(ppFrames, ICorDebugFrameEnum **);
1753
1754     HRESULT hr = S_OK;
1755     EX_TRY
1756     {
1757         ShimStackWalk * pSW = GetShimStackWalk();
1758         NewHolder<ShimFrameEnum> pFrameEnum(new ShimFrameEnum(pSW, this, m_frameStartIndex, m_frameEndIndex, m_pShimLock));
1759
1760         *ppFrames = pFrameEnum;
1761         (*ppFrames)->AddRef();
1762
1763         // link the new ShimFramEnum into the list on the ShimStackWalk
1764         pSW->AddFrameEnum(pFrameEnum);
1765
1766         pFrameEnum.SuppressRelease();
1767     }
1768     EX_CATCH_HRESULT(hr);
1769
1770     return hr;
1771 }
1772
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)
1776 {
1777     RSLockHolder lockHolder(m_pShimLock);
1778     FAIL_IF_NEUTERED(this);
1779     VALIDATE_POINTER_TO_OBJECT(ppFrame, ICorDebugFrame **);
1780     (*ppFrame) = NULL;
1781
1782     HRESULT hr = S_OK;
1783
1784     // Chains may be empty, so they have no active frame.
1785     if (m_frameStartIndex == m_frameEndIndex)
1786     {
1787         *ppFrame = NULL;
1788     }
1789     else
1790     {
1791         *ppFrame = m_pStackWalk->GetFrame(m_frameStartIndex);
1792         (*ppFrame)->AddRef();
1793     }
1794
1795     return hr;
1796 }
1797
1798 // Return the register set of the leaf end of the chain
1799 HRESULT ShimChain::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters)
1800 {
1801     FAIL_IF_NEUTERED(this);
1802     VALIDATE_POINTER_TO_OBJECT(ppRegisters, ICorDebugRegisterSet **);
1803
1804     HRESULT hr = S_OK;
1805     EX_TRY
1806     {
1807         CordbThread * pThread = static_cast<CordbThread *>(m_pStackWalk->GetThread());
1808
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), 
1813                                         m_chainReason,
1814                                         ppRegisters);
1815     }
1816     EX_CATCH_HRESULT(hr);
1817     return hr;
1818 }
1819
1820 // Return the chain reason
1821 HRESULT ShimChain::GetReason(CorDebugChainReason * pReason)
1822 {
1823     RSLockHolder lockHolder(m_pShimLock);
1824     FAIL_IF_NEUTERED(this);
1825     VALIDATE_POINTER_TO_OBJECT(pReason, CorDebugChainReason *);
1826
1827     *pReason = m_chainReason;
1828
1829     return S_OK;
1830 }
1831
1832 ShimStackWalk * ShimChain::GetShimStackWalk()
1833 {
1834     return m_pStackWalk;
1835 }
1836
1837 UINT32 ShimChain::GetFirstFrameIndex()
1838 {
1839     return this->m_frameStartIndex;
1840 }
1841
1842 UINT32 ShimChain::GetLastFrameIndex()
1843 {
1844     return this->m_frameEndIndex;
1845 }
1846
1847
1848 ShimChainEnum::ShimChainEnum(ShimStackWalk * pSW, RSLock * pShimLock)
1849   : m_pStackWalk(pSW),
1850     m_pNext(NULL),
1851     m_currentChainIndex(0),
1852     m_refCount(0),
1853     m_fIsNeutered(FALSE),
1854     m_pShimLock(pShimLock)
1855 {
1856 }
1857
1858 ShimChainEnum::~ShimChainEnum()
1859 {
1860     _ASSERTE(IsNeutered());
1861 }
1862
1863 void ShimChainEnum::Neuter()
1864 {
1865     if (IsNeutered())
1866     {
1867         return;
1868     }
1869
1870     m_fIsNeutered = TRUE;
1871 }
1872
1873 BOOL ShimChainEnum::IsNeutered()
1874 {
1875     return m_fIsNeutered;
1876 }
1877
1878
1879 ULONG STDMETHODCALLTYPE ShimChainEnum::AddRef()
1880 {
1881     return InterlockedIncrement((LONG *)&m_refCount);
1882 }
1883
1884 ULONG STDMETHODCALLTYPE ShimChainEnum::Release()
1885 {
1886     LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
1887     _ASSERTE(newRefCount >= 0);
1888
1889     if (newRefCount == 0)
1890     {
1891         delete this;
1892     }
1893     return newRefCount;
1894 }
1895
1896 HRESULT ShimChainEnum::QueryInterface(REFIID id, void ** ppInterface)
1897 {
1898     if (id == IID_ICorDebugChainEnum)
1899     {
1900         *ppInterface = static_cast<ICorDebugChainEnum *>(this);
1901     }
1902     else if (id == IID_ICorDebugEnum)
1903     {
1904         *ppInterface = static_cast<ICorDebugEnum *>(static_cast<ICorDebugChainEnum *>(this));
1905     }
1906     else if (id == IID_IUnknown)
1907     {
1908         *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugChainEnum *>(this));
1909     }
1910     else
1911     {
1912         *ppInterface = NULL;
1913         return E_NOINTERFACE;
1914     }
1915
1916     AddRef();
1917     return S_OK;
1918 }
1919
1920 // Skip the specified number of chains.
1921 HRESULT ShimChainEnum::Skip(ULONG celt)
1922 {
1923     RSLockHolder lockHolder(m_pShimLock);
1924     FAIL_IF_NEUTERED(this);
1925
1926     // increment the index by the specified amount
1927     m_currentChainIndex += celt;
1928     return S_OK;
1929 }
1930
1931 HRESULT ShimChainEnum::Reset()
1932 {
1933     m_currentChainIndex = 0;
1934     return S_OK;
1935 }
1936
1937 // Clone the chain enumerator and set the new one to the same current chain
1938 HRESULT ShimChainEnum::Clone(ICorDebugEnum ** ppEnum)
1939 {
1940     RSLockHolder lockHolder(m_pShimLock);
1941     FAIL_IF_NEUTERED(this);
1942     VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
1943
1944     HRESULT hr = S_OK;
1945     EX_TRY
1946     {
1947         NewHolder<ShimChainEnum> pChainEnum(new ShimChainEnum(m_pStackWalk, m_pShimLock));
1948
1949         // set the index in the new enumerator
1950         pChainEnum->m_currentChainIndex = this->m_currentChainIndex;
1951
1952         *ppEnum = pChainEnum;
1953         (*ppEnum)->AddRef();
1954         m_pStackWalk->AddChainEnum(pChainEnum);
1955
1956         pChainEnum.SuppressRelease();
1957     }
1958     EX_CATCH_HRESULT(hr);
1959     return hr;
1960 }
1961
1962 // Return the number of chains on the thread
1963 HRESULT ShimChainEnum::GetCount(ULONG * pcChains)
1964 {
1965     RSLockHolder lockHolder(m_pShimLock);
1966     FAIL_IF_NEUTERED(this);
1967     VALIDATE_POINTER_TO_OBJECT(pcChains, ULONG *);
1968
1969     *pcChains = m_pStackWalk->GetChainCount();
1970     return S_OK;
1971 }
1972
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)
1977 {
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 *);
1982
1983     // if the out parameter is NULL, then we can only return one chain at a time
1984     if ((pcChainsFetched == NULL) && (cChains != 1))
1985     {
1986         return E_INVALIDARG;
1987     }
1988
1989     // Check for the trivial case where no chain is actually requested.
1990     // This is probably a user error.
1991     if (cChains == 0)
1992     {
1993         if (pcChainsFetched != NULL)
1994         {
1995             *pcChainsFetched = 0;
1996         }
1997         return S_OK;
1998     }
1999
2000     ICorDebugChain ** ppCurrentChain = rgpChains;
2001
2002     while ((m_currentChainIndex < m_pStackWalk->GetChainCount()) &&
2003            (cChains > 0))
2004     {
2005         *ppCurrentChain = m_pStackWalk->GetChain(m_currentChainIndex);
2006         (*ppCurrentChain)->AddRef();
2007
2008         ppCurrentChain++;       // increment the pointer into the buffer
2009         m_currentChainIndex++;  // increment the index
2010         cChains--;
2011     }
2012
2013     // set the number of chains actually returned
2014     if (pcChainsFetched != NULL)
2015     {
2016         *pcChainsFetched = (ULONG)(ppCurrentChain - rgpChains);
2017     }
2018
2019     //
2020     // If we reached the end of the enumeration, but not the end
2021     // of the number of requested items, we return S_FALSE.
2022     //
2023     if (cChains > 0)
2024     {
2025         return S_FALSE;
2026     }
2027
2028     return S_OK;
2029 }
2030
2031 ShimChainEnum * ShimChainEnum::GetNext()
2032 {
2033     return m_pNext;
2034 }
2035
2036 void ShimChainEnum::SetNext(ShimChainEnum * pNext)
2037 {
2038     if (m_pNext != NULL)
2039     {
2040         m_pNext->Release();
2041     }
2042
2043     m_pNext = pNext;
2044
2045     if (m_pNext != NULL)
2046     {
2047         m_pNext->AddRef();
2048     }
2049 }
2050
2051
2052 ShimFrameEnum::ShimFrameEnum(ShimStackWalk * pSW, 
2053                              ShimChain *     pChain, 
2054                              UINT32          frameStartIndex, 
2055                              UINT32          frameEndIndex,
2056                              RSLock *        pShimLock)
2057   : m_pStackWalk(pSW),
2058     m_pChain(pChain),
2059     m_pShimLock(pShimLock),
2060     m_pNext(NULL),
2061     m_currentFrameIndex(frameStartIndex),
2062     m_endFrameIndex(frameEndIndex),
2063     m_refCount(0),
2064     m_fIsNeutered(FALSE)
2065 {
2066 }
2067
2068 ShimFrameEnum::~ShimFrameEnum()
2069 {
2070     _ASSERTE(IsNeutered());
2071 }
2072
2073 void ShimFrameEnum::Neuter()
2074 {
2075     if (IsNeutered())
2076     {
2077         return;
2078     }
2079
2080     m_fIsNeutered = TRUE;
2081 }
2082
2083 BOOL ShimFrameEnum::IsNeutered()
2084 {
2085     return m_fIsNeutered;
2086 }
2087
2088
2089 ULONG STDMETHODCALLTYPE ShimFrameEnum::AddRef()
2090 {
2091     return InterlockedIncrement((LONG *)&m_refCount);
2092 }
2093
2094 ULONG STDMETHODCALLTYPE ShimFrameEnum::Release()
2095 {
2096     LONG newRefCount = InterlockedDecrement((LONG *)&m_refCount);
2097     _ASSERTE(newRefCount >= 0);
2098
2099     if (newRefCount == 0)
2100     {
2101         delete this;
2102     }
2103     return newRefCount;
2104 }
2105
2106 HRESULT ShimFrameEnum::QueryInterface(REFIID id, void ** ppInterface)
2107 {
2108     if (id == IID_ICorDebugFrameEnum)
2109     {
2110         *ppInterface = static_cast<ICorDebugFrameEnum *>(this);
2111     }
2112     else if (id == IID_ICorDebugEnum)
2113     {
2114         *ppInterface = static_cast<ICorDebugEnum *>(static_cast<ICorDebugFrameEnum *>(this));
2115     }
2116     else if (id == IID_IUnknown)
2117     {
2118         *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugFrameEnum *>(this));
2119     }
2120     else
2121     {
2122         *ppInterface = NULL;
2123         return E_NOINTERFACE;
2124     }
2125
2126     AddRef();
2127     return S_OK;
2128 }
2129
2130 // Skip the specified number of chains.
2131 HRESULT ShimFrameEnum::Skip(ULONG celt)
2132 {
2133     RSLockHolder lockHolder(m_pShimLock);
2134     FAIL_IF_NEUTERED(this);
2135
2136     // increment the index by the specified amount
2137     m_currentFrameIndex += celt;
2138     return S_OK;
2139 }
2140
2141 HRESULT ShimFrameEnum::Reset()
2142 {
2143     RSLockHolder lockHolder(m_pShimLock);
2144     FAIL_IF_NEUTERED(this);
2145
2146     m_currentFrameIndex = m_pChain->GetFirstFrameIndex();
2147     return S_OK;
2148 }
2149
2150 // Clone the chain enumerator and set the new one to the same current chain
2151 HRESULT ShimFrameEnum::Clone(ICorDebugEnum ** ppEnum)
2152 {
2153     RSLockHolder lockHolder(m_pShimLock);
2154     FAIL_IF_NEUTERED(this);
2155     VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
2156
2157     HRESULT hr = S_OK;
2158     EX_TRY
2159     {
2160         NewHolder<ShimFrameEnum> pFrameEnum(new ShimFrameEnum(m_pStackWalk, 
2161                                                               m_pChain, 
2162                                                               m_currentFrameIndex, 
2163                                                               m_endFrameIndex,
2164                                                               m_pShimLock));
2165
2166         *ppEnum = pFrameEnum;
2167         (*ppEnum)->AddRef();
2168         m_pStackWalk->AddFrameEnum(pFrameEnum);
2169
2170         pFrameEnum.SuppressRelease();
2171     }
2172     EX_CATCH_HRESULT(hr);
2173
2174     return hr;
2175 }
2176
2177 // Return the number of chains on the thread
2178 HRESULT ShimFrameEnum::GetCount(ULONG * pcFrames)
2179 {
2180     RSLockHolder lockHolder(m_pShimLock);
2181     FAIL_IF_NEUTERED(this);
2182     VALIDATE_POINTER_TO_OBJECT(pcFrames, ULONG *);
2183
2184     *pcFrames = m_pChain->GetLastFrameIndex() - m_pChain->GetFirstFrameIndex();
2185     return S_OK;
2186 }
2187
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)
2192 {
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 *);
2197
2198     // if the out parameter is NULL, then we can only return one chain at a time
2199     if ((pcFramesFetched == NULL) && (cFrames != 1))
2200     {
2201         return E_INVALIDARG;
2202     }
2203
2204     // Check for the trivial case where no chain is actually requested.
2205     // This is probably a user error.
2206     if (cFrames == 0)
2207     {
2208         if (pcFramesFetched != NULL)
2209         {
2210             *pcFramesFetched = 0;
2211         }
2212         return S_OK;
2213     }
2214
2215     ICorDebugFrame ** ppCurrentFrame = rgpFrames;
2216
2217     while ((m_currentFrameIndex < m_endFrameIndex) &&
2218            (cFrames > 0))
2219     {
2220         *ppCurrentFrame = m_pStackWalk->GetFrame(m_currentFrameIndex);
2221         (*ppCurrentFrame)->AddRef();
2222
2223         ppCurrentFrame++;       // increment the pointer into the buffer
2224         m_currentFrameIndex++;  // increment the index
2225         cFrames--;
2226     }
2227
2228     // set the number of chains actually returned
2229     if (pcFramesFetched != NULL)
2230     {
2231         *pcFramesFetched = (ULONG)(ppCurrentFrame - rgpFrames);
2232     }
2233
2234     //
2235     // If we reached the end of the enumeration, but not the end
2236     // of the number of requested items, we return S_FALSE.
2237     //
2238     if (cFrames > 0)
2239     {
2240         return S_FALSE;
2241     }
2242
2243     return S_OK;
2244 }
2245
2246 ShimFrameEnum * ShimFrameEnum::GetNext()
2247 {
2248     return m_pNext;
2249 }
2250
2251 void ShimFrameEnum::SetNext(ShimFrameEnum * pNext)
2252 {
2253     if (m_pNext != NULL)
2254     {
2255         m_pNext->Release();
2256     }
2257
2258     m_pNext = pNext;
2259
2260     if (m_pNext != NULL)
2261     {
2262         m_pNext->AddRef();
2263     }
2264 }