1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 // This file contains the implementation of the V3 managed stackwalking API.
11 // ======================================================================================
14 #include "primitives.h"
17 //---------------------------------------------------------------------------------------
19 // Constructor for CordbStackWalk.
22 // pCordbThread - the thread on which this stackwalker is created
25 CordbStackWalk::CordbStackWalk(CordbThread * pCordbThread)
26 : CordbBase(pCordbThread->GetProcess(), 0, enumCordbStackWalk),
27 m_pCordbThread(pCordbThread),
29 m_cachedSetContextFlag(SET_CONTEXT_FLAG_ACTIVE_FRAME),
31 m_fIsOneFrameAhead(false)
33 m_pCachedFrame.Clear();
36 void CordbStackWalk::Init()
38 CordbProcess * pProcess = GetProcess();
39 m_lastSyncFlushCounter = pProcess->m_flushCounter;
41 IDacDbiInterface * pDAC = pProcess->GetDAC();
42 pDAC->CreateStackWalk(m_pCordbThread->m_vmThreadToken,
46 // see the function header of code:CordbStackWalk::CheckForLegacyHijackCase
47 CheckForLegacyHijackCase();
49 // Add itself to the neuter list.
50 m_pCordbThread->GetRefreshStackNeuterList()->Add(GetProcess(), this);
53 // ----------------------------------------------------------------------------
54 // CordbStackWalk::CheckForLegacyHijackCase
57 // @dbgtodo legacy interop debugging - In the case of an unhandled hardware exception, the
58 // thread will be hijacked to code:Debugger::GenericHijackFunc, which the stackwalker doesn't know how to
59 // unwind. We can teach the stackwalker to recognize that hijack stub, but since it's going to be deprecated
60 // anyway, it's not worth the effort. So we check for the hijack CONTEXT here and use it as the CONTEXT. This
61 // check should be removed when we are completely
65 void CordbStackWalk::CheckForLegacyHijackCase()
67 #if defined(FEATURE_INTEROP_DEBUGGING)
68 CordbProcess * pProcess = GetProcess();
70 // Only do this if we have a shim and we are interop-debugging.
71 if ((pProcess->GetShim() != NULL) &&
72 pProcess->IsInteropDebugging())
74 // And only if we have a CordbUnmanagedThread and we are hijacked to code:Debugger::GenericHijackFunc
75 CordbUnmanagedThread * pUT = pProcess->GetUnmanagedThread(m_pCordbThread->GetVolatileOSThreadID());
78 if (pUT->IsFirstChanceHijacked() || pUT->IsGenericHijacked())
80 // The GetThreadContext function hides the effects of hijacking and returns the unhijacked context
81 m_context.ContextFlags = DT_CONTEXT_FULL;
82 pUT->GetThreadContext(&m_context);
83 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
84 pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken,
86 SET_CONTEXT_FLAG_ACTIVE_FRAME,
91 #endif // FEATURE_INTEROP_DEBUGGING
94 //---------------------------------------------------------------------------------------
96 // Destructor for CordbStackWalk.
99 // We don't really need to do anything here since the CordbStackWalk should have been neutered already.
102 CordbStackWalk::~CordbStackWalk()
104 _ASSERTE(IsNeutered());
107 //---------------------------------------------------------------------------------------
109 // This function resets all the state on a CordbStackWalk and releases all the memory.
110 // It is used for neutering and refreshing.
113 void CordbStackWalk::DeleteAll()
115 _ASSERTE(GetProcess()->GetProcessLock()->HasLock());
117 // delete allocated memory
123 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
124 // For Mac debugging, it's not safe to call into the DAC once
125 // code:INativeEventPipeline::TerminateProcess is called. This is because the transport will not
126 // work anymore. The sole purpose of calling DeleteStackWalk() is to release the resources and
127 // memory allocated for the stackwalk. In the remote debugging case, the memory is allocated in
128 // the debuggee process. If the process is already terminated, then it's ok to skip the call.
129 if (!GetProcess()->m_exiting)
130 #endif // FEATURE_DBGIPC_TRANSPORT_DI
132 // This Delete call shouldn't actually throw. Worst case, the DDImpl leaked memory.
133 GetProcess()->GetDAC()->DeleteStackWalk(m_pSFIHandle);
136 EX_CATCH_HRESULT(hr);
137 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
141 // clear out the cached frame
142 m_pCachedFrame.Clear();
144 m_fIsOneFrameAhead = false;
147 //---------------------------------------------------------------------------------------
149 // Release all memory used by the stackwalker.
153 // CordbStackWalk is neutered by CordbThread or CleanupStack().
156 void CordbStackWalk::Neuter()
167 // standard QI function
168 HRESULT CordbStackWalk::QueryInterface(REFIID id, void **pInterface)
170 if (id == IID_ICorDebugStackWalk)
172 *pInterface = static_cast<ICorDebugStackWalk*>(this);
174 else if (id == IID_IUnknown)
176 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugStackWalk*>(this));
181 return E_NOINTERFACE;
188 //---------------------------------------------------------------------------------------
190 // Refreshes all the state stored on the CordbStackWalk. This is necessary because sending IPC events to
191 // the LS flushes the DAC cache, and m_pSFIHandle is allocated entirely in DAC memory. So, we keep track
192 // of whether we have sent an IPC event and refresh the CordbStackWalk if necessary.
198 void CordbStackWalk::RefreshIfNeeded()
200 CordbProcess * pProcess = GetProcess();
201 _ASSERTE(pProcess->GetProcessLock()->HasLock());
203 // check if we need to refresh
204 if (m_lastSyncFlushCounter != pProcess->m_flushCounter)
206 // Make a local copy of the CONTEXT here. DeleteAll() will delete the CONTEXT on the cached frame,
207 // and CreateStackWalk() actually uses the CONTEXT buffer we pass to it.
209 if (m_fIsOneFrameAhead)
211 ctx = *(m_pCachedFrame->GetContext());
218 // clear all the state
221 // create a new stackwalk handle
222 pProcess->GetDAC()->CreateStackWalk(m_pCordbThread->m_vmThreadToken,
226 // advance the stackwalker to where we originally were
227 SetContextWorker(m_cachedSetContextFlag, sizeof(DT_CONTEXT), reinterpret_cast<BYTE *>(&ctx));
229 // update the sync counter
230 m_lastSyncFlushCounter = pProcess->m_flushCounter;
232 } // CordbStackWalk::RefreshIfNeeded()
234 //---------------------------------------------------------------------------------------
236 // Retrieves the CONTEXT of the current frame.
239 // contextFlags - context flags used to determine the required size for the buffer
240 // contextBufSize - size of the CONTEXT buffer
241 // pContextSize - out parameter; returns the size required for the CONTEXT buffer
242 // pbContextBuf - the CONTEXT buffer
245 // Return S_OK on success.
246 // Return CORDBG_E_PAST_END_OF_STACK if we are already at the end of the stack.
247 // Return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) if the buffer is too small.
248 // Return E_FAIL on other failures.
251 HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags,
252 ULONG32 contextBufSize,
253 ULONG32 * pContextSize,
257 PUBLIC_REENTRANT_API_BEGIN(this)
261 // set the required size for the CONTEXT buffer
262 if (pContextSize != NULL)
264 *pContextSize = ContextSizeForFlags(contextFlags);
267 // If all the user wants to know is the CONTEXT size, then we are done.
268 if ((contextBufSize != 0) && (pbContextBuf != NULL))
270 if (contextBufSize < 4)
272 ThrowWin32(ERROR_INSUFFICIENT_BUFFER);
275 DT_CONTEXT * pContext = reinterpret_cast<DT_CONTEXT *>(pbContextBuf);
277 // Some helper functions that examine the context expect the flags to be initialized.
278 pContext->ContextFlags = contextFlags;
280 // check the size of the incoming buffer
281 if (!CheckContextSizeForBuffer(contextBufSize, pbContextBuf))
283 ThrowWin32(ERROR_INSUFFICIENT_BUFFER);
286 // Check if we are one frame ahead. If so, returned the CONTEXT on the cached frame.
287 if (m_fIsOneFrameAhead)
289 if (m_pCachedFrame != NULL)
291 const DT_CONTEXT * pSrcContext = m_pCachedFrame->GetContext();
292 _ASSERTE(pSrcContext);
293 CORDbgCopyThreadContext(pContext, pSrcContext);
297 // We encountered a problem when we were trying to initialize the CordbNativeFrame.
298 // However, the problem occurred after we have unwound the current frame.
299 // What do we do here? We don't have the CONTEXT anymore.
300 _ASSERTE(FAILED(m_cachedHR));
306 // No easy way out in this case. We have to call the DDI.
307 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
309 IDacDbiInterface::FrameType ft = pDAC->GetStackWalkCurrentFrameInfo(m_pSFIHandle, NULL);
310 if (ft == IDacDbiInterface::kInvalid)
314 else if (ft == IDacDbiInterface::kAtEndOfStack)
316 ThrowHR(CORDBG_E_PAST_END_OF_STACK);
318 else if (ft == IDacDbiInterface::kExplicitFrame)
320 ThrowHR(CORDBG_E_NO_CONTEXT_FOR_INTERNAL_FRAME);
324 // We always store the current CONTEXT, so just copy it into the buffer.
325 CORDbgCopyThreadContext(pContext, &m_context);
330 PUBLIC_REENTRANT_API_END(hr);
334 //---------------------------------------------------------------------------------------
336 // Set the stackwalker to the specified CONTEXT.
339 // flag - context flags used to determine the size of the CONTEXT
340 // contextSize - the size of the CONTEXT
341 // context - the CONTEXT as a byte array
344 // Return S_OK on success.
345 // Return E_INVALIDARG if context is NULL
346 // Return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) if the CONTEXT is too small.
347 // Return E_FAIL on other failures.
350 HRESULT CordbStackWalk::SetContext(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[])
353 PUBLIC_REENTRANT_API_BEGIN(this)
356 SetContextWorker(flag, contextSize, context);
358 PUBLIC_REENTRANT_API_END(hr);
362 //---------------------------------------------------------------------------------------
364 // Refer to the comment for code:CordbStackWalk::SetContext
367 void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[])
371 ThrowHR(E_INVALIDARG);
374 if (!CheckContextSizeForBuffer(contextSize, context))
376 ThrowWin32(ERROR_INSUFFICIENT_BUFFER);
379 // invalidate the cache
380 m_pCachedFrame.Clear();
382 m_fIsOneFrameAhead = false;
384 DT_CONTEXT * pSrcContext = reinterpret_cast<DT_CONTEXT *>(context);
386 // Check the incoming CONTEXT using a temporary CONTEXT buffer before updating our real CONTEXT buffer.
387 // The incoming CONTEXT is not required to have all the bits set in its CONTEXT flags, so only update
388 // the registers specified by the CONTEXT flags. Note that CORDbgCopyThreadContext() honours the CONTEXT
389 // flags on both the source and the destination CONTEXTs when it copies them.
390 DT_CONTEXT tmpCtx = m_context;
391 tmpCtx.ContextFlags |= pSrcContext->ContextFlags;
392 CORDbgCopyThreadContext(&tmpCtx, pSrcContext);
394 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
395 IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, &tmpCtx));
397 // At this point we have done all of our checks to verify that the incoming CONTEXT is sane, so we can
398 // update our internal CONTEXT buffer.
400 m_cachedSetContextFlag = flag;
402 pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken,
408 //---------------------------------------------------------------------------------------
410 // Helper to perform all the necessary operations when we unwind, including:
412 // 2) Save the new unwound CONTEXT
415 // Return TRUE if we successfully unwind to the next frame.
416 // Return FALSE if there is no more frame to walk.
420 BOOL CordbStackWalk::UnwindStackFrame()
422 CordbProcess * pProcess = GetProcess();
423 _ASSERTE(pProcess->GetProcessLock()->HasLock());
425 IDacDbiInterface * pDAC = pProcess->GetDAC();
426 BOOL retVal = pDAC->UnwindStackWalkFrame(m_pSFIHandle);
428 // Now that we have unwound, make sure we update the CONTEXT buffer to reflect the current stack frame.
429 // This call is safe regardless of whether the unwind is successful or not.
430 pDAC->GetStackWalkCurrentContext(m_pSFIHandle, &m_context);
433 } // CordbStackWalk::UnwindStackWalkFrame
435 //---------------------------------------------------------------------------------------
437 // Unwind the stackwalker to the next frame.
440 // Return S_OK on success.
441 // Return CORDBG_E_FAIL_TO_UNWIND_FRAME if the unwind fails.
442 // Return CORDBG_S_AT_END_OF_STACK if we have reached the end of the stack as a result of this unwind.
443 // Return CORDBG_E_PAST_END_OF_STACK if we are already at the end of the stack to begin with.
446 HRESULT CordbStackWalk::Next()
449 PUBLIC_REENTRANT_API_BEGIN(this)
452 if (m_fIsOneFrameAhead)
454 // We have already unwound to the next frame when we materialize the CordbNativeFrame
455 // for the current frame. So we just need to clear the cache because we are already at
457 if (m_pCachedFrame != NULL)
459 m_pCachedFrame.Clear();
462 m_fIsOneFrameAhead = false;
466 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
467 IDacDbiInterface::FrameType ft = IDacDbiInterface::kInvalid;
469 ft = pDAC->GetStackWalkCurrentFrameInfo(this->m_pSFIHandle, NULL);
470 if (ft == IDacDbiInterface::kAtEndOfStack)
472 ThrowHR(CORDBG_E_PAST_END_OF_STACK);
475 // update the cahced flag to indicate that we have reached an unwind CONTEXT
476 m_cachedSetContextFlag = SET_CONTEXT_FLAG_UNWIND_FRAME;
478 if (UnwindStackFrame())
484 hr = CORDBG_S_AT_END_OF_STACK;
488 PUBLIC_REENTRANT_API_END(hr);
492 //---------------------------------------------------------------------------------------
494 // Retrieves an ICDFrame corresponding to the current frame:
495 // Stopped At Out Parameter Return Value
496 // ---------- ------------- ------------
497 // explicit frame CordbInternalFrame S_OK
498 // managed stack frame CordbNativeFrame S_OK
499 // native stack frame NULL S_FALSE
502 // ppFrame - out parameter; return the ICDFrame
505 // On success return the HRs above.
506 // Return CORDBG_E_PAST_END_OF_STACK if we are already at the end of the stack.
507 // Return E_INVALIDARG if ppFrame is NULL
508 // Return E_FAIL on other errors.
511 // This is just a wrapper with an EX_TRY/EX_CATCH_HRESULT for GetFrameWorker().
514 HRESULT CordbStackWalk::GetFrame(ICorDebugFrame ** ppFrame)
517 PUBLIC_REENTRANT_API_NO_LOCK_BEGIN(this)
519 ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(GetProcess(), ThrowHR);
520 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
523 hr = GetFrameWorker(ppFrame);
525 PUBLIC_REENTRANT_API_END(hr);
529 if (m_fIsOneFrameAhead && (m_pCachedFrame == NULL))
531 // We encountered a problem when we try to materialize a CordbNativeFrame.
532 // Cache the failure HR so that we can return it later if the caller
533 // calls GetFrame() again or GetContext().
541 //---------------------------------------------------------------------------------------
543 // Refer to the comment for code:CordbStackWalk::GetFrame
546 HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame)
548 _ASSERTE(GetProcess()->GetProcessLock()->HasLock());
552 ThrowHR(E_INVALIDARG);
556 RSInitHolder<CordbFrame> pResultFrame(NULL);
558 if (m_fIsOneFrameAhead)
560 if (m_pCachedFrame != NULL)
562 pResultFrame.Assign(m_pCachedFrame);
563 pResultFrame.TransferOwnershipExternal(ppFrame);
568 // We encountered a problem when we were trying to initialize the CordbNativeFrame.
569 // However, the problem occurred after we have unwound the current frame.
570 // Whatever error code we return, it should be the same one GetContext() returns.
571 _ASSERTE(FAILED(m_cachedHR));
576 IDacDbiInterface * pDAC = NULL;
577 DebuggerIPCE_STRData frameData;
578 ZeroMemory(&frameData, sizeof(frameData));
579 IDacDbiInterface::FrameType ft = IDacDbiInterface::kInvalid;
581 pDAC = GetProcess()->GetDAC();
582 ft = pDAC->GetStackWalkCurrentFrameInfo(m_pSFIHandle, &frameData);
584 if (ft == IDacDbiInterface::kInvalid)
586 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CSW::GFW - invalid stackwalker (%p)", this);
589 else if (ft == IDacDbiInterface::kAtEndOfStack)
591 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CSW::GFW - past end of stack (%p)", this);
592 ThrowHR(CORDBG_E_PAST_END_OF_STACK);
594 else if (ft == IDacDbiInterface::kNativeStackFrame)
596 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CSW::GFW - native stack frame (%p)", this);
599 else if (ft == IDacDbiInterface::kExplicitFrame)
601 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CSW::GFW - explicit frame (%p)", this);
603 // We no longer expect to get internal frames by unwinding.
604 GetProcess()->TargetConsistencyCheck(false);
606 else if (ft == IDacDbiInterface::kManagedStackFrame)
608 _ASSERTE(frameData.eType == DebuggerIPCE_STRData::cMethodFrame);
612 // In order to find the FramePointer on x86, we need to unwind to the next frame.
613 // Technically, only x86 needs to do this, because the x86 runtime stackwalker doesn't uwnind
614 // one frame ahead of time. However, we are doing this on all platforms to keep things simple.
615 BOOL fSuccess = UnwindStackFrame();
616 (void)fSuccess; //prevent "unused variable" error from GCC
619 m_fIsOneFrameAhead = true;
620 #if defined(DBG_TARGET_X86)
621 frameData.fp = pDAC->GetFramePointer(m_pSFIHandle);
622 #endif // DBG_TARGET_X86
624 // currentFuncData contains general information about the method.
625 // It has no information about any particular jitted instance of the method.
626 DebuggerIPCE_FuncData * pFuncData = &(frameData.v.funcData);
628 // currentJITFuncData contains information about the current jitted instance of the method
630 DebuggerIPCE_JITFuncData * pJITFuncData = &(frameData.v.jitFuncData);
632 // Lookup the appdomain that the thread was in when it was executing code for this frame. We pass this
633 // to the frame when we create it so we can properly resolve locals in that frame later.
634 CordbAppDomain * pCurrentAppDomain = GetProcess()->LookupOrCreateAppDomain(frameData.vmCurrentAppDomainToken);
635 _ASSERTE(pCurrentAppDomain != NULL);
638 CordbModule* pModule = pCurrentAppDomain->LookupOrCreateModule(pFuncData->vmDomainFile);
639 PREFIX_ASSUME(pModule != NULL);
641 // Create or look up a CordbNativeCode. There is one for each jitted instance of a method,
642 // and we may have multiple instances because of generics.
643 CordbNativeCode * pNativeCode = pModule->LookupOrCreateNativeCode(pFuncData->funcMetadataToken,
644 pJITFuncData->vmNativeCodeMethodDescToken,
645 pJITFuncData->nativeStartAddressPtr);
648 // The native code object will create the function object if needed
649 CordbFunction * pFunction = pNativeCode->GetFunction();
651 // A CordbFunction is theoretically the uninstantiated method, yet for back-compat we allow
652 // debuggers to assume that it corresponds to exactly 1 native code blob. In order for
653 // an open generic function to know what native code to give back, we attach an arbitrary
654 // native code that we located through code inspection.
655 // Note that not all CordbFunction objects get created via stack traces because you can also
656 // create them by name. In that case you still won't get code for Open generic functions
657 // because we will never have attached one and the lookup by token is insufficient. This
658 // behavior mimics our 2.0 debugging behavior though so its not a regression.
659 pFunction->NotifyCodeCreated(pNativeCode);
663 _ASSERTE((pFunction != NULL) && (pNativeCode != NULL));
665 // initialize the auxiliary info required for funclets
666 CordbMiscFrame miscFrame(pJITFuncData);
668 // Create the native frame.
669 CordbNativeFrame* pNativeFrame = new CordbNativeFrame(m_pCordbThread,
672 pJITFuncData->nativeOffset,
674 frameData.v.taAmbientESP,
675 !!frameData.quicklyUnwound,
680 pResultFrame.Assign(static_cast<CordbFrame *>(pNativeFrame));
681 m_pCachedFrame.Assign(static_cast<CordbFrame *>(pNativeFrame));
683 // @dbgtodo dynamic language debugging
684 // If we are dealing with a dynamic method (e.g. an IL stub, a LCG method, etc.),
685 // then we don't have the metadata or the debug info (sequence points, etc.).
686 // This means that we can't do anything meaningful with a CordbJITILFrame anyway,
687 // so let's not create the CordbJITILFrame at all. Note that methods created with
688 // RefEmit are okay, i.e. they have metadata.
690 // The check for IsNativeImpl() != CordbFunction::kNativeOnly catches an odd profiler
691 // case. A profiler can rewrite assemblies at load time so that a P/invoke becomes a
692 // regular managed method. mscordbi isn't yet designed to handle runtime metadata
693 // changes, so it still thinks the method is a p/invoke. If we only relied on
694 // frameData.v.fNoMetadata which is populated by the DAC, that will report
695 // FALSE (the method does have metadata/IL now). However pNativeCode->LoadNativeInfo
696 // is going to check DBI's metadata and calculate this is a p/invoke, which will
697 // throw an exception that the method isn't IL.
698 // Ideally we probably want to expose the profiler's change to the method,
699 // however that will take significant work. Part of that is correctly detecting and
700 // updating metadata in DBI, part is determinging if/how the debugger is notified,
701 // and part is auditing mscordbi to ensure that anything we cached based on the
702 // old metadata is correctly invalidated.
703 // Since this is a late fix going into a controlled servicing release I have
704 // opted for a much narrower fix. Doing the check for IsNativeImpl() != CordbFunction::kNativeOnly
705 // will continue to treat our new method as though it was a p/invoke, and the
706 // debugger will not provide IL for it. The debugger can't inspect within the profiler
707 // modified method, but at least the error won't leak out to interfere with inspection
708 // of the callstack as a whole.
709 if (!frameData.v.fNoMetadata &&
710 pNativeCode->GetFunction()->IsNativeImpl() != CordbFunction::kNativeOnly)
712 pNativeCode->LoadNativeInfo();
714 // By design, when a managed exception occurs we return the sequence point containing the faulting
715 // instruction in the leaf frame. In the past we didn't always achieve this,
716 // but we are being more deliberate about this behavior now.
718 // If jsutAfterILThrow is true, it means nativeOffset points to the return address of IL_Throw
719 // (or another JIT exception helper) after an exception has been thrown.
720 // In such cases we want to adjust nativeOffset, so it will point an actual exception callsite.
721 // By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get
722 // an address somewhere inside CALL instruction.
723 // This ensures more consistent placement of exception line highlighting in Visual Studio
724 DWORD nativeOffsetToMap = pJITFuncData->jsutAfterILThrow ?
725 (DWORD)pJITFuncData->nativeOffset - STACKWALK_CONTROLPC_ADJUST_OFFSET :
726 (DWORD)pJITFuncData->nativeOffset;
727 CorDebugMappingResult mappingType;
728 ULONG uILOffset = pNativeCode->GetSequencePoints()->MapNativeOffsetToIL(
732 // Find or create the IL Code, and the pJITILFrame.
733 RSExtSmartPtr<CordbILCode> pCode;
735 // The code for populating CordbFunction ILCode looks really bizzare... it appears to only grab the
736 // correct version of the IL if that is still the current EnC version yet it is populated deliberately
737 // late bound at which point the latest version may be different. In fact even here the latest version
738 // could already be different, but this is no worse than what the code used to do
739 hr = pFunction->GetILCode(&pCode);
741 _ASSERTE(pCode != NULL);
743 // We populate the code for ReJit eagerly to make sure we still have it if the profiler removes the
744 // instrumentation later. Of course the only way it will still be accesible to our caller is if he
745 // saves a pointer to the ILCode.
746 // I'm not sure if ignoring rejit for mini-dumps is the right call long term, but we aren't doing
747 // anything special to collect the memory at dump time so we better be prepared to not fetch it here.
748 // We'll attempt to treat it as not being instrumented, though I suspect the abstraction is leaky.
749 RSSmartPtr<CordbReJitILCode> pReJitCode;
750 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
752 VMPTR_ReJitInfo reJitInfo = VMPTR_ReJitInfo::NullPtr();
753 IfFailThrow(GetProcess()->GetDAC()->GetReJitInfo(pJITFuncData->vmNativeCodeMethodDescToken, pJITFuncData->nativeStartAddressPtr, &reJitInfo));
754 if (!reJitInfo.IsNull())
756 VMPTR_SharedReJitInfo sharedReJitInfo = VMPTR_SharedReJitInfo::NullPtr();
757 IfFailThrow(GetProcess()->GetDAC()->GetSharedReJitInfo(reJitInfo, &sharedReJitInfo));
758 IfFailThrow(pFunction->LookupOrCreateReJitILCode(sharedReJitInfo, &pReJitCode));
761 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY
765 RSInitHolder<CordbJITILFrame> pJITILFrame(new CordbJITILFrame(pNativeFrame,
769 frameData.v.exactGenericArgsToken,
770 frameData.v.dwExactGenericArgsTokenIndex,
771 !!frameData.v.fVarArgs,
774 // Initialize the frame. This is a nop if the method is not a vararg method.
775 hr = pJITILFrame->Init();
778 pNativeFrame->m_JITILFrame.Assign(pJITILFrame);
779 pJITILFrame.ClearAndMarkDontNeuter();
782 STRESS_LOG3(LF_CORDB, LL_INFO1000, "CSW::GFW - managed stack frame (%p): CNF - 0x%p, CJILF - 0x%p",
783 this, pNativeFrame, pNativeFrame->m_JITILFrame.GetValue());
784 } // kManagedStackFrame
785 else if (ft == IDacDbiInterface::kNativeRuntimeUnwindableStackFrame)
787 _ASSERTE(frameData.eType == DebuggerIPCE_STRData::cRuntimeNativeFrame);
789 // In order to find the FramePointer on x86, we need to unwind to the next frame.
790 // Technically, only x86 needs to do this, because the x86 runtime stackwalker doesn't uwnind
791 // one frame ahead of time. However, we are doing this on all platforms to keep things simple.
792 BOOL fSuccess = UnwindStackFrame();
793 (void)fSuccess; //prevent "unused variable" error from GCC
796 m_fIsOneFrameAhead = true;
797 #if defined(DBG_TARGET_X86)
798 frameData.fp = pDAC->GetFramePointer(m_pSFIHandle);
799 #endif // DBG_TARGET_X86
801 // Lookup the appdomain that the thread was in when it was executing code for this frame. We pass this
802 // to the frame when we create it so we can properly resolve locals in that frame later.
803 CordbAppDomain * pCurrentAppDomain =
804 GetProcess()->LookupOrCreateAppDomain(frameData.vmCurrentAppDomainToken);
805 _ASSERTE(pCurrentAppDomain != NULL);
807 CordbRuntimeUnwindableFrame * pRuntimeFrame = new CordbRuntimeUnwindableFrame(m_pCordbThread,
812 pResultFrame.Assign(static_cast<CordbFrame *>(pRuntimeFrame));
813 m_pCachedFrame.Assign(static_cast<CordbFrame *>(pRuntimeFrame));
815 STRESS_LOG2(LF_CORDB, LL_INFO1000, "CSW::GFW - runtime unwindable stack frame (%p): 0x%p",
816 this, pRuntimeFrame);
819 pResultFrame.TransferOwnershipExternal(ppFrame);