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/**************************************************************/
6/* gmsAMD64.cpp */
7/**************************************************************/
8
9#include "common.h"
10#include "gmscpu.h"
11
12void LazyMachState::unwindLazyState(LazyMachState* baseState,
13 MachState* unwoundState,
14 DWORD threadId,
15 int funCallDepth /* = 1 */,
16 HostCallPreference hostCallPreference /* = (HostCallPreference)(-1) */)
17{
18 CONTRACTL
19 {
20 NOTHROW;
21 GC_NOTRIGGER;
22 SO_TOLERANT;
23 SUPPORTS_DAC;
24 }
25 CONTRACTL_END;
26
27 CONTEXT ctx;
28 KNONVOLATILE_CONTEXT_POINTERS nonVolRegPtrs;
29
30 ctx.Rip = baseState->m_CaptureRip;
31 ctx.Rsp = baseState->m_CaptureRsp + 8; // +8 for return addr pushed before calling LazyMachStateCaptureState
32
33#define CALLEE_SAVED_REGISTER(regname) ctx.regname = unwoundState->m_Capture.regname = baseState->m_Capture.regname;
34 ENUM_CALLEE_SAVED_REGISTERS();
35#undef CALLEE_SAVED_REGISTER
36
37#if !defined(DACCESS_COMPILE)
38
39 // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
40 // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
41#define CALLEE_SAVED_REGISTER(regname) nonVolRegPtrs.regname = (PDWORD64)&unwoundState->m_Capture.regname;
42 ENUM_CALLEE_SAVED_REGISTERS();
43#undef CALLEE_SAVED_REGISTER
44
45#endif // !DACCESS_COMPILE
46
47 LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->m_CaptureRip, baseState->m_CaptureRsp));
48
49 PCODE pvControlPc;
50
51 do
52 {
53
54#ifndef FEATURE_PAL
55 pvControlPc = Thread::VirtualUnwindCallFrame(&ctx, &nonVolRegPtrs);
56#else // !FEATURE_PAL
57
58#if defined(DACCESS_COMPILE)
59 HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs);
60 if (FAILED(hr))
61 {
62 DacError(hr);
63 }
64#else
65 BOOL success = PAL_VirtualUnwind(&ctx, &nonVolRegPtrs);
66 if (!success)
67 {
68 _ASSERTE(!"unwindLazyState: Unwinding failed");
69 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
70 }
71#endif // DACCESS_COMPILE
72
73 pvControlPc = GetIP(&ctx);
74#endif // !FEATURE_PAL
75
76 if (funCallDepth > 0)
77 {
78 --funCallDepth;
79 if (funCallDepth == 0)
80 break;
81 }
82 else
83 {
84 // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
85 // Use it now to see if we've unwound to managed code yet.
86 BOOL fFailedReaderLock = FALSE;
87 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc, hostCallPreference, &fFailedReaderLock);
88 if (fFailedReaderLock)
89 {
90 // We don't know if we would have been able to find a JIT
91 // manager, because we couldn't enter the reader lock without
92 // yielding (and our caller doesn't want us to yield). So abort
93 // now.
94
95 // Invalidate the lazyState we're returning, so the caller knows
96 // we aborted before we could fully unwind
97 unwoundState->_pRetAddr = NULL;
98 return;
99 }
100
101 if (fIsManagedCode)
102 break;
103 }
104 }
105 while(TRUE);
106
107 //
108 // Update unwoundState so that HelperMethodFrameRestoreState knows which
109 // registers have been potentially modified.
110 //
111
112 unwoundState->m_Rip = ctx.Rip;
113 unwoundState->m_Rsp = ctx.Rsp;
114
115 // For DAC, the return value of this function may be used after unwoundState goes out of scope. so we cannot do
116 // "unwoundState->_pRetAddr = PTR_TADDR(&unwoundState->m_Rip)".
117 unwoundState->_pRetAddr = PTR_TADDR(unwoundState->m_Rsp - 8);
118
119#ifdef FEATURE_PAL
120#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Unwound.regname = ctx.regname;
121 ENUM_CALLEE_SAVED_REGISTERS();
122#undef CALLEE_SAVED_REGISTER
123#endif
124
125#if defined(DACCESS_COMPILE)
126
127 // For DAC, we have to update the registers directly, since we don't have context pointers.
128#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Capture.regname = ctx.regname;
129 ENUM_CALLEE_SAVED_REGISTERS();
130#undef CALLEE_SAVED_REGISTER
131
132 // Since we don't have context pointers in this case, just assing them to NULL.
133#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = NULL;
134 ENUM_CALLEE_SAVED_REGISTERS();
135#undef CALLEE_SAVED_REGISTER
136
137#else // !DACCESS_COMPILE
138
139#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = PTR_ULONG64(nonVolRegPtrs.regname);
140 ENUM_CALLEE_SAVED_REGISTERS();
141#undef CALLEE_SAVED_REGISTER
142
143#endif // DACCESS_COMPILE
144}
145