Initial commit to populate CoreCLR repo
[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     // Check whether the debugger has given us an ICorDebugRemoteTarget to query for the host name of the remote machine.
484     void   CheckForPortInfo(ICorDebugRemoteTarget * pRemoteTarget);
485
486     // Resolve the host name given to us by the debugger to an IP address.  Currently we don't support IPv6.
487     DWORD  ResolveHostName(ICorDebugRemoteTarget * pRemoteTarget);
488
489     // Retrieve the IP address and the port number of the debugger proxy.
490     MachineInfo GetMachineInfo();
491
492     // Add an entry in the duplicate creation event hash table for the specified key.
493     void AddDuplicateCreationEvent(void * pKey);
494
495     // Check if a duplicate creation event entry exists for the specified key.  If so, remove it.  
496     bool RemoveDuplicateCreationEventIfPresent(void * pKey);
497
498     void SetMarkAttachPendingEvent();
499
500     void SetTerminatingEvent();
501
502     RSLock * GetShimLock();
503
504 protected:
505
506     // Reference count.
507     LONG m_ref;
508
509     //
510     // Helper functions
511     //
512     HRESULT CreateAndStartWin32ET(Cordb * pCordb);
513
514     //
515     // Synchronization events to ensure that AttachPending bit is marked before DebugActiveProcess 
516     // returns or debugger is detaching
517     // 
518     HANDLE  m_markAttachPendingEvent;
519     HANDLE  m_terminatingEvent;
520
521 #if !defined(FEATURE_CORESYSTEM)
522     // Finds the base address of mscorwks.dll 
523     CORDB_ADDRESS GetCLRInstanceBaseAddress();
524 #endif // !defined(FEATURE_CORESYSTEM)
525
526     //
527     // Event Queues
528     //
529
530     // Shim maintains event queue to emulate V2 semantics.
531     // In V2, IcorDebug internally queued debug events and dispatched them 
532     // once the debuggee was synchronized. In V3, ICorDebug dispatches events immediately. 
533     // The event queue is moved into the shim to build V2 semantics of V3 behavior.
534     ManagedEventQueue m_eventQueue;
535     
536     // Lock to protect Shim data structures. This is currently a small lock that 
537     // protects leaf-level structures, but it may grow to protect larger things.
538     RSLock m_ShimLock;
539
540     // Serializes ShimProcess:Dispose() with other ShimProcess functions. For now, this
541     // cannot be the same as m_ShimLock. See LL_SHIM_PROCESS_DISPOSE_LOCK for more
542     // information
543     RSLock m_ShimProcessDisposeLock;
544
545     // Sticky bit to do lazy-initialization on the first managed event.
546     bool                  m_fFirstManagedEvent;
547
548     RSExtSmartPtr<ShimProxyCallback> m_pShimCallback;
549
550
551     // This is for emulating V2 Attach. Initialized to false, and then set to true if we ened to send fake attach events.
552     // Reset to false once the events are sent. See code:ShimProcess::QueueFakeAttachEventsIfNeeded
553     bool  m_fNeedFakeAttachEvents;
554
555     // True if the process was created from an attach (DebugActiveProcess); False if it was launched (CreateProcess)
556     // This is used to send an Attach IPC event, and also used to provide more specific error codes.
557     bool m_attached;
558
559     // True iff we are in the shim's CreateProcess callback. This is used to determine which hresult to
560     // return from code:CordbProcess::SetDesiredNGENCompilerFlags so we correctly emulate the behavior of v2.0.
561     // This is set at the beginning of the callback and cleared in code:CordbProcess::ContinueInternal. 
562     bool m_fInCreateProcess;
563
564     // True iff we are in the shim's FakeLoadModule callback. This is used to determine which hresult to
565     // return from code:CordbModule::SetJITCompilerFlags so we correctly emulate the behavior of v2.0.
566     // This is set at the beginning of the callback and cleared in code:CordbProcess::ContinueInternal. 
567     bool m_fInLoadModule;
568     //
569     // Data
570     //
571
572     // Pointer to CordbProcess. 
573     // @dbgtodo shim: We'd like this to eventually go through public interfaces (ICorDebugProcess)
574     IProcessShimHooks * m_pProcess; // Reference is kept by m_pIProcess;
575     RSExtSmartPtr<ICorDebugProcess> m_pIProcess; 
576
577     // Win32EvenThread, which is the thread that uses the native debug API.
578     CordbWin32EventThread * m_pWin32EventThread;
579
580     // Actual data-target. Since we're shimming V2 scenarios, and V3 is always
581     // live-debugging, this is always a live data-target.
582     RSExtSmartPtr<ShimDataTarget> m_pLiveDataTarget;
583
584
585     // If true, the shim is emulating interop-debugging
586     // If false, the shim is emulating managed-only debugging.
587     // Both managed and native debugging have the same underlying pipeline (built
588     // on native-debug events). So the only difference is how they handle those events.
589     bool m_fIsInteropDebugging;
590
591     // true iff Dispose() was called.  Consult this and do your work under m_ShimProcessDisposeLock
592     // to serialize yourself against a call to Dispose().  This protects your work
593     // from the user doing a Debugger Detach in the middle.
594     bool m_fIsDisposed;
595
596     //.............................................................................
597     //
598     // Members used for handling native events when managed-only debugging.
599     //
600     //.............................................................................
601
602     // Default handler for native events when managed-only debugging.
603     void DefaultEventHandler(const DEBUG_EVENT * pEvent, DWORD * pdwContinueStatus);
604
605     // Given a debug event, track the file handles.
606     void TrackFileHandleForDebugEvent(const DEBUG_EVENT * pEvent);   
607
608     // Have we gotten the loader breakpoint yet?
609     // A Debugger needs to do special work to skip the loader breakpoint, 
610     // and that's also when it should dispatch the faked managed attach events.
611     bool m_loaderBPReceived;
612
613     // Raw callback for ContinueStatusChanged from Data-target.
614     static HRESULT ContinueStatusChanged(void * pUserData, DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
615
616     // Real worker to update ContinueStatusChangedData
617     HRESULT ContinueStatusChangedWorker(DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
618     
619     struct ContinueStatusChangedData
620     {
621         void Clear();
622         bool IsSet();
623         // Tid of Thread changed
624         DWORD m_dwThreadId;
625
626         // New continue status.
627         CORDB_CONTINUE_STATUS m_status;
628     } m_ContinueStatusChangedData;
629
630     // the hash table of ShimStackWalks
631     ShimStackWalkHashTable * m_pShimStackWalkHashTable;
632
633     // the hash table of duplicate creation events
634     DuplicateCreationEventsHashTable * m_pDupeEventsHashTable;
635
636     MachineInfo m_machineInfo;
637 };
638
639
640 //---------------------------------------------------------------------------------------
641 //
642 // This is the container class of ShimChains, ICorDebugFrames, ShimChainEnums, and ShimFrameEnums.   
643 // It has a 1:1 relationship  with ICorDebugThreads.  Upon creation, this class walks the entire stack and 
644 // caches all the stack frames and chains.  The enumerators are created on demand.
645 //
646
647 class ShimStackWalk
648 {
649 public:
650     ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread);
651     ~ShimStackWalk();
652
653     // These functions do not adjust the reference count.
654     ICorDebugThread * GetThread();
655     ShimChain *       GetChain(UINT32 index);
656     ICorDebugFrame *  GetFrame(UINT32 index);
657
658     // Get the number of frames and chains.
659     ULONG             GetChainCount();
660     ULONG             GetFrameCount();
661
662     RSLock *          GetShimLock();
663
664     // Add ICDChainEnum and ICDFrameEnum.
665     void AddChainEnum(ShimChainEnum * pChainEnum);
666     void AddFrameEnum(ShimFrameEnum * pFrameEnum);
667
668     // The next two functions are for ShimStackWalkHashTableTraits.
669     ICorDebugThread * GetKey();
670     static UINT32 Hash(ICorDebugThread * pThread);
671
672     // Check if the specified frame is the leaf frame according to the V2 definition.
673     BOOL IsLeafFrame(ICorDebugFrame * pFrame);
674
675     // Check if the two specified frames are the same.  This function checks the SPs, frame address, etc.
676     // instead of just checking for pointer equality.
677     BOOL IsSameFrame(ICorDebugFrame * pLeft, ICorDebugFrame * pRight);
678
679     // The following functions are entry point into the ShimStackWalk.  They are called by the RS.
680     void EnumerateChains(ICorDebugChainEnum ** ppChainEnum);
681
682     void GetActiveChain(ICorDebugChain ** ppChain);
683     void GetActiveFrame(ICorDebugFrame ** ppFrame);
684     void GetActiveRegisterSet(ICorDebugRegisterSet ** ppRegisterSet);
685
686     void GetChainForFrame(ICorDebugFrame * pFrame, ICorDebugChain ** ppChain);
687     void GetCallerForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCallerFrame);
688     void GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** ppCalleeFrame);
689
690 private:
691     //---------------------------------------------------------------------------------------
692     //
693     // This is a helper class used to store the information of a chain during a stackwalk.  A chain is marked
694     // by the CONTEXT on the leaf boundary and a FramePointer on the root boundary.  Also, notice that we
695     // are keeping two CONTEXTs.  This is because some chain types may cancel a previous unmanaged chain.  
696     // For example, a CHAIN_FUNC_EVAL chain cancels any CHAIN_ENTER_UNMANAGED chain immediately preceding
697     // it.  In this case, the leaf boundary of the CHAIN_FUNC_EVAL chain is marked by the CONTEXT of the
698     // previous CHAIN_ENTER_MANAGED, not the previous CHAIN_ENTER_UNMANAGED.
699     //
700
701     struct ChainInfo
702     {
703     public:
704         ChainInfo() : m_rootFP(LEAF_MOST_FRAME), m_reason(CHAIN_NONE), m_fNeedEnterManagedChain(FALSE), m_fLeafNativeContextIsValid(FALSE) {}
705
706         void CancelUMChain() { m_reason = CHAIN_NONE; }
707         BOOL IsTrackingUMChain() { return (m_reason == CHAIN_ENTER_UNMANAGED); }
708
709         DT_CONTEXT          m_leafNativeContext;
710         DT_CONTEXT          m_leafManagedContext;
711         FramePointer        m_rootFP;
712         CorDebugChainReason m_reason;
713         bool                m_fNeedEnterManagedChain;
714         bool                m_fLeafNativeContextIsValid;
715     };
716
717     //---------------------------------------------------------------------------------------
718     //
719     // This is a helper class used to store information during a stackwalk.  Conceptually it is a simplified
720     // version of FrameInfo used on the LS in V2.
721     //
722
723     struct StackWalkInfo
724     {
725     public:
726         StackWalkInfo();
727         ~StackWalkInfo();
728
729         // Reset all the per-frame information.
730         void ResetForNextFrame();
731
732         // During the stackwalk, we need to find out whether we should process the next stack frame or the
733         // next internal frame.  These functions help us determine whether we have exhausted one or both
734         // types of frames.  The stackwalk is finished when both types are exhausted.
735         bool ExhaustedAllFrames();
736         bool ExhaustedAllStackFrames();
737         bool ExhaustedAllInternalFrames();
738
739         // Simple helper function to get the current internal frame.
740         ICorDebugInternalFrame2 * GetCurrentInternalFrame();
741
742         // Check whether we are processing the first frame.
743         BOOL IsLeafFrame();
744
745         // Check whether we are skipping frames because of a child frame.
746         BOOL IsSkippingFrame();
747
748         // Indicates whether we are dealing with a converted frame.  
749         // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
750         BOOL HasConvertedFrame();
751
752         // Store the child frame we are currently trying to find the parent frame for.
753         // If this is NULL, then we are not skipping frames.
754         RSExtSmartPtr<ICorDebugNativeFrame2>   m_pChildFrame;
755
756         // Store the converted frame, if any.
757         RSExtSmartPtr<ICorDebugInternalFrame2> m_pConvertedInternalFrame2;
758
759         // Store the array of internal frames.  This is an array of RSExtSmartPtrs, and so each element 
760         // is protected, and we only need to call Clear() to release each element and free all the memory.
761         RSExtPtrArray<ICorDebugInternalFrame2> m_ppInternalFrame2;
762
763         UINT32  m_cChain;               // number of chains
764         UINT32  m_cFrame;               // number of frames
765         UINT32  m_firstFrameInChain;    // the index of the first frame in the current chain
766         UINT32  m_cInternalFrames;      // number of internal frames
767         UINT32  m_curInternalFrame;     // the index of the current internal frame being processed
768
769         CorDebugInternalFrameType m_internalFrameType;
770
771         bool m_fExhaustedAllStackFrames;
772
773         // Indicate whether we are processing an internal frame or a stack frame.
774         bool m_fProcessingInternalFrame;    
775
776         // Indicate whether we should skip the current chain because it's a chain derived from a leaf frame 
777         // of type TYPE_INTERNAL.  This is the behaviour in V2.  
778         // See code:DebuggerWalkStackProc.
779         bool m_fSkipChain;
780
781         // Indicate whether the current frame is the first frame we process.
782         bool m_fLeafFrame;
783
784         // Indicate whether we are processing a converted frame.
785         bool m_fHasConvertedFrame;
786     };
787
788     // A ShimStackWalk is deleted when a process is continued, or when the stack is changed in any way
789     // (e.g. SetIP, EnC, etc.).
790     void Populate();
791     void Clear();
792
793     // Get a FramePointer to mark the root boundary of a chain.
794     FramePointer GetFramePointerForChain(DT_CONTEXT * pContext);
795     FramePointer GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2);
796
797     CorDebugInternalFrameType GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2);
798
799     // Append a frame to the array.
800     void AppendFrame(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo);
801     void AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, StackWalkInfo * pStackWalkInfo);
802
803     // Append a chain to the array.
804     void AppendChainWorker(StackWalkInfo *     pStackWalkInfo,
805                            DT_CONTEXT *        pLeafContext,
806                            FramePointer        fpRoot,
807                            CorDebugChainReason chainReason,
808                            BOOL                fIsManagedChain);
809     void AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo);
810
811     // Save information on the ChainInfo regarding the current chain.
812     void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext);
813
814     // Check what we are process next, a internal frame or a stack frame.
815     BOOL CheckInternalFrame(ICorDebugFrame *     pNextStackFrame,
816                             StackWalkInfo *      pStackWalkInfo,
817                             ICorDebugThread3 *   pThread3,
818                             ICorDebugStackWalk * pSW);
819
820     // Convert an ICDInternalFrame to another ICDInternalFrame due to IL methods without metadata.
821     // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
822     BOOL ConvertInternalFrameToDynamicMethod(StackWalkInfo * pStackWalkInfo);
823
824     // Convert an ICDNativeFrame to an ICDInternalFrame due to IL methods without metadata.
825     // See code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
826     BOOL ConvertStackFrameToDynamicMethod(ICorDebugFrame * pFrame, StackWalkInfo * pStackWalkInfo);
827
828     // Process an unmanaged chain.
829     BOOL ShouldTrackUMChain(StackWalkInfo * pswInfo);
830     void TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo);
831
832     // Check whether the internal frame is a newly exposed type in Arrowhead.  If so, then the shim should
833     // not expose it.
834     BOOL IsV3FrameType(CorDebugInternalFrameType type);
835
836     // Check whether the specified frame represents a dynamic method.
837     BOOL IsILFrameWithoutMetadata(ICorDebugFrame * pFrame);
838
839     CDynArray<ShimChain *>      m_stackChains;  // growable ordered array of chains and frames
840     CDynArray<ICorDebugFrame *> m_stackFrames; 
841
842     ShimChainEnum * m_pChainEnumList;           // linked list of ShimChainEnum and ShimFrameEnum
843     ShimFrameEnum * m_pFrameEnumList;
844
845     // the thread on which we are doing a stackwalk, i.e. the "owning" thread
846     RSExtSmartPtr<ShimProcess>     m_pProcess;
847     RSExtSmartPtr<ICorDebugThread> m_pThread;
848 };
849
850
851 //---------------------------------------------------------------------------------------
852 //
853 // This class implements the deprecated ICDChain interface.
854 //
855
856 class ShimChain : public ICorDebugChain
857 {
858 public:
859     ShimChain(ShimStackWalk *     pSW,
860               DT_CONTEXT *        pContext,
861               FramePointer        fpRoot,
862               UINT32              chainIndex,
863               UINT32              frameStartIndex,
864               UINT32              frameEndIndex,
865               CorDebugChainReason chainReason,
866               BOOL                fIsManaged,
867               RSLock *            pShimLock);
868     ~ShimChain();
869
870     void Neuter();
871     BOOL IsNeutered();
872
873     //
874     // IUnknown
875     //
876
877     ULONG STDMETHODCALLTYPE AddRef();
878     ULONG STDMETHODCALLTYPE Release();
879     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
880
881     //
882     // ICorDebugChain
883     //
884
885     COM_METHOD GetThread(ICorDebugThread ** ppThread);
886     COM_METHOD GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd);
887     COM_METHOD GetContext(ICorDebugContext ** ppContext);
888     COM_METHOD GetCaller(ICorDebugChain ** ppChain);
889     COM_METHOD GetCallee(ICorDebugChain ** ppChain);
890     COM_METHOD GetPrevious(ICorDebugChain ** ppChain);
891     COM_METHOD GetNext(ICorDebugChain ** ppChain);
892     COM_METHOD IsManaged(BOOL * pManaged);
893     COM_METHOD EnumerateFrames(ICorDebugFrameEnum ** ppFrames);
894     COM_METHOD GetActiveFrame(ICorDebugFrame ** ppFrame);
895     COM_METHOD GetRegisterSet(ICorDebugRegisterSet ** ppRegisters);
896     COM_METHOD GetReason(CorDebugChainReason * pReason);
897
898     //
899     // accessors
900     //
901
902     // Get the owning ShimStackWalk.
903     ShimStackWalk * GetShimStackWalk();
904
905     // Get the first and last index of the frame owned by this chain.  This class itself doesn't store the
906     // frames.  Rather, the frames are stored on the ShimStackWalk.  This class just stores the indices.
907     // Note that the indices are [firstIndex, lastIndex), i.e. the last index is exclusive.
908     UINT32 GetFirstFrameIndex();
909     UINT32 GetLastFrameIndex();
910
911 private:
912     // A chain describes a stack range within the stack.  This includes a CONTEXT at the start (leafmost)
913     // end of the chain, and a frame pointer where the chain ends (rootmost).  This stack range is exposed
914     // publicly via ICDChain::GetStackRange(), and can be used to stitch managed and native stack frames
915     // together into a unified stack.
916     DT_CONTEXT          m_context;          // the leaf end of the chain
917     FramePointer        m_fpRoot;           // the root end of the chain
918
919     ShimStackWalk *     m_pStackWalk;       // the owning ShimStackWalk
920     Volatile<ULONG>     m_refCount; 
921
922     // The 0-based index of this chain in the ShimStackWalk's chain array (m_pStackWalk->m_stackChains).
923     UINT32              m_chainIndex;
924
925     // The 0-based index of the first frame owned by this chain in the ShimStackWalk's frame array 
926     // (m_pStackWalk->m_stackFrames).  See code::ShimChain::GetFirstFrameIndex().
927     UINT32              m_frameStartIndex;
928
929     // The 0-based index of the last frame owned by this chain in the ShimStackWalk's frame array 
930     // (m_pStackWalk->m_stackFrames).  This index is exlusive.  See code::ShimChain::GetLastFrameIndex().
931     UINT32              m_frameEndIndex;
932
933     CorDebugChainReason m_chainReason;
934     BOOL                m_fIsManaged;       // indicates whether this chain contains managed frames
935     BOOL                m_fIsNeutered;
936
937     RSLock *            m_pShimLock;        // shim lock from ShimProcess to protect neuteredness checks
938 };
939
940
941 //---------------------------------------------------------------------------------------
942 //
943 // This class implements the deprecated ICDChainEnum interface.
944 //
945
946 class ShimChainEnum : public ICorDebugChainEnum
947 {
948 public:
949     ShimChainEnum(ShimStackWalk * pSW, RSLock * pShimLock);
950     ~ShimChainEnum();
951
952     void Neuter();
953     BOOL IsNeutered();
954
955     //
956     // IUnknown
957     //
958
959     ULONG STDMETHODCALLTYPE AddRef();
960     ULONG STDMETHODCALLTYPE Release();
961     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
962
963     //
964     // ICorDebugEnum
965     //
966
967     COM_METHOD Skip(ULONG celt);
968     COM_METHOD Reset();
969     COM_METHOD Clone(ICorDebugEnum ** ppEnum);
970     COM_METHOD GetCount(ULONG * pcChains);
971
972     //
973     // ICorDebugChainEnum
974     //
975
976     COM_METHOD Next(ULONG cChains, ICorDebugChain * rgpChains[], ULONG * pcChainsFetched);
977
978     //
979     // accessors
980     // 
981
982     // used to link ShimChainEnums in a list
983     ShimChainEnum * GetNext();
984     void SetNext(ShimChainEnum * pNext);
985
986 private:
987     ShimStackWalk * m_pStackWalk;           // the owning ShimStackWalk
988
989     // This points to the next ShimChainEnum in the linked list of ShimChainEnums to be cleaned up.
990     // The head of the list is on the ShimStackWalk (m_pStackWalk->m_pChainEnumList).
991     ShimChainEnum * m_pNext;
992
993     UINT32          m_currentChainIndex;    // the index of the current ShimChain being enumerated
994     Volatile<ULONG> m_refCount;
995     BOOL            m_fIsNeutered;
996     
997     RSLock *        m_pShimLock;            // shim lock from ShimProcess to protect neuteredness checks
998 };
999
1000
1001 //---------------------------------------------------------------------------------------
1002 //
1003 // This class implements the deprecated ICDFrameEnum interface.
1004 //
1005
1006 class ShimFrameEnum : public ICorDebugFrameEnum
1007 {
1008 public:
1009     ShimFrameEnum(ShimStackWalk * pSW, ShimChain * pChain, UINT32 frameStartIndex, UINT32 frameEndIndex, RSLock * pShimLock);
1010     ~ShimFrameEnum();
1011
1012     void Neuter();
1013     BOOL IsNeutered();
1014
1015     //
1016     // IUnknown
1017     //
1018
1019     ULONG STDMETHODCALLTYPE AddRef();
1020     ULONG STDMETHODCALLTYPE Release();
1021     COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
1022
1023     //
1024     // ICorDebugEnum
1025     //
1026
1027     COM_METHOD Skip(ULONG celt);
1028     COM_METHOD Reset();
1029     COM_METHOD Clone(ICorDebugEnum ** ppEnum);
1030     COM_METHOD GetCount(ULONG * pcFrames);
1031
1032     //
1033     // ICorDebugFrameEnum
1034     //
1035
1036     COM_METHOD Next(ULONG cFrames, ICorDebugFrame * rgpFrames[], ULONG * pcFramesFetched);
1037
1038     //
1039     // accessors
1040     // 
1041
1042     // used to link ShimChainEnums in a list
1043     ShimFrameEnum * GetNext();
1044     void SetNext(ShimFrameEnum * pNext);
1045
1046 private:
1047     ShimStackWalk * m_pStackWalk;           // the owning ShimStackWalk
1048     ShimChain *     m_pChain;               // the owning ShimChain
1049     RSLock *        m_pShimLock;            // shim lock from ShimProcess to protect neuteredness checks
1050
1051     // This points to the next ShimFrameEnum in the linked list of ShimFrameEnums to be cleaned up.
1052     // The head of the list is on the ShimStackWalk (m_pStackWalk->m_pFrameEnumList).
1053     ShimFrameEnum * m_pNext;
1054
1055     UINT32          m_currentFrameIndex;    // the current ICDFrame being enumerated
1056     UINT32          m_endFrameIndex;        // the last index (exclusive) of the frame owned by the chain;
1057                                             // see code:ShimChain::GetLastFrameIndex
1058     Volatile<ULONG> m_refCount;
1059     BOOL            m_fIsNeutered;
1060 };
1061
1062
1063 #endif // SHIMPRIV_H
1064