1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
9 // Common include file for right-side of debugger.
10 //*****************************************************************************
31 #include "xcordebug.h"
32 #include "cordbpriv.h"
35 #include <cordbpriv.h>
36 #include <dbgipcevents.h>
38 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
39 #include <ipcmanagerinterface.h>
40 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
43 #include "primitives.h"
45 #include "dacdbiinterface.h"
51 #include "nativepipeline.h"
52 #include "stringcopyholder.h"
55 #include "eventchannel.h"
58 #define CRASH(x) _ASSERTE(!x)
59 #define ASSERT(x) _ASSERTE(x)
61 // We want to keep the 'worst' HRESULT - if one has failed (..._E_...) & the
62 // other hasn't, take the failing one. If they've both/neither failed, then
63 // it doesn't matter which we take.
64 // Note that this macro favors retaining the first argument
65 #define WORST_HR(hr1,hr2) (FAILED(hr1)?hr1:hr2)
68 // Forbid usage of OS APIs that we should be using the data-target for
69 #define ReadProcessMemory DONT_USE_READPROCESS_MEMORY
70 #define WriteProcessMemory DONT_USE_WRITEPROCESS_MEMORY
73 /* ------------------------------------------------------------------------- *
74 * Forward class declarations
75 * ------------------------------------------------------------------------- */
84 class CordbJITILFrame;
85 class CordbInternalFrame;
88 class CordbVariableHome;
90 #ifdef FEATURE_INTEROP_DEBUGGING
91 class CordbUnmanagedThread;
92 struct CordbUnmanagedEvent;
98 class CordbBreakpoint;
101 class CordbEnCSnapshot;
102 class CordbWin32EventThread;
103 class CordbRCEventThread;
104 class CordbRegisterSet;
105 class CordbNativeFrame;
106 class CordbObjectValue;
107 class CordbEnCErrorInfo;
108 class CordbEnCErrorInfoEnum;
111 class CordbNativeCode;
113 class CordbReJitILCode;
120 class CorpubAppDomain;
121 class CorpubProcessEnum;
122 class CorpubAppDomainEnum;
128 class IDacDbiInterface;
130 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
131 class DbgTransportTarget;
132 class DbgTransportSession;
133 #endif // FEATURE_DBGIPC_TRANSPORT_DI
135 // @dbgtodo private shim hook - the RS has private hooks into the shim to help bridge the V2/V3 gap.
136 // This helps provide a working dogfooding story throughout our transition.
137 // These hooks must be removed before shipping.
142 extern HINSTANCE GetModuleInst();
147 class CordbSafeHashTable;
150 //---------------------------------------------------------------------------------------
152 // This is an encapsulation of the information necessary to connect to the debugger proxy on a remote machine.
153 // It includes the IP address and the port number. The IP address can be set via the env var
154 // COMPlus_DbgTransportProxyAddress, and the port number is fixed when Mac debugging is configured.
160 void Init(DWORD dwIPAddress, USHORT usPort)
162 m_dwIPAddress = dwIPAddress;
172 DWORD GetIPAddress() {return m_dwIPAddress;};
173 USHORT GetPort() {return m_usPort;};
180 extern forDbiWorker forDbi;
182 // for dbi we just default to new, but we need to have these defined for both dac and dbi
183 inline void * operator new(size_t lenBytes, const forDbiWorker &)
185 void * result = new BYTE[lenBytes];
193 inline void * operator new[](size_t lenBytes, const forDbiWorker &)
195 void * result = new BYTE[lenBytes];
203 // Helper to delete memory used with the IDacDbiInterface::IAllocator interface.
204 template<class T> inline
205 void DeleteDbiMemory(T *p)
212 //---------------------------------------------------------------------------------------
214 // Simple array of holders (either RSSmartPtrs or RSExtSmartPtrs).
215 // Holds a reference to each element.
218 // T is the base type and HOLDER_T is the type of the holder. All functions implemented on this base
219 // class must work for both RSSmartPtrs and RSExtSmartPtrs. For example, there is no concept of neutering
220 // for RSExtSmartPtrs.
223 template<typename T, typename HOLDER_T>
233 // Is the array emtpy?
236 return (m_pArray == NULL);
239 // Allocate an array of ptrs.
240 // Returns false if not enough memory; else true.
241 bool Alloc(unsigned int cElements)
243 // Caller should have already Neutered
246 // It's legal to allocate 0 items. We'll succeed the allocation, but still claim that IsEmpty() == true.
252 // RSSmartPtr ctor will ensure all elements are null initialized.
253 m_pArray = new (nothrow) HOLDER_T [cElements];
254 if (m_pArray == NULL)
259 m_cElements = cElements;
263 // Allocate an array of ptrs.
265 void AllocOrThrow(unsigned int cElements)
267 if (!Alloc(cElements))
273 // Release each element and empty the array.
276 // this Invoke dtors on each element which will release each element
283 // Array lookup. Caller gaurantees this is in range.
285 T* operator [] (unsigned int index) const
287 _ASSERTE(m_pArray != NULL);
288 CONSISTENCY_CHECK_MSGF((index <= m_cElements), ("Index out of range. Index=%u, Max=%u\n", index, m_cElements));
290 return m_pArray[index];
293 // Assign a given index to the given value. The array holder will increment the internal reference on the value.
294 void Assign(unsigned int index, T* pValue)
296 _ASSERTE(m_pArray != NULL);
297 CONSISTENCY_CHECK_MSGF((index <= m_cElements), ("Index out of range. Index=%u, Max=%u\n", index, m_cElements));
299 m_pArray[index].Assign(pValue);
302 // Get lenght of array in elements.
303 unsigned int Length() const
308 // Some things need to get the address of an element in the table.
309 // For example, CordbThreads have an array of CordbFrame objects, and then CordbChains describe a range
310 // or frames via pointers into the CordbThread's array.
311 // This is a dangerous operation because it lets us side-step reference counting and protection.
312 T ** UnsafeGetAddrOfIndex(unsigned int index)
314 return m_pArray[index].UnsafeGetAddr();
318 // Raw array of values.
321 // Number of elements in m_pArray. Note the following is always true: (m_cElements == 0) == (m_pArray == NULL);
322 unsigned int m_cElements;
326 //-----------------------------------------------------------------------------
328 // Simple array holder of RSSmartPtrs (internal pointers).
329 // Holds a reference to each element.
332 // This derived class adds the concept of neutering to the base pointer array.
333 // Allows automatic Clear()ing; do not use this unless it is safe to do so in
334 // all cases - e.g. you're holding a local.
337 template< typename T, typename HOLDER_T = RSSmartPtr<T> > // We need to use HOLDER_T to make gcc happy.
338 class RSPtrArray : public BaseRSPtrArray<T, HOLDER_T>
341 typedef BaseRSPtrArray<T, HOLDER_T> Super;
345 RSPtrArray() : m_autoClear(FALSE)
357 // Caller should have already Neutered
358 _ASSERTE(Super::IsEmpty());
362 void EnableAutoClear()
367 // Neuter all elements in the array.
368 void NeuterAndClear()
370 for(unsigned int i = 0; i < Super::m_cElements; i++)
372 if (Super::m_pArray[i] != NULL)
374 Super::m_pArray[i]->Neuter();
383 //-----------------------------------------------------------------------------
385 // Simple array holder of RSExtSmartPtrs (external pointers).
386 // Holds a reference to each element.
389 // This derived class clears the array in its destructor.
392 template< typename T, typename HOLDER_T = RSExtSmartPtr<T> > // We need to use HOLDER_T to make gcc happy.
393 class RSExtPtrArray : public BaseRSPtrArray<T, HOLDER_T>
396 typedef BaseRSPtrArray<T, HOLDER_T> Super;
407 //-----------------------------------------------------------------------------
409 // This lets us map cookies <--> RSPTR_*,
410 // Then we just put the cookie in the IPC block instead of the raw RSPTR.
411 // This will also adjust the internal-reference count on the T* object.
412 // This isolates the RS from bugs in the LS.
413 // We templatize by type for type safety.
414 // Caller must syncrhonize all access (preferably w/ the stop-go lock).
415 //-----------------------------------------------------------------------------
431 for(UINT i = 0; i < m_cEntries; i++)
435 m_pTable[i]->InternalRelease();
443 // Add a value into table. Value can't be NULL.
444 // Returns 0 on failure (such as oom),
445 // Returns a non-zero cookie on success.
448 _ASSERTE(pValue != NULL);
449 // skip 0 because it's an invalid handle.
450 for(UINT i = 1; ; i++)
452 // If we've run out of space, allocate new space
453 if( i >= m_cEntries )
457 return 0; // failed to grow
459 _ASSERTE( i < m_cEntries );
460 _ASSERTE( m_pTable[i] == NULL );
461 // Since we grew, the next slot should now be open.
464 if (m_pTable[i] == NULL)
466 m_pTable[i] = pValue;
467 pValue->InternalAddRef();
474 // Lookup the value based off the cookie, which was obtained via "Add".
475 // return NULL on error.
476 T* Lookup(UINT cookie)
478 _ASSERTE(cookie != 0);
479 if (cookie >= m_cEntries)
481 CONSISTENCY_CHECK_MSGF(false, ("Cookie out of range.Cookie=0x%x. Size=0x%x.\n", cookie, m_cEntries));
484 T* p = m_pTable[cookie];
487 CONSISTENCY_CHECK_MSGF(false, ("Cookie is for empty slot.Cookie=0x%x.\n", cookie));
488 return NULL; // empty!
493 T* LookupAndRemove(UINT cookie)
495 _ASSERTE(cookie != 0);
496 T* p = Lookup(cookie);
499 m_pTable[cookie] = NULL;
500 p->InternalRelease();
506 // Resize the m_pTable array.
509 if (m_pTable == NULL)
511 _ASSERTE(m_cEntries == 0);
513 m_pTable = new (nothrow) T*[cSize];
514 if (m_pTable == NULL)
519 ZeroMemory(m_pTable, sizeof(T*) * m_cEntries);
522 size_t cNewSize = (m_cEntries * 3 / 2) + 1;
523 _ASSERTE(cNewSize > m_cEntries);
524 T** p = new (nothrow) T*[cNewSize];
529 ZeroMemory(p, sizeof(T*) * cNewSize);
532 // Copy over old stuff
533 memcpy(p, m_pTable, sizeof(T*) * m_cEntries);
537 m_cEntries = cNewSize;
547 //-----------------------------------------------------------------------------
548 // Simple Holder for RS object intialization to cooperate with Neutering
550 // The ctor will do an addref.
551 // The dtor (invoked in exception) will neuter and release the object. This
552 // release will likely be the final release to cause a delete.
553 // If the object is created successfully, caller should do a SuppressRelease()
554 // to avoid it getting neutered.
557 // RSInitHolder<CordbFoo> pFoo(new CordbFoo(x,y,z));
558 // pFoo->InitMore(a,b,c);
559 // GiveOwnershipToSomebodyElse(pFoo); // now somebody else owns and will clean up
560 // pFoo.ClearAndMarkDontNeuter(); // we no longer need to
562 // So if an exception is thrown before ClearAndMarkDontNeuter(), the dtor is invoked
563 // and the object is properly destroyed (deleted and neutered).
565 // Another common pattern is when initializing an object to hand off to an external:
566 // RSInitHolder<CordbFoo> pFoo(new CordbFoo(x,y,z));
567 // pFoo->InitMore(a,b,c);
568 // pFoo.TransferOwnershipExternal(ppOutParameter);
569 // TransferOwnershipExternal will assign to ppOutParameter, inc external ref, and
570 // call ClearAndMarkDontNeuter()
571 //-----------------------------------------------------------------------------
576 // Default ctor. Must call Assign() later.
580 RSInitHolder(T * pObject)
585 void Assign(T * pObject)
587 _ASSERTE(m_pObject == NULL); // only assign once.
588 m_pObject.Assign(pObject);
592 FORCEINLINE operator T *() const
597 FORCEINLINE T * operator->()
602 // This will null out m_pObject such that the dtor will not neuter it.
603 // This will also release the ref we took in the ctor.
604 // This will clear the current pointer.
605 void ClearAndMarkDontNeuter()
611 // Transfer ownership to a pointer
614 // ppOutParam - pointer to get ownership. External Reference is incremented.
615 // this pointer should do an external release.
618 // This calls ClearAndMarkDontNeuter(). This holder is Empty after this.
619 template <class TOther>
620 void TransferOwnershipExternal(TOther ** ppOutParam)
622 *ppOutParam = static_cast<TOther*> (m_pObject);
623 m_pObject->ExternalAddRef();
625 ClearAndMarkDontNeuter();
630 // Transfer the ownership of the wrapped object to the given hash table.
633 // pHashTable - hash table to take ownership.
636 // the contianing object for convenience. Throws on error (particularly
637 // if it fails adding to the hash).
640 // This calls ClearAndMarkDontNeuter(). This holder is Empty after this.
641 T* TransferOwnershipToHash(CordbSafeHashTable<T> * pHashtable)
643 T* pObject = m_pObject;
644 pHashtable->AddBaseOrThrow(m_pObject);
645 ClearAndMarkDontNeuter();
650 // Used to pass into a function that will assign to us.
653 // Address of this holder. This is like the & operator.
654 // This is provided for consistency with other holders which
655 // override the &operator.
656 RSInitHolder<T> * GetAddr()
663 RSSmartPtr<T> m_pObject;
668 //-----------------------------------------------------------------------------
669 // Have the extra level of indirection is useful for catching Cordbg errors.
670 //-----------------------------------------------------------------------------
672 // On debug, we have an opportunity to catch failing hresults during reproes.
673 #define ErrWrapper(hr) ErrWrapperHelper(hr, __FILE__, __LINE__)
675 inline HRESULT ErrWrapperHelper(HRESULT hr, const char * szFile, int line)
679 DWORD dwErr = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgBreakOnErr);
682 CONSISTENCY_CHECK_MSGF(false, ("Dbg Error break, hr=0x%08x, '%s':%d", hr, szFile, line));
688 // On release, it's just an identity function
689 #define ErrWrapper(hr) (hr)
692 //-----------------------------------------------------------------------------
693 // Quick helpers for threading semantics
694 //-----------------------------------------------------------------------------
696 bool IsWin32EventThread(CordbProcess* p);
697 bool IsRCEventThread(Cordb* p);
699 /* ------------------------------------------------------------------------- *
701 * ------------------------------------------------------------------------- */
703 typedef void* REMOTE_PTR;
706 //-----------------------------------------------------------------------------
707 // Wrapper class for locks. This is like Crst on the LS
708 //-----------------------------------------------------------------------------
713 // Attrs, can be bitwise-or together.
716 cLockUninit = 0x00000000,
717 cLockReentrant = 0x00000001,
718 cLockFlat = 0x00000002,
720 // (unusual). Not considered a debug API lock, for purposes of deciding whether
721 // to count this lock in m_cTotalDbgApiLocks, which is asserted to be 0 on entry
722 // to public APIs. Example of such a lock: LL_SHIM_PROCESS_DISPOSE_LOCK
723 cLockNonDbgApi = 0x00000004,
726 // To prevent deadlocks, we order all locks.
727 // A thread must acquire higher-numbered locks before lower numbered locks.
728 // These are used as indices into an array, so number them accordingly!
731 // Size of the array..
734 // The Stop-Go lock is used to make Stop + Continue be atomic operations.
735 // These methods will toggle the Process-lock b/c they go between multiple threads.
736 // This lock can never be taken on the Win32 ET.
739 // The win32-event-thread behaves as if it held a lock at this level.
740 LL_WIN32_EVENT_THREAD = 4,
742 // This held for the duration of ShimProcess::Dispose(), and protects
743 // ShimProcess::m_fIsDisposed, so that other ShimProcess functions can
744 // safely execute serially with ShimProcess::Dispose(). This needs to be
745 // a high-level lock, since ShimProcess methods that take this lock also
746 // call into CorDb* objects which take many of the other locks. In contrast,
747 // LL_SHIM_LOCK must remain low-level, as there exists at least one place where
748 // LL_SHIM_LOCK is taken while the CorDbProcess lock is also held (see
749 // CordbThread::GetActiveFunctions which takes the CorDbProcess lock while
750 // calling GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this), which
751 // takes LL_SHIM_LOCK).
752 LL_SHIM_PROCESS_DISPOSE_LOCK = 3,
754 // The process lock is the primary lock for a CordbProcess object. It synchronizes
755 // between RCET, W32ET, and user threads.
758 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
759 LL_DBG_TRANSPORT_MANAGER_LOCK = 1,
761 LL_DBG_TRANSPORT_TARGET_LOCK = 0,
763 LL_DD_MARSHAL_LOCK = 0,
764 #endif // FEATURE_DBGIPC_TRANSPORT_DI
766 // These are all leaf locks (they don't take any other lock once they're held).
767 LL_PROCESS_LIST_LOCK = 0,
769 // Win32 send lock is shared by all processes accessing a single w32et.
770 LL_WIN32_SEND_LOCK = 0,
772 // Small lock around sending IPC events to support workarounds in func-eval abort.
773 // See code:CordbEval::Abort for details.
774 LL_FUNC_EVAL_ABORT_HACK_LOCK = 0,
776 // Leaf-level lock used in the shim.
780 // Initialize a lock w/ debugging info. szTag must be a string literal.
781 void Init(const char * szTag, int eAttr, ERSLockLevel level);
788 // Accessors for holders.
789 static void HolderEnter(RSLock * pLock)
793 static void HolderLeave(RSLock * pLock)
799 CRITICAL_SECTION m_lock;
806 const char * Name() { return m_szTag; }
808 // Returns true if this thread has the lock.
811 // Returns true if this is safe to take on this thread (ie, this thread
812 // doesn't already hold bigger locks).
813 // bool IsSafeToTake();
815 ERSLockLevel GetLevel() { return m_level; }
817 // If we're inited, we must have either cLockReentrant or cLockFlat specified.
818 bool IsInit() { return m_eAttr != 0; }
819 bool IsReentrant() { return (m_eAttr & cLockReentrant) == cLockReentrant; }
820 bool IsDbgApiLock() { return ((m_eAttr & cLockNonDbgApi) == 0); }
823 ERSLockLevel m_level;
824 int m_eAttr; // Bitwise combination of ELockAttr values
827 const char * m_szTag;
832 typedef Holder<RSLock *, RSLock::HolderEnter, RSLock::HolderLeave> RSLockHolder;
833 typedef Holder<RSLock *, RSLock::HolderLeave, RSLock::HolderEnter> RSInverseLockHolder;
837 typedef RSLock::RSLockHolder RSLockHolder;
838 typedef RSLock::RSInverseLockHolder RSInverseLockHolder;
840 // In the RS, we should be using RSLocks instead of raw critical sections.
841 #define CRITICAL_SECTION USE_RSLOCK_INSTEAD_OF_CRITICAL_SECTION
844 /* ------------------------------------------------------------------------- *
845 * Helper macros. Use the ATT_* macros below instead of these.
846 * ------------------------------------------------------------------------- */
848 // This serves as glue for exceptions. Eventually, we shouldn't have unrecoverable
849 // error, and instead, errors should just propogate up.
850 #define SetUnrecoverableIfFailed(__p, __hr) \
853 CORDBSetUnrecoverableError(__p, __hr, 0); \
856 #define CORDBSetUnrecoverableError(__p, __hr, __code) \
857 ((__p)->UnrecoverableError((__hr), (__code), __FILE__, __LINE__))
859 #define _CORDBCheckProcessStateOK(__p) \
860 (!((__p)->m_unrecoverableError) && !((__p)->m_terminated) && !((__p)->m_detached))
862 #define _CORDBCheckProcessStateOKAndSync(__p, __c) \
863 (!((__p)->m_unrecoverableError) && !((__p)->m_terminated) && !((__p)->m_detached) && \
864 (__p)->GetSynchronized())
866 // Worker to get failure HR from given state. If not in a failure state, it yields __defaultHR.
867 // If a caller knows that we're in a failure state, it can pass in a failure value for __defaultHR.
868 #define CORDBHRFromProcessStateWorker(__p, __c, __defaultHR) \
869 ((__p)->m_unrecoverableError ? CORDBG_E_UNRECOVERABLE_ERROR : \
870 ((__p)->m_detached ? CORDBG_E_PROCESS_DETACHED : \
871 ((__p)->m_terminated ? CORDBG_E_PROCESS_TERMINATED : \
872 (!(__p)->GetSynchronized() ? CORDBG_E_PROCESS_NOT_SYNCHRONIZED \
875 #define CORDBHRFromProcessState(__p, __c) \
876 CORDBHRFromProcessStateWorker(__p, __c, S_OK) \
879 // Have a set of helper macros to check the process state and return a failure code.
880 // These only should be used at public interface boundaries, in which case we should
881 // not be holding the process lock. But we have enough places where we use them internally,
882 // so we can't really assert that we're not holding the lock.
884 // We're very restricted in what APIs we can call on the w32et. Have
885 // a convenient check for this.
886 // If we have no shim, then nop this check because everything becomes like the w32-event-thread.
887 #define CORDBFailOrThrowIfOnWin32EventThread(__p, errorAction) \
889 if (((__p)->GetShim() != NULL) && (__p)->IsWin32EventThread()) \
891 _ASSERTE(!"Don't call on this thread"); \
892 errorAction(ErrWrapper(CORDBG_E_CANT_CALL_ON_THIS_THREAD)); \
896 #define CORDBFailIfOnWin32EventThread(__p) CORDBFailOrThrowIfOnWin32EventThread(__p, return)
898 #define CORDBRequireProcessStateOK(__p) { \
899 if (!_CORDBCheckProcessStateOK(__p)) \
900 return ErrWrapper(CORDBHRFromProcessState(__p, NULL)); }
902 // If we need to be synced, then we shouldn't be on the win32 Event-Thread.
903 #define CORDBRequireProcessStateOKAndSync(__p,__c) { \
904 CORDBFailIfOnWin32EventThread(__p); \
905 if (!_CORDBCheckProcessStateOKAndSync(__p, __c)) \
906 return ErrWrapper(CORDBHRFromProcessState(__p, __c)); }
908 #define CORDBRequireProcessSynchronized(__p, __c) { \
909 CORDBFailIfOnWin32EventThread(__p); \
910 if (!(__p)->GetSynchronized()) return ErrWrapper(CORDBG_E_PROCESS_NOT_SYNCHRONIZED);}
915 //-----------------------------------------------------------------------------
916 // All public APIS fall into 2 categories regarding their API Threading Type (ATT)
917 // We use a standard set of macros to define & enforce each type.
919 // (1) ATT_REQUIRE_STOPPED
920 // We must be stopped (either synced or at a win32 event) to call this API.
921 // - We'll fail if we're not stopped.
922 // - If we're stopped, we'll sync. Thus after this API, we're always synced,
923 // and Cordbg must call Continue to resume the process.
924 // - We'll take the Stop-Go-lock. This prevents another thread from continuing underneath us.
925 // - We may send IPC events.
926 // Common for APIs like Stacktracing
928 // (2) ATT_ALLOW_LIVE
929 // We do not have to be stopped to call this API.
930 // - We can be live, thus we can not take the stop-go lock (unless it's from a SC-holder).
931 // - If we're going to send IPC events, we must use a Stop-Continue holder.
932 // - Our stop-status is the same after this API as it was before.
933 // Common usage: read-only APIs.
935 // (2b) ATT_ALLOW_LIVE_DO_STOPGO.
936 // - shortcut macro to do #2, but throw in a stop-continue holder. These really
937 // should be in camp #1, but that would require an interface change.
938 //-----------------------------------------------------------------------------
940 // Helper macros for the ATT stuff
942 // Do checks that need to be done before we take the SG lock. These include checks
943 // where if we fail them, taking the SG lock could deadlock (such as being on win32 thread).
944 #define DO_PRE_STOP_GO_CHECKS(errorAction) \
945 CORDBFailOrThrowIfOnWin32EventThread(__proc_for_ATT, errorAction) \
946 if ((__proc_for_ATT)->m_unrecoverableError) { errorAction(CORDBG_E_UNRECOVERABLE_ERROR); } \
948 // Do checks after we take the SG lock. These include checks that rely on state protected
950 #define DO_POST_STOP_GO_CHECKS(errorAction) \
951 _ASSERTE((this->GetProcess() == __proc_for_ATT) || this->IsNeutered()); \
952 if (this->IsNeutered()) { errorAction(CORDBG_E_OBJECT_NEUTERED); } \
955 // The exact details here are rocket-science.
956 // We cache the __proc value to a local variable (__proc_for_ATT) so that we don't re-evaluate __proc. (It also forces type-safety).
957 // This is essential in case __proc is something like "this->GetProcess()" and which can start returning NULL if 'this'
958 // gets neutered underneath us. Caching guarantees that we'll be able to make it to the StopGo-lock.
960 // We explicitily check some things before taking the Stop-Go lock:
961 // - CORDBG_E_UNRECOVERABLE_ERROR before the lock because if that's set,
962 // we may have leaked locks to the outside world, so taking the StopGo lock later could fail.
963 // - Are we on the W32et - can't take sg lock if on W32et
964 // Then we immediately take the stop-go lock to prevent another thread from continuing underneath us.
965 // Then, if we're stopped, we ensure that we're also synced.
968 // - fake win32-stopped. Eg, between SuspendUnmanagedThreads & ResumeUnmanagedThreads
969 // (one way to get here is getting debug events during the special-deferment region)
971 // If we're not stopped, then we fail. This macro must never return S_OK.
973 // If not-shimmed (using V3 pipeline), then skip all checks about stop-state.
974 #define ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(__proc, errorAction) \
975 CordbProcess * __proc_for_ATT = (__proc); \
976 DO_PRE_STOP_GO_CHECKS(errorAction); \
977 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
978 DO_POST_STOP_GO_CHECKS(errorAction); \
979 if ((__proc_for_ATT)->GetShim() != NULL) { \
980 if (!__proc_for_ATT->m_initialized) { errorAction(CORDBG_E_NOTREADY); } \
981 if ((__proc_for_ATT)->IsStopped()) { \
982 HRESULT _hr2 = (__proc_for_ATT)->StartSyncFromWin32Stop(NULL); \
983 if (FAILED(_hr2)) errorAction(_hr2); \
985 if (!_CORDBCheckProcessStateOKAndSync(__proc_for_ATT, NULL)) \
986 errorAction(CORDBHRFromProcessStateWorker(__proc_for_ATT, NULL, E_FAIL)); \
989 #define ATT_REQUIRE_STOPPED_MAY_FAIL(__proc)ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(__proc, return)
991 // #1b - allows it to be non-inited. This should look just like ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW
992 // except it doesn't do SSFW32Stop and doesn't have the m_initialized check.
993 #define ATT_REQUIRE_SYNCED_OR_NONINIT_MAY_FAIL(__proc) \
994 CordbProcess * __proc_for_ATT = (__proc); \
995 DO_PRE_STOP_GO_CHECKS(return); \
996 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
997 DO_POST_STOP_GO_CHECKS(return); \
998 if ((__proc_for_ATT)->GetShim() != NULL) { \
999 if (!_CORDBCheckProcessStateOKAndSync(__proc_for_ATT, NULL)) \
1000 return CORDBHRFromProcessStateWorker(__proc_for_ATT, NULL, E_FAIL); \
1005 // Gross variant on #1.
1006 // This is a very dangerous ATT contract; but we need to support it for backwards compat.
1007 // Some APIs, like ICDProcess:EnumerateThreads can be used before the process is actually
1008 // initialized (kind of for interop-debugging).
1009 // These can't check the m_initialized flag b/c that may not be set yet.
1010 // They also can't sync the runtime.
1011 // This should only be used for non-blocking leaf activity.
1012 #define ATT_EVERETT_HACK_REQUIRE_STOPPED_ALLOW_NONINIT(__proc) \
1013 CordbProcess * __proc_for_ATT = (__proc); \
1014 DO_PRE_STOP_GO_CHECKS(return); \
1015 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
1016 DO_POST_STOP_GO_CHECKS(return); \
1017 if (((__proc_for_ATT)->GetShim() != NULL) && !(__proc_for_ATT)->IsStopped()) { return CORDBG_E_PROCESS_NOT_SYNCHRONIZED; } \
1020 // #2 - caller may think debuggee is live, but throw in a Stop-Continue holder.
1021 #define ATT_ALLOW_LIVE_DO_STOPGO(__proc) \
1022 CordbProcess * __proc_for_ATT = (__proc); \
1023 DO_PRE_STOP_GO_CHECKS(return); \
1024 CORDBRequireProcessStateOK(__proc_for_ATT); \
1025 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
1026 DO_POST_STOP_GO_CHECKS(return); \
1027 StopContinueHolder __hStopGo; \
1028 if ((__proc_for_ATT)->GetShim() != NULL) \
1030 HRESULT _hr2 = __hStopGo.Init(__proc_for_ATT); \
1031 if (FAILED(_hr2)) return _hr2; \
1032 _ASSERTE((__proc_for_ATT)->GetSynchronized()); \
1038 //-----------------------------------------------------------------------------
1039 // StopContinueHolder. Ensure that we're synced during a certain region.
1040 // (Particularly when sending an IPCEvent)
1041 // Calls ICorDebugProcess::Stop & IMDArocess::Continue.
1045 // StopContinueHolder h;
1046 // IfFailRet(h.Init(process))
1048 // } // continue automatically called.
1049 //-----------------------------------------------------------------------------
1052 class StopContinueHolder
1055 StopContinueHolder() : m_p(NULL) { };
1057 HRESULT Init(CordbProcess * p);
1058 ~StopContinueHolder();
1065 /* ------------------------------------------------------------------------- *
1067 * ------------------------------------------------------------------------- */
1069 #define COM_METHOD HRESULT STDMETHODCALLTYPE
1072 enumCordbUnknown, // 0
1073 enumCordb, // 1 1 [1]x1
1074 enumCordbProcess, // 2 1 [1]x1
1075 enumCordbAppDomain, // 3 1 [1]x1
1076 enumCordbAssembly, // 4
1077 enumCordbModule, // 5 15 [27-38,55-57]x1
1078 enumCordbClass, // 6
1079 enumCordbFunction, // 7
1080 enumCordbThread, // 8 2 [4,7]x1
1082 enumCordbChain, // 10
1083 enumCordbChainEnum, // 11
1084 enumCordbContext, // 12
1085 enumCordbFrame, // 13
1086 enumCordbFrameEnum, // 14
1087 enumCordbValueEnum, // 15
1088 enumCordbRegisterSet, // 16
1089 enumCordbJITILFrame, // 17
1090 enumCordbBreakpoint, // 18
1091 enumCordbStepper, // 19
1092 enumCordbValue, // 20
1093 enumCordbEnCSnapshot, // 21
1094 enumCordbEval, // 22
1095 enumCordbUnmanagedThread,// 23
1096 enumCorpubPublish, // 24
1097 enumCorpubProcess, // 25
1098 enumCorpubAppDomain, // 26
1099 enumCorpubProcessEnum, // 27
1100 enumCorpubAppDomainEnum,// 28
1101 enumCordbEnumFilter, // 29
1102 enumCordbEnCErrorInfo, // 30
1103 enumCordbEnCErrorInfoEnum,//31
1104 enumCordbUnmanagedEvent,// 32
1105 enumCordbWin32EventThread,//33
1106 enumCordbRCEventThread, // 34
1107 enumCordbNativeFrame, // 35
1108 enumCordbObjectValue, // 36
1109 enumCordbType, // 37
1110 enumCordbNativeCode, // 38
1111 enumCordbILCode, // 39
1112 enumCordbEval2, // 40
1114 enumCordbHashTableEnum, // 42
1115 enumCordbCodeEnum, // 43
1116 enumCordbStackWalk, // 44
1117 enumCordbEnumerator, // 45
1118 enumCordbHeap, // 48
1119 enumCordbHeapSegments, // 47
1126 //-----------------------------------------------------------------------------
1127 // Support for Native Breakpoints
1128 //-----------------------------------------------------------------------------
1131 void * pAddress; // pointer into the LS address space.
1132 PRD_TYPE opcode; // opcode to restore with.
1134 inline bool operator==(NativePatch p2)
1136 return memcmp(this, &p2, sizeof(p2)) == 0;
1140 //-----------------------------------------------------------------------------
1141 // Cross-platform patch operations
1142 //-----------------------------------------------------------------------------
1144 // Remove the int3 from the remote address
1145 HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE opcode);
1147 // This flavor is assuming our caller already knows the opcode.
1148 HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress);
1150 // Apply the patch and get the opcode that we're replacing.
1151 HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE * pOpcode);
1154 class CordbHashTable;
1156 #define CORDB_COMMON_BASE_SIGNATURE 0x0d00d96a
1157 #define CORDB_COMMON_BASE_SIGNATURE_DEAD 0x0dead0b1
1159 // Common base for both CorPublish + CorDebug objects.
1160 class CordbCommonBase : public IUnknown
1163 // GENERIC: made this private as I'm changing the use of m_id for CordbClass, and
1164 // I want to make sure I catch all the places where m_id is used directly and cast
1165 // to/from tokens and/or (void*).
1169 static LONG m_saDwInstance[enumMaxDerived]; // instance x this
1170 static LONG m_saDwAlive[enumMaxDerived];
1171 static PVOID m_sdThis[enumMaxDerived][enumMaxThis];
1173 enumCordbDerived m_type;
1179 DWORD m_signature : 30;
1181 // Sticky bit set when we neuter an object. All methods (besides AddRef,Release,QI)
1182 // should check this bit and fail via the FAIL_IF_NEUTERED macro.
1183 DWORD m_fIsNeutered : 1;
1185 // Mark that this object can be "neutered at will". NeuterList::SweepAllNeuterAtWillObjects
1186 // looks at this bit.
1187 // For some objects, we don't explicitly mark when the lifetime is up. The only way
1188 // we know is when external count goes to 0. This avoids forcing us to do cleanup
1189 // in the dtor (which may come at a bad time). Sticky bit set in BaseRelease().
1190 DWORD m_fNeuterAtWill : 1;
1193 static LONG s_CordbObjectUID; // Unique ID for each object.
1194 static LONG s_TotalObjectCount; // total number of outstanding objects.
1197 void ValidateObject()
1199 if( !IsValidObject() )
1201 STRESS_LOG1(LF_ASSERT, LL_ALWAYS, "CordbCommonBase::IsValidObject() failed: %x\n", this);
1202 _ASSERTE(!"CordbCommonBase::IsValidObject() failed");
1203 FreeBuildDebugBreak();
1207 bool IsValidObject()
1209 return (m_signature == CORDB_COMMON_BASE_SIGNATURE);
1212 CordbCommonBase(UINT_PTR id, enumCordbDerived type)
1217 CordbCommonBase(UINT_PTR id)
1219 init(id, enumCordbUnknown);
1222 void init(UINT_PTR id, enumCordbDerived type)
1224 // To help us track object leaks, we want to log when we create & destory CordbBase objects.
1226 InterlockedIncrement(&s_TotalObjectCount);
1227 InterlockedIncrement(&s_CordbObjectUID);
1229 LOG((LF_CORDB, LL_EVERYTHING, "Memory: CordbBase object allocated: this=%p, count=%d, id=%p, Type=%d\n", this, s_CordbObjectUID, id, type));
1232 m_signature = CORDB_COMMON_BASE_SIGNATURE;
1233 m_fNeuterAtWill = 0;
1241 //m_dwInstance = CordbBase::m_saDwInstance[m_type];
1242 //InterlockedIncrement(&CordbBase::m_saDwInstance[m_type]);
1243 //InterlockedIncrement(&CordbBase::m_saDwAlive[m_type]);
1244 //if (m_dwInstance < enumMaxThis)
1246 // m_sdThis[m_type][m_dwInstance] = this;
1251 virtual ~CordbCommonBase()
1253 // If we're deleting, we really should have released any outstanding reference.
1254 // If we call Release() on a deleted object, we'll av (especially b/c Release
1255 // may call delete again).
1256 CONSISTENCY_CHECK_MSGF(m_RefCount == 0, ("Deleting w/ non-zero ref count. 0x%08x", m_RefCount));
1259 //InterlockedDecrement(&CordbBase::m_saDwAlive[m_type]);
1260 //if (m_dwInstance < enumMaxThis)
1262 // m_sdThis[m_type][m_dwInstance] = NULL;
1265 // To help us track object leaks, we want to log when we create & destory CordbBase objects.
1266 LOG((LF_CORDB, LL_EVERYTHING, "Memory: CordbBase object deleted: this=%p, id=%p, Refcount=0x%x\n", this, m_id, m_RefCount));
1269 LONG newTotalObjectsCount = InterlockedDecrement(&s_TotalObjectCount);
1270 _ASSERTE(newTotalObjectsCount >= 0);
1273 // Don't shutdown logic until everybody is done with it.
1274 // If we leak objects, this may mean that we never shutdown logging at all!
1275 #if defined(_DEBUG) && defined(LOGGING)
1276 if (newTotalObjectsCount == 0)
1284 Member function behavior of a neutered COM object:
1286 1. AddRef(), Release(), QueryInterface() work as normal.
1287 a. This gives folks who are responsible for pairing a Release() with
1288 an AddRef() a chance to dereference their pointer and call Release()
1289 when they are informed, explicitly or implicitly, that the object is neutered.
1291 2. Any other member function will return an error code unless documented.
1292 a. If a member function returns information when the COM object is
1293 neutered then the semantics of that function need to be documented.
1294 (ie. If an AppDomain is unloaded and you have a reference to the COM
1295 object representing the AppDomain, how _should_ it behave? That behavior
1296 should be documented)
1299 Postcondions of Neuter():
1301 1. All circular references (aka back-pointers) are "broken". They are broken
1302 by calling Release() on all "Weak References" to the object. If you're a purist,
1303 these pointers should also be NULLed out.
1304 a. Weak References/Strong References:
1305 i. If any objects are not "reachable" from the root (ie. stack or from global pointers)
1306 they should be reclaimed. If they are not, they are leaked and there is an issue.
1307 ii. There must be a partial order on the objects such that if A < B then:
1308 1. A has a reference to B. This reference is a "strong reference"
1309 2. A, and thus B, is reachable from the root
1310 iii. If a reference belongs in the partial order then it is a "strong reference" else
1311 it is a weak reference.
1312 *** 2. Sufficient conditions to ensure no COM objects are leaked: ***
1313 a. When Neuter() is invoked:
1314 i. Calles Release on all its weak references.
1315 ii. Then, for each strong reference:
1318 iii. If it's derived from a CordbXXX class, call Neuter() on the base class.
1319 1. Sense Neuter() is virtual, use the scope specifier Cordb[BaseClass]::Neuter().
1320 3. All members return error codes, except:
1321 a. Members of IUknown, AddRef(), Release(), QueryInterfac()
1322 b. Those documented to have functionality when the object is neutered.
1323 i. Neuter() still works w/o error. If it is invoke a second time it will have already
1324 released all its strong and weak references so it could just return.
1327 Alternate design ideas:
1329 DESIGN: Note that it's possible for object B to have two parents in the partial order
1330 and it must be documented which one is responsible for calling Neuter() on B.
1331 1. For example, CordbCode could reasonably be a sibling of CordbFunction and CordbNativeFrame.
1332 Which one should call Release()? For now we have CordbFunction call Release() on CordbCode.
1334 DESIGN: It is not a necessary condition in that Neuter() invoke Release() on all
1335 it's strong references. Instead, it would be sufficient to ensure all object are released, that
1336 each object call Release() on all its strong pointers in its destructor.
1337 1. This might be done if its necessary for some member to return "tombstone"
1338 information after the object has been netuered() which involves the siblings (wrt poset)
1339 of the object. However, no sibling could access a parent (wrt poset) because
1340 Neuter called Release() on all its weak pointers.
1342 DESIGN: Rename Neuter() to some name that more accurately reflect the semantics.
1343 1. The three operations are:
1344 a. ReleaseWeakPointers()
1345 b. NeuterStrongPointers()
1346 c. ReleaseStrongPointers()
1347 1. Assert that it's done after NeuterStrongPointers()
1348 2. That would introduce a bunch of functions... but it would be clear.
1350 DESIGN: CordbBase could provide a function to register strong and weak references. That way CordbBase
1351 could implement a general version of ReleaseWeak/ReleaseStrong/NeuterStrongPointers(). This
1352 would provide a very error resistant framework for extending the object model plus it would
1353 be very explicit about what is going on.
1354 One thing that might trip this is idea up is that if an object has two parents,
1355 like the CordbCode might, then either both objects call Neuter or one is reference
1361 The graph formed by the strong references must remain acyclic.
1362 It's up to the developer (YOU!) to ensure that each Neuter
1363 function maintains that invariant.
1365 Here is the current Partial Order on CordbXXX objects. (All these classes
1366 eventually chain to CordbBase.Neuter() for completeness.)
1376 CordbCode (Can we assert a thread will not reference
1377 the same CordbCode as a CordbFunction?)
1380 CordbNativeFrame -> CordbFrame (Chain to baseClass)
1384 <TODO>TODO: Some Neuter functions have not yet been implemented due to time restrictions.</TODO>
1386 <TODO>TODO: Some weak references never have AddRef() called on them. If that's cool then
1387 it should be stated in the documentation. Else it should be changed.</TODO>
1390 virtual void Neuter();
1392 // Unsafe neuter for an object that's already dead.
1393 void UnsafeNeuterDeadObject();
1397 // For debugging (asserts, logging, etc) provide a pretty name (this is 1:1 w/ the VTable)
1398 // We provide a default impl in the base object in case this gets called from a dtor (virtuals
1399 // called from dtors use the base version, not the derived). A pure call would AV in that case.
1400 virtual const char * DbgGetName() { return "CordbBase"; };
1403 bool IsNeutered() const {LIMITED_METHOD_CONTRACT; return m_fIsNeutered == 1; }
1404 bool IsNeuterAtWill() const { LIMITED_METHOD_CONTRACT; return m_fNeuterAtWill == 1; }
1405 void MarkNeuterAtWill() { LIMITED_METHOD_CONTRACT; m_fNeuterAtWill = 1; }
1407 //-----------------------------------------------------------
1409 //----------------------------------------------------------
1412 // We maintain both an internal + external refcount. This allows us to catch
1413 // if an external caller has too many releases.
1414 // low bits are internal count, high bits are external count
1415 // so Total count = (m_RefCount & CordbBase_InternalRefCountMask) + (m_RefCount >> CordbBase_ExternalRefCountShift);
1416 typedef LONGLONG MixedRefCountSigned;
1417 typedef ULONGLONG MixedRefCountUnsigned;
1418 typedef LONG ExternalRefCount;
1419 MixedRefCountUnsigned m_RefCount;
1422 // Adjust the internal ref count.
1423 // These aren't available to the external world, so only internal code can manipulate the internal count.
1424 void InternalAddRef();
1425 void InternalRelease();
1427 // Derived versions of AddRef / Release will call these.
1428 // External AddRef & Release
1429 // These do not have any additional Asserts to enforce that we're not manipulating the external count
1431 ULONG STDMETHODCALLTYPE BaseAddRef();
1432 ULONG STDMETHODCALLTYPE BaseRelease();
1434 // External ref count versions, with extra debug count to enforce that this is done externally.
1435 // When derive classes use these versions, it Asserts that we're not adjusting external counts from inside.
1436 // Thus we can be confident that we're *never* leaking external refs to these objects.
1437 // @todo - eventually everything should use these.
1438 ULONG STDMETHODCALLTYPE BaseAddRefEnforceExternal();
1439 ULONG STDMETHODCALLTYPE BaseReleaseEnforceExternal();
1441 // Do an AddRef against the External count. This is a semantics issue.
1442 // We use this when an internal component Addrefs out-parameters (which Cordbg will call Release on).
1443 // This just does a regular external AddRef().
1444 void ExternalAddRef();
1448 static void InitializeCommon();
1451 static void AddDebugPrivilege();
1454 #define CordbBase_ExternalRefCountShift 32
1455 #define CordbBase_InternalRefCountMask 0xFFFFFFFF
1456 #define CordbBase_InternalRefCountMax 0x7FFFFFFF
1459 // Does the given Cordb object type have affinity to a CordbProcess object?
1460 // This is only used for certain asserts.
1461 inline bool DoesCordbObjectTypeHaveProcessPtr(enumCordbDerived type)
1464 (type != enumCordbCodeEnum) &&
1465 (type != enumCordb) &&
1466 (type != enumCordbHashTableEnum);
1470 // Base class specifically for CorDebug objects
1471 class CordbBase : public CordbCommonBase
1474 CordbBase(CordbProcess * pProcess, UINT_PTR id, enumCordbDerived type) : CordbCommonBase(id, type)
1476 // CordbProcess can't pass 'this' to base class, per error C4355. So we pass null and set later.
1477 _ASSERTE((pProcess != NULL) ||
1478 ((type) == enumCordbProcess) ||
1479 !DoesCordbObjectTypeHaveProcessPtr(type));
1481 m_pProcess.Assign(pProcess);
1484 CordbBase(CordbProcess * pProcess, UINT_PTR id) : CordbCommonBase(id)
1486 _ASSERTE(pProcess != NULL);
1487 m_pProcess.Assign(pProcess);
1490 virtual ~CordbBase()
1492 // Derived classes should not have cleared out our pointer.
1493 // CordbProcess's Neuter explicitly nulls out its pointer to avoid circular reference.
1494 _ASSERTE(m_pProcess!= NULL ||
1495 (CordbCommonBase::m_type == enumCordbProcess) ||
1496 !DoesCordbObjectTypeHaveProcessPtr(CordbCommonBase::m_type));
1498 // Ideally, all CorDebug objects to be neutered by the time their dtor is called.
1499 // @todo - we're still working out neutering semantics for a few remaining objects, so we exclude
1500 // those from the assert.
1501 _ASSERTE(IsNeutered() ||
1502 (m_type == enumCordbBreakpoint) ||
1503 (m_type == enumCordbStepper));
1506 // Neuter just the right-side state.
1507 virtual void Neuter();
1509 // Neuter both left-side state and right-side state.
1510 virtual void NeuterLeftSideResources();
1512 // Get the CordbProcess object that this CordbBase object is associated with (or NULL if there's none).
1513 CordbProcess * GetProcess() const
1518 // All objects need a strong pointer back to the process so that they can get access to key locks
1519 // held by the process (StopGo lock) so that they can synchronize their operations against neutering.
1520 // This pointer is cleared in our dtor, and not when we're neutered. Since we can't control when the
1521 // dtor is called (it's controlled by external references), we classify this as an external reference too.
1523 // This is the only "strong" reference backpointer that objects need have. All other backpointers can be weak references
1524 // because when a parent object is neutered, it will null out all weak reference pointers in all of its children.
1525 // That will also break any potential cycles.
1526 RSUnsafeExternalSmartPtr<CordbProcess> m_pProcess;
1534 //-----------------------------------------------------------------------------
1535 // Macro to check if a CordbXXX object is neutered, and return a standard
1536 // error code if it is.
1537 // We pass the 'this' pointer of the object in because it gives us some extra
1538 // flexibility and lets us log debug info.
1539 // It is an API breach to access a neutered object.
1540 //-----------------------------------------------------------------------------
1541 #define FAIL_IF_NEUTERED(pThis) \
1542 int _____Neuter_Status_Already_Marked; \
1543 _____Neuter_Status_Already_Marked = 0; \
1545 if (pThis->IsNeutered()) { \
1546 LOG((LF_CORDB, LL_ALWAYS, "Accessing a neutered object at %p\n", pThis)); \
1547 return ErrWrapper(CORDBG_E_OBJECT_NEUTERED); \
1551 //-----------------------------------------------------------------------------
1552 // Macro to check if a CordbXXX object is neutered, and return a standard
1553 // error code if it is.
1554 // We pass the 'this' pointer of the object in because it gives us some extra
1555 // flexibility and lets us log debug info.
1556 // It is an API breach to access a neutered object.
1557 //-----------------------------------------------------------------------------
1558 #define THROW_IF_NEUTERED(pThis) \
1559 int _____Neuter_Status_Already_Marked; \
1560 _____Neuter_Status_Already_Marked = 0; \
1562 if (pThis->IsNeutered()) { \
1563 LOG((LF_CORDB, LL_ALWAYS, "Accessing a neutered object at %p\n", pThis)); \
1564 ThrowHR(CORDBG_E_OBJECT_NEUTERED); \
1568 // We have an OK_IF_NEUTERED macro to say that this method can be safely
1569 // called if we're neutered. Mostly for semantic benefits.
1570 // Also, if a method is marked OK, then somebody won't go and add a 'fail'
1571 // This is an extremely dangerous quality because:
1572 // 1) it means that we have no synchronization (can't take the Stop-Go lock)
1573 // 2) none of our backpointers are usable (they may be nulled out at anytime by another thread).
1574 // - this also means we absolutely can't send IPC events (since that requires a CordbProcess)
1575 // 3) The only safe data are blittalbe embedded fields (eg, a pid or stack range)
1577 // Any usage of this macro should clearly specify why this is safe.
1578 #define OK_IF_NEUTERED(pThis) \
1579 int _____Neuter_Status_Already_Marked; \
1580 _____Neuter_Status_Already_Marked = 0;
1583 //-------------------------------------------------------------------------------
1584 // Simple COM enumerator pattern on a fixed list of items
1585 //--------------------------------------------------------------------------------
1586 template< typename ElemType,
1587 typename ElemPublicType,
1588 typename EnumInterfaceType,
1589 ElemPublicType (*GetPublicType)(ElemType)>
1590 class CordbEnumerator : public CordbBase, public EnumInterfaceType
1593 // the list of items being enumerated over
1595 // the number of items in the list
1597 // the index of the next item to be returned in the enumeration
1601 // makes a copy of the elements in the "items" array
1602 CordbEnumerator(CordbProcess* pProcess, ElemType *items, DWORD elemCount);
1603 // assumes ownership of the elements in the "*items" array.
1604 // this avoids an extra allocation + copy
1605 CordbEnumerator(CordbProcess* pProcess, ElemType **items, DWORD elemCount);
1608 // IUnknown interface
1609 virtual COM_METHOD QueryInterface(REFIID riid, VOID** ppInterface);
1610 virtual ULONG __stdcall AddRef();
1611 virtual ULONG __stdcall Release();
1613 // ICorDebugEnum interface
1614 virtual COM_METHOD Clone(ICorDebugEnum **ppEnum);
1615 virtual COM_METHOD GetCount(ULONG *pcelt);
1616 virtual COM_METHOD Reset();
1617 virtual COM_METHOD Skip(ULONG celt);
1619 // ICorDebugXXXEnum interface
1620 virtual COM_METHOD Next(ULONG celt, ElemPublicType items[], ULONG *pceltFetched);
1622 // CordbBase overrides
1623 virtual VOID Neuter();
1626 // Converts T to U* by using QueryInterface
1627 template<typename T, typename U>
1628 U* QueryInterfaceConvert(T obj);
1630 // No conversion, just returns the argument
1631 template<typename T>
1632 T IdentityConvert(T obj);
1634 // CorDebugGuidToTypeMapping-adapter used by CordbGuidToTypeEnumerator
1635 // in the CordbEnumerator pattern
1636 struct RsGuidToTypeMapping
1639 RSSmartPtr<CordbType> spType;
1643 CorDebugGuidToTypeMapping GuidToTypeMappingConvert(RsGuidToTypeMapping m)
1645 CorDebugGuidToTypeMapping result;
1647 result.pType = (ICorDebugType*)(m.spType.GetValue());
1648 result.pType->AddRef();
1653 // Some useful enumerators
1655 typedef CordbEnumerator<RSSmartPtr<CordbThread>,
1657 ICorDebugThreadEnum,
1658 QueryInterfaceConvert<RSSmartPtr<CordbThread>, ICorDebugThread> > CordbThreadEnumerator;
1660 typedef CordbEnumerator<CorDebugBlockingObject,
1661 CorDebugBlockingObject,
1662 ICorDebugBlockingObjectEnum,
1663 IdentityConvert<CorDebugBlockingObject> > CordbBlockingObjectEnumerator;
1665 // Template classes must be fully defined rather than just declared in the header
1666 #include "rsenumerator.hpp"
1669 typedef CordbEnumerator<COR_SEGMENT,
1671 ICorDebugHeapSegmentEnum,
1672 IdentityConvert<COR_SEGMENT> > CordbHeapSegmentEnumerator;
1674 typedef CordbEnumerator<CorDebugExceptionObjectStackFrame,
1675 CorDebugExceptionObjectStackFrame,
1676 ICorDebugExceptionObjectCallStackEnum,
1677 IdentityConvert<CorDebugExceptionObjectStackFrame> > CordbExceptionObjectCallStackEnumerator;
1679 typedef CordbEnumerator<RsGuidToTypeMapping,
1680 CorDebugGuidToTypeMapping,
1681 ICorDebugGuidToTypeEnum,
1682 GuidToTypeMappingConvert > CordbGuidToTypeEnumerator;
1684 typedef CordbEnumerator<RSSmartPtr<CordbVariableHome>,
1685 ICorDebugVariableHome*,
1686 ICorDebugVariableHomeEnum,
1687 QueryInterfaceConvert<RSSmartPtr<CordbVariableHome>, ICorDebugVariableHome> > CordbVariableHomeEnumerator;
1689 // ----------------------------------------------------------------------------
1690 // Hash table for CordbBase objects.
1691 // - Uses Internal AddRef/Release (not external)
1692 // - Templatize for type-safety w/ Cordb objects
1693 // - Many hashtables are implicitly protected by a lock. For debug-only, we
1694 // explicitly associate w/ an optional RSLock and assert that lock is held on access.
1695 // ----------------------------------------------------------------------------
1697 struct CordbHashEntry
1699 FREEHASHENTRY entry;
1703 class CordbHashTable : private CHashTableAndData<CNewDataNoThrow>
1709 BOOL Cmp(SIZE_T k1, const HASHENTRY * pc2)
1711 LIMITED_METHOD_CONTRACT;
1713 return ((ULONG_PTR)k1) != (reinterpret_cast<const CordbHashEntry *>(pc2))->pBase->m_id;
1716 ULONG HASH(ULONG_PTR id)
1721 SIZE_T KEY(UINT_PTR id)
1727 bool IsInitialized();
1729 #ifndef DACCESS_COMPILE
1730 CordbHashTable(ULONG size)
1731 : CHashTableAndData<CNewDataNoThrow>(size), m_initialized(false), m_count(0)
1735 m_dbgChangeCount = 0;
1738 virtual ~CordbHashTable();
1741 // CordbHashTables may be protected by a lock. For debug-builds, we can associate
1742 // the hash w/ that lock and then assert if it's not held.
1743 void DebugSetRSLock(RSLock * pLock)
1747 int GetChangeCount() { return m_dbgChangeCount; }
1749 void AssertIsProtected();
1751 // Increment the Change count. This can be used to check if the hashtable changes while being enumerated.
1752 void DbgIncChangeCount() { m_dbgChangeCount++; }
1754 int m_dbgChangeCount;
1755 RSLock * m_pDbgLock;
1757 // RSLock association is a no-op on free builds.
1758 void AssertIsProtected() { };
1759 void DbgIncChangeCount() { };
1769 return ((ULONG32)m_count);
1772 // These operators are unsafe b/c they have no typesafety.
1773 // Use a derived CordbSafeHashTable<T> instead.
1774 HRESULT UnsafeAddBase(CordbBase *pBase);
1775 HRESULT UnsafeSwapBase(CordbBase* pBaseOld, CordbBase* pBaseNew);
1776 CordbBase *UnsafeGetBase(ULONG_PTR id, BOOL fFab = TRUE);
1777 CordbBase *UnsafeRemoveBase(ULONG_PTR id);
1779 CordbBase *UnsafeFindFirst(HASHFIND *find);
1780 CordbBase *UnsafeFindNext(HASHFIND *find);
1782 // Unlocked versions don't assert that the lock us held.
1783 CordbBase *UnsafeUnlockedFindFirst(HASHFIND *find);
1784 CordbBase *UnsafeUnlockedFindNext(HASHFIND *find);
1789 // Typesafe wrapper around a normal hash table
1790 // T is expected to be a derived clas of CordbBase
1791 // Note that this still isn't fully typesafe. Ideally we'd take a strongly-typed key
1792 // instead of UINT_PTR (the type could have a fixed relationship to T, or could be
1793 // an additional template argument like standard template hash tables like std::hash_map<K,V>)
1795 class CordbSafeHashTable : public CordbHashTable
1798 #ifndef DACCESS_COMPILE
1799 CordbSafeHashTable<T>(ULONG size) : CordbHashTable(size)
1803 // Typesafe wrappers
1804 HRESULT AddBase(T * pBase) { return UnsafeAddBase(pBase); }
1806 // Either add (eg, future cals to GetBase will succeed) or throw.
1807 void AddBaseOrThrow(T * pBase)
1809 HRESULT hr = AddBase(pBase);
1812 HRESULT SwapBase(T* pBaseOld, T* pBaseNew) { return UnsafeSwapBase(pBaseOld, pBaseNew); }
1813 // Move the function definition of GetBase to rspriv.inl to work around gcc 2.9.5 warnings
1814 T* GetBase(ULONG_PTR id, BOOL fFab = TRUE);
1815 T* GetBaseOrThrow(ULONG_PTR id, BOOL fFab = TRUE);
1817 T* RemoveBase(ULONG_PTR id) { return static_cast<T*>(UnsafeRemoveBase(id)); }
1819 T* FindFirst(HASHFIND *find) { return static_cast<T*>(UnsafeFindFirst(find)); }
1820 T* FindNext(HASHFIND *find) { return static_cast<T*>(UnsafeFindNext(find)); }
1822 // Neuter all items and clear
1823 void NeuterAndClear(RSLock * pLock);
1825 void CopyToArray(RSPtrArray<T> * pArray);
1826 void TransferToArray(RSPtrArray<T> * pArray);
1830 class CordbHashTableEnum : public CordbBase,
1831 public ICorDebugProcessEnum,
1832 public ICorDebugBreakpointEnum,
1833 public ICorDebugStepperEnum,
1834 public ICorDebugThreadEnum,
1835 public ICorDebugModuleEnum,
1836 public ICorDebugAppDomainEnum,
1837 public ICorDebugAssemblyEnum
1839 // Private ctors. Use build function to access.
1841 CordbBase * pOwnerObj,
1842 NeuterList * pOwnerList,
1843 CordbHashTable *table,
1847 static void BuildOrThrow(
1848 CordbBase * pOwnerObj,
1849 NeuterList * pOwnerList,
1850 CordbHashTable *table,
1852 RSInitHolder<CordbHashTableEnum> * pHolder);
1854 CordbHashTableEnum(CordbHashTableEnum *cloneSrc);
1856 ~CordbHashTableEnum();
1857 virtual void Neuter();
1861 // For debugging (asserts, logging, etc) provide a pretty name (this is 1:1 w/ the VTable)
1862 virtual const char * DbgGetName() { return "CordbHashTableEnum"; };
1866 HRESULT Next(ULONG celt, CordbBase *bases[], ULONG *pceltFetched);
1868 //-----------------------------------------------------------
1870 //-----------------------------------------------------------
1872 ULONG STDMETHODCALLTYPE AddRef()
1874 return (BaseAddRef());
1876 ULONG STDMETHODCALLTYPE Release()
1878 return (BaseRelease());
1880 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
1882 //-----------------------------------------------------------
1884 //-----------------------------------------------------------
1886 COM_METHOD Skip(ULONG celt);
1888 COM_METHOD Clone(ICorDebugEnum **ppEnum);
1889 COM_METHOD GetCount(ULONG *pcelt);
1891 //-----------------------------------------------------------
1892 // ICorDebugProcessEnum
1893 //-----------------------------------------------------------
1895 COM_METHOD Next(ULONG celt, ICorDebugProcess *processes[],
1896 ULONG *pceltFetched)
1898 VALIDATE_POINTER_TO_OBJECT_ARRAY(processes, ICorDebugProcess *,
1900 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1902 return (Next(celt, (CordbBase **)processes, pceltFetched));
1905 //-----------------------------------------------------------
1906 // ICorDebugBreakpointEnum
1907 //-----------------------------------------------------------
1909 COM_METHOD Next(ULONG celt, ICorDebugBreakpoint *breakpoints[],
1910 ULONG *pceltFetched)
1912 VALIDATE_POINTER_TO_OBJECT_ARRAY(breakpoints, ICorDebugBreakpoint *,
1914 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1916 return (Next(celt, (CordbBase **)breakpoints, pceltFetched));
1919 //-----------------------------------------------------------
1920 // ICorDebugStepperEnum
1921 //-----------------------------------------------------------
1923 COM_METHOD Next(ULONG celt, ICorDebugStepper *steppers[],
1924 ULONG *pceltFetched)
1926 VALIDATE_POINTER_TO_OBJECT_ARRAY(steppers, ICorDebugStepper *,
1928 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1930 return (Next(celt, (CordbBase **)steppers, pceltFetched));
1933 //-----------------------------------------------------------
1934 // ICorDebugThreadEnum
1935 //-----------------------------------------------------------
1937 COM_METHOD Next(ULONG celt, ICorDebugThread *threads[],
1938 ULONG *pceltFetched)
1940 VALIDATE_POINTER_TO_OBJECT_ARRAY(threads, ICorDebugThread *,
1942 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1944 return (Next(celt, (CordbBase **)threads, pceltFetched));
1947 //-----------------------------------------------------------
1948 // ICorDebugModuleEnum
1949 //-----------------------------------------------------------
1951 COM_METHOD Next(ULONG celt, ICorDebugModule *modules[],
1952 ULONG *pceltFetched)
1954 VALIDATE_POINTER_TO_OBJECT_ARRAY(modules, ICorDebugModule *,
1956 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1958 return (Next(celt, (CordbBase **)modules, pceltFetched));
1961 //-----------------------------------------------------------
1962 // ICorDebugAppDomainEnum
1963 //-----------------------------------------------------------
1965 COM_METHOD Next(ULONG celt, ICorDebugAppDomain *appdomains[],
1966 ULONG *pceltFetched)
1968 VALIDATE_POINTER_TO_OBJECT_ARRAY(appdomains, ICorDebugAppDomain *,
1970 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1972 return (Next(celt, (CordbBase **)appdomains, pceltFetched));
1974 //-----------------------------------------------------------
1975 // ICorDebugAssemblyEnum
1976 //-----------------------------------------------------------
1978 COM_METHOD Next(ULONG celt, ICorDebugAssembly *assemblies[],
1979 ULONG *pceltFetched)
1981 VALIDATE_POINTER_TO_OBJECT_ARRAY(assemblies, ICorDebugAssembly *,
1983 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1985 return (Next(celt, (CordbBase **)assemblies, pceltFetched));
1988 // Owning object is our link to the CordbProcess* tree. Never null until we're neutered.
1989 // NeuterList is related to the owning object. Need to cache it so that we can pass it on
1991 CordbBase * m_pOwnerObj; // provides us w/ a CordbProcess*
1992 NeuterList * m_pOwnerNeuterList;
1995 CordbHashTable *m_table;
1998 HASHFIND m_hashfind;
2005 // timestampt of hashtable when we start enumerating it. Useful for detecting if the table
2006 // changes underneath us.
2007 int m_DbgChangeCount;
2010 void AssertValid() { }
2014 //These factor code between Next & Skip
2015 HRESULT PrepForEnum(CordbBase **pBase);
2017 // Note that the set of types advanced by Pre & by Post are disjoint, and
2018 // that the union of these two sets are all possible types enuerated by
2019 // the CordbHashTableEnum.
2020 HRESULT AdvancePreAssign(CordbBase **pBase);
2021 HRESULT AdvancePostAssign(CordbBase **pBase,
2025 // This factors some code that initializes the module enumerator.
2026 HRESULT SetupModuleEnum();
2031 //-----------------------------------------------------------------------------
2033 // Dtors can be called at any time (whenever Cordbg calls Release, which is outside
2034 // of our control), so we never want to do significant work in a dtor
2035 // (this includes sending IPC events + neutering).
2036 // So objects can queue themselves up to be neutered at a safe time.
2038 // Items in a NeuterList should only contain state in the Right-Side.
2039 // If the item holds resources in the left-side, it should be placed on a
2040 // code:LeftSideResourceCleanupList
2041 //-----------------------------------------------------------------------------
2048 // Add an object to be neutered.
2049 // Anybody calls this to add themselves to the list.
2050 // This will add it to the list and maintain an internal reference to it.
2051 void Add(CordbProcess * pProcess, CordbBase * pObject);
2053 // Add w/o checking for safety. Should only be used by Process-list enum.
2054 void UnsafeAdd(CordbProcess * pProcess, CordbBase * pObject);
2056 // Neuter everything on the list.
2057 // This should only be called by the "owner", but we can't really enforce that.
2058 // This will release all internal references and empty the list.
2059 void NeuterAndClear(CordbProcess * pProcess);
2061 // Sweep for all objects that are marked as 'm_fNeuterAtWill'.
2062 // Neuter and remove these.
2063 void SweepAllNeuterAtWillObjects(CordbProcess * pProcess);
2068 RSSmartPtr<CordbBase> m_pObject;
2072 // Manipulating the list is done under the Process lock.
2076 //-----------------------------------------------------------------------------
2077 // This list is for objects that hold left-side resources.
2078 // If the object does not hold left-side resources, it can be placed on a
2080 //-----------------------------------------------------------------------------
2081 class LeftSideResourceCleanupList : public NeuterList
2084 // dispose everything contained in the list by calling SafeDispose() on each element
2085 void SweepNeuterLeftSideResources(CordbProcess * pProcess);
2086 void NeuterLeftSideResourcesAndClear(CordbProcess * pProcess);
2089 //-------------------------------------------------------------------------
2092 // Stores a value along with a bit indicating whether the value is valid.
2094 // This is particularly useful for LS data read via DAC. We need to gracefully
2095 // handle missing data, and we may want to track independent pieces of data
2096 // separately (often with lazy initialization). It's essential that we can't
2097 // easily lose track of whether the data has been cached yet or not. So
2098 // rather than have extra "isValid" bools everywhere, we use this class to
2099 // encapsulate the validity bit in with the data, and ASSERT that it is true
2100 // whenever reading out the data.
2101 // Note that the client must still remember to call GetValue only when HasValue
2102 // is true. Since C++ doesn't have type-safe sum types, we can't enforce this
2103 // explicitly at compile time (ML-style datatypes and pattern matching is perfect
2106 // Note that we could consider adding some operator overloads to make using
2107 // instances of this class more transparent. Experience will tell if this
2108 // is a good idea or not.
2110 template <typename T>
2114 // By default, initialize to invalid
2115 Optional() : m_fHasValue(false), m_value(T()) {}
2117 // Allow implicit initialization from a value (for copyable T)
2118 Optional(const T& val) : m_fHasValue(true), m_value(val) {}
2120 // Returns true if a value has been stored
2121 bool HasValue() const { return m_fHasValue; }
2123 // Extract the value. Can only be called when HasValue is true.
2124 const T& GetValue() { _ASSERTE(m_fHasValue); return m_value; }
2126 // Get a writable pointer to the value structure, for filling in uncopyable data structures
2127 T * GetValueAddr() { return &m_value; }
2129 // Explicitly mark this object as having a value (for use after writing to it directly using
2130 // GetValueAddr. Not necessary for simple/primitive types).
2131 void SetHasValue() { m_fHasValue = true; }
2133 // Also gets compiler-default copy constructor and assignment operator if T has them
2141 /* ------------------------------------------------------------------------- *
2143 * ------------------------------------------------------------------------- */
2145 class Cordb : public CordbBase, public ICorDebug, public ICorDebugRemote
2148 Cordb(CorDebugInterfaceVersion iDebuggerVersion);
2150 virtual void Neuter();
2155 virtual const char * DbgGetName() { return "Cordb"; }
2157 // Under Debug, we keep some extra state for tracking leaks. The goal is that
2158 // we can assert that we aren't leaking internal refs. We'd like to assert that
2159 // we're not leaking external refs, but since we can't force Cordbg to release,
2160 // we can't really assert that.
2161 // So the idea is that when Cordbg has released its last Cordb object, that
2162 // all internal references have been released.
2163 // Unfortunately, certain CordbBase objects are unrooted and thus we have no
2164 // good time to neuter them and clean up any internal references they may hold.
2165 // So we keep count of those guys too.
2166 static LONG s_DbgMemTotalOutstandingCordb;
2167 static LONG s_DbgMemTotalOutstandingInternalRefs;
2171 // Turn this on to enable an array which will contain all objects that have
2172 // not been completely released.
2174 // #define TRACK_OUTSTANDING_OBJECTS 1
2176 #ifdef TRACK_OUTSTANDING_OBJECTS
2178 #define MAX_TRACKED_OUTSTANDING_OBJECTS 256
2179 static void *Cordb::s_DbgMemOutstandingObjects[MAX_TRACKED_OUTSTANDING_OBJECTS];
2180 static LONG Cordb::s_DbgMemOutstandingObjectMax;
2184 //-----------------------------------------------------------
2186 //-----------------------------------------------------------
2188 ULONG STDMETHODCALLTYPE AddRef()
2190 return (BaseAddRef());
2192 ULONG STDMETHODCALLTYPE Release()
2194 return (BaseRelease());
2196 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2198 //-----------------------------------------------------------
2200 //-----------------------------------------------------------
2202 HRESULT SetTargetCLR(HMODULE hmodTargetCLR);
2204 COM_METHOD Initialize();
2205 COM_METHOD Terminate();
2206 COM_METHOD SetManagedHandler(ICorDebugManagedCallback *pCallback);
2207 COM_METHOD SetUnmanagedHandler(ICorDebugUnmanagedCallback *pCallback);
2208 COM_METHOD CreateProcess(LPCWSTR lpApplicationName,
2209 __in_z LPWSTR lpCommandLine,
2210 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2211 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2212 BOOL bInheritHandles,
2213 DWORD dwCreationFlags,
2214 PVOID lpEnvironment,
2215 LPCWSTR lpCurrentDirectory,
2216 LPSTARTUPINFOW lpStartupInfo,
2217 LPPROCESS_INFORMATION lpProcessInformation,
2218 CorDebugCreateProcessFlags debuggingFlags,
2219 ICorDebugProcess **ppProcess);
2220 COM_METHOD DebugActiveProcess(DWORD dwProcessId, BOOL fWin32Attach, ICorDebugProcess **ppProcess);
2221 COM_METHOD EnumerateProcesses(ICorDebugProcessEnum **ppProcess);
2222 COM_METHOD GetProcess(DWORD dwProcessId, ICorDebugProcess **ppProcess);
2223 COM_METHOD CanLaunchOrAttach(DWORD dwProcessId, BOOL win32DebuggingEnabled);
2225 //-----------------------------------------------------------
2227 //-----------------------------------------------------------
2229 static COM_METHOD CreateObjectV1(REFIID id, void **object);
2230 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
2231 static COM_METHOD CreateObjectTelesto(REFIID id, void ** pObject);
2232 #endif // FEATURE_DBGIPC_TRANSPORT_DI
2233 static COM_METHOD CreateObject(CorDebugInterfaceVersion iDebuggerVersion, REFIID id, void **object);
2235 //-----------------------------------------------------------
2237 //-----------------------------------------------------------
2239 COM_METHOD CreateProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
2240 LPCWSTR lpApplicationName,
2241 __in_z LPWSTR lpCommandLine,
2242 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2243 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2244 BOOL bInheritHandles,
2245 DWORD dwCreationFlags,
2246 PVOID lpEnvironment,
2247 LPCWSTR lpCurrentDirectory,
2248 LPSTARTUPINFOW lpStartupInfo,
2249 LPPROCESS_INFORMATION lpProcessInformation,
2250 CorDebugCreateProcessFlags debuggingFlags,
2251 ICorDebugProcess ** ppProcess);
2253 COM_METHOD DebugActiveProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
2256 ICorDebugProcess ** ppProcess);
2259 //-----------------------------------------------------------
2260 // Methods not exposed via a COM interface.
2261 //-----------------------------------------------------------
2263 HRESULT CreateProcessCommon(ICorDebugRemoteTarget * pRemoteTarget,
2264 LPCWSTR lpApplicationName,
2265 __in_z LPWSTR lpCommandLine,
2266 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2267 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2268 BOOL bInheritHandles,
2269 DWORD dwCreationFlags,
2270 PVOID lpEnvironment,
2271 LPCWSTR lpCurrentDirectory,
2272 LPSTARTUPINFOW lpStartupInfo,
2273 LPPROCESS_INFORMATION lpProcessInformation,
2274 CorDebugCreateProcessFlags debuggingFlags,
2275 ICorDebugProcess **ppProcess);
2277 HRESULT DebugActiveProcessCommon(ICorDebugRemoteTarget * pRemoteTarget, DWORD id, BOOL win32Attach, ICorDebugProcess **ppProcess);
2279 void EnsureCanLaunchOrAttach(BOOL fWin32DebuggingEnabled);
2281 void EnsureAllowAnotherProcess();
2282 void AddProcess(CordbProcess* process);
2283 void RemoveProcess(CordbProcess* process);
2284 CordbSafeHashTable<CordbProcess> *GetProcessList();
2286 void LockProcessList();
2287 void UnlockProcessList();
2290 bool ThreadHasProcessListLock();
2294 HRESULT SendIPCEvent(CordbProcess * pProcess,
2295 DebuggerIPCEvent * pEvent,
2298 void ProcessStateChanged();
2300 HRESULT WaitForIPCEventFromProcess(CordbProcess* process,
2301 CordbAppDomain *appDomain,
2302 DebuggerIPCEvent* event);
2304 //-----------------------------------------------------------
2306 //-----------------------------------------------------------
2309 RSExtSmartPtr<ICorDebugManagedCallback> m_managedCallback;
2310 RSExtSmartPtr<ICorDebugManagedCallback2> m_managedCallback2;
2311 RSExtSmartPtr<ICorDebugManagedCallback3> m_managedCallback3;
2312 RSExtSmartPtr<ICorDebugUnmanagedCallback> m_unmanagedCallback;
2314 CordbRCEventThread* m_rcEventThread;
2316 CorDebugInterfaceVersion GetDebuggerVersion() const;
2318 HMODULE GetTargetCLR() { return m_targetCLR; }
2321 bool IsCreateProcessSupported();
2322 bool IsInteropDebuggingSupported();
2323 void CheckCompatibility();
2325 CordbSafeHashTable<CordbProcess> m_processes;
2327 // List to track outstanding CordbProcessEnum objects.
2328 NeuterList m_pProcessEnumList;
2330 RSLock m_processListMutex;
2333 // This is the version of the ICorDebug APIs that the debugger believes it's consuming.
2334 CorDebugInterfaceVersion m_debuggerSpecifiedVersion;
2336 //Note - this code could be useful outside coresystem, but keeping the change localized
2337 // because we are late in the win8 release
2338 HMODULE m_targetCLR;
2344 /* ------------------------------------------------------------------------- *
2346 * ------------------------------------------------------------------------- */
2348 // Provides the implementation for ICorDebugAppDomain, ICorDebugAppDomain2,
2349 // and ICorDebugAppDomain3
2350 class CordbAppDomain : public CordbBase,
2351 public ICorDebugAppDomain,
2352 public ICorDebugAppDomain2,
2353 public ICorDebugAppDomain3,
2354 public ICorDebugAppDomain4
2357 // Create a CordbAppDomain object based on a pointer to the AppDomain instance in the CLR
2358 CordbAppDomain(CordbProcess * pProcess,
2359 VMPTR_AppDomain vmAppDomain);
2361 virtual ~CordbAppDomain();
2363 virtual void Neuter();
2365 using CordbBase::GetProcess;
2368 virtual const char * DbgGetName() { return "CordbAppDomain"; }
2372 //-----------------------------------------------------------
2374 //-----------------------------------------------------------
2376 ULONG STDMETHODCALLTYPE AddRef()
2378 return (BaseAddRef());
2380 ULONG STDMETHODCALLTYPE Release()
2382 return (BaseRelease());
2384 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2386 //-----------------------------------------------------------
2387 // ICorDebugController
2388 //-----------------------------------------------------------
2390 COM_METHOD Stop(DWORD dwTimeout);
2391 COM_METHOD Continue(BOOL fIsOutOfBand);
2392 COM_METHOD IsRunning(BOOL * pbRunning);
2393 COM_METHOD HasQueuedCallbacks(ICorDebugThread * pThread,
2395 COM_METHOD EnumerateThreads(ICorDebugThreadEnum ** ppThreads);
2396 COM_METHOD SetAllThreadsDebugState(CorDebugThreadState state, ICorDebugThread * pExceptThisThread);
2398 // Deprecated, returns E_NOTIMPL
2399 COM_METHOD Detach();
2401 COM_METHOD Terminate(unsigned int exitCode);
2403 COM_METHOD CanCommitChanges(
2405 ICorDebugEditAndContinueSnapshot * pSnapshots[],
2406 ICorDebugErrorInfoEnum ** pError);
2408 COM_METHOD CommitChanges(
2410 ICorDebugEditAndContinueSnapshot * pSnapshots[],
2411 ICorDebugErrorInfoEnum ** pError);
2413 //-----------------------------------------------------------
2414 // ICorDebugAppDomain
2415 //-----------------------------------------------------------
2417 * GetProcess returns the process containing the app domain
2420 COM_METHOD GetProcess(ICorDebugProcess ** ppProcess);
2423 * EnumerateAssemblies enumerates all assemblies in the app domain
2426 COM_METHOD EnumerateAssemblies(ICorDebugAssemblyEnum ** ppAssemblies);
2428 COM_METHOD GetModuleFromMetaDataInterface(IUnknown * pIMetaData,
2429 ICorDebugModule ** ppModule);
2431 * EnumerateBreakpoints returns an enum of all active breakpoints
2432 * in the app domain. This includes all types of breakpoints :
2433 * function breakpoints, data breakpoints, etc.
2436 COM_METHOD EnumerateBreakpoints(ICorDebugBreakpointEnum ** ppBreakpoints);
2439 * EnumerateSteppers returns an enum of all active steppers in the app domain.
2442 COM_METHOD EnumerateSteppers(ICorDebugStepperEnum ** ppSteppers);
2444 // Deprecated, always returns true.
2445 COM_METHOD IsAttached(BOOL * pfAttached);
2447 // Returns the friendly name of the AppDomain
2448 COM_METHOD GetName(ULONG32 cchName,
2450 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2453 * GetObject returns the runtime app domain object.
2454 * Note: This method is not yet implemented.
2457 COM_METHOD GetObject(ICorDebugValue ** ppObject);
2459 // Deprecated, does nothing
2460 COM_METHOD Attach();
2461 COM_METHOD GetID(ULONG32 * pId);
2463 //-----------------------------------------------------------
2464 // ICorDebugAppDomain2 APIs
2465 //-----------------------------------------------------------
2466 COM_METHOD GetArrayOrPointerType(CorElementType elementType,
2468 ICorDebugType * pTypeArg,
2469 ICorDebugType ** ppResultType);
2471 COM_METHOD GetFunctionPointerType(ULONG32 cTypeArgs,
2472 ICorDebugType * rgpTypeArgs[],
2473 ICorDebugType ** ppResultType);
2475 //-----------------------------------------------------------
2476 // ICorDebugAppDomain3 APIs
2477 //-----------------------------------------------------------
2478 COM_METHOD GetCachedWinRTTypesForIIDs(
2481 ICorDebugTypeEnum * * ppTypesEnum);
2483 COM_METHOD GetCachedWinRTTypes(
2484 ICorDebugGuidToTypeEnum * * ppType);
2486 //-----------------------------------------------------------
2487 // ICorDebugAppDomain4
2488 //-----------------------------------------------------------
2489 COM_METHOD GetObjectForCCW(CORDB_ADDRESS ccwPointer, ICorDebugValue **ppManagedObject);
2491 // Get the VMPTR for this appdomain.
2492 VMPTR_AppDomain GetADToken() { return m_vmAppDomain; }
2494 // Given a metadata interface, find the module in this appdomain that matches it.
2495 CordbModule * GetModuleFromMetaDataInterface(IUnknown *pIMetaData);
2497 // Lookup a module from the cache. Create and to the cache if needed.
2498 CordbModule * LookupOrCreateModule(VMPTR_Module vmModuleToken, VMPTR_DomainFile vmDomainFileToken);
2500 // Lookup a module from the cache. Create and to the cache if needed.
2501 CordbModule * LookupOrCreateModule(VMPTR_DomainFile vmDomainFileToken);
2503 // Callback from DAC for module enumeration
2504 static void ModuleEnumerationCallback(VMPTR_DomainFile vmModule, void * pUserData);
2506 // Use DAC to add any modules for this assembly.
2507 void PrepopulateModules();
2509 void InvalidateName() { m_strAppDomainName.Clear(); }
2512 ULONG m_AppDomainId;
2514 CordbAssembly * LookupOrCreateAssembly(VMPTR_DomainAssembly vmDomainAssembly);
2515 CordbAssembly * LookupOrCreateAssembly(VMPTR_Assembly vmAssembly);
2516 void RemoveAssemblyFromCache(VMPTR_DomainAssembly vmDomainAssembly);
2519 CordbSafeHashTable<CordbBreakpoint> m_breakpoints;
2521 // Unique objects that represent the use of some
2522 // basic ELEMENT_TYPE's as type parameters. These
2523 // are shared acrosss the entire process. We could
2524 // go and try to find the classes corresponding to these
2525 // element types but it seems simpler just to keep
2526 // them as special cases.
2527 CordbSafeHashTable<CordbType> m_sharedtypes;
2529 CordbAssembly * CacheAssembly(VMPTR_DomainAssembly vmDomainAssembly);
2530 CordbAssembly * CacheAssembly(VMPTR_Assembly vmAssembly);
2533 // Cache of modules in this appdomain. In the VM, modules live in an assembly.
2534 // This cache lives on the appdomain because we generally want to do appdomain (or process)
2536 // This is indexed by VMPTR_DomainFile, which has appdomain affinity.
2537 // This is populated by code:CordbAppDomain::LookupOrCreateModule (which may be invoked
2538 // anytime the RS gets hold of a VMPTR), and are removed at the unload event.
2539 CordbSafeHashTable<CordbModule> m_modules;
2541 // Cache of assemblies in this appdomain.
2542 // This is indexed by VMPTR_DomainAssembly, which has appdomain affinity.
2543 // This is populated by code:CordbAppDomain::LookupOrCreateAssembly (which may be invoked
2544 // anytime the RS gets hold of a VMPTR), and are removed at the unload event.
2545 CordbSafeHashTable<CordbAssembly> m_assemblies;
2547 static void AssemblyEnumerationCallback(VMPTR_DomainAssembly vmDomainAssembly, void * pThis);
2548 void PrepopulateAssembliesOrThrow();
2550 // Use DAC to refresh our name
2551 HRESULT RefreshName();
2553 StringCopyHolder m_strAppDomainName;
2555 NeuterList m_TypeNeuterList; // List of types owned by this AppDomain.
2557 // List of Sweepable objects owned by this AppDomain.
2558 // This includes some objects taht hold resources in the left-side (mainly
2559 // as CordbHandleValue, see code:CordbHandleValue::Dispose), as well as:
2560 // - Cordb*Value objects that survive across continues and have appdomain affinity.
2561 LeftSideResourceCleanupList m_SweepableNeuterList;
2563 VMPTR_AppDomain m_vmAppDomain;
2565 // The "Long" exit list is for items that don't get neutered until the appdomain exits.
2566 // The "Sweepable" exit list is for items that may be neuterable sooner than AD exit.
2567 // By splitting out the list, we can just try to sweep the "Sweepable" list and we
2568 // don't waste any time sweeping things on the "Long" list that aren't neuterable anyways.
2569 NeuterList * GetLongExitNeuterList() { return &m_TypeNeuterList; }
2570 LeftSideResourceCleanupList * GetSweepableExitNeuterList() { return &m_SweepableNeuterList; }
2572 void AddToTypeList(CordbBase *pObject);
2577 /* ------------------------------------------------------------------------- *
2579 * ------------------------------------------------------------------------- */
2581 class CordbAssembly : public CordbBase, public ICorDebugAssembly, ICorDebugAssembly2
2584 CordbAssembly(CordbAppDomain * pAppDomain,
2585 VMPTR_Assembly vmAssembly,
2586 VMPTR_DomainAssembly vmDomainAssembly);
2587 virtual ~CordbAssembly();
2588 virtual void Neuter();
2590 using CordbBase::GetProcess;
2593 virtual const char * DbgGetName() { return "CordbAssembly"; }
2597 //-----------------------------------------------------------
2599 //-----------------------------------------------------------
2601 ULONG STDMETHODCALLTYPE AddRef()
2603 return (BaseAddRef());
2605 ULONG STDMETHODCALLTYPE Release()
2607 return (BaseRelease());
2609 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2611 //-----------------------------------------------------------
2612 // ICorDebugAssembly
2613 //-----------------------------------------------------------
2616 * GetProcess returns the process containing the assembly
2618 COM_METHOD GetProcess(ICorDebugProcess ** ppProcess);
2620 // Gets the AppDomain containing this assembly
2621 COM_METHOD GetAppDomain(ICorDebugAppDomain ** ppAppDomain);
2624 * EnumerateModules enumerates all modules in the assembly
2626 COM_METHOD EnumerateModules(ICorDebugModuleEnum ** ppModules);
2629 * GetCodeBase returns the code base used to load the assembly
2631 COM_METHOD GetCodeBase(ULONG32 cchName,
2633 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2635 // returns the filename of the assembly, or "<unknown>" for in-memory assemblies
2636 COM_METHOD GetName(ULONG32 cchName,
2638 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2641 //-----------------------------------------------------------
2642 // ICorDebugAssembly2
2643 //-----------------------------------------------------------
2646 * IsFullyTrusted returns a flag indicating whether the security system
2647 * has granted the assembly full trust.
2649 COM_METHOD IsFullyTrusted(BOOL * pbFullyTrusted);
2651 //-----------------------------------------------------------
2652 // internal accessors
2653 //-----------------------------------------------------------
2656 void DbgAssertAssemblyDeleted();
2658 static void DbgAssertAssemblyDeletedCallback(VMPTR_DomainAssembly vmDomainAssembly, void * pUserData);
2661 CordbAppDomain * GetAppDomain() { return m_pAppDomain; }
2663 VMPTR_DomainAssembly GetDomainAssemblyPtr() { return m_vmDomainAssembly; }
2665 VMPTR_Assembly m_vmAssembly;
2666 VMPTR_DomainAssembly m_vmDomainAssembly;
2667 CordbAppDomain * m_pAppDomain;
2669 StringCopyHolder m_strAssemblyFileName;
2670 Optional<BOOL> m_foptIsFullTrust;
2674 //-----------------------------------------------------------------------------
2675 // Describe what to do w/ a win32 debug event
2676 //-----------------------------------------------------------------------------
2682 // Inband events: Dispatch to Cordbg
2683 // safe for stopping the shell and communicating with the runtime
2686 // workaround. Inband event, but NewEvent =false
2687 cInband_NotNewEvent,
2689 // This is a debug event that corresponds with getting to the beginning
2690 // of a first chance hijack.
2691 cFirstChanceHijackStarted,
2693 // This is the debug event that corresponds with getting to the end of
2694 // a hijack. To continue we need to restore an unhijacked context
2695 cInbandHijackComplete,
2697 // This is a debug event which corresponds to re-hiting a previous
2698 // IB event after returning from the hijack. Now we have already dispatched it
2699 // so we know how the user wants it to be continued
2700 // Continue immediately with the previously determined
2701 cInbandExceptionRetrigger,
2703 // This debug event is a breakpoint in unmanaged code that we placed. It will need
2704 // the M2UHandoffHijack to run the in process breakpoint handling code.
2705 cBreakpointRequiringHijack,
2707 // Oob events: Dispatch to Cordbg
2708 // Not safe stopping events. They must be continued immediately.
2711 // CLR internal exception, Continue(not_handled), don't dispatch
2712 // The CLR expects this exception and will deal with it properly.
2715 // Don't dispatch. Continue(DBG_CONTINUE).
2716 // Common for flare.
2720 Type GetType() const { return m_type; };
2723 const char * GetReactionName()
2727 case cInband: return "cInband";
2728 case cInband_NotNewEvent: return "cInband_NotNewEvent";
2729 case cInbandHijackComplete: return "cInbandHijackComplete";
2730 case cInbandExceptionRetrigger: return "cInbandExceptionRetrigger";
2731 case cBreakpointRequiringHijack: return "cBreakpointRequiringHijack";
2732 case cOOB: return "cOOB";
2733 case cCLR: return "cCLR";
2734 case cIgnore: return "cIgnore";
2735 default: return "<unknown>";
2744 Reaction(Type t, int line) : m_type(t) {
2748 LOG((LF_CORDB, LL_EVERYTHING, "Reaction:%s (determined on line: %d)\n", GetReactionName(), line));
2752 void operator=(const Reaction & other)
2754 m_type = other.m_type;
2756 m_line = other.m_line;
2764 // Under a debug build, track the line # for where this came from.
2769 // Macro for creating a Reaction.
2770 #define REACTION(type) Reaction(Reaction::type, __LINE__)
2772 // Different forms of Unmanaged Continue
2773 enum EUMContinueType
2776 cInternalUMContinue,
2780 /* ------------------------------------------------------------------------- *
2782 * ------------------------------------------------------------------------- */
2786 // On debug, we can afford a larger native event queue..
2787 const int DEBUG_EVENTQUEUE_SIZE = 30;
2789 const int DEBUG_EVENTQUEUE_SIZE = 10;
2792 void DeleteIPCEventHelper(DebuggerIPCEvent *pDel);
2795 // Private interface on CordbProcess that ShimProcess needs to emulate V2 functionality.
2796 // The fact that we need private hooks means that V3 is not sufficiently finished to allow building
2797 // a V2 debugger. This interface should shrink over time (and eventually go away) as the functionality gets exposed
2799 // CordbProcess calls back into ShimProcess too, so the public surface of code:ShimProcess plus
2800 // the spots in CordbProcess that call them are additional surface area that may need to addressed
2801 // to make the shim public.
2802 class IProcessShimHooks
2805 // Get the OS Process ID of the target.
2806 virtual DWORD GetPid() = 0;
2808 // Request a synchronization for attach.
2809 // This essentially just sends an AsyncBreak to the left-side. Once the target is
2810 // synchronized, the Shim can use inspection to send all the various fake-attach events.
2812 // Once the shim has a way of requesting a synchronization from out-of-process for an
2813 // arbitrary running target that's not stopped at a managed debug event, we can
2815 virtual void QueueManagedAttachIfNeeded() = 0;
2817 // Hijack a thread at an unhandled exception to allow us to resume executing the target so
2818 // that the helper thread can run and service IPC requests. This is also needed to allow
2819 // func-eval at a 2nd-chance exception
2821 // This will require an architectural change to remove. Either:
2822 // - actions like func-eval / synchronization may call this directly themselves.
2823 // - the CLR's managed Unhandled-exception event is moved out of the native
2824 // unhandled-exception event, thus making native unhandled exceptions uninteresting to ICorDebug.
2825 // - everything is out-of-process, and so the CLR doesn't need to continue after an unhandled
2826 // native exception.
2827 virtual BOOL HijackThreadForUnhandledExceptionIfNeeded(DWORD dwThreadId) = 0;
2829 #ifdef FEATURE_INTEROP_DEBUGGING
2830 // Private hook to do the bulk of the interop-debugging goo. This includes hijacking inband
2831 // events and queueing them so that the helper-thread can run.
2833 // We can remove this once we kill the helper-thread, or after enough functionality is
2834 // out-of-process that the debugger doesn't need the helper thread when stopped at an event.
2835 virtual void HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEvent) = 0;
2836 #endif // FEATURE_INTEROP_DEBUGGING
2838 // Get the modules in the order that they were loaded. This is needed to send the fake-attach events
2839 // for module load in the right order.
2841 // This can be removed once ICorDebug's enumerations are ordered.
2842 virtual void GetModulesInLoadOrder(
2843 ICorDebugAssembly * pAssembly,
2844 RSExtSmartPtr<ICorDebugModule>* pModules,
2845 ULONG countModules) = 0;
2847 // Get the assemblies in the order that they were loaded. This is needed to send the fake-attach events
2848 // for assembly load in the right order.
2850 // This can be removed once ICorDebug's enumerations are ordered.
2851 virtual void GetAssembliesInLoadOrder(
2852 ICorDebugAppDomain * pAppDomain,
2853 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
2854 ULONG countAssemblies) = 0;
2856 // Queue up fake connection events for attach.
2857 // ICorDebug doesn't expose any enumeration for connections, so the shim needs to call into a
2858 // private hook to enumerate them for attach.
2859 virtual void QueueFakeConnectionEvents() = 0;
2861 // This finishes initializing the IPC channel between the LS + RS, which includes duplicating
2862 // some handles and events.
2864 // This can be removed once the IPC channel is completely gone and all communication goes
2865 // soley through the data-target.
2866 virtual void FinishInitializeIPCChannel() = 0;
2868 // Called when stopped at a managed debug event to request a synchronization.
2869 // This can be replaced when we expose synchronization from ICorDebug.
2870 // The fact that the debuggee is at a managed debug event greatly simplifies the request here
2871 // (in contrast to QueueManagedAttachIfNeeded). It means that we can just flip a flag from
2872 // out-of-process, and when the debuggee thread resumes, it can check that flag and do the
2873 // synchronization from in-process.
2874 virtual void RequestSyncAtEvent()= 0;
2876 virtual bool IsThreadSuspendedOrHijacked(ICorDebugThread * pThread) = 0;
2880 // entry for the array of connections in EnumerateConnectionsData
2881 struct EnumerateConnectionsEntry
2884 StringCopyHolder m_pName; // name of the connection
2885 DWORD m_dwID; // ID of the connection
2888 // data structure used in the callback for enumerating connections (code:CordbProcess::QueueFakeConnectionEvents)
2889 struct EnumerateConnectionsData
2892 ~EnumerateConnectionsData()
2894 if (m_pEntryArray != NULL)
2896 delete [] m_pEntryArray;
2897 m_pEntryArray = NULL;
2901 CordbProcess * m_pThis; // the "this" process
2902 EnumerateConnectionsEntry * m_pEntryArray; // an array of connections to be filled in
2903 UINT32 m_uIndex; // the next entry in the array to be filled
2906 // data structure used in the callback for asserting that an appdomain has been deleted
2907 // (code:CordbProcess::DbgAssertAppDomainDeleted)
2908 struct DbgAssertAppDomainDeletedData
2911 CordbProcess * m_pThis;
2912 VMPTR_AppDomain m_vmAppDomainDeleted;
2915 class CordbProcess :
2917 public ICorDebugProcess,
2918 public ICorDebugProcess2,
2919 public ICorDebugProcess3,
2920 public ICorDebugProcess4,
2921 public ICorDebugProcess5,
2922 public ICorDebugProcess7,
2923 public ICorDebugProcess8,
2924 public IDacDbiInterface::IAllocator,
2925 public IDacDbiInterface::IMetaDataLookup,
2926 public IProcessShimHooks
2927 #ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
2928 , public ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly
2931 // Ctor is private. Use OpenVirtualProcess instead.
2932 CordbProcess(ULONG64 clrInstanceId, IUnknown * pDataTarget, HMODULE hDacModule, Cordb * pCordb, DWORD dwProcessID, ShimProcess * pShim);
2936 virtual ~CordbProcess();
2937 virtual void Neuter();
2939 // Neuter left-side resources for all children
2940 void NeuterChildrenLeftSideResources();
2942 // Neuter all of all children, but not the actual process object.
2943 void NeuterChildren();
2946 // The way to instantiate a new CordbProcess object.
2947 // @dbgtodo managed pipeline - this is not fully active in all scenarios yet.
2948 static HRESULT OpenVirtualProcess(ULONG64 clrInstanceId,
2949 IUnknown * pDataTarget,
2953 ShimProcess * pShim,
2954 CordbProcess ** ppProcess);
2956 // Helper function to determine whether this ICorDebug is compatibile with a debugger
2957 // designed for the specified major version
2958 static bool IsCompatibleWith(DWORD clrMajorVersion);
2960 //-----------------------------------------------------------
2962 // -----------------------------------------------------------
2963 IMDInternalImport * LookupMetaData(VMPTR_PEFile vmPEFile, bool &isILMetaDataForNGENImage);
2965 // Helper functions for LookupMetaData implementation
2966 IMDInternalImport * LookupMetaDataFromDebugger(VMPTR_PEFile vmPEFile,
2967 bool &isILMetaDataForNGENImage,
2968 CordbModule * pModule);
2970 IMDInternalImport * LookupMetaDataFromDebuggerForSingleFile(CordbModule * pModule,
2971 LPCWSTR pwszImagePath,
2976 //-----------------------------------------------------------
2977 // IDacDbiInterface::IAllocator
2978 //-----------------------------------------------------------
2980 void * Alloc(SIZE_T lenBytes);
2981 void Free(void * p);
2984 virtual const char * DbgGetName() { return "CordbProcess"; }
2987 //-----------------------------------------------------------
2989 //-----------------------------------------------------------
2991 ULONG STDMETHODCALLTYPE AddRef()
2993 return BaseAddRefEnforceExternal();
2995 ULONG STDMETHODCALLTYPE Release()
2997 return BaseReleaseEnforceExternal();
2999 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
3001 //-----------------------------------------------------------
3002 // ICorDebugController
3003 //-----------------------------------------------------------
3005 COM_METHOD Stop(DWORD dwTimeout);
3006 COM_METHOD Deprecated_Continue();
3007 COM_METHOD IsRunning(BOOL *pbRunning);
3008 COM_METHOD HasQueuedCallbacks(ICorDebugThread *pThread, BOOL *pbQueued);
3009 COM_METHOD EnumerateThreads(ICorDebugThreadEnum **ppThreads);
3010 COM_METHOD SetAllThreadsDebugState(CorDebugThreadState state,
3011 ICorDebugThread *pExceptThisThread);
3012 COM_METHOD Detach();
3013 COM_METHOD Terminate(unsigned int exitCode);
3015 COM_METHOD CanCommitChanges(
3017 ICorDebugEditAndContinueSnapshot *pSnapshots[],
3018 ICorDebugErrorInfoEnum **pError);
3020 COM_METHOD CommitChanges(
3022 ICorDebugEditAndContinueSnapshot *pSnapshots[],
3023 ICorDebugErrorInfoEnum **pError);
3025 COM_METHOD Continue(BOOL fIsOutOfBand);
3026 COM_METHOD ThreadForFiberCookie(DWORD fiberCookie,
3027 ICorDebugThread **ppThread);
3028 COM_METHOD GetHelperThreadID(DWORD *pThreadID);
3030 //-----------------------------------------------------------
3032 //-----------------------------------------------------------
3034 COM_METHOD GetID(DWORD *pdwProcessId);
3035 COM_METHOD GetHandle(HANDLE *phProcessHandle);
3036 COM_METHOD EnableSynchronization(BOOL bEnableSynchronization);
3037 COM_METHOD GetThread(DWORD dwThreadId, ICorDebugThread **ppThread);
3038 COM_METHOD EnumerateBreakpoints(ICorDebugBreakpointEnum **ppBreakpoints);
3039 COM_METHOD EnumerateSteppers(ICorDebugStepperEnum **ppSteppers);
3040 COM_METHOD EnumerateObjects(ICorDebugObjectEnum **ppObjects);
3041 COM_METHOD IsTransitionStub(CORDB_ADDRESS address, BOOL *pbTransitionStub);
3042 COM_METHOD EnumerateModules(ICorDebugModuleEnum **ppModules);
3043 COM_METHOD GetModuleFromMetaDataInterface(IUnknown *pIMetaData,
3044 ICorDebugModule **ppModule);
3045 COM_METHOD SetStopState(DWORD threadID, CorDebugThreadState state);
3046 COM_METHOD IsOSSuspended(DWORD threadID, BOOL *pbSuspended);
3047 COM_METHOD GetThreadContext(DWORD threadID, ULONG32 contextSize,
3049 COM_METHOD SetThreadContext(DWORD threadID, ULONG32 contextSize,
3051 COM_METHOD ReadMemory(CORDB_ADDRESS address, DWORD size, BYTE buffer[],
3053 COM_METHOD WriteMemory(CORDB_ADDRESS address, DWORD size, BYTE buffer[],
3056 COM_METHOD ClearCurrentException(DWORD threadID);
3059 * EnableLogMessages enables/disables sending of log messages to the
3060 * debugger for logging.
3062 COM_METHOD EnableLogMessages(BOOL fOnOff);
3065 * ModifyLogSwitch modifies the specified switch's severity level.
3067 COM_METHOD ModifyLogSwitch(__in_z WCHAR *pLogSwitchName, LONG lLevel);
3069 COM_METHOD EnumerateAppDomains(ICorDebugAppDomainEnum **ppAppDomains);
3070 COM_METHOD GetObject(ICorDebugValue **ppObject);
3072 //-----------------------------------------------------------
3073 // ICorDebugProcess2
3074 //-----------------------------------------------------------
3076 COM_METHOD GetThreadForTaskID(TASKID taskId, ICorDebugThread2 ** ppThread);
3077 COM_METHOD GetVersion(COR_VERSION* pInfo);
3079 COM_METHOD SetUnmanagedBreakpoint(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen);
3080 COM_METHOD ClearUnmanagedBreakpoint(CORDB_ADDRESS address);
3081 COM_METHOD GetCodeAtAddress(CORDB_ADDRESS address, ICorDebugCode ** pCode, ULONG32 * offset);
3083 COM_METHOD SetDesiredNGENCompilerFlags(DWORD pdwFlags);
3084 COM_METHOD GetDesiredNGENCompilerFlags(DWORD *pdwFlags );
3086 COM_METHOD GetReferenceValueFromGCHandle(UINT_PTR handle, ICorDebugReferenceValue **pOutValue);
3088 //-----------------------------------------------------------
3089 // ICorDebugProcess3
3090 //-----------------------------------------------------------
3092 // enables or disables CustomNotifications of a given type
3093 COM_METHOD SetEnableCustomNotification(ICorDebugClass * pClass, BOOL fEnable);
3095 //-----------------------------------------------------------
3096 // ICorDebugProcess4
3097 //-----------------------------------------------------------
3099 const BYTE pRecord[],
3101 CorDebugRecordFormat format,
3104 ICorDebugManagedCallback *pCallback,
3105 DWORD * pContinueStatus);
3107 COM_METHOD ProcessStateChanged(CorDebugStateChange eChange);
3109 //-----------------------------------------------------------
3110 // ICorDebugProcess5
3111 //-----------------------------------------------------------
3112 COM_METHOD GetGCHeapInformation(COR_HEAPINFO *pHeapInfo);
3113 COM_METHOD EnumerateHeap(ICorDebugHeapEnum **ppObjects);
3114 COM_METHOD EnumerateHeapRegions(ICorDebugHeapSegmentEnum **ppRegions);
3115 COM_METHOD GetObject(CORDB_ADDRESS addr, ICorDebugObjectValue **pObject);
3116 COM_METHOD EnableNGENPolicy(CorDebugNGENPolicy ePolicy);
3117 COM_METHOD EnumerateGCReferences(BOOL enumerateWeakReferences, ICorDebugGCReferenceEnum **ppEnum);
3118 COM_METHOD EnumerateHandles(CorGCReferenceType types, ICorDebugGCReferenceEnum **ppEnum);
3119 COM_METHOD GetTypeID(CORDB_ADDRESS obj, COR_TYPEID *pId);
3120 COM_METHOD GetTypeForTypeID(COR_TYPEID id, ICorDebugType **ppType);
3121 COM_METHOD GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout);
3122 COM_METHOD GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout);
3123 COM_METHOD GetTypeFields(COR_TYPEID id, ULONG32 celt, COR_FIELD fields[], ULONG32 *pceltNeeded);
3125 //-----------------------------------------------------------
3126 // ICorDebugProcess7
3127 //-----------------------------------------------------------
3128 COM_METHOD SetWriteableMetadataUpdateMode(WriteableMetadataUpdateMode flags);
3130 //-----------------------------------------------------------
3131 // ICorDebugProcess8
3132 //-----------------------------------------------------------
3133 COM_METHOD EnableExceptionCallbacksOutsideOfMyCode(BOOL enableExceptionsOutsideOfJMC);
3135 #ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
3136 // ---------------------------------------------------------------
3137 // ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly
3138 // ---------------------------------------------------------------
3140 COM_METHOD InvokePauseCallback();
3141 COM_METHOD InvokeResumeCallback();
3145 //-----------------------------------------------------------
3146 // Methods not exposed via a COM interface.
3147 //-----------------------------------------------------------
3149 HRESULT ContinueInternal(BOOL fIsOutOfBand);
3150 HRESULT StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainToken);
3152 // Sets an unmanaged breakpoint at the target address
3153 HRESULT SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen);
3155 // Allocate a buffer within the target and return the range. Throws on error.
3156 TargetBuffer GetRemoteBuffer(ULONG cbBuffer); // throws
3158 // Same as above except also copy-in the contents of a RS buffer using WriteProcessMemory
3159 HRESULT GetAndWriteRemoteBuffer(CordbAppDomain *pDomain, unsigned int bufferSize, const void *bufferFrom, void **ppBuffer);
3162 * This will release a previously allocated left side buffer.
3163 * Often they are deallocated by the LS itself.
3165 HRESULT ReleaseRemoteBuffer(void **ppBuffer);
3168 void TargetConsistencyCheck(bool fExpression);
3170 // Activate interop-debugging, after the process has initially been Init()
3171 void EnableInteropDebugging();
3174 void DeleteQueuedEvents();
3175 void CleanupHalfBakedLeftSide();
3176 void Terminating(BOOL fDetach);
3178 CordbThread * TryLookupThread(VMPTR_Thread vmThread);
3179 CordbThread * TryLookupOrCreateThreadByVolatileOSId(DWORD dwThreadId);
3180 CordbThread * TryLookupThreadByVolatileOSId(DWORD dwThreadId);
3181 CordbThread * LookupOrCreateThread(VMPTR_Thread vmThread);
3183 void QueueManagedAttachIfNeeded();
3184 void QueueManagedAttachIfNeededWorker();
3185 HRESULT QueueManagedAttach();
3189 // Flush for when the process is running.
3190 void FlushProcessRunning();
3195 BOOL HijackThreadForUnhandledExceptionIfNeeded(DWORD dwThreadId);
3197 // Filter a CLR notification (subset of exceptions).
3198 void FilterClrNotification(
3199 DebuggerIPCEvent * pManagedEvent,
3200 RSLockHolder * pLockHolder,
3201 ICorDebugManagedCallback * pCallback);
3203 // Wrapper to invoke IClrDataTarget4::ContinueStatusChanged
3204 void ContinueStatusChanged(DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
3207 // Request a synchronization to occur after a debug event is dispatched.
3208 void RequestSyncAtEvent();
3211 // Basic managed event plumbing
3214 // This is called on the first IPC event from the debuggee. It initializes state.
3215 void FinishInitializeIPCChannel();
3216 void FinishInitializeIPCChannelWorker();
3218 // This is called on each IPC event from the debuggee.
3219 void HandleRCEvent(DebuggerIPCEvent * pManagedEvent, RSLockHolder * pLockHolder, ICorDebugManagedCallback * pCallback);
3221 // Queue the RC event.
3222 void QueueRCEvent(DebuggerIPCEvent * pManagedEvent);
3224 // This marshals a managed debug event from the
3225 void MarshalManagedEvent(DebuggerIPCEvent * pManagedEvent);
3227 // This copies a managed debug event from the IPC block and to pManagedEvent.
3228 // The event still needs to be marshalled.
3229 void CopyRCEventFromIPCBlock(DebuggerIPCEvent * pManagedEvent);
3231 // This copies a managed debug event out of the Native-Debug event envelope.
3232 // The event still needs to be marshalled.
3233 bool CopyManagedEventFromTarget(const EXCEPTION_RECORD * pRecord, DebuggerIPCEvent * pLocalManagedEvent);
3235 // Helper for Filter() to verify parameters and return a type-safe exception record.
3236 const EXCEPTION_RECORD * ValidateExceptionRecord(
3237 const BYTE pRawRecord[],
3239 CorDebugRecordFormat format);
3241 // Helper to read a structure from the target.
3242 template<typename T>
3243 HRESULT SafeReadStruct(CORDB_ADDRESS pRemotePtr, T* pLocalBuffer);
3245 // Helper to write a structure into the target.
3246 template<typename T>
3247 HRESULT SafeWriteStruct(CORDB_ADDRESS pRemotePtr, const T* pLocalBuffer);
3249 // Reads a buffer from the target
3250 HRESULT SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer, BOOL throwOnError = TRUE);
3252 // Writes a buffer to the target
3253 void SafeWriteBuffer(TargetBuffer tb, const BYTE * pLocalBuffer);
3255 #if defined(FEATURE_INTEROP_DEBUGGING)
3256 void DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle);
3257 #endif // FEATURE_INTEROP_DEBUGGING
3259 bool IsThreadSuspendedOrHijacked(ICorDebugThread * pICorDebugThread);
3261 // Helper to get PID internally.
3264 HRESULT GetRuntimeOffsets();
3266 // Are we blocked waiting fo ran OOB event to be continue?
3267 bool IsWaitingForOOBEvent()
3269 #ifdef FEATURE_INTEROP_DEBUGGING
3270 return m_outOfBandEventQueue != NULL;
3272 // If no interop, then we're never waiting for an OOB event.
3278 // Shim callbacks to simulate fake attach events.
3282 // Callback for Shim to get the assemblies in load order
3283 void GetAssembliesInLoadOrder(
3284 ICorDebugAppDomain * pAppDomain,
3285 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
3286 ULONG countAssemblies);
3288 // Callback for Shim to get the modules in load order
3289 void GetModulesInLoadOrder(
3290 ICorDebugAssembly * pAssembly,
3291 RSExtSmartPtr<ICorDebugModule>* pModules,
3292 ULONG countModules);
3294 // Functions to queue fake Connection events on attach.
3295 static void CountConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData);
3296 static void EnumerateConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData);
3297 void QueueFakeConnectionEvents();
3301 void DispatchRCEvent();
3303 // Dispatch a single event via the callbacks.
3304 void RawDispatchEvent(
3305 DebuggerIPCEvent * pEvent,
3306 RSLockHolder * pLockHolder,
3307 ICorDebugManagedCallback * pCallback1,
3308 ICorDebugManagedCallback2 * pCallback2,
3309 ICorDebugManagedCallback3 * pCallback3);
3311 void MarkAllThreadsDirty();
3313 bool CheckIfLSExited();
3317 // Lock Hierarchy - shouldn't have List lock when taking/release the process lock.
3319 m_processMutex.Lock();
3320 LOG((LF_CORDB, LL_EVERYTHING, "P::Lock enter, this=0x%p\n", this));
3325 // Lock Hierarchy - shouldn't have List lock when taking/releasing the process lock.
3327 LOG((LF_CORDB, LL_EVERYTHING, "P::Lock leave, this=0x%p\n", this));
3328 m_processMutex.Unlock();
3332 bool ThreadHoldsProcessLock()
3334 return m_processMutex.HasLock();
3338 // Expose the process lock.
3339 // This is the main lock in V3.
3340 RSLock * GetProcessLock()
3342 return &m_processMutex;
3346 // @dbgtodo synchronization - the SG lock goes away in V3.
3347 // Expose the stop-go lock b/c varios Cordb objects in our process tree may need to take it.
3348 RSLock * GetStopGoLock()
3350 return &m_StopGoLock;
3354 void UnrecoverableError(HRESULT errorHR,
3355 unsigned int errorCode,
3356 const char *errorFile,
3357 unsigned int errorLine);
3358 HRESULT CheckForUnrecoverableError();
3359 void VerifyControlBlock();
3361 // The implementation of EnumerateThreads without the public API error checks
3362 VOID InternalEnumerateThreads(RSInitHolder<CordbHashTableEnum> * ppThreads);
3364 //-----------------------------------------------------------
3365 // Convenience routines
3366 //-----------------------------------------------------------
3368 // Is it safe to send events to the LS?
3369 bool IsSafeToSendEvents() { return !m_unrecoverableError && !m_terminated && !m_detached; }
3371 bool IsWin32EventThread();
3373 void HandleSyncCompleteRecieved();
3375 // Send a truly asynchronous IPC event.
3376 void SendAsyncIPCEvent(DebuggerIPCEventType t);
3378 HRESULT SendIPCEvent(DebuggerIPCEvent *event, SIZE_T eventSize)
3380 // @dbgtodo - eventually remove this when all IPC events are gone.
3381 // In V3 paths, we can't send IPC events.
3382 if (GetShim() == NULL)
3384 STRESS_LOG1(LF_CORDB, LL_INFO1000, "!! Can't send IPC event in V3. %s", IPCENames::GetName(event->type));
3387 _ASSERTE(m_cordb != NULL);
3388 return (m_cordb->SendIPCEvent(this, event, eventSize));
3391 void InitAsyncIPCEvent(DebuggerIPCEvent *ipce,
3392 DebuggerIPCEventType type,
3393 VMPTR_AppDomain vmAppDomain)
3395 // Async events only allowed for the following:
3396 _ASSERTE(type == DB_IPCE_ATTACHING);
3398 InitIPCEvent(ipce, type, false, vmAppDomain);
3399 ipce->asyncSend = true;
3402 void InitIPCEvent(DebuggerIPCEvent *ipce,
3403 DebuggerIPCEventType type,
3405 VMPTR_AppDomain vmAppDomain
3408 // zero out the event in case we try and use any uninitialized fields
3409 memset( ipce, 0, sizeof(DebuggerIPCEvent) );
3411 _ASSERTE((!vmAppDomain.IsNull()) ||
3412 type == DB_IPCE_GET_GCHANDLE_INFO ||
3413 type == DB_IPCE_ENABLE_LOG_MESSAGES ||
3414 type == DB_IPCE_MODIFY_LOGSWITCH ||
3415 type == DB_IPCE_ASYNC_BREAK ||
3416 type == DB_IPCE_CONTINUE ||
3417 type == DB_IPCE_GET_BUFFER ||
3418 type == DB_IPCE_RELEASE_BUFFER ||
3419 type == DB_IPCE_IS_TRANSITION_STUB ||
3420 type == DB_IPCE_ATTACHING ||
3421 type == DB_IPCE_APPLY_CHANGES ||
3422 type == DB_IPCE_CONTROL_C_EVENT_RESULT ||
3423 type == DB_IPCE_SET_REFERENCE ||
3424 type == DB_IPCE_SET_ALL_DEBUG_STATE ||
3425 type == DB_IPCE_GET_THREAD_FOR_TASKID ||
3426 type == DB_IPCE_DETACH_FROM_PROCESS ||
3427 type == DB_IPCE_INTERCEPT_EXCEPTION ||
3428 type == DB_IPCE_GET_NGEN_COMPILER_FLAGS ||
3429 type == DB_IPCE_SET_NGEN_COMPILER_FLAGS ||
3430 type == DB_IPCE_SET_VALUE_CLASS);
3434 ipce->processId = 0;
3435 ipce->vmAppDomain = vmAppDomain;
3436 ipce->vmThread = VMPTR_Thread::NullPtr();
3437 ipce->replyRequired = twoWay;
3438 ipce->asyncSend = false;
3442 // Looks up a previously constructed CordbClass instance without creating. May return NULL if the
3443 // CordbClass instance doesn't exist.
3444 CordbClass * LookupClass(ICorDebugAppDomain * pAppDomain, VMPTR_DomainFile vmDomainFile, mdTypeDef classToken);
3446 CordbModule * LookupOrCreateModule(VMPTR_DomainFile vmDomainFile);
3448 #ifdef FEATURE_INTEROP_DEBUGGING
3449 CordbUnmanagedThread *GetUnmanagedThread(DWORD dwThreadId)
3451 _ASSERTE(ThreadHoldsProcessLock());
3452 return m_unmanagedThreads.GetBase(dwThreadId);
3454 #endif // FEATURE_INTEROP_DEBUGGING
3457 * This will cleanup the patch table, releasing memory,etc.
3459 void ClearPatchTable();
3462 * This will grab the patch table from the left side & go through
3463 * it to gather info needed for faster access. If address,size,buffer
3464 * are passed in, while going through the table we'll undo patches
3465 * in buffer at the same time
3467 HRESULT RefreshPatchTable(CORDB_ADDRESS address = NULL, SIZE_T size = NULL, BYTE buffer[] = NULL);
3469 // Find if a patch exists at a given address.
3470 HRESULT FindPatchByAddress(CORDB_ADDRESS address, bool *patchFound, bool *patchIsUnmanaged);
3479 * Once we've called RefreshPatchTable to get the patch table,
3480 * this routine will iterate through the patches & either apply
3481 * or unapply the patches to buffer. AB_READ => Replaces patches
3482 * in buffer with the original opcode, AB_WRTE => replace opcode
3483 * with breakpoint instruction, caller is responsible for
3484 * updating the patchtable back to the left side.
3486 * <TODO>@todo Perf Instead of a copy, undo the changes
3487 * Since the 'buffer' arg is an [in] param, we're not supposed to
3488 * change it. If we do, we'll allocate & copy it to bufferCopy
3489 * (we'll also set *pbUpdatePatchTable to true), otherwise we
3490 * don't manipuldate bufferCopy (so passing a NULL in for
3491 * reading is fine).</TODO>
3493 HRESULT AdjustBuffer(CORDB_ADDRESS address,
3498 BOOL *pbUpdatePatchTable = NULL);
3501 * AdjustBuffer, above, doesn't actually update the local patch table
3502 * if asked to do a write. It stores the changes alongside the table,
3503 * and this will cause the changes to be written to the table (for
3504 * a range of left-side addresses
3506 void CommitBufferAdjustments(CORDB_ADDRESS start,
3510 * Clear the stored changes, or they'll sit there until we
3511 * accidentally commit them
3513 void ClearBufferAdjustments();
3518 //-----------------------------------------------------------
3519 // Accessors for key synchronization fields.
3520 //-----------------------------------------------------------
3522 // If CAD is NULL, returns true if all appdomains (ie, the entire process)
3523 // is synchronized. Otherwise, returns true if the specified appdomain is
3525 bool GetSynchronized();
3526 void SetSynchronized(bool fSynch);
3528 void IncStopCount();
3529 void DecStopCount();
3531 // Gets the exact stop count. You need the Proecss lock for this.
3534 // Just gets whether we're stopped or not (m_stopped > 0).
3535 // You only need the StopGo lock for this.
3536 // This is biases towards returning false.
3539 bool GetSyncCompleteRecv();
3540 void SetSyncCompleteRecv(bool fSyncRecv);
3543 // Cordbg may not always continue during a callback; but we really shouldn't do meaningful
3544 // work after a callback has returned yet before they've called continue. Thus we may need
3545 // to remember some state at the time of dispatch so that we do stuff at continue.
3546 // Only example here is neutering... we'd like to Neuter an object X after the ExitX callback,
3547 // but we can't neuter it until Continue. So remember X when we dispatch, and neuter this at continue.
3548 // Use a smart ptr to keep it alive until we neuter it.
3550 // Add objects to various neuter lists.
3551 // NeuterOnContinue is for all objects that can be neutered once we continue.
3552 // NeuterOnExit is for all objects that can survive continues (but are neutered on process shutdown).
3553 // If an object's external ref count goes to 0, it gets promoted to the NeuterOnContinue list.
3554 void AddToNeuterOnExitList(CordbBase *pObject);
3555 void AddToNeuterOnContinueList(CordbBase *pObject);
3557 NeuterList * GetContinueNeuterList() { return &m_ContinueNeuterList; }
3558 NeuterList * GetExitNeuterList() { return &m_ExitNeuterList; }
3560 void AddToLeftSideResourceCleanupList(CordbBase * pObject);
3562 // Routines to read and write thread context records between the processes safely.
3563 HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, DT_CONTEXT * pCtx);
3564 HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, const DT_CONTEXT * pCtx);
3566 #ifdef FEATURE_INTEROP_DEBUGGING
3567 // Record a win32 event for debugging purposes.
3568 void DebugRecordWin32Event(const DEBUG_EVENT * pEvent, CordbUnmanagedThread * pUThread);
3569 #endif // FEATURE_INTEROP_DEBUGGING
3571 //-----------------------------------------------------------
3573 //-----------------------------------------------------------
3575 // Get the DAC interface.
3576 IDacDbiInterface * GetDAC();
3578 // Get the data-target, which provides access to the debuggee.
3579 ICorDebugDataTarget * GetDataTarget();
3581 BOOL IsDacInitialized();
3583 void ForceDacFlush();
3586 #ifdef FEATURE_INTEROP_DEBUGGING
3587 // Deal with native debug events for the interop-debugging scenario.
3588 void HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEvent);
3590 void ResumeHijackedThreads();
3592 //@todo - We should try to make these all private
3593 CordbUnmanagedThread *HandleUnmanagedCreateThread(DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase);
3595 HRESULT ContinueOOB();
3596 void QueueUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3597 void DequeueUnmanagedEvent(CordbUnmanagedThread *pUThread);
3598 void QueueOOBUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3599 void DequeueOOBUnmanagedEvent(CordbUnmanagedThread *pUThread);
3600 void DispatchUnmanagedInBandEvent();
3601 void DispatchUnmanagedOOBEvent();
3602 bool ExceptionIsFlare(DWORD exceptionCode, const void *exceptionAddress);
3604 bool IsSpecialStackOverflowCase(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3606 HRESULT SuspendUnmanagedThreads();
3607 HRESULT ResumeUnmanagedThreads();
3609 HRESULT HijackIBEvent(CordbUnmanagedEvent * pUnmanagedEvent);
3611 BOOL HasUndispatchedNativeEvents();
3612 BOOL HasUserUncontinuedNativeEvents();
3613 #endif // FEATURE_INTEROP_DEBUGGING
3615 HRESULT StartSyncFromWin32Stop(BOOL * pfAsyncBreakSent);
3618 // For interop attach, we first do native, and then once Cordbg continues from
3619 // the loader-bp, we kick off the managed attach. This field remembers that
3620 // whether we need the managed attach.
3621 // @dbgtodo managed pipeline - hoist to shim.
3622 bool m_fDoDelayedManagedAttached;
3626 // Table of CordbEval objects that we've sent over to the LS.
3627 // This is synced via the process lock.
3628 RsPtrTable<CordbEval> m_EvalTable;
3630 void PrepopulateThreadsOrThrow();
3632 // Lookup or create an appdomain.
3633 CordbAppDomain * LookupOrCreateAppDomain(VMPTR_AppDomain vmAppDomain);
3635 // Get the shared app domain.
3636 CordbAppDomain * GetSharedAppDomain();
3638 // Get metadata dispenser.
3639 IMetaDataDispenserEx * GetDispenser();
3641 // Sets a bitfield reflecting the managed debugging state at the time of
3643 HRESULT GetAttachStateFlags(CLR_DEBUGGING_PROCESS_FLAGS *pFlags);
3645 HRESULT GetTypeForObject(CORDB_ADDRESS obj, CordbType **ppType, CordbAppDomain **pAppDomain = NULL);
3647 WriteableMetadataUpdateMode GetWriteableMetadataUpdateMode() { return m_writableMetadataUpdateMode; }
3651 // Assert that vmAppDomainDeleted doesn't show up in dac enumerations
3652 void DbgAssertAppDomainDeleted(VMPTR_AppDomain vmAppDomainDeleted);
3654 // Callback helper for DbgAssertAppDomainDeleted.
3655 static void DbgAssertAppDomainDeletedCallback(VMPTR_AppDomain vmAppDomain, void * pUserData);
3658 static void ThreadEnumerationCallback(VMPTR_Thread vmThread, void * pUserData);
3661 // Callback for AppDomain enumeration
3662 static void AppDomainEnumerationCallback(VMPTR_AppDomain vmAppDomain, void * pUserData);
3664 // Helper to create a new CordbAppDomain around the vmptr and cache it
3665 CordbAppDomain * CacheAppDomain(VMPTR_AppDomain vmAppDomain);
3667 // Helper to traverse Appdomains in target and build up our cache.
3668 void PrepopulateAppDomainsOrThrow();
3671 void ProcessFirstLogMessage (DebuggerIPCEvent *event);
3672 void ProcessContinuedLogMessage (DebuggerIPCEvent *event);
3674 void CloseIPCHandles();
3675 void UpdateThreadsForAdUnload( CordbAppDomain* pAppDomain );
3677 #ifdef FEATURE_INTEROP_DEBUGGING
3678 // Each win32 debug event needs to be triaged to get a Reaction.
3679 Reaction TriageBreakpoint(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3680 Reaction TriageSyncComplete();
3681 Reaction Triage1stChanceNonSpecial(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3682 Reaction TriageExcep1stChanceAndInit(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3683 Reaction TriageExcep2ndChanceAndInit(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3684 Reaction TriageWin32DebugEvent(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3685 #endif // FEATURE_INTEROP_DEBUGGING
3687 //-----------------------------------------------------------
3689 //-----------------------------------------------------------
3692 RSSmartPtr<Cordb> m_cordb;
3695 // OS process handle to live process.
3696 // @dbgtodo - , Move this into the Shim. This should only be needed in the live-process
3697 // case. Get rid of this since it breaks the data-target abstraction.
3698 // For Mac debugging, this handle is of course not the real process handle. This is just a handle to
3699 // wait on for process termination.
3703 // Wrapper to get the OS process handle. This is unsafe because it breaks the data-target abstraction.
3704 // The only things that need this should be calls to DuplicateHandle, and some shimming work.
3705 HANDLE UnsafeGetProcessHandle()
3710 // Set when code:CordbProcess::Detach is called.
3711 // Public APIs can check this and return CORDBG_E_PROCESS_DETACHED.
3712 // @dbgtodo managed pipeline - really could merge this with neuter.
3715 // True if we code:CordbProcess::Stop is called before the managed CreateProcess event.
3716 // In this case, m_initialized is false, and we can't send an AsyncBreak event to the LS.
3717 // (since the LS isn't going to send a SyncComplete event back since the CLR isn't loaded/ready).
3718 // @dbgtodo managed pipeline - move into shim, along with Stop/Continue.
3719 bool m_uninitializedStop;
3722 // m_exiting is true if we know the LS is starting to exit (if the
3723 // RS is telling the LS to exit) or if we know the LS has already exited.
3727 // m_terminated can only be set to true if we know 100% the LS has exited (ie, somebody
3728 // waited on the LS process handle).
3731 bool m_unrecoverableError;
3733 bool m_specialDeferment;
3734 bool m_helperThreadDead; // flag used for interop
3736 // This tracks if the loader breakpoint has been received during interop-debugging.
3737 // The Loader Breakpoint is an breakpoint event raised by the OS once the debugger is attached.
3738 // It comes in both Attach and Launch scenarios.
3739 // This is also used in fake-native debugging scenarios.
3740 bool m_loaderBPReceived;
3745 // MetaData dispenser.
3746 RSExtSmartPtr<IMetaDataDispenserEx> m_pMetaDispenser;
3749 // Count of the number of outstanding CordbEvals in the process.
3751 LONG m_cOutstandingEvals;
3753 // Number of oustanding code:CordbHandleValue objects containing
3754 // Left-side resources. This can be used to tell if ICorDebug needs to
3755 // cleanup gc handles.
3756 LONG m_cOutstandingHandles;
3758 // Pointer to the CordbModule instance that can currently change the Jit flags.
3759 // There can be at most one of these. It will represent a module that has just been loaded, before the
3760 // Continue is sent. See code:CordbProcess::RawDispatchEvent and code:CordbProcess::ContinueInternal.
3761 CordbModule * m_pModuleThatCanChangeJitFlags;
3764 LONG OutstandingEvalCount()
3766 return m_cOutstandingEvals;
3769 void IncrementOutstandingEvalCount()
3771 InterlockedIncrement(&m_cOutstandingEvals);
3774 void DecrementOutstandingEvalCount()
3776 InterlockedDecrement(&m_cOutstandingEvals);
3779 LONG OutstandingHandles();
3780 void IncrementOutstandingHandles();
3781 void DecrementOutstandingHandles();
3784 // Is it OK to detach at this time
3786 HRESULT IsReadyForDetach();
3790 // This is a target pointer that uniquely identifies the runtime in the target.
3791 // This lets ICD discriminate between multiple CLRs within a single process.
3792 // On windows, this is the base-address of mscorwks.dll in the target.
3793 // If this is 0, then we have V2 semantics where there was only 1 CLR in the target.
3794 // In that case, we can lazily initialize it in code:CordbProcess::CopyManagedEventFromTarget.
3795 // This is just used for backwards compat.
3796 CORDB_ADDRESS m_clrInstanceId;
3798 // List of things that get neutered on process exit and Continue respectively.
3799 NeuterList m_ExitNeuterList;
3800 NeuterList m_ContinueNeuterList;
3802 // List of objects that hold resources into the left-side.
3803 // This is currently for funceval, which cleans up resources in code:CordbEval::SendCleanup.
3804 // @dbgtodo - , (func-eval feature crew): we can get rid of this
3805 // list if we make func-eval not hold resources after it's complete.
3806 LeftSideResourceCleanupList m_LeftSideResourceCleanupList;
3808 // m_stopCount, m_synchronized, & m_syncCompleteReceived are key fields describing
3809 // the processes' sync status.
3812 // m_synchronized is the Debugger's view of SyncStatus. It will go high & low for each
3813 // callback. Continue() will set this to false.
3814 // This flag is true roughly from the time that we've dispatched a managed callback
3815 // until the time that it's continued.
3816 bool m_synchronized;
3818 // m_syncCompleteReceived tells us if the runtime is _actually_ sychronized. It goes
3819 // high once we get a SyncComplete, and it goes low once we actually send the continue.
3820 // This is always set by the thread that receives the sync-complete. In interop, that's the w32et.
3821 // Thus this is the most accurate indication of wether the Debuggee is _actually_ synchronized or not.
3822 bool m_syncCompleteReceived;
3825 // Back pointer to Shim process. This is used for hooks back into the shim.
3826 // If this is Non-null, then we're emulating the V2 case. If this is NULL, then it's the real V3 pipeline.
3827 RSExtSmartPtr<ShimProcess> m_pShim;
3829 CordbSafeHashTable<CordbThread> m_userThreads;
3832 ShimProcess* GetShim();
3837 void BuildThreadEnum(CordbBase * pOwnerObj, NeuterList * pOwnerList, RSInitHolder<CordbHashTableEnum> * pHolder);
3839 #ifdef FEATURE_INTEROP_DEBUGGING
3840 // List of unmanaged threads. This is only populated for interop-debugging.
3841 CordbSafeHashTable<CordbUnmanagedThread> m_unmanagedThreads;
3842 #endif // FEATURE_INTEROP_DEBUGGING
3844 CordbSafeHashTable<CordbAppDomain> m_appDomains;
3846 CordbAppDomain * m_sharedAppDomain;
3848 // Since a stepper can begin in one appdomain, and complete in another,
3849 // we put the hashtable here, rather than on specific appdomains.
3850 CordbSafeHashTable<CordbStepper> m_steppers;
3852 // Used to figure out if we have to refresh any reference objects
3853 // on the left side. Gets incremented each time a continue is called, or
3854 // global debugee state is modified in some other way.
3855 UINT m_continueCounter;
3857 // Used to track whether the DAC cache has been flushed.
3858 // We use this information to determine whether CordbStackWalk instances need to
3860 UINT m_flushCounter;
3862 // The DCB is essentially a buffer area used to temporarily hold information read from the debugger
3863 // control block residing on the LS helper thread. We make no assumptions about the validity of this
3864 // information over time, so before using a value from it on the RS, we will always update this buffer
3865 // with a call to UpdateRightSideDCB. This uses a ReadProcessMemory to get the current information from
3867 DebuggerIPCControlBlock * GetDCB() {return ((m_pEventChannel == NULL) ? NULL : m_pEventChannel->GetDCB());}
3870 DebuggerIPCRuntimeOffsets m_runtimeOffsets;
3871 HANDLE m_leftSideEventAvailable;
3872 HANDLE m_leftSideEventRead;
3873 #if defined(FEATURE_INTEROP_DEBUGGING)
3874 HANDLE m_leftSideUnmanagedWaitEvent;
3875 #endif // FEATURE_INTEROP_DEBUGGING
3878 // This becomes true when the RS receives its first managed event.
3879 // This goes false in shutdown cases.
3880 // If this is true, we can assume:
3881 // - the CLR is loaded.
3882 // - the IPC block is opened and initialized.
3883 // - DAC is initialized (see code:CordbProcess::IsDacInitialized)
3885 // If this is false, we can assume:
3886 // - the CLR may not be loaded into the target process.
3887 // - We can't send IPC events to the LS (because we can't expect a response)
3889 // Many APIs can check this bit and return CORDBG_E_NOTREADY if it's false.
3893 void * m_pDBGLastIPCEventType;
3896 bool m_stopRequested;
3897 HANDLE m_stopWaitEvent;
3898 RSLock m_processMutex;
3900 #ifdef FEATURE_INTEROP_DEBUGGING
3901 // The number of threads which are IsFirstChanceHijacked
3902 DWORD m_cFirstChanceHijackedThreads;
3904 CordbUnmanagedEvent *m_unmanagedEventQueue;
3905 CordbUnmanagedEvent *m_lastQueuedUnmanagedEvent;
3906 CordbUnmanagedEvent *m_lastQueuedOOBEvent;
3907 CordbUnmanagedEvent *m_outOfBandEventQueue;
3909 CordbUnmanagedEvent *m_lastDispatchedIBEvent;
3910 bool m_dispatchingUnmanagedEvent;
3911 bool m_dispatchingOOBEvent;
3912 bool m_doRealContinueAfterOOBBlock;
3916 PS_WIN32_STOPPED = 0x0001,
3917 PS_HIJACKS_IN_PLACE = 0x0002,
3918 PS_SOME_THREADS_SUSPENDED = 0x0004,
3919 PS_WIN32_ATTACHED = 0x0008,
3920 PS_WIN32_OUTOFBAND_STOPPED = 0x0010,
3923 unsigned int m_state;
3924 #endif // FEATURE_INTEROP_DEBUGGING
3926 // True if we're interop-debugging, else false.
3927 bool IsInteropDebugging();
3929 DWORD m_helperThreadId; // helper thread ID calculated from sniffing from UM thread-create events.
3931 // Is the given thread id a helper thread (real or worker?)
3932 bool IsHelperThreadWorked(DWORD tid);
3935 // We cache the LS patch table on the RS.
3938 // The array of entries. (The patchtable is a hash implemented as a single-array)
3939 // This array includes empty entries.
3940 // There is an auxillary bucket structure used to map hash codes to array indices.
3941 // We traverse the array, and we recognize an empty slot
3942 // if DebuggerControllerPatch::opcode == 0.
3943 // If we haven't gotten the table, then m_pPatchTable is NULL
3944 BYTE* m_pPatchTable;
3946 // The number of entries (both used & unused) in m_pPatchTable.
3949 // so we know where to write the changes patchtable back to
3950 // This has m_cPatch elements.
3953 // Cached value of iNext entries such that:
3954 // m_rgNextPatch[i] = ((DebuggerControllerPatch*)m_pPatchTable)[i]->iNext;
3955 // where 0 <= i < m_cPatch
3956 // This provides a linked list (via indices) to traverse the used entries of m_pPatchTable.
3957 // This has m_cPatch elements.
3958 ULONG *m_rgNextPatch;
3960 // This has m_cPatch elements.
3961 PRD_TYPE *m_rgUncommitedOpcode;
3963 // CORDB_ADDRESS's are UINT_PTR's (64 bit under _WIN64, 32 bit otherwise)
3964 #if defined(DBG_TARGET_WIN64)
3965 #define MAX_ADDRESS (_UI64_MAX)
3967 #define MAX_ADDRESS (ULONG_MAX)
3969 #define MIN_ADDRESS (0x0)
3970 CORDB_ADDRESS m_minPatchAddr; //smallest patch in table
3971 CORDB_ADDRESS m_maxPatchAddr;
3973 // <TODO>@todo port : if slots of CHashTable change, so should these</TODO>
3974 #define DPT_TERMINATING_INDEX (UINT32_MAX)
3975 // Index into m_pPatchTable of the first patch (first used entry).
3976 ULONG m_iFirstPatch;
3978 // Initializes the DAC
3981 // copy new data from LS DCB to RS buffer
3982 void UpdateRightSideDCB();
3984 // copy new data from RS DCB buffer to LS DCB
3985 void UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size);
3987 // allocate and initialize the RS DCB buffer
3988 void GetEventBlock(BOOL * pfBlockExists);
3990 IEventChannel * GetEventChannel();
3992 bool SupportsVersion(CorDebugInterfaceVersion featureVersion);
3994 void StartEventDispatch(DebuggerIPCEventType event);
3995 void FinishEventDispatch();
3996 bool AreDispatchingEvent();
3998 HANDLE GetHelperThreadHandle() { return m_hHelperThread; }
4000 CordbAppDomain* GetDefaultAppDomain() { return m_pDefaultAppDomain; }
4002 #ifdef FEATURE_INTEROP_DEBUGGING
4003 // Lookup if there's a native BP at the given address. Return NULL not found.
4004 NativePatch * GetNativePatch(const void * pAddress);
4005 #endif // FEATURE_INTEROP_DEBUGGING
4007 bool IsBreakOpcodeAtAddress(const void * address);
4011 // handle to helper thread. Used for managed debugging.
4012 // Initialized only after we get the tid from the DCB.
4013 HANDLE m_hHelperThread;
4015 DebuggerIPCEventType m_dispatchedEvent; // what event are we currently dispatching?
4017 RSLock m_StopGoLock;
4019 // Each process has exactly one Default AppDomain
4020 // @dbgtodo appdomain : We should try and simplify things by removing this.
4021 // At the moment it's necessary for CordbProcess::UpdateThreadsForAdUnload.
4022 CordbAppDomain* m_pDefaultAppDomain; // owned by m_appDomains
4024 #ifdef FEATURE_INTEROP_DEBUGGING
4026 CordbUnmanagedThread * GetUnmanagedThreadFromEvent(const DEBUG_EVENT * pEvent);
4027 #endif // FEATURE_INTEROP_DEBUGGING
4029 // Ensure we have a CLR Instance ID to debug
4030 HRESULT EnsureClrInstanceIdSet();
4032 #ifdef FEATURE_INTEROP_DEBUGGING
4033 // // The full debug event is too large, so we just remember the important stuff.
4034 struct MiniDebugEvent
4036 BYTE code; // event code from the debug event
4037 CordbUnmanagedThread * pUThread; // unmanaged thread this was on.
4038 // @todo - we should have some misc data.
4042 void * pAddress; // address of an exception
4046 void * pBaseAddress; // for module load & unload
4051 // Group fields that are just used for debug support here.
4052 // Some are included even in retail builds to help debug retail failures.
4055 // For debugging, we keep a rolling queue of the last N Win32 debug events.
4056 MiniDebugEvent m_DebugEventQueue[DEBUG_EVENTQUEUE_SIZE];
4057 int m_DebugEventQueueIdx;
4058 int m_TotalNativeEvents;
4060 // Breakdown of different types of native events
4066 CUnorderedArray<NativePatch, 10> m_NativePatchList;
4067 #endif // FEATURE_INTEROP_DEBUGGING
4073 // Try to initalize DAC, may fail
4074 BOOL TryInitializeDac();
4076 // Expect DAC initialize to succeed.
4077 void InitializeDac();
4080 void CreateDacDbiInterface();
4086 HModuleHolder m_hDacModule;
4087 RSExtSmartPtr<ICorDebugDataTarget> m_pDACDataTarget;
4089 // The mutable version of the data target, or null if read-only
4090 RSExtSmartPtr<ICorDebugMutableDataTarget> m_pMutableDataTarget;
4092 RSExtSmartPtr<ICorDebugMetaDataLocator> m_pMetaDataLocator;
4094 IDacDbiInterface * m_pDacPrimitives;
4096 IEventChannel * m_pEventChannel;
4098 // If true, then we'll ASSERT if we detect the target is corrupt or inconsistent
4099 // This switch is for diagnostics purposes only and should always be false in retail builds.
4100 bool m_fAssertOnTargetInconsistency;
4102 // When a successful attempt to read runtime offsets from LS occurs, this flag is set.
4103 bool m_runtimeOffsetsInitialized;
4105 // controls how metadata updated in the target is handled
4106 WriteableMetadataUpdateMode m_writableMetadataUpdateMode;
4109 // Some IMDArocess APIs are supported as interop-only.
4110 #define FAIL_IF_MANAGED_ONLY(pProcess) \
4111 { CordbProcess * __Proc = pProcess; if (!__Proc->IsInteropDebugging()) return CORDBG_E_MUST_BE_INTEROP_DEBUGGING; }
4114 /* ------------------------------------------------------------------------- *
4116 * ------------------------------------------------------------------------- */
4118 class CordbModule : public CordbBase,
4119 public ICorDebugModule,
4120 public ICorDebugModule2,
4121 public ICorDebugModule3
4124 CordbModule(CordbProcess * process,
4125 VMPTR_Module vmModule,
4126 VMPTR_DomainFile vmDomainFile);
4128 virtual ~CordbModule();
4129 virtual void Neuter();
4131 using CordbBase::GetProcess;
4134 virtual const char * DbgGetName() { return "CordbModule"; }
4138 //-----------------------------------------------------------
4140 //-----------------------------------------------------------
4142 ULONG STDMETHODCALLTYPE AddRef()
4144 return (BaseAddRef());
4146 ULONG STDMETHODCALLTYPE Release()
4148 return (BaseRelease());
4150 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4152 //-----------------------------------------------------------
4154 //-----------------------------------------------------------
4156 COM_METHOD GetProcess(ICorDebugProcess **ppProcess);
4157 COM_METHOD GetBaseAddress(CORDB_ADDRESS *pAddress);
4158 COM_METHOD GetAssembly(ICorDebugAssembly **ppAssembly);
4159 COM_METHOD GetName(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4160 COM_METHOD EnableJITDebugging(BOOL bTrackJITInfo, BOOL bAllowJitOpts);
4161 COM_METHOD EnableClassLoadCallbacks(BOOL bClassLoadCallbacks);
4163 // Gets the latest version of a function given the methodDef token
4164 COM_METHOD GetFunctionFromToken(mdMethodDef methodDef,
4165 ICorDebugFunction **ppFunction);
4166 COM_METHOD GetFunctionFromRVA(CORDB_ADDRESS rva, ICorDebugFunction **ppFunction);
4167 COM_METHOD GetClassFromToken(mdTypeDef typeDef,
4168 ICorDebugClass **ppClass);
4169 COM_METHOD CreateBreakpoint(ICorDebugModuleBreakpoint **ppBreakpoint);
4171 // Not implemented - legacy
4172 COM_METHOD GetEditAndContinueSnapshot(
4173 ICorDebugEditAndContinueSnapshot **ppEditAndContinueSnapshot);
4175 COM_METHOD GetMetaDataInterface(REFIID riid, IUnknown **ppObj);
4176 COM_METHOD GetToken(mdModule *pToken);
4177 COM_METHOD IsDynamic(BOOL *pDynamic);
4178 COM_METHOD GetGlobalVariableValue(mdFieldDef fieldDef,
4179 ICorDebugValue **ppValue);
4180 COM_METHOD GetSize(ULONG32 *pcBytes);
4181 COM_METHOD IsInMemory(BOOL *pInMemory);
4183 //-----------------------------------------------------------
4185 //-----------------------------------------------------------
4186 COM_METHOD SetJMCStatus(
4191 // Applies an EnC edit to the module
4192 COM_METHOD ApplyChanges(
4198 // Resolve an assembly given an AssemblyRef token. Note that
4199 // this will not trigger the loading of assembly. If assembly is not yet loaded,
4200 // this will return an CORDBG_E_CANNOT_RESOLVE_ASSEMBLY error
4201 COM_METHOD ResolveAssembly(mdToken tkAssemblyRef,
4202 ICorDebugAssembly **ppAssembly);
4204 // Sets EnC and optimization flags
4205 COM_METHOD SetJITCompilerFlags(DWORD dwFlags);
4207 // Gets EnC and optimization flags
4208 COM_METHOD GetJITCompilerFlags(DWORD *pdwFlags);
4210 //-----------------------------------------------------------
4212 //-----------------------------------------------------------
4213 COM_METHOD CreateReaderForInMemorySymbols(REFIID riid,
4216 //-----------------------------------------------------------
4218 //-----------------------------------------------------------
4221 // Debug helper to ensure that module is no longer discoverable
4222 void DbgAssertModuleDeleted();
4225 // Internal help to get the "name" (filename or pretty name) of the module.
4226 HRESULT GetNameWorker(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4228 // Marks that the module's metadata has become invalid and needs to be refetched.
4229 void RefreshMetaData();
4231 // Cache the current continue counter as the one that the LoadEvent is
4233 void SetLoadEventContinueMarker();
4235 // Return CORDBG_E_MUST_BE_IN_LOAD_MODULE if this module is not in its load callback.
4236 HRESULT EnsureModuleIsInLoadCallback();
4240 // Gets the latest version of the function for the methodDef, if any
4241 CordbFunction * LookupFunctionLatestVersion(mdMethodDef methodToken);
4243 // Gets the latest version of the function. Creates a new instance if none exists yet.
4244 CordbFunction* LookupOrCreateFunctionLatestVersion(mdMethodDef funcMetaDataToken);
4246 // Finds or creates a function for the first time (not for use on EnC if function doesn't exist yet)
4247 CordbFunction * LookupOrCreateFunction(mdMethodDef token, SIZE_T enCVersion);
4249 // Creates an CordbFunction instances for the first time (not for use on EnC)
4250 CordbFunction * CreateFunction(mdMethodDef token, SIZE_T enCVersion);
4252 // Creates a CordbFunction object to represent the specified EnC version
4253 HRESULT UpdateFunction(mdMethodDef token,
4254 SIZE_T newEnCVersion,
4255 CordbFunction** ppFunction);
4257 CordbClass* LookupClass(mdTypeDef classToken);
4258 HRESULT LookupOrCreateClass(mdTypeDef classToken, CordbClass** ppClass);
4259 HRESULT CreateClass(mdTypeDef classToken, CordbClass** ppClass);
4260 HRESULT LookupClassByToken(mdTypeDef token, CordbClass **ppClass);
4261 HRESULT ResolveTypeRef(mdTypeRef token, CordbClass **ppClass);
4262 HRESULT ResolveTypeRefOrDef(mdToken token, CordbClass **ppClass);
4264 // Sends the event to the left side to apply the changes to the debugee
4265 HRESULT ApplyChangesInternal(
4271 // Pulls new metadata if needed in order to ensure the availability of
4273 void UpdateMetaDataCacheIfNeeded(mdToken token);
4275 HRESULT InitPublicMetaDataFromFile(const WCHAR * pszFullPathName, DWORD dwOpenFlags, bool validateFileInfo);
4277 // Creates a CordbNativeCode (if it's not already created) and adds it to the
4278 // hash table of CordbNativeCodes belonging to the module.
4279 CordbNativeCode * LookupOrCreateNativeCode(mdMethodDef methodToken,
4280 VMPTR_MethodDesc methodDesc,
4281 CORDB_ADDRESS startAddress);
4284 // Set the metadata (both public and internal) for the module.
4285 void InitMetaData(TargetBuffer buffer, BOOL useFileMappingOptimization);
4287 // Checks if the given token is in the cached metadata
4288 BOOL CheckIfTokenInMetaData(mdToken token);
4290 // Update the public metadata given a buffer in the target.
4291 void UpdatePublicMetaDataFromRemote(TargetBuffer bufferRemoteMetaData);
4293 // Initialize just the public metadata by reading from an on-disk module
4294 HRESULT InitPublicMetaDataFromFile();
4295 // Initialize just the public metadata by reading new metadata from the buffer
4296 void InitPublicMetaData(TargetBuffer buffer);
4298 // Rebuild the internal metadata given the public one.
4299 void UpdateInternalMetaData();
4301 // Determines whether the on-disk metadata for this module is usable as the
4303 BOOL IsFileMetaDataValid();
4305 // Helper to copy metadata buffer from the Target to the host.
4306 void CopyRemoteMetaData(TargetBuffer buffer, CoTaskMemHolder<VOID> * pLocalBuffer);
4309 CordbAssembly * ResolveAssemblyInternal(mdToken tkAssemblyRef);
4313 //-----------------------------------------------------------
4314 // Convenience routines
4315 //-----------------------------------------------------------
4318 CordbAppDomain *GetAppDomain()
4320 return m_pAppDomain;
4323 CordbAssembly * GetCordbAssembly ();
4325 // Get the module filename, or NULL if none. Throws on error.
4326 const WCHAR * GetModulePath();
4328 const WCHAR * GetNGenImagePath();
4330 const VMPTR_DomainFile GetRuntimeDomainFile ()
4332 return m_vmDomainFile;
4335 const VMPTR_Module GetRuntimeModule()
4340 // Get symbol stream for in-memory modules.
4341 IDacDbiInterface::SymbolFormat GetInMemorySymbolStream(IStream ** ppStream);
4343 // accessor for PE file
4344 VMPTR_PEFile GetPEFile();
4347 IMetaDataImport * GetMetaDataImporter();
4349 // accessor for Internal MetaData importer.
4350 IMDInternalImport * GetInternalMD();
4352 //-----------------------------------------------------------
4354 //-----------------------------------------------------------
4357 CordbAssembly* m_pAssembly;
4358 CordbAppDomain* m_pAppDomain;
4359 CordbSafeHashTable<CordbClass> m_classes;
4361 // A collection, indexed by methodDef, of the latest version of functions in this module
4362 // The collection is filled lazily by LookupOrCreateFunction
4363 CordbSafeHashTable<CordbFunction> m_functions;
4365 // The real handle into the VM for a module. This is appdomain aware.
4366 // This is the primary VM counterpart for the CordbModule.
4367 VMPTR_DomainFile m_vmDomainFile;
4369 VMPTR_Module m_vmModule;
4382 // Base Address and size of this module in debuggee's process. Maybe null if unknown.
4383 TargetBuffer m_PEBuffer;
4385 BOOL m_fDynamic; // Dynamic modules can grow (like Reflection Emit)
4386 BOOL m_fInMemory; // In memory modules don't have file-backing.
4387 ILWinMDState m_isIlWinMD; // WinMD modules don't support all metadata interfaces
4389 // Indicates that the module must serialize its metadata in process as part of metadata
4390 // refresh. This is required for modules updated on the fly by the profiler
4391 BOOL m_fForceMetaDataSerialize;
4393 // Full path to module's image, if any. Empty if none, NULL if not yet set.
4394 StringCopyHolder m_strModulePath;
4396 // Full path to the ngen file. Empty if not ngenned, NULL if not yet set.
4397 // This isn't exposed publicly, but we may use it internally for loading metadata.
4398 StringCopyHolder m_strNGenImagePath;
4400 // "Global" class for this module. Global functions + vars exist in this class.
4401 RSSmartPtr<CordbClass> m_pClass;
4403 // Handle to PEFile, useful for metadata lookups.
4404 // this should always be non-null.
4405 VMPTR_PEFile m_vmPEFile;
4408 // Public metadata importer. This is lazily initialized and accessed from code:GetMetaDataImporter
4409 // This is handed out to debugger clients via code:CordbModule::GetMetaDataInterface
4410 // This is also tightly coupled to the internal metadata importer, m_pInternalMetaDataImport.
4411 RSExtSmartPtr<IMetaDataImport> m_pIMImport;
4413 // Internal metadata object. This is closely tied to the public metadata object (m_pIMImport).
4414 // They share the same backing storage, but expose different interfaces to that storage.
4415 // Debugger authors and tools use the public interfaces.
4416 // DAC-ized operations in the VM require an IMDInternalImport.
4417 // The public and internal must be updated together.
4418 // This ultimately gets handed back to DAC via code:CordbProcess::LookupMetaData
4419 RSExtSmartPtr<IMDInternalImport> m_pInternalMetaDataImport;
4421 // Continue counter of when the module was loaded.
4422 // See code:CordbModule::SetLoadEventContinueMarker for details
4423 UINT m_nLoadEventContinueCounter;
4425 // This is a table of all NativeCode objects in the module indexed
4427 // The collection is filled lazily by LookupOrCreateNativeCode
4428 CordbSafeHashTable<CordbNativeCode> m_nativeCodeTable;
4432 //-----------------------------------------------------------------------------
4433 // Cordb MDA notification
4434 //-----------------------------------------------------------------------------
4435 class CordbMDA : public CordbBase, public ICorDebugMDA
4438 CordbMDA(CordbProcess * pProc, DebuggerMDANotification * pData);
4441 virtual void Neuter();
4444 virtual const char * DbgGetName() { return "CordbMDA"; }
4447 //-----------------------------------------------------------
4449 //-----------------------------------------------------------
4451 ULONG STDMETHODCALLTYPE AddRef()
4453 return (BaseAddRefEnforceExternal());
4455 ULONG STDMETHODCALLTYPE Release()
4457 return (BaseReleaseEnforceExternal());
4459 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4461 //-----------------------------------------------------------
4463 //-----------------------------------------------------------
4465 // Get the string for the type of the MDA. Never empty.
4466 // This is a convenient performant alternative to getting the XML stream and extracting
4467 // the type from that based off the schema.
4468 COM_METHOD GetName(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4470 // Get a string description of the MDA. This may be empty (0-length).
4471 COM_METHOD GetDescription(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4473 // Get the full associated XML for the MDA. This may be empty.
4474 // This could be a potentially expensive operation if the xml stream is large.
4475 // See the MDA documentation for the schema for this XML stream.
4476 COM_METHOD GetXML(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4478 COM_METHOD GetFlags(CorDebugMDAFlags * pFlags);
4480 // Thread that the MDA is fired on. We use the os tid instead of an ICDThread in case an MDA is fired on a
4481 // native thread (or a managed thread that hasn't yet entered managed code and so we don't have a ICDThread
4482 // object for it yet)
4483 COM_METHOD GetOSThreadId(DWORD * pOsTid);
4486 NewArrayHolder<WCHAR> m_szName;
4487 NewArrayHolder<WCHAR> m_szDescription;
4488 NewArrayHolder<WCHAR> m_szXml;
4491 CorDebugMDAFlags m_flags;
4496 struct CordbHangingField
4498 FREEHASHENTRY entry;
4502 // A hashtable for storing EnC hanging field information
4503 // FieldData.m_fldMetadataToken is the key
4504 class CordbHangingFieldTable : public CHashTableAndData<CNewDataNoThrow>
4508 BOOL Cmp(SIZE_T k1, const HASHENTRY *pc2)
4510 LIMITED_METHOD_CONTRACT;
4511 return (ULONG)(UINT_PTR)(k1) !=
4512 (reinterpret_cast<const CordbHangingField *>(pc2))->data.m_fldMetadataToken;
4515 ULONG HASH(mdFieldDef fldToken)
4517 LIMITED_METHOD_CONTRACT;
4521 SIZE_T KEY(mdFieldDef fldToken)
4523 return (SIZE_T)fldToken;
4528 #ifndef DACCESS_COMPILE
4530 CordbHangingFieldTable() : CHashTableAndData<CNewDataNoThrow>(11)
4532 NewInit(11, sizeof(CordbHangingField), 11);
4535 FieldData * AddFieldInfo(FieldData * pInfo)
4537 _ASSERTE(pInfo != NULL);
4539 CordbHangingField *pEntry = (CordbHangingField *)Add(HASH(pInfo->m_fldMetadataToken));
4540 pEntry->data = *pInfo; // copy everything over
4542 // Return a pointer to the data
4543 return &(pEntry->data);
4546 void RemoveFieldInfo(mdFieldDef fldToken)
4548 CordbHangingField *entry = (CordbHangingField*)Find(HASH(fldToken), KEY(fldToken));
4549 _ASSERTE(entry != NULL);
4550 Delete(HASH(fldToken), (HASHENTRY*)entry);
4553 #endif // #ifndef DACCESS_COMPILE
4555 FieldData * GetFieldInfo(mdFieldDef fldToken)
4557 CordbHangingField * entry = (CordbHangingField *)Find(HASH(fldToken), KEY(fldToken));
4558 return (entry!=NULL?&(entry->data):NULL);
4563 /* ------------------------------------------------------------------------- *
4566 * This struct stores a set of type parameters. It is used in
4567 * the heap-allocated data structures CordbType and CordbNativeCode.
4569 * CordbType::m_inst. Stores the class type parameters if any,
4570 * or the solitary array type parameter, or the solitary parameter
4573 * CordbJITILFrame::m_genericArgs. Stores exact generic parameters for the generic method frame if available
4574 * Need not be identicial if code is shared between generic instantiations.
4575 * May be inexact if real instantiation has been optimized away off
4576 * the frame (nb this gets reported by the left side)
4578 * This is conceptually an array of Type-parameters, with the split (m_cClassTyPars) between
4579 * where the Type's type-parameters end and the Method's type-parameters begin.
4580 * ------------------------------------------------------------------------- */
4586 : m_cInst(0), m_ppInst(NULL), m_cClassTyPars (0)
4589 // Instantiation for Type. 0 Method type-parameters.
4590 Instantiation(unsigned int _cClassInst, CordbType **_ppClassInst)
4591 : m_cInst(_cClassInst), m_ppInst(_ppClassInst), m_cClassTyPars(_cClassInst)
4592 {LIMITED_METHOD_CONTRACT; }
4594 // Instantiation for Type + Function.
4595 Instantiation(unsigned int _cInst, CordbType **_ppInst, unsigned int numClassTyPars)
4596 : m_cInst(_cInst), m_ppInst(_ppInst),
4597 m_cClassTyPars (numClassTyPars)
4600 // Copy constructor.
4601 Instantiation(const Instantiation &inst)
4602 : m_cInst(inst.m_cInst), m_ppInst(inst.m_ppInst), m_cClassTyPars (inst.m_cClassTyPars)
4605 // Number of elements in array pointed to by m_ppInst
4606 unsigned int m_cInst;
4608 // Pointer to array of CordbType objects. Length of array is m_cInst.
4609 // Array is Class Type parameters followed by Function's Type parameters.
4610 // Eg, Instantiation for Class<Foo, Goo>::Func<Bar> would be {Foo, Goo, Bar}.
4611 // m_cInst = 3, m_cClassTyPars = 2.
4612 // In contrast, Instantiation for Class::Func<Foo, Goo, Bar> would have same
4613 // array, but m_cClassTyPars = 0.
4614 CordbType **m_ppInst;
4616 // Track the split between Type vs. Method type-params.
4617 unsigned int m_cClassTyPars;
4620 //------------------------------------------------------------------------
4621 // CordbType: replaces the use of signatures.
4623 // Left Side & Right Side
4624 // ---------------------------
4625 // CordbTypes may come from either the Right Side (via being built up from
4626 // ICorDebug), or from the Left-Side (being handed back from LS operations
4627 // like getting the type from an Object the LS handed back).
4628 // The RightSide CordbType corresponds to a Left-Side TypeHandle.
4629 // CordbTypes are communicated across the LS/RS boundary by marshalling
4630 // to BasicTypeData + ExpandedTypeData IPC events.
4633 // Invariants on CordbType
4634 // ---------------------------
4636 // The m_elementType is NEVER ELEMENT_TYPE_VAR or ELEMENT_TYPE_MVAR or ELEMENT_TYPE_GENERICINST
4637 // CordbTypes are always _ground_ types (fully instantiated generics or non-generic types). If
4638 // they represent an instantiated type like List<int> then m_inst will be non-empty.
4641 // !!!! The m_elementType is NEVER ELEMENT_TYPE_VALUETYPE !!!!
4642 // !!!! To find out if it is a value type call CordbType::IsValueType() !!!!
4644 // Where CordbTypes are stored
4645 // ---------------------------
4647 // Because we could have a significant number of different instantiations for a given templated type,
4648 // we need an efficient way to store and retrieve the CordbType instances for these instantiations.
4649 // For this reason, we use a tree-like scheme to hash-cons types. To implement this we use the following
4651 // - CordbTypes are created for "partially instantiated" types,
4652 // e.g. CordbTypes exist for "Dict" and "Dict<int>" even if the real
4653 // type being manipulated by the user is "Dict<int,string>"
4654 // - Subordinate types (E.g. Dict<int,string> is subordinate to Dict<int>,
4655 // which is itself subordinate to the type for Dict) get stored
4656 // in the m_spinetypes hash table of the parent type.
4657 // - In m_spinetypes the pointers of the CordbTypes themselves
4658 // are used for the unique ids for entries in the table.
4659 // Note that CordbType instances that are created for "partially instantiated" types
4660 // are never used for any purpose other than efficient hashing. Specifically, the debugger will
4661 // never have reason to expose a partially instantiated type outside of the hashing algorithm.
4663 // CordbTypes have object identity: if 2 CordbTypes represent the same type (in the same AppDomain),
4664 // then they will be the same CordbType instance.
4666 // Thus the representation for "Dict<class String,class Foo, class Foo* >" goes as follows:
4667 // 1. Assume the type Foo is represented by CordbClass *5678x
4668 // 1b. Assume the hashtable m_sharedtypes in the AppDomain maps E_T_STRING to the CordbType *0ABCx
4669 // Assume m_type in class Foo (i.e. CordbClass *5678x) is the CordbType *0DEFx
4670 // Assume m_type in class Foo maps E_T_PTR to the CordbType *0647x
4671 // 2. The hash table m_spinetypes in "Dict" maps "0ABCx" to a new CordbType
4672 // representing Dict<String> (a single type application)
4673 // 3. The hash table m_spinetypes in this new CordbType maps "0DEFx" to a
4674 // new CordbType representing Dict<class String,class Foo>
4675 // 3. The hash table m_spinetypes in this new CordbType maps "0647" to a
4676 // new CordbType representing Dict<class String,class Foo, class Foo*>
4678 // This lets us reuse the existing hash table scheme to build
4679 // up instantiated types of arbitrary size.
4681 // Array types are similar, excpet that they start with a head type
4682 // for the "type constructor", e.g. "_ []" is a type constructor with rank 1
4683 // and m_elementType = ELEMENT_TYPE_SZARRAY. These head constructors are
4684 // stored in the m_sharedtypes table in the appdomain. The actual instantiations
4685 // of the array types are then subordinate types to the array constructor type.
4687 // Other types are simpler, and have unique objects stored in the m_sharedtypes
4688 // table in the appdomain. This table is indexed by CORDBTYPE_ID in RsType.cpp
4691 // Memory Management of CordbTypes
4692 // ---------------------------
4693 // All CordbTypes are ultimately stored off the CordbAppDomain object.
4694 // The most common place is in the AppDomain's neuter-list.
4696 // See definition of ICorDebugType for further invariants on types.
4699 class CordbType : public CordbBase, public ICorDebugType, public ICorDebugType2
4702 CordbType(CordbAppDomain *appdomain, CorElementType ty, unsigned int rank);
4703 CordbType(CordbAppDomain *appdomain, CorElementType ty, CordbClass *c);
4704 CordbType(CordbType *tycon, CordbType *tyarg);
4705 virtual ~CordbType();
4706 virtual void Neuter();
4709 virtual const char * DbgGetName() { return "CordbType"; }
4712 // If you want to force the init to happen even if we think the class
4713 // is up to date, set fForceInit to TRUE
4714 HRESULT Init(BOOL fForceInit);
4716 //-----------------------------------------------------------
4718 //-----------------------------------------------------------
4720 ULONG STDMETHODCALLTYPE AddRef();
4721 ULONG STDMETHODCALLTYPE Release();
4722 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4724 //-----------------------------------------------------------
4726 //-----------------------------------------------------------
4728 COM_METHOD GetType(CorElementType *ty);
4729 COM_METHOD GetClass(ICorDebugClass **ppClass);
4730 COM_METHOD EnumerateTypeParameters(ICorDebugTypeEnum **ppTyParEnum);
4731 COM_METHOD GetFirstTypeParameter(ICorDebugType **ppType);
4732 COM_METHOD GetBase(ICorDebugType **ppType);
4733 COM_METHOD GetStaticFieldValue(mdFieldDef fieldDef,
4734 ICorDebugFrame * pFrame,
4735 ICorDebugValue ** ppValue);
4736 COM_METHOD GetRank(ULONG32 *pnRank);
4738 //-----------------------------------------------------------
4740 //-----------------------------------------------------------
4741 COM_METHOD GetTypeID(COR_TYPEID *pId);
4743 //-----------------------------------------------------------
4745 //-----------------------------------------------------------
4747 //-----------------------------------------------------------
4748 // Basic constructor operations for the algebra of types.
4749 // These all create unique objects within an AppDomain.
4750 //-----------------------------------------------------------
4752 // This one is used to create simple types, e.g. int32, int64, typedbyref etc.
4753 static HRESULT MkType(CordbAppDomain * pAppDomain,
4754 CorElementType elementType,
4755 CordbType ** ppResultType);
4757 // This one is used to create array, pointer and byref types
4758 static HRESULT MkType(CordbAppDomain * pAppDomain,
4759 CorElementType elementType,
4762 CordbType ** ppResultType);
4764 // This one is used to create function pointer types. et must be ELEMENT_TYPE_FNPTR
4765 static HRESULT MkType(CordbAppDomain * pAppDomain,
4766 CorElementType elementType,
4767 const Instantiation * pInst,
4768 CordbType ** ppResultType);
4770 // This one is used to class and value class types, e.g. "class MyClass" or "class ArrayList<int>"
4771 static HRESULT MkType(CordbAppDomain * pAppDomain,
4772 CorElementType elementType,
4773 CordbClass * pClass,
4774 const Instantiation * pInst,
4775 CordbType ** ppResultType);
4777 // Some derived constructors... Use this one if the type is definitely not
4778 // a paramterized type, e.g. to implement functions on the API where types cannot
4779 // be parameterized.
4780 static HRESULT MkUnparameterizedType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cl, CordbType **ppType);
4782 //-----------------------------------------------------------
4783 // Basic destructor operations over the algebra
4784 //-----------------------------------------------------------
4785 void DestUnaryType(CordbType **pRes) ;
4786 void DestConstructedType(CordbClass **pClass, Instantiation *pInst);
4787 void DestNaryType(Instantiation *pInst);
4789 CorElementType GetElementType() { return m_elementType; }
4790 VMPTR_DomainFile GetDomainFile();
4791 VMPTR_Module GetModule();
4793 // If this is a ptr type, get the CordbType that it points to.
4794 // Eg, for CordbType("Int*"), returns CordbType("Int").
4795 // If not a ptr type, returns null.
4796 // Since it's all internal, no reference counting.
4797 // This is effectively a specialized version of DestUnaryType.
4798 CordbType * GetPointerElementType();
4801 // Create a type from metadata
4802 static HRESULT SigToType(CordbModule * pModule, SigParser * pSigParser, const Instantiation * pInst, CordbType ** ppResultType);
4804 // Create a type from from the data received from the left-side
4805 static HRESULT TypeDataToType(CordbAppDomain *appdomain, DebuggerIPCE_ExpandedTypeData *data, CordbType **pRes);
4806 static HRESULT TypeDataToType(CordbAppDomain *appdomain, DebuggerIPCE_BasicTypeData *data, CordbType **pRes);
4807 static HRESULT InstantiateFromTypeHandle(CordbAppDomain * appdomain,
4808 VMPTR_TypeHandle vmTypeHandle,
4813 // Prepare data to send back to left-side during Init() and FuncEval. Fail if the the exact
4814 // type data is requested but was not fetched correctly during Init()
4815 HRESULT TypeToBasicTypeData(DebuggerIPCE_BasicTypeData *data);
4816 void TypeToExpandedTypeData(DebuggerIPCE_ExpandedTypeData *data);
4817 void TypeToTypeArgData(DebuggerIPCE_TypeArgData *data);
4819 void CountTypeDataNodes(unsigned int *count);
4820 static void CountTypeDataNodesForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], unsigned int *count);
4821 static void GatherTypeData(CordbType *type, DebuggerIPCE_TypeArgData **curr_tyargData);
4822 static void GatherTypeDataForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], DebuggerIPCE_TypeArgData **curr_tyargData);
4824 HRESULT GetParentType(CordbClass * baseClass, CordbType ** ppRes);
4826 // These are available after Init() has been called....
4827 HRESULT GetUnboxedObjectSize(ULONG32 *res);
4828 HRESULT GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData);
4830 CordbAppDomain *GetAppDomain() { return m_appdomain; }
4834 // Is this type a GC-root.
4837 #ifdef FEATURE_64BIT_ALIGNMENT
4838 // checks if the type requires 8-byte alignment.
4839 // this is not exposed via ICorDebug at present.
4840 HRESULT CordbType::RequiresAlign8(BOOL* isRequired);
4843 //-----------------------------------------------------------
4845 //-----------------------------------------------------------
4848 // Internal representation of the element type. This may not map exactly to the public element type.
4849 // Specifically, m_elementType is NEVER:
4850 // ELEMENT_TYPE_VAR, ELEMENT_TYPE_MVAR, ELEMENT_TYPE_GENERICINST,
4851 // or ELEMENT_TYPE_VALUETYPE.
4852 // To find out if this CordbType corresponds to a value type (instead of Reference type) call CordbType::IsValueType()
4853 CorElementType m_elementType;
4855 // The appdomain that this type lives in. Types (and their type-parameters) are all contained in a single appdomain.
4856 // (alhtough the types may be from different modules).
4857 // This is valid for all CordbType objects, regardless of m_elementType;
4858 CordbAppDomain * m_appdomain;
4860 // The matching class for this type.
4861 // Initially only set for E_T_CLASS, lazily computed for E_T_STRING and E_T_OBJECT if needed
4862 CordbClass * m_pClass;
4864 ULONG m_rank; // Only set for E_T_ARRAY etc.
4866 // Array of Type Parameters for this Type.
4867 Instantiation m_inst;
4869 // A unique mapping from CordbType objects that are type parameters to CordbType objects. Each mapping
4870 // represents the use of the containing type as type constructor. e.g. If the containing type
4871 // is CordbType(CordbClass "List") then the table here will map parameters such as (CordbType(CordbClass "String")) to
4872 // the constructed type CordbType(CordbClass "List", <CordbType(CordbClass "String")>)
4873 // @dbgtodo synchronization - this is currently protected by the Stop-Go lock. Transition to process-lock.
4874 CordbSafeHashTable<CordbType> m_spinetypes;
4876 // Valid after Init(), only for E_T_ARRAY etc.and E_T_CLASS when m_pClass->m_classInfo.m_genericArgsCount > 0.
4877 // m_typeHandleExact is the precise Runtime type handle for this type.
4878 VMPTR_TypeHandle m_typeHandleExact;
4880 // Valid after Init(), only for E_T_CLASS, and when m_pClass->m_classInfo.m_genericArgsCount > 0.
4881 // May not be set correctly if m_fieldInfoNeedsInit.
4882 SIZE_T m_objectSize;
4884 // DON'T KEEP POINTERS TO ELEMENTS OF m_pFields AROUND!!
4885 // This may be deleted if the class gets EnC'd.
4887 // Valid after Init(), only for E_T_CLASS, and when m_pClass->m_classInfo.m_genericArgsCount > 0
4888 // All fields will be valid if we have m_typeHandleExact.
4890 // Only some fields will be valid if we have called Init() but still have m_fieldInfoNeedsInit.
4891 DacDbiArrayList<FieldData> m_fieldList;
4893 HRESULT ReturnedByValue();
4896 static HRESULT MkTyAppType(CordbAppDomain * pAddDomain,
4898 const Instantiation * pInst,
4899 CordbType ** pResultType);
4901 BOOL m_fieldInfoNeedsInit;
4904 HRESULT InitInstantiationTypeHandle(BOOL fForceInit);
4905 HRESULT InitInstantiationFieldInfo(BOOL fForceInit);
4906 HRESULT InitStringOrObjectClass(BOOL fForceInit);
4909 /* ------------------------------------------------------------------------- *
4911 * ------------------------------------------------------------------------- */
4913 class CordbClass : public CordbBase, public ICorDebugClass, public ICorDebugClass2
4916 CordbClass(CordbModule* m, mdTypeDef token);
4917 virtual ~CordbClass();
4918 virtual void Neuter();
4920 using CordbBase::GetProcess;
4923 virtual const char * DbgGetName() { return "CordbClass"; }
4927 //-----------------------------------------------------------
4929 //-----------------------------------------------------------
4931 ULONG STDMETHODCALLTYPE AddRef()
4933 return (BaseAddRef());
4935 ULONG STDMETHODCALLTYPE Release()
4937 return (BaseRelease());
4939 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4941 //-----------------------------------------------------------
4943 //-----------------------------------------------------------
4945 COM_METHOD GetStaticFieldValue(mdFieldDef fieldDef,
4946 ICorDebugFrame *pFrame,
4947 ICorDebugValue **ppValue);
4948 COM_METHOD GetModule(ICorDebugModule **pModule);
4949 COM_METHOD GetToken(mdTypeDef *pTypeDef);
4950 //-----------------------------------------------------------
4952 //-----------------------------------------------------------
4953 COM_METHOD GetParameterizedType(CorElementType elementType,
4955 ICorDebugType * rgpTypeArgs[],
4956 ICorDebugType ** ppType);
4958 COM_METHOD SetJMCStatus(BOOL fIsUserCode);
4960 //-----------------------------------------------------------
4961 // Convenience routines and Accessors
4962 //-----------------------------------------------------------
4964 // Helper to get containing module
4965 CordbModule * GetModule()
4970 // get the metadata token for this class
4971 mdTypeDef GetToken() { return m_token; }
4973 // Helper to get the AppDomain the class lives in.
4974 CordbAppDomain * GetAppDomain()
4976 return m_pModule->GetAppDomain();
4979 // This only very roughly resembles the CLASS_LOAD_LEVEL concept in the VM.
4980 // because DBI's needs are far more coarse grained. Also DBI
4981 // may contain more, equal, or less information than what is available in
4982 // native runtime data structures. We can have less when we are being lazy
4983 // and haven't yet fetched it. We can have more if use an independent data
4984 // source such as the metadata blob and then compute some type data ourselves
4987 // At this state the constructor has been run.
4988 // m_module and m_token will be valid
4991 // At this state we have additionally certain to have initialized
4992 // m_fIsValueClass and m_fHasTypeParams
4993 // Calls to IsValueClass() and HasTypeParams() are valid
4994 // This stage should be achievable as long as a runtime type handle
4995 // exists, even if it is unrestored
4998 //Everything is loaded, or at least anything created lazily from this
4999 //point on should be certain to succeed (ie m_type)
5004 ClassLoadLevel GetLoadLevel()
5009 // determine if a load event has been sent for this class
5010 BOOL LoadEventSent() { return m_fLoadEventSent; }
5012 // set value of m_fLoadEventSent
5013 void SetLoadEventSent(BOOL fEventSent) { m_fLoadEventSent = fEventSent; }
5015 // determine if the class has been unloaded
5016 BOOL HasBeenUnloaded() { return m_fHasBeenUnloaded; }
5018 // set value of m_fHasBeenUnloaded
5019 void SetHasBeenUnloaded(BOOL fUnloaded) { m_fHasBeenUnloaded = (fUnloaded == TRUE); }
5021 // determine if this is a value class
5022 BOOL IsValueClassNoInit() { return m_fIsValueClass; }
5024 // set value of m_fIsValueClass
5025 void SetIsValueClass(BOOL fIsValueClass) { m_fIsValueClass = (fIsValueClass == TRUE); }
5027 // determine if the value class is known
5028 BOOL IsValueClassKnown() { return m_fIsValueClassKnown; }
5030 // set value of m_fIsValueClassKnown
5031 void SetIsValueClassKnown(BOOL fIsValueClassKnown) { m_fIsValueClassKnown = (fIsValueClassKnown == TRUE); }
5033 // get value of m_type
5034 CordbType * GetType() { return m_type; }
5036 void SetType(CordbType * pType) { m_type.Assign(pType); }
5038 // get the type parameter count
5039 bool HasTypeParams() { _ASSERTE(m_loadLevel >= BasicInfo); return m_fHasTypeParams; }
5041 // get the object size
5042 SIZE_T ObjectSize() { return m_classInfo.m_objectSize; }
5044 // get the metadata token for this class
5045 mdTypeDef MDToken() { return m_token; }
5047 // get the number of fields
5048 unsigned int FieldCount() { return m_classInfo.m_fieldList.Count(); }
5050 //-----------------------------------------------------------
5051 // Functionality shared for CordbType and CordbClass
5052 //-----------------------------------------------------------
5054 static HRESULT SearchFieldInfo(CordbModule * module,
5055 DacDbiArrayList<FieldData> * pFieldList,
5056 mdTypeDef classToken,
5057 mdFieldDef fldToken,
5058 FieldData ** ppFieldData);
5060 static HRESULT GetStaticFieldValue2(CordbModule * pModule,
5061 FieldData * pFieldData,
5062 BOOL fEnCHangingField,
5063 const Instantiation * pInst,
5064 ICorDebugFrame * pFrame,
5065 ICorDebugValue ** ppValue);
5067 //-----------------------------------------------------------
5069 //-----------------------------------------------------------
5071 // Get information about a field that was added by EnC
5072 HRESULT GetEnCHangingField(mdFieldDef fldToken,
5073 FieldData ** ppFieldData,
5074 CordbObjectValue * pObject);
5077 // Get information via the DAC about a field added with Edit and Continue.
5078 FieldData * GetEnCFieldFromDac(BOOL fStatic,
5079 CordbObjectValue * pObject,
5080 mdFieldDef fieldToken);
5082 // Initialize an instance of EnCHangingFieldInfo.
5083 void InitEnCFieldInfo(EnCHangingFieldInfo * pEncField,
5085 CordbObjectValue * pObject,
5086 mdFieldDef fieldToken,
5087 mdTypeDef classToken);
5092 // set or clear the custom notifications flag to control whether we ignore custom debugger notifications
5093 void SetCustomNotifications(BOOL fEnable) { m_fCustomNotificationsEnabled = fEnable; }
5094 BOOL CustomNotificationsEnabled () { return m_fCustomNotificationsEnabled; }
5096 HRESULT GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData);
5098 // If you want to force the init to happen even if we think the class
5099 // is up to date, set fForceInit to TRUE
5100 void Init(ClassLoadLevel desiredLoadLevel = FullInfo);
5102 // determine if any fields for a type are unallocated statics
5103 BOOL GotUnallocatedStatic(DacDbiArrayList<FieldData> * pFieldList);
5105 bool IsValueClass();
5106 HRESULT GetThisType(const Instantiation * pInst, CordbType ** ppResultType);
5107 static HRESULT PostProcessUnavailableHRESULT(HRESULT hr,
5108 IMetaDataImport *pImport,
5109 mdFieldDef fieldDef);
5110 mdTypeDef GetTypeDef() { return (mdTypeDef)m_id; }
5112 #ifdef EnC_SUPPORTED
5113 // when we get an added field or method, mark the class to force re-init when we access it
5116 m_loadLevel = Constructed;
5118 #endif // EnC_SUPPORTED
5120 //-----------------------------------------------------------
5122 //-----------------------------------------------------------
5124 // contains information about the type: size and
5125 // field information
5126 ClassInfo m_classInfo;
5128 ClassLoadLevel m_loadLevel;
5130 // @dbgtodo managed pipeline - can we get rid of both of these fields?
5131 BOOL m_fLoadEventSent;
5132 bool m_fHasBeenUnloaded;
5134 // [m_type] is the type object for when this class is used
5135 // as a type. If the class is a value class then it can represent
5136 // either the boxed or unboxed type - it depends on the context where the
5137 // type is used. For example on a CordbBoxValue it represents the type of the
5138 // boxed VC, on a CordbVCObjectValue it represents the type of the unboxed VC.
5140 // The type field starts of NULL as there
5141 // is no need to create the type object until it is needed.
5142 RSSmartPtr<CordbType> m_type;
5144 // Module that this Class lives in. Valid at the Constructed type level.
5145 CordbModule * m_pModule;
5147 // the token for the type constructor - m_id cannot be used for constructed types
5148 // valid at the Constructed type level
5151 // Whether the class is a VC or not is discovered either by
5152 // seeing the class used in a signature after ELEMENT_TYPE_VALUETYPE
5153 // or ELEMENT_TYPE_CLASS or by going and asking the EE.
5154 bool m_fIsValueClassKnown;
5156 // Whether the class is a VC or not
5157 bool m_fIsValueClass;
5159 // Whether the class has generic type parameters in its definition
5160 bool m_fHasTypeParams;
5162 // Timestamp from GetProcess()->m_continueCounter, which we can use to tell if
5163 // the process has been continued since we last took a snapshot.
5164 UINT m_continueCounterLastSync;
5166 // if we add static fields with EnC after this class is loaded (in the debuggee),
5167 // their value will be hung off the FieldDesc. Hold information about such fields here.
5168 CordbHangingFieldTable m_hangingFieldsStatic;
5170 // this indicates whether we should send custom debugger notifications
5171 BOOL m_fCustomNotificationsEnabled;
5176 /* ------------------------------------------------------------------------- *
5177 * TypeParameter enumerator class
5178 * ------------------------------------------------------------------------- */
5180 class CordbTypeEnum : public CordbBase, public ICorDebugTypeEnum
5183 // Factory method: Create a new instance of this class. Returns NULL on out-of-memory.
5184 // On success, returns a new initialized instance of CordbTypeEnum with ref-count 0 (just like a ctor).
5185 // the life expectancy of the enumerator varies by caller so we require them to specify the applicable neuter list here.
5186 static CordbTypeEnum* Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, CordbType **ppTypars);
5187 static CordbTypeEnum* Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, RSSmartPtr<CordbType>*ppTypars);
5189 virtual ~CordbTypeEnum() ;
5191 virtual void Neuter();
5195 virtual const char * DbgGetName() { return "CordbTypeEnum"; }
5199 //-----------------------------------------------------------
5201 //-----------------------------------------------------------
5203 ULONG STDMETHODCALLTYPE AddRef()
5205 return (BaseAddRef());
5207 ULONG STDMETHODCALLTYPE Release()
5209 return (BaseRelease());
5211 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5213 //-----------------------------------------------------------
5215 //-----------------------------------------------------------
5217 COM_METHOD Skip(ULONG celt);
5219 COM_METHOD Clone(ICorDebugEnum **ppEnum);
5220 COM_METHOD GetCount(ULONG *pcelt);
5222 //-----------------------------------------------------------
5223 // ICorDebugTypeEnum
5224 //-----------------------------------------------------------
5226 COM_METHOD Next(ULONG celt, ICorDebugType *Types[], ULONG *pceltFetched);
5229 // Private constructor, only partially initializes the object.
5230 // Clients should use the 'Build' factory method to create an instance of this class.
5231 CordbTypeEnum( CordbAppDomain * pAppDomain, NeuterList * pNeuterList );
5232 template<class T> static CordbTypeEnum* BuildImpl(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, T* ppTypars );
5235 CordbAppDomain * m_pAppDomain;
5237 // Array of Types. We own the array, and share refs to the types.
5238 // @todo- since these are guaranteed to be kept alive as long as we're not neutered,
5239 // we don't need to keep refs to them.
5240 RSSmartPtr<CordbType> * m_ppTypars;
5245 /* ------------------------------------------------------------------------- *
5246 * Code enumerator class
5247 * ------------------------------------------------------------------------- */
5249 class CordbCodeEnum : public CordbBase, public ICorDebugCodeEnum
5252 CordbCodeEnum(unsigned int cCode, RSSmartPtr<CordbCode> * ppCode);
5253 virtual ~CordbCodeEnum() ;
5257 virtual const char * DbgGetName() { return "CordbCodeEnum"; }
5261 //-----------------------------------------------------------
5263 //-----------------------------------------------------------
5265 ULONG STDMETHODCALLTYPE AddRef()
5267 return (BaseAddRef());
5269 ULONG STDMETHODCALLTYPE Release()
5271 return (BaseRelease());
5273 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5275 //-----------------------------------------------------------
5277 //-----------------------------------------------------------
5279 COM_METHOD Skip(ULONG celt);
5281 COM_METHOD Clone(ICorDebugEnum **ppEnum);
5282 COM_METHOD GetCount(ULONG *pcelt);
5284 //-----------------------------------------------------------
5285 // ICorDebugCodeEnum
5286 //-----------------------------------------------------------
5288 COM_METHOD Next(ULONG celt, ICorDebugCode *Codes[], ULONG *pceltFetched);
5291 // Ptr to an array of CordbCode*
5292 // We own the array.
5293 RSSmartPtr<CordbCode> * m_ppCodes;
5302 typedef CUnorderedArray<CordbCode*,11> UnorderedCodeArray;
5303 //<TODO>@todo port: different SIZE_T size/</TODO>
5304 const int DMI_VERSION_INVALID = 0;
5305 const int DMI_VERSION_MOST_RECENTLY_JITTED = 1;
5306 const int DMI_VERSION_MOST_RECENTLY_EnCED = 2;
5309 /* ------------------------------------------------------------------------- *
5312 * @review . The CordbFunction class now keeps a multiple MethodDescInfo
5313 * structures in a hash table indexed by tokens provided by the left-side.
5314 * In 99.9% of cases this hash table will only contain one entry - we only
5315 * use a hashtable to cover the case where we have multiple JITtings of
5316 * a single version of a function, in particular multiple JITtings of generic
5317 * code under different instantiations. This will increase space usage.
5318 * The way around it is to store one CordbNativeCode in-line in the CordbFunction
5319 * class, or at least store one such pointer so no hash table will normally
5320 * be needed. This is similar to other cases, e.g. the hash table in
5321 * CordbClass used to indicate different CordbTypes made from that class -
5322 * again in the normal case these tables will only contain one element.
5324 * However, for the moment I've focused on correctness and we can minimize
5325 * this space usage in due course.
5326 * ------------------------------------------------------------------------- */
5328 const BOOL bNativeCode = FALSE;
5329 const BOOL bILCode = TRUE;
5332 // Each E&C version gets its own function object. So the IL that a function
5333 // is associated w/ does not change.
5334 // B/C of generics, a single IL function may get jitted multiple times and
5335 // be associated w/ multiple native code blobs (CordbNativeCode).
5337 class CordbFunction : public CordbBase, public ICorDebugFunction, public ICorDebugFunction2, public ICorDebugFunction3
5340 //-----------------------------------------------------------
5341 // Create from scope and member objects.
5342 //-----------------------------------------------------------
5343 CordbFunction(CordbModule * m,
5346 virtual ~CordbFunction();
5347 virtual void Neuter();
5352 virtual const char * DbgGetName() { return "CordbFunction"; }
5356 //-----------------------------------------------------------
5358 //-----------------------------------------------------------
5360 ULONG STDMETHODCALLTYPE AddRef()
5362 return (BaseAddRef());
5364 ULONG STDMETHODCALLTYPE Release()
5366 return (BaseRelease());
5368 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5370 //-----------------------------------------------------------
5371 // ICorDebugFunction
5372 //-----------------------------------------------------------
5373 COM_METHOD GetModule(ICorDebugModule **pModule);
5374 COM_METHOD GetClass(ICorDebugClass **ppClass);
5375 COM_METHOD GetToken(mdMethodDef *pMemberDef);
5376 COM_METHOD GetILCode(ICorDebugCode **ppCode);
5377 COM_METHOD GetNativeCode(ICorDebugCode **ppCode);
5378 COM_METHOD CreateBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint);
5379 COM_METHOD GetLocalVarSigToken(mdSignature *pmdSig);
5380 COM_METHOD GetCurrentVersionNumber(ULONG32 *pnCurrentVersion);
5382 //-----------------------------------------------------------
5383 // ICorDebugFunction2
5384 //-----------------------------------------------------------
5385 COM_METHOD SetJMCStatus(BOOL fIsUserCode);
5386 COM_METHOD GetJMCStatus(BOOL * pfIsUserCode);
5387 COM_METHOD EnumerateNativeCode(ICorDebugCodeEnum **ppCodeEnum) { return E_NOTIMPL; }
5388 COM_METHOD GetVersionNumber(ULONG32 *pnCurrentVersion);
5390 //-----------------------------------------------------------
5391 // ICorDebugFunction3
5392 //-----------------------------------------------------------
5393 COM_METHOD GetActiveReJitRequestILCode(ICorDebugILCode **ppReJitedILCode);
5395 //-----------------------------------------------------------
5397 //-----------------------------------------------------------
5399 // Returns the function's ILCode and SigToken
5400 HRESULT GetILCodeAndSigToken();
5402 // Get the metadata token for the class to which a function belongs.
5403 mdTypeDef InitParentClassOfFunctionHelper(mdToken funcMetaDataToken);
5405 // Get information about one of the native code blobs for this function
5406 HRESULT InitNativeCodeInfo();
5410 // Get the class to which a given function belongs
5411 HRESULT InitParentClassOfFunction();
5413 void NotifyCodeCreated(CordbNativeCode* nativeCode);
5415 HRESULT GetSig(SigParser *pMethodSigParser,
5416 ULONG *pFunctionArgCount,
5417 BOOL *pFunctionIsStatic);
5419 HRESULT GetArgumentType(DWORD dwIndex, const Instantiation * pInst, CordbType ** ppResultType);
5422 //-----------------------------------------------------------
5423 // Internal routines
5424 //-----------------------------------------------------------
5426 // Get the existing IL code object
5427 HRESULT GetILCode(CordbILCode ** ppCode);
5429 // Finds or creates an ILCode for a given rejit request
5430 HRESULT LookupOrCreateReJitILCode(VMPTR_SharedReJitInfo vmSharedRejitInfo,
5431 CordbReJitILCode** ppILCode);
5434 #ifdef EnC_SUPPORTED
5438 //-----------------------------------------------------------
5440 //-----------------------------------------------------------
5442 // Get the AppDomain that this function lives in.
5443 CordbAppDomain * GetAppDomain()
5445 return (m_pModule->GetAppDomain());
5448 // Get the CordbModule that this Function lives in.
5449 CordbModule * GetModule()
5454 // Get the CordbClass this of which this function is a member
5455 CordbClass * GetClass()
5460 // Get the IL code blob corresponding to this function
5461 CordbILCode * GetILCode()
5466 // Get metadata token for this function
5467 mdMethodDef GetMetadataToken()
5472 SIZE_T GetEnCVersionNumber()
5474 return m_dwEnCVersionNumber;
5477 CordbFunction * GetPrevVersion()
5479 return m_pPrevVersion;
5482 void SetPrevVersion(CordbFunction * prevVersion)
5484 m_pPrevVersion.Assign(prevVersion);
5487 typedef enum {kNativeOnly, kHasIL, kUnknownImpl} ImplementationKind;
5488 ImplementationKind IsNativeImpl()
5490 return (m_fIsNativeImpl);
5493 // determine whether we have a native-only implementation
5494 void InitNativeImpl();
5497 //-----------------------------------------------------------
5499 //-----------------------------------------------------------
5502 // The module that this Function is contained in. It maintains a strong reference to this object
5503 // and will neuter this object.
5504 CordbModule * m_pModule;
5506 // The Class that this function is contained in.
5507 CordbClass * m_pClass;
5509 // We only have 1 IL blob associated with a given Function object.
5510 RSSmartPtr<CordbILCode> m_pILCode;
5513 // Generics allow a single IL method to be instantiated to multiple native
5514 // code blobs. So CordbFunction : CordbNativeCode is 1:n.
5515 // This pointer is to arbitrary one of those n code bodies.
5516 // Someday we may need to get access to all N of them but not today
5517 RSSmartPtr<CordbNativeCode> m_nativeCode;
5519 // Metadata Token for the IL function. Scoped to m_module.
5520 mdMethodDef m_MDToken;
5522 // EnC version number of this instance
5523 SIZE_T m_dwEnCVersionNumber;
5525 // link to previous version of this function
5526 RSSmartPtr<CordbFunction> m_pPrevVersion;
5528 // Is the function implemented natively in the runtime?? (eg, it has no IL, may be an Ecall/fcall)
5529 ImplementationKind m_fIsNativeImpl;
5531 // True if method signature (argument) values are cached.
5532 BOOL m_fCachedMethodValuesValid;
5534 // Cached SigParser for this Function's argument signature.
5535 // Only valid if m_fCachedMethodValuesValid is set.
5536 SigParser m_methodSigParserCached;
5538 // Cached Count of arguments in the argument signature.
5539 // Only valid if m_fCachedMethodValuesValid is set.
5540 ULONG m_argCountCached;
5542 // Cached boolean if method is static or instance (part of the argument signature).
5543 // Only valid if m_fCachedMethodValuesValid is set.
5544 BOOL m_fIsStaticCached;
5546 // A collection, indexed by VMPTR_SharedReJitInfo, of IL code for rejit requests
5547 // The collection is filled lazily by LookupOrCreateReJitILCode
5548 CordbSafeHashTable<CordbReJitILCode> m_reJitILCodes;
5551 //-----------------------------------------------------------------------------
5553 // Represents either IL or Native code blobs associated with a function.
5555 // See the comments at the ICorDebugCode definition for invariants about Code objects.
5557 //-----------------------------------------------------------------------------
5558 class CordbCode : public CordbBase, public ICorDebugCode
5561 CordbCode(CordbFunction * pFunction, UINT_PTR id, SIZE_T encVersion, BOOL fIsIL);
5564 virtual ~CordbCode();
5565 virtual void Neuter();
5568 virtual const char * DbgGetName() = 0;
5572 //-----------------------------------------------------------
5574 //-----------------------------------------------------------
5576 ULONG STDMETHODCALLTYPE AddRef()
5578 return (BaseAddRef());
5580 ULONG STDMETHODCALLTYPE Release()
5582 return (BaseRelease());
5584 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5586 //-----------------------------------------------------------
5588 //-----------------------------------------------------------
5590 COM_METHOD IsIL(BOOL * pbIL);
5591 COM_METHOD GetFunction(ICorDebugFunction ** ppFunction);
5592 COM_METHOD GetAddress(CORDB_ADDRESS * pStart) = 0;
5593 COM_METHOD GetSize(ULONG32 * pcBytes);
5594 COM_METHOD CreateBreakpoint(ULONG32 offset,
5595 ICorDebugFunctionBreakpoint ** ppBreakpoint);
5596 COM_METHOD GetCode(ULONG32 startOffset, ULONG32 endOffset,
5597 ULONG32 cBufferAlloc,
5599 ULONG32 * pcBufferSize);
5600 COM_METHOD GetVersionNumber( ULONG32 * nVersion);
5601 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5603 COR_DEBUG_IL_TO_NATIVE_MAP map[]) = 0;
5604 COM_METHOD GetEnCRemapSequencePoints(ULONG32 cMap,
5608 //-----------------------------------------------------------
5609 // Accessors and convenience routines
5610 //-----------------------------------------------------------
5612 // get the CordbFunction instance for this code object
5613 CordbFunction * GetFunction();
5615 // get the actual code bytes for this function
5616 virtual HRESULT ReadCodeBytes() = 0;
5618 // get the size in bytes of this function
5619 virtual ULONG32 GetSize() = 0;
5622 // get the metadata token for this code object
5623 mdMethodDef GetMetadataToken()
5625 _ASSERTE(m_pFunction != NULL);
5626 return (m_pFunction->GetMetadataToken());
5629 // get the module this code object belongs to
5630 CordbModule * GetModule()
5632 _ASSERTE(m_pFunction != NULL);
5633 return (m_pFunction->GetModule());
5636 // get the function signature for this code blob or throw on failure
5637 void GetSig(SigParser *pMethodSigParser,
5638 ULONG *pFunctionArgCount,
5639 BOOL *pFunctionIsStatic)
5641 _ASSERTE(m_pFunction != NULL);
5642 IfFailThrow(m_pFunction->GetSig(pMethodSigParser, pFunctionArgCount, pFunctionIsStatic));
5645 // get the class to which this code blob belongs
5646 CordbClass * GetClass()
5648 _ASSERTE(m_pFunction != NULL);
5649 return (m_pFunction->GetClass());
5652 // Quick helper to get the AppDomain that this code object lives in.
5653 CordbAppDomain *GetAppDomain()
5655 _ASSERTE(m_pFunction != NULL);
5656 return (m_pFunction->GetAppDomain());
5659 // Get the EnC version of this blob
5660 SIZE_T GetVersion() { return m_nVersion; };
5662 // Return true if this is an IL code blob. Else return false.
5663 BOOL IsIL() { return m_fIsIL; }
5665 // convert to CordbNativeCode as long as m_fIsIl is false.
5666 CordbNativeCode * AsNativeCode()
5668 _ASSERTE(m_fIsIL == FALSE);
5669 return reinterpret_cast<CordbNativeCode *>(this);
5672 // convert to CordbILCode as long as m_fIsIl is true.
5673 CordbILCode * AsILCode()
5675 _ASSERTE(m_fIsIL == TRUE);
5676 return reinterpret_cast<CordbILCode *>(this);
5679 //-----------------------------------------------------------
5681 //-----------------------------------------------------------
5686 // EnC version number.
5690 // Our local copy of the code. It will be GetSize() bytes long.
5691 BYTE * m_rgbCode; // will be NULL if we can't fit it into memory
5693 UINT m_continueCounterLastSync;
5695 // Owning Function associated with this code.
5696 CordbFunction * m_pFunction;
5697 }; //class CordbCode
5703 /* ------------------------------------------------------------------------- *
5705 * This class represents an IL code blob for a particular EnC version. Thus it is
5706 * 1:1 with a given instantiation of CordbFunction. Provided functionality includes
5707 * methods to get the starting address and size of an IL code blob and to read
5708 * the actual bytes of IL into a buffer.
5709 * ------------------------------------------------------------------------- */
5711 class CordbILCode : public CordbCode
5714 // Initialize a new CordbILCode instance
5715 CordbILCode(CordbFunction *pFunction, TargetBuffer codeRegionInfo, SIZE_T nVersion, mdSignature localVarSigToken, UINT_PTR id = 0);
5718 const char * DbgGetName() { return "CordbILCode"; };
5721 COM_METHOD GetAddress(CORDB_ADDRESS * pStart);
5722 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5724 COR_DEBUG_IL_TO_NATIVE_MAP map[]);
5725 // Quick helper for internal access to: GetAddress(CORDB_ADDRESS *pStart);
5726 CORDB_ADDRESS GetAddress() { return m_codeRegionInfo.pAddress; }
5728 // get total size of the IL code
5729 ULONG32 GetSize() { return m_codeRegionInfo.cbSize; }
5731 #ifdef EnC_SUPPORTED
5733 #endif // EnC_SUPPORTED
5735 HRESULT GetLocalVarSig(SigParser *pLocalsSigParser, ULONG *pLocalVarCount);
5736 HRESULT GetLocalVariableType(DWORD dwIndex, const Instantiation * pInst, CordbType ** ppResultType);
5737 mdSignature GetLocalVarSigToken();
5740 // Read the actual bytes of IL code into the data member m_rgbCode.
5741 // Helper routine for GetCode
5742 HRESULT ReadCodeBytes();
5744 //-----------------------------------------------------------
5746 //-----------------------------------------------------------
5749 #ifdef EnC_SUPPORTED
5750 UINT m_fIsOld : 1; // marks this instance as an old EnC version
5751 bool m_encBreakpointsApplied;
5754 // derived types can init this
5756 TargetBuffer m_codeRegionInfo; // stores the starting address and size of the
5759 // Metadata token for local's signature.
5760 mdSignature m_localVarSigToken;
5762 }; // class CordbILCode
5764 /* ------------------------------------------------------------------------- *
5765 * CordbReJitILCode class
5766 * This class represents an IL code blob for a particular EnC version and
5767 * rejitID. Thus it is 1:N with a given instantiation of CordbFunction.
5768 * ------------------------------------------------------------------------- */
5770 class CordbReJitILCode : public CordbILCode, public ICorDebugILCode, public ICorDebugILCode2
5773 // Initialize a new CordbILCode instance
5774 CordbReJitILCode(CordbFunction *pFunction, SIZE_T encVersion, VMPTR_SharedReJitInfo vmSharedReJitInfo);
5776 //-----------------------------------------------------------
5778 //-----------------------------------------------------------
5779 ULONG STDMETHODCALLTYPE AddRef();
5780 ULONG STDMETHODCALLTYPE Release();
5781 COM_METHOD QueryInterface(REFIID riid, void** ppInterface);
5784 //-----------------------------------------------------------
5786 //-----------------------------------------------------------
5787 COM_METHOD GetEHClauses(ULONG32 cClauses, ULONG32 * pcClauses, CorDebugEHClause clauses[]);
5790 //-----------------------------------------------------------
5792 //-----------------------------------------------------------
5793 COM_METHOD GetLocalVarSigToken(mdSignature *pmdSig);
5794 COM_METHOD GetInstrumentedILMap(ULONG32 cMap, ULONG32 *pcMap, COR_IL_MAP map[]);
5797 HRESULT Init(DacSharedReJitInfo* pSharedReJitInfo);
5801 NewArrayHolder<CorDebugEHClause> m_pClauses;
5802 ULONG32 m_cbLocalIL;
5803 NewArrayHolder<BYTE> m_pLocalIL;
5805 NewArrayHolder<COR_IL_MAP> m_pILMap;
5808 /* ------------------------------------------------------------------------- *
5809 * CordbNativeCode class. These correspond to MethodDesc's on the left-side.
5810 * There may or may not be a DebuggerJitInfo associated with the MethodDesc.
5811 * At most one CordbNativeCode is created for each native code compilation of each method
5812 * that is seen by the right-side. Note that if each method were JITted only once
5813 * then this information could go in CordbFunction, however generics allow
5814 * methods to be compiled more than once.
5816 * The purpose of this class is to encapsulate details about a blob of jitted/ngen'ed
5817 * code, including an optional set of mappings from IL to offsets in the native Code.
5818 * ------------------------------------------------------------------------- */
5820 class CordbNativeCode : public CordbCode,
5821 public ICorDebugCode2,
5822 public ICorDebugCode3,
5823 public ICorDebugCode4
5826 CordbNativeCode(CordbFunction * pFunction,
5827 const NativeCodeFunctionData * pJitData,
5828 BOOL fIsInstantiatedGeneric);
5830 const char * DbgGetName() { return "CordbNativeCode"; };
5833 ULONG STDMETHODCALLTYPE AddRef()
5835 return (BaseAddRef());
5837 ULONG STDMETHODCALLTYPE Release()
5839 return (BaseRelease());
5841 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5843 //-----------------------------------------------------------
5845 //-----------------------------------------------------------
5846 COM_METHOD GetAddress(CORDB_ADDRESS * pStart);
5847 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5849 COR_DEBUG_IL_TO_NATIVE_MAP map[]);
5850 //-----------------------------------------------------------
5852 //-----------------------------------------------------------
5853 COM_METHOD GetCodeChunks(ULONG32 cbufSize, ULONG32 * pcnumChunks, CodeChunkInfo chunks[]);
5855 COM_METHOD GetCompilerFlags(DWORD * pdwFlags);
5857 //-----------------------------------------------------------
5859 //-----------------------------------------------------------
5860 COM_METHOD GetReturnValueLiveOffset(ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets);
5863 //-----------------------------------------------------------
5865 //-----------------------------------------------------------
5866 COM_METHOD EnumerateVariableHomes(ICorDebugVariableHomeEnum **ppEnum);
5868 //-----------------------------------------------------------
5870 //-----------------------------------------------------------
5872 HRESULT ILVariableToNative(DWORD dwIndex,
5874 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
5875 void LoadNativeInfo();
5877 //-----------------------------------------------------------
5878 // Accessors and convenience routines
5879 //-----------------------------------------------------------
5881 // get the argument type for a generic
5882 void GetArgumentType(DWORD dwIndex,
5883 const Instantiation * pInst,
5884 CordbType ** ppResultType)
5886 CordbFunction * pFunction = GetFunction();
5887 _ASSERTE(pFunction != NULL);
5888 IfFailThrow(pFunction->GetArgumentType(dwIndex, pInst, ppResultType));
5891 // Quick helper for internall access to: GetAddress(CORDB_ADDRESS *pStart);
5892 CORDB_ADDRESS GetAddress() { return m_rgCodeRegions[kHot].pAddress; };
5894 VMPTR_MethodDesc GetVMNativeCodeMethodDescToken() { return m_vmNativeCodeMethodDescToken; };
5896 // Worker function for GetReturnValueLiveOffset.
5897 HRESULT GetReturnValueLiveOffsetImpl(Instantiation *currentInstantiation, ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets);
5899 // get total size of the code including both hot and cold regions
5902 // get the size of the cold region(s) only
5903 ULONG32 GetColdSize();
5905 // Return true if the Code is split into hot + cold regions.
5906 bool HasColdRegion() { return m_rgCodeRegions[kCold].pAddress != NULL; }
5908 // Get the number of fixed arguments for this function (the "this"
5910 unsigned int GetFixedArgCount()
5912 return m_nativeVarData.GetFixedArgCount();
5915 // Get the number of all arguments for this function
5916 // ("this" pointer, fixed args and varargs)
5917 ULONG32 GetAllArgsCount()
5919 return m_nativeVarData.GetAllArgsCount();
5922 void SetAllArgsCount(ULONG32 count)
5924 m_nativeVarData.SetAllArgsCount(count);
5927 // Determine whether this is an instantiation of a generic function
5928 BOOL IsInstantiatedGeneric()
5930 return m_fIsInstantiatedGeneric != 0;
5933 // Determine whether we have initialized the native variable and
5934 // sequence point offsets
5935 BOOL IsNativeCodeValid ()
5937 return ((m_nativeVarData.IsInitialized() != 0) &&
5938 (m_sequencePoints.IsInitialized() != 0));
5941 SequencePoints * GetSequencePoints()
5943 return &m_sequencePoints;
5947 // Given an ILOffset in the current function, return the class token and function token of the IL call target at that
5948 // location. Also fill "methodSig" with the method's signature and "genericSig" with the method's generic signature.
5949 HRESULT GetCallSignature(ULONG32 ILOffset, mdToken *pClass, mdToken *pMDFunction, SigParser &methodSig, SigParser &genericSig);
5951 // Moves a method signature from the start of the signature to the location of the return value (passing out the
5952 // number of generic parameters in the method).
5953 static HRESULT SkipToReturn(SigParser &parser, ULONG *genArgCount = 0);
5956 // Read the actual bytes of native code into the data member m_rgbCode.
5957 // Helper routine for GetCode
5958 HRESULT ReadCodeBytes();
5960 // Returns a failure HRESULT if we cannot handle the return value of the given
5961 // methodref, methoddef, or methodspec token, otherwise S_OK. Does NOT return S_FALSE;
5962 HRESULT EnsureReturnValueAllowed(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics);
5963 HRESULT EnsureReturnValueAllowedWorker(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics, ULONG genCount);
5965 // Grabs the appropriate signature parser for a methodref, methoddef, methodspec.
5966 HRESULT GetSigParserFromFunction(mdToken mdFunction, mdToken *pClass, SigParser &methodSig, SigParser &genericSig);
5968 int GetCallInstructionLength(BYTE *buffer, ULONG32 len);
5970 //-----------------------------------------------------------
5972 //-----------------------------------------------------------
5974 // offset of the beginning of the last sequence point in the sequence point map
5977 // start address(es) and size(s) of hot and cold regions
5978 TargetBuffer m_rgCodeRegions[MAX_REGIONS];
5980 // LS data structure--method desc for this instantiation.
5981 VMPTR_MethodDesc m_vmNativeCodeMethodDescToken;
5983 bool m_fCodeAvailable; // true iff the code has been jitted but not pitched
5985 bool m_fIsInstantiatedGeneric; // true iff this is an instantiated generic
5987 // information in the following two classes tracks native offsets and is initialized on demand.
5989 // location and ID information for local variables. See code:NativeVarData for details.
5990 NativeVarData m_nativeVarData;
5992 // mapping between IL and native code sequence points.
5993 SequencePoints m_sequencePoints;
5995 }; //class CordbNativeCode
5997 //---------------------------------------------------------------------------------------
5999 // GetActiveInternalFramesData is used to enumerate internal frames on a specific thread.
6000 // It is used in conjunction with code:CordbThread::GetActiveInternalFramesCallback.
6001 // We store each internal frame in ppInternalFrames as we enumerate them.
6004 struct GetActiveInternalFramesData
6007 // the thread we are walking
6008 CordbThread * pThis;
6010 // an array to store the internal frames
6011 RSPtrArray<CordbInternalFrame> pInternalFrames;
6013 // next element in the array to be filled
6018 /* ------------------------------------------------------------------------- *
6020 * ------------------------------------------------------------------------- */
6022 class CordbThread : public CordbBase, public ICorDebugThread,
6023 public ICorDebugThread2,
6024 public ICorDebugThread3,
6025 public ICorDebugThread4
6028 CordbThread(CordbProcess * pProcess, VMPTR_Thread);
6030 virtual ~CordbThread();
6031 virtual void Neuter();
6033 using CordbBase::GetProcess;
6036 virtual const char * DbgGetName() { return "CordbThread"; }
6039 //-----------------------------------------------------------
6041 //-----------------------------------------------------------
6043 ULONG STDMETHODCALLTYPE AddRef()
6045 // there's an external add ref from within RS in CordbEnumFilter
6046 return (BaseAddRef());
6048 ULONG STDMETHODCALLTYPE Release()
6050 return (BaseRelease());
6052 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6054 //-----------------------------------------------------------
6056 //-----------------------------------------------------------
6058 COM_METHOD GetProcess(ICorDebugProcess **ppProcess);
6059 COM_METHOD GetID(DWORD *pdwThreadId);
6060 COM_METHOD GetHandle(HANDLE * phThreadHandle);
6061 COM_METHOD GetAppDomain(ICorDebugAppDomain **ppAppDomain);
6062 COM_METHOD SetDebugState(CorDebugThreadState state);
6063 COM_METHOD GetDebugState(CorDebugThreadState *pState);
6064 COM_METHOD GetUserState(CorDebugUserState *pState);
6065 COM_METHOD GetCurrentException(ICorDebugValue ** ppExceptionObject);
6066 COM_METHOD ClearCurrentException();
6067 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
6068 COM_METHOD EnumerateChains(ICorDebugChainEnum **ppChains);
6069 COM_METHOD GetActiveChain(ICorDebugChain **ppChain);
6070 COM_METHOD GetActiveFrame(ICorDebugFrame **ppFrame);
6071 COM_METHOD GetRegisterSet(ICorDebugRegisterSet **ppRegisters);
6072 COM_METHOD CreateEval(ICorDebugEval **ppEval);
6073 COM_METHOD GetObject(ICorDebugValue ** ppObject);
6076 COM_METHOD GetConnectionID(CONNID * pConnectionID);
6077 COM_METHOD GetTaskID(TASKID * pTaskID);
6078 COM_METHOD GetVolatileOSThreadID(DWORD * pdwTID);
6079 COM_METHOD GetActiveFunctions(ULONG32 cFunctions, ULONG32 * pcFunctions, COR_ACTIVE_FUNCTION pFunctions[]);
6080 // Intercept the current exception at the specified frame. pFrame must be a valid ICDFrame, possibly from
6081 // a previous stackwalk.
6082 COM_METHOD InterceptCurrentException(ICorDebugFrame * pFrame);
6087 COM_METHOD CreateStackWalk(ICorDebugStackWalk **ppStackWalk);
6089 COM_METHOD GetActiveInternalFrames(ULONG32 cInternalFrames,
6090 ULONG32 * pcInternalFrames,
6091 ICorDebugInternalFrame2 * ppInternalFrames[]);
6094 COM_METHOD HasUnhandledException();
6096 COM_METHOD GetBlockingObjects(ICorDebugBlockingObjectEnum **ppBlockingObjectEnum);
6098 // Gets the current CustomNotification object from the thread or NULL if no such object exists
6099 COM_METHOD GetCurrentCustomDebuggerNotification(ICorDebugValue ** ppNotificationObject);
6100 //-----------------------------------------------------------
6102 //-----------------------------------------------------------
6104 // callback used to enumerate the internal frames on a thread
6105 static void GetActiveInternalFramesCallback(const DebuggerIPCE_STRData * pFrameData,
6108 CorDebugUserState GetUserState();
6110 // Given a FramePointer, find the matching CordbFrame.
6111 HRESULT FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp);
6113 // Get the task ID for this thread.
6116 void RefreshStack();
6117 void CleanupStack();
6118 void MarkStackFramesDirty();
6120 #if !defined(DBG_TARGET_ARM) // @ARMTODO
6122 #if defined(DBG_TARGET_X86)
6123 // Converts the values in the floating point register area of the context to real number values.
6124 void Get32bitFPRegisters(CONTEXT * pContext);
6126 #elif defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_ARM64)
6127 // Converts the values in the floating point register area of the context to real number values.
6128 void Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters);
6129 #endif // DBG_TARGET_X86
6131 // Initializes the float state members of this instance of CordbThread. This function gets the context and
6132 // converts the floating point values from their context representation to real number values.
6133 void LoadFloatState();
6135 #endif //!DBG_TARGET_ARM @ARMTODO
6137 HRESULT SetIP( bool fCanSetIPOnly,
6138 CordbNativeCode * pNativeCode,
6142 // Tells the LS to remap to the latest version of the function
6143 HRESULT SetRemapIP(SIZE_T offset);
6145 // Ask the left-side for the current (up-to-date) AppDomain of this thread's IP.
6146 // This should be preferred over using the cached value from GetAppDomain.
6147 HRESULT GetCurrentAppDomain(CordbAppDomain ** ppAppDomain);
6149 //-----------------------------------------------------------
6150 // Convenience routines
6151 //-----------------------------------------------------------
6153 // The last domain from which a debug event for this thread was sent.
6154 // This usually (but not always) the domain the thread is currently executing in.
6155 // Since this is a cache, it may sometimes be out-of-date. I believe all current
6156 // usage of this is OK (we pass AppDomains around a lot without really using them),
6157 // but no new code should rely on this value.
6158 // TODO: eliminate this and the m_pAppDomain field entirely
6159 CordbAppDomain *GetAppDomain()
6161 return (m_pAppDomain);
6164 DWORD GetVolatileOSThreadID();
6166 //////////////////////////////////////////////////////////////////////////
6170 // <TODO>TODO: Since Thread will share the memory with RegisterSets, how
6171 // do we know that the RegisterSets have relinquished all pointers
6172 // to the m_pContext structure?</TODO>
6174 // Returns: NULL if the thread's CONTEXT structure couldn't be obtained
6175 // A pointer to the CONTEXT otherwise.
6178 //////////////////////////////////////////////////////////////////////////
6179 HRESULT GetManagedContext( DT_CONTEXT ** ppContext );
6180 HRESULT SetManagedContext( DT_CONTEXT * pContext );
6182 // API to retrieve the thread handle from the LS.
6183 void InternalGetHandle(HANDLE * phThread);
6184 void RefreshHandle(HANDLE * phThread);
6186 // NeuterList that's executed when this Thread's stack is refreshed.
6187 // Chain + Frame + some Value enums can be held on this.
6188 NeuterList * GetRefreshStackNeuterList()
6190 return &m_RefreshStackNeuterList;
6193 DWORD GetUniqueId();
6196 // Hijack a thread at a 2nd-chance exception so that it can execute the CLR's UEF
6197 void HijackForUnhandledException();
6199 // check whether the specified frame lives on the stack of the current thread
6200 bool OwnsFrame(CordbFrame *pFrame);
6202 // Specify that there's an outstanding exception on this thread.
6203 void SetExInfo(VMPTR_OBJECTHANDLE vmExcepObjHandle);
6205 VMPTR_OBJECTHANDLE GetThreadExceptionRawObjectHandle() { return m_vmExcepObjHandle; }
6206 bool HasException() { return m_fException; }
6208 void SetUnhandledNativeException(const EXCEPTION_RECORD * pExceptionRecord);
6209 bool HasUnhandledNativeException();
6212 // Helper to assert that this thread no longer appears in dac-dbi enumerations
6213 void DbgAssertThreadDeleted();
6215 // Callback for DbgAssertThreadDeleted
6216 static void DbgAssertThreadDeletedCallback(VMPTR_Thread vmThread, void * pUserData);
6219 // Determine if the thread's current exception is managed or unmanaged.
6220 BOOL IsThreadExceptionManaged();
6222 // This is a private hook for the shim to create a CordbRegisterSet for a ShimChain.
6223 void CreateCordbRegisterSet(DT_CONTEXT * pContext,
6225 CorDebugChainReason reason,
6226 ICorDebugRegisterSet ** ppRegSet);
6228 // This is a private hook for the shim to convert an ICDFrame into an ICDInternalFrame for a dynamic
6229 // method. Refer to the function header for more information.
6230 BOOL ConvertFrameForILMethodWithoutMetadata(ICorDebugFrame * pFrame,
6231 ICorDebugInternalFrame2 ** ppInternalFrame2);
6233 // Gets/sets m_fCreationEventQueued
6234 bool CreateEventWasQueued();
6235 void SetCreateEventQueued();
6237 //-----------------------------------------------------------
6239 //-----------------------------------------------------------
6242 // RS Cache for LS context.
6243 // NULL if we haven't allocated memory for a Right side context
6244 DT_CONTEXT * m_pContext;
6246 // Set to the CONTEXT pointer in the LS if this LS thread is
6247 // stopped in managed code. This may be either stopped for execution control
6248 // (breakpoint / single-step exception) or hijacked w/ a redirected frame because
6249 // another thread synced the LS.
6250 // This context is used by the RS to set enregistered vars.
6251 VMPTR_CONTEXT m_vmLeftSideContext;
6253 // indicates whether m_pContext is up-to-date
6254 bool m_fContextFresh;
6256 // last domain we've seen this thread.
6257 // If the appdomain exits, it will clear out this value.
6258 CordbAppDomain *m_pAppDomain;
6260 // Handle to VM's Thread* object. This is the primary key for a CordbThread object
6261 // @dbgtodo ICDThread - merge with m_id;
6262 VMPTR_Thread m_vmThreadToken;
6264 // Unique ID for this thread. See code:CordbThread::GetID for semantics of this field.
6267 CorDebugThreadState m_debugState; // Note that this is for resume
6268 // purposes, NOT the current state of
6271 // The frames are all protected under the Stop-Go lock.
6272 // This field indicates whether the stack is valid (i.e. no update is necessary).
6273 bool m_fFramesFresh;
6275 // This is a cache of V3 ICDFrames. The cache is only used by two functions:
6276 // - code:CordbThread::GetActiveFunctions
6277 // - code:CordbThread::InterceptCurrentException.
6279 // We don't clear the cache in CleanupStack() because we don't refresh the cache every time we stop.
6280 // Instead, we mark m_fFramesFresh in CleanupStack() and clear the cache only when it is used next time.
6281 CDynArray<CordbFrame *> m_stackFrames;
6283 #if !defined(DBG_TARGET_ARM) // @ARMTODO
6284 bool m_fFloatStateValid;
6285 unsigned int m_floatStackTop;
6286 double m_floatValues[DebuggerIPCE_FloatCount];
6287 #endif // !DBG_TARGET_ARM @ARMTODO
6290 // True for the window after an Exception callback, but before it's been continued.
6291 // We dispatch two exception events in a row (ICDManagedCallback::Exception and ICDManagedCallback2::Exception),
6292 // and a debugger may normally just skip the first one knowing it can stop on the 2nd once.
6293 // Both events will set this bit high. Be careful not to reset this bit inbetween them.
6296 // True if a creation event has been queued for this thread
6297 // The event may or may not have been dispatched yet
6298 // Bugfix DevDiv2\DevDiv 77523 - this is only being set from ShimProcess::QueueFakeThreadAttachEventsNativeOrder
6299 bool m_fCreationEventQueued;
6301 // Object handle for Exception object in debuggee.
6302 VMPTR_OBJECTHANDLE m_vmExcepObjHandle;
6306 //Returns true if current user state of a thread is USER_WAIT_SLEEP_JOIN
6307 bool IsThreadWaitingOrSleeping();
6309 // Returns true if the thread is dead. See function header for definition.
6310 bool IsThreadDead();
6312 // Return CORDBG_E_BAD_THREAD_STATE if the thread is dead.
6313 HRESULT EnsureThreadIsAlive();
6315 // On a RemapBreakpoint, the debugger will eventually call RemapFunction and
6316 // we need to communicate the IP back to LS. So we stash the address of where
6317 // to store the IP here and stuff it in on RemapFunction.
6318 // If we're not at an outstanding RemapOpportunity, this will be NULL
6319 REMOTE_PTR m_EnCRemapFunctionIP;
6322 void ClearStackFrameCache();
6324 // True iff this thread has an unhandled exception on it.
6325 // Set high when Filter() gets noitifed of an unhandled exception.
6326 // Set Low if the thread is hijacked.
6327 bool m_fHasUnhandledException;
6329 // Exception record for last unhandled exception on this thread.
6330 // Lazily initialized.
6331 EXCEPTION_RECORD * m_pExceptionRecord;
6333 static const CorDebugUserState kInvalidUserState = CorDebugUserState(-1);
6334 CorDebugUserState m_userState; // This is the current state of the
6335 // thread, at the time that the
6336 // left side synchronized
6338 // NeuterList that's executed when this Thread's stack is refreshed.
6339 // This list is for everything related to stackwalking, i.e. everything which is invalidated
6340 // if the stack changes in any way. This list is cleared when any of the following is called:
6343 // 3) RemapFunction()
6344 // 4) ICDProcess::SetThreadContext()
6345 NeuterList m_RefreshStackNeuterList;
6347 // The following two data members are used for caching thread handles.
6348 // @dbgtodo - Remove in V3 (can't have local handles with data-target abstraction);
6349 // offload to the shim to support V2 scenarios.
6350 HANDLE m_hCachedThread;
6351 HANDLE m_hCachedOutOfProcThread;
6354 /* ------------------------------------------------------------------------- *
6356 * ------------------------------------------------------------------------- */
6358 class CordbStackWalk : public CordbBase, public ICorDebugStackWalk
6361 CordbStackWalk(CordbThread * pCordbThread);
6362 virtual ~CordbStackWalk();
6363 virtual void Neuter();
6365 // helper function for Neuter
6366 virtual void DeleteAll();
6368 using CordbBase::GetProcess;
6371 virtual const char * DbgGetName() { return "CordbStackWalk"; }
6374 //-----------------------------------------------------------
6376 //-----------------------------------------------------------
6378 ULONG STDMETHODCALLTYPE AddRef()
6380 return (BaseAddRef());
6382 ULONG STDMETHODCALLTYPE Release()
6384 return (BaseRelease());
6386 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6388 //-----------------------------------------------------------
6389 // ICorDebugStackWalk
6390 //-----------------------------------------------------------
6392 COM_METHOD GetContext(ULONG32 contextFlags,
6393 ULONG32 contextBufSize,
6394 ULONG32 * pContextSize,
6395 BYTE pbContextBuf[]);
6396 COM_METHOD SetContext(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[]);
6398 COM_METHOD GetFrame(ICorDebugFrame **ppFrame);
6400 //-----------------------------------------------------------
6402 //-----------------------------------------------------------
6404 void SetContextWorker(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[]);
6405 HRESULT GetFrameWorker(ICorDebugFrame **ppFrame);
6407 //-----------------------------------------------------------
6409 //-----------------------------------------------------------
6415 // handle legacy V2 hijacking for unhandled hardware exceptions
6416 void CheckForLegacyHijackCase();
6418 // refresh the data for this instance of CordbStackWalk if we have had an IPC event followed by a
6419 // continue since we got the information.
6420 void RefreshIfNeeded();
6422 // unwind the frame and update m_context with the new context
6423 BOOL UnwindStackFrame();
6425 // the thread on which this CordbStackWalk is created
6426 CordbThread * m_pCordbThread;
6428 // This is the same iterator used by the runtime itself.
6429 IDacDbiInterface::StackWalkHandle m_pSFIHandle;
6431 // buffers used for stackwalking
6432 DT_CONTEXT m_context;
6434 // Used to figure out if we have to refresh any reference objects
6435 // on the left side. We set it to CordbProcess::m_flushCounter on
6436 // creation and will check it against that value when we call GetFrame or Next.
6437 // If it doesn't match, an IPC event has occurred and the values will need to be
6438 // refreshed via the DAC.
6439 UINT m_lastSyncFlushCounter;
6441 // cached flag used for refreshing a CordbStackWalk
6442 CorDebugSetContextFlag m_cachedSetContextFlag;
6444 // We unwind one frame ahead of time to get the FramePointer on x86.
6445 // These fields are used for the bookkeeping.
6446 RSSmartPtr<CordbFrame> m_pCachedFrame;
6448 bool m_fIsOneFrameAhead;
6452 class CordbContext : public CordbBase, public ICorDebugContext
6456 CordbContext() : CordbBase(NULL, 0, enumCordbContext) {}
6461 virtual const char * DbgGetName() { return "CordbContext"; }
6465 //-----------------------------------------------------------
6467 //-----------------------------------------------------------
6469 ULONG STDMETHODCALLTYPE AddRef()
6471 return (BaseAddRef());
6473 ULONG STDMETHODCALLTYPE Release()
6475 return (BaseRelease());
6477 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6479 //-----------------------------------------------------------
6481 //-----------------------------------------------------------
6487 /* ------------------------------------------------------------------------- *
6489 * ------------------------------------------------------------------------- */
6491 class CordbFrame : public CordbBase, public ICorDebugFrame
6494 // Ctor to provide dummy frame that just wraps a frame-pointer
6495 CordbFrame(CordbProcess * pProcess, FramePointer fp);
6498 CordbFrame(CordbThread * pThread,
6501 CordbAppDomain * pCurrentAppDomain);
6503 virtual ~CordbFrame();
6504 virtual void Neuter();
6507 virtual const char * DbgGetName() { return "CordbFrame"; }
6510 //-----------------------------------------------------------
6512 //-----------------------------------------------------------
6514 ULONG STDMETHODCALLTYPE AddRef()
6516 return (BaseAddRef());
6518 ULONG STDMETHODCALLTYPE Release()
6520 return (BaseRelease());
6522 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6524 //-----------------------------------------------------------
6526 //-----------------------------------------------------------
6528 COM_METHOD GetChain(ICorDebugChain **ppChain);
6530 // Derived versions of Frame will implement GetCode.
6531 COM_METHOD GetCode(ICorDebugCode **ppCode) = 0;
6533 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
6534 COM_METHOD GetFunctionToken(mdMethodDef *pToken);
6536 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
6537 COM_METHOD GetCaller(ICorDebugFrame **ppFrame);
6538 COM_METHOD GetCallee(ICorDebugFrame **ppFrame);
6539 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
6541 //-----------------------------------------------------------
6542 // Convenience routines
6543 //-----------------------------------------------------------
6545 CordbAppDomain *GetCurrentAppDomain()
6547 return m_currentAppDomain;
6550 // Internal helper to get a CordbFunction for this frame.
6551 virtual CordbFunction *GetFunction() = 0;
6553 FramePointer GetFramePointer()
6558 //-----------------------------------------------------------
6560 //-----------------------------------------------------------
6562 // Accessors to return NULL or typesafe cast to derived frame
6563 virtual CordbInternalFrame * GetAsInternalFrame() { return NULL; }
6564 virtual CordbNativeFrame * GetAsNativeFrame() { return NULL; }
6566 // determine if the frame pointer is in the stack range owned by the frame
6567 bool IsContainedInFrame(FramePointer fp);
6569 // This is basically a complicated cast function. We are casting from an ICorDebugFrame to a CordbFrame.
6570 static CordbFrame* GetCordbFrameFromInterface(ICorDebugFrame *pFrame);
6572 virtual const DT_CONTEXT * GetContext() const { return NULL; }
6575 // this represents the IL offset for a CordbJITILFrame, the native offset for a CordbNativeFrame,
6576 // and 0 for a CordbInternalFrame
6579 CordbThread * m_pThread;
6581 CordbAppDomain *m_currentAppDomain;
6585 // indicates whether this frame is the leaf frame; lazily initialized
6586 mutable Optional<bool> m_optfIsLeafFrame;
6590 // For tracking down neutering bugs;
6591 UINT m_DbgContinueCounter;
6595 // Dummy frame that just wraps a frame pointer.
6596 // This is used to pass a FramePointer back in the Exception2 callback.
6597 // Currently, the callback passes back an ICorDebugFrame as a way of exposing a cross-platform
6598 // frame pointer. However passing back an ICDFrame means we need to do a stackwalk, and
6599 // that may not be possible in V3:
6600 // - the stackwalk is very chatty, and may be too much work just to give an exception notification.
6601 // - in 64-bit, we may not even be able to do the stackwalk ourselves.
6603 // The shim can take the framePointer and do the stackwalk and resolve it to a real frame,
6604 // so V2 emulation scenarios will continue to work.
6605 // @dbgtodo exception - resolve this when we iron out exceptions in V3.
6606 class CordbPlaceholderFrame : public CordbFrame
6609 // Ctor to provide dummy frame that just wraps a frame-pointer
6610 CordbPlaceholderFrame(CordbProcess * pProcess, FramePointer fp)
6611 : CordbFrame(pProcess, fp)
6616 virtual const char * DbgGetName() { return "CordbFrame"; }
6619 // Provide dummy implementation for some methods. These should never be called.
6620 COM_METHOD GetCode(ICorDebugCode **ppCode)
6622 _ASSERTE(!"Don't call this");
6625 virtual CordbFunction *GetFunction()
6627 _ASSERTE(!"Don't call this");
6632 class CordbInternalFrame : public CordbFrame, public ICorDebugInternalFrame, public ICorDebugInternalFrame2
6635 CordbInternalFrame(CordbThread * pThread,
6637 CordbAppDomain * pCurrentAppDomain,
6638 const DebuggerIPCE_STRData * pData);
6640 CordbInternalFrame(CordbThread * pThread,
6642 CordbAppDomain * pCurrentAppDomain,
6643 CorDebugInternalFrameType frameType,
6644 mdMethodDef funcMetadataToken,
6645 CordbFunction * pFunction,
6646 VMPTR_MethodDesc vmMethodDesc);
6648 virtual void Neuter();
6651 virtual const char * DbgGetName() { return "CordbInternalFrame"; }
6654 //-----------------------------------------------------------
6656 //-----------------------------------------------------------
6658 ULONG STDMETHODCALLTYPE AddRef()
6660 return (BaseAddRef());
6662 ULONG STDMETHODCALLTYPE Release()
6664 return (BaseRelease());
6666 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6668 //-----------------------------------------------------------
6670 //-----------------------------------------------------------
6672 COM_METHOD GetChain(ICorDebugChain **ppChain)
6674 return (CordbFrame::GetChain(ppChain));
6677 // We don't expose a code-object for stubs.
6678 COM_METHOD GetCode(ICorDebugCode **ppCode)
6680 return CORDBG_E_CODE_NOT_AVAILABLE;
6683 COM_METHOD GetFunction(ICorDebugFunction **ppFunction)
6685 return (CordbFrame::GetFunction(ppFunction));
6687 COM_METHOD GetFunctionToken(mdMethodDef *pToken)
6689 return (CordbFrame::GetFunctionToken(pToken));
6692 COM_METHOD GetCaller(ICorDebugFrame **ppFrame)
6694 return (CordbFrame::GetCaller(ppFrame));
6696 COM_METHOD GetCallee(ICorDebugFrame **ppFrame)
6698 return (CordbFrame::GetCallee(ppFrame));
6700 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper)
6705 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
6707 //-----------------------------------------------------------
6708 // ICorDebugInternalFrame
6709 //-----------------------------------------------------------
6711 // Get the type of internal frame. This will never be STUBFRAME_NONE.
6712 COM_METHOD GetFrameType(CorDebugInternalFrameType * pType)
6714 VALIDATE_POINTER_TO_OBJECT(pType, CorDebugInternalFrameType)
6715 *pType = m_eFrameType;
6719 //-----------------------------------------------------------
6720 // ICorDebugInternalFrame2
6721 //-----------------------------------------------------------
6723 COM_METHOD GetAddress(CORDB_ADDRESS * pAddress);
6724 COM_METHOD IsCloserToLeaf(ICorDebugFrame * pFrameToCompare,
6727 BOOL IsCloserToLeafWorker(ICorDebugFrame * pFrameToCompare);
6729 //-----------------------------------------------------------
6731 //-----------------------------------------------------------
6733 virtual CordbFunction *GetFunction();
6736 // Accessors to return NULL or typesafe cast to derived frame
6737 virtual CordbInternalFrame * GetAsInternalFrame() { return this; }
6739 // accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata
6740 BOOL ConvertInternalFrameForILMethodWithoutMetadata(ICorDebugInternalFrame2 ** ppInternalFrame2);
6744 CorDebugInternalFrameType m_eFrameType;
6746 // the method token of the method (if any) associated with the internal frame
6747 mdMethodDef m_funcMetadataToken;
6749 // the method (if any) associated with the internal frame
6750 RSSmartPtr<CordbFunction> m_function;
6752 VMPTR_MethodDesc m_vmMethodDesc;
6755 //---------------------------------------------------------------------------------------
6757 // This class implements ICorDebugRuntimeUnwindableFrame. It is used to mark a native stack frame
6758 // which requires special unwinding and which doesn't correspond to any IL code. It is really
6759 // just a marker to tell the debugger to use the managed unwinder. The debugger is still responsible
6760 // to do all the inspection and symbol lookup. An example is the hijack stub.
6763 class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUnwindableFrame
6766 CordbRuntimeUnwindableFrame(CordbThread * pThread,
6768 CordbAppDomain * pCurrentAppDomain,
6769 DT_CONTEXT * pContext);
6771 virtual void Neuter();
6774 virtual const char * DbgGetName() { return "CordbRuntimeUnwindableFrame"; }
6777 //-----------------------------------------------------------
6779 //-----------------------------------------------------------
6781 ULONG STDMETHODCALLTYPE AddRef()
6783 return (BaseAddRef());
6786 ULONG STDMETHODCALLTYPE Release()
6788 return (BaseRelease());
6791 COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
6793 //-----------------------------------------------------------
6795 //-----------------------------------------------------------
6798 // Just return E_NOTIMPL for everything.
6799 // See the class comment.
6802 COM_METHOD GetChain(ICorDebugChain ** ppChain)
6807 COM_METHOD GetCode(ICorDebugCode ** ppCode)
6812 COM_METHOD GetFunction(ICorDebugFunction ** ppFunction)
6817 COM_METHOD GetFunctionToken(mdMethodDef * pToken)
6822 COM_METHOD GetCaller(ICorDebugFrame ** ppFrame)
6827 COM_METHOD GetCallee(ICorDebugFrame ** ppFrame)
6832 COM_METHOD CreateStepper(ICorDebugStepper ** ppStepper)
6837 COM_METHOD GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd)
6842 //-----------------------------------------------------------
6844 //-----------------------------------------------------------
6846 virtual CordbFunction * GetFunction()
6851 virtual const DT_CONTEXT * GetContext() const;
6854 DT_CONTEXT m_context;
6858 class CordbValueEnum : public CordbBase, public ICorDebugValueEnum
6861 enum ValueEnumMode {
6862 LOCAL_VARS_ORIGINAL_IL,
6863 LOCAL_VARS_REJIT_IL,
6867 CordbValueEnum(CordbNativeFrame *frame, ValueEnumMode mode);
6870 virtual void Neuter();
6873 virtual const char * DbgGetName() { return "CordbValueEnum"; }
6877 //-----------------------------------------------------------
6879 //-----------------------------------------------------------
6881 ULONG STDMETHODCALLTYPE AddRef()
6883 return (BaseAddRef());
6885 ULONG STDMETHODCALLTYPE Release()
6887 return (BaseRelease());
6889 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6891 //-----------------------------------------------------------
6893 //-----------------------------------------------------------
6895 COM_METHOD Skip(ULONG celt);
6897 COM_METHOD Clone(ICorDebugEnum **ppEnum);
6898 COM_METHOD GetCount(ULONG *pcelt);
6900 //-----------------------------------------------------------
6901 // ICorDebugValueEnum
6902 //-----------------------------------------------------------
6904 COM_METHOD Next(ULONG celt, ICorDebugValue *values[], ULONG *pceltFetched);
6907 CordbNativeFrame* m_frame;
6908 ValueEnumMode m_mode;
6914 /* ------------------------------------------------------------------------- *
6915 * Misc Info for the Native Frame class
6916 * ------------------------------------------------------------------------- */
6918 struct CordbMiscFrame
6923 // new-style constructor
6924 CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData);
6926 #ifdef WIN64EXCEPTIONS
6928 FramePointer fpParentOrSelf;
6929 bool fIsFilterFunclet;
6930 #endif // WIN64EXCEPTIONS
6934 /* ------------------------------------------------------------------------- *
6935 * Native Frame class
6936 * ------------------------------------------------------------------------- */
6938 class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public ICorDebugNativeFrame2
6941 CordbNativeFrame(CordbThread * pThread,
6943 CordbNativeCode * pNativeCode,
6945 DebuggerREGDISPLAY * pDRD,
6946 TADDR addrAmbientESP,
6947 bool fQuicklyUnwound,
6948 CordbAppDomain * pCurrentAppDomain,
6949 CordbMiscFrame * pMisc = NULL,
6950 DT_CONTEXT * pContext = NULL);
6951 virtual ~CordbNativeFrame();
6952 virtual void Neuter();
6955 virtual const char * DbgGetName() { return "CordbNativeFrame"; }
6958 //-----------------------------------------------------------
6960 //-----------------------------------------------------------
6962 ULONG STDMETHODCALLTYPE AddRef()
6964 return (BaseAddRef());
6966 ULONG STDMETHODCALLTYPE Release()
6968 return (BaseRelease());
6970 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6972 //-----------------------------------------------------------
6974 //-----------------------------------------------------------
6976 COM_METHOD GetChain(ICorDebugChain **ppChain)
6978 return (CordbFrame::GetChain(ppChain));
6980 COM_METHOD GetCode(ICorDebugCode **ppCode);
6981 COM_METHOD GetFunction(ICorDebugFunction **ppFunction)
6983 return (CordbFrame::GetFunction(ppFunction));
6985 COM_METHOD GetFunctionToken(mdMethodDef *pToken)
6987 return (CordbFrame::GetFunctionToken(pToken));
6989 COM_METHOD GetCaller(ICorDebugFrame **ppFrame)
6991 return (CordbFrame::GetCaller(ppFrame));
6993 COM_METHOD GetCallee(ICorDebugFrame **ppFrame)
6995 return (CordbFrame::GetCallee(ppFrame));
6997 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper)
6999 return (CordbFrame::CreateStepper(ppStepper));
7002 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
7004 //-----------------------------------------------------------
7005 // ICorDebugNativeFrame
7006 //-----------------------------------------------------------
7008 COM_METHOD GetIP(ULONG32* pnOffset);
7009 COM_METHOD SetIP(ULONG32 nOffset);
7010 COM_METHOD GetRegisterSet(ICorDebugRegisterSet **ppRegisters);
7011 COM_METHOD GetLocalRegisterValue(CorDebugRegister reg,
7013 PCCOR_SIGNATURE pvSigBlob,
7014 ICorDebugValue ** ppValue);
7016 COM_METHOD GetLocalDoubleRegisterValue(CorDebugRegister highWordReg,
7017 CorDebugRegister lowWordReg,
7019 PCCOR_SIGNATURE pvSigBlob,
7020 ICorDebugValue ** ppValue);
7022 COM_METHOD GetLocalMemoryValue(CORDB_ADDRESS address,
7024 PCCOR_SIGNATURE pvSigBlob,
7025 ICorDebugValue ** ppValue);
7027 COM_METHOD GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
7028 CORDB_ADDRESS lowWordAddress,
7030 PCCOR_SIGNATURE pvSigBlob,
7031 ICorDebugValue ** ppValue);
7033 COM_METHOD GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
7034 CorDebugRegister lowWordRegister,
7036 PCCOR_SIGNATURE pvSigBlob,
7037 ICorDebugValue ** ppValue);
7039 COM_METHOD CanSetIP(ULONG32 nOffset);
7041 //-----------------------------------------------------------
7042 // ICorDebugNativeFrame2
7043 //-----------------------------------------------------------
7045 COM_METHOD IsChild(BOOL * pIsChild);
7047 COM_METHOD IsMatchingParentFrame(ICorDebugNativeFrame2 *pPotentialParentFrame,
7050 COM_METHOD GetStackParameterSize(ULONG32 * pSize);
7052 //-----------------------------------------------------------
7054 //-----------------------------------------------------------
7056 // Accessors to return NULL or typesafe cast to derived frame
7057 virtual CordbNativeFrame * GetAsNativeFrame() { return this; }
7059 CordbFunction * GetFunction();
7060 CordbNativeCode * GetNativeCode();
7061 virtual const DT_CONTEXT * GetContext() const;
7063 // Given the native variable information of a variable, return its value.
7064 // This function assumes that the value is either in a register or on the stack
7065 // (i.e. VLT_REG or VLT_STK).
7066 SIZE_T GetRegisterOrStackValue(const ICorDebugInfo::NativeVarInfo * pNativeVarInfo);
7068 HRESULT GetLocalRegisterValue(CorDebugRegister reg,
7070 ICorDebugValue **ppValue);
7071 HRESULT GetLocalDoubleRegisterValue(CorDebugRegister highWordReg,
7072 CorDebugRegister lowWordReg,
7074 ICorDebugValue **ppValue);
7075 HRESULT GetLocalMemoryValue(CORDB_ADDRESS address,
7077 ICorDebugValue **ppValue);
7078 HRESULT GetLocalByRefMemoryValue(CORDB_ADDRESS address,
7080 ICorDebugValue **ppValue);
7081 HRESULT GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
7082 CORDB_ADDRESS lowWordAddress,
7084 ICorDebugValue **ppValue);
7085 HRESULT GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
7086 CorDebugRegister lowWordRegister,
7088 ICorDebugValue **ppValue);
7089 UINT_PTR * GetAddressOfRegister(CorDebugRegister regNum) const;
7090 CORDB_ADDRESS GetLeftSideAddressOfRegister(CorDebugRegister regNum) const;
7091 #if !defined(DBG_TARGET_ARM) // @ARMTODO
7092 HRESULT GetLocalFloatingPointValue(DWORD index,
7094 ICorDebugValue **ppValue);
7095 #endif // !DBG_TARGET_ARM @ARMTODO
7098 CORDB_ADDRESS GetLSStackAddress(ICorDebugInfo::RegNum regNum, signed offset);
7100 bool IsLeafFrame() const;
7102 // Return the offset used for inspection purposes.
7103 // Refer to the comment at the beginning of the function definition in RsThread.cpp for more information.
7104 SIZE_T GetInspectionIP();
7106 ULONG32 GetIPOffset();
7108 // whether this is a funclet frame
7110 bool IsFilterFunclet();
7112 #if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
7113 // return the offset of the parent method frame at which an exception occurs
7114 SIZE_T GetParentIP();
7115 #endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM
7117 TADDR GetAmbientESP() { return m_taAmbientESP; }
7118 TADDR GetReturnRegisterValue();
7120 // accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata
7121 BOOL ConvertNativeFrameForILMethodWithoutMetadata(ICorDebugInternalFrame2 ** ppInternalFrame2);
7123 //-----------------------------------------------------------
7125 //-----------------------------------------------------------
7129 DebuggerREGDISPLAY m_rd;
7131 // This field is only true for Enter-Managed chain. It means that the register set is invalid.
7132 bool m_quicklyUnwound;
7134 // each CordbNativeFrame corresponds to exactly one CordbJITILFrame and one CordbNativeCode
7135 RSSmartPtr<CordbJITILFrame> m_JITILFrame;
7136 RSSmartPtr<CordbNativeCode> m_nativeCode;
7138 // auxiliary information only used on 64-bit to find the parent stack pointer and offset for funclets
7139 CordbMiscFrame m_misc;
7142 // the ambient SP value only used on x86 to retrieve sp-relative local variables
7143 // (most likely in a frameless method)
7144 TADDR m_taAmbientESP;
7146 // @dbgtodo inspection - When we DACize the various Cordb*Value classes, we should consider getting rid of the
7147 // DebuggerREGDISPLAY and just use the CONTEXT. A lot of simplification can be done here.
7148 DT_CONTEXT m_context;
7152 /* ------------------------------------------------------------------------- *
7153 * CordbRegisterSet class
7155 * This can be obtained via GetRegisterSet from
7159 * ------------------------------------------------------------------------- */
7161 #define SETBITULONG64( x ) ( (ULONG64)1 << (x) )
7162 #define SET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] |= (1 << ((_reg) & 7)))
7163 #define RESET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] &= ~(1 << ((_reg) & 7)))
7164 #define IS_SET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] & (1 << ((_reg) & 7)))
7167 class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public ICorDebugRegisterSet2
7170 CordbRegisterSet(DebuggerREGDISPLAY * pRegDisplay,
7171 CordbThread * pThread,
7174 bool fTakeOwnershipOfDRD = false);
7177 ~CordbRegisterSet();
7181 virtual void Neuter();
7184 virtual const char * DbgGetName() { return "CordbRegisterSet"; }
7187 //-----------------------------------------------------------
7189 //-----------------------------------------------------------
7191 ULONG STDMETHODCALLTYPE AddRef()
7193 return (BaseAddRefEnforceExternal());
7195 ULONG STDMETHODCALLTYPE Release()
7197 return (BaseReleaseEnforceExternal());
7200 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7204 //-----------------------------------------------------------
7205 // ICorDebugRegisterSet
7206 // More extensive explanation are in Src/inc/CorDebug.idl
7207 //-----------------------------------------------------------
7208 COM_METHOD GetRegistersAvailable(ULONG64 *pAvailable);
7210 COM_METHOD GetRegisters(ULONG64 mask,
7212 CORDB_REGISTER regBuffer[]);
7213 COM_METHOD SetRegisters( ULONG64 mask,
7215 CORDB_REGISTER regBuffer[])
7217 LIMITED_METHOD_CONTRACT;
7219 VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER,
7220 regCount, true, true);
7225 COM_METHOD GetThreadContext(ULONG32 contextSize, BYTE context[]);
7227 // SetThreadContexthad a very problematic implementation in v1.1.
7228 // We've ripped it out in V2.0 and E_NOTIMPL it. See V1.1 sources for what it used to look like
7229 // in case we ever want to re-add it.
7230 // If we ever re-implement it consider the following:
7231 // - must fail on non-leaf frames (just check m_active).
7232 // - must make sure that GetThreadContext() is fully accurate. If we don't have SetThCtx, then
7233 // GetThreadCtx bugs are much more benign.
7234 // - be sure to update any shared reg displays (what if a frame + chain have the same rd) and
7235 // also update any cached contexts (such as CordbThread::m_context).
7236 // - be sure to honor the context flags and only setting what we can set.
7238 // Friday, July 16, 2004. (This date will be useful for Source control history)
7239 COM_METHOD SetThreadContext(ULONG32 contextSize, BYTE context[])
7244 //-----------------------------------------------------------
7245 // ICorDebugRegisterSet2
7246 // More extensive explanation are in Src/inc/CorDebug.idl
7247 //-----------------------------------------------------------
7248 COM_METHOD GetRegistersAvailable(ULONG32 regCount,
7251 COM_METHOD GetRegisters(ULONG32 maskCount,
7254 CORDB_REGISTER regBuffer[]);
7256 COM_METHOD SetRegisters(ULONG32 maskCount,
7259 CORDB_REGISTER regBuffer[])
7261 LIMITED_METHOD_CONTRACT;
7263 VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER,
7264 regCount, true, true);
7270 // Platform specific helper for GetThreadContext.
7271 void InternalCopyRDToContext(DT_CONTEXT * pContext);
7273 // Adapters to impl v2.0 interfaces on top of v1.0 interfaces.
7274 HRESULT GetRegistersAvailableAdapter(ULONG32 regCount, BYTE pAvailable[]);
7275 HRESULT GetRegistersAdapter(ULONG32 maskCount, BYTE mask[], ULONG32 regCount, CORDB_REGISTER regBuffer[]);
7278 // This CordbRegisterSet is responsible to free this memory if m_fTakeOwnershipOfDRD is true. Otherwise,
7279 // this memory is freed by the CordbNativeFrame or CordbThread which creates this CordbRegisterSet.
7280 DebuggerREGDISPLAY *m_rd;
7281 CordbThread *m_thread;
7282 bool m_active; // true if we're the leafmost register set.
7285 // true if the CordbRegisterSet owns the DebuggerREGDISPLAY pointer and needs to free the memory
7286 bool m_fTakeOwnershipOfDRD;
7292 /* ------------------------------------------------------------------------- *
7293 * JIT-IL Frame class
7294 * ------------------------------------------------------------------------- */
7296 class CordbJITILFrame : public CordbBase, public ICorDebugILFrame, public ICorDebugILFrame2, public ICorDebugILFrame3, public ICorDebugILFrame4
7299 CordbJITILFrame(CordbNativeFrame * pNativeFrame,
7300 CordbILCode * pCode,
7302 CorDebugMappingResult mapping,
7303 GENERICS_TYPE_TOKEN exactGenericArgsToken,
7304 DWORD dwExactGenericArgsTokenIndex,
7306 CordbReJitILCode * pReJitCode);
7308 virtual ~CordbJITILFrame();
7309 virtual void Neuter();
7313 virtual const char * DbgGetName() { return "CordbJITILFrame"; }
7316 //-----------------------------------------------------------
7318 //-----------------------------------------------------------
7320 ULONG STDMETHODCALLTYPE AddRef()
7322 return (BaseAddRef());
7324 ULONG STDMETHODCALLTYPE Release()
7326 return (BaseRelease());
7328 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7330 //-----------------------------------------------------------
7332 //-----------------------------------------------------------
7334 COM_METHOD GetChain(ICorDebugChain **ppChain);
7335 COM_METHOD GetCode(ICorDebugCode **ppCode);
7336 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
7337 COM_METHOD GetFunctionToken(mdMethodDef *pToken);
7338 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
7339 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
7340 COM_METHOD GetCaller(ICorDebugFrame **ppFrame);
7341 COM_METHOD GetCallee(ICorDebugFrame **ppFrame);
7343 //-----------------------------------------------------------
7345 //-----------------------------------------------------------
7347 COM_METHOD GetIP(ULONG32* pnOffset, CorDebugMappingResult *pMappingResult);
7348 COM_METHOD SetIP(ULONG32 nOffset);
7349 COM_METHOD EnumerateLocalVariables(ICorDebugValueEnum **ppValueEnum);
7350 COM_METHOD GetLocalVariable(DWORD dwIndex, ICorDebugValue **ppValue);
7351 COM_METHOD EnumerateArguments(ICorDebugValueEnum **ppValueEnum);
7352 COM_METHOD GetArgument(DWORD dwIndex, ICorDebugValue ** ppValue);
7353 COM_METHOD GetStackDepth(ULONG32 *pDepth);
7354 COM_METHOD GetStackValue(DWORD dwIndex, ICorDebugValue **ppValue);
7355 COM_METHOD CanSetIP(ULONG32 nOffset);
7357 //-----------------------------------------------------------
7358 // ICorDebugILFrame2
7359 //-----------------------------------------------------------
7361 // Called at an EnC remap opportunity to remap to the latest version of a function
7362 COM_METHOD RemapFunction(ULONG32 nOffset);
7364 COM_METHOD EnumerateTypeParameters(ICorDebugTypeEnum **ppTyParEnum);
7366 //-----------------------------------------------------------
7367 // ICorDebugILFrame3
7368 //-----------------------------------------------------------
7370 COM_METHOD GetReturnValueForILOffset(ULONG32 ILoffset, ICorDebugValue** ppReturnValue);
7372 //-----------------------------------------------------------
7373 // ICorDebugILFrame4
7374 //-----------------------------------------------------------
7376 COM_METHOD EnumerateLocalVariablesEx(ILCodeKind flags, ICorDebugValueEnum **ppValueEnum);
7377 COM_METHOD GetLocalVariableEx(ILCodeKind flags, DWORD dwIndex, ICorDebugValue **ppValue);
7378 COM_METHOD GetCodeEx(ILCodeKind flags, ICorDebugCode **ppCode);
7380 //-----------------------------------------------------------
7382 //-----------------------------------------------------------
7384 CordbModule *GetModule();
7386 HRESULT GetNativeVariable(CordbType *type,
7387 const ICorDebugInfo::NativeVarInfo *pNativeVarInfo,
7388 ICorDebugValue **ppValue);
7390 CordbAppDomain *GetCurrentAppDomain();
7392 CordbFunction *GetFunction();
7394 // ILVariableToNative serves to let the frame intercept accesses
7395 // to var args variables.
7396 HRESULT ILVariableToNative(DWORD dwIndex,
7397 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
7399 // Fills in our array of var args variables
7400 HRESULT FabricateNativeInfo(DWORD dwIndex,
7401 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
7403 HRESULT GetArgumentType(DWORD dwIndex,
7404 CordbType ** ppResultType);
7406 // load the generics type and method arguments into a cache
7407 void LoadGenericArgs();
7409 HRESULT QueryInterfaceInternal(REFIID id, void** pInterface);
7411 // Builds an generic Instaniation object from the mdClass and generic signature
7412 // for what we are calling into.
7413 static HRESULT BuildInstantiationForCallsite(CordbModule *pModule, NewArrayHolder<CordbType*> &types, Instantiation &inst, Instantiation *currentInstantiation, mdToken targetClass, SigParser funcGenerics);
7415 CordbILCode* GetOriginalILCode();
7416 CordbReJitILCode* GetReJitILCode();
7419 void RefreshCachedVarArgSigParserIfNeeded();
7421 // Worker function for GetReturnValueForILOffset.
7422 HRESULT GetReturnValueForILOffsetImpl(ULONG32 ILoffset, ICorDebugValue** ppReturnValue);
7424 // Given pType, fills ppReturnValue with the correct value.
7425 HRESULT GetReturnValueForType(CordbType *pType, ICorDebugValue **ppReturnValue);
7427 //-----------------------------------------------------------
7429 //-----------------------------------------------------------
7432 // each CordbJITILFrame corresponds to exactly one CordbNativeFrame and one CordbILCode
7433 CordbNativeFrame * m_nativeFrame;
7434 CordbILCode * m_ilCode;
7436 // the IL offset and the mapping result for the offset
7438 CorDebugMappingResult m_mapping;
7440 // <vararg-specific fields>
7442 // whether this is a vararg function
7445 // the number of arguments, including the var args
7446 ULONG m_allArgsCount;
7448 // This byte array is used to store the signature for vararg methods.
7449 // It points to the underlying memory used by m_sigParserCached, and it enables us to easily delete
7450 // the underlying memory when the CordbJITILFrame is neutered.
7451 BYTE * m_rgbSigParserBuf;
7453 // Do not mutate this, instead make copies of it and use the copies, that way we are guaranteed to
7454 // start at the correct position in the signature each time.
7455 // The underlying memory used for the signature in the SigParser must not be in the DAC cache.
7456 // Otherwise it may be flushed underneath us, and we would AV when we try to access it.
7457 SigParser m_sigParserCached;
7459 // the address of the first arg; only used for vararg functions
7460 CORDB_ADDRESS m_FirstArgAddr;
7462 // This is an array of variable information for the arguments.
7463 // The variable information is fabricated by the RS.
7464 ICorDebugInfo::NativeVarInfo * m_rgNVI;
7466 // </vararg-specific fields>
7468 Instantiation m_genericArgs; // the generics type arguments
7469 BOOL m_genericArgsLoaded; // whether we have loaded and cached the generics type arguments
7471 // An extra token to help fetch information about any generic
7472 // parameters passed to the method, perhaps dynamically.
7473 // This is the so-called generics type context/token.
7475 // This token comes from the stackwalker and it may be NULL, in which case we need to retrieve the token
7476 // ourselves using m_dwFrameParamsTokenIndex and the variable lifetime information.
7477 GENERICS_TYPE_TOKEN m_frameParamsToken;
7479 // IL Variable index of the Generics Arg Token.
7480 DWORD m_dwFrameParamsTokenIndex;
7482 // if this frame is instrumented with rejit, this will point to the instrumented IL code
7483 RSSmartPtr<CordbReJitILCode> m_pReJitCode;
7486 /* ------------------------------------------------------------------------- *
7488 * ------------------------------------------------------------------------- */
7490 enum CordbBreakpointType
7497 class CordbBreakpoint : public CordbBase, public ICorDebugBreakpoint
7500 CordbBreakpoint(CordbProcess * pProcess, CordbBreakpointType bpType);
7501 virtual void Neuter();
7504 virtual const char * DbgGetName() { return "CordbBreakpoint"; }
7507 //-----------------------------------------------------------
7509 //-----------------------------------------------------------
7511 ULONG STDMETHODCALLTYPE AddRef()
7513 return (BaseAddRef());
7515 ULONG STDMETHODCALLTYPE Release()
7517 return (BaseRelease());
7519 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7521 //-----------------------------------------------------------
7522 // ICorDebugBreakpoint
7523 //-----------------------------------------------------------
7525 COM_METHOD BaseIsActive(BOOL *pbActive);
7527 //-----------------------------------------------------------
7529 //-----------------------------------------------------------
7530 CordbBreakpointType GetBPType()
7535 virtual void Disconnect() {}
7537 CordbAppDomain *GetAppDomain()
7539 return m_pAppDomain;
7541 //-----------------------------------------------------------
7543 //-----------------------------------------------------------
7547 CordbAppDomain *m_pAppDomain;
7548 CordbBreakpointType m_type;
7551 /* ------------------------------------------------------------------------- *
7552 * Function Breakpoint class
7553 * ------------------------------------------------------------------------- */
7555 class CordbFunctionBreakpoint : public CordbBreakpoint,
7556 public ICorDebugFunctionBreakpoint
7559 CordbFunctionBreakpoint(CordbCode *code, SIZE_T offset);
7560 ~CordbFunctionBreakpoint();
7562 virtual void Neuter();
7564 virtual const char * DbgGetName() { return "CordbFunctionBreakpoint"; }
7568 //-----------------------------------------------------------
7570 //-----------------------------------------------------------
7572 ULONG STDMETHODCALLTYPE AddRef()
7574 return (BaseAddRef());
7576 ULONG STDMETHODCALLTYPE Release()
7578 return (BaseRelease());
7580 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7582 //-----------------------------------------------------------
7583 // ICorDebugBreakpoint
7584 //-----------------------------------------------------------
7586 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
7587 COM_METHOD GetOffset(ULONG32 *pnOffset);
7588 COM_METHOD Activate(BOOL bActive);
7589 COM_METHOD IsActive(BOOL *pbActive)
7591 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
7593 return BaseIsActive(pbActive);
7596 //-----------------------------------------------------------
7598 //-----------------------------------------------------------
7602 //-----------------------------------------------------------
7603 // Convenience routines
7604 //-----------------------------------------------------------
7607 //-----------------------------------------------------------
7609 //-----------------------------------------------------------
7611 // Get a point to the LS BP object.
7612 LSPTR_BREAKPOINT GetLsPtrBP();
7615 // We need to have a strong pointer because we may access the m_code object after we're neutered.
7616 // @todo - use external pointer b/c Breakpoints aren't yet rooted, and so this reference could be
7618 RSExtSmartPtr<CordbCode> m_code;
7622 /* ------------------------------------------------------------------------- *
7623 * Module Breakpoint class
7624 * ------------------------------------------------------------------------- */
7626 class CordbModuleBreakpoint : public CordbBreakpoint,
7627 public ICorDebugModuleBreakpoint
7630 CordbModuleBreakpoint(CordbModule *pModule);
7635 virtual const char * DbgGetName() { return "CordbModuleBreakpoint"; }
7639 //-----------------------------------------------------------
7641 //-----------------------------------------------------------
7643 ULONG STDMETHODCALLTYPE AddRef()
7645 return (BaseAddRef());
7647 ULONG STDMETHODCALLTYPE Release()
7649 return (BaseRelease());
7651 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7653 //-----------------------------------------------------------
7654 // ICorDebugModuleBreakpoint
7655 //-----------------------------------------------------------
7657 COM_METHOD GetModule(ICorDebugModule **ppModule);
7658 COM_METHOD Activate(BOOL bActive);
7659 COM_METHOD IsActive(BOOL *pbActive)
7661 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
7663 return BaseIsActive(pbActive);
7666 //-----------------------------------------------------------
7668 //-----------------------------------------------------------
7673 CordbModule *m_module;
7677 /* ------------------------------------------------------------------------- *
7679 * ------------------------------------------------------------------------- */
7681 class CordbStepper : public CordbBase, public ICorDebugStepper, public ICorDebugStepper2
7684 CordbStepper(CordbThread *thread, CordbFrame *frame = NULL);
7689 virtual const char * DbgGetName() { return "CordbStepper"; }
7693 //-----------------------------------------------------------
7695 //-----------------------------------------------------------
7697 ULONG STDMETHODCALLTYPE AddRef()
7699 return (BaseAddRef());
7701 ULONG STDMETHODCALLTYPE Release()
7703 return (BaseRelease());
7705 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7707 //-----------------------------------------------------------
7709 //-----------------------------------------------------------
7711 COM_METHOD IsActive(BOOL *pbActive);
7712 COM_METHOD Deactivate();
7713 COM_METHOD SetInterceptMask(CorDebugIntercept mask);
7714 COM_METHOD SetUnmappedStopMask(CorDebugUnmappedStop mask);
7715 COM_METHOD Step(BOOL bStepIn);
7716 COM_METHOD StepRange(BOOL bStepIn,
7717 COR_DEBUG_STEP_RANGE ranges[],
7718 ULONG32 cRangeCount);
7719 COM_METHOD StepOut();
7720 COM_METHOD SetRangeIL(BOOL bIL);
7722 //-----------------------------------------------------------
7723 // ICorDebugStepper2
7724 //-----------------------------------------------------------
7725 COM_METHOD SetJMC(BOOL fIsJMCStepper);
7727 //-----------------------------------------------------------
7728 // Convenience routines
7729 //-----------------------------------------------------------
7731 CordbAppDomain *GetAppDomain()
7733 return (m_thread->GetAppDomain());
7736 LSPTR_STEPPER GetLsPtrStepper();
7738 //-----------------------------------------------------------
7740 //-----------------------------------------------------------
7742 CordbThread *m_thread;
7743 CordbFrame *m_frame;
7744 REMOTE_PTR m_stepperToken;
7747 bool m_fIsJMCStepper;
7748 CorDebugUnmappedStop m_rgfMappingStop;
7749 CorDebugIntercept m_rgfInterceptStop;
7752 #define REG_SIZE sizeof(SIZE_T)
7754 // class RegisterInfo: encapsulates information necessary to identify and access a specific register in a
7759 // constructor for an instance of RegisterInfo
7761 // input: kNumber - value from CorDebugRegister to identify the register
7762 // addr - address in remote register display that holds the value
7763 // output: no out parameters, but this instance of RegisterInfo has been initialized
7764 RegisterInfo(const CorDebugRegister kNumber, CORDB_ADDRESS addr, SIZE_T value):
7765 m_kRegNumber((CorDebugRegister)kNumber),
7773 // input: regInfo - register info from which the values for this instance will come
7774 // output: no out parameters, but this instance of RegisterInfo has been initialized
7775 RegisterInfo(const RegisterInfo * pRegInfo):
7776 m_kRegNumber(pRegInfo->m_kRegNumber),
7777 m_regAddr(pRegInfo->m_regAddr),
7778 m_regValue(pRegInfo->m_regValue)
7782 //-------------------------------------
7784 //-------------------------------------
7786 // enumeration value to identify the register, e.g., REGISTER_X86_EAX, or REGISTER_AMD64_XMM0
7787 CorDebugRegister m_kRegNumber;
7789 // address in a context or frame register display of the register value
7790 CORDB_ADDRESS m_regAddr;
7792 // the actual value of the register
7794 }; // class RegisterInfo
7796 // class EnregisteredValueHome: abstract class to encapsulate basic information for a register value, and
7797 // serve as a base class for values residing in register-based locations, such as a single register, a
7798 // register pair, or a register and memory location.
7799 class EnregisteredValueHome
7803 // constructor to initialize an instance of EnregisteredValueHome
7804 EnregisteredValueHome(const CordbNativeFrame * pFrame);
7806 virtual ~EnregisteredValueHome() {}
7808 // virtual "copy constructor" to make a copy of "this" to be owned by a different instance of
7809 // Cordb*Value. If an instance of CordbVCObjectValue represents an enregistered value class, it means
7810 // there is a single field. This implies that the register for the CordbVCObject instance is the same as
7811 // the register for its field. When we create a Cordb*Value to represent this field, we need to make a
7812 // copy of the EnregisteredValueHome belonging to the CordbVCObject instance to become the
7813 // EnregisteredValueHome of the Cord*Value representing the field.
7815 // a new cloned copy of this object, allocated on the heap.
7816 // Caller is responsible for deleting the memory (using the standard delete operator).
7818 // C++ allows derived implementations to differ on return type, thus allowing
7819 // derived impls to return the cloned copy as its actual derived type, and not just as a base type.
7823 EnregisteredValueHome * Clone() const = 0;
7825 // set a remote enregistered location to a new value
7827 // input: pNewValue - buffer containing the new value along with its size
7828 // pContext - context from which the value comes
7829 // fIsSigned - indicates whether the value is signed or not. The value provided may be smaller than
7830 // a register, in which case we'll need to extend it to a full register width. To do this
7831 // correctly, we need to know whether to sign extend or zero extend. Currently, only
7832 // the RegValueHome virtual function uses this, but we may need it if we introduce
7833 // types that don't completely occupy the size of two registers.
7834 // output: updates the remote enregistered value on success
7835 // Note: Throws E_FAIL for invalid input or various HRESULTs from an
7836 // unsuccessful call to WriteProcessMemory
7838 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) = 0;
7840 // Gets an enregistered value and returns it to the caller
7842 // input: pValueOutBuffer - buffer in which to return the value, along with its size
7843 // output: pValueOutBuffer - filled with the value
7844 // Note: Throws E_NOTIMPL for attempts to get an enregistered value for a float register
7845 // (implementation for derived class FloatRegValueHome)
7847 void GetEnregisteredValue(MemoryRange valueOutBuffer) = 0;
7849 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
7850 // instance of a derived class of EnregisteredValueHome
7851 // Arguments: input: none--uses fields of "this"
7852 // output: pRegAddr - address of an instance of RemoteAddress with field values set to corresponding
7853 // field values of "this"
7855 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
7858 const CordbNativeFrame * GetFrame() const { return m_pFrame; };
7860 //-------------------------------------
7862 //-------------------------------------
7864 // The frame on which the value resides
7865 const CordbNativeFrame * m_pFrame;
7867 }; // class EnregisteredValueHome
7869 typedef NewHolder<EnregisteredValueHome> EnregisteredValueHomeHolder;
7871 // class RegValueHome: encapsulates basic information for a value that resides in a single register
7872 // and serves as a base class for values residing in a register pair.
7873 class RegValueHome: public EnregisteredValueHome
7877 // initializing constructor
7879 // input: pFrame - frame to which the value belongs
7880 // regNum - enumeration value corresponding to the particular hardware register in
7881 // which the value resides
7882 // regAddr - remote address within a register display (in a context or frame) of the
7884 // output: no out parameters, but the instance has been initialized
7885 RegValueHome(const CordbNativeFrame * pFrame,
7886 CorDebugRegister regNum):
7887 EnregisteredValueHome(pFrame),
7889 pFrame->GetLeftSideAddressOfRegister(regNum),
7890 *(pFrame->GetAddressOfRegister(regNum)))
7895 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
7896 // instance will come
7897 // output: no out parameters, but the instance has been initialized
7898 RegValueHome(const RegValueHome * pRemoteRegAddr):
7899 EnregisteredValueHome(pRemoteRegAddr->m_pFrame),
7900 m_reg1Info(pRemoteRegAddr->m_reg1Info)
7903 // make a copy of this instance of RegValueHome
7905 RegValueHome * Clone() const { return new RegValueHome(*this); };
7907 // updates a register in a given context, and in the regdisplay of a given frame.
7908 void SetContextRegister(DT_CONTEXT * pContext,
7909 CorDebugRegister regNum,
7912 // set the value of a remote enregistered value
7914 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
7916 // Gets an enregistered value and returns it to the caller
7918 void GetEnregisteredValue(MemoryRange valueOutBuffer);
7919 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
7920 // instance of a derived class of RegValueHome
7922 void CopyToIPCEType(RemoteAddress * pRegAddr);
7924 //-------------------------------------
7926 //-------------------------------------
7928 // The information for the register in which the value resides.
7929 const RegisterInfo m_reg1Info;
7930 }; // class RegValueHome
7932 // class RegRegValueHome
7933 // derived class to add a second register for values that live in a pair of registers
7934 class RegRegValueHome: public RegValueHome
7937 // initializing constructor
7939 // input: pFrame - frame to which the value belongs
7940 // reg1Num - enumeration value corresponding to the first particular hardware register in
7941 // which the value resides
7942 // reg1Addr - remote address within a register display (in a context or frame) of the
7944 // reg2Num - enumeration value corresponding to the second particular hardware register in
7945 // which the value resides
7946 // reg2Addr - remote address within a register display (in a context or frame) of the
7948 // output: no out parameters, but the instance has been initialized
7949 RegRegValueHome(const CordbNativeFrame * pFrame,
7950 CorDebugRegister reg1Num,
7951 CorDebugRegister reg2Num):
7952 RegValueHome(pFrame, reg1Num),
7954 pFrame->GetLeftSideAddressOfRegister(reg2Num),
7955 *(pFrame->GetAddressOfRegister(reg2Num)))
7960 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
7961 // instance will come
7962 // output: no out parameters, but the instance has been initialized
7963 RegRegValueHome(const RegRegValueHome * pRemoteRegAddr):
7964 RegValueHome(pRemoteRegAddr),
7965 m_reg2Info(pRemoteRegAddr->m_reg2Info)
7968 // make a copy of this instance of RegRegValueHome
7970 RegRegValueHome * Clone() const { return new RegRegValueHome(*this); };
7972 // set the value of a remote enregistered value
7974 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
7976 // Gets an enregistered value and returns it to the caller
7978 void GetEnregisteredValue(MemoryRange valueOutBuffer);
7980 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
7981 // instance of a derived class of EnregisteredValueHome
7982 void CopyToIPCEType(RemoteAddress * pRegAddr);
7984 //-------------------------------------
7986 //-------------------------------------
7989 // The information for the second of two registers in which the value resides.
7990 const RegisterInfo m_reg2Info;
7991 }; // class RegRegValueHome
7993 // class RegAndMemBaseValueHome
7994 // derived from RegValueHome, this class is also a base class for RegMemValueHome
7995 // and MemRegValueHome, which add a memory location for reg-mem or mem-reg values
7996 class RegAndMemBaseValueHome: public RegValueHome
7999 // initializing constructor
8001 // input: pFrame - frame to which the value belongs
8002 // reg1Num - enumeration value corresponding to the first particular hardware register in
8003 // which the value resides
8004 // reg1Addr - remote address within a register display (in a context or frame) of the
8005 // register component of the value
8006 // memAddr - remote address for the memory component of the value
8007 // output: no out parameters, but the instance has been initialized
8008 RegAndMemBaseValueHome(const CordbNativeFrame * pFrame,
8009 CorDebugRegister reg1Num,
8010 CORDB_ADDRESS memAddr):
8011 RegValueHome(pFrame, reg1Num),
8017 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8018 // instance will come
8019 // output: no out parameters, but the instance has been initialized
8020 RegAndMemBaseValueHome(const RegAndMemBaseValueHome * pRemoteRegAddr):
8021 RegValueHome(pRemoteRegAddr),
8025 // make a copy of this instance of RegRegValueHome
8027 RegAndMemBaseValueHome * Clone() const = 0;
8029 // set the value of a remote enregistered value
8031 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * DT_pContext, bool fIsSigned) = 0;
8033 // Gets an enregistered value and returns it to the caller
8035 void GetEnregisteredValue(MemoryRange valueOutBuffer) = 0;
8037 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8038 // instance of a derived class of EnregisteredValueHome
8040 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
8042 //-------------------------------------
8044 //-------------------------------------
8047 // remote address for the memory component of the value
8048 CORDB_ADDRESS m_memAddr;
8050 }; // class RegAndMemBaseValueHome;
8052 // class RegMemValueHome
8053 // type derived from abstract class RegAndMemBaseValueHome to represent a Register/Memory location where the
8054 // high order part of the value is kept in a register, and the low order part is kept in memory
8055 class RegMemValueHome: public RegAndMemBaseValueHome
8059 // initializing constructor
8061 // input: pFrame - frame to which the value belongs
8062 // reg1Num - enumeration value corresponding to the first particular hardware register in
8063 // which the value resides
8064 // reg1Addr - remote address within a register display (in a context or frame) of the
8065 // register component of the value
8066 // memAddr - remote address for the memory component of the value
8067 // output: no out parameters, but the instance has been initialized
8068 RegMemValueHome(const CordbNativeFrame * pFrame,
8069 CorDebugRegister reg1Num,
8070 CORDB_ADDRESS memAddr):
8071 RegAndMemBaseValueHome(pFrame, reg1Num, memAddr)
8076 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8077 // instance will come
8078 // output: no out parameters, but the instance has been initialized
8079 RegMemValueHome(const RegMemValueHome * pRemoteRegAddr):
8080 RegAndMemBaseValueHome(pRemoteRegAddr)
8083 // make a copy of this instance of RegMemValueHome
8085 RegMemValueHome * Clone() const { return new RegMemValueHome(*this); };
8087 // set the value of a remote enregistered value
8089 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8091 // Gets an enregistered value and returns it to the caller
8093 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8095 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8096 // instance of a derived class of EnregisteredValueHome
8098 void CopyToIPCEType(RemoteAddress * pRegAddr);
8100 }; // class RegMemValueHome;
8102 // class MemRegValueHome
8103 // type derived from abstract class RegAndMemBaseValueHome to represent a Register/Memory location where the
8104 // low order part of the value is kept in a register, and the high order part is kept in memory
8105 class MemRegValueHome: public RegAndMemBaseValueHome
8109 // initializing constructor
8111 // input: pFrame - frame to which the value belongs
8112 // reg1Num - enumeration value corresponding to the first particular hardware register in
8113 // which the value resides
8114 // reg1Addr - remote address within a register display (in a context or frame) of the
8115 // register component of the value
8116 // memAddr - remote address for the memory component of the value
8117 // output: no out parameters, but the instance has been initialized
8118 MemRegValueHome(const CordbNativeFrame * pFrame,
8119 CorDebugRegister reg1Num,
8120 CORDB_ADDRESS memAddr):
8121 RegAndMemBaseValueHome(pFrame, reg1Num, memAddr)
8126 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8127 // instance will come
8128 // output: no out parameters, but the instance has been initialized
8129 MemRegValueHome(const MemRegValueHome * pRemoteRegAddr):
8130 RegAndMemBaseValueHome(pRemoteRegAddr)
8133 // make a copy of this instance of MemRegValueHome
8135 MemRegValueHome * Clone() const { return new MemRegValueHome(*this); };
8137 // set the value of a remote enregistered value
8139 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8141 // Gets an enregistered value and returns it to the caller
8143 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8145 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8146 // instance of a derived class of EnregisteredValueHome
8148 void CopyToIPCEType(RemoteAddress * pRegAddr);
8150 }; // class MemRegValueHome;
8152 // class FloatRegValueHome
8153 // derived class to add an index into the FP register stack for a floating point value
8154 class FloatRegValueHome: public EnregisteredValueHome
8157 // initializing constructor
8159 // input: pFrame - frame to which the value belongs
8160 // index - index into the floating point stack where the value resides
8161 // output: no out parameters, but the instance has been initialized
8162 FloatRegValueHome(const CordbNativeFrame * pFrame,
8164 EnregisteredValueHome(pFrame),
8170 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8171 // instance will come
8172 // output: no out parameters, but the instance has been initialized
8173 FloatRegValueHome(const FloatRegValueHome * pRemoteRegAddr):
8174 EnregisteredValueHome(pRemoteRegAddr->m_pFrame),
8175 m_floatIndex(pRemoteRegAddr->m_floatIndex)
8178 // make a copy of this instance of FloatRegValueHome
8180 FloatRegValueHome * Clone() const { return new FloatRegValueHome(*this); };
8182 // set the value of a remote enregistered value
8184 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8186 // Gets an enregistered value and returns it to the caller
8188 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8190 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8191 // instance of a derived class of EnregisteredValueHome
8193 void CopyToIPCEType(RemoteAddress * pRegAddr);
8195 //-------------------------------------
8197 //-------------------------------------
8200 // index into the FP registers for the register in which the floating point value resides
8201 const DWORD m_floatIndex;
8202 }; // class FloatRegValueHome
8204 // ----------------------------------------------------------------------------
8205 // Type hierarchy for value locations
8208 // ------------------ | -------------------
8210 // RemoteValueHome RegisterValueHome HandleValueHome
8214 // VCRemoteValueHome RefRemoteValueHome
8216 // ValueHome: abstract base class, provides remote read and write utilities
8217 // RemoteValueHome: used for CordbObjectValue, CordbArrayValue, and CordbBoxValue instances,
8218 // which have only remote locations, and for other ICDValues with a remote address
8219 // RegisterValueHome: used for CordbGenericValue and CordbReferenceValue instances with
8220 // only a register location
8221 // HandleValueHome: used for CordbReferenceValue instances with only an object handle
8222 // VCRemoteValueHome: used for CordbVCObjectValue instances to supply special operation CreateInternalValue for
8223 // value class objects with only a remote location
8224 // RefRemoteValueHome: used for CordbReferenceValue instances with only a remote location
8226 // In addition, we have a special type for the ValueHome field for CordbReferenceValue instances:
8227 // RefValueHome. This will have a field of type ValueHome and will implement extra operations only relevant
8228 // for object references.
8230 // ----------------------------------------------------------------------------
8235 ValueHome(CordbProcess * pProcess):
8236 m_pProcess(pProcess) { _ASSERTE(pProcess != NULL); };
8241 // releases resources as necessary
8245 // gets the remote address for the value or returns NULL if none exists
8247 CORDB_ADDRESS GetAddress() = 0;
8249 // Gets a value and returns it in dest
8251 // input: none (uses fields of the instance)
8252 // output: dest - buffer containing the value retrieved as long as the returned HRESULT doesn't
8253 // indicate an error.
8254 // Note: Throws errors from read process memory operation or GetThreadContext operation
8256 void GetValue(MemoryRange dest) = 0;
8258 // Sets a location to the value provided in src
8260 // input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller
8261 // pType - type information about the value
8262 // output: none, but on success, changes m_remoteValue to hold the new value
8263 // Note: Throws errors from SafeWriteBuffer
8265 void SetValue(MemoryRange src, CordbType * pType) = 0;
8267 // creates an ICDValue for a field or array element or for the value type of a boxed object
8269 // input: pType - type of the internal value
8270 // offset - offset to the internal value
8271 // localAddress - address of thelogical buffer within the parent class' local cached
8272 // copy that holds the internal element
8273 // size - size of the internal value
8274 // output: ppValue - the newly created ICDValue instance
8275 // Note: Throws for a variety of possible failures: OOM, E_FAIL, errors from
8276 // ReadProcessMemory.
8278 void CreateInternalValue(CordbType * pType,
8280 void * localAddress,
8282 ICorDebugValue ** ppValue) = 0;
8284 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8286 // input: offset - offset within the value to the internal field or element
8287 // output: dest - buffer to hold the value--memory for this buffer is owned by the caller
8288 // Note: Throws process memory write errors
8290 void GetInternalValue(MemoryRange dest, SIZE_T offset) = 0;
8292 // copies register information from this to a RemoteAddress instance for FuncEval
8294 // output: pRegAddr - copy of information in m_pRemoteRegAddr, converted to
8295 // an instance of RemoteAddress
8297 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
8300 // unimplemented copy constructor to prevent passing by value
8301 ValueHome(ValueHome * pValHome);
8307 CordbProcess * m_pProcess;
8308 }; // class ValueHome
8310 // ============================================================================
8311 // RemoteValueHome class
8312 // ============================================================================
8313 // to be used for CordbObjectValue, CordbArrayValue, and CordbBoxValue, none of which ever have anything but
8315 class RemoteValueHome: public ValueHome
8319 // Note: It's possible that remoteValue.pAddress may be NULL--FuncEval makes
8320 // empty GenericValues for literals in which case we would have neither a remote address nor a
8322 RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue);
8324 // gets the remote address for the value
8326 CORDB_ADDRESS GetAddress() { return m_remoteValue.pAddress; };
8328 // releases resources as necessary
8332 // Gets a value and returns it in dest
8334 void GetValue(MemoryRange dest);
8336 // Sets a location to the value provided in src
8338 void SetValue(MemoryRange src, CordbType * pType);
8340 // creates an ICDValue for a field or array element or for the value type of a boxed object
8342 void CreateInternalValue(CordbType * pType,
8344 void * localAddress,
8346 ICorDebugValue ** ppValue);
8348 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8350 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8352 // copies register information from this to a RemoteAddress instance for FuncEval
8354 void CopyToIPCEType(RemoteAddress * pRegAddr);
8362 TargetBuffer m_remoteValue;
8363 }; // class RemoteValueHome
8365 // ============================================================================
8366 // RegisterValueHome class
8367 // ============================================================================
8368 // for values that may either have a remote location or be enregistered--
8369 // to be used for CordbGenericValue, and as base for CordbVCObjectValue and CordbReferenceValue
8370 class RegisterValueHome: public ValueHome
8374 RegisterValueHome(CordbProcess * pProcess,
8375 EnregisteredValueHomeHolder * ppRemoteRegAddr);
8377 // clean up resources
8381 // gets the remote address for the value or returns NULL if none exists
8383 CORDB_ADDRESS GetAddress() { return NULL; };
8385 // Gets a value and returns it in dest
8387 void GetValue(MemoryRange dest);
8389 // Sets a location to the value provided in src
8391 void SetValue(MemoryRange src, CordbType * pType);
8393 // creates an ICDValue for a field or array element or for the value type of a boxed object
8395 void CreateInternalValue(CordbType * pType,
8397 void * localAddress,
8399 ICorDebugValue ** ppValue);
8401 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8403 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8405 // copies the register information from this to a RemoteAddress instance
8407 void CopyToIPCEType(RemoteAddress * pRegAddr);
8411 // sets a remote enregistered location to a new value
8412 void SetEnregisteredValue(MemoryRange src, bool fIsSigned);
8414 // gets a value from an enregistered location
8415 void GetEnregisteredValue(MemoryRange dest);
8417 bool IsSigned(CorElementType elementType);
8424 // Left Side register location info for various kinds of (partly) enregistered values.
8425 EnregisteredValueHome * m_pRemoteRegAddr;
8427 }; // class RegisterValueHome
8429 // ============================================================================
8430 // HandleValueHome class
8431 // ============================================================================
8433 class HandleValueHome: public ValueHome
8438 // input: pProcess - process to which the value belongs
8439 // vmObjHandle - objectHandle holding the object address
8440 HandleValueHome(CordbProcess * pProcess, VMPTR_OBJECTHANDLE vmObjHandle):
8441 ValueHome(pProcess),
8442 m_vmObjectHandle(vmObjHandle) {};
8444 // releases resources as necessary
8448 // gets the remote address for the value or returns NULL if none exists
8450 CORDB_ADDRESS GetAddress();
8452 // Gets a value and returns it in dest
8454 void GetValue(MemoryRange dest);
8456 // Sets a location to the value provided in src
8458 void SetValue(MemoryRange src, CordbType * pType);
8460 // creates an ICDValue for a field or array element or for the value type of a boxed object
8462 void CreateInternalValue(CordbType * pType,
8464 void * localAddress,
8466 ICorDebugValue ** ppValue);
8468 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8470 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8472 // copies the register information from this to a RemoteAddress instance
8474 void CopyToIPCEType(RemoteAddress * pRegAddr);
8480 VMPTR_OBJECTHANDLE m_vmObjectHandle;
8481 }; // class HandleValueHome;
8483 // ============================================================================
8484 // VCRemoteValueHome class
8485 // ============================================================================
8486 // used only for CordbVCObjectValue
8487 class VCRemoteValueHome: public RemoteValueHome
8491 VCRemoteValueHome(CordbProcess * pProcess,
8492 TargetBuffer remoteValue):
8493 RemoteValueHome(pProcess, remoteValue) {};
8495 // Sets a location to the value provided in src
8497 void SetValue(MemoryRange src, CordbType * pType);
8499 }; // class VCRemoteValueHome
8501 // ============================================================================
8502 // RefRemoteValueHome class
8503 // ============================================================================
8505 // used only for CordbReferenceValue
8506 class RefRemoteValueHome: public RemoteValueHome
8511 RefRemoteValueHome(CordbProcess * pProcess,
8512 TargetBuffer remoteValue);
8514 // Sets a location to the value provided in src
8516 void SetValue(MemoryRange src, CordbType * pType);
8518 }; // class RefRemoteValueHome
8520 // ============================================================================
8521 // RefValueHome class
8522 // ============================================================================
8524 // abstract superclass for derivations RefRemoteValueHome and RefRegValueHome
8529 RefValueHome() { m_pHome = NULL; m_fNullObjHandle = true; };
8532 RefValueHome(CordbProcess * pProcess,
8533 TargetBuffer remoteValue,
8534 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8535 VMPTR_OBJECTHANDLE vmObjHandle);
8537 // indicates whether the object handle is null
8538 bool ObjHandleIsNull() { return m_fNullObjHandle; };
8539 void SetObjHandleFlag(bool isNull) { m_fNullObjHandle = isNull; };
8544 // appropriate instantiation of ValueHome
8545 ValueHome * m_pHome;
8548 // true iff m_pHome is an instantiation of RemoteValueHome or RegisterValueHome
8549 bool m_fNullObjHandle;
8550 }; // class RefValueHome
8552 typedef enum {kUnboxed, kBoxed} BoxedValue;
8553 #define EMPTY_BUFFER TargetBuffer(PTR_TO_CORDB_ADDRESS((void *)NULL), 0)
8555 /* ------------------------------------------------------------------------- *
8556 * Variable Home class
8557 * ------------------------------------------------------------------------- */
8558 class CordbVariableHome : public CordbBase, public ICorDebugVariableHome
8561 CordbVariableHome(CordbNativeCode *pCode,
8562 const ICorDebugInfo::NativeVarInfo nativeVarInfo,
8565 ~CordbVariableHome();
8566 virtual void Neuter();
8569 virtual const char * DbgGetName() { return "CordbVariableHome"; }
8572 //-----------------------------------------------------------
8574 //-----------------------------------------------------------
8575 ULONG STDMETHODCALLTYPE AddRef()
8577 return (BaseAddRef());
8579 ULONG STDMETHODCALLTYPE Release()
8581 return (BaseRelease());
8584 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8586 //-----------------------------------------------------------
8587 // ICorDebugVariableHome
8588 //-----------------------------------------------------------
8590 COM_METHOD GetCode(ICorDebugCode **ppCode);
8592 COM_METHOD GetSlotIndex(ULONG32 *pSlotIndex);
8594 COM_METHOD GetArgumentIndex(ULONG32* pArgumentIndex);
8596 COM_METHOD GetLiveRange(ULONG32* pStartOffset,
8597 ULONG32 *pEndOffset);
8599 COM_METHOD GetLocationType(VariableLocationType *pLocationType);
8601 COM_METHOD GetRegister(CorDebugRegister *pRegister);
8603 COM_METHOD GetOffset(LONG *pOffset);
8605 RSSmartPtr<CordbNativeCode> m_pCode;
8606 ICorDebugInfo::NativeVarInfo m_nativeVarInfo;
8612 // for an inheritance graph of the ICDValue types, // See file:./ICorDebugValueTypes.vsd for a diagram of the types.
8613 /* ------------------------------------------------------------------------- *
8615 * ------------------------------------------------------------------------- */
8617 class CordbValue : public CordbBase
8620 //-----------------------------------------------------------
8621 // Constructor/destructor
8622 //-----------------------------------------------------------
8623 CordbValue(CordbAppDomain * appdomain,
8627 NeuterList * pList = NULL);
8629 virtual ~CordbValue();
8630 virtual void Neuter();
8632 //-----------------------------------------------------------
8634 //-----------------------------------------------------------
8636 ULONG STDMETHODCALLTYPE AddRef()
8638 return (BaseAddRef());
8640 ULONG STDMETHODCALLTYPE Release()
8642 return (BaseRelease());
8645 //-----------------------------------------------------------
8647 //-----------------------------------------------------------
8649 COM_METHOD GetType(CorElementType *pType)
8651 LIMITED_METHOD_CONTRACT;
8653 FAIL_IF_NEUTERED(this);
8654 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
8656 *pType = m_type->m_elementType;
8660 COM_METHOD GetSize(ULONG32 *pSize)
8662 LIMITED_METHOD_CONTRACT;
8664 FAIL_IF_NEUTERED(this);
8665 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG32 *);
8667 if (m_size > ULONG_MAX)
8670 return (COR_E_OVERFLOW);
8673 *pSize = (ULONG)m_size;
8677 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
8679 //-----------------------------------------------------------
8681 //-----------------------------------------------------------
8683 COM_METHOD GetExactType(ICorDebugType **ppType);
8685 //-----------------------------------------------------------
8687 //-----------------------------------------------------------
8689 COM_METHOD GetSize64(ULONG64 *pSize)
8691 LIMITED_METHOD_CONTRACT;
8693 FAIL_IF_NEUTERED(this);
8694 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG64 *);
8700 //-----------------------------------------------------------
8701 // Methods not exported through COM
8702 //-----------------------------------------------------------
8704 // Helper for code:CordbValue::CreateValueByType. Create a new instance of CordbGenericValue
8706 void CreateGenericValue(CordbAppDomain * pAppdomain,
8708 TargetBuffer remoteValue,
8709 MemoryRange localValue,
8710 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8711 ICorDebugValue** ppValue);
8713 // Helper for code:CordbValue::CreateValueByType. Create a new instance of CordbVCObjectValue or
8714 // CordbReferenceValue
8716 void CreateVCObjOrRefValue(CordbAppDomain * pAppdomain,
8719 TargetBuffer remoteValue,
8720 MemoryRange localValue,
8721 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8722 ICorDebugValue** ppValue);
8724 // Create the proper ICDValue instance based on the given element type.
8725 static void CreateValueByType(CordbAppDomain * appdomain,
8728 TargetBuffer remoteValue,
8729 MemoryRange localValue,
8730 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8731 ICorDebugValue** ppValue);
8733 // Create the proper ICDValue instance based on the given remote heap object
8734 static ICorDebugValue* CreateHeapValue(CordbAppDomain* pAppDomain,
8735 VMPTR_Object vmObj);
8738 // Returns a pointer to the ValueHome field of this instance of CordbValue if one exists or NULL
8739 // otherwise. Therefore, this also tells us indirectly whether this instance of CordbValue is also an
8740 // instance of one of its derived types and thus has a ValueHome field.
8742 ValueHome * GetValueHome() { return NULL; };
8744 static ULONG32 GetSizeForType(CordbType * pType, BoxedValue boxing);
8746 virtual CordbAppDomain *GetAppDomain()
8751 HRESULT InternalCreateHandle(
8752 CorDebugHandleType handleType,
8753 ICorDebugHandleValue ** ppHandle);
8755 //-----------------------------------------------------------
8757 //-----------------------------------------------------------
8760 CordbAppDomain * m_appdomain;
8761 RSSmartPtr<CordbType> m_type;
8763 // size of the value
8766 // true if the value is a RS fabrication.
8771 /* ------------------------------------------------------------------------- *
8772 * Value Breakpoint class
8773 * ------------------------------------------------------------------------- */
8775 class CordbValueBreakpoint : public CordbBreakpoint,
8776 public ICorDebugValueBreakpoint
8779 CordbValueBreakpoint(CordbValue *pValue);
8783 virtual const char * DbgGetName() { return "CordbValueBreakpoint"; }
8786 //-----------------------------------------------------------
8788 //-----------------------------------------------------------
8790 ULONG STDMETHODCALLTYPE AddRef()
8792 return (BaseAddRef());
8794 ULONG STDMETHODCALLTYPE Release()
8796 return (BaseRelease());
8798 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8800 //-----------------------------------------------------------
8801 // ICorDebugValueBreakpoint
8802 //-----------------------------------------------------------
8804 COM_METHOD GetValue(ICorDebugValue **ppValue);
8805 COM_METHOD Activate(BOOL bActive);
8806 COM_METHOD IsActive(BOOL *pbActive)
8808 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
8810 return BaseIsActive(pbActive);
8813 //-----------------------------------------------------------
8815 //-----------------------------------------------------------
8820 CordbValue *m_value;
8823 /* ------------------------------------------------------------------------- *
8824 * Generic Value class
8825 * ------------------------------------------------------------------------- */
8827 class CordbGenericValue : public CordbValue, public ICorDebugGenericValue, public ICorDebugValue2, public ICorDebugValue3
8830 CordbGenericValue(CordbAppDomain * appdomain,
8832 TargetBuffer remoteValue,
8833 EnregisteredValueHomeHolder * ppRemoteRegAddr);
8835 CordbGenericValue(CordbType * pType);
8837 ~CordbGenericValue();
8840 virtual const char * DbgGetName() { return "CordbGenericValue"; }
8844 //-----------------------------------------------------------
8846 //-----------------------------------------------------------
8848 ULONG STDMETHODCALLTYPE AddRef()
8850 return (BaseAddRef());
8852 ULONG STDMETHODCALLTYPE Release()
8854 return (BaseRelease());
8856 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8858 //-----------------------------------------------------------
8860 //-----------------------------------------------------------
8862 // gets the type of the value
8864 // output: pType - the type of the value. The caller must guarantee that pType is non-null.
8865 // Return Value: S_OK on success, E_INVALIDARG on failure
8866 COM_METHOD GetType(CorElementType *pType)
8868 return (CordbValue::GetType(pType));
8871 // gets the size of the value
8873 // output: pSize - the size of the value. The caller must guarantee that pSize is non-null.
8874 // Return Value: S_OK on success, E_INVALIDARG on failure
8875 COM_METHOD GetSize(ULONG32 *pSize)
8877 return (CordbValue::GetSize(pSize));
8879 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
8881 return (CordbValue::CreateBreakpoint(ppBreakpoint));
8884 // gets the remote (LS) address of the value. This may return NULL if the
8885 // value is a literal or resides in a register.
8887 // output: pAddress - the address of the value. The caller must guarantee is
8889 // Return Value: S_OK on success or E_INVALIDARG if pAddress is null
8890 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
8892 LIMITED_METHOD_CONTRACT;
8894 FAIL_IF_NEUTERED(this);
8895 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pAddress, CORDB_ADDRESS *);
8897 *pAddress = m_pValueHome ? m_pValueHome->GetAddress() : NULL;
8901 //-----------------------------------------------------------
8903 //-----------------------------------------------------------
8905 COM_METHOD GetExactType(ICorDebugType **ppType)
8907 return (CordbValue::GetExactType(ppType));
8910 //-----------------------------------------------------------
8912 //-----------------------------------------------------------
8914 COM_METHOD GetSize64(ULONG64 *pSize)
8916 return (CordbValue::GetSize64(pSize));
8919 //-----------------------------------------------------------
8920 // ICorDebugGenericValue
8921 //-----------------------------------------------------------
8923 COM_METHOD GetValue(void *pTo);
8924 COM_METHOD SetValue(void *pFrom);
8926 //-----------------------------------------------------------
8928 //-----------------------------------------------------------
8930 // initialize a generic value by copying the necessary data, either
8931 // from the remote process or from another value in this process.
8932 void Init(MemoryRange localValue);
8933 bool CopyLiteralData(BYTE *pBuffer);
8935 // Returns a pointer to the ValueHome field
8937 ValueHome * GetValueHome() { return m_pValueHome; };
8939 //-----------------------------------------------------------
8941 //-----------------------------------------------------------
8944 // hold copies of up to 64-bit values.
8945 BYTE m_pCopyOfData[8];
8947 // location information--remote or register address
8948 ValueHome * m_pValueHome;
8952 /* ------------------------------------------------------------------------- *
8953 * Reference Value class
8954 * ------------------------------------------------------------------------- */
8956 class CordbReferenceValue : public CordbValue, public ICorDebugReferenceValue, public ICorDebugValue2, public ICorDebugValue3
8959 CordbReferenceValue(CordbAppDomain * pAppdomain,
8961 MemoryRange localValue,
8962 TargetBuffer remoteValue,
8963 EnregisteredValueHomeHolder * ppRegAddr,
8964 VMPTR_OBJECTHANDLE vmObjectHandle);
8965 CordbReferenceValue(CordbType * pType);
8966 virtual ~CordbReferenceValue();
8967 virtual void Neuter();
8971 virtual const char * DbgGetName() { return "CordbReferenceValue"; }
8974 //-----------------------------------------------------------
8976 //-----------------------------------------------------------
8978 ULONG STDMETHODCALLTYPE AddRef()
8980 return (BaseAddRef());
8982 ULONG STDMETHODCALLTYPE Release()
8984 return (BaseRelease());
8986 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8988 //-----------------------------------------------------------
8990 //-----------------------------------------------------------
8992 COM_METHOD GetType(CorElementType *pType);
8994 // get the size of the reference
8996 // output: pSize - the size of the value--this must be non-NULL
8997 // Return Value: S_OK on success or E_INVALIDARG
8998 COM_METHOD GetSize(ULONG32 *pSize)
9000 return (CordbValue::GetSize(pSize));
9003 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress);
9004 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9006 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9009 //-----------------------------------------------------------
9011 //-----------------------------------------------------------
9013 COM_METHOD GetExactType(ICorDebugType **ppType)
9015 return (CordbValue::GetExactType(ppType));
9018 //-----------------------------------------------------------
9020 //-----------------------------------------------------------
9022 COM_METHOD GetSize64(ULONG64 *pSize)
9024 return (CordbValue::GetSize64(pSize));
9027 //-----------------------------------------------------------
9028 // ICorDebugReferenceValue
9029 //-----------------------------------------------------------
9031 COM_METHOD IsNull(BOOL * pfIsNull);
9032 COM_METHOD GetValue(CORDB_ADDRESS *pAddress);
9033 COM_METHOD SetValue(CORDB_ADDRESS address);
9034 COM_METHOD Dereference(ICorDebugValue **ppValue);
9035 COM_METHOD DereferenceStrong(ICorDebugValue **ppValue);
9037 //-----------------------------------------------------------
9039 //-----------------------------------------------------------
9041 // Helper function for SanityCheckPointer. Make an attempt to read memory at the address which is the
9042 // value of the reference.
9043 void TryDereferencingTarget();
9045 // Do a sanity check on the pointer which is the value of the object reference. We can't efficiently
9046 // ensure that the pointer is really good, so we settle for a quick check just to make sure the memory at
9047 // the address is readable. We're actually just checking that we can dereference the pointer.
9048 // If the address is invalid, this will throw.
9049 void SanityCheckPointer (CorElementType type);
9051 // get information about the reference when it's not an object address but another kind of pointer type:
9052 // ELEMENT_TYPE_BYREF, ELEMENT_TYPE_PTR or ELEMENT_TYPE_FNPTR
9053 void GetPointerData(CorElementType type, MemoryRange localValue);
9055 // get basic object specific data when a reference points to an object, plus extra data if the object is
9056 // an array or string
9058 void GetObjectData(CordbProcess * pProcess,
9059 void * objectAddress,
9060 CorElementType type,
9061 VMPTR_AppDomain vmAppdomain,
9062 DebuggerIPCE_ObjectData * pInfo);
9064 // get information about a TypedByRef object when the reference is the address of a TypedByRef structure.
9066 void GetTypedByRefData(CordbProcess * pProcess,
9067 CORDB_ADDRESS pTypedByRef,
9068 CorElementType type,
9069 VMPTR_AppDomain vmAppDomain,
9070 DebuggerIPCE_ObjectData * pInfo);
9072 // get the address of the object referenced
9073 void * GetObjectAddress(MemoryRange localValue);
9075 // update type information after initializing -- when we initialize, we may get more exact type
9076 // information than we previously had
9077 void UpdateTypeInfo();
9079 // Initialize this CordbReferenceValue. This may involve inspecting the LS to get information about the
9081 HRESULT InitRef(MemoryRange localValue);
9083 bool CopyLiteralData(BYTE *pBuffer);
9085 static HRESULT Build(CordbAppDomain * appdomain,
9087 TargetBuffer remoteValue,
9088 MemoryRange localValue,
9089 VMPTR_OBJECTHANDLE vmObjectHandle,
9090 EnregisteredValueHomeHolder * ppRemoteRegAddr,
9091 CordbReferenceValue** ppValue);
9093 static HRESULT BuildFromGCHandle(CordbAppDomain *pAppDomain, VMPTR_OBJECTHANDLE gcHandle, ICorDebugReferenceValue ** pOutRef);
9095 // Common dereference routine shared by both CordbReferenceValue + CordbHandleValue
9096 static HRESULT DereferenceCommon(CordbAppDomain * pAppDomain,
9098 CordbType * pRealTypeOfTypedByref,
9099 DebuggerIPCE_ObjectData * m_pInfo,
9100 ICorDebugValue ** ppValue);
9102 // Returns a pointer to the ValueHome field
9104 ValueHome * GetValueHome() { return m_valueHome.m_pHome; };
9106 //-----------------------------------------------------------
9108 //-----------------------------------------------------------
9111 DebuggerIPCE_ObjectData m_info;
9112 CordbType * m_realTypeOfTypedByref; // weak ref
9114 RefValueHome m_valueHome;
9116 // Indicates when we last syncronized our stored data (m_info) from the left side
9117 UINT m_continueCounterLastSync;
9120 /* ------------------------------------------------------------------------- *
9121 * Object Value class
9123 * Because of the oddness of string objects in the Runtime we have one
9124 * object that implements both ObjectValue and StringValue. There is a
9125 * definite string type, but its really just an object of the string
9126 * class. Furthermore, you can have a variable whose type is listed as
9127 * "class", but its an instance of the string class and therefore needs
9128 * to be treated like a string.
9129 * ------------------------------------------------------------------------- */
9131 class CordbObjectValue : public CordbValue,
9132 public ICorDebugObjectValue,
9133 public ICorDebugObjectValue2,
9134 public ICorDebugGenericValue,
9135 public ICorDebugStringValue,
9136 public ICorDebugValue2,
9137 public ICorDebugValue3,
9138 public ICorDebugHeapValue2,
9139 public ICorDebugHeapValue3,
9140 public ICorDebugExceptionObjectValue,
9141 public ICorDebugComObjectValue
9145 CordbObjectValue(CordbAppDomain * appdomain,
9147 TargetBuffer remoteValue,
9148 DebuggerIPCE_ObjectData * pObjectData );
9150 virtual ~CordbObjectValue();
9153 virtual void Neuter();
9155 virtual const char * DbgGetName() { return "CordbObjectValue"; }
9158 //-----------------------------------------------------------
9160 //-----------------------------------------------------------
9162 ULONG STDMETHODCALLTYPE AddRef()
9164 return (BaseAddRef());
9166 ULONG STDMETHODCALLTYPE Release()
9168 return (BaseRelease());
9170 COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
9172 //-----------------------------------------------------------
9174 //-----------------------------------------------------------
9176 COM_METHOD GetType(CorElementType * pType);
9177 COM_METHOD GetSize(ULONG32 * pSize);
9178 COM_METHOD GetAddress(CORDB_ADDRESS * pAddress);
9179 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint ** ppBreakpoint);
9181 //-----------------------------------------------------------
9183 //-----------------------------------------------------------
9185 COM_METHOD GetExactType(ICorDebugType ** ppType)
9187 return (CordbValue::GetExactType(ppType));
9190 //-----------------------------------------------------------
9192 //-----------------------------------------------------------
9194 COM_METHOD GetSize64(ULONG64 *pSize);
9196 //-----------------------------------------------------------
9197 // ICorDebugHeapValue
9198 //-----------------------------------------------------------
9200 COM_METHOD IsValid(BOOL * pfIsValid);
9201 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint ** ppBreakpoint);
9203 //-----------------------------------------------------------
9204 // ICorDebugHeapValue2
9205 //-----------------------------------------------------------
9206 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9208 //-----------------------------------------------------------
9209 // ICorDebugHeapValue3
9210 //-----------------------------------------------------------
9211 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9212 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9214 //-----------------------------------------------------------
9215 // ICorDebugObjectValue
9216 //-----------------------------------------------------------
9218 COM_METHOD GetClass(ICorDebugClass ** ppClass);
9219 COM_METHOD GetFieldValue(ICorDebugClass * pClass,
9220 mdFieldDef fieldDef,
9221 ICorDebugValue ** ppValue);
9222 COM_METHOD GetVirtualMethod(mdMemberRef memberRef,
9223 ICorDebugFunction **ppFunction);
9224 COM_METHOD GetContext(ICorDebugContext ** ppContext);
9225 COM_METHOD IsValueClass(BOOL * pfIsValueClass);
9226 COM_METHOD GetManagedCopy(IUnknown ** ppObject);
9227 COM_METHOD SetFromManagedCopy(IUnknown * pObject);
9229 COM_METHOD GetFieldValueForType(ICorDebugType * pType,
9230 mdFieldDef fieldDef,
9231 ICorDebugValue ** ppValue);
9233 COM_METHOD GetVirtualMethodAndType(mdMemberRef memberRef,
9234 ICorDebugFunction ** ppFunction,
9235 ICorDebugType ** ppType);
9237 //-----------------------------------------------------------
9238 // ICorDebugGenericValue
9239 //-----------------------------------------------------------
9241 COM_METHOD GetValue(void * pTo);
9242 COM_METHOD SetValue(void * pFrom);
9244 //-----------------------------------------------------------
9245 // ICorDebugStringValue
9246 //-----------------------------------------------------------
9247 COM_METHOD GetLength(ULONG32 * pcchString);
9248 COM_METHOD GetString(ULONG32 cchString,
9249 ULONG32 * ppcchStrin,
9250 __out_ecount_opt(cchString) WCHAR szString[]);
9252 //-----------------------------------------------------------
9253 // ICorDebugExceptionObjectValue
9254 //-----------------------------------------------------------
9255 COM_METHOD EnumerateExceptionCallStack(ICorDebugExceptionObjectCallStackEnum** ppCallStackEnum);
9257 //-----------------------------------------------------------
9258 // ICorDebugComObjectValue
9259 //-----------------------------------------------------------
9260 COM_METHOD GetCachedInterfaceTypes(BOOL bIInspectableOnly,
9261 ICorDebugTypeEnum** ppInterfacesEnum);
9263 COM_METHOD GetCachedInterfacePointers(BOOL bIInspectableOnly,
9265 ULONG32 *pcEltFetched,
9266 CORDB_ADDRESS * ptrs);
9268 //-----------------------------------------------------------
9270 //-----------------------------------------------------------
9274 DebuggerIPCE_ObjectData GetInfo() { return m_info; }
9275 CordbHangingFieldTable * GetHangingFieldTable() { return &m_hangingFieldsInstance; }
9277 // Returns a pointer to the ValueHome field
9279 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9282 //-----------------------------------------------------------
9284 //-----------------------------------------------------------
9285 DebuggerIPCE_ObjectData m_info;
9286 BYTE * m_pObjectCopy; // local cached copy of the object
9287 BYTE * m_objectLocalVars; // var base in _this_ process
9288 // points _into_ m_pObjectCopy
9289 BYTE * m_stringBuffer; // points _into_ m_pObjectCopy
9291 // remote location information
9292 RemoteValueHome m_valueHome;
9294 // If instances fields are added by EnC, their storage will be off the objects
9295 // syncblock. Cache per-object information about such fields here.
9296 CordbHangingFieldTable m_hangingFieldsInstance;
9299 HRESULT IsExceptionObject();
9301 BOOL m_fIsExceptionObject;
9308 /* ------------------------------------------------------------------------- *
9309 * Value Class Object Value class
9310 * ------------------------------------------------------------------------- */
9312 class CordbVCObjectValue : public CordbValue,
9313 public ICorDebugObjectValue, public ICorDebugObjectValue2,
9314 public ICorDebugGenericValue, public ICorDebugValue2,
9315 public ICorDebugValue3
9318 CordbVCObjectValue(CordbAppDomain * pAppdomain,
9320 TargetBuffer remoteValue,
9321 EnregisteredValueHomeHolder * ppRemoteRegAddr);
9322 virtual ~CordbVCObjectValue();
9325 virtual const char * DbgGetName() { return "CordbVCObjectValue"; }
9328 //-----------------------------------------------------------
9330 //-----------------------------------------------------------
9332 ULONG STDMETHODCALLTYPE AddRef()
9334 return (BaseAddRef());
9336 ULONG STDMETHODCALLTYPE Release()
9338 return (BaseRelease());
9340 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9342 //-----------------------------------------------------------
9344 //-----------------------------------------------------------
9346 COM_METHOD GetType(CorElementType *pType);
9348 COM_METHOD GetSize(ULONG32 *pSize)
9350 return (CordbValue::GetSize(pSize));
9352 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9354 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9357 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9359 LIMITED_METHOD_CONTRACT;
9361 FAIL_IF_NEUTERED(this);
9362 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9364 *pAddress = m_pValueHome->GetAddress();
9368 //-----------------------------------------------------------
9370 //-----------------------------------------------------------
9372 COM_METHOD GetExactType(ICorDebugType **ppType)
9374 return (CordbValue::GetExactType(ppType));
9377 //-----------------------------------------------------------
9379 //-----------------------------------------------------------
9381 COM_METHOD GetSize64(ULONG64 *pSize)
9383 return (CordbValue::GetSize64(pSize));
9386 //-----------------------------------------------------------
9387 // ICorDebugObjectValue
9388 //-----------------------------------------------------------
9390 COM_METHOD GetClass(ICorDebugClass **ppClass);
9391 COM_METHOD GetFieldValue(ICorDebugClass *pClass,
9392 mdFieldDef fieldDef,
9393 ICorDebugValue **ppValue);
9394 COM_METHOD GetVirtualMethod(mdMemberRef memberRef,
9395 ICorDebugFunction **ppFunction);
9396 COM_METHOD GetContext(ICorDebugContext **ppContext);
9397 COM_METHOD IsValueClass(BOOL *pbIsValueClass);
9398 COM_METHOD GetManagedCopy(IUnknown **ppObject);
9399 COM_METHOD SetFromManagedCopy(IUnknown *pObject);
9400 COM_METHOD GetFieldValueForType(ICorDebugType * pType,
9401 mdFieldDef fieldDef,
9402 ICorDebugValue ** ppValue);
9403 COM_METHOD GetVirtualMethodAndType(mdMemberRef memberRef,
9404 ICorDebugFunction **ppFunction,
9405 ICorDebugType **ppType);
9407 //-----------------------------------------------------------
9408 // ICorDebugGenericValue
9409 //-----------------------------------------------------------
9411 COM_METHOD GetValue(void *pTo);
9412 COM_METHOD SetValue(void *pFrom);
9414 //-----------------------------------------------------------
9416 //-----------------------------------------------------------
9418 // Initializes the Right-Side's representation of a Value Class object.
9419 HRESULT Init(MemoryRange localValue);
9420 //HRESULT ResolveValueClass();
9421 CordbClass *GetClass();
9423 // Returns a pointer to the ValueHome field
9425 ValueHome * GetValueHome() { return m_pValueHome; };
9427 //-----------------------------------------------------------
9429 //-----------------------------------------------------------
9433 // local cached copy of the value class
9434 BYTE * m_pObjectCopy;
9436 // location information
9437 ValueHome * m_pValueHome;
9441 /* ------------------------------------------------------------------------- *
9443 * ------------------------------------------------------------------------- */
9445 class CordbBoxValue : public CordbValue,
9446 public ICorDebugBoxValue,
9447 public ICorDebugGenericValue,
9448 public ICorDebugValue2,
9449 public ICorDebugValue3,
9450 public ICorDebugHeapValue2,
9451 public ICorDebugHeapValue3
9454 CordbBoxValue(CordbAppDomain * appdomain,
9456 TargetBuffer remoteValue,
9458 SIZE_T offsetToVars);
9459 virtual ~CordbBoxValue();
9462 virtual const char * DbgGetName() { return "CordbBoxValue"; }
9465 //-----------------------------------------------------------
9467 //-----------------------------------------------------------
9469 ULONG STDMETHODCALLTYPE AddRef()
9471 return (BaseAddRef());
9473 ULONG STDMETHODCALLTYPE Release()
9475 return (BaseRelease());
9477 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9479 //-----------------------------------------------------------
9481 //-----------------------------------------------------------
9483 COM_METHOD GetType(CorElementType *pType);
9485 COM_METHOD GetSize(ULONG32 *pSize)
9487 return (CordbValue::GetSize(pSize));
9489 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9491 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9494 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9496 LIMITED_METHOD_CONTRACT;
9498 FAIL_IF_NEUTERED(this);
9499 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9501 *pAddress = m_valueHome.GetAddress();
9505 //-----------------------------------------------------------
9507 //-----------------------------------------------------------
9509 COM_METHOD GetExactType(ICorDebugType **ppType)
9511 return (CordbValue::GetExactType(ppType));
9514 //-----------------------------------------------------------
9516 //-----------------------------------------------------------
9518 COM_METHOD GetSize64(ULONG64 *pSize)
9520 return (CordbValue::GetSize64(pSize));
9523 //-----------------------------------------------------------
9524 // ICorDebugHeapValue
9525 //-----------------------------------------------------------
9527 COM_METHOD IsValid(BOOL *pbValid);
9528 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9530 //-----------------------------------------------------------
9531 // ICorDebugHeapValue2
9532 //-----------------------------------------------------------
9533 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9535 //-----------------------------------------------------------
9536 // ICorDebugHeapValue3
9537 //-----------------------------------------------------------
9538 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9539 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9541 //-----------------------------------------------------------
9542 // ICorDebugGenericValue
9543 //-----------------------------------------------------------
9545 COM_METHOD GetValue(void *pTo);
9546 COM_METHOD SetValue(void *pFrom);
9548 //-----------------------------------------------------------
9549 // ICorDebugBoxValue
9550 //-----------------------------------------------------------
9551 COM_METHOD GetObject(ICorDebugObjectValue **ppObject);
9553 // Returns a pointer to the ValueHome field
9555 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9557 //-----------------------------------------------------------
9559 //-----------------------------------------------------------
9562 SIZE_T m_offsetToVars;
9564 // remote location information
9565 RemoteValueHome m_valueHome;
9569 /* ------------------------------------------------------------------------- *
9571 * ------------------------------------------------------------------------- */
9573 class CordbArrayValue : public CordbValue,
9574 public ICorDebugArrayValue,
9575 public ICorDebugGenericValue,
9576 public ICorDebugValue2,
9577 public ICorDebugValue3,
9578 public ICorDebugHeapValue2,
9579 public ICorDebugHeapValue3
9582 CordbArrayValue(CordbAppDomain * appdomain,
9584 DebuggerIPCE_ObjectData * pObjectInfo,
9585 TargetBuffer remoteValue);
9586 virtual ~CordbArrayValue();
9589 virtual const char * DbgGetName() { return "CordbArrayValue"; }
9592 //-----------------------------------------------------------
9594 //-----------------------------------------------------------
9596 ULONG STDMETHODCALLTYPE AddRef()
9598 return (BaseAddRef());
9600 ULONG STDMETHODCALLTYPE Release()
9602 return (BaseRelease());
9604 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9606 //-----------------------------------------------------------
9608 //-----------------------------------------------------------
9610 COM_METHOD GetType(CorElementType *pType)
9612 return (CordbValue::GetType(pType));
9614 COM_METHOD GetSize(ULONG32 *pSize)
9616 return (CordbValue::GetSize(pSize));
9618 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9620 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9621 *pAddress = m_valueHome.GetAddress();
9624 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9626 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9629 //-----------------------------------------------------------
9631 //-----------------------------------------------------------
9633 COM_METHOD GetExactType(ICorDebugType **ppType)
9635 return (CordbValue::GetExactType(ppType));
9638 //-----------------------------------------------------------
9640 //-----------------------------------------------------------
9642 COM_METHOD GetSize64(ULONG64 *pSize)
9644 return (CordbValue::GetSize64(pSize));
9647 //-----------------------------------------------------------
9648 // ICorDebugHeapValue
9649 //-----------------------------------------------------------
9651 COM_METHOD IsValid(BOOL *pbValid);
9652 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9654 //-----------------------------------------------------------
9655 // ICorDebugHeapValue2
9656 //-----------------------------------------------------------
9657 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9659 //-----------------------------------------------------------
9660 // ICorDebugHeapValue3
9661 //-----------------------------------------------------------
9662 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9663 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9665 //-----------------------------------------------------------
9666 // ICorDebugArrayValue
9667 //-----------------------------------------------------------
9669 COM_METHOD GetElementType(CorElementType * pType);
9670 COM_METHOD GetRank(ULONG32 * pnRank);
9671 COM_METHOD GetCount(ULONG32 * pnCount);
9672 COM_METHOD GetDimensions(ULONG32 cdim, ULONG32 dims[]);
9673 COM_METHOD HasBaseIndicies(BOOL * pbHasBaseIndices);
9674 COM_METHOD GetBaseIndicies(ULONG32 cdim, ULONG32 indices[]);
9675 COM_METHOD GetElement(ULONG32 cdim, ULONG32 indices[], ICorDebugValue ** ppValue);
9676 COM_METHOD GetElementAtPosition(ULONG32 nIndex, ICorDebugValue ** ppValue);
9678 //-----------------------------------------------------------
9679 // ICorDebugGenericValue
9680 //-----------------------------------------------------------
9682 COM_METHOD GetValue(void *pTo);
9683 COM_METHOD SetValue(void *pFrom);
9685 //-----------------------------------------------------------
9687 //-----------------------------------------------------------
9691 // Returns a pointer to the ValueHome field
9693 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9695 //-----------------------------------------------------------
9697 //-----------------------------------------------------------
9700 // contains information about the array, such as rank, number of elements, element size, etc.
9701 DebuggerIPCE_ObjectData m_info;
9703 // type of the elements
9704 CordbType *m_elemtype;
9706 // consists of three parts: a vector containing the lower bounds for each dimension,
9707 // a vector containing the upper bounds for each dimension,
9708 // a local cached copy of (part of) the array--initialized lazily when we
9709 // request a particular element. If the array is large, we will store only
9710 // part of it, swapping out the cached segment as necessary to retrieve
9711 // requested elements.
9712 BYTE * m_pObjectCopy;
9714 // points to the beginning of the vector containing the lower bounds for each dimension in m_pObjectCopy
9715 DWORD * m_arrayLowerBase;
9717 // points to the beginning of the vector containing the lower bounds for each dimension in m_pObjectCopy
9718 DWORD * m_arrayUpperBase;
9719 // index of lower bound of data currently stored in m_pObjectCopy
9722 // index of upper bound of data currently stored in m_pObjectCopy
9725 // remote location information
9726 RemoteValueHome m_valueHome;
9730 class CordbHandleValue : public CordbValue, public ICorDebugHandleValue, public ICorDebugValue2, public ICorDebugValue3
9733 CordbHandleValue(CordbAppDomain *appdomain,
9735 CorDebugHandleType handleType);
9736 HRESULT Init(VMPTR_OBJECTHANDLE pHandle);
9738 virtual ~CordbHandleValue();
9740 virtual void Neuter();
9741 virtual void NeuterLeftSideResources();
9744 virtual const char * DbgGetName() { return "CordbHandleValue"; }
9748 //-----------------------------------------------------------
9750 //-----------------------------------------------------------
9752 ULONG STDMETHODCALLTYPE AddRef()
9754 return (BaseAddRef());
9756 ULONG STDMETHODCALLTYPE Release()
9758 return (BaseRelease());
9760 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9762 //-----------------------------------------------------------
9763 // ICorDebugHandleValue interface
9764 //-----------------------------------------------------------
9765 COM_METHOD GetHandleType(CorDebugHandleType *pType);
9769 * The final release of the interface will also dispose of the handle. This
9770 * API provides the ability for client to early dispose the handle.
9773 COM_METHOD Dispose();
9775 //-----------------------------------------------------------
9776 // ICorDebugValue interface
9777 //-----------------------------------------------------------
9778 COM_METHOD GetType(CorElementType *pType);
9779 COM_METHOD GetSize(ULONG32 *pSize);
9780 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress);
9781 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9783 //-----------------------------------------------------------
9785 //-----------------------------------------------------------
9787 COM_METHOD GetExactType(ICorDebugType **ppType)
9789 FAIL_IF_NEUTERED(this);
9791 // If AppDomain is already unloaded, return error
9792 if (m_appdomain->IsNeutered() == TRUE)
9794 return COR_E_APPDOMAINUNLOADED;
9796 if (m_vmHandle.IsNull())
9798 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
9801 return (CordbValue::GetExactType(ppType));
9804 //-----------------------------------------------------------
9806 //-----------------------------------------------------------
9808 COM_METHOD GetSize64(ULONG64 *pSize);
9810 //-----------------------------------------------------------
9811 // ICorDebugReferenceValue interface
9812 //-----------------------------------------------------------
9814 COM_METHOD IsNull(BOOL *pbNull);
9815 COM_METHOD GetValue(CORDB_ADDRESS *pValue);
9816 COM_METHOD SetValue(CORDB_ADDRESS value);
9817 COM_METHOD Dereference(ICorDebugValue **ppValue);
9818 COM_METHOD DereferenceStrong(ICorDebugValue **ppValue);
9820 //-----------------------------------------------------------
9822 //-----------------------------------------------------------
9824 // Returns a pointer to the ValueHome field
9826 RemoteValueHome * GetValueHome() { return NULL; };
9829 //BOOL RefreshHandleValue(void **pObjectToken);
9830 HRESULT RefreshHandleValue();
9832 // EE object handle pointer. Can be casted to OBJECTHANDLE when go to LS
9833 // This instance owns the handle object and must call into the VM to release
9835 // If this is non-null, then we increment code:CordbProces::IncrementOutstandingHandles.
9836 // Once it goes null, we should decrement the count.
9837 // Use AssignHandle, ClearHandle to keep this in sync.
9838 VMPTR_OBJECTHANDLE m_vmHandle;
9841 void AssignHandle(VMPTR_OBJECTHANDLE handle);
9844 BOOL m_fCanBeValid; // true if object "can" be valid. False when object is no longer valid.
9845 CorDebugHandleType m_handleType; // handle type can be strong or weak
9846 DebuggerIPCE_ObjectData m_info;
9847 ; // ICORDebugClass of this object when we create the handle
9850 // This class actually has the implementation for ICorDebugHeap3 interfaces. Any value which implements
9851 // the interface just delegates to these static calls.
9852 class CordbHeapValue3Impl
9855 static HRESULT GetThreadOwningMonitorLock(CordbProcess* pProcess,
9856 CORDB_ADDRESS remoteObjAddress,
9857 ICorDebugThread **ppThread,
9858 DWORD *pAcquistionCount);
9859 static HRESULT GetMonitorEventWaitList(CordbProcess* pProcess,
9860 CORDB_ADDRESS remoteObjAddress,
9861 ICorDebugThreadEnum **ppThreadEnum);
9864 /* ------------------------------------------------------------------------- *
9866 * ------------------------------------------------------------------------- */
9868 class CordbEval : public CordbBase, public ICorDebugEval, public ICorDebugEval2
9871 CordbEval(CordbThread* pThread);
9872 virtual ~CordbEval();
9875 virtual const char * DbgGetName() { return "CordbEval"; }
9878 virtual void Neuter();
9879 virtual void NeuterLeftSideResources();
9881 //-----------------------------------------------------------
9883 //-----------------------------------------------------------
9885 ULONG STDMETHODCALLTYPE AddRef()
9887 return (BaseAddRef());
9889 ULONG STDMETHODCALLTYPE Release()
9891 return (BaseRelease());
9893 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9895 //-----------------------------------------------------------
9897 //-----------------------------------------------------------
9899 COM_METHOD CallFunction(ICorDebugFunction *pFunction,
9901 ICorDebugValue *ppArgs[]);
9902 COM_METHOD NewObject(ICorDebugFunction *pConstructor,
9904 ICorDebugValue *ppArgs[]);
9905 COM_METHOD NewObjectNoConstructor(ICorDebugClass *pClass);
9906 COM_METHOD NewString(LPCWSTR string);
9907 COM_METHOD NewArray(CorElementType elementType,
9908 ICorDebugClass *pElementClass,
9911 ULONG32 lowBounds[]);
9912 COM_METHOD IsActive(BOOL *pbActive);
9914 COM_METHOD GetResult(ICorDebugValue **ppResult);
9915 COM_METHOD GetThread(ICorDebugThread **ppThread);
9916 COM_METHOD CreateValue(CorElementType elementType,
9917 ICorDebugClass *pElementClass,
9918 ICorDebugValue **ppValue);
9919 COM_METHOD NewStringWithLength(LPCWSTR wszString, UINT iLength);
9921 COM_METHOD CallParameterizedFunction(ICorDebugFunction * pFunction,
9923 ICorDebugType * rgpTypeArgs[],
9925 ICorDebugValue * rgpArgs[]);
9927 COM_METHOD CreateValueForType(ICorDebugType *pType,
9928 ICorDebugValue **ppValue);
9930 COM_METHOD NewParameterizedObject(ICorDebugFunction * pConstructor,
9932 ICorDebugType * rgpTypeArgs[],
9934 ICorDebugValue * rgpArgs[]);
9936 COM_METHOD NewParameterizedObjectNoConstructor(ICorDebugClass * pClass,
9938 ICorDebugType * rgpTypeArgs[]);
9940 COM_METHOD NewParameterizedArray(ICorDebugType * pElementType,
9943 ULONG32 lowBounds[]);
9945 //-----------------------------------------------------------
9947 //-----------------------------------------------------------
9949 COM_METHOD RudeAbort();
9951 //-----------------------------------------------------------
9953 //-----------------------------------------------------------
9954 HRESULT GatherArgInfo(ICorDebugValue *pValue,
9955 DebuggerIPCE_FuncEvalArgData *argData);
9956 HRESULT SendCleanup();
9958 // Create a RS literal for primitive type funceval result. In case the result is used as an argument for
9959 // another funceval, we need to make sure that we're not relying on the LS value, which will be freed and
9960 // thus unavailable.
9961 HRESULT CreatePrimitiveLiteral(CordbType * pType,
9962 ICorDebugValue ** ppValue);
9964 //-----------------------------------------------------------
9966 //-----------------------------------------------------------
9968 bool IsEvalDuringException() { return m_evalDuringException; }
9970 // We must keep a strong reference to the thread so we can properly fail out of SendCleanup if someone releases an
9971 // ICorDebugEval after the process has completely gone away.
9972 RSSmartPtr<CordbThread> m_thread;
9974 CordbFunction *m_function;
9975 CordbClass *m_class;
9976 DebuggerIPCE_FuncEvalType m_evalType;
9978 HRESULT SendFuncEval(unsigned int genericArgsCount, ICorDebugType *genericArgs[], void *argData1, unsigned int argData1Size, void *argData2, unsigned int argData2Size, DebuggerIPCEvent * event);
9979 HRESULT FilterHR(HRESULT hr);
9980 BOOL DoAppDomainsMatch( CordbAppDomain* pAppDomain, ULONG32 nTypes, ICorDebugType *pTypes[], ULONG32 nValues, ICorDebugValue *pValues[] );
9988 // This is an OBJECTHANDLE on the LS if func-eval creates a strong handle.
9989 // This is a resource in the left-side and must be cleaned up in the left-side.
9990 // This gets handled off to a CordbHandleValue (m_pHandleValue) once code:CordbEval::GetResult
9991 // and then the CordbHandle is responsible for releasing it in the left-side.
9992 // Issue!! This will be leaked if nobody calls GetResult().
9993 VMPTR_OBJECTHANDLE m_vmObjectHandle;
9995 // This is the corresponding cached CordbHandleValue for GetResult.
9996 // This takes ownership of the strong handle, m_objectHandle.
9997 // This is an External reference, which keeps the Value from being neutered
9998 // on a NeuterAtWill sweep.
9999 RSExtSmartPtr<CordbHandleValue> m_pHandleValue;
10001 DebuggerIPCE_ExpandedTypeData m_resultType;
10002 VMPTR_AppDomain m_resultAppDomainToken;
10004 // Left-side memory that needs to be freed.
10005 LSPTR_DEBUGGEREVAL m_debuggerEvalKey;
10008 // If we're evalling during a thread's exception, remember the info so that we can restore it when we're done.
10009 bool m_evalDuringException; // flag whether we're during the thread's exception.
10010 VMPTR_OBJECTHANDLE m_vmThreadOldExceptionHandle; // object handle for thread's managed exception object.
10013 // Func-eval should perturb the the thread's current appdomain. So we remember it at start
10014 // and then ensure that the func-eval complete restores it.
10015 CordbAppDomain * m_DbgAppDomainStarted;
10020 /* ------------------------------------------------------------------------- *
10021 * Win32 Event Thread class
10022 * ------------------------------------------------------------------------- */
10023 const unsigned int CW32ET_UNKNOWN_PROCESS_SLOT = 0xFFffFFff; // it's a managed process,
10024 //but we don't know which slot it's in - for Detach.
10026 //---------------------------------------------------------------------------------------
10028 // Dedicated thread for win32 debugging operations.
10031 // This is owned by the ShimProcess object. That will both create this and destroy it.
10032 // OS restriction is that all win32 debugging APIs (CreateProcess, DebugActiveProcess,
10033 // DebugActiveProcessStop, WaitForDebugEvent, ContinueDebugEvent, etc) are on the same thread.
10035 class CordbWin32EventThread
10037 friend class CordbProcess; //so that Detach can call ExitProcess
10039 CordbWin32EventThread(Cordb * pCordb, ShimProcess * pShim);
10040 virtual ~CordbWin32EventThread();
10043 // You create a new instance of this class, call Init() to set it up,
10044 // then call Start() start processing events. Stop() terminates the
10045 // thread and deleting the instance cleans all the handles and such
10052 HRESULT SendCreateProcessEvent(MachineInfo machineInfo,
10053 LPCWSTR programName,
10054 __in_z LPWSTR programArgs,
10055 LPSECURITY_ATTRIBUTES lpProcessAttributes,
10056 LPSECURITY_ATTRIBUTES lpThreadAttributes,
10057 BOOL bInheritHandles,
10058 DWORD dwCreationFlags,
10059 PVOID lpEnvironment,
10060 LPCWSTR lpCurrentDirectory,
10061 LPSTARTUPINFOW lpStartupInfo,
10062 LPPROCESS_INFORMATION lpProcessInformation,
10063 CorDebugCreateProcessFlags corDebugFlags);
10065 HRESULT SendDebugActiveProcessEvent(MachineInfo machineInfo,
10068 CordbProcess *pProcess);
10070 HRESULT SendDetachProcessEvent(CordbProcess *pProcess);
10072 #ifdef FEATURE_INTEROP_DEBUGGING
10073 HRESULT SendUnmanagedContinue(CordbProcess *pProcess,
10074 EUMContinueType eContType);
10075 HRESULT UnmanagedContinue(CordbProcess *pProcess,
10076 EUMContinueType eContType);
10077 void DoDbgContinue(CordbProcess * pProcess,
10078 CordbUnmanagedEvent * pUnmanagedEvent);
10079 void ForceDbgContinue(CordbProcess *pProcess,
10080 CordbUnmanagedThread *ut,
10084 #endif //FEATURE_INTEROP_DEBUGGING
10086 void LockSendToWin32EventThreadMutex()
10088 LOG((LF_CORDB, LL_INFO10000, "W32ET::LockSendToWin32EventThreadMutex\n"));
10089 m_sendToWin32EventThreadMutex.Lock();
10092 void UnlockSendToWin32EventThreadMutex()
10094 m_sendToWin32EventThreadMutex.Unlock();
10095 LOG((LF_CORDB, LL_INFO10000, "W32ET::UnlockSendToWin32EventThreadMutex\n"));
10098 bool IsWin32EventThread()
10100 return (m_threadId == GetCurrentThreadId());
10103 void Win32EventLoop();
10106 INativeEventPipeline * GetNativePipeline();
10109 static DWORD WINAPI ThreadProc(LPVOID parameter);
10111 void CreateProcess();
10114 INativeEventPipeline * m_pNativePipeline;
10117 void AttachProcess();
10119 void HandleUnmanagedContinue();
10121 void ExitProcess(bool fDetach);
10124 RSSmartPtr<Cordb> m_cordb;
10128 HANDLE m_threadControlEvent;
10129 HANDLE m_actionTakenEvent;
10132 // The process that we're 1:1 with.
10133 // This is set when we get a Create / Attach event.
10134 // This is only used on the W32ET, which guarantees it will free of races.
10135 RSSmartPtr<CordbProcess> m_pProcess;
10138 ShimProcess * m_pShim;
10140 // @todo - convert this into Stop-Go lock?
10141 RSLock m_sendToWin32EventThreadMutex;
10143 unsigned int m_action;
10144 HRESULT m_actionResult;
10149 MachineInfo machineInfo;
10150 LPCWSTR programName;
10151 LPWSTR programArgs;
10152 LPSECURITY_ATTRIBUTES lpProcessAttributes;
10153 LPSECURITY_ATTRIBUTES lpThreadAttributes;
10154 BOOL bInheritHandles;
10155 DWORD dwCreationFlags;
10156 PVOID lpEnvironment;
10157 LPCWSTR lpCurrentDirectory;
10158 LPSTARTUPINFOW lpStartupInfo;
10159 LPPROCESS_INFORMATION lpProcessInformation;
10160 CorDebugCreateProcessFlags corDebugFlags;
10165 MachineInfo machineInfo;
10167 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10170 CordbProcess *pProcess;
10172 // Wrapper to determine if we're interop-debugging.
10173 bool IsInteropDebugging()
10175 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10176 return fWin32Attach;
10185 CordbProcess *pProcess;
10190 CordbProcess *process;
10191 EUMContinueType eContType;
10197 // Thread-safe stack which.
10198 template <typename T>
10199 class InterlockedStack
10202 InterlockedStack();
10203 ~InterlockedStack();
10205 // Thread safe pushes + pops.
10206 // Many threads can push simultaneously.
10207 // Only 1 thread can pop.
10208 void Push(T * pItem);
10215 //-----------------------------------------------------------------------------
10216 // Workitem to be placed on RCET worker queue.
10217 // There's 1 RCET for to be shared by all processes.
10218 //-----------------------------------------------------------------------------
10223 virtual ~RCETWorkItem() {}
10225 // Item is executed and then removed from the list and deleted.
10226 virtual void Do() = 0;
10228 CordbProcess * GetProcess() { return m_pProcess; }
10231 RCETWorkItem(CordbProcess * pProcess)
10233 m_pProcess.Assign(pProcess);
10237 RSSmartPtr<CordbProcess> m_pProcess;
10239 // This field is accessed by the InterlockedStack.
10240 friend class InterlockedStack<RCETWorkItem>;
10241 RCETWorkItem * m_next;
10245 // Item to do Neutering work on ExitProcess.
10246 class ExitProcessWorkItem : public RCETWorkItem
10249 ExitProcessWorkItem(CordbProcess * pProc) : RCETWorkItem(pProc)
10256 // Item to do send Attach event.
10257 class SendAttachProcessWorkItem : public RCETWorkItem
10260 SendAttachProcessWorkItem(CordbProcess * pProc) : RCETWorkItem(pProc)
10268 /* ------------------------------------------------------------------------- *
10269 * Runtime Controller Event Thread class
10270 * ------------------------------------------------------------------------- */
10272 class CordbRCEventThread
10275 CordbRCEventThread(Cordb* cordb);
10276 virtual ~CordbRCEventThread();
10279 // You create a new instance of this class, call Init() to set it up,
10280 // then call Start() start processing events. Stop() terminates the
10281 // thread and deleting the instance cleans all the handles and such
10288 // RCET will take ownership of this item and delete it.
10289 void QueueAsyncWorkItem(RCETWorkItem * pItem);
10291 HRESULT SendIPCEvent(CordbProcess* process,
10292 DebuggerIPCEvent* event,
10295 void ProcessStateChanged();
10296 void FlushQueuedEvents(CordbProcess* process);
10298 HRESULT WaitForIPCEventFromProcess(CordbProcess* process,
10299 CordbAppDomain *pAppDomain,
10300 DebuggerIPCEvent* event);
10302 bool IsRCEventThread();
10305 void DrainWorkerQueue();
10308 static DWORD WINAPI ThreadProc(LPVOID parameter);
10312 InterlockedStack<class RCETWorkItem> m_WorkerStack;
10314 RSSmartPtr<Cordb> m_cordb;
10318 HANDLE m_threadControlEvent;
10319 BOOL m_processStateChanged;
10322 #ifdef FEATURE_INTEROP_DEBUGGING
10323 /* ------------------------------------------------------------------------- *
10324 * Unmanaged Event struct
10325 * ------------------------------------------------------------------------- */
10327 enum CordbUnmanagedEventState
10330 // The continued flags get set in one of a few patterns.
10331 // 1) The event is continued having never been hijacked =>
10332 // EventContinuedUnhijacked is set
10333 // 2) The event is continued having been hijacked and then the process terminates or
10334 // an error occurs before the hijack finishes =>
10335 // EventContinuedHijacked is set
10336 // 3) The event is continued having been hijacked, then the hijack completes and
10337 // execution resumes in the debuggee
10338 // EventContinuedHijacked is set
10339 // EventContinuedUnhijacked is set
10342 CUES_ExceptionCleared = 0x01,
10343 CUES_EventContinuedHijacked = 0x02,
10344 CUES_EventContinuedUnhijacked = 0x04,
10345 CUES_Dispatched = 0x08,
10346 CUES_ExceptionUnclearable = 0x10,
10348 // This is set when a user continues the event by calling
10350 CUES_UserContinued = 0x20,
10351 // This is true if the event is an IB event
10352 CUES_IsIBEvent = 0x40,
10355 struct CordbUnmanagedEvent
10358 BOOL IsExceptionCleared() { return m_state & CUES_ExceptionCleared; }
10359 BOOL IsEventContinuedHijacked() { return m_state & CUES_EventContinuedHijacked; }
10360 BOOL IsEventContinuedUnhijacked() { return m_state & CUES_EventContinuedUnhijacked; }
10361 BOOL IsEventUserContinued() { return m_state & CUES_UserContinued; }
10362 BOOL IsEventWaitingForContinue()
10364 return (!IsEventContinuedHijacked() && !IsEventContinuedUnhijacked());
10366 BOOL IsDispatched() { return m_state & CUES_Dispatched; }
10367 BOOL IsExceptionUnclearable() { return m_state & CUES_ExceptionUnclearable; }
10368 BOOL IsIBEvent() { return m_state & CUES_IsIBEvent; }
10370 void SetState(CordbUnmanagedEventState state) { m_state = (CordbUnmanagedEventState)(m_state | state); }
10371 void ClearState(CordbUnmanagedEventState state) { m_state = (CordbUnmanagedEventState)(m_state & ~state); }
10373 CordbUnmanagedThread *m_owner;
10374 CordbUnmanagedEventState m_state;
10375 DEBUG_EVENT m_currentDebugEvent;
10376 CordbUnmanagedEvent *m_next;
10380 /* ------------------------------------------------------------------------- *
10381 * Unmanaged Thread class
10382 * ------------------------------------------------------------------------- */
10384 enum CordbUnmanagedThreadState
10386 CUTS_None = 0x0000,
10387 CUTS_Deleted = 0x0001,
10388 CUTS_FirstChanceHijacked = 0x0002,
10389 // Set when interop debugging needs the SS flag to be enabled
10390 // regardless of what the user wants it to be
10391 CUTS_IsSSFlagNeeded = 0x0004,
10392 CUTS_GenericHijacked = 0x0008,
10393 // when the m_raiseExceptionEntryContext is valid
10394 CUTS_HasRaiseExceptionEntryCtx = 0x0010,
10395 CUTS_BlockingForSync = 0x0020,
10396 CUTS_Suspended = 0x0040,
10397 CUTS_IsSpecialDebuggerThread = 0x0080,
10398 // when the thread is re-executing RaiseException to retrigger an exception
10399 CUTS_IsRaiseExceptionHijacked = 0x0100,
10400 CUTS_HasIBEvent = 0x0200,
10401 CUTS_HasOOBEvent = 0x0400,
10402 CUTS_HasSpecialStackOverflowCase = 0x0800,
10404 CUTS_DEBUG_SingleStep = 0x1000,
10406 CUTS_SkippingNativePatch = 0x2000,
10407 CUTS_HasContextSet = 0x4000,
10408 // Set when interop debugging is making use of the single step flag
10409 // but the user has not set it
10410 CUTS_IsSSFlagHidden = 0x8000
10414 class CordbUnmanagedThread : public CordbBase
10417 CordbUnmanagedThread(CordbProcess *pProcess, DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase);
10418 ~CordbUnmanagedThread();
10420 using CordbBase::GetProcess;
10423 virtual const char * DbgGetName() { return "CordbUnmanagedThread"; }
10426 // CordbUnmanagedThread is a purely internal object. It's not exposed via ICorDebug APIs and so
10427 // we should never use External AddRef.
10428 ULONG STDMETHODCALLTYPE AddRef() { _ASSERTE(!"Don't use external addref on a CordbUnmanagedThread"); return (BaseAddRef());}
10429 ULONG STDMETHODCALLTYPE Release() { _ASSERTE(!"Don't use external release on a CordbUnmanagedThread"); return (BaseRelease());}
10431 COM_METHOD QueryInterface(REFIID riid, void **ppInterface)
10433 _ASSERTE(!"Don't use QI on a CordbUnmanagedThread");
10434 // Not really used since we never expose this class. If we ever do expose this class via the ICorDebug API then
10435 // we should, of course, implement this.
10436 return E_NOINTERFACE;
10439 HRESULT LoadTLSArrayPtr();
10441 // Hijacks this thread to a hijack worker function which recieves the current
10442 // context and the provided exception record. The reason determines what code
10443 // the hijack worker executes
10444 HRESULT SetupFirstChanceHijack(EHijackReason::EHijackReason reason, const EXCEPTION_RECORD * pExceptionRecord);
10445 HRESULT SetupFirstChanceHijackForSync();
10447 HRESULT SetupGenericHijack(DWORD eventCode, const EXCEPTION_RECORD * pRecord);
10448 HRESULT FixupFromGenericHijack();
10450 HRESULT FixupAfterOOBException(CordbUnmanagedEvent * ue);
10452 void SetupForSkipBreakpoint(NativePatch * pNativePatch);
10453 void FixupForSkipBreakpoint();
10456 // These are wrappers for the OS calls which hide
10457 // the effects of hijacking and internal SS flag usage
10458 HRESULT GetThreadContext(DT_CONTEXT * pContext);
10459 HRESULT SetThreadContext(DT_CONTEXT * pContext);
10461 // Turns on and off the internal usage of the SS flag
10462 VOID BeginStepping();
10463 VOID EndStepping();
10465 // An accessor for &m_context, this value generally stores
10466 // a context we may need to restore after a hijack completes
10467 DT_CONTEXT * GetHijackCtx();
10470 CORDB_ADDRESS m_stackBase;
10471 CORDB_ADDRESS m_stackLimit;
10474 BOOL GetStackRange(CORDB_ADDRESS *pBase, CORDB_ADDRESS *pLimit);
10476 BOOL IsDeleted() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_Deleted; }
10477 BOOL IsFirstChanceHijacked() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_FirstChanceHijacked; }
10478 BOOL IsGenericHijacked() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_GenericHijacked; }
10479 BOOL IsBlockingForSync() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_BlockingForSync; }
10480 BOOL IsSuspended() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_Suspended; }
10481 BOOL IsSpecialDebuggerThread() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSpecialDebuggerThread; }
10482 BOOL HasIBEvent() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasIBEvent; }
10483 BOOL HasOOBEvent() { return m_state & CUTS_HasOOBEvent; }
10484 BOOL HasSpecialStackOverflowCase() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasSpecialStackOverflowCase; }
10486 BOOL IsDEBUGTrace() { return m_state & CUTS_DEBUG_SingleStep; }
10488 BOOL IsSkippingNativePatch() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_SkippingNativePatch; }
10489 BOOL IsContextSet() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasContextSet; }
10490 BOOL IsSSFlagNeeded() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSSFlagNeeded; }
10491 BOOL IsSSFlagHidden() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSSFlagHidden; }
10492 BOOL HasRaiseExceptionEntryCtx() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasRaiseExceptionEntryCtx; }
10493 BOOL IsRaiseExceptionHijacked() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsRaiseExceptionHijacked; }
10495 void SetState(CordbUnmanagedThreadState state)
10497 LIMITED_METHOD_CONTRACT;
10498 m_state = (CordbUnmanagedThreadState)(m_state | state);
10499 _ASSERTE(!IsSuspended() || !IsBlockingForSync());
10500 _ASSERTE(!IsSuspended() || !IsFirstChanceHijacked());
10502 void ClearState(CordbUnmanagedThreadState state) {LIMITED_METHOD_CONTRACT; m_state = (CordbUnmanagedThreadState)(m_state & ~state); }
10504 void HijackToRaiseException();
10505 void RestoreFromRaiseExceptionHijack();
10506 void SaveRaiseExceptionEntryContext();
10507 void ClearRaiseExceptionEntryContext();
10508 BOOL IsExceptionFromLastRaiseException(const EXCEPTION_RECORD* pExceptionRecord);
10510 CordbUnmanagedEvent *IBEvent() {LIMITED_METHOD_CONTRACT; return &m_IBEvent; }
10511 CordbUnmanagedEvent *IBEvent2() {LIMITED_METHOD_CONTRACT; return &m_IBEvent2; }
10512 CordbUnmanagedEvent *OOBEvent() { return &m_OOBEvent; }
10516 return (DWORD) this->m_id;
10519 #ifdef DBG_TARGET_X86
10520 // Stores the thread's current leaf SEH handler
10521 HRESULT SaveCurrentLeafSeh();
10522 // Restores the thread's leaf SEH handler from the previously saved value
10523 HRESULT RestoreLeafSeh();
10526 // Logs basic data about a context to the debugging log
10527 static VOID LogContext(DT_CONTEXT* pContext);
10532 // @dbgtodo - the TLS reading is only used for interop hijacks; which goes away in Arrowhead.
10533 // Target address of the Thread Information Block (TIB).
10534 void *m_threadLocalBase;
10536 // Target address of the Thread Local Storage (TLS) array. This is for slots 0 -63.
10539 // Target Address of extended Thread local Storage array. These are for slots about 63.
10540 // This may be NULL if extended storage is not yet allocated.
10541 void *m_pTLSExtendedArray;
10544 CordbUnmanagedThreadState m_state;
10546 CordbUnmanagedEvent m_IBEvent;
10547 CordbUnmanagedEvent m_IBEvent2;
10548 CordbUnmanagedEvent m_OOBEvent;
10550 LSPTR_CONTEXT m_pLeftSideContext;
10551 void *m_originalHandler;
10554 // Spare context used for various purposes.
10555 // See CordbUnmanagedThread::GetThreadContext for details
10556 DT_CONTEXT m_context;
10558 // The context of the thread the last time it called into kernel32!RaiseException
10559 DT_CONTEXT m_raiseExceptionEntryContext;
10561 DWORD m_raiseExceptionExceptionCode;
10562 DWORD m_raiseExceptionExceptionFlags;
10563 DWORD m_raiseExceptionNumberParameters;
10564 ULONG_PTR m_raiseExceptionExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
10567 #ifdef DBG_TARGET_X86
10568 // the SEH handler which was the leaf when SaveCurrentSeh was called (prior to hijack)
10569 REMOTE_PTR m_pSavedLeafSeh;
10572 HRESULT EnableSSAfterBP();
10573 bool GetEEThreadCantStopHelper();
10575 DWORD_PTR GetTlsSlot(SIZE_T slot);
10576 REMOTE_PTR GetPreDefTlsSlot(SIZE_T slot, bool * pRead);
10578 void * m_pPatchSkipAddress;
10583 * This abstracts away an overload of the OS thread's TLS slot. In
10584 * particular the runtime may or may not have created a thread object for
10585 * a particular OS thread at any point.
10587 * If the runtime has created a thread object, then it stores a pointer to
10588 * that thread object in the thread's TLS slot.
10590 * If not, then interop-debugging uses that TLS slot to store temporary
10593 * To determine this, interop-debugging will set the low bit. Thus when
10594 * we read the TLS slot, if it is non-NULL, anything w/o the low bit set
10595 * is an EE thread object ptr. Anything with the low bit set is an
10596 * interop-debugging value. Any NULL is null, and an indicator that
10597 * there does not exist a runtime thread object for this thread yet.
10600 REMOTE_PTR m_pEEThread;
10601 REMOTE_PTR m_pdwTlsValue;
10602 BOOL m_fValidTlsData;
10604 UINT m_continueCountCached;
10606 void CacheEEDebuggerWord();
10607 HRESULT SetEEThreadValue(REMOTE_PTR EETlsValue);
10608 #ifdef FEATURE_IMPLICIT_TLS
10609 DWORD_PTR GetEEThreadValue();
10610 REMOTE_PTR GetClrModuleTlsDataAddress();
10611 REMOTE_PTR GetEETlsDataBlock();
10615 HRESULT GetEEDebuggerWord(REMOTE_PTR *pValue);
10616 HRESULT SetEEDebuggerWord(REMOTE_PTR value);
10617 HRESULT GetEEThreadPtr(REMOTE_PTR *ppEEThread);
10619 bool GetEEPGCDisabled();
10620 void GetEEState(bool *threadStepping, bool *specialManagedException);
10623 #endif // FEATURE_INTEROP_DEBUGGING
10626 //********************************************************************************
10627 //**************** App Domain Publishing Service API *****************************
10628 //********************************************************************************
10640 void SetData (void *pData) { m_pData = pData;}
10641 void *GetData () { return m_pData;}
10642 void SetNext (EnumElement *pNext) { m_pNext = pNext;}
10643 EnumElement *GetNext () { return m_pNext;}
10647 EnumElement *m_pNext;
10650 #if defined(FEATURE_DBG_PUBLISH)
10652 // Prototype of psapi!GetModuleFileNameEx.
10653 typedef DWORD FPGetModuleFileNameEx(HANDLE, HMODULE, LPTSTR, DWORD);
10656 class CorpubPublish : public CordbCommonBase, public ICorPublish
10660 virtual ~CorpubPublish();
10663 virtual const char * DbgGetName() { return "CordbPublish"; }
10666 //-----------------------------------------------------------
10668 //-----------------------------------------------------------
10670 ULONG STDMETHODCALLTYPE AddRef()
10672 return (BaseAddRef());
10674 ULONG STDMETHODCALLTYPE Release()
10676 return (BaseRelease());
10678 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10680 //-----------------------------------------------------------
10682 //-----------------------------------------------------------
10684 COM_METHOD EnumProcesses(
10685 COR_PUB_ENUMPROCESS Type,
10686 ICorPublishProcessEnum **ppIEnum);
10688 COM_METHOD GetProcess(
10690 ICorPublishProcess **ppProcess);
10692 //-----------------------------------------------------------
10694 //-----------------------------------------------------------
10695 static COM_METHOD CreateObject(REFIID id, void **object)
10699 if (id != IID_IUnknown && id != IID_ICorPublish)
10700 return (E_NOINTERFACE);
10702 CorpubPublish *pCorPub = new (nothrow) CorpubPublish();
10704 if (pCorPub == NULL)
10705 return (E_OUTOFMEMORY);
10707 *object = (ICorPublish*)pCorPub;
10714 HRESULT GetProcessInternal( unsigned pid, CorpubProcess **ppProcess );
10716 // Cached information to get the process name. Not available on all platforms, so may be null.
10717 HModuleHolder m_hPSAPIdll;
10718 FPGetModuleFileNameEx * m_fpGetModuleFileNameEx;
10721 class CorpubProcess : public CordbCommonBase, public ICorPublishProcess
10724 CorpubProcess(DWORD dwProcessId,
10728 AppDomainEnumerationIPCBlock *pAD,
10729 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10730 IPCReaderInterface *pIPCReader,
10731 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
10732 FPGetModuleFileNameEx * fpGetModuleFileNameEx);
10733 virtual ~CorpubProcess();
10736 virtual const char * DbgGetName() { return "CorpubProcess"; }
10740 //-----------------------------------------------------------
10742 //-----------------------------------------------------------
10744 ULONG STDMETHODCALLTYPE AddRef()
10746 return (BaseAddRef());
10748 ULONG STDMETHODCALLTYPE Release()
10750 return (BaseRelease());
10752 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10754 //-----------------------------------------------------------
10755 // ICorPublishProcess
10756 //-----------------------------------------------------------
10757 COM_METHOD IsManaged(BOOL *pbManaged);
10760 * Enumerate the list of known application domains in the target process.
10762 COM_METHOD EnumAppDomains(ICorPublishAppDomainEnum **ppEnum);
10765 * Returns the OS ID for the process in question.
10767 COM_METHOD GetProcessID(unsigned *pid);
10770 * Get the display name for a process.
10772 COM_METHOD GetDisplayName(ULONG32 cchName,
10774 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
10776 CorpubProcess *GetNextProcess () { return m_pNext;}
10777 void SetNext (CorpubProcess *pNext) { m_pNext = pNext;}
10779 // Helper to tell if this process has exited
10783 DWORD m_dwProcessId;
10789 AppDomainEnumerationIPCBlock *m_AppDomainCB;
10790 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10791 IPCReaderInterface *m_pIPCReader; // controls the lifetime of the AppDomainEnumerationIPCBlock
10792 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
10793 CorpubProcess *m_pNext; // pointer to the next process in the process list
10794 WCHAR *m_szProcessName;
10798 class CorpubAppDomain : public CordbCommonBase, public ICorPublishAppDomain
10801 CorpubAppDomain (__in LPWSTR szAppDomainName, ULONG Id);
10802 virtual ~CorpubAppDomain();
10805 virtual const char * DbgGetName() { return "CorpubAppDomain"; }
10808 //-----------------------------------------------------------
10810 //-----------------------------------------------------------
10812 ULONG STDMETHODCALLTYPE AddRef()
10814 return (BaseAddRef());
10816 ULONG STDMETHODCALLTYPE Release()
10818 return (BaseRelease());
10820 COM_METHOD QueryInterface (REFIID riid, void **ppInterface);
10822 //-----------------------------------------------------------
10823 // ICorPublishAppDomain
10824 //-----------------------------------------------------------
10827 * Get the name and ID for an application domain.
10829 COM_METHOD GetID (ULONG32 *pId);
10832 * Get the name for an application domain.
10834 COM_METHOD GetName (ULONG32 cchName,
10836 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
10838 CorpubAppDomain *GetNextAppDomain () { return m_pNext;}
10839 void SetNext (CorpubAppDomain *pNext) { m_pNext = pNext;}
10842 CorpubAppDomain *m_pNext;
10843 WCHAR *m_szAppDomainName;
10848 class CorpubProcessEnum : public CordbCommonBase, public ICorPublishProcessEnum
10851 CorpubProcessEnum(CorpubProcess *pFirst);
10852 virtual ~CorpubProcessEnum();
10855 virtual const char * DbgGetName() { return "CorpubProcessEnum"; }
10859 //-----------------------------------------------------------
10861 //-----------------------------------------------------------
10863 ULONG STDMETHODCALLTYPE AddRef()
10865 return (BaseAddRef());
10867 ULONG STDMETHODCALLTYPE Release()
10869 return (BaseRelease());
10871 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10873 //-----------------------------------------------------------
10874 // ICorPublishProcessEnum
10875 //-----------------------------------------------------------
10877 COM_METHOD Skip(ULONG celt);
10878 COM_METHOD Reset();
10879 COM_METHOD Clone(ICorPublishEnum **ppEnum);
10880 COM_METHOD GetCount(ULONG *pcelt);
10881 COM_METHOD Next(ULONG celt,
10882 ICorPublishProcess *objects[],
10883 ULONG *pceltFetched);
10886 CorpubProcess *m_pFirst;
10887 CorpubProcess *m_pCurrent;
10891 class CorpubAppDomainEnum : public CordbCommonBase, public ICorPublishAppDomainEnum
10894 CorpubAppDomainEnum(CorpubAppDomain *pFirst);
10895 virtual ~CorpubAppDomainEnum();
10899 virtual const char * DbgGetName() { return "CordbAppDomainEnum"; }
10903 //-----------------------------------------------------------
10905 //-----------------------------------------------------------
10907 ULONG STDMETHODCALLTYPE AddRef()
10909 return (BaseAddRef());
10911 ULONG STDMETHODCALLTYPE Release()
10913 return (BaseRelease());
10915 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10917 //-----------------------------------------------------------
10918 // ICorPublishAppDomainEnum
10919 //-----------------------------------------------------------
10920 COM_METHOD Skip(ULONG celt);
10921 COM_METHOD Reset();
10922 COM_METHOD Clone(ICorPublishEnum **ppEnum);
10923 COM_METHOD GetCount(ULONG *pcelt);
10925 COM_METHOD Next(ULONG celt,
10926 ICorPublishAppDomain *objects[],
10927 ULONG *pceltFetched);
10930 CorpubAppDomain *m_pFirst;
10931 CorpubAppDomain *m_pCurrent;
10935 #endif // defined(FEATURE_DBG_PUBLISH)
10937 class CordbHeapEnum : public CordbBase, public ICorDebugHeapEnum
10940 CordbHeapEnum(CordbProcess *proc);
10943 virtual const char * DbgGetName() { return "CordbHeapEnum"; }
10946 //-----------------------------------------------------------
10948 //-----------------------------------------------------------
10949 ULONG STDMETHODCALLTYPE AddRef()
10951 return (BaseAddRef());
10953 ULONG STDMETHODCALLTYPE Release()
10955 return (BaseRelease());
10957 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10959 COM_METHOD Skip(ULONG celt);
10960 COM_METHOD Reset();
10961 COM_METHOD Clone(ICorDebugEnum **ppEnum);
10962 COM_METHOD GetCount(ULONG *pcelt);
10964 COM_METHOD Next(ULONG celt,
10965 COR_HEAPOBJECT objects[],
10966 ULONG *pceltFetched);
10968 virtual void Neuter()
10971 CordbBase::Neuter();
10977 IDacDbiInterface::HeapWalkHandle mHeapHandle;
10981 class CordbRefEnum : public CordbBase, public ICorDebugGCReferenceEnum
10984 CordbRefEnum(CordbProcess *proc, BOOL walkWeakRefs);
10985 CordbRefEnum(CordbProcess *proc, CorGCReferenceType types);
10988 virtual const char * DbgGetName() { return "CordbHeapEnum"; }
10991 //-----------------------------------------------------------
10993 //-----------------------------------------------------------
10994 ULONG STDMETHODCALLTYPE AddRef()
10996 return (BaseAddRef());
10998 ULONG STDMETHODCALLTYPE Release()
11000 return (BaseRelease());
11002 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
11004 COM_METHOD Skip(ULONG celt);
11005 COM_METHOD Reset();
11006 COM_METHOD Clone(ICorDebugEnum **ppEnum);
11007 COM_METHOD GetCount(ULONG *pcelt);
11009 COM_METHOD Next(ULONG celt,
11010 COR_GC_REFERENCE refs[],
11011 ULONG *pceltFetched);
11013 virtual void Neuter();
11016 RefWalkHandle mRefHandle;
11017 BOOL mEnumStacksFQ;
11018 UINT32 mHandleMask;
11021 // Since the hash table of modules is per app domain (and
11022 // threads is per process) (for fast lookup from the appdomain/process),
11023 // we need this wrapper
11024 // here which allows us to iterate through an assembly's
11025 // modules. Is basically filters out modules/threads that aren't
11026 // in the assembly/appdomain. This slow & awkward for assemblies, but fast
11027 // for the common case - appdomain lookup.
11028 class CordbEnumFilter : public CordbBase,
11029 public ICorDebugThreadEnum,
11030 public ICorDebugModuleEnum
11033 CordbEnumFilter(CordbBase * pOwnerObj, NeuterList * pOwnerList);
11034 CordbEnumFilter(CordbEnumFilter*src);
11035 virtual ~CordbEnumFilter();
11037 virtual void Neuter();
11041 virtual const char * DbgGetName() { return "CordbEnumFilter"; }
11045 //-----------------------------------------------------------
11047 //-----------------------------------------------------------
11049 ULONG STDMETHODCALLTYPE AddRef()
11051 return (BaseAddRef());
11053 ULONG STDMETHODCALLTYPE Release()
11055 return (BaseRelease());
11057 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
11059 //-----------------------------------------------------------
11061 //-----------------------------------------------------------
11062 COM_METHOD Skip(ULONG celt);
11063 COM_METHOD Reset();
11064 COM_METHOD Clone(ICorDebugEnum **ppEnum);
11065 COM_METHOD GetCount(ULONG *pcelt);
11066 //-----------------------------------------------------------
11067 // ICorDebugModuleEnum
11068 //-----------------------------------------------------------
11069 COM_METHOD Next(ULONG celt,
11070 ICorDebugModule *objects[],
11071 ULONG *pceltFetched);
11073 //-----------------------------------------------------------
11074 // ICorDebugThreadEnum
11075 //-----------------------------------------------------------
11076 COM_METHOD Next(ULONG celt,
11077 ICorDebugThread *objects[],
11078 ULONG *pceltFetched);
11080 HRESULT Init (ICorDebugModuleEnum *pModEnum, CordbAssembly *pAssembly);
11081 HRESULT Init (ICorDebugThreadEnum *pThreadEnum, CordbAppDomain *pAppDomain);
11085 HRESULT NextWorker(ULONG celt, ICorDebugModule *objects[], ULONG *pceltFetched);
11086 HRESULT NextWorker(ULONG celt,ICorDebugThread *objects[], ULONG *pceltFetched);
11088 // Owning object is our link to the CordbProcess* tree. Never null until we're neutered.
11089 // NeuterList is related to the owning object. Need to cache it so that we can pass it on
11091 CordbBase * m_pOwnerObj; // provides us w/ a CordbProcess*
11092 NeuterList * m_pOwnerNeuterList;
11095 EnumElement *m_pFirst;
11096 EnumElement *m_pCurrent;
11100 // Helpers to double-check the RS results against DAC.
11101 #if defined(_DEBUG)
11102 void CheckAgainstDAC(CordbFunction * pFunc, void * pIP, mdMethodDef mdExpected);
11105 HRESULT CopyOutString(const WCHAR * pInputString, ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
11109 inline UINT AllocCookieCordbEval(CordbProcess *pProc, CordbEval* p)
11111 _ASSERTE(pProc->GetProcessLock()->HasLock());
11112 return pProc->m_EvalTable.Add(p);
11114 inline CordbEval * UnwrapCookieCordbEval(CordbProcess *pProc, UINT cookie)
11116 _ASSERTE(pProc->GetProcessLock()->HasLock());
11117 return pProc->m_EvalTable.LookupAndRemove(cookie);
11121 // We defined this at the top of the file - undef it now so that we don't pollute other files.
11122 #undef CRITICAL_SECTION
11127 //-----------------------------------------------------------------------------
11128 // For debug builds, we maintain some thread-state to track debug bits
11129 // to help us do some more aggressive asserts.
11130 //-----------------------------------------------------------------------------
11132 class PublicAPIHolder;
11133 class PublicReentrantAPIHolder;
11134 class PublicCallbackHolder;
11135 class PublicDebuggerErrorCallbackHolder;
11140 friend class PublicAPIHolder;
11141 friend class PublicReentrantAPIHolder;
11142 friend class PublicCallbackHolder;
11143 friend class PublicDebuggerErrorCallbackHolder;
11144 friend class PrivateShimCallbackHolder;
11148 // The TLS slot that we'll put this thread object in.
11149 static DWORD s_TlsSlot;
11151 static LONG s_Total; // Total count of thread objects
11153 // Get a thread object for the current thread via a TLS lookup.
11154 static DbgRSThread * GetThread();
11156 // Call during DllMain to release this.
11157 static DbgRSThread * Create()
11159 InterlockedIncrement(&s_Total);
11161 DbgRSThread * p = new (nothrow) DbgRSThread();
11162 BOOL f = TlsSetValue(s_TlsSlot, p);
11169 InterlockedDecrement(&s_Total);
11171 BOOL f = TlsSetValue(s_TlsSlot, NULL);
11177 // Return true if this thread is inside the RS.
11178 bool IsInRS() { return m_cInsideRS > 0; }
11181 // These will assert if the operation is unsafe.
11182 void NotifyTakeLock(RSLock * pLock);
11183 void NotifyReleaseLock(RSLock * pLock);
11185 // Used to map other resources (like thread access) into the lock hierachy.
11186 // Note this only effects lock leveling checks and doesn't effect HoldsAnyLock().
11187 void TakeVirtualLock(RSLock::ERSLockLevel level);
11188 void ReleaseVirtualLock(RSLock::ERSLockLevel level);
11190 // return true if this thread is holding any RS locks. Useful to check on Public API transition boundaries.
11191 bool HoldsAnyDbgApiLocks() { return m_cTotalDbgApiLocks > 0; }
11198 void SetThreadType(EThreadType e) { m_eThreadType = e; }
11200 bool IsWin32EventThread() { return m_eThreadType == cW32ET; }
11202 void SetUnrecoverableCallback(bool fIsUnrecoverableErrorCallback)
11205 _ASSERTE(m_fIsUnrecoverableErrorCallback != fIsUnrecoverableErrorCallback);
11207 m_fIsUnrecoverableErrorCallback = fIsUnrecoverableErrorCallback;
11210 inline void AssertThreadIsLockFree()
11212 // If we're in an unrecoverable callback, we may hold locks.
11213 _ASSERTE(m_fIsUnrecoverableErrorCallback
11214 || !HoldsAnyDbgApiLocks() ||
11215 !"Thread should not have locks on public/internal transition");
11219 EThreadType m_eThreadType;
11221 // More debugging tidbits - tid that we're on, and a sanity checking cookie.
11227 COOKIE_VALUE = 0x12345678
11231 // This tells us if the thread is currently in the scope of a PublicAPIHolder.
11234 // This tells us if a thread is currently being dispatched via a callback.
11235 bool m_fIsInCallback;
11237 // We explicitly track if this thread is in an unrecoverable error callback
11238 // b/c that will weaken some other asserts.
11239 // It would be nice to clean up the unrecoverable error callback and have it
11240 // behave like all the other callbacks. Then we can remove this.
11241 bool m_fIsUnrecoverableErrorCallback;
11243 // Locking context. Used to tell what levels of locks we hold so we can determine if a lock is safe to take.
11244 int m_cLocks[RSLock::LL_MAX];
11245 int m_cTotalDbgApiLocks;
11248 //-----------------------------------------------------------------------------
11249 // Mark when we enter / exit public APIs
11250 //-----------------------------------------------------------------------------
11252 // Holder for Non-reentrant Public API (this is the vast majority)
11253 class PublicAPIHolder
11259 DbgRSThread * pThread = DbgRSThread::GetThread();
11260 pThread->m_cInsideRS++;
11261 _ASSERTE(pThread->m_cInsideRS == 1 || !"Non-reentrant API being called re-entrantly");
11263 // Should never be in public w/ these locks
11264 pThread->AssertThreadIsLockFree();
11266 ~PublicAPIHolder() {
11268 DbgRSThread * pThread = DbgRSThread::GetThread();
11269 pThread->m_cInsideRS--;
11270 _ASSERTE(!pThread->IsInRS());
11272 // Should never be in public w/ these locks. If we assert here,
11273 // then we're leaking locks.
11274 pThread->AssertThreadIsLockFree();
11278 // Holder for reentrant public API
11279 class PublicReentrantAPIHolder
11282 PublicReentrantAPIHolder()
11285 DbgRSThread * pThread = DbgRSThread::GetThread();
11286 pThread->m_cInsideRS++;
11288 // Cache count now so that we can calidate it in the dtor.
11289 m_oldCount = pThread->m_cInsideRS;
11290 // Since a we may have been called from within the RS, we may hold locks
11292 ~PublicReentrantAPIHolder()
11296 DbgRSThread * pThread = DbgRSThread::GetThread();
11298 // Ensure that our children were balanced
11299 _ASSERTE(pThread->m_cInsideRS == m_oldCount);
11301 pThread->m_cInsideRS--;
11302 _ASSERTE(pThread->m_cInsideRS >= 0);
11304 // Since a we may have been called from within the RS, we may hold locks
11310 // Special holder for DebuggerError callback. This adjusts InsideRS count w/o
11311 // verifying locks. This is very dangerous. We allow this b/c the Debugger Error callback can come at any time.
11312 class PublicDebuggerErrorCallbackHolder
11315 PublicDebuggerErrorCallbackHolder()
11317 // Exiting from RS; entering Cordbg via a callback
11318 DbgRSThread * pThread = DbgRSThread::GetThread();
11320 // This callback is called from within the RS
11321 _ASSERTE(pThread->IsInRS());
11323 // Debugger error callback may be called from deep within the RS (after many nestings).
11324 // So immediately jump to outside. We'll restore this in dtor.
11325 m_oldCount = pThread->m_cInsideRS;
11326 pThread->m_cInsideRS = 0;
11328 _ASSERTE(!pThread->IsInRS());
11330 // We may be leaking locks for the unrecoverable callback. We mark that so that
11331 // the asserts about locking can be relaxed.
11332 pThread->SetUnrecoverableCallback(true);
11335 ~PublicDebuggerErrorCallbackHolder()
11337 // Re-entering RS from after a callback.
11338 DbgRSThread * pThread = DbgRSThread::GetThread();
11340 pThread->SetUnrecoverableCallback(false);
11341 pThread->m_cInsideRS = m_oldCount;
11343 // Our status of being "Inside the RS" is now restored.
11344 _ASSERTE(pThread->IsInRS());
11350 //---------------------------------------------------------------------------------------
11352 // This is the same as the PublicCallbackHolder, except that this class doesn't assert that we are not holding
11353 // any locks when we call out to the shim.
11356 // @dbgtodo shim, synchronization - We need to settle on one consistent relationshipo between the RS
11357 // and the shim. Then we can clean up the sychronization story. Right now some code considers the shim
11358 // to be outside of the RS, and so we cannot hold any locks when we call out to the shim. However, there
11359 // are cases where we must hold a lock when we call out to the shim. For example, when we call out to the
11360 // shim to do a V2-style stackwalk, we need to be holding the stop-go lock so that another thread can't
11361 // come in and call Continue(). Finally, when we fix this, we should fix
11362 // PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM() as well.
11365 class PrivateShimCallbackHolder
11368 PrivateShimCallbackHolder()
11370 // Exiting from RS; entering Cordbg via a callback
11371 DbgRSThread * pThread = DbgRSThread::GetThread();
11373 // This callback is called from within the RS
11374 _ASSERTE(pThread->IsInRS());
11376 // Debugger error callback may be called from deep within the RS (after many nestings).
11377 // So immediately jump to outside. We'll restore this in dtor.
11378 m_oldCount = pThread->m_cInsideRS;
11379 pThread->m_cInsideRS = 0;
11381 _ASSERTE(!pThread->IsInRS());
11384 ~PrivateShimCallbackHolder()
11386 // Re-entering RS from after a callback.
11387 DbgRSThread * pThread = DbgRSThread::GetThread();
11389 pThread->m_cInsideRS = m_oldCount;
11391 // Our status of being "Inside the RS" is now restored.
11392 _ASSERTE(pThread->IsInRS());
11398 class InternalAPIHolder
11401 InternalAPIHolder()
11403 DbgRSThread * pThread = DbgRSThread::GetThread();
11405 // Internal APIs should already be inside the RS.
11406 _ASSERTE(pThread->IsInRS() ||!"Internal API being called directly from outside (there should be a public API on the stack)");
11411 //---------------------------------------------------------------------------------------
11413 // This is a simple holder to assert that the current thread is holding the process lock. The purpose of
11414 // having this holder is to enforce a lock ordering between the process lock in the RS and the DD lock in DAC.
11415 // If a thread needs to take the process lock, it must do so BEFORE taking the DD lock. Otherwise we could have
11416 // a deadlock between the process lock and the DD lock.
11418 // Normally we take the process lock before calling out to DAC, and every DAC API takes the DD lock on entry.
11419 // Moreover, normally DAC doesn't call back into the RS. The exceptions we currently have are:
11420 // 1) enumeration callbacks (e.g. code:CordbProcess::AppDomainEnumerationCallback)
11421 // 2) code:IDacDbiInterface::IMetaDataLookup
11422 // 3) code:IDacDbiInterface::IAllocator
11423 // 4) code:IStringHolder
11425 // Note that the last two are fine because they don't need to take the process lock. The first two categories
11426 // need to take the process lock before calling into DAC to avoid potential deadlocks.
11429 class InternalDacCallbackHolder
11432 InternalDacCallbackHolder(CordbProcess * pProcess)
11434 _ASSERTE(pProcess->ThreadHoldsProcessLock());
11438 // cotract that occurs at public builds.
11439 #define PUBLIC_CONTRACT \
11440 CONTRACTL { NOTHROW; } CONTRACTL_END;
11443 // Private hook for Shim to call into DBI.
11444 // Since Shim is considered outside DBI, we need to mark that we've re-entered.
11445 // Big difference is that we can throw across this boundary.
11446 // @dbgtodo private shim hook - Eventually, these will all go away since the shim will be fully public.
11447 #define PUBLIC_API_ENTRY_FOR_SHIM(_pThis) \
11448 PublicAPIHolder __pah;
11451 #define PUBLIC_API_UNSAFE_ENTRY_FOR_SHIM(_pThis) \
11452 PublicDebuggerErrorCallbackHolder __pahCallback;
11454 // @dbgtodo shim, synchronization - Because of the problem mentioned in the comments for
11455 // PrivateShimCallbackHolder, we need this macro so that we don't hit an assertion when we come back into
11456 // the RS from the shim.
11457 #define PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(_pThis) \
11458 PublicReentrantAPIHolder __pah;
11460 //-----------------------------------------------------------------------------
11461 // Declare whether an API is public or internal
11462 // Public APIs have the following:
11463 // - We may be called concurrently from multiple threads (ie, not thread safe)
11464 // - This thread does not hold any RS Locks while entering or leaving this function.
11465 // - May or May-not be reentrant.
11467 // - let us specifically mark that we're not a public API, and
11468 // - we're only being called through a public API.
11469 //-----------------------------------------------------------------------------
11470 #define PUBLIC_API_ENTRY(_pThis) \
11471 STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API '%s', this=0x%p]\n", __FUNCTION__, _pThis); \
11473 PublicAPIHolder __pah;
11475 // Mark public APIs that are re-entrant.
11476 // Very few of our APIs should be re-entrant. Even for field access APIs (like GetXXX), the
11477 // public version is heavier (eg, checking the HRESULT) so we benefit from having a fast
11478 // internal version and calling that directly.
11479 #define PUBLIC_REENTRANT_API_ENTRY(_pThis) \
11480 STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API (re) '%s', this=0x%p]\n", __FUNCTION__, _pThis); \
11482 PublicReentrantAPIHolder __pah;
11486 // Mark internal APIs.
11487 // All internal APIs are reentrant (duh)
11488 #define INTERNAL_API_ENTRY(_pThis) InternalAPIHolder __pah; __pah.dummy();
11490 // Mark an internal API from ATT_REQUIRE_STOP / ATT_ALLOW_LIVE_DO_STOP_GO.
11491 // This can assert that we're safe to send IPC events (that we're stopped and hold the SG lock)
11492 // @dbgtodo synchronization - in V2, this would assert that we were synced.
11493 // In V3, our definition of Sync is in flux. Need to resolve this with the synchronization feature crew.
11494 #define INTERNAL_SYNC_API_ENTRY(pProc) \
11495 CordbProcess * __pProc = (pProc); \
11496 _ASSERTE(__pProc->GetStopGoLock()->HasLock() || !"Must have stop go lock for internal-sync-api"); \
11497 InternalAPIHolder __pah; __pah.dummy();
11501 // Mark that a thread is owned by us. Thus the thread's "Inside RS" count > 0.
11502 #define INTERNAL_THREAD_ENTRY(_pThis) \
11503 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[Internal thread started, this=0x%p]\n", _pThis); \
11505 PublicAPIHolder __pah;
11507 // @dbgtodo unrecoverable error - This sould be deprecated once we deprecate UnrecoverableError.
11508 #define PUBLIC_CALLBACK_IN_THIS_SCOPE_DEBUGGERERROR(_pThis) \
11509 PublicDebuggerErrorCallbackHolder __pahCallback;
11511 #define PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(_pThis) \
11512 PrivateShimCallbackHolder __pahCallback;
11514 // Mark places where DAC may call back into DBI. We need to assert that we are holding the process lock in
11515 // these places, since otherwise we could deadlock between the DD lock and the process lock.
11516 #define INTERNAL_DAC_CALLBACK(__pProcess) \
11517 InternalDacCallbackHolder __idch(__pProcess);
11520 // Helper to log debug events.
11521 inline void StressLogNativeDebugEvent(const DEBUG_EVENT * pDebugEvent, bool fOOB)
11523 if ((pDebugEvent)->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
11525 STRESS_LOG4(LF_CORDB, LL_EVERYTHING, "[Dispatching Win32 code=1 (EXCEPTION_DEBUG_EVENT, tid=%x, oob=%d, code=0x%x, 1st=%d]\n",
11526 pDebugEvent->dwThreadId,
11528 pDebugEvent->u.Exception.ExceptionRecord.ExceptionCode,
11529 pDebugEvent->u.Exception.dwFirstChance);
11533 STRESS_LOG3(LF_CORDB, LL_EVERYTHING, "[Dispatching Win32 code=%d, tid=%x, oob=%d.]\n",
11534 pDebugEvent->dwDebugEventCode, pDebugEvent->dwThreadId, fOOB);
11539 #define PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(_pThis, _pDebugEvent, _fOOB) \
11540 StressLogNativeDebugEvent(_pDebugEvent, _fOOB); \
11541 PublicCallbackHolder __pahCallback(DB_IPCE_INVALID_EVENT);
11543 // Visisbility spec for dtors.
11544 // Currently, dtors are like public methods b/c they can be called from Release.
11545 // But they're also reentrant since they may be called from an internal-release.
11546 // @todo - we'd like to get all "useful" work out of the dtor; in which case we may
11547 // be able to change this to something more aggressive.
11548 #define DTOR_ENTRY(_pThis) PUBLIC_REENTRANT_API_ENTRY(_pThis)
11551 //-----------------------------------------------------------------------------
11552 // Typesafe bool for thread safety. This typesafety forces us to use
11553 // an specific reason for thread-safety, taken from a well-known list.
11554 // This is mostly concerned w/ being serialized.
11555 // Note that this assertion must be done on a per function basis and we
11556 // can't have any sort of 'ThreadSafetyReason CallerIsSafe()' b/c we can't
11557 // enforce that all of our callers are thread safe (only that our current caller is safe).
11558 //-----------------------------------------------------------------------------
11559 struct ThreadSafetyReason
11562 ThreadSafetyReason(bool f) { fIsSafe = f; }
11567 // Different valid reasons that we may be threads safe.
11568 inline ThreadSafetyReason HoldsLock(RSLock * pLock)
11570 _ASSERTE(pLock != NULL);
11571 return ThreadSafetyReason(pLock->HasLock());
11573 inline ThreadSafetyReason OnW32ET(CordbProcess * pProc)
11575 return ThreadSafetyReason(IsWin32EventThread(pProc));
11578 inline ThreadSafetyReason OnRCET(Cordb *pCordb)
11580 return ThreadSafetyReason (IsRCEventThread(pCordb));
11583 // We use this when we assume that a function is thread-safe (b/c it's serialized).
11584 // The reason also lets us assert that our assumption is true.
11585 // By using a function, we enforce typesafety and thus require a valid reason
11586 // (as opposed to an arbitrary bool)
11587 inline void AssertThreadSafeHelper(ThreadSafetyReason r) {
11588 _ASSERTE(r.fIsSafe);
11591 //-----------------------------------------------------------------------------
11592 // Assert that the given scope is always called on a single thread b/c of
11593 // xReason. Common reasons may be b/c we hold a lock or we're always
11594 // called on a specific thread (Eg w32et).
11595 // The only valid reasons are of type ThreadSafetyReason (thus forcing us to
11596 // choose from a well-known list of valid reasons).
11597 //-----------------------------------------------------------------------------
11598 #define ASSERT_SINGLE_THREAD_ONLY(xReason) \
11599 AssertThreadSafeHelper(xReason);
11603 //-----------------------------------------------------------------------------
11604 // Retail versions just nop. See the debug implementation for these
11605 // for their semantics.
11606 //-----------------------------------------------------------------------------
11608 #define PUBLIC_CONTRACT
11609 #define PUBLIC_API_ENTRY_FOR_SHIM(_pThis)
11610 #define PUBLIC_API_UNSAFE_ENTRY_FOR_SHIM(_pThis)
11611 #define PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(_pThis)
11612 #define PUBLIC_API_ENTRY(_pThis)
11613 #define PUBLIC_REENTRANT_API_ENTRY(_pThis)
11614 #define INTERNAL_API_ENTRY(_pThis)
11615 #define INTERNAL_SYNC_API_ENTRY(pProc)
11616 #define INTERNAL_THREAD_ENTRY(_pThis)
11617 #define PUBLIC_CALLBACK_IN_THIS_SCOPE_DEBUGGERERROR(_pThis)
11618 #define PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(_pThis)
11619 #define INTERNAL_DAC_CALLBACK(__pProcess)
11620 #define PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(_pThis, _pDebugEvent, _fOOB)
11621 #define DTOR_ENTRY(_pThis)
11624 #define ASSERT_SINGLE_THREAD_ONLY(x)
11626 #endif // #if RSCONTRACTS
11629 class PublicCallbackHolder
11632 PublicCallbackHolder(RSLockHolder * pHolder, DebuggerIPCEventType type)
11634 m_pHolder = pHolder;
11635 _ASSERTE(!pHolder->IsNull()); // acquired
11637 // Release the lock. We'll reacquire it at the dtor.
11638 m_pHolder->Release();
11643 PublicCallbackHolder(DebuggerIPCEventType type)
11649 void Init(DebuggerIPCEventType type)
11653 #if defined(RSCONTRACTS)
11654 // Exiting from RS; entering Cordbg via a callback
11655 DbgRSThread * pThread = DbgRSThread::GetThread();
11657 // m_cInsideRS may be arbitrarily large if we're called from a PUBLIC_REENTRANT_API,
11658 // so just remember the current count and blast it back to 0.
11659 m_oldCount = pThread->m_cInsideRS;
11660 pThread->m_cInsideRS = 0;
11662 _ASSERTE(!pThread->IsInRS());
11664 // Should never be in public w/ these locks. (Even if we're re-entrant.)
11665 pThread->AssertThreadIsLockFree();
11666 #endif // RSCONTRACTS
11669 ~PublicCallbackHolder()
11671 #if defined(RSCONTRACTS)
11672 // Re-entering RS from after a callback.
11673 DbgRSThread * pThread = DbgRSThread::GetThread();
11674 _ASSERTE(!pThread->IsInRS());
11676 pThread->m_cInsideRS = m_oldCount;
11678 // Should never be in public w/ these locks. (Even if we're re-entrant.)
11679 pThread->AssertThreadIsLockFree();
11680 #endif // RSCONTRACTS
11682 // Reacquire the lock
11683 if (m_pHolder != NULL)
11685 m_pHolder->Acquire();
11690 DebuggerIPCEventType m_type;
11691 RSLockHolder * m_pHolder;
11695 // Mark that a thread is calling out via a callback. This will adjust the "Inside RS" counter.
11696 #define PUBLIC_CALLBACK_IN_THIS_SCOPE(_pThis, pLockHolder, event) \
11697 STRESS_LOG1(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s']\n", IPCENames::GetName((event)->type)); \
11698 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11700 #define PUBLIC_CALLBACK_IN_THIS_SCOPE1(_pThis, pLockHolder, event, formatLiteralString, arg0) \
11701 STRESS_LOG2(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0); \
11702 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11704 #define PUBLIC_CALLBACK_IN_THIS_SCOPE2(_pThis, pLockHolder, event, formatLiteralString, arg0, arg1) \
11705 STRESS_LOG3(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0, arg1); \
11706 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11708 #define PUBLIC_CALLBACK_IN_THIS_SCOPE3(_pThis, pLockHolder, event, formatLiteralString, arg0, arg1, arg2) \
11709 STRESS_LOG4(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0, arg1, arg2); \
11710 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11713 #define PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(_pThis) \
11714 PublicCallbackHolder __pahCallback(DB_IPCE_INVALID_EVENT);
11716 #define PUBLIC_CALLBACK_IN_THIS_SCOPE0(_pThis, pLockHolder) \
11717 PublicCallbackHolder __pahCallback(pLockHolder, DB_IPCE_INVALID_EVENT);
11720 //-----------------------------------------------------------------------------
11722 inline void ValidateOrThrow(const void * p)
11726 ThrowHR(E_INVALIDARG);
11730 // aligns argBase on platforms that require it else it's a no-op
11731 inline void AlignAddressForType(CordbType* pArgType, CORDB_ADDRESS& argBase)
11733 #ifdef DBG_TARGET_ARM
11734 // TODO: review the following
11735 #ifdef FEATURE_64BIT_ALIGNMENT
11736 BOOL align = FALSE;
11737 HRESULT hr = pArgType->RequiresAlign8(&align);
11738 _ASSERTE(SUCCEEDED(hr));
11741 argBase = ALIGN_ADDRESS(argBase, 8);
11742 #endif // FEATURE_64BIT_ALIGNMENT
11743 #endif // DBG_TARGET_ARM
11746 //-----------------------------------------------------------------------------
11747 // Macros to mark public ICorDebug functions
11750 // HRESULT CordbXYZ:Function(...)
11752 // HRESULT hr = S_OK;
11753 // PUBLIC_API_BEGIN(this);
11754 // // body, may throw
11755 // PUBLIC_API_END(hr);
11758 #define PUBLIC_API_BEGIN(__this) \
11759 CordbBase * __pThis = (__this); \
11760 PUBLIC_API_ENTRY(__pThis); \
11762 RSLockHolder __lockHolder(__pThis->GetProcess()->GetProcessLock()); \
11763 THROW_IF_NEUTERED(__pThis); \
11765 // You should not use this in general. We're adding it as a temporary workaround for a
11766 // particular scenario until we do the synchronization feature crew
11767 #define PUBLIC_API_NO_LOCK_BEGIN(__this) \
11768 CordbBase * __pThis = (__this); \
11769 PUBLIC_API_ENTRY(__pThis); \
11771 THROW_IF_NEUTERED(__pThis); \
11773 // Some APIs (that invoke callbacks), need to toggle the lock.
11774 #define GET_PUBLIC_LOCK_HOLDER() (&__lockHolder)
11776 #define PUBLIC_API_END(__hr) \
11777 } EX_CATCH_HRESULT(__hr); \
11779 // @todo: clean up API constracts. Should we really be taking the Process lock for
11780 // reentrant APIS??
11781 #define PUBLIC_REENTRANT_API_BEGIN(__this) \
11782 CordbBase * __pThis = (__this); \
11783 PUBLIC_REENTRANT_API_ENTRY(__pThis); \
11785 RSLockHolder __lockHolder(__pThis->GetProcess()->GetProcessLock()); \
11786 THROW_IF_NEUTERED(__pThis); \
11788 #define PUBLIC_REENTRANT_API_END(__hr) \
11789 } EX_CATCH_HRESULT(__hr); \
11791 // If an API needs to take the stop/go lock as well as the process lock, the
11792 // stop/go lock has to be taken first. This is an alternative to PUBLIC_REENTRANT_API_BEGIN
11793 // that allows this, since it doesn't take the process lock. It should be closed with
11794 // PUBLIC_REENTRANT_API_END
11795 #define PUBLIC_REENTRANT_API_NO_LOCK_BEGIN(__this) \
11796 CordbBase * __pThis = (__this); \
11797 PUBLIC_REENTRANT_API_ENTRY(__pThis); \
11799 THROW_IF_NEUTERED(__pThis); \
11802 //-----------------------------------------------------------------------------
11803 // For debugging ease, cache some global values.
11804 // Include these in retail & free because that's where we need them the most!!
11805 // Optimized builds may not let us view locals & parameters. So Having these
11806 // cached as global values should let us inspect almost all of
11807 // the interesting parts of the RS even in a Retail build!
11808 //-----------------------------------------------------------------------------
11809 struct RSDebuggingInfo
11811 // There should only be 1 global Cordb object. Store it here.
11814 // We have lots of processes. Keep a pointer to the most recently touched
11815 // (subjective) process, as a hint about what our "current" process is.
11816 // If we're only debugging 1 process, this will be sufficient.
11817 CordbProcess * m_MRUprocess;
11819 CordbRCEventThread * m_RCET;
11822 #include "rspriv.inl"
11824 #endif // #if RSPRIV_H