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