Add a fourth parameter to the DEFINE_DACVAR macro that is the actual fully qualified...
[platform/upstream/coreclr.git] / src / vm / stubmgr.h
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 // StubMgr.h
6 //
7
8 //
9 // The stub manager exists so that the debugger can accurately step through 
10 // the myriad stubs & wrappers which exist in the EE, without imposing undue 
11 // overhead on the stubs themselves.
12 //
13 // Each type of stub (except those which the debugger can treat as atomic operations)
14 // needs to have a stub manager to represent it.  The stub manager is responsible for
15 // (a) identifying the stub as such, and
16 // (b) tracing into the stub & reporting what the stub will call.  This
17 //        report can consist of
18 //              (i) a managed code address
19 //              (ii) an unmanaged code address
20 //              (iii) another stub address
21 //              (iv) a "frame patch" address - that is, an address in the stub, 
22 //                      which the debugger can patch. When the patch is hit, the debugger
23 //                      will query the topmost frame to trace itself.  (Thus this is 
24 //                      a way of deferring the trace logic to the frame which the stub
25 //                      will push.)
26 //
27 // The set of stub managers is extensible, but should be kept to a reasonable number
28 // as they are currently linearly searched & queried for each stub.
29 //
30
31
32 #ifndef __stubmgr_h__
33 #define __stubmgr_h__
34
35 #include "simplerwlock.hpp"
36
37 // When 'TraceStub' returns, it gives the address of where the 'target' is for a stub'
38 // TraceType indicates what this 'target' is
39 enum TraceType
40 {
41     TRACE_ENTRY_STUB,               // Stub goes to an unmanaged entry stub 
42     TRACE_STUB,                     // Stub goes to another stub
43     TRACE_UNMANAGED,                // Stub goes to unmanaged code
44     TRACE_MANAGED,                  // Stub goes to Jitted code
45     TRACE_UNJITTED_METHOD,          // Is the prestub, since there is no code, the address will actually be a MethodDesc*
46
47     TRACE_FRAME_PUSH,               // Don't know where stub goes, stop at address, and then ask the frame that is on the stack
48     TRACE_MGR_PUSH,                 // Don't know where stub goes, stop at address then call TraceManager() below to find out 
49
50     TRACE_OTHER                     // We are going somewhere you can't step into (eg. ee helper function)
51 };
52
53 class StubManager;
54 class SString;
55
56 class DebuggerRCThread;
57
58 enum StubCodeBlockKind : int;
59
60 // A TraceDestination describes where code is going to call. This can be used by the Debugger's Step-In functionality
61 // to skip through stubs and place a patch directly at a call's target.
62 // TD are supplied by the stubmanagers.
63 class TraceDestination
64 {
65 public:
66     friend class DebuggerRCThread;
67     
68     TraceDestination() { }
69
70 #ifdef _DEBUG
71     // Get a string representation of this TraceDestination
72     // Uses the supplied buffer to store the memory (or may return a string literal).
73     // This will also print the TD's arguments.    
74     const WCHAR * DbgToString(SString &buffer);
75 #endif
76
77     // Initialize for unmanaged code.
78     // The addr is in unmanaged code. Used for Step-in from managed to native.
79     void InitForUnmanaged(PCODE addr)
80     {
81         STATIC_CONTRACT_SO_TOLERANT;
82         this->type = TRACE_UNMANAGED;
83         this->address = addr;
84         this->stubManager = NULL;        
85     }
86
87     // The addr is inside jitted code (eg, there's a JitManaged that will claim it)
88     void InitForManaged(PCODE addr)
89     {
90         STATIC_CONTRACT_SO_TOLERANT;
91         this->type = TRACE_MANAGED;
92         this->address = addr;
93         this->stubManager = NULL;
94     }
95
96     // Initialize for an unmanaged entry stub.
97     void InitForUnmanagedStub(PCODE addr)
98     {
99         STATIC_CONTRACT_SO_TOLERANT;
100         this->type = TRACE_ENTRY_STUB;
101         this->address = addr;
102         this->stubManager = NULL;
103     }
104
105     // Initialize for a stub.
106     void InitForStub(PCODE addr)
107     {
108         STATIC_CONTRACT_SO_TOLERANT;
109         this->type = TRACE_STUB;
110         this->address = addr;
111         this->stubManager = NULL;
112     }
113
114     // Init for a managed unjitted method.
115     // This will place an IL patch that will get bound when the debugger gets a Jit complete
116     // notification for this method.
117     // If pDesc is a wrapper methoddesc, we will unwrap it.
118     void InitForUnjittedMethod(MethodDesc * pDesc);
119
120     // Place a patch at the given addr, and then when it's hit,
121     // call pStubManager->TraceManager() to get the next TraceDestination.
122     void InitForManagerPush(PCODE addr, StubManager * pStubManager)
123     {
124         STATIC_CONTRACT_SO_TOLERANT;
125         this->type = TRACE_MGR_PUSH;
126         this->address = addr;
127         this->stubManager = pStubManager;
128     }
129
130     // Place a patch at the given addr, and then when it's hit
131     // call GetThread()->GetFrame()->TraceFrame() to get the next TraceDestination.
132     // This address must be safe to run a callstack at.
133     void InitForFramePush(PCODE addr)
134     {
135         this->type = TRACE_FRAME_PUSH;
136         this->address = addr;
137         this->stubManager = NULL;
138     }
139
140     // Nobody recognized the target address. We will not be able to step-in to it.
141     // This is ok if the target just calls into mscorwks (such as an Fcall) because
142     // there's no managed code to step in to, and we don't support debugging the CLR
143     // itself, so there's no native code to step into either.
144     void InitForOther(PCODE addr)
145     {
146         this->type = TRACE_OTHER;
147         this->address = addr;
148         this->stubManager = NULL;
149     }
150
151     // Accessors
152     TraceType GetTraceType() { return type; }
153     PCODE GetAddress() 
154     {
155         LIMITED_METHOD_CONTRACT;
156         _ASSERTE(type != TRACE_UNJITTED_METHOD);
157         return address; 
158     }
159     MethodDesc* GetMethodDesc()
160     {
161         LIMITED_METHOD_CONTRACT;
162         _ASSERTE(type == TRACE_UNJITTED_METHOD);
163         return pDesc;
164     }    
165
166     StubManager * GetStubManager()
167     {
168         return stubManager;
169     }
170
171     // Expose this b/c DebuggerPatchTable::AddPatchForAddress() needs it.
172     // Ideally we'd get rid of this.
173     void Bad_SetTraceType(TraceType t)
174     {
175         this->type = t;
176     }
177 private:
178     TraceType                       type;               // The kind of code the stub is going to
179     PCODE                           address;            // Where the stub is going    
180     StubManager                     *stubManager;       // The manager that claims this stub
181     MethodDesc                      *pDesc;
182 };
183
184 // For logging
185 #ifdef LOGGING
186     void LogTraceDestination(const char * szHint, PCODE stubAddr, TraceDestination * pTrace);
187     #define LOG_TRACE_DESTINATION(_tracedestination, stubAddr, _stHint)  LogTraceDestination(_stHint, stubAddr, _tracedestination)
188 #else
189     #define LOG_TRACE_DESTINATION(_tracedestination, stubAddr, _stHint)    
190 #endif
191
192 typedef VPTR(class StubManager) PTR_StubManager;
193
194 class StubManager
195 {
196     friend class StubManagerIterator;
197
198     VPTR_BASE_VTABLE_CLASS(StubManager)
199     
200   public:
201     // Startup and shutdown the global stubmanager service.
202     static void InitializeStubManagers();
203     static void TerminateStubManagers();
204
205     // Does any sub manager recognise this EIP?
206     static BOOL IsStub(PCODE stubAddress)
207     {
208         WRAPPER_NO_CONTRACT;
209         return FindStubManager(stubAddress) != NULL;
210     }
211
212     // Find stub manager for given code address
213     static PTR_StubManager FindStubManager(PCODE stubAddress);
214         
215     // Look for stubAddress, if found return TRUE, and set 'trace' to 
216     static BOOL TraceStub(PCODE stubAddress, TraceDestination *trace);
217     
218     // if 'trace' indicates TRACE_STUB, keep calling TraceStub on 'trace', until you get out of all stubs
219     // returns true if successfull
220     static BOOL FollowTrace(TraceDestination *trace);
221     
222 #ifdef DACCESS_COMPILE
223     static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
224 #endif
225
226     static void AddStubManager(StubManager *mgr);
227
228     // NOTE: Very important when using this. It is not thread safe, except in this very
229     //       limited scenario: the thread must have the runtime suspended.
230     static void UnlinkStubManager(StubManager *mgr);
231     
232 #ifndef DACCESS_COMPILE
233     StubManager();
234     virtual ~StubManager();
235 #endif
236
237
238 #ifdef _DEBUG
239     // Debug helper to help identify stub-managers. Make it pure to force stub managers to implement it.
240     virtual const char * DbgGetName() = 0;
241 #endif
242
243     // Only Stubmanagers that return 'TRACE_MGR_PUSH' as a trace type need to implement this function
244     // Fills in 'trace' (the target), and 'pRetAddr' (the method that called the stub) (this is needed
245     // as a 'fall back' so that the debugger can at least stop when the stub returns.  
246     virtual BOOL TraceManager(Thread *thread, TraceDestination *trace,
247                               T_CONTEXT *pContext, BYTE **pRetAddr)
248     {
249         LIMITED_METHOD_CONTRACT;
250
251         _ASSERTE(!"Default impl of TraceManager should never be called!");
252         return FALSE;
253     }
254
255     // The worker for IsStub. This calls CheckIsStub_Internal, but wraps it w/ 
256     // a try-catch.
257     BOOL CheckIsStub_Worker(PCODE stubStartAddress);
258
259
260
261 #ifdef _DEBUG
262 public:
263     //-----------------------------------------------------------------------------
264     // Debugging Stubmanager bugs is very painful. You need to figure out
265     // how you go to where you got and which stub-manager is at fault.
266     // To help with this, we track a rolling log so that we can give very
267     // informative asserts. this log is not thread-safe, but we really only expect
268     // a single stub-manager usage at a time.
269     //
270     // A stub manager for a step-in operation may be used across 
271     // both the helper thread and then the managed thread doing the step-in.
272     // These threads will coordinate to have exclusive access (helper will only access
273     // when stopped; and managed thread will only access when running).
274     //
275     // It's also possible (but rare) for a single thread to have multiple step-in operations.
276     // Since that's so rare, no present need to expand our logging to support it.    
277     //-----------------------------------------------------------------------------
278
279
280     static bool IsStubLoggingEnabled();
281
282     // Call to reset the log. This is used at the start of a new step-operation.    
283     static void DbgBeginLog(TADDR addrCallInstruction, TADDR addrCallTarget);
284     static void DbgFinishLog();
285     
286     // Log arbitrary string. This is a nop if it's outside the Begin/Finish window.
287     // We could consider making each log entry type-safe (and thus avoid the string operations).
288     static void DbgWriteLog(const CHAR *format, ...);
289     
290     // Get the log as a string.
291     static void DbgGetLog(SString * pStringOut);
292
293 protected:
294     // Implement log as a SString.
295     static SString * s_pDbgStubManagerLog;
296
297     static CrstStatic s_DbgLogCrst;
298
299 #endif
300
301         
302 protected:
303
304     // Each stubmanaged implements this. 
305     // This may throw, AV, etc depending on the implementation. This should not 
306     // be called directly unless you know exactly what you're doing.
307     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress) = 0;
308
309     // The worker for TraceStub
310     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) = 0;
311
312 #ifdef _DEBUG_IMPL
313     static BOOL IsSingleOwner(PCODE stubAddress, StubManager * pOwner);
314 #endif
315
316 #ifdef DACCESS_COMPILE
317     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
318
319 public:
320     // This is used by DAC to provide more information on who owns a stub.
321     virtual LPCWSTR GetStubManagerName(PCODE addr) = 0;
322 #endif
323  
324 private:
325     SPTR_DECL(StubManager, g_pFirstManager);
326     PTR_StubManager m_pNextManager;
327
328     static CrstStatic s_StubManagerListCrst;
329 };
330
331 // -------------------------------------------------------
332 // This just wraps the RangeList methods in a read or
333 // write lock depending on the operation.
334 // -------------------------------------------------------
335
336 class LockedRangeList : public RangeList
337 {
338   public:
339     VPTR_VTABLE_CLASS(LockedRangeList, RangeList)
340     
341     LockedRangeList() : RangeList(), m_RangeListRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT)
342     {
343         LIMITED_METHOD_CONTRACT;
344     }
345
346     ~LockedRangeList()
347     {
348         LIMITED_METHOD_CONTRACT;
349     }
350
351   protected:
352
353     virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id)
354     {
355         WRAPPER_NO_CONTRACT;
356         SimpleWriteLockHolder lh(&m_RangeListRWLock);
357         return RangeList::AddRangeWorker(start,end,id);
358     }
359
360     virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL)
361     {
362         WRAPPER_NO_CONTRACT;
363         SimpleWriteLockHolder lh(&m_RangeListRWLock);
364         RangeList::RemoveRangesWorker(id,start,end);
365     }
366
367     virtual BOOL IsInRangeWorker(TADDR address, TADDR *pID = NULL)
368     {
369         WRAPPER_NO_CONTRACT;
370         SUPPORTS_DAC;
371         SimpleReadLockHolder lh(&m_RangeListRWLock);
372         return RangeList::IsInRangeWorker(address, pID);
373     }
374
375     SimpleRWLock m_RangeListRWLock;
376 };
377
378 //-----------------------------------------------------------
379 // Stub manager for the prestub.  Although there is just one, it has
380 // unique behavior so it gets its own stub manager.
381 //-----------------------------------------------------------
382 class ThePreStubManager : public StubManager
383 {
384     VPTR_VTABLE_CLASS(ThePreStubManager, StubManager)
385     
386   public:
387 #ifndef DACCESS_COMPILE
388     ThePreStubManager() { LIMITED_METHOD_CONTRACT; }
389 #endif
390
391 #ifdef _DEBUG
392     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "ThePreStubManager"; }
393 #endif
394
395     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
396
397     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
398
399 #ifndef DACCESS_COMPILE
400     static void Init(void);
401 #endif
402
403 #ifdef DACCESS_COMPILE
404   protected:
405     virtual LPCWSTR GetStubManagerName(PCODE addr)
406         { LIMITED_METHOD_CONTRACT; return W("ThePreStub"); }
407 #endif
408 };
409
410 // -------------------------------------------------------
411 // Stub manager classes for method desc prestubs & normal
412 // frame-pushing, StubLinker created stubs
413 // -------------------------------------------------------
414
415 typedef VPTR(class PrecodeStubManager) PTR_PrecodeStubManager;
416
417 class PrecodeStubManager : public StubManager
418 {
419     VPTR_VTABLE_CLASS(PrecodeStubManager, StubManager)
420
421   public:
422
423     SPTR_DECL(PrecodeStubManager, g_pManager);
424
425 #ifdef _DEBUG
426         // Debug helper to help identify stub-managers.
427         virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "PrecodeStubManager"; }
428 #endif
429
430
431     static void Init();
432
433 #ifndef DACCESS_COMPILE
434     PrecodeStubManager() {LIMITED_METHOD_CONTRACT;}
435     ~PrecodeStubManager() {WRAPPER_NO_CONTRACT;}
436 #endif
437
438   public:
439     static BOOL IsPrecodeByAsm(PCODE stubStartAddress);
440
441     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
442
443     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
444 #ifndef DACCESS_COMPILE
445     virtual BOOL TraceManager(Thread *thread,
446                               TraceDestination *trace,
447                               CONTEXT *pContext,
448                               BYTE **pRetAddr);
449 #endif
450
451 #ifdef DACCESS_COMPILE
452     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
453
454   protected:
455     virtual LPCWSTR GetStubManagerName(PCODE addr)
456         { LIMITED_METHOD_CONTRACT; return W("MethodDescPrestub"); }
457 #endif
458 };
459
460 // Note that this stub was written by a debugger guy, and thus when he refers to 'multicast'
461 // stub, he really means multi or single cast stub.  This was done b/c the same stub
462 // services both types of stub.
463 // Note from the debugger guy: the way to understand what this manager does is to
464 // first grok EmitMulticastInvoke for the platform you're working on (right now, just x86).
465 // Then return here, and understand that (for x86) the only way we know which method
466 // we're going to invoke next is by inspecting EDI when we've got the debuggee stopped
467 // in the stub, and so our trace frame will either (FRAME_PUSH) put a breakpoint
468 // in the stub, or (if we hit the BP) examine EDI, etc, & figure out where we're going next.
469
470 typedef VPTR(class StubLinkStubManager) PTR_StubLinkStubManager;
471
472 class StubLinkStubManager : public StubManager
473 {
474     VPTR_VTABLE_CLASS(StubLinkStubManager, StubManager)
475
476   public:
477
478 #ifdef _DEBUG
479     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "StubLinkStubManager"; }
480 #endif    
481
482
483     SPTR_DECL(StubLinkStubManager, g_pManager);
484
485     static void Init();
486
487 #ifndef DACCESS_COMPILE
488     StubLinkStubManager() : StubManager(), m_rangeList() {LIMITED_METHOD_CONTRACT;}
489     ~StubLinkStubManager() {WRAPPER_NO_CONTRACT;}
490 #endif
491   
492   protected:
493     LockedRangeList m_rangeList;
494   public:
495     // Get dac-ized pointer to rangelist.
496     PTR_RangeList GetRangeList() 
497     {
498         SUPPORTS_DAC;
499
500         TADDR addr = PTR_HOST_MEMBER_TADDR(StubLinkStubManager, this, m_rangeList);
501         return PTR_RangeList(addr);
502     }
503
504
505     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
506
507     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
508 #ifndef DACCESS_COMPILE
509     virtual BOOL TraceManager(Thread *thread,
510                               TraceDestination *trace,
511                               CONTEXT *pContext,
512                               BYTE **pRetAddr);
513 #endif
514
515 #ifdef DACCESS_COMPILE
516     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
517
518   protected:
519     virtual LPCWSTR GetStubManagerName(PCODE addr)
520         { LIMITED_METHOD_CONTRACT; return W("StubLinkStub"); }
521 #endif
522 } ;
523
524 // Stub manager for thunks.
525
526 typedef VPTR(class ThunkHeapStubManager) PTR_ThunkHeapStubManager;
527
528 class ThunkHeapStubManager : public StubManager
529 {
530     VPTR_VTABLE_CLASS(ThunkHeapStubManager, StubManager)
531
532   public:
533
534     SPTR_DECL(ThunkHeapStubManager, g_pManager);
535
536     static void Init();
537
538 #ifndef DACCESS_COMPILE
539     ThunkHeapStubManager() : StubManager(), m_rangeList() { LIMITED_METHOD_CONTRACT; }
540     ~ThunkHeapStubManager() {WRAPPER_NO_CONTRACT;}
541 #endif
542
543 #ifdef _DEBUG
544     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "ThunkHeapStubManager"; }
545 #endif
546
547   protected:
548     LockedRangeList m_rangeList;
549   public:
550     // Get dac-ized pointer to rangelist.
551     PTR_RangeList GetRangeList() 
552     {
553         SUPPORTS_DAC;
554         TADDR addr = PTR_HOST_MEMBER_TADDR(ThunkHeapStubManager, this, m_rangeList);
555         return PTR_RangeList(addr);
556     }
557     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
558
559   private:
560     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
561
562 #ifdef DACCESS_COMPILE
563     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
564
565   protected:
566     virtual LPCWSTR GetStubManagerName(PCODE addr)
567         { LIMITED_METHOD_CONTRACT; return W("ThunkHeapStub"); }
568 #endif
569 };
570
571 //
572 // Stub manager for jump stubs created by ExecutionManager::jumpStub()
573 // These are currently used only on the 64-bit targets IA64 and AMD64
574 //
575 typedef VPTR(class JumpStubStubManager) PTR_JumpStubStubManager;
576
577 class JumpStubStubManager : public StubManager
578 {
579     VPTR_VTABLE_CLASS(JumpStubStubManager, StubManager)
580
581   public:
582
583     SPTR_DECL(JumpStubStubManager, g_pManager);
584
585     static void Init();
586
587 #ifndef DACCESS_COMPILE
588     JumpStubStubManager() {LIMITED_METHOD_CONTRACT;}
589     ~JumpStubStubManager() {WRAPPER_NO_CONTRACT;}
590
591 #endif
592   
593 #ifdef _DEBUG
594     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "JumpStubStubManager"; }
595 #endif
596
597     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
598
599     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
600
601 #ifdef DACCESS_COMPILE
602     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
603
604   protected:
605     virtual LPCWSTR GetStubManagerName(PCODE addr)
606         { LIMITED_METHOD_CONTRACT; return W("JumpStub"); }
607 #endif
608 };
609
610 //
611 // Stub manager for code sections. It forwards the query to the more appropriate 
612 // stub manager, or handles the query itself.
613 //
614 typedef VPTR(class RangeSectionStubManager) PTR_RangeSectionStubManager;
615
616 class RangeSectionStubManager : public StubManager
617 {
618     VPTR_VTABLE_CLASS(RangeSectionStubManager, StubManager)
619
620   public:
621     SPTR_DECL(RangeSectionStubManager, g_pManager);
622
623     static void Init();
624
625 #ifndef DACCESS_COMPILE
626     RangeSectionStubManager() {LIMITED_METHOD_CONTRACT;}
627     ~RangeSectionStubManager() {WRAPPER_NO_CONTRACT;}
628 #endif
629
630     static StubCodeBlockKind GetStubKind(PCODE stubStartAddress);
631
632     static PCODE GetMethodThunkTarget(PCODE stubStartAddress);
633   
634   public:
635 #ifdef _DEBUG
636     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "RangeSectionStubManager"; }
637 #endif
638
639     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
640
641   private:
642
643     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
644
645 #ifndef DACCESS_COMPILE
646     virtual BOOL TraceManager(Thread *thread,
647                               TraceDestination *trace,
648                               CONTEXT *pContext,
649                               BYTE **pRetAddr);
650 #endif
651
652 #ifdef DACCESS_COMPILE
653     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
654
655   protected:
656     virtual LPCWSTR GetStubManagerName(PCODE addr);
657 #endif
658 };
659
660 //
661 // This is the stub manager for IL stubs.
662 //
663 typedef VPTR(class ILStubManager) PTR_ILStubManager;
664
665 #ifdef FEATURE_COMINTEROP
666 struct ComPlusCallInfo;
667 #endif // FEATURE_COMINTEROP
668
669 class ILStubManager : public StubManager
670 {
671     VPTR_VTABLE_CLASS(ILStubManager, StubManager)
672
673   public:
674     static void Init();
675
676 #ifndef DACCESS_COMPILE
677     ILStubManager() : StubManager() {WRAPPER_NO_CONTRACT;}
678     ~ILStubManager()
679     {
680         CONTRACTL
681         {
682             NOTHROW;
683             GC_NOTRIGGER;
684             CAN_TAKE_LOCK;     // StubManager::UnlinkStubManager uses a crst
685         }
686         CONTRACTL_END;
687     }
688 #endif
689
690    public:
691
692 #ifdef _DEBUG
693     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "ILStubManager"; }
694 #endif
695
696     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
697
698   private:
699
700     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
701
702 #ifndef DACCESS_COMPILE
703 #ifdef FEATURE_COMINTEROP
704     static PCODE GetCOMTarget(Object *pThis, ComPlusCallInfo *pComPlusCallInfo);
705     static PCODE GetWinRTFactoryTarget(ComPlusCallMethodDesc *pCMD);
706 #endif // FEATURE_COMINTEROP
707
708     virtual BOOL TraceManager(Thread *thread,
709                               TraceDestination *trace,
710                               CONTEXT *pContext,
711                               BYTE **pRetAddr);
712 #endif
713
714 #ifdef DACCESS_COMPILE
715     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
716
717   protected:
718     virtual LPCWSTR GetStubManagerName(PCODE addr)
719         { LIMITED_METHOD_CONTRACT; return W("ILStub"); }
720 #endif
721 };
722
723 // This is used to recognize
724 //   GenericComPlusCallStub()
725 //   VarargPInvokeStub()
726 //   GenericPInvokeCalliHelper()
727 typedef VPTR(class InteropDispatchStubManager) PTR_InteropDispatchStubManager;
728
729 class InteropDispatchStubManager : public StubManager
730 {
731     VPTR_VTABLE_CLASS(InteropDispatchStubManager, StubManager)
732
733   public:
734     static void Init();
735
736 #ifndef DACCESS_COMPILE
737     InteropDispatchStubManager() : StubManager() {WRAPPER_NO_CONTRACT;}
738     ~InteropDispatchStubManager() {WRAPPER_NO_CONTRACT;}
739 #endif
740
741 #ifdef _DEBUG
742     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "InteropDispatchStubManager"; }
743 #endif
744
745     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
746
747   private:
748
749     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
750
751 #ifndef DACCESS_COMPILE
752     virtual BOOL TraceManager(Thread *thread,
753                               TraceDestination *trace,
754                               CONTEXT *pContext,
755                               BYTE **pRetAddr);
756 #endif
757
758 #ifdef DACCESS_COMPILE
759     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
760
761   protected:
762     virtual LPCWSTR GetStubManagerName(PCODE addr)
763         { LIMITED_METHOD_CONTRACT; return W("InteropDispatchStub"); }
764 #endif
765 };
766
767 //
768 // Since we don't generate delegate invoke stubs at runtime on WIN64, we
769 // can't use the StubLinkStubManager for these stubs.  Instead, we create
770 // an additional DelegateInvokeStubManager instead.
771 //
772 typedef VPTR(class DelegateInvokeStubManager) PTR_DelegateInvokeStubManager;
773
774 class DelegateInvokeStubManager : public StubManager
775 {
776     VPTR_VTABLE_CLASS(DelegateInvokeStubManager, StubManager)
777
778   public:
779
780     SPTR_DECL(DelegateInvokeStubManager, g_pManager);
781
782     static void Init();
783
784 #if !defined(DACCESS_COMPILE)
785     DelegateInvokeStubManager() : StubManager(), m_rangeList() {LIMITED_METHOD_CONTRACT;}
786     ~DelegateInvokeStubManager() {WRAPPER_NO_CONTRACT;}
787 #endif // DACCESS_COMPILE
788
789     BOOL AddStub(Stub* pStub);
790     void RemoveStub(Stub* pStub);
791
792 #ifdef _DEBUG
793     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "DelegateInvokeStubManager"; }
794 #endif
795
796     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
797
798 #if !defined(DACCESS_COMPILE)
799     virtual BOOL TraceManager(Thread *thread, TraceDestination *trace, CONTEXT *pContext, BYTE **pRetAddr);
800     static BOOL TraceDelegateObject(BYTE *orDel, TraceDestination *trace);
801 #endif // DACCESS_COMPILE
802
803   private:
804
805     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
806
807    protected:
808     LockedRangeList m_rangeList;
809    public:
810     // Get dac-ized pointer to rangelist.
811     PTR_RangeList GetRangeList() 
812     {
813         SUPPORTS_DAC;
814
815         TADDR addr = PTR_HOST_MEMBER_TADDR(DelegateInvokeStubManager, this, m_rangeList);
816         return PTR_RangeList(addr);
817     }
818
819
820 #ifdef DACCESS_COMPILE
821     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
822
823   protected:
824     virtual LPCWSTR GetStubManagerName(PCODE addr)
825         { LIMITED_METHOD_CONTRACT; return W("DelegateInvokeStub"); }
826 #endif
827 };
828
829 //---------------------------------------------------------------------------------------
830 //
831 // This is the stub manager to help the managed debugger step into a tail call.
832 // It helps the debugger trace through JIT_TailCall().
833 //
834
835 typedef VPTR(class TailCallStubManager) PTR_TailCallStubManager;
836
837 class TailCallStubManager : public StubManager
838 {
839     VPTR_VTABLE_CLASS(TailCallStubManager, StubManager)
840
841 public:
842     static void Init();
843
844 #if !defined(DACCESS_COMPILE)
845     TailCallStubManager() : StubManager() {WRAPPER_NO_CONTRACT;}
846     ~TailCallStubManager() {WRAPPER_NO_CONTRACT;}
847
848     virtual BOOL TraceManager(Thread * pThread, TraceDestination * pTrace, CONTEXT * pContext, BYTE ** ppRetAddr);
849
850     static bool IsTailCallStubHelper(PCODE code);
851 #endif // DACCESS_COMPILE
852
853 #if defined(_DEBUG)
854     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "TailCallStubManager"; }
855 #endif // _DEBUG
856
857     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
858
859 private:
860     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination * pTrace);
861
862 #if defined(DACCESS_COMPILE)
863     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
864
865 protected:
866     virtual LPCWSTR GetStubManagerName(PCODE addr) {LIMITED_METHOD_CONTRACT; return W("TailCallStub");}
867 #endif // !DACCESS_COMPILE
868 };
869
870 //
871 // Helpers for common value locations in stubs to make stub managers more portable
872 //
873 class StubManagerHelpers
874 {
875 public:
876     static PCODE GetReturnAddress(T_CONTEXT * pContext)
877     {
878 #if defined(_TARGET_X86_)
879         return *dac_cast<PTR_PCODE>(pContext->Esp);
880 #elif defined(_TARGET_AMD64_)
881         return *dac_cast<PTR_PCODE>(pContext->Rsp);
882 #elif defined(_TARGET_ARM_)
883         return pContext->Lr;
884 #elif defined(_TARGET_ARM64_)
885         return pContext->Lr;
886 #else
887         PORTABILITY_ASSERT("StubManagerHelpers::GetReturnAddress");
888         return NULL;
889 #endif
890     }
891
892     static PTR_Object GetThisPtr(T_CONTEXT * pContext)
893     {
894 #if defined(_TARGET_X86_)
895         return dac_cast<PTR_Object>(pContext->Ecx);
896 #elif defined(_TARGET_AMD64_)
897 #ifdef UNIX_AMD64_ABI
898         return dac_cast<PTR_Object>(pContext->Rdi);
899 #else
900         return dac_cast<PTR_Object>(pContext->Rcx);
901 #endif
902 #elif defined(_TARGET_ARM_)
903         return dac_cast<PTR_Object>(pContext->R0);
904 #elif defined(_TARGET_ARM64_)
905         return dac_cast<PTR_Object>(pContext->X0);
906 #else
907         PORTABILITY_ASSERT("StubManagerHelpers::GetThisPtr");
908         return NULL;
909 #endif
910     }
911
912     static PCODE GetTailCallTarget(T_CONTEXT * pContext)
913     {
914 #if defined(_TARGET_X86_)
915         return pContext->Eax;
916 #elif defined(_TARGET_AMD64_)
917         return pContext->Rax;
918 #elif defined(_TARGET_ARM_)
919         return pContext->R12;
920 #else
921         PORTABILITY_ASSERT("StubManagerHelpers::GetTailCallTarget");
922         return NULL;
923 #endif
924     }
925
926     static TADDR GetHiddenArg(T_CONTEXT * pContext)
927     {
928 #if defined(_TARGET_X86_)
929         return pContext->Eax;
930 #elif defined(_TARGET_AMD64_)
931         return pContext->R10;
932 #elif defined(_TARGET_ARM_)
933         return pContext->R12;
934 #elif defined(_TARGET_ARM64_)
935         return pContext->X15;
936 #else
937         PORTABILITY_ASSERT("StubManagerHelpers::GetHiddenArg");
938         return NULL;
939 #endif
940     }
941
942 #ifndef CROSSGEN_COMPILE
943     static PCODE GetRetAddrFromMulticastILStubFrame(T_CONTEXT * pContext)
944     {
945         /*
946                 Following is the callstack corresponding to context  received by ILStubManager::TraceManager.
947                 This function returns the return address (user code address) where control should return after all 
948                 delegates in multicast delegate have been executed.
949               
950                 StubHelpers::MulticastDebuggerTraceHelper
951                 IL_STUB_MulticastDelegate_Invoke
952                 UserCode which invokes multicast delegate <---
953               */
954
955 #if defined(_TARGET_X86_)
956         return *((PCODE *)pContext->Ebp + 1);      
957 #elif defined(_TARGET_AMD64_)
958         T_CONTEXT context(*pContext);
959         Thread::VirtualUnwindCallFrame(&context);
960         Thread::VirtualUnwindCallFrame(&context);
961
962         return pContext->Rip;
963 #elif defined(_TARGET_ARM_)
964         return *((PCODE *)pContext->R11 + 1);      
965 #elif defined(_TARGET_ARM64_)
966         return *((PCODE *)pContext->Fp + 1);      
967 #else
968         PORTABILITY_ASSERT("StubManagerHelpers::GetRetAddrFromMulticastILStubFrame");
969         return NULL;
970 #endif
971     }
972 #endif // !CROSSGEN_COMPILE
973
974     static TADDR GetSecondArg(T_CONTEXT * pContext)
975     {
976 #if defined(_TARGET_X86_)
977         return pContext->Edx;
978 #elif defined(_TARGET_AMD64_)
979 #ifdef UNIX_AMD64_ABI
980         return pContext->Rsi;
981 #else
982         return pContext->Rdx;
983 #endif
984 #elif defined(_TARGET_ARM_)
985         return pContext->R1;
986 #elif defined(_TARGET_ARM_)
987         return pContext->X1;
988 #else
989         PORTABILITY_ASSERT("StubManagerHelpers::GetSecondArg");
990         return NULL;
991 #endif
992     }
993
994 };
995
996 #endif