[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / stackwalktypes.h
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: stackwalktypes.h
6 //
7
8 // ============================================================================
9 // Contains types used by stackwalk.h.
10
11
12 #ifndef __STACKWALKTYPES_H__
13 #define __STACKWALKTYPES_H__
14
15 class CrawlFrame;
16 struct RangeSection;
17 struct StackwalkCacheEntry;
18
19 //
20 // This type should be used internally inside the code manager only. EECodeInfo should 
21 // be used in general code instead. Ideally, we would replace all uses of METHODTOKEN 
22 // with EECodeInfo.
23 //
24 struct METHODTOKEN
25 {
26     METHODTOKEN(RangeSection * pRangeSection, TADDR pCodeHeader)
27         : m_pRangeSection(pRangeSection), m_pCodeHeader(pCodeHeader)
28     {
29     }
30
31     METHODTOKEN()
32     {
33     }
34
35     // Cache of RangeSection containing the code to avoid redundant lookups.
36     RangeSection * m_pRangeSection;
37
38     // CodeHeader* for EEJitManager
39     // PTR_RUNTIME_FUNCTION for managed native code
40     TADDR m_pCodeHeader;
41
42     BOOL IsNull() const
43     {
44         return m_pCodeHeader == NULL;
45     }
46 };
47
48 //************************************************************************
49 // Stack walking
50 //************************************************************************
51 enum StackCrawlMark
52 {
53     LookForMe = 0,
54     LookForMyCaller = 1,
55     LookForMyCallersCaller = 2,
56     LookForThread = 3
57 };
58
59 enum StackWalkAction 
60 {
61     SWA_CONTINUE    = 0,    // continue walking
62     SWA_ABORT       = 1,    // stop walking, early out in "failure case"
63     SWA_FAILED      = 2     // couldn't walk stack
64 };
65
66 #define SWA_DONE SWA_CONTINUE
67
68
69 // Pointer to the StackWalk callback function.
70 typedef StackWalkAction (*PSTACKWALKFRAMESCALLBACK)(
71     CrawlFrame       *pCF,      //
72     VOID*             pData     // Caller's private data
73
74 );
75
76 /******************************************************************************
77    StackwalkCache: new class implements stackwalk perf optimization features.
78    StackwalkCacheEntry array: very simple per thread hash table, keeping cached data.
79    StackwalkCacheUnwindInfo: used by EECodeManager::UnwindStackFrame to return
80    stackwalk cache flags.
81    Cf. Ilyakoz for any questions.
82 */
83
84 struct StackwalkCacheUnwindInfo
85 {
86 #if defined(_TARGET_AMD64_)
87     ULONG RBPOffset;
88     ULONG RSPOffsetFromUnwindInfo;
89 #else  // !_TARGET_AMD64_
90     size_t securityObjectOffset;    // offset of SecurityObject. 0 if there is no security object
91     BOOL fUseEbp;                   // Is EBP modified by the method - either for a frame-pointer or for a scratch-register?
92     BOOL fUseEbpAsFrameReg;         // use EBP as the frame pointer?
93 #endif // !_TARGET_AMD64_
94
95     inline StackwalkCacheUnwindInfo() { SUPPORTS_DAC; ZeroMemory(this, sizeof(StackwalkCacheUnwindInfo)); }
96     StackwalkCacheUnwindInfo(StackwalkCacheEntry * pCacheEntry);
97 };
98
99 //************************************************************************
100
101 #if defined(_WIN64)
102     #define STACKWALK_CACHE_ENTRY_ALIGN_BOUNDARY 0x10
103 #else  // !_WIN64
104     #define STACKWALK_CACHE_ENTRY_ALIGN_BOUNDARY 0x8
105 #endif // !_WIN64
106
107 struct 
108 DECLSPEC_ALIGN(STACKWALK_CACHE_ENTRY_ALIGN_BOUNDARY)
109 StackwalkCacheEntry
110 {
111     //
112     //  don't rearrange the fields, so that invalid value 0x8000000000000000 will never appear
113     //  as StackwalkCacheEntry, it's required for atomicMOVQ using FILD/FISTP instructions
114     //
115     UINT_PTR IP;
116 #if !defined(_TARGET_AMD64_)
117     WORD ESPOffset:15;          // stack offset (frame size + pending arguments + etc)
118     WORD securityObjectOffset:3;// offset of SecurityObject. 0 if there is no security object
119     WORD fUseEbp:1;             // For ESP methods, is EBP touched at all?
120     WORD fUseEbpAsFrameReg:1;   // use EBP as the frame register?
121     WORD argSize:11;            // size of args pushed on stack
122 #else  // _TARGET_AMD64_
123     DWORD RSPOffset;
124     DWORD RBPOffset;
125 #endif // _TARGET_AMD64_
126
127     inline BOOL Init(UINT_PTR   IP,
128                      UINT_PTR   SPOffset,
129                      StackwalkCacheUnwindInfo *pUnwindInfo,
130                      UINT_PTR   argSize)
131     {
132         LIMITED_METHOD_CONTRACT;
133
134         this->IP              = IP;
135
136 #if defined(_TARGET_X86_)
137         this->ESPOffset         = SPOffset;
138         this->argSize           = argSize;
139         
140         this->securityObjectOffset = (WORD)pUnwindInfo->securityObjectOffset;
141         _ASSERTE(this->securityObjectOffset == pUnwindInfo->securityObjectOffset);
142         
143         this->fUseEbp           = pUnwindInfo->fUseEbp;
144         this->fUseEbpAsFrameReg = pUnwindInfo->fUseEbpAsFrameReg;
145         _ASSERTE(!fUseEbpAsFrameReg || fUseEbp);
146
147         // return success if we fit SPOffset and argSize into
148         return ((this->ESPOffset == SPOffset) && 
149                 (this->argSize == argSize));
150 #elif defined(_TARGET_AMD64_)
151         // The size of a stack frame is guaranteed to fit in 4 bytes, so we don't need to check RSPOffset and RBPOffset.
152
153         // The actual SP offset may be bigger than the offset we get from the unwind info because of stack allocations.
154         _ASSERTE(SPOffset >= pUnwindInfo->RSPOffsetFromUnwindInfo);
155
156         _ASSERTE(FitsIn<DWORD>(SPOffset));
157         this->RSPOffset  = static_cast<DWORD>(SPOffset);
158         _ASSERTE(FitsIn<DWORD>(pUnwindInfo->RBPOffset + (SPOffset - pUnwindInfo->RSPOffsetFromUnwindInfo)));
159         this->RBPOffset  = static_cast<DWORD>(pUnwindInfo->RBPOffset + (SPOffset - pUnwindInfo->RSPOffsetFromUnwindInfo));
160         return TRUE;
161 #else  // !_TARGET_X86_ && !_TARGET_AMD64_
162         return FALSE;
163 #endif // !_TARGET_X86_ && !_TARGET_AMD64_
164     }
165
166     inline BOOL HasSecurityObject()
167     {
168         LIMITED_METHOD_CONTRACT;
169
170 #if defined(_TARGET_X86_)
171         return securityObjectOffset != 0;
172 #else  // !_TARGET_X86_
173         // On AMD64 we don't save anything by grabbing the security object before it is needed.  This is because
174         // we need to crack the GC info in order to find the security object, and to unwind we only need to
175         // crack the unwind info.
176         return FALSE;
177 #endif // !_TARGET_X86_
178     }
179
180     inline BOOL IsSafeToUseCache()
181     {
182         LIMITED_METHOD_CONTRACT;
183
184 #if defined(_TARGET_X86_)
185         return (!fUseEbp || fUseEbpAsFrameReg);
186 #elif defined(_TARGET_AMD64_)
187         return TRUE;
188 #else  // !_TARGET_X86_ && !_TARGET_AMD64_
189         return FALSE;
190 #endif // !_TARGET_X86_ && !_TARGET_AMD64_
191     }
192 };
193
194 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
195 static_assert_no_msg(sizeof(StackwalkCacheEntry) == 2 * sizeof(UINT_PTR));
196 #endif // _TARGET_X86_ || _TARGET_AMD64_
197
198 //************************************************************************
199
200 class StackwalkCache 
201 {
202     friend struct _DacGlobals;
203
204     public:
205         BOOL Lookup(UINT_PTR IP);
206         void Insert(StackwalkCacheEntry *pCacheEntry);
207         inline void ClearEntry () { LIMITED_METHOD_DAC_CONTRACT; m_CacheEntry.IP = 0; }
208         inline BOOL Enabled() { LIMITED_METHOD_DAC_CONTRACT;  return s_Enabled; };
209         inline BOOL IsEmpty () { LIMITED_METHOD_CONTRACT;  return m_CacheEntry.IP == 0; }
210
211 #ifndef DACCESS_COMPILE
212         StackwalkCache();
213 #endif
214         static void Init();
215
216         StackwalkCacheEntry m_CacheEntry; // local copy of Global Cache entry for current IP
217         
218         static void Invalidate(LoaderAllocator * pLoaderAllocator);
219         
220     private:
221         unsigned GetKey(UINT_PTR IP);
222         
223 #ifdef DACCESS_COMPILE
224         // DAC can't rely on the cache here
225         const static BOOL s_Enabled;
226 #else
227         static BOOL s_Enabled;
228 #endif
229 };
230
231 //************************************************************************
232
233 inline StackwalkCacheUnwindInfo::StackwalkCacheUnwindInfo(StackwalkCacheEntry * pCacheEntry) 
234 {
235     LIMITED_METHOD_CONTRACT;
236     
237 #if defined(_TARGET_AMD64_)
238     RBPOffset = pCacheEntry->RBPOffset;
239 #else  // !_TARGET_AMD64_
240     securityObjectOffset = pCacheEntry->securityObjectOffset;
241     fUseEbp = pCacheEntry->fUseEbp;
242     fUseEbpAsFrameReg = pCacheEntry->fUseEbpAsFrameReg;
243 #endif // !_TARGET_AMD64_
244 }
245
246 #endif  // __STACKWALKTYPES_H__