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 | // EETwain.h |
7 | // |
8 | // This file has the definition of ICodeManager and EECodeManager. |
9 | // |
10 | // ICorJitCompiler compiles the IL of a method to native code, and stores |
11 | // auxilliary data called as GCInfo (via ICorJitInfo::allocGCInfo()). |
12 | // The data is used by the EE to manage the method's garbage collection, |
13 | // exception handling, stack-walking etc. |
14 | // This data can be parsed by an ICodeManager corresponding to that |
15 | // ICorJitCompiler. |
16 | // |
17 | // EECodeManager is an implementation of ICodeManager for a default format |
18 | // of GCInfo. Various ICorJitCompiler's are free to share this format so that |
19 | // they do not need to provide their own implementation of ICodeManager |
20 | // (though they are permitted to, if they want). |
21 | // |
22 | //***************************************************************************** |
23 | |
24 | #ifndef _EETWAIN_H |
25 | #define _EETWAIN_H |
26 | //***************************************************************************** |
27 | |
28 | #include <daccess.h> |
29 | #include "regdisp.h" |
30 | #include "corjit.h" // For NativeVarInfo |
31 | #include "stackwalktypes.h" |
32 | #include "bitvector.h" |
33 | #include "gcinfotypes.h" |
34 | |
35 | #if !defined(_TARGET_X86_) |
36 | #define USE_GC_INFO_DECODER |
37 | #endif |
38 | |
39 | #if (defined(_TARGET_X86_) && !defined(FEATURE_PAL)) || defined(_TARGET_AMD64_) |
40 | #define HAS_QUICKUNWIND |
41 | #endif |
42 | |
43 | #define CHECK_APP_DOMAIN 0 |
44 | |
45 | #define NO_OVERRIDE_OFFSET (DWORD)-1 |
46 | |
47 | struct EHContext; |
48 | |
49 | #ifdef DACCESS_COMPILE |
50 | typedef struct _DAC_SLOT_LOCATION |
51 | { |
52 | int reg; |
53 | int regOffset; |
54 | bool targetPtr; |
55 | |
56 | _DAC_SLOT_LOCATION(int _reg, int _regOffset, bool _targetPtr) |
57 | : reg(_reg), regOffset(_regOffset), targetPtr(_targetPtr) |
58 | { |
59 | } |
60 | } DacSlotLocation; |
61 | #endif |
62 | |
63 | typedef void (*GCEnumCallback)( |
64 | LPVOID hCallback, // callback data |
65 | OBJECTREF* pObject, // address of obect-reference we are reporting |
66 | uint32_t flags // is this a pinned and/or interior pointer |
67 | DAC_ARG(DacSlotLocation loc) // where the reference came from |
68 | ); |
69 | |
70 | /****************************************************************************** |
71 | The stackwalker maintains some state on behalf of ICodeManager. |
72 | */ |
73 | |
74 | const int CODEMAN_STATE_SIZE = 512; |
75 | |
76 | struct CodeManState |
77 | { |
78 | DWORD dwIsSet; // Is set to 0 by the stackwalk as appropriate |
79 | BYTE stateBuf[CODEMAN_STATE_SIZE]; |
80 | }; |
81 | |
82 | /****************************************************************************** |
83 | These flags are used by some functions, although not all combinations might |
84 | make sense for all functions. |
85 | */ |
86 | |
87 | enum ICodeManagerFlags |
88 | { |
89 | ActiveStackFrame = 0x0001, // this is the currently active function |
90 | ExecutionAborted = 0x0002, // execution of this function has been aborted |
91 | // (i.e. it will not continue execution at the |
92 | // current location) |
93 | AbortingCall = 0x0004, // The current call will never return |
94 | UpdateAllRegs = 0x0008, // update full register set |
95 | CodeAltered = 0x0010, // code of that function might be altered |
96 | // (e.g. by debugger), need to call EE |
97 | // for original code |
98 | SpeculativeStackwalk |
99 | = 0x0020, // we're in the middle of a stackwalk seeded |
100 | // by an untrusted source (e.g., sampling profiler) |
101 | |
102 | ParentOfFuncletStackFrame |
103 | = 0x0040, // A funclet for this frame was previously reported |
104 | NoReportUntracked |
105 | = 0x0080, // EnumGCRefs/EnumerateLiveSlots should *not* include |
106 | // any untracked slots |
107 | }; |
108 | |
109 | //***************************************************************************** |
110 | // |
111 | // EECodeInfo is used by ICodeManager to get information about the |
112 | // method whose GCInfo is being processed. |
113 | // It is useful so that some information which is available elsewhere does |
114 | // not need to be cached in the GCInfo. |
115 | // |
116 | |
117 | class EECodeInfo; |
118 | |
119 | enum GenericParamContextType |
120 | { |
121 | GENERIC_PARAM_CONTEXT_NONE = 0, |
122 | GENERIC_PARAM_CONTEXT_THIS = 1, |
123 | GENERIC_PARAM_CONTEXT_METHODDESC = 2, |
124 | GENERIC_PARAM_CONTEXT_METHODTABLE = 3 |
125 | }; |
126 | |
127 | //***************************************************************************** |
128 | // |
129 | // ICodeManager is the abstract class that all CodeManagers |
130 | // must inherit from. This will probably need to move into |
131 | // cor.h and become a real com interface. |
132 | // |
133 | //***************************************************************************** |
134 | |
135 | class ICodeManager |
136 | { |
137 | VPTR_BASE_VTABLE_CLASS_AND_CTOR(ICodeManager) |
138 | |
139 | public: |
140 | |
141 | /* |
142 | Last chance for the runtime support to do fixups in the context |
143 | before execution continues inside a filter, catch handler, or fault/finally |
144 | */ |
145 | |
146 | enum ContextType |
147 | { |
148 | FILTER_CONTEXT, |
149 | CATCH_CONTEXT, |
150 | FINALLY_CONTEXT |
151 | }; |
152 | |
153 | /* Type of funclet corresponding to a shadow stack-pointer */ |
154 | |
155 | enum |
156 | { |
157 | SHADOW_SP_IN_FILTER = 0x1, |
158 | SHADOW_SP_FILTER_DONE = 0x2, |
159 | SHADOW_SP_BITS = 0x3 |
160 | }; |
161 | |
162 | #ifndef DACCESS_COMPILE |
163 | #ifndef WIN64EXCEPTIONS |
164 | virtual void FixContext(ContextType ctxType, |
165 | EHContext *ctx, |
166 | EECodeInfo *pCodeInfo, |
167 | DWORD dwRelOffset, |
168 | DWORD nestingLevel, |
169 | OBJECTREF thrownObject, |
170 | CodeManState *pState, |
171 | size_t ** ppShadowSP, // OUT |
172 | size_t ** ppEndRegion) = 0; // OUT |
173 | #endif // !WIN64EXCEPTIONS |
174 | #endif // #ifndef DACCESS_COMPILE |
175 | |
176 | #ifdef _TARGET_X86_ |
177 | /* |
178 | Gets the ambient stack pointer value at the given nesting level within |
179 | the method. |
180 | */ |
181 | virtual TADDR GetAmbientSP(PREGDISPLAY pContext, |
182 | EECodeInfo *pCodeInfo, |
183 | DWORD dwRelOffset, |
184 | DWORD nestingLevel, |
185 | CodeManState *pState) = 0; |
186 | #endif // _TARGET_X86_ |
187 | |
188 | /* |
189 | Get the number of bytes used for stack parameters. |
190 | This is currently only used on x86. |
191 | */ |
192 | virtual ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo) = 0; |
193 | |
194 | #ifndef CROSSGEN_COMPILE |
195 | /* |
196 | Unwind the current stack frame, i.e. update the virtual register |
197 | set in pContext. This will be similar to the state after the function |
198 | returns back to caller (IP points to after the call, Frame and Stack |
199 | pointer has been reset, callee-saved registers restored |
200 | (if UpdateAllRegs), callee-UNsaved registers are trashed) |
201 | Returns success of operation. |
202 | */ |
203 | virtual bool UnwindStackFrame(PREGDISPLAY pContext, |
204 | EECodeInfo *pCodeInfo, |
205 | unsigned flags, |
206 | CodeManState *pState, |
207 | StackwalkCacheUnwindInfo *pUnwindInfo) = 0; |
208 | #endif // CROSSGEN_COMPILE |
209 | |
210 | /* |
211 | Is the function currently at a "GC safe point" ? |
212 | Can call EnumGcRefs() successfully |
213 | */ |
214 | virtual bool IsGcSafe(EECodeInfo *pCodeInfo, |
215 | DWORD dwRelOffset) = 0; |
216 | |
217 | #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) |
218 | virtual bool HasTailCalls(EECodeInfo *pCodeInfo) = 0; |
219 | #endif // _TARGET_ARM_ || _TARGET_ARM64_ |
220 | |
221 | #if defined(_TARGET_AMD64_) && defined(_DEBUG) |
222 | /* |
223 | Locates the end of the last interruptible region in the given code range. |
224 | Returns 0 if the entire range is uninterruptible. Returns the end point |
225 | if the entire range is interruptible. |
226 | */ |
227 | virtual unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, |
228 | unsigned endOffset, |
229 | GCInfoToken gcInfoToken) = 0; |
230 | #endif // _TARGET_AMD64_ && _DEBUG |
231 | |
232 | #ifndef CROSSGEN_COMPILE |
233 | /* |
234 | Enumerate all live object references in that function using |
235 | the virtual register set. Same reference location cannot be enumerated |
236 | multiple times (but all differenct references pointing to the same |
237 | object have to be individually enumerated). |
238 | Returns success of operation. |
239 | */ |
240 | virtual bool EnumGcRefs(PREGDISPLAY pContext, |
241 | EECodeInfo *pCodeInfo, |
242 | unsigned flags, |
243 | GCEnumCallback pCallback, |
244 | LPVOID hCallBack, |
245 | DWORD relOffsetOverride = NO_OVERRIDE_OFFSET) = 0; |
246 | #endif // !CROSSGEN_COMPILE |
247 | |
248 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
249 | /* |
250 | Return the address of the local security object reference |
251 | (if available). |
252 | */ |
253 | virtual OBJECTREF* GetAddrOfSecurityObject(CrawlFrame *pCF) = 0; |
254 | #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE |
255 | |
256 | #ifndef CROSSGEN_COMPILE |
257 | /* |
258 | For a non-static method, "this" pointer is passed in as argument 0. |
259 | However, if there is a "ldarga 0" or "starg 0" in the IL, |
260 | JIT will create a copy of arg0 and redirect all "ldarg(a) 0" and "starg 0" to this copy. |
261 | (See Compiler::lvaArg0Var for more details.) |
262 | |
263 | The following method returns the original "this" argument, i.e. the one that is passed in, |
264 | if it is a non-static method AND the object is still alive. |
265 | Returns NULL in all other cases. |
266 | */ |
267 | virtual OBJECTREF GetInstance(PREGDISPLAY pContext, |
268 | EECodeInfo* pCodeInfo) = 0; |
269 | #endif // !CROSSGEN_COMPILE |
270 | |
271 | #ifndef CROSSGEN_COMPILE |
272 | /* |
273 | Returns the extra argument passed to to shared generic code if it is still alive. |
274 | Returns NULL in all other cases. |
275 | */ |
276 | virtual PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, |
277 | EECodeInfo * pCodeInfo) = 0; |
278 | #endif // !CROSSGEN_COMPILE |
279 | |
280 | // Returns the type of the context parameter (this, methodtable, methoddesc, or none) |
281 | virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, |
282 | EECodeInfo * pCodeInfo) = 0; |
283 | |
284 | #ifndef CROSSGEN_COMPILE |
285 | /* |
286 | Returns the offset of the GuardStack cookie if it exists. |
287 | Returns NULL if there is no cookie. |
288 | */ |
289 | virtual void * GetGSCookieAddr(PREGDISPLAY pContext, |
290 | EECodeInfo * pCodeInfo, |
291 | CodeManState * pState) = 0; |
292 | #endif |
293 | |
294 | #ifndef USE_GC_INFO_DECODER |
295 | /* |
296 | Returns true if the given IP is in the given method's prolog or an epilog. |
297 | */ |
298 | virtual bool IsInPrologOrEpilog(DWORD relPCOffset, |
299 | GCInfoToken gcInfoToken, |
300 | size_t* prologSize) = 0; |
301 | |
302 | /* |
303 | Returns true if the given IP is in the synchronized region of the method (valid for synchronized methods only) |
304 | */ |
305 | virtual bool IsInSynchronizedRegion( |
306 | DWORD relOffset, |
307 | GCInfoToken gcInfoToken, |
308 | unsigned flags) = 0; |
309 | #endif // !USE_GC_INFO_DECODER |
310 | |
311 | /* |
312 | Returns the size of a given function as reported in the GC info (does |
313 | not take procedure splitting into account). For the actual size of |
314 | the hot region call IJitManager::JitTokenToMethodHotSize. |
315 | */ |
316 | virtual size_t GetFunctionSize(GCInfoToken gcInfoToken) = 0; |
317 | |
318 | /* |
319 | Returns the ReturnKind of a given function as reported in the GC info. |
320 | */ |
321 | |
322 | virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken) = 0; |
323 | |
324 | #ifndef USE_GC_INFO_DECODER |
325 | /* |
326 | Returns the size of the frame (barring localloc) |
327 | */ |
328 | virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) = 0; |
329 | #endif // USE_GC_INFO_DECODER |
330 | |
331 | #ifndef DACCESS_COMPILE |
332 | |
333 | /* Debugger API */ |
334 | |
335 | #ifndef WIN64EXCEPTIONS |
336 | virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)=0; |
337 | |
338 | virtual BOOL IsInFilter(GCInfoToken gcInfoToken, |
339 | unsigned offset, |
340 | PCONTEXT pCtx, |
341 | DWORD curNestLevel) = 0; |
342 | |
343 | virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, |
344 | unsigned offset, |
345 | PCONTEXT pCtx) = 0; |
346 | |
347 | virtual void LeaveCatch(GCInfoToken gcInfoToken, |
348 | unsigned offset, |
349 | PCONTEXT pCtx)=0; |
350 | #endif // WIN64EXCEPTIONS |
351 | |
352 | #ifdef EnC_SUPPORTED |
353 | |
354 | /* |
355 | Last chance for the runtime support to do fixups in the context |
356 | before execution continues inside an EnC updated function. |
357 | */ |
358 | |
359 | virtual HRESULT FixContextForEnC(PCONTEXT pCtx, |
360 | EECodeInfo * pOldCodeInfo, |
361 | const ICorDebugInfo::NativeVarInfo * oldMethodVars, |
362 | SIZE_T oldMethodVarsCount, |
363 | EECodeInfo * pNewCodeInfo, |
364 | const ICorDebugInfo::NativeVarInfo * newMethodVars, |
365 | SIZE_T newMethodVarsCount) = 0; |
366 | |
367 | #endif // EnC_SUPPORTED |
368 | |
369 | #endif // #ifndef DACCESS_COMPILE |
370 | |
371 | |
372 | #ifdef DACCESS_COMPILE |
373 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0; |
374 | #endif |
375 | }; |
376 | |
377 | //***************************************************************************** |
378 | // |
379 | // EECodeManager is the EE's implementation of the ICodeManager which |
380 | // supports the default format of GCInfo. |
381 | // |
382 | //***************************************************************************** |
383 | |
384 | struct hdrInfo; |
385 | |
386 | class EECodeManager : public ICodeManager { |
387 | |
388 | VPTR_VTABLE_CLASS_AND_CTOR(EECodeManager, ICodeManager) |
389 | |
390 | public: |
391 | |
392 | |
393 | #ifndef DACCESS_COMPILE |
394 | #ifndef WIN64EXCEPTIONS |
395 | /* |
396 | Last chance for the runtime support to do fixups in the context |
397 | before execution continues inside a filter, catch handler, or finally |
398 | */ |
399 | virtual |
400 | void FixContext(ContextType ctxType, |
401 | EHContext *ctx, |
402 | EECodeInfo *pCodeInfo, |
403 | DWORD dwRelOffset, |
404 | DWORD nestingLevel, |
405 | OBJECTREF thrownObject, |
406 | CodeManState *pState, |
407 | size_t ** ppShadowSP, // OUT |
408 | size_t ** ppEndRegion); // OUT |
409 | #endif // !WIN64EXCEPTIONS |
410 | #endif // #ifndef DACCESS_COMPILE |
411 | |
412 | #ifdef _TARGET_X86_ |
413 | /* |
414 | Gets the ambient stack pointer value at the given nesting level within |
415 | the method. |
416 | */ |
417 | virtual |
418 | TADDR GetAmbientSP(PREGDISPLAY pContext, |
419 | EECodeInfo *pCodeInfo, |
420 | DWORD dwRelOffset, |
421 | DWORD nestingLevel, |
422 | CodeManState *pState); |
423 | #endif // _TARGET_X86_ |
424 | |
425 | /* |
426 | Get the number of bytes used for stack parameters. |
427 | This is currently only used on x86. |
428 | */ |
429 | virtual |
430 | ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo); |
431 | |
432 | #ifndef CROSSGEN_COMPILE |
433 | /* |
434 | Unwind the current stack frame, i.e. update the virtual register |
435 | set in pContext. This will be similar to the state after the function |
436 | returns back to caller (IP points to after the call, Frame and Stack |
437 | pointer has been reset, callee-saved registers restored |
438 | (if UpdateAllRegs), callee-UNsaved registers are trashed) |
439 | Returns success of operation. |
440 | */ |
441 | virtual |
442 | bool UnwindStackFrame( |
443 | PREGDISPLAY pContext, |
444 | EECodeInfo *pCodeInfo, |
445 | unsigned flags, |
446 | CodeManState *pState, |
447 | StackwalkCacheUnwindInfo *pUnwindInfo); |
448 | #endif // CROSSGEN_COMPILE |
449 | |
450 | #ifdef HAS_QUICKUNWIND |
451 | enum QuickUnwindFlag |
452 | { |
453 | UnwindCurrentStackFrame, |
454 | EnsureCallerStackFrameIsValid |
455 | }; |
456 | |
457 | /* |
458 | * Light unwind the current stack frame, using provided cache entry. |
459 | * only pPC and Esp of pContext are updated. And pEbp if necessary. |
460 | */ |
461 | |
462 | static |
463 | void QuickUnwindStackFrame( |
464 | PREGDISPLAY pRD, |
465 | StackwalkCacheEntry *pCacheEntry, |
466 | QuickUnwindFlag flag); |
467 | #endif // HAS_QUICKUNWIND |
468 | |
469 | /* |
470 | Is the function currently at a "GC safe point" ? |
471 | Can call EnumGcRefs() successfully |
472 | */ |
473 | virtual |
474 | bool IsGcSafe( EECodeInfo *pCodeInfo, |
475 | DWORD dwRelOffset); |
476 | |
477 | #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) |
478 | virtual |
479 | bool HasTailCalls(EECodeInfo *pCodeInfo); |
480 | #endif // _TARGET_ARM_ || _TARGET_ARM64_ |
481 | |
482 | #if defined(_TARGET_AMD64_) && defined(_DEBUG) |
483 | /* |
484 | Locates the end of the last interruptible region in the given code range. |
485 | Returns 0 if the entire range is uninterruptible. Returns the end point |
486 | if the entire range is interruptible. |
487 | */ |
488 | virtual |
489 | unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, |
490 | unsigned endOffset, |
491 | GCInfoToken gcInfoToken); |
492 | #endif // _TARGET_AMD64_ && _DEBUG |
493 | |
494 | #ifndef CROSSGEN_COMPILE |
495 | /* |
496 | Enumerate all live object references in that function using |
497 | the virtual register set. Same reference location cannot be enumerated |
498 | multiple times (but all differenct references pointing to the same |
499 | object have to be individually enumerated). |
500 | Returns success of operation. |
501 | */ |
502 | virtual |
503 | bool EnumGcRefs(PREGDISPLAY pContext, |
504 | EECodeInfo *pCodeInfo, |
505 | unsigned flags, |
506 | GCEnumCallback pCallback, |
507 | LPVOID hCallBack, |
508 | DWORD relOffsetOverride = NO_OVERRIDE_OFFSET); |
509 | #endif // !CROSSGEN_COMPILE |
510 | |
511 | #ifdef FEATURE_CONSERVATIVE_GC |
512 | // Temporary conservative collection, for testing purposes, until we have |
513 | // accurate gc info from the JIT. |
514 | bool EnumGcRefsConservative(PREGDISPLAY pRD, |
515 | EECodeInfo *pCodeInfo, |
516 | unsigned flags, |
517 | GCEnumCallback pCallBack, |
518 | LPVOID hCallBack); |
519 | #endif // FEATURE_CONSERVATIVE_GC |
520 | |
521 | #ifdef _TARGET_X86_ |
522 | /* |
523 | Return the address of the local security object reference |
524 | using data that was previously cached before in UnwindStackFrame |
525 | using StackwalkCacheUnwindInfo |
526 | */ |
527 | static OBJECTREF* GetAddrOfSecurityObjectFromCachedInfo( |
528 | PREGDISPLAY pRD, |
529 | StackwalkCacheUnwindInfo * stackwalkCacheUnwindInfo); |
530 | #endif // _TARGET_X86_ |
531 | |
532 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
533 | virtual |
534 | OBJECTREF* GetAddrOfSecurityObject(CrawlFrame *pCF) DAC_UNEXPECTED(); |
535 | #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE |
536 | |
537 | #ifndef CROSSGEN_COMPILE |
538 | virtual |
539 | OBJECTREF GetInstance( |
540 | PREGDISPLAY pContext, |
541 | EECodeInfo * pCodeInfo); |
542 | #endif // !CROSSGEN_COMPILE |
543 | |
544 | #ifndef CROSSGEN_COMPILE |
545 | /* |
546 | Returns the extra argument passed to to shared generic code if it is still alive. |
547 | Returns NULL in all other cases. |
548 | */ |
549 | virtual |
550 | PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, |
551 | EECodeInfo * pCodeInfo); |
552 | #endif // !CROSSGEN_COMPILE |
553 | |
554 | // Returns the type of the context parameter (this, methodtable, methoddesc, or none) |
555 | virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, |
556 | EECodeInfo * pCodeInfo); |
557 | |
558 | #if defined(WIN64EXCEPTIONS) && defined(USE_GC_INFO_DECODER) && !defined(CROSSGEN_COMPILE) |
559 | /* |
560 | Returns the generics token. This is used by GetInstance() and GetParamTypeArg() on WIN64. |
561 | */ |
562 | static |
563 | PTR_VOID GetExactGenericsToken(PREGDISPLAY pContext, |
564 | EECodeInfo * pCodeInfo); |
565 | |
566 | static |
567 | PTR_VOID GetExactGenericsToken(SIZE_T baseStackSlot, |
568 | EECodeInfo * pCodeInfo); |
569 | |
570 | |
571 | #endif // WIN64EXCEPTIONS && USE_GC_INFO_DECODER && !CROSSGEN_COMPILE |
572 | |
573 | #ifndef CROSSGEN_COMPILE |
574 | /* |
575 | Returns the offset of the GuardStack cookie if it exists. |
576 | Returns NULL if there is no cookie. |
577 | */ |
578 | virtual |
579 | void * GetGSCookieAddr(PREGDISPLAY pContext, |
580 | EECodeInfo * pCodeInfo, |
581 | CodeManState * pState); |
582 | #endif |
583 | |
584 | |
585 | #ifndef USE_GC_INFO_DECODER |
586 | /* |
587 | Returns true if the given IP is in the given method's prolog or an epilog. |
588 | */ |
589 | virtual |
590 | bool IsInPrologOrEpilog( |
591 | DWORD relOffset, |
592 | GCInfoToken gcInfoToken, |
593 | size_t* prologSize); |
594 | |
595 | /* |
596 | Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only) |
597 | */ |
598 | virtual |
599 | bool IsInSynchronizedRegion( |
600 | DWORD relOffset, |
601 | GCInfoToken gcInfoToken, |
602 | unsigned flags); |
603 | #endif // !USE_GC_INFO_DECODER |
604 | |
605 | /* |
606 | Returns the size of a given function. |
607 | */ |
608 | virtual |
609 | size_t GetFunctionSize(GCInfoToken gcInfoToken); |
610 | |
611 | /* |
612 | Returns the ReturnKind of a given function. |
613 | */ |
614 | virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken); |
615 | |
616 | #ifndef USE_GC_INFO_DECODER |
617 | /* |
618 | Returns the size of the frame (barring localloc) |
619 | */ |
620 | virtual |
621 | unsigned int GetFrameSize(GCInfoToken gcInfoToken); |
622 | #endif // USE_GC_INFO_DECODER |
623 | |
624 | #ifndef DACCESS_COMPILE |
625 | |
626 | #ifndef WIN64EXCEPTIONS |
627 | virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg); |
628 | virtual BOOL IsInFilter(GCInfoToken gcInfoToken, |
629 | unsigned offset, |
630 | PCONTEXT pCtx, |
631 | DWORD curNestLevel); |
632 | virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, |
633 | unsigned offset, |
634 | PCONTEXT pCtx); |
635 | virtual void LeaveCatch(GCInfoToken gcInfoToken, |
636 | unsigned offset, |
637 | PCONTEXT pCtx); |
638 | #endif // WIN64EXCEPTIONS |
639 | |
640 | #ifdef EnC_SUPPORTED |
641 | /* |
642 | Last chance for the runtime support to do fixups in the context |
643 | before execution continues inside an EnC updated function. |
644 | */ |
645 | virtual |
646 | HRESULT FixContextForEnC(PCONTEXT pCtx, |
647 | EECodeInfo * pOldCodeInfo, |
648 | const ICorDebugInfo::NativeVarInfo * oldMethodVars, |
649 | SIZE_T oldMethodVarsCount, |
650 | EECodeInfo * pNewCodeInfo, |
651 | const ICorDebugInfo::NativeVarInfo * newMethodVars, |
652 | SIZE_T newMethodVarsCount); |
653 | #endif // EnC_SUPPORTED |
654 | |
655 | #endif // #ifndef DACCESS_COMPILE |
656 | |
657 | #ifdef WIN64EXCEPTIONS |
658 | static void EnsureCallerContextIsValid( PREGDISPLAY pRD, StackwalkCacheEntry* pCacheEntry, EECodeInfo * pCodeInfo = NULL ); |
659 | static size_t GetCallerSp( PREGDISPLAY pRD ); |
660 | #ifdef _TARGET_X86_ |
661 | static size_t GetResumeSp( PCONTEXT pContext ); |
662 | #endif // _TARGET_X86_ |
663 | #endif // WIN64EXCEPTIONS |
664 | |
665 | #ifdef DACCESS_COMPILE |
666 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
667 | #endif |
668 | |
669 | }; |
670 | |
671 | #ifdef _TARGET_X86_ |
672 | bool UnwindStackFrame(PREGDISPLAY pContext, |
673 | EECodeInfo *pCodeInfo, |
674 | unsigned flags, |
675 | CodeManState *pState, |
676 | StackwalkCacheUnwindInfo *pUnwindInfo); |
677 | #endif |
678 | |
679 | /***************************************************************************** |
680 | <TODO>ToDo: Do we want to include JIT/IL/target.h? </TODO> |
681 | */ |
682 | |
683 | enum regNum |
684 | { |
685 | REGI_EAX, REGI_ECX, REGI_EDX, REGI_EBX, |
686 | REGI_ESP, REGI_EBP, REGI_ESI, REGI_EDI, |
687 | REGI_COUNT, |
688 | REGI_NA = REGI_COUNT |
689 | }; |
690 | |
691 | /***************************************************************************** |
692 | Register masks |
693 | */ |
694 | |
695 | enum RegMask |
696 | { |
697 | RM_EAX = 0x01, |
698 | RM_ECX = 0x02, |
699 | RM_EDX = 0x04, |
700 | RM_EBX = 0x08, |
701 | RM_ESP = 0x10, |
702 | RM_EBP = 0x20, |
703 | RM_ESI = 0x40, |
704 | RM_EDI = 0x80, |
705 | |
706 | RM_NONE = 0x00, |
707 | RM_ALL = (RM_EAX|RM_ECX|RM_EDX|RM_EBX|RM_ESP|RM_EBP|RM_ESI|RM_EDI), |
708 | RM_CALLEE_SAVED = (RM_EBP|RM_EBX|RM_ESI|RM_EDI), |
709 | RM_CALLEE_TRASHED = (RM_ALL & ~RM_CALLEE_SAVED), |
710 | }; |
711 | |
712 | /***************************************************************************** |
713 | * |
714 | * Helper to extract basic info from a method info block. |
715 | */ |
716 | |
717 | struct hdrInfo |
718 | { |
719 | unsigned int methodSize; // native code bytes |
720 | unsigned int argSize; // in bytes |
721 | unsigned int stackSize; // including callee saved registers |
722 | unsigned int rawStkSize; // excluding callee saved registers |
723 | ReturnKind returnKind; // The ReturnKind for this method. |
724 | |
725 | unsigned int prologSize; |
726 | |
727 | // Size of the epilogs in the method. |
728 | // For methods which use CEE_JMP, some epilogs may end with a "ret" instruction |
729 | // and some may end with a "jmp". The epilogSize reported should be for the |
730 | // epilog with the smallest size. |
731 | unsigned int epilogSize; |
732 | |
733 | unsigned char epilogCnt; |
734 | bool epilogEnd; // is the epilog at the end of the method |
735 | |
736 | bool ebpFrame; // locals and arguments addressed relative to EBP |
737 | bool doubleAlign; // is the stack double-aligned? locals addressed relative to ESP, and arguments relative to EBP |
738 | bool interruptible; // intr. at all times (excluding prolog/epilog), not just call sites |
739 | |
740 | bool securityCheck; // has a slot for security object |
741 | bool handlers; // has callable handlers |
742 | bool localloc; // uses localloc |
743 | bool editNcontinue; // has been compiled in EnC mode |
744 | bool varargs; // is this a varargs routine |
745 | bool profCallbacks; // does the method have Enter-Leave callbacks |
746 | bool genericsContext;// has a reported generic context paramter |
747 | bool genericsContextIsMethodDesc;// reported generic context parameter is methoddesc |
748 | bool isSpeculativeStackWalk; // is the stackwalk seeded by an untrusted source (e.g., sampling profiler)? |
749 | |
750 | // These always includes EBP for EBP-frames and double-aligned-frames |
751 | RegMask savedRegMask:8; // which callee-saved regs are saved on stack |
752 | |
753 | // Count of the callee-saved registers, excluding the frame pointer. |
754 | // This does not include EBP for EBP-frames and double-aligned-frames. |
755 | unsigned int savedRegsCountExclFP; |
756 | |
757 | unsigned int untrackedCnt; |
758 | unsigned int varPtrTableSize; |
759 | unsigned int argTabOffset; // INVALID_ARGTAB_OFFSET if argtab must be reached by stepping through ptr tables |
760 | unsigned int gsCookieOffset; // INVALID_GS_COOKIE_OFFSET if there is no GuardStack cookie |
761 | |
762 | unsigned int syncStartOffset; // start/end code offset of the protected region in synchronized methods. |
763 | unsigned int syncEndOffset; // INVALID_SYNC_OFFSET if there not synchronized method |
764 | unsigned int syncEpilogStart; // The start of the epilog. Synchronized methods are guaranteed to have no more than one epilog. |
765 | unsigned int revPInvokeOffset; // INVALID_REV_PINVOKE_OFFSET if there is no Reverse PInvoke frame |
766 | |
767 | enum { NOT_IN_PROLOG = -1, NOT_IN_EPILOG = -1 }; |
768 | |
769 | int prologOffs; // NOT_IN_PROLOG if not in prolog |
770 | int epilogOffs; // NOT_IN_EPILOG if not in epilog. It is never 0 |
771 | |
772 | // |
773 | // Results passed back from scanArgRegTable |
774 | // |
775 | regNum thisPtrResult; // register holding "this" |
776 | RegMask regMaskResult; // registers currently holding GC ptrs |
777 | RegMask iregMaskResult; // iptr qualifier for regMaskResult |
778 | unsigned argHnumResult; |
779 | PTR_CBYTE argTabResult; // Table of encoded offsets of pending ptr args |
780 | unsigned argTabBytes; // Number of bytes in argTabResult[] |
781 | |
782 | // These next two are now large structs (i.e 132 bytes each) |
783 | |
784 | ptrArgTP argMaskResult; // pending arguments mask |
785 | ptrArgTP iargMaskResult; // iptr qualifier for argMaskResult |
786 | }; |
787 | |
788 | /***************************************************************************** |
789 | How the stackwalkers buffer will be interpreted |
790 | */ |
791 | |
792 | struct CodeManStateBuf |
793 | { |
794 | DWORD hdrInfoSize; |
795 | hdrInfo hdrInfoBody; |
796 | }; |
797 | //***************************************************************************** |
798 | #endif // _EETWAIN_H |
799 | //***************************************************************************** |
800 | |