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