Merge pull request #695 from ValMenn/xplat_build_update
[platform/upstream/coreclr.git] / src / debug / di / shimpriv.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 //*****************************************************************************
6 // shimprivate.h
7 // 
8
9 // 
10 // private header for RS shim which bridges from V2 to V3.
11 //*****************************************************************************
12
13 #ifndef SHIMPRIV_H
14 #define SHIMPRIV_H
15
16 #include "helpers.h"
17
18 #include "shimdatatarget.h"
19
20 #include <shash.h>
21
22 // Forward declarations
23 class CordbWin32EventThread;
24 class Cordb;
25
26 class ShimStackWalk;
27 class ShimChain;
28 class ShimChainEnum;
29 class ShimFrameEnum;
30
31 // This struct specifies that it's a hash table of ShimStackWalk * using ICorDebugThread as the key.
32 struct ShimStackWalkHashTableTraits : public PtrSHashTraits<ShimStackWalk, ICorDebugThread *> {};
33 typedef SHash<ShimStackWalkHashTableTraits> ShimStackWalkHashTable;
34
35
36 //---------------------------------------------------------------------------------------
37 //
38 // Simple struct for storing a void *.  This is to be used with a SHash hash table.
39 //
40
41 struct DuplicateCreationEventEntry
42 {
43 public:
44     DuplicateCreationEventEntry(void * pKey) : m_pKey(pKey) {};
45
46     // These functions must be defined for DuplicateCreationEventsHashTableTraits.
47     void * GetKey() {return m_pKey;};
48     static UINT32 Hash(void * pKey) {return (UINT32)(size_t)pKey;};
49
50 private:
51     void * m_pKey;
52 };
53
54 // This struct specifies that it's a hash table of DuplicateCreationEventEntry * using a void * as the key.
55 // The void * is expected to be an ICDProcess/ICDAppDomain/ICDThread/ICDAssembly/ICDThread interface pointer.
56 struct DuplicateCreationEventsHashTableTraits : public PtrSHashTraits<DuplicateCreationEventEntry, void *> {};
57 typedef SHash<DuplicateCreationEventsHashTableTraits> DuplicateCreationEventsHashTable;
58
59 //
60 // Callback that shim provides, which then queues up the events.
61 //
62 class ShimProxyCallback : 
63     public ICorDebugManagedCallback,
64     public ICorDebugManagedCallback2, 
65     public ICorDebugManagedCallback3
66 {
67     ShimProcess * m_pShim; // weak reference
68     LONG m_cRef; 
69
70 public:
71     ShimProxyCallback(ShimProcess * pShim);
72
73     // Implement IUnknown
74     ULONG STDMETHODCALLTYPE AddRef();
75     ULONG STDMETHODCALLTYPE Release();
76     COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
77
78     //
79     // Implementation of ICorDebugManagedCallback
80     //
81
82     COM_METHOD Breakpoint( ICorDebugAppDomain *pAppDomain,
83         ICorDebugThread *pThread,
84         ICorDebugBreakpoint *pBreakpoint);
85     
86     COM_METHOD StepComplete( ICorDebugAppDomain *pAppDomain,
87         ICorDebugThread *pThread,
88         ICorDebugStepper *pStepper,
89         CorDebugStepReason reason);
90
91     COM_METHOD Break( ICorDebugAppDomain *pAppDomain,
92         ICorDebugThread *thread);
93
94     COM_METHOD Exception( ICorDebugAppDomain *pAppDomain,
95         ICorDebugThread *pThread,
96         BOOL unhandled);
97
98     COM_METHOD EvalComplete( ICorDebugAppDomain *pAppDomain,
99         ICorDebugThread *pThread,
100         ICorDebugEval *pEval);
101
102     COM_METHOD EvalException( ICorDebugAppDomain *pAppDomain,
103         ICorDebugThread *pThread,
104         ICorDebugEval *pEval);
105
106     COM_METHOD CreateProcess( ICorDebugProcess *pProcess);
107     void QueueCreateProcess( ICorDebugProcess *pProcess);
108
109     COM_METHOD ExitProcess( ICorDebugProcess *pProcess);
110
111     COM_METHOD CreateThread( ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread);
112
113
114     COM_METHOD ExitThread( ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread);
115
116     COM_METHOD LoadModule( ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule);
117
118     void FakeLoadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule);
119
120     COM_METHOD UnloadModule( ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule);
121
122     COM_METHOD LoadClass( ICorDebugAppDomain *pAppDomain, ICorDebugClass *c);
123
124     COM_METHOD UnloadClass( ICorDebugAppDomain *pAppDomain, ICorDebugClass *c);
125
126     COM_METHOD DebuggerError( ICorDebugProcess *pProcess, HRESULT errorHR, DWORD errorCode);
127
128     COM_METHOD LogMessage( ICorDebugAppDomain *pAppDomain,
129         ICorDebugThread *pThread,
130         LONG lLevel,
131         __in LPWSTR pLogSwitchName,
132         __in LPWSTR pMessage);
133
134     COM_METHOD LogSwitch( ICorDebugAppDomain *pAppDomain,
135         ICorDebugThread *pThread,
136         LONG lLevel,
137         ULONG ulReason,
138         __in LPWSTR pLogSwitchName,
139         __in LPWSTR pParentName);
140
141     COM_METHOD CreateAppDomain(ICorDebugProcess *pProcess,
142         ICorDebugAppDomain *pAppDomain);
143
144     COM_METHOD ExitAppDomain(ICorDebugProcess *pProcess,
145         ICorDebugAppDomain *pAppDomain); 
146
147     COM_METHOD LoadAssembly(ICorDebugAppDomain *pAppDomain,
148         ICorDebugAssembly *pAssembly);
149
150     COM_METHOD UnloadAssembly(ICorDebugAppDomain *pAppDomain,
151         ICorDebugAssembly *pAssembly);
152
153     COM_METHOD ControlCTrap(ICorDebugProcess *pProcess);
154
155     COM_METHOD NameChange(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread);
156
157
158     COM_METHOD UpdateModuleSymbols( ICorDebugAppDomain *pAppDomain,
159         ICorDebugModule *pModule,
160         IStream *pSymbolStream);
161
162     COM_METHOD EditAndContinueRemap( ICorDebugAppDomain *pAppDomain,
163         ICorDebugThread *pThread,
164         ICorDebugFunction *pFunction,
165         BOOL fAccurate);
166
167     COM_METHOD BreakpointSetError( ICorDebugAppDomain *pAppDomain,
168         ICorDebugThread *pThread,
169         ICorDebugBreakpoint *pBreakpoint,
170         DWORD dwError);
171
172     ///
173     /// Implementation of ICorDebugManagedCallback2
174     ///
175     COM_METHOD FunctionRemapOpportunity( ICorDebugAppDomain *pAppDomain,
176         ICorDebugThread *pThread,
177         ICorDebugFunction *pOldFunction,
178         ICorDebugFunction *pNewFunction,
179         ULONG32 oldILOffset);
180
181     COM_METHOD CreateConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId, __in LPWSTR pConnName);
182
183     COM_METHOD ChangeConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId );
184
185
186     COM_METHOD DestroyConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId);
187
188     COM_METHOD Exception(ICorDebugAppDomain *pAppDomain,
189         ICorDebugThread *pThread,
190         ICorDebugFrame *pFrame,
191         ULONG32 nOffset,
192         CorDebugExceptionCallbackType dwEventType,
193         DWORD dwFlags );
194
195     COM_METHOD ExceptionUnwind(ICorDebugAppDomain *pAppDomain,
196         ICorDebugThread *pThread,
197         CorDebugExceptionUnwindCallbackType dwEventType,
198         DWORD dwFlags);
199
200     COM_METHOD FunctionRemapComplete( ICorDebugAppDomain *pAppDomain,
201         ICorDebugThread *pThread,
202         ICorDebugFunction *pFunction);
203
204     COM_METHOD MDANotification(ICorDebugController * pController, ICorDebugThread *pThread, ICorDebugMDA * pMDA);
205
206     ///
207     /// Implementation of ICorDebugManagedCallback3
208     ///
209
210     // Implementation of ICorDebugManagedCallback3::CustomNotification
211     COM_METHOD CustomNotification(ICorDebugThread * pThread, ICorDebugAppDomain * pAppDomain);
212
213 };
214
215
216 //
217 // Base class for event queue. These are nested into a singly linked list.
218 // Shim maintains event queue
219 //
220 class ManagedEvent
221 {
222 public:
223     // Need virtual dtor since this is a base class.
224     virtual ~ManagedEvent();
225
226 #ifdef _DEBUG
227     // For debugging, get a pointer value that can identify the type of this event.
228     void * GetDebugCookie();
229 #endif
230
231     // We'll have a lot of derived classes of ManagedEvent, and so encapsulating the arguments
232     // for the Dispatch() function lets us juggle them around easily without hitting every signature.
233     class DispatchArgs
234     {
235     public:
236         DispatchArgs(ICorDebugManagedCallback * pCallback1, ICorDebugManagedCallback2 * pCallback2, ICorDebugManagedCallback3 * pCallback3);
237
238         ICorDebugManagedCallback * GetCallback1();
239         ICorDebugManagedCallback2 * GetCallback2();
240         ICorDebugManagedCallback3 * GetCallback3();
241
242
243     protected:
244         ICorDebugManagedCallback * m_pCallback1;
245         ICorDebugManagedCallback2 * m_pCallback2;
246         ICorDebugManagedCallback3 * m_pCallback3;
247     };
248
249     // Returns: value of callback from end-user
250     virtual HRESULT Dispatch(DispatchArgs args) = 0;
251
252
253     // Returns 0 if none.
254     DWORD GetOSTid();
255
256 protected:
257     // Ctor for events with thread-affinity
258     ManagedEvent(ICorDebugThread * pThread);
259
260     // Ctor for events without thread affinity.
261     ManagedEvent();
262     
263     friend class ManagedEventQueue;
264     ManagedEvent * m_pNext;
265
266     DWORD m_dwThreadId;
267 };
268
269 //
270 // Queue of managed events.
271 // Shim can use this to collect managed debug events, queue them, and then drain the event
272 // queue when a sync-complete occurs.
273 // Event queue gets initialized with a lock and will lock internally.
274 class ManagedEventQueue
275 {
276 public:
277     ManagedEventQueue();
278
279     
280     void Init(RSLock * pLock);
281     
282     // Remove event from the top. Caller then takes ownership of Event and will call Delete on it.
283     // Caller checks IsEmpty() first.
284     ManagedEvent * Dequeue();
285
286     // Queue owns the event and will delete it (unless it's dequeued first).
287     void QueueEvent(ManagedEvent * pEvent);
288
289     // Test if event queue is empty
290     bool IsEmpty();
291
292     // Empty event queue and delete all objects
293     void DeleteAll();
294
295     // Nothrows
296     BOOL HasQueuedCallbacks(ICorDebugThread * pThread);
297
298     // Save the current queue and start with a new empty queue
299     void SuspendQueue();
300
301     // Restore the saved queue onto the end of the current queue
302     void RestoreSuspendedQueue();
303
304 protected:
305     // The lock to be used for synchronizing all access to the queue 
306     RSLock * m_pLock;
307
308     // If empty,  First + Last are both NULL.
309     // Else first points to the head of the queue; and Last points to the end of the queue.
310     ManagedEvent * m_pFirstEvent;
311     ManagedEvent * m_pLastEvent;
312
313 };
314
315
316 //---------------------------------------------------------------------------------------
317 //
318 // Shim's layer on top of a process.
319 //
320 // Notes:
321 //    This contains a V3 ICorDebugProcess, and provides V2 ICDProcess functionality.
322 //
323 class ShimProcess
324 {
325     // Delete via Ref count semantics.
326     ~ShimProcess();  
327 public:
328     // Initialize ref count is 0.
329     ShimProcess();    
330
331     // Lifetime semantics handled by reference counting.
332     void AddRef();
333     void Release();
334
335     // Release all resources. Can be called multiple times.
336     void Dispose();
337
338     // Initialization phases.
339     // 1. allocate new ShimProcess(). This lets us spin up a Win32 EventThread, which can then
340     //    be used to 
341     // 2. Call ShimProcess::CreateProcess/DebugActiveProcess. This will call CreateAndStartWin32ET to
342     //     craete the w32et.
343     // 3. Create OS-debugging pipeline. This establishes the physical OS process and gets us a pid/handle
344     // 4. pShim->InitializeDataTarget - this creates a reader/writer abstraction around the OS process.
345     // 5. pShim->SetProcess() - this connects the Shim to the ICDProcess object.
346     HRESULT InitializeDataTarget(DWORD processId);
347     void SetProcess(ICorDebugProcess * pProcess);
348
349     //-----------------------------------------------------------
350     // Creation
351     //-----------------------------------------------------------
352
353     static HRESULT CreateProcess(
354           Cordb * pCordb,
355           ICorDebugRemoteTarget * pRemoteTarget,
356           LPCWSTR programName,
357           __in_z LPWSTR  programArgs,
358           LPSECURITY_ATTRIBUTES lpProcessAttributes,
359           LPSECURITY_ATTRIBUTES lpThreadAttributes,
360           BOOL bInheritHandles,
361           DWORD dwCreationFlags,
362           PVOID lpEnvironment,
363           LPCWSTR lpCurrentDirectory,
364           LPSTARTUPINFOW lpStartupInfo,
365           LPPROCESS_INFORMATION lpProcessInformation,
366           CorDebugCreateProcessFlags corDebugFlags
367     );
368
369     static HRESULT DebugActiveProcess(
370         Cordb * pCordb,
371         ICorDebugRemoteTarget * pRemoteTarget,
372         DWORD pid,
373         BOOL win32Attach
374
375     );
376
377     // Locates the DAC module adjacent to DBI
378     static HMODULE GetDacModule();
379
380     //
381     // Functions used by CordbProcess
382     // 
383
384     // Determine if the calling thread is the win32 event thread.
385     bool IsWin32EventThread();
386
387
388     // Expose the W32ET thread to the CordbProcess so that it can emulate V2 behavior
389     CordbWin32EventThread * GetWin32EventThread();
390
391     // Accessor wrapper to mark whether we're interop-debugging.
392     void SetIsInteropDebugging(bool fIsInteropDebugging);
393
394     // Handle a debug event. 
395     HRESULT HandleWin32DebugEvent(const DEBUG_EVENT * pEvent);
396
397     ManagedEventQueue * GetManagedEventQueue();
398
399     ManagedEvent * DequeueManagedEvent();
400
401     ShimProxyCallback * GetShimCallback();
402
403     // Begin Queing the fake attach events.
404     void BeginQueueFakeAttachEvents();
405
406     // Queue fake attach events if needed
407     void QueueFakeAttachEventsIfNeeded(bool fRealCreateProcessEvent);
408
409     // Actually do the work to queue the fake attach events.
410     void QueueFakeAttachEvents();
411
412     // Helper to queue fake assembly and mdule events
413     void QueueFakeAssemblyAndModuleEvent(ICorDebugAssembly * pAssembly);
414
415     // Queue fake thread-create events on attach. Order via native threads.
416     HRESULT QueueFakeThreadAttachEventsNativeOrder();
417
418     // Queue fake thread-create events on attach. No ordering.
419     HRESULT QueueFakeThreadAttachEventsNoOrder();
420
421     bool IsThreadSuspendedOrHijacked(ICorDebugThread * pThread);
422
423     // Expose m_attached to CordbProcess.
424     bool GetAttached();
425
426     // We need to know whether we are in the CreateProcess callback to be able to 
427     // return the v2.0 hresults from code:CordbProcess::SetDesiredNGENCompilerFlags 
428     // when we are using the shim.
429     // 
430     // Expose m_fInCreateProcess
431     bool GetInCreateProcess();
432     void SetInCreateProcess(bool value);
433
434     // We need to know whether we are in the FakeLoadModule callback to be able to 
435     // return the v2.0 hresults from code:CordbModule::SetJITCompilerFlags when
436     // we are using the shim.
437     // 
438     // Expose m_fInLoadModule
439     bool GetInLoadModule();
440     void SetInLoadModule(bool value);
441
442     // When we get a continue, we need to clear the flags indicating we're still in a callback
443     void NotifyOnContinue ();
444
445     // The RS calls this function when the stack is about to be changed in any way, e.g. continue, SetIP,
446     // etc.
447     void NotifyOnStackInvalidate();
448
449     // Helpers to filter HRs to emulate V2 error codes.
450     HRESULT FilterSetNgenHresult(HRESULT hr);
451     HRESULT FilterSetJitFlagsHresult(HRESULT hr);
452
453     //.............................................................
454
455
456     // Lookup or create a ShimStackWalk for the specified thread.  ShimStackWalk and ICorDebugThread has
457     // a 1:1 relationship.
458     ShimStackWalk * LookupOrCreateShimStackWalk(ICorDebugThread * pThread);
459
460     // Clear all ShimStackWalks and flush all the caches.
461     void            ClearAllShimStackWalk();
462
463     // Get the corresponding ICDProcess object. 
464     ICorDebugProcess * GetProcess();
465
466     // Get the data target to access the debuggee.
467     ICorDebugMutableDataTarget * GetDataTarget();
468
469     // Get the native event pipeline
470     INativeEventPipeline * GetNativePipeline();
471
472     // Are we interop-debugging?
473     bool IsInteropDebugging();
474
475
476     // Finish all the necessary initialization work and queue up any necessary fake attach events before
477     // dispatching an event.
478     void PreDispatchEvent(bool fRealCreateProcessEvent = false);
479
480     // Look for a CLR in the process and if found, return it's instance ID
481     HRESULT FindLoadedCLR(CORDB_ADDRESS * pClrInstanceId);    
482
483     // Retrieve the IP address and the port number of the debugger proxy.
484     MachineInfo GetMachineInfo();
485
486     // Add an entry in the duplicate creation event hash table for the specified key.
487     void AddDuplicateCreationEvent(void * pKey);
488
489     // Check if a duplicate creation event entry exists for the specified key.  If so, remove it.  
490     bool RemoveDuplicateCreationEventIfPresent(void * pKey);
491
492     void SetMarkAttachPendingEvent();
493
494     void SetTerminatingEvent();
495
496     RSLock * GetShimLock();
497
498 protected:
499
500     // Reference count.
501     LONG m_ref;
502
503     //
504     // Helper functions
505     //
506     HRESULT CreateAndStartWin32ET(Cordb * pCordb);
507
508     //
509     // Synchronization events to ensure that AttachPending bit is marked before DebugActiveProcess 
510     // returns or debugger is detaching
511     // 
512     HANDLE  m_markAttachPendingEvent;
513     HANDLE  m_terminatingEvent;
514
515     // Finds the base address of [core]clr.dll 
516     CORDB_ADDRESS GetCLRInstanceBaseAddress();
517
518     //
519     // Event Queues
520     //
521
522     // Shim maintains event queue to emulate V2 semantics.
523     // In V2, IcorDebug internally queued debug events and dispatched them 
524     // once the debuggee was synchronized. In V3, ICorDebug dispatches events immediately. 
525     // The event queue is moved into the shim to build V2 semantics of V3 behavior.
526     ManagedEventQueue m_eventQueue;
527     
528     // Lock to protect Shim data structures. This is currently a small lock that 
529     // protects leaf-level structures, but it may grow to protect larger things.
530     RSLock m_ShimLock;
531
532     // Serializes ShimProcess:Dispose() with other ShimProcess functions. For now, this
533     // cannot be the same as m_ShimLock. See LL_SHIM_PROCESS_DISPOSE_LOCK for more
534     // information
535     RSLock m_ShimProcessDisposeLock;
536
537     // Sticky bit to do lazy-initialization on the first managed event.
538     bool                  m_fFirstManagedEvent;
539
540     RSExtSmartPtr<ShimProxyCallback> m_pShimCallback;
541
542
543     // This is for emulating V2 Attach. Initialized to false, and then set to true if we ened to send fake attach events.
544     // Reset to false once the events are sent. See code:ShimProcess::QueueFakeAttachEventsIfNeeded
545     bool  m_fNeedFakeAttachEvents;
546
547     // True if the process was created from an attach (DebugActiveProcess); False if it was launched (CreateProcess)
548     // This is used to send an Attach IPC event, and also used to provide more specific error codes.
549     bool m_attached;
550
551     // True iff we are in the shim's CreateProcess callback. This is used to determine which hresult to
552     // return from code:CordbProcess::SetDesiredNGENCompilerFlags so we correctly emulate the behavior of v2.0.
553     // This is set at the beginning of the callback and cleared in code:CordbProcess::ContinueInternal. 
554     bool m_fInCreateProcess;
555
556     // True iff we are in the shim's FakeLoadModule callback. This is used to determine which hresult to
557     // return from code:CordbModule::SetJITCompilerFlags so we correctly emulate the behavior of v2.0.
558     // This is set at the beginning of the callback and cleared in code:CordbProcess::ContinueInternal. 
559     bool m_fInLoadModule;
560     //
561     // Data
562     //
563
564     // Pointer to CordbProcess. 
565     // @dbgtodo shim: We'd like this to eventually go through public interfaces (ICorDebugProcess)
566     IProcessShimHooks * m_pProcess; // Reference is kept by m_pIProcess;
567     RSExtSmartPtr<ICorDebugProcess> m_pIProcess; 
568
569     // Win32EvenThread, which is the thread that uses the native debug API.
570     CordbWin32EventThread * m_pWin32EventThread;
571
572     // Actual data-target. Since we're shimming V2 scenarios, and V3 is always
573     // live-debugging, this is always a live data-target.
574     RSExtSmartPtr<ShimDataTarget> m_pLiveDataTarget;
575
576
577     // If true, the shim is emulating interop-debugging
578     // If false, the shim is emulating managed-only debugging.
579     // Both managed and native debugging have the same underlying pipeline (built
580     // on native-debug events). So the only difference is how they handle those events.
581     bool m_fIsInteropDebugging;
582
583     // true iff Dispose() was called.  Consult this and do your work under m_ShimProcessDisposeLock
584     // to serialize yourself against a call to Dispose().  This protects your work
585     // from the user doing a Debugger Detach in the middle.
586     bool m_fIsDisposed;
587
588     //.............................................................................
589     //
590     // Members used for handling native events when managed-only debugging.
591     //
592     //.............................................................................
593
594     // Default handler for native events when managed-only debugging.
595     void DefaultEventHandler(const DEBUG_EVENT * pEvent, DWORD * pdwContinueStatus);
596
597     // Given a debug event, track the file handles.
598     void TrackFileHandleForDebugEvent(const DEBUG_EVENT * pEvent);   
599
600     // Have we gotten the loader breakpoint yet?
601     // A Debugger needs to do special work to skip the loader breakpoint, 
602     // and that's also when it should dispatch the faked managed attach events.
603     bool m_loaderBPReceived;
604
605     // Raw callback for ContinueStatusChanged from Data-target.
606     static HRESULT ContinueStatusChanged(void * pUserData, DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
607
608     // Real worker to update ContinueStatusChangedData
609     HRESULT ContinueStatusChangedWorker(DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
610     
611     struct ContinueStatusChangedData
612     {
613         void Clear();
614         bool IsSet();
615         // Tid of Thread changed
616         DWORD m_dwThreadId;
617
618         // New continue status.
619         CORDB_CONTINUE_STATUS m_status;
620     } m_ContinueStatusChangedData;
621
622     // the hash table of ShimStackWalks
623     ShimStackWalkHashTable * m_pShimStackWalkHashTable;
624
625     // the hash table of duplicate creation events
626     DuplicateCreationEventsHashTable * m_pDupeEventsHashTable;
627
628     MachineInfo m_machineInfo;
629 };
630
631
632 //---------------------------------------------------------------------------------------
633 //
634 // This is the container class of ShimChains, ICorDebugFrames, ShimChainEnums, and ShimFrameEnums.   
635 // It has a 1:1 relationship  with ICorDebugThreads.  Upon creation, this class walks the entire stack and 
636 // caches all the stack frames and chains.  The enumerators are created on demand.
637 //
638
639 class ShimStackWalk
640 {
641 public:
642     ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread);
643     ~ShimStackWalk();
644
645     // These functions do not adjust the reference count.
646     ICorDebugThread * GetThread();
647     ShimChain *       GetChain(UINT32 index);
648     ICorDebugFrame *  GetFrame(UINT32 index);
649
650     // Get the number of frames and chains.
651     ULONG             GetChainCount();
652     ULONG             GetFrameCount();
653
654     RSLock *          GetShimLock();
655
656     // Add ICDChainEnum and ICDFrameEnum.
657     void AddChainEnum(ShimChainEnum * pChainEnum);
658     void AddFrameEnum(ShimFrameEnum * pFrameEnum);
659
660     // The next two functions are for ShimStackWalkHashTableTraits.
661     ICorDebugThread * GetKey();
662     static UINT32 Hash(ICorDebugThread * pThread);
663
664     // Check if the specified frame is the leaf frame according to the V2 definition.
665     BOOL IsLeafFrame(ICorDebugFrame * pFrame);
666
667     // Check if the two specified frames are the same.  This function checks the SPs, frame address, etc.
668     // instead of just checking for pointer equality.
669     BOOL IsSameFrame(ICorDebugFrame * pLeft, ICorDebugFrame * pRight);
670
671     // The following functions are entry point into the ShimStackWalk.  They are called by the RS.
672     void EnumerateChains(ICorDebugChainEnum ** ppChainEnum);
673
674     void GetActiveChain(ICorDebugChain ** ppChain);
675     void GetActiveFrame(ICorDebugFrame ** ppFrame);
676     void GetActiveRegisterSet(ICorDebugRegisterSet ** ppRegisterSet);
677
678     void GetChainForFrame(ICorDebugFrame * pFrame, ICorDebugChain ** ppChain);
679     void GetCallerForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCallerFrame);
680     void GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCalleeFrame);
681
682 private:
683     //---------------------------------------------------------------------------------------
684     //
685     // This is a helper class used to store the information of a chain during a stackwalk.  A chain is marked
686     // by the CONTEXT on the leaf boundary and a FramePointer on the root boundary.  Also, notice that we
687     // are keeping two CONTEXTs.  This is because some chain types may cancel a previous unmanaged chain.  
688     // For example, a CHAIN_FUNC_EVAL chain cancels any CHAIN_ENTER_UNMANAGED chain immediately preceding
689     // it.  In this case, the leaf boundary of the CHAIN_FUNC_EVAL chain is marked by the CONTEXT of the
690     // previous CHAIN_ENTER_MANAGED, not the previous CHAIN_ENTER_UNMANAGED.
691     //
692
693     struct ChainInfo
694     {
695     public:
696         ChainInfo() : m_rootFP(LEAF_MOST_FRAME), m_reason(CHAIN_NONE), m_fNeedEnterManagedChain(FALSE), m_fLeafNativeContextIsValid(FALSE) {}
697
698         void CancelUMChain() { m_reason = CHAIN_NONE; }
699         BOOL IsTrackingUMChain() { return (m_reason == CHAIN_ENTER_UNMANAGED); }
700
701         DT_CONTEXT          m_leafNativeContext;
702         DT_CONTEXT          m_leafManagedContext;
703         FramePointer        m_rootFP;
704         CorDebugChainReason m_reason;
705         bool                m_fNeedEnterManagedChain;
706         bool                m_fLeafNativeContextIsValid;
707     };
708
709     //---------------------------------------------------------------------------------------
710     //
711     // This is a helper class used to store information during a stackwalk.  Conceptually it is a simplified
712     // version of FrameInfo used on the LS in V2.
713     //
714
715     struct StackWalkInfo
716     {
717     public:
718         StackWalkInfo();
719         ~StackWalkInfo();
720
721         // Reset all the per-frame information.
722         void ResetForNextFrame();
723
724         // During the stackwalk, we need to find out whether we should process the next stack frame or the
725         // next internal frame.  These functions help us determine whether we have exhausted one or both
726         // types of frames.  The stackwalk is finished when both types are exhausted.
727         bool ExhaustedAllFrames();
728         bool ExhaustedAllStackFrames();
729         bool ExhaustedAllInternalFrames();
730
731         // Simple helper function to get the current internal frame.
732         ICorDebugInternalFrame2 * GetCurrentInternalFrame();
733
734         // Check whether we are processing the first frame.
735         BOOL IsLeafFrame();
736
737         // Check whether we are skipping frames because of a child frame.
738         BOOL IsSkippingFrame();
739
740         // Indicates whether we are dealing with a converted frame.  
741         // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
742         BOOL HasConvertedFrame();
743
744         // Store the child frame we are currently trying to find the parent frame for.
745         // If this is NULL, then we are not skipping frames.
746         RSExtSmartPtr<ICorDebugNativeFrame2>   m_pChildFrame;
747
748         // Store the converted frame, if any.
749         RSExtSmartPtr<ICorDebugInternalFrame2> m_pConvertedInternalFrame2;
750
751         // Store the array of internal frames.  This is an array of RSExtSmartPtrs, and so each element 
752         // is protected, and we only need to call Clear() to release each element and free all the memory.
753         RSExtPtrArray<ICorDebugInternalFrame2> m_ppInternalFrame2;
754
755         UINT32  m_cChain;               // number of chains
756         UINT32  m_cFrame;               // number of frames
757         UINT32  m_firstFrameInChain;    // the index of the first frame in the current chain
758         UINT32  m_cInternalFrames;      // number of internal frames
759         UINT32  m_curInternalFrame;     // the index of the current internal frame being processed
760
761         CorDebugInternalFrameType m_internalFrameType;
762
763         bool m_fExhaustedAllStackFrames;
764
765         // Indicate whether we are processing an internal frame or a stack frame.
766         bool m_fProcessingInternalFrame;    
767
768         // Indicate whether we should skip the current chain because it's a chain derived from a leaf frame 
769         // of type TYPE_INTERNAL.  This is the behaviour in V2.  
770         // See code:DebuggerWalkStackProc.
771         bool m_fSkipChain;
772
773         // Indicate whether the current frame is the first frame we process.
774         bool m_fLeafFrame;
775
776         // Indicate whether we are processing a converted frame.
777         bool m_fHasConvertedFrame;
778     };
779
780     // A ShimStackWalk is deleted when a process is continued, or when the stack is changed in any way
781     // (e.g. SetIP, EnC, etc.).
782     void Populate();
783     void Clear();
784
785     // Get a FramePointer to mark the root boundary of a chain.
786     FramePointer GetFramePointerForChain(DT_CONTEXT * pContext);
787     FramePointer GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2);
788
789     CorDebugInternalFrameType GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2);
790
791     // Append a frame to the array.
792     void AppendFrame(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo);
793     void AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, StackWalkInfo * pStackWalkInfo);
794
795     // Append a chain to the array.
796     void AppendChainWorker(StackWalkInfo *     pStackWalkInfo,
797                            DT_CONTEXT *        pLeafContext,
798                            FramePointer        fpRoot,
799                            CorDebugChainReason chainReason,
800                            BOOL                fIsManagedChain);
801     void AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo);
802
803     // Save information on the ChainInfo regarding the current chain.
804     void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext);
805
806     // Check what we are process next, a internal frame or a stack frame.
807     BOOL CheckInternalFrame(ICorDebugFrame *     pNextStackFrame,
808                             StackWalkInfo *      pStackWalkInfo,
809                             ICorDebugThread3 *   pThread3,
810                             ICorDebugStackWalk * pSW);
811
812     // Convert an ICDInternalFrame to another ICDInternalFrame due to IL methods without metadata.
813     // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
814     BOOL ConvertInternalFrameToDynamicMethod(StackWalkInfo * pStackWalkInfo);
815
816     // Convert an ICDNativeFrame to an ICDInternalFrame due to IL methods without metadata.
817     // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
818     BOOL ConvertStackFrameToDynamicMethod(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo);
819
820     // Process an unmanaged chain.
821     BOOL ShouldTrackUMChain(StackWalkInfo * pswInfo);
822     void TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo);
823
824     // Check whether the internal frame is a newly exposed type in Arrowhead.  If so, then the shim should
825     // not expose it.
826     BOOL IsV3FrameType(CorDebugInternalFrameType type);
827
828     // Check whether the specified frame represents a dynamic method.
829     BOOL IsILFrameWithoutMetadata(ICorDebugFrame * pFrame);
830
831     CDynArray<ShimChain *>      m_stackChains;  // growable ordered array of chains and frames
832     CDynArray<ICorDebugFrame *> m_stackFrames; 
833
834     ShimChainEnum * m_pChainEnumList;           // linked list of ShimChainEnum and ShimFrameEnum
835     ShimFrameEnum * m_pFrameEnumList;
836
837     // the thread on which we are doing a stackwalk, i.e. the "owning" thread
838     RSExtSmartPtr<ShimProcess>     m_pProcess;
839     RSExtSmartPtr<ICorDebugThread> m_pThread;
840 };
841
842
843 //---------------------------------------------------------------------------------------
844 //
845 // This class implements the deprecated ICDChain interface.
846 //
847
848 class ShimChain : public ICorDebugChain
849 {
850 public:
851     ShimChain(ShimStackWalk *     pSW,
852               DT_CONTEXT *        pContext,
853               FramePointer        fpRoot,
854               UINT32              chainIndex,
855               UINT32              frameStartIndex,
856               UINT32              frameEndIndex,
857               CorDebugChainReason chainReason,
858               BOOL                fIsManaged,
859               RSLock *            pShimLock);
860     ~ShimChain();
861
862     void Neuter();
863     BOOL IsNeutered();
864
865     //
866     // IUnknown
867     //
868
869     ULONG STDMETHODCALLTYPE AddRef();
870     ULONG STDMETHODCALLTYPE Release();
871     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
872
873     //
874     // ICorDebugChain
875     //
876
877     COM_METHOD GetThread(ICorDebugThread ** ppThread);
878     COM_METHOD GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd);
879     COM_METHOD GetContext(ICorDebugContext ** ppContext);
880     COM_METHOD GetCaller(ICorDebugChain ** ppChain);
881     COM_METHOD GetCallee(ICorDebugChain ** ppChain);
882     COM_METHOD GetPrevious(ICorDebugChain ** ppChain);
883     COM_METHOD GetNext(ICorDebugChain ** ppChain);
884     COM_METHOD IsManaged(BOOL * pManaged);
885     COM_METHOD EnumerateFrames(ICorDebugFrameEnum ** ppFrames);
886     COM_METHOD GetActiveFrame(ICorDebugFrame ** ppFrame);
887     COM_METHOD GetRegisterSet(ICorDebugRegisterSet ** ppRegisters);
888     COM_METHOD GetReason(CorDebugChainReason * pReason);
889
890     //
891     // accessors
892     //
893
894     // Get the owning ShimStackWalk.
895     ShimStackWalk * GetShimStackWalk();
896
897     // Get the first and last index of the frame owned by this chain.  This class itself doesn't store the
898     // frames.  Rather, the frames are stored on the ShimStackWalk.  This class just stores the indices.
899     // Note that the indices are [firstIndex, lastIndex), i.e. the last index is exclusive.
900     UINT32 GetFirstFrameIndex();
901     UINT32 GetLastFrameIndex();
902
903 private:
904     // A chain describes a stack range within the stack.  This includes a CONTEXT at the start (leafmost)
905     // end of the chain, and a frame pointer where the chain ends (rootmost).  This stack range is exposed
906     // publicly via ICDChain::GetStackRange(), and can be used to stitch managed and native stack frames
907     // together into a unified stack.
908     DT_CONTEXT          m_context;          // the leaf end of the chain
909     FramePointer        m_fpRoot;           // the root end of the chain
910
911     ShimStackWalk *     m_pStackWalk;       // the owning ShimStackWalk
912     Volatile<ULONG>     m_refCount; 
913
914     // The 0-based index of this chain in the ShimStackWalk's chain array (m_pStackWalk->m_stackChains).
915     UINT32              m_chainIndex;
916
917     // The 0-based index of the first frame owned by this chain in the ShimStackWalk's frame array 
918     // (m_pStackWalk->m_stackFrames).  See code::ShimChain::GetFirstFrameIndex().
919     UINT32              m_frameStartIndex;
920
921     // The 0-based index of the last frame owned by this chain in the ShimStackWalk's frame array 
922     // (m_pStackWalk->m_stackFrames).  This index is exlusive.  See code::ShimChain::GetLastFrameIndex().
923     UINT32              m_frameEndIndex;
924
925     CorDebugChainReason m_chainReason;
926     BOOL                m_fIsManaged;       // indicates whether this chain contains managed frames
927     BOOL                m_fIsNeutered;
928
929     RSLock *            m_pShimLock;        // shim lock from ShimProcess to protect neuteredness checks
930 };
931
932
933 //---------------------------------------------------------------------------------------
934 //
935 // This class implements the deprecated ICDChainEnum interface.
936 //
937
938 class ShimChainEnum : public ICorDebugChainEnum
939 {
940 public:
941     ShimChainEnum(ShimStackWalk * pSW, RSLock * pShimLock);
942     ~ShimChainEnum();
943
944     void Neuter();
945     BOOL IsNeutered();
946
947     //
948     // IUnknown
949     //
950
951     ULONG STDMETHODCALLTYPE AddRef();
952     ULONG STDMETHODCALLTYPE Release();
953     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
954
955     //
956     // ICorDebugEnum
957     //
958
959     COM_METHOD Skip(ULONG celt);
960     COM_METHOD Reset();
961     COM_METHOD Clone(ICorDebugEnum ** ppEnum);
962     COM_METHOD GetCount(ULONG * pcChains);
963
964     //
965     // ICorDebugChainEnum
966     //
967
968     COM_METHOD Next(ULONG cChains, ICorDebugChain * rgpChains[], ULONG * pcChainsFetched);
969
970     //
971     // accessors
972     // 
973
974     // used to link ShimChainEnums in a list
975     ShimChainEnum * GetNext();
976     void SetNext(ShimChainEnum * pNext);
977
978 private:
979     ShimStackWalk * m_pStackWalk;           // the owning ShimStackWalk
980
981     // This points to the next ShimChainEnum in the linked list of ShimChainEnums to be cleaned up.
982     // The head of the list is on the ShimStackWalk (m_pStackWalk->m_pChainEnumList).
983     ShimChainEnum * m_pNext;
984
985     UINT32          m_currentChainIndex;    // the index of the current ShimChain being enumerated
986     Volatile<ULONG> m_refCount;
987     BOOL            m_fIsNeutered;
988     
989     RSLock *        m_pShimLock;            // shim lock from ShimProcess to protect neuteredness checks
990 };
991
992
993 //---------------------------------------------------------------------------------------
994 //
995 // This class implements the deprecated ICDFrameEnum interface.
996 //
997
998 class ShimFrameEnum : public ICorDebugFrameEnum
999 {
1000 public:
1001     ShimFrameEnum(ShimStackWalk * pSW, ShimChain * pChain, UINT32 frameStartIndex, UINT32 frameEndIndex, RSLock * pShimLock);
1002     ~ShimFrameEnum();
1003
1004     void Neuter();
1005     BOOL IsNeutered();
1006
1007     //
1008     // IUnknown
1009     //
1010
1011     ULONG STDMETHODCALLTYPE AddRef();
1012     ULONG STDMETHODCALLTYPE Release();
1013     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
1014
1015     //
1016     // ICorDebugEnum
1017     //
1018
1019     COM_METHOD Skip(ULONG celt);
1020     COM_METHOD Reset();
1021     COM_METHOD Clone(ICorDebugEnum ** ppEnum);
1022     COM_METHOD GetCount(ULONG * pcFrames);
1023
1024     //
1025     // ICorDebugFrameEnum
1026     //
1027
1028     COM_METHOD Next(ULONG cFrames, ICorDebugFrame * rgpFrames[], ULONG * pcFramesFetched);
1029
1030     //
1031     // accessors
1032     // 
1033
1034     // used to link ShimChainEnums in a list
1035     ShimFrameEnum * GetNext();
1036     void SetNext(ShimFrameEnum * pNext);
1037
1038 private:
1039     ShimStackWalk * m_pStackWalk;           // the owning ShimStackWalk
1040     ShimChain *     m_pChain;               // the owning ShimChain
1041     RSLock *        m_pShimLock;            // shim lock from ShimProcess to protect neuteredness checks
1042
1043     // This points to the next ShimFrameEnum in the linked list of ShimFrameEnums to be cleaned up.
1044     // The head of the list is on the ShimStackWalk (m_pStackWalk->m_pFrameEnumList).
1045     ShimFrameEnum * m_pNext;
1046
1047     UINT32          m_currentFrameIndex;    // the current ICDFrame being enumerated
1048     UINT32          m_endFrameIndex;        // the last index (exclusive) of the frame owned by the chain;
1049                                             // see code:ShimChain::GetLastFrameIndex
1050     Volatile<ULONG> m_refCount;
1051     BOOL            m_fIsNeutered;
1052 };
1053
1054
1055 #endif // SHIMPRIV_H
1056