summaryrefslogtreecommitdiff
path: root/src/vm/amd64/gmsamd64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/amd64/gmsamd64.cpp')
-rw-r--r--src/vm/amd64/gmsamd64.cpp144
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
+}