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
47struct EHContext;
48
49#ifdef DACCESS_COMPILE
50typedef 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
63typedef 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
74const int CODEMAN_STATE_SIZE = 512;
75
76struct 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
87enum 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
117class EECodeInfo;
118
119enum 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
135class ICodeManager
136{
137 VPTR_BASE_VTABLE_CLASS_AND_CTOR(ICodeManager)
138
139public:
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
146enum ContextType
147{
148 FILTER_CONTEXT,
149 CATCH_CONTEXT,
150 FINALLY_CONTEXT
151};
152
153/* Type of funclet corresponding to a shadow stack-pointer */
154
155enum
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
164virtual 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*/
181virtual 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*/
192virtual 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*/
203virtual 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*/
214virtual bool IsGcSafe(EECodeInfo *pCodeInfo,
215 DWORD dwRelOffset) = 0;
216
217#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
218virtual 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*/
227virtual 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*/
240virtual 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*/
253virtual 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*/
267virtual 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*/
276virtual 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)
281virtual 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*/
289virtual 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*/
298virtual 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*/
305virtual 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*/
316virtual size_t GetFunctionSize(GCInfoToken gcInfoToken) = 0;
317
318/*
319Returns the ReturnKind of a given function as reported in the GC info.
320*/
321
322virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken) = 0;
323
324#ifndef USE_GC_INFO_DECODER
325/*
326 Returns the size of the frame (barring localloc)
327*/
328virtual 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
336virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)=0;
337
338virtual BOOL IsInFilter(GCInfoToken gcInfoToken,
339 unsigned offset,
340 PCONTEXT pCtx,
341 DWORD curNestLevel) = 0;
342
343virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
344 unsigned offset,
345 PCONTEXT pCtx) = 0;
346
347virtual 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
359virtual 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
384struct hdrInfo;
385
386class EECodeManager : public ICodeManager {
387
388 VPTR_VTABLE_CLASS_AND_CTOR(EECodeManager, ICodeManager)
389
390public:
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*/
399virtual
400void 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*/
417virtual
418TADDR 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*/
429virtual
430ULONG32 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*/
441virtual
442bool 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
451enum 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
462static
463void 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*/
473virtual
474bool IsGcSafe( EECodeInfo *pCodeInfo,
475 DWORD dwRelOffset);
476
477#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
478virtual
479bool 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*/
488virtual
489unsigned 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*/
502virtual
503bool 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.
514bool 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*/
527static OBJECTREF* GetAddrOfSecurityObjectFromCachedInfo(
528 PREGDISPLAY pRD,
529 StackwalkCacheUnwindInfo * stackwalkCacheUnwindInfo);
530#endif // _TARGET_X86_
531
532#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
533virtual
534OBJECTREF* GetAddrOfSecurityObject(CrawlFrame *pCF) DAC_UNEXPECTED();
535#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
536
537#ifndef CROSSGEN_COMPILE
538virtual
539OBJECTREF 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*/
549virtual
550PTR_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)
555virtual 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*/
562static
563PTR_VOID GetExactGenericsToken(PREGDISPLAY pContext,
564 EECodeInfo * pCodeInfo);
565
566static
567PTR_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*/
578virtual
579void * 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*/
589virtual
590bool 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*/
598virtual
599bool 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*/
608virtual
609size_t GetFunctionSize(GCInfoToken gcInfoToken);
610
611/*
612Returns the ReturnKind of a given function.
613*/
614virtual ReturnKind GetReturnKind(GCInfoToken gcInfotoken);
615
616#ifndef USE_GC_INFO_DECODER
617/*
618 Returns the size of the frame (barring localloc)
619*/
620virtual
621unsigned int GetFrameSize(GCInfoToken gcInfoToken);
622#endif // USE_GC_INFO_DECODER
623
624#ifndef DACCESS_COMPILE
625
626#ifndef WIN64EXCEPTIONS
627virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg);
628virtual BOOL IsInFilter(GCInfoToken gcInfoToken,
629 unsigned offset,
630 PCONTEXT pCtx,
631 DWORD curNestLevel);
632virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
633 unsigned offset,
634 PCONTEXT pCtx);
635virtual 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*/
645virtual
646HRESULT 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_
672bool 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
683enum 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
695enum 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
717struct 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
792struct CodeManStateBuf
793{
794 DWORD hdrInfoSize;
795 hdrInfo hdrInfoBody;
796};
797//*****************************************************************************
798#endif // _EETWAIN_H
799//*****************************************************************************
800