diff options
Diffstat (limited to 'src/vm/amd64/gmsamd64.cpp')
-rw-r--r-- | src/vm/amd64/gmsamd64.cpp | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/vm/amd64/gmsamd64.cpp b/src/vm/amd64/gmsamd64.cpp new file mode 100644 index 0000000000..d595db0c91 --- /dev/null +++ b/src/vm/amd64/gmsamd64.cpp @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/**************************************************************/ +/* gmsAMD64.cpp */ +/**************************************************************/ + +#include "common.h" +#include "gmscpu.h" + +void LazyMachState::unwindLazyState(LazyMachState* baseState, + MachState* unwoundState, + DWORD threadId, + int funCallDepth /* = 1 */, + HostCallPreference hostCallPreference /* = (HostCallPreference)(-1) */) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + SUPPORTS_DAC; + } + CONTRACTL_END; + + CONTEXT ctx; + KNONVOLATILE_CONTEXT_POINTERS nonVolRegPtrs; + + ctx.Rip = baseState->m_CaptureRip; + ctx.Rsp = baseState->m_CaptureRsp + 8; // +8 for return addr pushed before calling LazyMachStateCaptureState + +#define CALLEE_SAVED_REGISTER(regname) ctx.regname = unwoundState->m_Capture.regname = baseState->m_Capture.regname; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + +#if !defined(DACCESS_COMPILE) + + // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it. + // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers. +#define CALLEE_SAVED_REGISTER(regname) nonVolRegPtrs.regname = (PDWORD64)&unwoundState->m_Capture.regname; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + +#endif // !DACCESS_COMPILE + + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->m_CaptureRip, baseState->m_CaptureRsp)); + + PCODE pvControlPc; + + do + { + +#ifndef FEATURE_PAL + pvControlPc = Thread::VirtualUnwindCallFrame(&ctx, &nonVolRegPtrs); +#else // !FEATURE_PAL + +#if defined(DACCESS_COMPILE) + HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs); + if (FAILED(hr)) + { + DacError(hr); + } +#else + BOOL success = PAL_VirtualUnwind(&ctx, &nonVolRegPtrs); + if (!success) + { + _ASSERTE(!"unwindLazyState: Unwinding failed"); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); + } +#endif // DACCESS_COMPILE + + pvControlPc = GetIP(&ctx); +#endif // !FEATURE_PAL + + if (funCallDepth > 0) + { + --funCallDepth; + if (funCallDepth == 0) + break; + } + else + { + // Determine whether given IP resides in JITted code. (It returns nonzero in that case.) + // Use it now to see if we've unwound to managed code yet. + BOOL fFailedReaderLock = FALSE; + BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc, hostCallPreference, &fFailedReaderLock); + if (fFailedReaderLock) + { + // We don't know if we would have been able to find a JIT + // manager, because we couldn't enter the reader lock without + // yielding (and our caller doesn't want us to yield). So abort + // now. + + // Invalidate the lazyState we're returning, so the caller knows + // we aborted before we could fully unwind + unwoundState->_pRetAddr = NULL; + return; + } + + if (fIsManagedCode) + break; + } + } + while(TRUE); + + // + // Update unwoundState so that HelperMethodFrameRestoreState knows which + // registers have been potentially modified. + // + + unwoundState->m_Rip = ctx.Rip; + unwoundState->m_Rsp = ctx.Rsp; + + // For DAC, the return value of this function may be used after unwoundState goes out of scope. so we cannot do + // "unwoundState->_pRetAddr = PTR_TADDR(&unwoundState->m_Rip)". + unwoundState->_pRetAddr = PTR_TADDR(unwoundState->m_Rsp - 8); + +#ifdef FEATURE_PAL +#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Unwound.regname = ctx.regname; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER +#endif + +#if defined(DACCESS_COMPILE) + + // For DAC, we have to update the registers directly, since we don't have context pointers. +#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Capture.regname = ctx.regname; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + + // Since we don't have context pointers in this case, just assing them to NULL. +#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = NULL; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + +#else // !DACCESS_COMPILE + +#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = PTR_ULONG64(nonVolRegPtrs.regname); + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + +#endif // DACCESS_COMPILE +} |