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// File: frameinfo.cpp
6//
7
8//
9// Code to find control info about a stack frame.
10//
11//*****************************************************************************
12
13#include "stdafx.h"
14
15// Include so we can get information out of ComMethodFrame
16#ifdef FEATURE_COMINTEROP
17#include "COMToClrCall.h"
18#endif
19
20// Get a frame pointer from a RegDisplay.
21// This is mostly used for chains and stub frames (i.e. internal frames), where we don't need an exact
22// frame pointer. This is why it is okay to use the current SP instead of the caller SP on IA64.
23// We should really rename this and possibly roll it into GetFramePointer() when we move the stackwalker
24// to OOP.
25FramePointer GetSP(REGDISPLAY * pRDSrc)
26{
27 FramePointer fp = FramePointer::MakeFramePointer(
28 (LPVOID)GetRegdisplaySP(pRDSrc));
29
30 return fp;
31}
32
33// Get a frame pointer from a RegDisplay.
34FramePointer GetFramePointer(REGDISPLAY * pRDSrc)
35{
36 return FramePointer::MakeFramePointer(GetRegdisplaySP(pRDSrc));
37}
38
39//---------------------------------------------------------------------------------------
40//
41// Convert a FramePointer to a StackFrame and return it.
42//
43// Arguments:
44// fp - the FramePointer to be converted
45//
46// Return Value:
47// a StackFrame equivalent to the given FramePointer
48//
49// Notes:
50// We really should consolidate the two abstractions for "stack frame identifiers"
51// (StackFrame and FramePointer) when we move the debugger stackwalker to OOP.
52//
53
54FORCEINLINE StackFrame ConvertFPToStackFrame(FramePointer fp)
55{
56 return StackFrame((UINT_PTR)fp.GetSPValue());
57}
58
59/* ------------------------------------------------------------------------- *
60 * DebuggerFrameInfo routines
61 * ------------------------------------------------------------------------- */
62
63//struct DebuggerFrameData: Contains info used by the DebuggerWalkStackProc
64// to do a stack walk. The info and pData fields are handed to the pCallback
65// routine at each frame,
66struct DebuggerFrameData
67{
68 // Initialize this struct. Only done at the start of a stackwalk.
69 void Init(
70 Thread * _pThread,
71 FramePointer _targetFP,
72 BOOL fIgnoreNonmethodFrames, // generally true for stackwalking and false for stepping
73 DebuggerStackCallback _pCallback,
74 void *_pData
75 )
76 {
77 LIMITED_METHOD_CONTRACT;
78
79 this->pCallback = _pCallback;
80 this->pData = _pData;
81
82 this->cRealCounter = 0;
83
84 this->thread = _pThread;
85 this->targetFP = _targetFP;
86 this->targetFound = (_targetFP == LEAF_MOST_FRAME);
87
88 this->ignoreNonmethodFrames = fIgnoreNonmethodFrames;
89
90 // For now, we can tie these to flags together.
91 // In everett, we disable SIS (For backwards compat).
92 this->fProvideInternalFrames = (fIgnoreNonmethodFrames != 0);
93
94 this->fNeedToSendEnterManagedChain = false;
95 this->fTrackingUMChain = false;
96 this->fHitExitFrame = false;
97
98 this->info.eStubFrameType = STUBFRAME_NONE;
99 this->info.quickUnwind = false;
100
101 this->info.frame = NULL;
102 this->needParentInfo = false;
103
104#ifdef WIN64EXCEPTIONS
105 this->fpParent = LEAF_MOST_FRAME;
106 this->info.fIsLeaf = true;
107 this->info.fIsFunclet = false;
108 this->info.fIsFilter = false;
109#endif // WIN64EXCEPTIONS
110
111 // Look strange? Go to definition of this field. I dare you.
112 this->info.fIgnoreThisFrameIfSuppressingUMChainFromComPlusMethodFrameGeneric = false;
113
114#if defined(_DEBUG)
115 this->previousFP = LEAF_MOST_FRAME;
116#endif // _DEBUG
117 }
118
119 // True if we need the next CrawlFrame to fill out part of this FrameInfo's data.
120 bool needParentInfo;
121
122 // The FrameInfo that we'll dispatch to the pCallback. This matches against
123 // the CrawlFrame for that frame that the callback belongs too.
124 FrameInfo info;
125
126 // Regdisplay that the EE stackwalker is updating.
127 REGDISPLAY regDisplay;
128
129
130#ifdef WIN64EXCEPTIONS
131 // This is used to skip funclets in a stackwalk. It marks the frame pointer to which we should skip.
132 FramePointer fpParent;
133#endif // WIN64EXCEPTIONS
134#if defined(_DEBUG)
135 // For debugging, track the previous FramePointer so we can assert that we're
136 // making progress through the stack.
137 FramePointer previousFP;
138#endif // _DEBUG
139
140 // whether we have hit an exit frame or not (i.e. a M2U frame)
141 bool fHitExitFrame;
142
143private:
144 // The scope of this field is each section of managed method frames on the stack.
145 bool fNeedToSendEnterManagedChain;
146
147 // Flag set when we first stack-walk to decide if we want to ignore certain frames.
148 // Stepping doesn't ignore these frames; end user stacktraces do.
149 BOOL ignoreNonmethodFrames;
150
151 // Do we want callbacks for internal frames?
152 // Steppers generally don't. User stack-walk does.
153 bool fProvideInternalFrames;
154
155 // Info for tracking unmanaged chains.
156 // We track the starting (leaf) context for an unmanaged chain, as well as the
157 // ending (root) framepointer.
158 bool fTrackingUMChain;
159 REGDISPLAY rdUMChainStart;
160 FramePointer fpUMChainEnd;
161
162 // Thread that the stackwalk is for.
163 Thread *thread;
164
165
166 // Target FP indicates at what point in the stackwalk we'll start dispatching callbacks.
167 // Naturally, if this is LEAF_MOST_FRAME, then all callbacks will be dispatched
168 FramePointer targetFP;
169 bool targetFound;
170
171 // Count # of callbacks we could have dispatched (assuming targetFP==LEAF_MOST_FRAME).
172 // Useful for detecting leaf.
173 int cRealCounter;
174
175 // Callback & user-data supplied to that callback.
176 DebuggerStackCallback pCallback;
177 void *pData;
178
179 private:
180
181 // Raw invoke. This just does some consistency asserts,
182 // and invokes the callback if we're in the requested target range.
183 StackWalkAction RawInvokeCallback(FrameInfo * pInfo)
184 {
185#ifdef _DEBUG
186 _ASSERTE(pInfo != NULL);
187 MethodDesc * md = pInfo->md;
188 // Invoke the callback to the user. Log what we're invoking.
189 LOG((LF_CORDB, LL_INFO10000, "DSWCallback: MD=%s,0x%p, Chain=%x, Stub=%x, Frame=0x%p, Internal=%d\n",
190 ((md == NULL) ? "None" : md->m_pszDebugMethodName), md,
191 pInfo->chainReason,
192 pInfo->eStubFrameType,
193 pInfo->frame, pInfo->internal));
194
195 // Make sure we're providing a valid FrameInfo for the callback.
196 pInfo->AssertValid();
197#endif
198 // Update counter. This provides a convenient check for leaf FrameInfo.
199 this->cRealCounter++;
200
201
202 // Only invoke if we're past the target.
203 if (!this->targetFound && IsEqualOrCloserToLeaf(this->targetFP, this->info.fp))
204 {
205 this->targetFound = true;
206 }
207
208 if (this->targetFound)
209 {
210 return (pCallback)(pInfo, pData);
211 }
212 else
213 {
214 LOG((LF_CORDB, LL_INFO10000, "Not invoking yet.\n"));
215 }
216
217 return SWA_CONTINUE;
218 }
219
220public:
221 // Invoke a callback. This may do extra logic to preserve the interface between
222 // the LS stackwalker and the LS:
223 // - don't invoke if we're not at the target yet
224 // - send EnterManagedChains if we need it.
225 StackWalkAction InvokeCallback(FrameInfo * pInfo)
226 {
227 // Track if we've sent any managed code yet.
228 // If we haven't, then don't send the enter-managed chain. This catches cases
229 // when we have leaf-most unmanaged chain.
230 if ((pInfo->frame == NULL) && (pInfo->md != NULL))
231 {
232 this->fNeedToSendEnterManagedChain = true;
233 }
234
235
236 // Do tracking to decide if we need to send a Enter-Managed chain.
237 if (pInfo->HasChainMarker())
238 {
239 if (pInfo->managed)
240 {
241 // If we're dispatching a managed-chain, then we don't need to send another one.
242 fNeedToSendEnterManagedChain = false;
243 }
244 else
245 {
246 // If we're dispatching an UM chain, then send the Managed one.
247 // Note that the only unmanaged chains are ThreadStart chains and UM chains.
248 if (fNeedToSendEnterManagedChain)
249 {
250 fNeedToSendEnterManagedChain = false;
251
252 FrameInfo f;
253
254 // Assume entry chain's FP is one pointer-width after the upcoming UM chain.
255 FramePointer fpRoot = FramePointer::MakeFramePointer(
256 (BYTE*) GetRegdisplaySP(&pInfo->registers) - sizeof(DWORD*));
257
258 f.InitForEnterManagedChain(fpRoot);
259 if (RawInvokeCallback(&f) == SWA_ABORT)
260 {
261 return SWA_ABORT;
262 }
263 }
264 }
265 }
266
267 return RawInvokeCallback(pInfo);
268 }
269
270 // Note that we should start tracking an Unmanaged Chain.
271 void BeginTrackingUMChain(FramePointer fpRoot, REGDISPLAY * pRDSrc)
272 {
273 LIMITED_METHOD_CONTRACT;
274
275 _ASSERTE(!this->fTrackingUMChain);
276
277 CopyREGDISPLAY(&this->rdUMChainStart, pRDSrc);
278
279 this->fTrackingUMChain = true;
280 this->fpUMChainEnd = fpRoot;
281 this->fHitExitFrame = false;
282
283 LOG((LF_CORDB, LL_EVERYTHING, "UM Chain starting at Frame=0x%p\n", this->fpUMChainEnd.GetSPValue()));
284
285 // This UM chain may get cancelled later, so don't even worry about toggling the fNeedToSendEnterManagedChain bit here.
286 // Invoke() will track whether to send an Enter-Managed chain or not.
287 }
288
289 // For various heuristics, we may not want to send an UM chain.
290 void CancelUMChain()
291 {
292 LIMITED_METHOD_CONTRACT;
293
294 _ASSERTE(this->fTrackingUMChain);
295 this->fTrackingUMChain = false;
296 }
297
298 // True iff we're currently tracking an unmanaged chain.
299 bool IsTrackingUMChain()
300 {
301 LIMITED_METHOD_CONTRACT;
302
303 return this->fTrackingUMChain;
304 }
305
306
307
308 // Get/Set Regdisplay that starts an Unmanaged chain.
309 REGDISPLAY * GetUMChainStartRD()
310 {
311 LIMITED_METHOD_CONTRACT;
312 _ASSERTE(fTrackingUMChain);
313 return &rdUMChainStart;
314 }
315
316 // Get/Set FramePointer that ends an unmanaged chain.
317 void SetUMChainEnd(FramePointer fp)
318 {
319 LIMITED_METHOD_CONTRACT;
320 _ASSERTE(fTrackingUMChain);
321 fpUMChainEnd = fp;
322 }
323
324 FramePointer GetUMChainEnd()
325 {
326 LIMITED_METHOD_CONTRACT;
327 _ASSERTE(fTrackingUMChain);
328 return fpUMChainEnd;
329 }
330
331 // Get thread we're currently tracing.
332 Thread * GetThread()
333 {
334 LIMITED_METHOD_CONTRACT;
335 return thread;
336 }
337
338 // Returns true if we're on the leaf-callback (ie, we haven't dispatched a callback yet.
339 bool IsLeafCallback()
340 {
341 LIMITED_METHOD_CONTRACT;
342 return cRealCounter == 0;
343 }
344
345 bool ShouldProvideInternalFrames()
346 {
347 LIMITED_METHOD_CONTRACT;
348 return fProvideInternalFrames;
349 }
350 bool ShouldIgnoreNonmethodFrames()
351 {
352 LIMITED_METHOD_CONTRACT;
353 return ignoreNonmethodFrames != 0;
354 }
355};
356
357
358//---------------------------------------------------------------------------------------
359//
360// On IA64, the offset given by the OS during stackwalking is actually the offset at the call instruction.
361// This is different from x86 and X64, where the offset is immediately after the call instruction. In order
362// to have a uniform behaviour, we need to do adjust the relative offset on IA64. This function is a nop on
363// other platforms.
364//
365// Arguments:
366// pCF - the CrawlFrame for the current method frame
367// pInfo - This is the FrameInfo for the current method frame. We need to use the fIsLeaf field,
368// since no adjustment is necessary for leaf frames.
369//
370// Return Value:
371// returns the adjusted relative offset
372//
373
374inline ULONG AdjustRelOffset(CrawlFrame *pCF,
375 FrameInfo *pInfo)
376{
377 CONTRACTL
378 {
379 NOTHROW;
380 GC_NOTRIGGER;
381 MODE_ANY;
382 PRECONDITION(pCF != NULL);
383 }
384 CONTRACTL_END;
385
386#if defined(_TARGET_ARM_)
387 return pCF->GetRelOffset() & ~THUMB_CODE;
388#else
389 return pCF->GetRelOffset();
390#endif
391}
392
393
394//---------------------------------------------------------------------------------------
395//
396// Even when there is an exit frame in the explicit frame chain, it does not necessarily mean that we have
397// actually called out to unmanaged code yet or that we actually have a managed call site. Given an exit
398// frame, this function determines if we have a managed call site and have already called out to unmanaged
399// code. If we have, then we return the caller SP as the potential frame pointer. Otherwise we return
400// LEAF_MOST_FRAME.
401//
402// Arguments:
403// pFrame - the exit frame to be checked
404// pData - the state of the current frame maintained by the debugger stackwalker
405// pPotentialFP - This is an out parameter. It returns the caller SP of the last managed caller if
406// there is a managed call site and we have already called out to unmanaged code.
407// Otherwise, LEAF_MOST_FRAME is returned.
408//
409// Return Value:
410// true - we have a managed call site and we have called out to unmanaged code
411// false - otherwise
412//
413
414bool HasExitRuntime(Frame *pFrame, DebuggerFrameData *pData, FramePointer *pPotentialFP)
415{
416 CONTRACTL
417 {
418 NOTHROW;
419 GC_NOTRIGGER; // Callers demand this function be GC_NOTRIGGER.
420 MODE_ANY;
421 PRECONDITION(pFrame->GetFrameType() == Frame::TYPE_EXIT);
422 }
423 CONTRACTL_END;
424
425#ifdef _TARGET_X86_
426 TADDR returnIP, returnSP;
427
428 EX_TRY
429 {
430 // This is a real issue. This may be called while holding GC-forbid locks, and so
431 // this function can't trigger a GC. However, the only impl we have calls GC-trigger functions.
432 CONTRACT_VIOLATION(GCViolation);
433 pFrame->GetUnmanagedCallSite(NULL, &returnIP, &returnSP);
434 }
435 EX_CATCH
436 {
437 // We never expect an actual exception here (maybe in oom).
438 // If we get an exception, then simulate the default behavior for GetUnmanagedCallSite.
439 returnIP = NULL;
440 returnSP = NULL; // this will cause us to return true.
441 }
442 EX_END_CATCH(SwallowAllExceptions);
443
444 LOG((LF_CORDB, LL_INFO100000,
445 "DWSP: TYPE_EXIT: returnIP=0x%08x, returnSP=0x%08x, frame=0x%08x, threadFrame=0x%08x, regSP=0x%08x\n",
446 returnIP, returnSP, pFrame, pData->GetThread()->GetFrame(), GetRegdisplaySP(&pData->regDisplay)));
447
448 if (pPotentialFP != NULL)
449 {
450 *pPotentialFP = FramePointer::MakeFramePointer((void*)returnSP);
451 }
452
453 return ((pFrame != pData->GetThread()->GetFrame()) ||
454 (returnSP == NULL) ||
455 ((TADDR)GetRegdisplaySP(&pData->regDisplay) <= returnSP));
456
457#else // _TARGET_X86_
458 // DebuggerExitFrame always return a NULL returnSP on x86.
459 if (pFrame->GetVTablePtr() == DebuggerExitFrame::GetMethodFrameVPtr())
460 {
461 if (pPotentialFP != NULL)
462 {
463 *pPotentialFP = LEAF_MOST_FRAME;
464 }
465 return true;
466 }
467 else if (pFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr())
468 {
469 InlinedCallFrame *pInlinedFrame = static_cast<InlinedCallFrame *>(pFrame);
470 LPVOID sp = (LPVOID)pInlinedFrame->GetCallSiteSP();
471
472 // The sp returned below is the sp of the caller, which is either an IL stub in the normal case
473 // or a normal managed method in the inlined pinvoke case.
474 // This sp may be the same as the frame's address, so we need to use the largest
475 // possible bsp value to make sure that this frame pointer is closer to the root than
476 // the frame pointer made from the frame address itself.
477 if (pPotentialFP != NULL)
478 {
479 *pPotentialFP = FramePointer::MakeFramePointer( (LPVOID)sp );
480 }
481
482 return ((pFrame != pData->GetThread()->GetFrame()) ||
483 InlinedCallFrame::FrameHasActiveCall(pInlinedFrame));
484
485 }
486 else
487 {
488 // It'll be nice if there's a way to assert that the current frame is indeed of a
489 // derived class of TransitionFrame.
490 TransitionFrame *pTransFrame = static_cast<TransitionFrame*>(pFrame);
491 LPVOID sp = (LPVOID)pTransFrame->GetSP();
492
493 // The sp returned below is the sp of the caller, which is either an IL stub in the normal case
494 // or a normal managed method in the inlined pinvoke case.
495 // This sp may be the same as the frame's address, so we need to use the largest
496 // possible bsp value to make sure that this frame pointer is closer to the root than
497 // the frame pointer made from the frame address itself.
498 if (pPotentialFP != NULL)
499 {
500 *pPotentialFP = FramePointer::MakeFramePointer( (LPVOID)sp );
501 }
502
503 return true;
504 }
505#endif // _TARGET_X86_
506}
507
508#ifdef _DEBUG
509
510//-----------------------------------------------------------------------------
511// Debug helpers to get name of Frame.
512//-----------------------------------------------------------------------------
513LPCUTF8 FrameInfo::DbgGetClassName()
514{
515 return (md == NULL) ? ("None") : (md->m_pszDebugClassName);
516}
517LPCUTF8 FrameInfo::DbgGetMethodName()
518{
519 return (md == NULL) ? ("None") : (md->m_pszDebugMethodName);
520}
521
522
523//-----------------------------------------------------------------------------
524// Debug helper to asserts invariants about a FrameInfo before we dispatch it.
525//-----------------------------------------------------------------------------
526void FrameInfo::AssertValid()
527{
528 LIMITED_METHOD_CONTRACT;
529
530 bool fMethod = this->HasMethodFrame();
531 bool fStub = this->HasStubFrame();
532 bool fChain = this->HasChainMarker();
533
534 // Can't be both Stub & Chain
535 _ASSERTE(!fStub || !fChain);
536
537 // Must be at least a Method, Stub or Chain or Internal
538 _ASSERTE(fMethod || fStub || fChain || this->internal);
539
540 // Check Managed status is consistent
541 if (fMethod)
542 {
543 _ASSERTE(this->managed); // We only report managed methods
544 }
545 if (fChain)
546 {
547 if (!managed)
548 {
549 // Only certain chains can be unmanaged
550 _ASSERTE((this->chainReason == CHAIN_THREAD_START) ||
551 (this->chainReason == CHAIN_ENTER_UNMANAGED));
552 }
553 else
554 {
555 // UM chains can never be managed.
556 _ASSERTE((this->chainReason != CHAIN_ENTER_UNMANAGED));
557 }
558
559 }
560
561 // FramePointer should be valid
562 _ASSERTE(this->fp != LEAF_MOST_FRAME);
563 _ASSERTE((this->fp != ROOT_MOST_FRAME) || (chainReason== CHAIN_THREAD_START) || (chainReason == CHAIN_ENTER_UNMANAGED));
564
565 // If we have a Method, then we need an AppDomain.
566 // (RS will need it to do lookup)
567 if (fMethod)
568 {
569 _ASSERTE(currentAppDomain != NULL);
570 _ASSERTE(managed);
571 // Stubs may have a method w/o any code (eg, PInvoke wrapper).
572 // @todo - Frame::TYPE_TP_METHOD_FRAME breaks this assert. Are there other cases too?
573 //_ASSERTE(fStub || (pIJM != NULL));
574 }
575
576 if (fStub)
577 {
578 // All stubs (except LightWeightFunctions) match up w/a Frame.
579 _ASSERTE(this->frame || (eStubFrameType == STUBFRAME_LIGHTWEIGHT_FUNCTION));
580 }
581}
582#endif
583
584//-----------------------------------------------------------------------------
585// Get the DJI associated w/ this frame. This is a convenience function.
586// This is recommended over using MethodDescs because DJI's are version-aware.
587//-----------------------------------------------------------------------------
588DebuggerJitInfo * FrameInfo::GetJitInfoFromFrame()
589{
590 CONTRACTL
591 {
592 NOTHROW;
593 GC_NOTRIGGER;
594 }
595 CONTRACTL_END;
596
597 // Not all FrameInfo objects correspond to actual code.
598 if (HasChainMarker() || HasStubFrame() || (frame != NULL))
599 {
600 return NULL;
601 }
602
603 DebuggerJitInfo *ji = NULL;
604
605 // @todo - we shouldn't need both a MD and an IP here.
606 EX_TRY
607 {
608 _ASSERTE(this->md != NULL);
609 ji = g_pDebugger->GetJitInfo(this->md, (const BYTE*)GetControlPC(&(this->registers)));
610 _ASSERTE(ji != NULL);
611 _ASSERTE(ji->m_fd == this->md);
612 }
613 EX_CATCH
614 {
615 ji = NULL;
616 }
617 EX_END_CATCH(SwallowAllExceptions);
618
619 return ji;
620}
621
622//-----------------------------------------------------------------------------
623// Get the DMI associated w/ this frame. This is a convenience function.
624// DMIs are 1:1 with the (token, module) pair.
625//-----------------------------------------------------------------------------
626DebuggerMethodInfo * FrameInfo::GetMethodInfoFromFrameOrThrow()
627{
628 CONTRACTL
629 {
630 THROWS;
631 GC_NOTRIGGER;
632 }
633 CONTRACTL_END;
634
635 MethodDesc * pDesc = this->md;
636 mdMethodDef token = pDesc-> GetMemberDef();
637 Module * pRuntimeModule = pDesc->GetModule();
638
639 DebuggerMethodInfo *dmi = g_pDebugger->GetOrCreateMethodInfo(pRuntimeModule, token);
640 return dmi;
641}
642
643
644//-----------------------------------------------------------------------------
645// Init a FrameInfo for a UM chain.
646// We need a stackrange to give to an unmanaged debugger.
647// pRDSrc->Esp will provide the start (leaf) marker.
648// fpRoot will provide the end (root) portion.
649//-----------------------------------------------------------------------------
650void FrameInfo::InitForUMChain(FramePointer fpRoot, REGDISPLAY * pRDSrc)
651{
652 _ASSERTE(pRDSrc != NULL);
653
654 // Mark that we're an UM Chain (and nothing else).
655 this->frame = NULL;
656 this->md = NULL;
657
658 // Fp will be the end (root) of the stack range.
659 // pRDSrc->Sp will be the start (leaf) of the stack range.
660 CopyREGDISPLAY(&(this->registers), pRDSrc);
661 this->fp = fpRoot;
662
663 this->quickUnwind = false;
664 this->internal = false;
665 this->managed = false;
666
667 // These parts of the FrameInfo can be ignored for a UM chain.
668 this->relOffset = 0;
669 this->pIJM = NULL;
670 this->MethodToken = METHODTOKEN(NULL, 0);
671 this->currentAppDomain = NULL;
672 this->exactGenericArgsToken = NULL;
673
674 InitForScratchFrameInfo();
675
676 this->chainReason = CHAIN_ENTER_UNMANAGED;
677 this->eStubFrameType = STUBFRAME_NONE;
678
679#ifdef _DEBUG
680 FramePointer fpLeaf = GetSP(pRDSrc);
681 _ASSERTE(IsCloserToLeaf(fpLeaf, fpRoot));
682#endif
683
684#ifdef _DEBUG
685 // After we just init it, it had better be valid.
686 this->AssertValid();
687#endif
688}
689
690
691//---------------------------------------------------------------------------------------
692//
693// This is just a small helper to initialize the fields which are specific to 64-bit. Note that you should
694// only call this function on a scratch FrameInfo. Never call it on the FrameInfo used by the debugger
695// stackwalker to store information on the current frame.
696//
697
698void FrameInfo::InitForScratchFrameInfo()
699{
700#ifdef WIN64EXCEPTIONS
701 // The following flags cannot be trashed when we are calling this function on the curret FrameInfo
702 // (the one we keep track of across multiple stackwalker callbacks). Thus, make sure you do not call
703 // this function from InitForDynamicMethod(). In all other cases, we can call this method after we
704 // call InitFromStubHelper() because we are working on a local scratch variable.
705 this->fIsLeaf = false;
706 this->fIsFunclet = false;
707 this->fIsFilter = false;
708#endif // WIN64EXCEPTIONS
709}
710
711
712//-----------------------------------------------------------------------------
713//
714// Init a FrameInfo for a stub. Stub frames map to internal frames on the RS. Stubs which we care about
715// usually contain an explicit frame which translates to an internal frame on the RS. Dynamic method is
716// the sole exception.
717//
718// Arguments:
719// pCF - the CrawlFrame containing the state of the current frame
720// pMDHint - some stubs have associated MethodDesc but others don't,
721// which is why this argument can be NULL
722// type - the type of the stub/internal frame
723//
724
725void FrameInfo::InitFromStubHelper(
726 CrawlFrame * pCF,
727 MethodDesc * pMDHint, // NULL ok
728 CorDebugInternalFrameType type
729)
730{
731 _ASSERTE(pCF != NULL);
732
733 Frame * pFrame = pCF->GetFrame();
734
735 LOG((LF_CORDB, LL_EVERYTHING, "InitFromStubHelper. Frame=0x%p, type=%d\n", pFrame, type));
736
737 // All Stubs have a Frame except for LightWeight methods
738 _ASSERTE((type == STUBFRAME_LIGHTWEIGHT_FUNCTION) || (pFrame != NULL));
739 REGDISPLAY *pRDSrc = pCF->GetRegisterSet();
740
741 this->frame = pFrame;
742
743 // Stub frames may be associated w/ a Method (as a hint). However this method
744 // will never have a JitManager b/c it will never have IL (if it had IL, we'd be a
745 // regulare frame, not a stub frame)
746 this->md = pMDHint;
747
748 CopyREGDISPLAY(&this->registers, pRDSrc);
749
750 // FramePointer must match up w/ an EE Frame b/c that's how we match
751 // we Exception callbacks.
752 if (pFrame != NULL)
753 {
754 this->fp = FramePointer::MakeFramePointer(
755 (LPVOID) pFrame);
756 }
757 else
758 {
759 this->fp = GetSP(pRDSrc);
760 }
761
762 this->quickUnwind = false;
763 this->internal = false;
764 this->managed = true;
765 this->relOffset = 0;
766 this->ambientSP = NULL;
767
768
769 // Method associated w/a stub will never have a JitManager.
770 this->pIJM = NULL;
771 this->MethodToken = METHODTOKEN(NULL, 0);
772 this->currentAppDomain = pCF->GetAppDomain();
773 this->exactGenericArgsToken = NULL;
774
775 // Stub frames are mutually exclusive with chain markers.
776 this->chainReason = CHAIN_NONE;
777 this->eStubFrameType = type;
778
779#ifdef _DEBUG
780 // After we just init it, it had better be valid.
781 this->AssertValid();
782#endif
783}
784
785//-----------------------------------------------------------------------------
786// Initialize a FrameInfo to be used for an "InternalFrame"
787// Frame should be a derived class of FramedMethodFrame.
788// FrameInfo's MethodDesc will be for managed wrapper for native call.
789//-----------------------------------------------------------------------------
790void FrameInfo::InitForM2UInternalFrame(CrawlFrame * pCF)
791{
792 // For a M2U call, there's a managed method wrapping the unmanaged call. Use that.
793 Frame * pFrame = pCF->GetFrame();
794 _ASSERTE(pFrame->GetTransitionType() == Frame::TT_M2U);
795 FramedMethodFrame * pM2U = static_cast<FramedMethodFrame*> (pFrame);
796 MethodDesc * pMDWrapper = pM2U->GetFunction();
797
798 // Soem M2U transitions may not have a function associated w/ them,
799 // so pMDWrapper may be NULL. PInvokeCalliFrame is an example.
800
801 InitFromStubHelper(pCF, pMDWrapper, STUBFRAME_M2U);
802 InitForScratchFrameInfo();
803}
804
805//-----------------------------------------------------------------------------
806// Initialize for the U2M case...
807//-----------------------------------------------------------------------------
808void FrameInfo::InitForU2MInternalFrame(CrawlFrame * pCF)
809{
810 PREFIX_ASSUME(pCF != NULL);
811 MethodDesc * pMDHint = NULL;
812
813#ifdef FEATURE_COMINTEROP
814 Frame * pFrame = pCF->GetFrame();
815 PREFIX_ASSUME(pFrame != NULL);
816
817
818 // For regular U2M PInvoke cases, we don't care about MD b/c it's just going to
819 // be the next frame.
820 // If we're a COM2CLR call, perhaps we can get the MD for the interface.
821 if (pFrame->GetVTablePtr() == ComMethodFrame::GetMethodFrameVPtr())
822 {
823 ComMethodFrame* pCOMFrame = static_cast<ComMethodFrame*> (pFrame);
824 ComCallMethodDesc* pCMD = reinterpret_cast<ComCallMethodDesc *> (pCOMFrame->ComMethodFrame::GetDatum());
825 pMDHint = pCMD->GetInterfaceMethodDesc();
826
827 // Some COM-interop cases don't have an intermediate interface method desc, so
828 // pMDHint may be null.
829 }
830#endif
831
832 InitFromStubHelper(pCF, pMDHint, STUBFRAME_U2M);
833 InitForScratchFrameInfo();
834}
835
836//-----------------------------------------------------------------------------
837// Init for an AD transition
838//-----------------------------------------------------------------------------
839void FrameInfo::InitForADTransition(CrawlFrame * pCF)
840{
841 Frame * pFrame;
842 pFrame = pCF->GetFrame();
843 _ASSERTE(pFrame->GetTransitionType() == Frame::TT_AppDomain);
844 MethodDesc * pMDWrapper = NULL;
845
846 InitFromStubHelper(pCF, pMDWrapper, STUBFRAME_APPDOMAIN_TRANSITION);
847 InitForScratchFrameInfo();
848}
849
850
851//-----------------------------------------------------------------------------
852// Init frame for a dynamic method.
853//-----------------------------------------------------------------------------
854void FrameInfo::InitForDynamicMethod(CrawlFrame * pCF)
855{
856 // These are just stack markers that there's a dynamic method on the callstack.
857 InitFromStubHelper(pCF, NULL, STUBFRAME_LIGHTWEIGHT_FUNCTION);
858 // Do not call InitForScratchFrameInfo() here! Please refer to the comment in that function.
859}
860
861//-----------------------------------------------------------------------------
862// Init an internal frame to mark a func-eval.
863//-----------------------------------------------------------------------------
864void FrameInfo::InitForFuncEval(CrawlFrame * pCF)
865{
866 // We don't store a MethodDesc hint referring to the method we're going to invoke because
867 // uses of stub frames will assume the MD is relative to the AppDomain the frame is in.
868 // For cross-AD funcevals, we're invoking a method in a domain other than the one this frame
869 // is in.
870 MethodDesc * pMDHint = NULL;
871
872 // Add a stub frame here to mark that there is a FuncEvalFrame on the stack.
873 InitFromStubHelper(pCF, pMDHint, STUBFRAME_FUNC_EVAL);
874 InitForScratchFrameInfo();
875}
876
877
878//---------------------------------------------------------------------------------------
879//
880// Initialize a FrameInfo for sending the CHAIN_THREAD_START reason.
881// The common case is that the chain is NOT managed, since the lowest (closest to the root) managed method
882// is usually called from unmanaged code. In fact, in Whidbey, we should never have a managed chain.
883//
884// Arguments:
885// pRDSrc - a REGDISPLAY for the beginning (the leafmost frame) of the chain
886//
887void FrameInfo::InitForThreadStart(Thread * pThread, REGDISPLAY * pRDSrc)
888{
889 this->frame = (Frame *) FRAME_TOP;
890 this->md = NULL;
891 CopyREGDISPLAY(&(this->registers), pRDSrc);
892 this->fp = FramePointer::MakeFramePointer(pThread->GetCachedStackBase());
893 this->quickUnwind = false;
894 this->internal = false;
895 this->managed = false;
896 this->relOffset = 0;
897 this->pIJM = NULL;
898 this->MethodToken = METHODTOKEN(NULL, 0);
899
900 this->currentAppDomain = NULL;
901 this->exactGenericArgsToken = NULL;
902
903 InitForScratchFrameInfo();
904
905 this->chainReason = CHAIN_THREAD_START;
906 this->eStubFrameType = STUBFRAME_NONE;
907
908#ifdef _DEBUG
909 // After we just init it, it had better be valid.
910 this->AssertValid();
911#endif
912}
913
914
915//---------------------------------------------------------------------------------------
916//
917// Initialize a FrameInfo for sending a CHAIN_ENTER_MANAGED.
918// A Enter-Managed chain is always sent immediately before an UM chain, meaning that the Enter-Managed chain
919// is closer to the leaf than the UM chain.
920//
921// Arguments:
922// fpRoot - This is the frame pointer for the Enter-Managed chain. It is currently arbitrarily set
923// to be one stack slot higher (closer to the leaf) than the frame pointer of the beginning
924// of the upcoming UM chain.
925//
926
927void FrameInfo::InitForEnterManagedChain(FramePointer fpRoot)
928{
929 // Nobody should use a EnterManagedChain's Frame*, but there's no
930 // good value to enforce that.
931 this->frame = (Frame *) FRAME_TOP;
932 this->md = NULL;
933 memset((void *)&this->registers, 0, sizeof(this->registers));
934 this->fp = fpRoot;
935
936 this->quickUnwind = true;
937 this->internal = false;
938 this->managed = true;
939 this->relOffset = 0;
940 this->pIJM = NULL;
941 this->MethodToken = METHODTOKEN(NULL, 0);
942
943 this->currentAppDomain = NULL;
944 this->exactGenericArgsToken = NULL;
945
946 InitForScratchFrameInfo();
947
948 this->chainReason = CHAIN_ENTER_MANAGED;
949 this->eStubFrameType = STUBFRAME_NONE;
950}
951
952//-----------------------------------------------------------------------------
953// Do tracking for UM chains.
954// This may invoke the UMChain callback and M2U callback.
955//-----------------------------------------------------------------------------
956StackWalkAction TrackUMChain(CrawlFrame *pCF, DebuggerFrameData *d)
957{
958 Frame *frame = g_pEEInterface->GetFrame(pCF);
959
960 // If we encounter an ExitFrame out in the wild, then we'll convert it to an UM chain.
961 if (!d->IsTrackingUMChain())
962 {
963 if ((frame != NULL) && (frame != FRAME_TOP) && (frame->GetFrameType() == Frame::TYPE_EXIT))
964 {
965 LOG((LF_CORDB, LL_EVERYTHING, "DWSP. ExitFrame while not tracking\n"));
966 REGDISPLAY* pRDSrc = pCF->GetRegisterSet();
967
968 d->BeginTrackingUMChain(GetSP(pRDSrc), pRDSrc);
969
970 // fall through and we'll send the UM chain.
971 }
972 else
973 {
974 return SWA_CONTINUE;
975 }
976 }
977
978 _ASSERTE(d->IsTrackingUMChain());
979
980
981 // If we're tracking an UM chain, then we need to:
982 // - possibly refine the start & end values as we get new information in the stacktrace.
983 // - possibly cancel the UM chain for various heuristics.
984 // - possibly dispatch if we've hit managed code again.
985
986 bool fDispatchUMChain = false;
987 // UM Chain stops when managed code starts again.
988 if (frame != NULL)
989 {
990 // If it's just a EE Frame, then update this as a possible end of stack range for the UM chain.
991 // (The end of a stack range is closer to the root.)
992 d->SetUMChainEnd(FramePointer::MakeFramePointer((LPVOID)(frame)));
993
994
995 Frame::ETransitionType t = frame->GetTransitionType();
996 int ft = frame->GetFrameType();
997
998
999 // Sometimes we may not want to show an UM chain b/c we know it's just
1000 // code inside of mscorwks. (Eg: Funcevals & AD transitions both fall into this category).
1001 // These are perfectly valid UM chains and we could give them if we wanted to.
1002 if ((t == Frame::TT_AppDomain) || (ft == Frame::TYPE_FUNC_EVAL))
1003 {
1004 d->CancelUMChain();
1005 return SWA_CONTINUE;
1006 }
1007
1008 // If we hit an M2U frame, then go ahead and dispatch the UM chain now.
1009 // This will likely also be an exit frame.
1010 if (t == Frame::TT_M2U)
1011 {
1012 fDispatchUMChain = true;
1013 }
1014
1015 // If we get an Exit frame, we can use that to "prune" the UM chain to a more friendly state.
1016 // This heuristic is optional, it just eliminates lots of internal mscorwks frames from the callstack.
1017 // Note that this heuristic is only useful if we get a callback on the entry frame
1018 // (e.g. UMThkCallFrame) between the callback on the native marker and the callback on the exit frame.
1019 // Otherwise the REGDISPLAY will be the same.
1020 if (ft == Frame::TYPE_EXIT)
1021 {
1022 // If we have a valid reg-display (non-null IP) then update it.
1023 // We may have an invalid reg-display if we have an exit frame on an inactive thread.
1024 REGDISPLAY * pNewRD = pCF->GetRegisterSet();
1025 if (GetControlPC(pNewRD) != NULL)
1026 {
1027 LOG((LF_CORDB, LL_EVERYTHING, "DWSP. updating RD while tracking UM chain\n"));
1028 CopyREGDISPLAY(d->GetUMChainStartRD(), pNewRD);
1029 }
1030
1031 FramePointer fpLeaf = GetSP(d->GetUMChainStartRD());
1032 _ASSERTE(IsCloserToLeaf(fpLeaf, d->GetUMChainEnd()));
1033
1034
1035 _ASSERTE(!d->fHitExitFrame); // should only have 1 exit frame per UM chain code.
1036 d->fHitExitFrame = true;
1037
1038 FramePointer potentialFP;
1039
1040 FramePointer fpNewChainEnd = d->GetUMChainEnd();
1041
1042 // Check to see if we are inside the unmanaged call. We want to make sure we only report an exit frame after
1043 // we've really exited. There is a short period between where we setup the frame and when we actually exit
1044 // the runtime. This check is intended to ensure we're actually outside now.
1045 if (HasExitRuntime(frame, d, &potentialFP))
1046 {
1047 LOG((LF_CORDB, LL_EVERYTHING, "HasExitRuntime. potentialFP=0x%p\n", potentialFP.GetSPValue()));
1048
1049 // If we have no call site, manufacture a FP using the current frame.
1050 // If we do have a call site, then the FP is actually going to be the caller SP,
1051 // where the caller is the last managed method before calling out to unmanaged code.
1052 if (potentialFP == LEAF_MOST_FRAME)
1053 {
1054 fpNewChainEnd = FramePointer::MakeFramePointer((LPVOID)((BYTE*)frame - sizeof(LPVOID)));
1055 }
1056 else
1057 {
1058 fpNewChainEnd = potentialFP;
1059 }
1060
1061 }
1062 // For IL stubs, we may actually push an uninitialized InlinedCallFrame frame onto the frame chain
1063 // in jitted managed code, and then later on initialize it in a native runtime helper. In this case, if
1064 // HasExitRuntime() is false (meaning the frame is uninitialized), then we are actually still in managed
1065 // code and have not made the call to native code yet, so we should report an unmanaged chain.
1066 else
1067 {
1068 d->CancelUMChain();
1069 return SWA_CONTINUE;
1070 }
1071
1072 fDispatchUMChain = true;
1073
1074 // If we got a valid chain end, then prune the UM chain accordingly.
1075 // Note that some EE Frames will give invalid info back so we have to check.
1076 // PInvokeCalliFrame is one example (when doing MC++ function pointers)
1077 if (IsCloserToRoot(fpNewChainEnd, fpLeaf))
1078 {
1079 d->SetUMChainEnd(fpNewChainEnd);
1080 }
1081 else
1082 {
1083 _ASSERTE(IsCloserToLeaf(fpLeaf, d->GetUMChainEnd()));
1084 }
1085 } // end ExitFrame
1086
1087 // Only CLR internal code / stubs can push Frames onto the Frame chain.
1088 // So if we hit a raw interceptor frame before we hit any managed frame, then this whole
1089 // UM chain must still be in CLR internal code.
1090 // Either way, this UM chain has ended (and some new chain based off the frame has started)
1091 // so we need to either Cancel the chain or dispatch it.
1092 if (frame->GetInterception() != Frame::INTERCEPTION_NONE)
1093 {
1094 // Interceptors may contain calls out to unmanaged code (such as unmanaged dllmain when
1095 // loading a new dll), so we need to dispatch these.
1096 // These extra UM chains don't show in Everett, and so everett debuggers on whidbey
1097 // may see new chains.
1098 // We need to ensure that whidbey debuggers are updated first.
1099 fDispatchUMChain = true;
1100 }
1101 }
1102 else
1103 {
1104 // If it's a real method (not just an EE Frame), then the UM chain is over.
1105 fDispatchUMChain = true;
1106 }
1107
1108
1109 if (fDispatchUMChain)
1110 {
1111 // Check if we should cancel the UM chain.
1112
1113 // We need to discriminate between the following 2 cases:
1114 // 1) Managed -(a)-> mscorwks -(b)-> Managed (leaf)
1115 // 2) Native -(a)-> mscorwks -(b)-> Managed (leaf)
1116 //
1117 // --INCORRECT RATIONALE SEE "CORRECTION" BELOW--
1118 // Case 1 could happen if a managed call injects a stub (such as w/ delegates).
1119 // In both cases, the (mscorwks-(b)->managed) transition causes a IsNativeMarker callback
1120 // which initiates a UM chain. In case 1, we want to cancel the UM chain, but
1121 // in case 2 we want to dispatch it.
1122 // The difference is case #2 will have some EE Frame at (b) and case #1 won't.
1123 // That EE Frame should have caused us to dispatch the call for the managed method, and
1124 // thus by the time we get around to dispatching the UM Chain, we shouldn't have a managed
1125 // method waiting to be dispatched in the DebuggerFrameData.
1126 // --END INCORRECT RATIONALE--
1127 //
1128 // This is kind of messed up. First of all, the assertions on case 2 is not true on 64-bit.
1129 // We won't have an explicit frame at (b). Secondly, case 1 is not always true either.
1130 // Consider the case where we are calling a cctor at prestub time. This is what the stack may
1131 // look like: managed -> PrestubMethodFrame -> GCFrame -> managed (cctor) (leaf). In this case,
1132 // we will actually send the UM chain because we will have dispatched the call for the managed
1133 // method (the cctor) when we get a callback for the GCFrame.
1134 //
1135 // --INCORRECT SEE "CORRECTION" BELOW--
1136 // Keep in mind that this is just a heuristic to reduce the number of UM chains we are sending
1137 // over to the RS.
1138 // --END INCORRECT --
1139 //
1140 // CORRECTION: These UM chains also feed into the results of at least ControllerStackInfo and probably other
1141 // places. Issue 650903 is a concrete example of how not filtering a UM chain causes correctness
1142 // issues in the LS. This code may still have bugs in it based on those incorrect assumptions.
1143 // A narrow fix for 650903 is the only thing that was changed at the time of adding this comment.
1144 if (d->needParentInfo && d->info.HasMethodFrame())
1145 {
1146 LOG((LF_CORDB, LL_EVERYTHING, "Cancelling UM Chain b/c it's internal\n"));
1147 d->CancelUMChain();
1148 return SWA_CONTINUE;
1149 }
1150
1151 // If we're NOT ignoring non-method frames, and we didn't get an explicit ExitFrame somewhere
1152 // in this chain, then don't send the non-leaf UM chain.
1153 // The practical cause here is that w/o an exit frame, we don't know where the UM chain
1154 // is starting (could be from anywhere in mscorwks). And we can't patch any random spot in
1155 // mscorwks.
1156 // Sending leaf-UM chains is OK b/c we can't step-out to them (they're the leaf, duh).
1157 // (ignoreNonmethodFrames is generally false for stepping and true for regular
1158 // end-user stacktraces.)
1159 //
1160 // This check is probably unnecessary. The client of the debugger stackwalker should make
1161 // the decision themselves as to what to do with the UM chain callbacks.
1162 //
1163 // -- INCORRECT SEE SEE "CORRECTION" BELOW --
1164 // Currently, both
1165 // ControllerStackInfo and InterceptorStackInfo ignore UM chains completely anyway.
1166 // (For an example, refer to the cctor example in the previous comment.)
1167 // -- END INCORRECT --
1168 //
1169 // CORRECTION: See issue 650903 for a concrete example of ControllerStackInfo getting a different
1170 // result based on a UM chain that wasn't filtered. This code may still have issues in
1171 // it based on those incorrect assumptions. A narrow fix for 650903 is the only thing
1172 // that was changed at the time of adding this comment.
1173 if (!d->fHitExitFrame && !d->ShouldIgnoreNonmethodFrames() && !d->IsLeafCallback())
1174 {
1175 LOG((LF_CORDB, LL_EVERYTHING, "Cancelling UM Chain b/c it's stepper not requested\n"));
1176 d->CancelUMChain();
1177 return SWA_CONTINUE;
1178 }
1179
1180
1181 // Ok, we haven't cancelled it yet, so go ahead and send the UM chain.
1182 FrameInfo f;
1183 FramePointer fpRoot = d->GetUMChainEnd();
1184 FramePointer fpLeaf = GetSP(d->GetUMChainStartRD());
1185
1186 // If we didn't actually get any range, then don't bother sending it.
1187 if (fpRoot == fpLeaf)
1188 {
1189 d->CancelUMChain();
1190 return SWA_CONTINUE;
1191 }
1192
1193 f.InitForUMChain(fpRoot, d->GetUMChainStartRD());
1194
1195#ifdef FEATURE_COMINTEROP
1196 if ((frame != NULL) &&
1197 (frame->GetVTablePtr() == ComPlusMethodFrame::GetMethodFrameVPtr()))
1198 {
1199 // This condition is part of the fix for 650903. (See
1200 // code:ControllerStackInfo::WalkStack and code:DebuggerStepper::TrapStepOut
1201 // for the other parts.) Here, we know that the frame we're looking it may be
1202 // a ComPlusMethodFrameGeneric (this info is not otherwise plubmed down into
1203 // the walker; even though the walker does get to see "f.frame", that may not
1204 // be "frame"). Given this, if the walker chooses to ignore these frames
1205 // (while doing a Step Out during managed-only debugging), then it can ignore
1206 // this frame.
1207 f.fIgnoreThisFrameIfSuppressingUMChainFromComPlusMethodFrameGeneric = true;
1208 }
1209#endif // FEATURE_COMINTEROP
1210
1211 if (d->InvokeCallback(&f) == SWA_ABORT)
1212 {
1213 // don't need to cancel if they abort.
1214 return SWA_ABORT;
1215 }
1216 d->CancelUMChain(); // now that we've sent it, we're done.
1217
1218
1219 // Check for a M2U internal frame.
1220 if (d->ShouldProvideInternalFrames() && (frame != NULL) && (frame != FRAME_TOP))
1221 {
1222 // We want to dispatch a M2U transition right after we dispatch the UM chain.
1223 Frame::ETransitionType t = frame->GetTransitionType();
1224 if (t == Frame::TT_M2U)
1225 {
1226 // Frame for a M2U transition.
1227 FrameInfo fM2U;
1228 fM2U.InitForM2UInternalFrame(pCF);
1229 if (d->InvokeCallback(&fM2U) == SWA_ABORT)
1230 {
1231 return SWA_ABORT;
1232 }
1233 }
1234 }
1235
1236
1237 }
1238
1239 return SWA_CONTINUE;
1240}
1241
1242//---------------------------------------------------------------------------------------
1243//
1244// A frame pointer is a unique identifier for a particular stack location. This function returns the
1245// frame pointer for the current frame, whether it is a method frame or an explicit frame.
1246//
1247// Arguments:
1248// pData - the state of the current frame maintained by the debugger stackwalker
1249// pCF - the CrawlFrame for the current callback by the real stackwalker (i.e. StackWalkFramesEx());
1250// this is NULL for the case where we fake an extra callbakc to top off a debugger stackwalk
1251//
1252// Return Value:
1253// the frame pointer for the current frame
1254//
1255
1256FramePointer GetFramePointerForDebugger(DebuggerFrameData* pData, CrawlFrame* pCF)
1257{
1258 CONTRACTL
1259 {
1260 NOTHROW;
1261 GC_NOTRIGGER;
1262 MODE_ANY;
1263 }
1264 CONTRACTL_END;
1265
1266 FramePointer fpResult;
1267
1268#if defined(WIN64EXCEPTIONS)
1269 if (pData->info.frame == NULL)
1270 {
1271 // This is a managed method frame.
1272 fpResult = FramePointer::MakeFramePointer((LPVOID)GetRegdisplayStackMark(&pData->info.registers));
1273 }
1274 else
1275 {
1276 // This is an actual frame.
1277 fpResult = FramePointer::MakeFramePointer((LPVOID)(pData->info.frame));
1278 }
1279
1280#else // !WIN64EXCEPTIONS
1281 if ((pCF == NULL || !pCF->IsFrameless()) && pData->info.frame != NULL)
1282 {
1283 //
1284 // If we're in an explicit frame now, and the previous frame was
1285 // also an explicit frame, pPC will not have been updated. So
1286 // use the address of the frame itself as fp.
1287 //
1288 fpResult = FramePointer::MakeFramePointer((LPVOID)(pData->info.frame));
1289
1290 LOG((LF_CORDB, LL_INFO100000, "GFPFD: Two explicit frames in a row; using frame address 0x%p\n",
1291 pData->info.frame));
1292 }
1293 else
1294 {
1295 //
1296 // Otherwise use pPC as the frame pointer, as this will be
1297 // pointing to the return address on the stack.
1298 //
1299 fpResult = FramePointer::MakeFramePointer((LPVOID)GetRegdisplayStackMark(&(pData->regDisplay)));
1300 }
1301
1302#endif // !WIN64EXCEPTIONS
1303
1304 LOG((LF_CORDB, LL_INFO100000, "GFPFD: Frame pointer is 0x%p\n", fpResult.GetSPValue()));
1305
1306 return fpResult;
1307}
1308
1309
1310#ifdef WIN64EXCEPTIONS
1311//---------------------------------------------------------------------------------------
1312//
1313// This function is called to determine if we should start skipping funclets. If we should, then we return the
1314// frame pointer for the parent method frame. Otherwise we return LEAF_MOST_FRAME. If we are already skipping
1315// frames, then we return the current frame pointer for the parent method frame.
1316//
1317// The return value of this function corresponds to the return value of ExceptionTracker::FindParentStackFrame().
1318// Refer to that function for more information.
1319//
1320// Arguments:
1321// fpCurrentParentMarker - This is the current frame pointer of the parent method frame. It can be
1322// LEAF_MOST_FRAME if we are not currently skipping funclets.
1323// pCF - the CrawlFrame for the current callback from the real stackwalker
1324// fIsNonFilterFuncletFrame - whether the current frame is a non-filter funclet frame
1325//
1326// Return Value:
1327// LEAF_MOST_FRAME - skipping not required
1328// ROOT_MOST_FRAME - skip one frame and try again
1329// anything else - skip all frames up to but not including the returned frame pointer
1330//
1331
1332inline FramePointer CheckForParentFP(FramePointer fpCurrentParentMarker, CrawlFrame* pCF, bool fIsNonFilterFuncletFrame)
1333{
1334 WRAPPER_NO_CONTRACT;
1335
1336 if (fpCurrentParentMarker == LEAF_MOST_FRAME)
1337 {
1338 // When we encounter a funclet, we simply stop processing frames until we hit the parent
1339 // of the funclet. Funclets and their parents have the same MethodDesc pointers, and they
1340 // should really be treated as one frame. However, we report both of them and let the callers
1341 // decide what they want to do with them. For example, DebuggerThread::TraceAndSendStack()
1342 // should never report both frames, but ControllerStackInfo::GetStackInfo() may need both to
1343 // determine where to put a patch. We use the fpParent as a flag to indicate if we are
1344 // searching for a parent of a funclet.
1345 //
1346 // Note that filter funclets are an exception. We don't skip them.
1347 if (fIsNonFilterFuncletFrame)
1348 {
1349 // We really should be using the same structure, but FramePointer is used everywhere in the debugger......
1350 StackFrame sfParent = g_pEEInterface->FindParentStackFrame(pCF);
1351 return FramePointer::MakeFramePointer((LPVOID)sfParent.SP);
1352 }
1353 else
1354 {
1355 return LEAF_MOST_FRAME;
1356 }
1357 }
1358 else
1359 {
1360 // Just return the current marker if we are already skipping frames.
1361 return fpCurrentParentMarker;
1362 }
1363}
1364#endif // WIN64EXCEPTIONS
1365
1366
1367//-----------------------------------------------------------------------------
1368// StackWalkAction DebuggerWalkStackProc(): This is the callback called
1369// by the EE stackwalker.
1370// Note that since we don't know what the frame pointer for frame
1371// X is until we've looked at the caller of frame X, we actually end up
1372// stashing the info and pData pointers in the DebuggerFrameDat struct, and
1373// then invoking pCallback when we've moved up one level, into the caller's
1374// frame. We use the needParentInfo field to indicate that the previous frame
1375// needed this (parental) info, and so when it's true we should invoke
1376// pCallback.
1377// What happens is this: if the previous frame set needParentInfo, then we
1378// do pCallback (and set needParentInfo to false).
1379// Then we look at the current frame - if it's frameless (ie,
1380// managed), then we set needParentInfo to callback in the next frame.
1381// Otherwise we must be at a chain boundary, and so we set the chain reason
1382// appropriately. We then figure out what type of frame it is, setting
1383// flags depending on the type. If the user should see this frame, then
1384// we'll set needParentInfo to record it's existence. Lastly, if we're in
1385// a funky frame, we'll explicitly update the register set, since the
1386// CrawlFrame doesn't do it automatically.
1387//-----------------------------------------------------------------------------
1388StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
1389{
1390 DebuggerFrameData *d = (DebuggerFrameData *)data;
1391
1392 if (pCF->IsNativeMarker())
1393 {
1394#ifdef WIN64EXCEPTIONS
1395 // The tricky part here is that we want to skip all frames between a funclet method frame
1396 // and the parent method frame UNLESS the funclet is a filter. Moreover, we should never
1397 // let a native marker execute the rest of this method, so we just short-circuit it here.
1398 if ((d->fpParent != LEAF_MOST_FRAME) || d->info.IsNonFilterFuncletFrame())
1399 {
1400 return SWA_CONTINUE;
1401 }
1402#endif // WIN64EXCEPTIONS
1403
1404 // This REGDISPLAY is for the native method immediately following the managed method for which
1405 // we have received the previous callback, i.e. the native caller of the last managed method
1406 // we have encountered.
1407 REGDISPLAY* pRDSrc = pCF->GetRegisterSet();
1408 d->BeginTrackingUMChain(GetSP(pRDSrc), pRDSrc);
1409
1410 return SWA_CONTINUE;
1411 }
1412
1413 // Note that a CrawlFrame may have both a methoddesc & an EE Frame.
1414 Frame *frame = g_pEEInterface->GetFrame(pCF);
1415 MethodDesc *md = pCF->GetFunction();
1416
1417 LOG((LF_CORDB, LL_EVERYTHING, "Calling DebuggerWalkStackProc. Frame=0x%p, md=0x%p(%s), native_marker=%d\n",
1418 frame, md, (md == NULL || md == (MethodDesc*)POISONC) ? "null" : md->m_pszDebugMethodName, pCF->IsNativeMarker() ));
1419
1420 // The fp for a frame must be obtained from the _next_ frame. Fill it in now for the previous frame, if appropriate.
1421 if (d->needParentInfo)
1422 {
1423 LOG((LF_CORDB, LL_INFO100000, "DWSP: NeedParentInfo.\n"));
1424
1425 d->info.fp = GetFramePointerForDebugger(d, pCF);
1426
1427#if defined(_DEBUG) && !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_)
1428 // Make sure the stackwalk is making progress.
1429 // On ARM this is invalid as the stack pointer does necessarily have to move when unwinding a frame.
1430 _ASSERTE(IsCloserToLeaf(d->previousFP, d->info.fp));
1431
1432 d->previousFP = d->info.fp;
1433#endif // _DEBUG && !_TARGET_ARM_
1434
1435 d->needParentInfo = false;
1436
1437 {
1438 // Don't invoke Stubs if we're not asking for internal frames.
1439 bool fDoInvoke = true;
1440 if (!d->ShouldProvideInternalFrames())
1441 {
1442 if (d->info.HasStubFrame())
1443 {
1444 fDoInvoke = false;
1445 }
1446 }
1447
1448 LOG((LF_CORDB, LL_INFO1000000, "DWSP: handling our target\n"));
1449
1450 if (fDoInvoke)
1451 {
1452 if (d->InvokeCallback(&d->info) == SWA_ABORT)
1453 {
1454 return SWA_ABORT;
1455 }
1456 }
1457
1458 // @todo - eventually we should be initing our frame-infos properly
1459 // and thus should be able to remove this.
1460 d->info.eStubFrameType = STUBFRAME_NONE;
1461 }
1462 } // if (d->needParentInfo)
1463
1464
1465#ifdef WIN64EXCEPTIONS
1466 // The tricky part here is that we want to skip all frames between a funclet method frame
1467 // and the parent method frame UNLESS the funclet is a filter. We only have to check for fpParent
1468 // here (instead of checking d->info.fIsFunclet and d->info.fIsFilter as well, as in the beginning of
1469 // this method) is because at this point, fpParent is already set by the code above.
1470 if (d->fpParent == LEAF_MOST_FRAME)
1471#endif // WIN64EXCEPTIONS
1472 {
1473 // Track the UM chain after we flush any managed goo from the last iteration.
1474 if (TrackUMChain(pCF, d) == SWA_ABORT)
1475 {
1476 return SWA_ABORT;
1477 }
1478 }
1479
1480
1481 // Track if we want to send a callback for this Frame / Method
1482 bool use=false;
1483
1484 //
1485 // Examine the frame.
1486 //
1487
1488 // We assume that the stack walker is just updating the
1489 // register display we passed in - assert it to be sure
1490 _ASSERTE(pCF->GetRegisterSet() == &d->regDisplay);
1491
1492#ifdef WIN64EXCEPTIONS
1493 Frame* pPrevFrame = d->info.frame;
1494
1495 // Here we need to determine if we are in a non-leaf frame, in which case we want to adjust the relative offset.
1496 // Also, we need to check if this frame has faulted (throws a native exception), since if it has, then it should be
1497 // considered the leaf frame (and thus we don't need to update the relative offset).
1498 if (pCF->IsActiveFrame() || pCF->HasFaulted())
1499 {
1500 d->info.fIsLeaf = true;
1501 }
1502 else if ( (pPrevFrame != NULL) &&
1503 (pPrevFrame->GetFrameType() == Frame::TYPE_EXIT) &&
1504 !HasExitRuntime(pPrevFrame, d, NULL) )
1505 {
1506 // This is for the inlined NDirectMethodFrameGeneric case. We have not exit the runtime yet, so the current
1507 // frame should still be regarded as the leaf frame.
1508 d->info.fIsLeaf = true;
1509 }
1510 else
1511 {
1512 d->info.fIsLeaf = false;
1513 }
1514
1515 d->info.fIsFunclet = pCF->IsFunclet();
1516 d->info.fIsFilter = false;
1517 if (d->info.fIsFunclet)
1518 {
1519 d->info.fIsFilter = pCF->IsFilterFunclet();
1520 }
1521
1522 if (pCF->IsFrameless())
1523 {
1524 // Check if we are skipping.
1525 if (d->fpParent != LEAF_MOST_FRAME)
1526 {
1527 // If fpParent is ROOT_MOST_FRAME, then we just need to skip one frame. Otherwise, we should stop
1528 // skipping if the current frame pointer matches fpParent. In either case, clear fpParent, and
1529 // then check again.
1530 if ((d->fpParent == ROOT_MOST_FRAME) ||
1531 ExceptionTracker::IsUnwoundToTargetParentFrame(pCF, ConvertFPToStackFrame(d->fpParent)))
1532 {
1533 LOG((LF_CORDB, LL_INFO100000, "DWSP: Stopping to skip funclet at 0x%p.\n", d->fpParent.GetSPValue()));
1534
1535 d->fpParent = LEAF_MOST_FRAME;
1536 d->fpParent = CheckForParentFP(d->fpParent, pCF, d->info.IsNonFilterFuncletFrame());
1537 }
1538 }
1539 }
1540
1541#endif // WIN64EXCEPTIONS
1542
1543 d->info.frame = frame;
1544 d->info.ambientSP = NULL;
1545
1546 // Record the appdomain that the thread was in when it
1547 // was running code for this frame.
1548 d->info.currentAppDomain = pCF->GetAppDomain();
1549
1550 // Grab all the info from CrawlFrame that we need to
1551 // check for "Am I in an exeption code blob?" now.
1552
1553#ifdef WIN64EXCEPTIONS
1554 // We are still searching for the parent of the last funclet we encounter.
1555 if (d->fpParent != LEAF_MOST_FRAME)
1556 {
1557 // We do nothing here.
1558 LOG((LF_CORDB, LL_INFO100000, "DWSP: Skipping to parent method frame at 0x%p.\n", d->fpParent.GetSPValue()));
1559 }
1560 else
1561#endif // WIN64EXCEPTIONS
1562 // We should ignore IL stubs with no frames in our stackwalking.
1563 // The only exception is dynamic methods. We want to report them when SIS is turned on.
1564 if ((md != NULL) && md->IsILStub() && pCF->IsFrameless())
1565 {
1566#ifdef FEATURE_MULTICASTSTUB_AS_IL
1567 if(md->AsDynamicMethodDesc()->IsMulticastStub())
1568 {
1569 use = true;
1570 d->info.managed = true;
1571 d->info.internal = false;
1572 }
1573#endif
1574 // We do nothing here.
1575 LOG((LF_CORDB, LL_INFO100000, "DWSP: Skip frameless IL stub.\n"));
1576 }
1577 else
1578 // For frames w/o method data, send them as an internal stub frame.
1579 if ((md != NULL) && md->IsDynamicMethod())
1580 {
1581 // Only Send the frame if "InternalFrames" are requested.
1582 // Else completely ignore it.
1583 if (d->ShouldProvideInternalFrames())
1584 {
1585 d->info.InitForDynamicMethod(pCF);
1586
1587 // We'll loop around to get the FramePointer. Only modification to FrameInfo
1588 // after this is filling in framepointer and resetting MD.
1589 use = true;
1590 }
1591 }
1592 else if (pCF->IsFrameless())
1593 {
1594 // Regular managed-method.
1595 LOG((LF_CORDB, LL_INFO100000, "DWSP: Is frameless.\n"));
1596 use = true;
1597 d->info.managed = true;
1598 d->info.internal = false;
1599 d->info.chainReason = CHAIN_NONE;
1600 d->needParentInfo = true; // Possibly need chain reason
1601 d->info.relOffset = AdjustRelOffset(pCF, &(d->info));
1602 d->info.pIJM = pCF->GetJitManager();
1603 d->info.MethodToken = pCF->GetMethodToken();
1604
1605#ifdef _TARGET_X86_
1606 // This is collecting the ambientSP a lot more than we actually need it. Only time we need it is
1607 // inspecting local vars that are based off the ambient esp.
1608 d->info.ambientSP = pCF->GetAmbientSPFromCrawlFrame();
1609#endif
1610 }
1611 else
1612 {
1613 d->info.pIJM = NULL;
1614 d->info.MethodToken = METHODTOKEN(NULL, 0);
1615
1616 //
1617 // Retrieve any interception info
1618 //
1619
1620 // Each interception type in the switch statement below is associated with a chain reason.
1621 // The other chain reasons are:
1622 // CHAIN_INTERCEPTION - not used
1623 // CHAIN_PROCESS_START - not used
1624 // CHAIN_THREAD_START - thread start
1625 // CHAIN_ENTER_MANAGED - managed chain
1626 // CHAIN_ENTER_UNMANAGED - unmanaged chain
1627 // CHAIN_DEBUGGER_EVAL - not used
1628 // CHAIN_CONTEXT_SWITCH - not used
1629 // CHAIN_FUNC_EVAL - funceval
1630
1631 switch (frame->GetInterception())
1632 {
1633 case Frame::INTERCEPTION_CLASS_INIT:
1634 //
1635 // Fall through
1636 //
1637
1638 // V2 assumes that the only thing the prestub intercepts is the class constructor
1639 case Frame::INTERCEPTION_PRESTUB:
1640 d->info.chainReason = CHAIN_CLASS_INIT;
1641 break;
1642
1643 case Frame::INTERCEPTION_EXCEPTION:
1644 d->info.chainReason = CHAIN_EXCEPTION_FILTER;
1645 break;
1646
1647 case Frame::INTERCEPTION_CONTEXT:
1648 d->info.chainReason = CHAIN_CONTEXT_POLICY;
1649 break;
1650
1651 case Frame::INTERCEPTION_SECURITY:
1652 d->info.chainReason = CHAIN_SECURITY;
1653 break;
1654
1655 default:
1656 d->info.chainReason = CHAIN_NONE;
1657 }
1658
1659 //
1660 // Look at the frame type to figure out how to treat it.
1661 //
1662
1663 LOG((LF_CORDB, LL_INFO100000, "DWSP: Chain reason is 0x%X.\n", d->info.chainReason));
1664
1665 switch (frame->GetFrameType())
1666 {
1667 case Frame::TYPE_ENTRY: // We now ignore entry + exit frames.
1668 case Frame::TYPE_EXIT:
1669 case Frame::TYPE_HELPER_METHOD_FRAME:
1670 case Frame::TYPE_INTERNAL:
1671
1672 /* If we have a specific interception type, use it. However, if this
1673 is the top-most frame (with a specific type), we can ignore it
1674 and it wont appear in the stack-trace */
1675#define INTERNAL_FRAME_ACTION(d, use) \
1676 (d)->info.managed = true; \
1677 (d)->info.internal = false; \
1678 use = true
1679
1680 LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_INTERNAL.\n"));
1681 if (d->info.chainReason == CHAIN_NONE || pCF->IsActiveFrame())
1682 {
1683 use = false;
1684 }
1685 else
1686 {
1687 INTERNAL_FRAME_ACTION(d, use);
1688 }
1689 break;
1690
1691 case Frame::TYPE_INTERCEPTION:
1692 case Frame::TYPE_SECURITY: // Security is a sub-type of interception
1693 LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_INTERCEPTION/TYPE_SECURITY.\n"));
1694 d->info.managed = true;
1695 d->info.internal = true;
1696 use = true;
1697 break;
1698
1699 case Frame::TYPE_CALL:
1700 LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_CALL.\n"));
1701 // In V4, StubDispatchFrame is only used on 64-bit (and PPC?) but not on x86. x86 uses a
1702 // different code path which sets up a HelperMethodFrame instead. In V4.5, x86 and ARM
1703 // both use the 64-bit code path and they set up a StubDispatchFrame as well. This causes
1704 // a problem in the debugger stackwalker (see Dev11 Issue 13229) since the two frame types
1705 // are treated differently. More specifically, a StubDispatchFrame causes the debugger
1706 // stackwalk to make an invalid callback, i.e. a callback which is not for a managed method,
1707 // an explicit frame, or a chain.
1708 //
1709 // Ideally we would just change the StubDispatchFrame to behave like a HMF, but it's
1710 // too big of a change for an in-place release. For now I'm just making surgical fixes in
1711 // the debugger stackwalker. This may introduce behavioural changes in on X64, but the
1712 // chance of that is really small. StubDispatchFrame is only used in the virtual stub
1713 // disptch code path. It stays on the stack in a small time window and it's not likely to
1714 // be on the stack while some managed methods closer to the leaf are on the stack. There is
1715 // only one scenario I know of, and that's the repro for Dev11 13229, but that's for x86 only.
1716 // The jitted code on X64 behaves differently.
1717 //
1718 // Note that there is a corresponding change in DacDbiInterfaceImpl::GetInternalFrameType().
1719 if (frame->GetVTablePtr() == StubDispatchFrame::GetMethodFrameVPtr())
1720 {
1721 use = false;
1722 }
1723 else
1724 {
1725 d->info.managed = true;
1726 d->info.internal = false;
1727 use = true;
1728 }
1729 break;
1730
1731 case Frame::TYPE_FUNC_EVAL:
1732 LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_FUNC_EVAL.\n"));
1733 d->info.managed = true;
1734 d->info.internal = true;
1735 // This is actually a nop. We reset the chain reason in InitForFuncEval() below.
1736 // So is a FuncEvalFrame a chain or an internal frame?
1737 d->info.chainReason = CHAIN_FUNC_EVAL;
1738
1739 {
1740 // We only show a FuncEvalFrame if the funceval is not trying to abort the thread.
1741 FuncEvalFrame *pFuncEvalFrame = static_cast<FuncEvalFrame *>(frame);
1742 use = pFuncEvalFrame->ShowFrame() ? true : false;
1743 }
1744
1745 // Send Internal frame. This is "inside" (leafmost) the chain, so we send it first
1746 // since sending starts from the leaf.
1747 if (use && d->ShouldProvideInternalFrames())
1748 {
1749 FrameInfo f;
1750 f.InitForFuncEval(pCF);
1751 if (d->InvokeCallback(&f) == SWA_ABORT)
1752 {
1753 return SWA_ABORT;
1754 }
1755 }
1756
1757 break;
1758
1759 // Put frames we want to ignore here:
1760 case Frame::TYPE_MULTICAST:
1761 LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_MULTICAST.\n"));
1762 if (d->ShouldIgnoreNonmethodFrames())
1763 {
1764 // Multicast frames exist only to gc protect the arguments
1765 // between invocations of a delegate. They don't have code that
1766 // we can (currently) show the user (we could change this with
1767 // work, but why bother? It's an internal stub, and even if the
1768 // user could see it, they can't modify it).
1769 LOG((LF_CORDB, LL_INFO100000, "DWSP: Skipping frame 0x%x b/c it's "
1770 "a multicast frame!\n", frame));
1771 use = false;
1772 }
1773 else
1774 {
1775 LOG((LF_CORDB, LL_INFO100000, "DWSP: NOT Skipping frame 0x%x even thought it's "
1776 "a multicast frame!\n", frame));
1777 INTERNAL_FRAME_ACTION(d, use);
1778 }
1779 break;
1780
1781 default:
1782 _ASSERTE(!"Invalid frame type!");
1783 break;
1784 }
1785 }
1786
1787
1788 // Check for ICorDebugInternalFrame stuff.
1789 // These callbacks are dispatched out of band.
1790 if (d->ShouldProvideInternalFrames() && (frame != NULL) && (frame != FRAME_TOP))
1791 {
1792 Frame::ETransitionType t = frame->GetTransitionType();
1793 FrameInfo f;
1794 bool fUse = false;
1795
1796 if (t == Frame::TT_U2M)
1797 {
1798 // We can invoke the Internal U2M frame now.
1799 f.InitForU2MInternalFrame(pCF);
1800 fUse = true;
1801 }
1802 else if (t == Frame::TT_AppDomain)
1803 {
1804 // Internal frame for an Appdomain transition.
1805 // We used to ignore frames for ADs which we hadn't sent a Create event for yet. In V3 we send AppDomain
1806 // create events immediately (before any assemblies are loaded), so this should no longer be an issue.
1807 f.InitForADTransition(pCF);
1808 fUse = true;
1809 }
1810
1811 // Frame's setup. Now invoke the callback.
1812 if (fUse)
1813 {
1814 if (d->InvokeCallback(&f) == SWA_ABORT)
1815 {
1816 return SWA_ABORT;
1817 }
1818 }
1819 } // should we give frames?
1820
1821
1822
1823 if (use)
1824 {
1825 //
1826 // If we are returning a complete stack walk from the helper thread, then we
1827 // need to gather information to instantiate generics. However, a stepper doing
1828 // a stackwalk does not need this information, so skip in that case.
1829 //
1830 if (d->ShouldIgnoreNonmethodFrames())
1831 {
1832 // Finding sizes of value types on the argument stack while
1833 // looking for the arg runs the class loader in non-load mode.
1834 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
1835 d->info.exactGenericArgsToken = pCF->GetExactGenericArgsToken();
1836 }
1837 else
1838 {
1839 d->info.exactGenericArgsToken = NULL;
1840 }
1841
1842 d->info.md = md;
1843 CopyREGDISPLAY(&(d->info.registers), &(d->regDisplay));
1844
1845#if defined(_TARGET_AMD64_)
1846 LOG((LF_CORDB, LL_INFO100000, "DWSP: Saving REGDISPLAY with sp = 0x%p, pc = 0x%p.\n",
1847 GetRegdisplaySP(&(d->info.registers)),
1848 GetControlPC(&(d->info.registers))));
1849#endif // _TARGET_AMD64_
1850
1851 d->needParentInfo = true;
1852 LOG((LF_CORDB, LL_INFO100000, "DWSP: Setting needParentInfo\n"));
1853 }
1854
1855#if defined(WIN64EXCEPTIONS)
1856 d->fpParent = CheckForParentFP(d->fpParent, pCF, d->info.IsNonFilterFuncletFrame());
1857#endif // WIN64EXCEPTIONS
1858
1859 //
1860 // The stackwalker doesn't update the register set for the
1861 // case where a non-frameless frame is returning to another
1862 // non-frameless frame. Cover this case.
1863 //
1864 // !!! This assumes that updating the register set multiple times
1865 // for a given frame times is not a bad thing...
1866 //
1867 if (!pCF->IsFrameless())
1868 {
1869 LOG((LF_CORDB, LL_INFO100000, "DWSP: updating regdisplay.\n"));
1870 pCF->GetFrame()->UpdateRegDisplay(&d->regDisplay);
1871 }
1872
1873 return SWA_CONTINUE;
1874}
1875
1876#if defined(_TARGET_X86_) && defined(FEATURE_INTEROP_DEBUGGING)
1877// Helper to get the Wait-Sleep-Join bit from the thread
1878bool IsInWaitSleepJoin(Thread * pThread)
1879{
1880 // Partial User state is sufficient because that has the bit we're checking against.
1881 CorDebugUserState cts = g_pEEInterface->GetPartialUserState(pThread);
1882 return ((cts & USER_WAIT_SLEEP_JOIN) != 0);
1883}
1884
1885//-----------------------------------------------------------------------------
1886// Decide if we should send an UM leaf chain.
1887// This goes through a bunch of heuristics.
1888// The driving guidelines here are:
1889// - we try not to send an UM chain if it's just internal mscorwks stuff
1890// and we know it can't have native user code.
1891// (ex, anything beyond a filter context, various hijacks, etc).
1892// - If it may have native user code, we send it anyway.
1893//-----------------------------------------------------------------------------
1894bool ShouldSendUMLeafChain(Thread * pThread)
1895{
1896 // If we're in shutodown, don't bother trying to sniff for an UM leaf chain.
1897 // @todo - we'd like to never even be trying to stack trace on shutdown, this
1898 // comes up when we do helper thread duty on shutdown.
1899 if (g_fProcessDetach)
1900 {
1901 return false;
1902 }
1903
1904 if (pThread->IsUnstarted() || pThread->IsDead())
1905 {
1906 return false;
1907 }
1908
1909 // If a thread is suspended for sync purposes, it was suspended from managed
1910 // code and the only native code is a mscorwks hijack.
1911 // There are a few caveats here:
1912 // - This means a thread will lose it's UM chain. But what if a user inactive thread
1913 // enters the CLR from native code and hits a GC toggle? We'll lose that entire
1914 // UM chain.
1915 // - at a managed-only stop, preemptive threads are still live. Thus a thread
1916 // may not have this state set, run a little, try to enter the GC, and then get
1917 // this state set. Thus we'll lose the UM chain right out from under our noses.
1918 Thread::ThreadState ts = pThread->GetSnapshotState();
1919 if ((ts & Thread::TS_SyncSuspended) != 0)
1920 {
1921 // If we've been stopped inside the runtime (eg, at a gc-toggle) but
1922 // not actually at a stopping context, then the thread must have some
1923 // leafframes in mscorwks.
1924 // We can detect this case by checking if GetManagedStoppedCtx(pThread) == NULL.
1925 // This is very significant for notifcations (like LogMessage) that are
1926 // dispatches from within mscorwks w/o a filter context.
1927 // We don't send a UM chain for these cases because that would
1928 // cause managed debug events to be dispatched w/ UM chains on the callstack.
1929 // And that just seems wrong ...
1930
1931 return false;
1932 }
1933
1934#ifdef FEATURE_HIJACK
1935 if ((ts & Thread::TS_Hijacked) != 0)
1936 {
1937 return false;
1938 }
1939#endif
1940
1941 // This is pretty subjective. If we have a thread stopped in a managed sleep,
1942 // managed wait, or managed join, then don't bother showing the native end of the
1943 // stack. This check can be removed w/o impacting correctness.
1944 // @todo - may be a problem if Sleep/Wait/Join go through a hosting interface
1945 // which lands us in native user code.
1946 // Partial User state is sufficient because that has the bit we're checking against.
1947 if (IsInWaitSleepJoin(pThread))
1948 {
1949 return false;
1950 }
1951
1952 // If we're tracing ourselves, we must be in managed code.
1953 // Native user code can't initiate a managed stackwalk.
1954 if (pThread == GetThread())
1955 {
1956 return false;
1957 }
1958
1959 return true;
1960}
1961
1962//-----------------------------------------------------------------------------
1963// Prepare a Leaf UM chain. This assumes we should send an UM leaf chain.
1964// Returns true if we actually prep for an UM leaf,
1965// false if we don't.
1966//-----------------------------------------------------------------------------
1967bool PrepareLeafUMChain(DebuggerFrameData * pData, CONTEXT * pCtxTemp)
1968{
1969 // Get the current user context (depends on if we're the active thread or not).
1970 Thread * thread = pData->GetThread();
1971 REGDISPLAY * pRDSrc = NULL;
1972 REGDISPLAY rdTemp;
1973
1974
1975#ifdef _DEBUG
1976 // Anybody stopped at an native debug event (and hijacked) should have a filter ctx.
1977 if (thread->GetInteropDebuggingHijacked() && (thread->GetFrame() != NULL) && (thread->GetFrame() != FRAME_TOP))
1978 {
1979 _ASSERTE(g_pEEInterface->GetThreadFilterContext(thread) != NULL);
1980 }
1981#endif
1982
1983 // If we're hijacked, then we assume we're in native code. This covers the active thread case.
1984 if (g_pEEInterface->GetThreadFilterContext(thread) != NULL)
1985 {
1986 LOG((LF_CORDB, LL_EVERYTHING, "DWS - sending special case UM Chain.\n"));
1987
1988 // This will get it from the filter ctx.
1989 pRDSrc = &(pData->regDisplay);
1990 }
1991 else
1992 {
1993 // For inactive thread, we may not be hijacked. So just get the current ctx.
1994 // This will use a filter ctx if we have one.
1995 // We may suspend a thread in native code w/o hijacking it, so it's still at it's live context.
1996 // This can happen when we get a debug event on 1 thread; and then switch to look at another thread.
1997 // This is very common when debugging apps w/ cross-thread causality (including COM STA objects)
1998 pRDSrc = &rdTemp;
1999
2000 bool fOk;
2001
2002
2003 // We need to get thread's context (InitRegDisplay will do that under the covers).
2004 // If this is our thread, we're in bad shape. Fortunately that should never happen.
2005 _ASSERTE(thread != GetThread());
2006
2007 Thread::SuspendThreadResult str = thread->SuspendThread();
2008 if (str != Thread::STR_Success)
2009 {
2010 return false;
2011 }
2012
2013 // @todo - this context is less important because the RS will overwrite it with the live context.
2014 // We don't need to even bother getting it. We can just intialize the regdisplay w/ a sentinal.
2015 fOk = g_pEEInterface->InitRegDisplay(thread, pRDSrc, pCtxTemp, false);
2016 thread->ResumeThread();
2017
2018 if (!fOk)
2019 {
2020 return false;
2021 }
2022 }
2023
2024 // By now we have a Regdisplay from somewhere (filter ctx, current ctx, etc).
2025 _ASSERTE(pRDSrc != NULL);
2026
2027 // If we're stopped in mscorwks (b/c of a handler for a managed BP), then the filter ctx will
2028 // still be set out in jitted code.
2029 // If our regdisplay is out in UM code , then send a UM chain.
2030 BYTE* ip = (BYTE*) GetControlPC(pRDSrc);
2031 if (g_pEEInterface->IsManagedNativeCode(ip))
2032 {
2033 return false;
2034 }
2035
2036 LOG((LF_CORDB, LL_EVERYTHING, "DWS - sending leaf UM Chain.\n"));
2037
2038 // Get the ending fp. We may not have any managed goo on the stack (eg, native thread called
2039 // into a managed method and then returned from it).
2040 FramePointer fpRoot;
2041 Frame * pFrame = thread->GetFrame();
2042 if ((pFrame != NULL) && (pFrame != FRAME_TOP))
2043 {
2044 fpRoot = FramePointer::MakeFramePointer((void*) pFrame);
2045 }
2046 else
2047 {
2048 fpRoot= ROOT_MOST_FRAME;
2049 }
2050
2051
2052 // Start tracking an UM chain. We won't actually send the UM chain until
2053 // we hit managed code. Since this is the leaf, we don't need to send an
2054 // Enter-Managed chain either.
2055 pData->BeginTrackingUMChain(fpRoot, pRDSrc);
2056
2057 return true;
2058}
2059#endif // defined(_TARGET_X86_) && defined(FEATURE_INTEROP_DEBUGGING)
2060
2061//-----------------------------------------------------------------------------
2062// Entry function for the debugger's stackwalking layer.
2063// This will invoke pCallback(FrameInfo * pInfo, pData) for each 'frame'
2064//-----------------------------------------------------------------------------
2065StackWalkAction DebuggerWalkStack(Thread *thread,
2066 FramePointer targetFP,
2067 CONTEXT *context,
2068 BOOL contextValid,
2069 DebuggerStackCallback pCallback,
2070 void *pData,
2071 BOOL fIgnoreNonmethodFrames)
2072{
2073 _ASSERTE(context != NULL);
2074
2075 DebuggerFrameData data;
2076
2077 StackWalkAction result = SWA_CONTINUE;
2078 bool fRegInit = false;
2079
2080 LOG((LF_CORDB, LL_EVERYTHING, "DebuggerWalkStack called\n"));
2081
2082 if(contextValid || g_pEEInterface->GetThreadFilterContext(thread) != NULL)
2083 {
2084 fRegInit = g_pEEInterface->InitRegDisplay(thread, &data.regDisplay, context, contextValid != 0);
2085 _ASSERTE(fRegInit);
2086 }
2087
2088 if (!fRegInit)
2089 {
2090#if defined(CONTEXT_EXTENDED_REGISTERS)
2091
2092 // Note: the size of a CONTEXT record contains the extended registers, but the context pointer we're given
2093 // here may not have room for them. Therefore, we only set the non-extended part of the context to 0.
2094 memset((void *)context, 0, offsetof(CONTEXT, ExtendedRegisters));
2095#else
2096 memset((void *)context, 0, sizeof(CONTEXT));
2097#endif
2098 memset((void *)&data, 0, sizeof(data));
2099
2100#if defined(_TARGET_X86_)
2101 // @todo - this seems pointless. context->Eip will be 0; and when we copy it over to the DebuggerRD,
2102 // the context will be completely null.
2103 data.regDisplay.ControlPC = context->Eip;
2104 data.regDisplay.PCTAddr = (TADDR)&(context->Eip);
2105
2106#else
2107 //
2108 // @TODO: this should be the code for all platforms now that it uses FillRegDisplay,
2109 // which encapsulates the platform variances. This could all be avoided if we used
2110 // StackWalkFrames instead of StackWalkFramesEx.
2111 //
2112 ::SetIP(context, 0);
2113 ::SetSP(context, 0);
2114 FillRegDisplay(&data.regDisplay, context);
2115
2116 ::SetSP(data.regDisplay.pCallerContext, 0);
2117#endif
2118 }
2119
2120 data.Init(thread, targetFP, fIgnoreNonmethodFrames, pCallback, pData);
2121
2122
2123#if defined(_TARGET_X86_) && defined(FEATURE_INTEROP_DEBUGGING)
2124 CONTEXT ctxTemp; // Temp context for Leaf UM chain. Need it here so that it stays alive for whole stackwalk.
2125
2126 // Important case for Interop Debugging -
2127 // We may be stopped in Native Code (perhaps at a BP) w/ no Transition frame on the stack!
2128 // We still need to send an UM Chain for this case.
2129 if (ShouldSendUMLeafChain(thread))
2130 {
2131 // It's possible this may fail (eg, GetContext fails on win9x), so we're not guaranteed
2132 // to be sending an UM chain even though we want to.
2133 PrepareLeafUMChain(&data, &ctxTemp);
2134
2135 }
2136#endif // defined(_TARGET_X86_) && defined(FEATURE_INTEROP_DEBUGGING)
2137
2138 if ((result != SWA_FAILED) && !thread->IsUnstarted() && !thread->IsDead())
2139 {
2140 int flags = 0;
2141
2142 result = g_pEEInterface->StackWalkFramesEx(thread, &data.regDisplay,
2143 DebuggerWalkStackProc,
2144 &data,
2145 flags | HANDLESKIPPEDFRAMES | NOTIFY_ON_U2M_TRANSITIONS |
2146 ALLOW_ASYNC_STACK_WALK | SKIP_GSCOOKIE_CHECK);
2147 }
2148 else
2149 {
2150 result = SWA_DONE;
2151 }
2152
2153 if (result == SWA_DONE || result == SWA_FAILED) // SWA_FAILED if no frames
2154 {
2155 // Since Debugger StackWalk callbacks are delayed 1 frame from EE stackwalk callbacks, we
2156 // have to touch up the 1 leftover here.
2157 //
2158 // This is safe only because we use the REGDISPLAY of the native marker callback for any subsequent
2159 // explicit frames which do not update the REGDISPLAY. It's kind of fragile. If we can change
2160 // the x86 real stackwalker to unwind one frame ahead of time, we can get rid of this code.
2161 if (data.needParentInfo)
2162 {
2163 data.info.fp = GetFramePointerForDebugger(&data, NULL);
2164
2165 if (data.InvokeCallback(&data.info) == SWA_ABORT)
2166 {
2167 return SWA_ABORT;
2168 }
2169 }
2170
2171 //
2172 // Top off the stack trace as necessary w/ a thread-start chain.
2173 //
2174 REGDISPLAY * pRegDisplay = &(data.regDisplay);
2175 if (data.IsTrackingUMChain())
2176 {
2177 // This is the common case b/c managed code gets called from native code.
2178 pRegDisplay = data.GetUMChainStartRD();
2179 }
2180
2181
2182 // All Thread starts in unmanaged code (at something like kernel32!BaseThreadStart),
2183 // so all ThreadStart chains must be unmanaged.
2184 // InvokeCallback will fabricate the EnterManaged chain if we haven't already sent one.
2185 data.info.InitForThreadStart(thread, pRegDisplay);
2186 result = data.InvokeCallback(&data.info);
2187
2188 }
2189 return result;
2190}
2191