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//*****************************************************************************
5// rspriv.
6//
7
8//
9// Common include file for right-side of debugger.
10//*****************************************************************************
11
12#ifndef RSPRIV_H
13#define RSPRIV_H
14
15#include <winwrap.h>
16#include <windows.h>
17
18#include <utilcode.h>
19
20
21#ifdef _DEBUG
22#define LOGGING
23#endif
24
25#include <log.h>
26#include <corerror.h>
27
28#include "cor.h"
29
30#include "cordebug.h"
31#include "xcordebug.h"
32#include "cordbpriv.h"
33#include "mscoree.h"
34
35#include <cordbpriv.h>
36#include <dbgipcevents.h>
37
38#include "common.h"
39#include "primitives.h"
40
41#include "dacdbiinterface.h"
42
43#include "helpers.h"
44
45struct MachineInfo;
46
47#include "processdescriptor.h"
48#include "nativepipeline.h"
49#include "stringcopyholder.h"
50
51
52#include "eventchannel.h"
53
54#undef ASSERT
55#define CRASH(x) _ASSERTE(!x)
56#define ASSERT(x) _ASSERTE(x)
57
58// We want to keep the 'worst' HRESULT - if one has failed (..._E_...) & the
59// other hasn't, take the failing one. If they've both/neither failed, then
60// it doesn't matter which we take.
61// Note that this macro favors retaining the first argument
62#define WORST_HR(hr1,hr2) (FAILED(hr1)?hr1:hr2)
63
64// #UseDataTarget
65// Forbid usage of OS APIs that we should be using the data-target for
66#define ReadProcessMemory DONT_USE_READPROCESS_MEMORY
67#define WriteProcessMemory DONT_USE_WRITEPROCESS_MEMORY
68
69
70/* ------------------------------------------------------------------------- *
71 * Forward class declarations
72 * ------------------------------------------------------------------------- */
73
74class CordbBase;
75class CordbValue;
76class CordbModule;
77class CordbClass;
78class CordbFunction;
79class CordbCode;
80class CordbFrame;
81class CordbJITILFrame;
82class CordbInternalFrame;
83class CordbContext;
84class CordbThread;
85class CordbVariableHome;
86
87#ifdef FEATURE_INTEROP_DEBUGGING
88class CordbUnmanagedThread;
89struct CordbUnmanagedEvent;
90#endif
91
92class CordbProcess;
93class CordbAppDomain;
94class CordbAssembly;
95class CordbBreakpoint;
96class CordbStepper;
97class Cordb;
98class CordbEnCSnapshot;
99class CordbWin32EventThread;
100class CordbRCEventThread;
101class CordbRegisterSet;
102class CordbNativeFrame;
103class CordbObjectValue;
104class CordbEnCErrorInfo;
105class CordbEnCErrorInfoEnum;
106class Instantiation;
107class CordbType;
108class CordbNativeCode;
109class CordbILCode;
110class CordbReJitILCode;
111class CordbEval;
112
113class CordbMDA;
114
115class CorpubPublish;
116class CorpubProcess;
117class CorpubAppDomain;
118class CorpubProcessEnum;
119class CorpubAppDomainEnum;
120
121
122class RSLock;
123class NeuterList;
124
125class IDacDbiInterface;
126
127#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
128class DbgTransportTarget;
129class DbgTransportSession;
130#endif // FEATURE_DBGIPC_TRANSPORT_DI
131
132// @dbgtodo private shim hook - the RS has private hooks into the shim to help bridge the V2/V3 gap.
133// This helps provide a working dogfooding story throughout our transition.
134// These hooks must be removed before shipping.
135class ShimProcess;
136
137
138#ifndef FEATURE_PAL
139extern HINSTANCE GetModuleInst();
140#endif
141
142
143template <class T>
144class CordbSafeHashTable;
145
146
147//---------------------------------------------------------------------------------------
148//
149// This is an encapsulation of the information necessary to connect to the debugger proxy on a remote machine.
150// It includes the IP address and the port number. The IP address can be set via the env var
151// COMPlus_DbgTransportProxyAddress, and the port number is fixed when Mac debugging is configured.
152//
153
154struct MachineInfo
155{
156public:
157 void Init(DWORD dwIPAddress, USHORT usPort)
158 {
159 m_dwIPAddress = dwIPAddress;
160 m_usPort = usPort;
161 }
162
163 void Clear()
164 {
165 m_dwIPAddress = 0;
166 m_usPort = 0;
167 }
168
169 DWORD GetIPAddress() {return m_dwIPAddress;};
170 USHORT GetPort() {return m_usPort;};
171
172private:
173 DWORD m_dwIPAddress;
174 USHORT m_usPort;
175};
176
177extern forDbiWorker forDbi;
178
179// for dbi we just default to new, but we need to have these defined for both dac and dbi
180inline void * operator new(size_t lenBytes, const forDbiWorker &)
181{
182 void * result = new BYTE[lenBytes];
183 if (result == NULL)
184 {
185 ThrowOutOfMemory();
186 }
187 return result;
188}
189
190inline void * operator new[](size_t lenBytes, const forDbiWorker &)
191{
192 void * result = new BYTE[lenBytes];
193 if (result == NULL)
194 {
195 ThrowOutOfMemory();
196 }
197 return result;
198}
199
200// Helper to delete memory used with the IDacDbiInterface::IAllocator interface.
201template<class T> inline
202void DeleteDbiMemory(T *p)
203{
204 delete p;
205}
206
207
208
209//---------------------------------------------------------------------------------------
210//
211// Simple array of holders (either RSSmartPtrs or RSExtSmartPtrs).
212// Holds a reference to each element.
213//
214// Notes:
215// T is the base type and HOLDER_T is the type of the holder. All functions implemented on this base
216// class must work for both RSSmartPtrs and RSExtSmartPtrs. For example, there is no concept of neutering
217// for RSExtSmartPtrs.
218//
219
220template<typename T, typename HOLDER_T>
221class BaseRSPtrArray
222{
223public:
224 BaseRSPtrArray()
225 {
226 m_pArray = NULL;
227 m_cElements = 0;
228 }
229
230 // Is the array emtpy?
231 bool IsEmpty() const
232 {
233 return (m_pArray == NULL);
234 }
235
236 // Allocate an array of ptrs.
237 // Returns false if not enough memory; else true.
238 bool Alloc(unsigned int cElements)
239 {
240 // Caller should have already Neutered
241 _ASSERTE(IsEmpty());
242
243 // It's legal to allocate 0 items. We'll succeed the allocation, but still claim that IsEmpty() == true.
244 if (cElements == 0)
245 {
246 return true;
247 }
248
249 // RSSmartPtr ctor will ensure all elements are null initialized.
250 m_pArray = new (nothrow) HOLDER_T [cElements];
251 if (m_pArray == NULL)
252 {
253 return false;
254 }
255
256 m_cElements = cElements;
257 return true;
258 }
259
260 // Allocate an array of ptrs.
261 // Throw on failure
262 void AllocOrThrow(unsigned int cElements)
263 {
264 if (!Alloc(cElements))
265 {
266 ThrowOutOfMemory();
267 }
268 }
269
270 // Release each element and empty the array.
271 void Clear()
272 {
273 // this Invoke dtors on each element which will release each element
274 delete [] m_pArray;
275
276 m_pArray = NULL;
277 m_cElements = 0;
278 }
279
280 // Array lookup. Caller gaurantees this is in range.
281 // Used for reading
282 T* operator [] (unsigned int index) const
283 {
284 _ASSERTE(m_pArray != NULL);
285 CONSISTENCY_CHECK_MSGF((index <= m_cElements), ("Index out of range. Index=%u, Max=%u\n", index, m_cElements));
286
287 return m_pArray[index];
288 }
289
290 // Assign a given index to the given value. The array holder will increment the internal reference on the value.
291 void Assign(unsigned int index, T* pValue)
292 {
293 _ASSERTE(m_pArray != NULL);
294 CONSISTENCY_CHECK_MSGF((index <= m_cElements), ("Index out of range. Index=%u, Max=%u\n", index, m_cElements));
295
296 m_pArray[index].Assign(pValue);
297 }
298
299 // Get lenght of array in elements.
300 unsigned int Length() const
301 {
302 return m_cElements;
303 }
304
305 // Some things need to get the address of an element in the table.
306 // For example, CordbThreads have an array of CordbFrame objects, and then CordbChains describe a range
307 // or frames via pointers into the CordbThread's array.
308 // This is a dangerous operation because it lets us side-step reference counting and protection.
309 T ** UnsafeGetAddrOfIndex(unsigned int index)
310 {
311 return m_pArray[index].UnsafeGetAddr();
312 }
313
314protected:
315 // Raw array of values.
316 HOLDER_T * m_pArray;
317
318 // Number of elements in m_pArray. Note the following is always true: (m_cElements == 0) == (m_pArray == NULL);
319 unsigned int m_cElements;
320};
321
322
323//-----------------------------------------------------------------------------
324//
325// Simple array holder of RSSmartPtrs (internal pointers).
326// Holds a reference to each element.
327//
328// Notes:
329// This derived class adds the concept of neutering to the base pointer array.
330// Allows automatic Clear()ing; do not use this unless it is safe to do so in
331// all cases - e.g. you're holding a local.
332//
333
334template< typename T, typename HOLDER_T = RSSmartPtr<T> > // We need to use HOLDER_T to make gcc happy.
335class RSPtrArray : public BaseRSPtrArray<T, HOLDER_T>
336{
337private:
338 typedef BaseRSPtrArray<T, HOLDER_T> Super;
339 BOOL m_autoClear;
340
341public:
342 RSPtrArray() : m_autoClear(FALSE)
343 {
344 }
345
346 ~RSPtrArray()
347 {
348 if (m_autoClear)
349 {
350 Super::Clear();
351 }
352 else
353 {
354 // Caller should have already Neutered
355 _ASSERTE(Super::IsEmpty());
356 }
357 }
358
359 void EnableAutoClear()
360 {
361 m_autoClear = TRUE;
362 }
363
364 // Neuter all elements in the array.
365 void NeuterAndClear()
366 {
367 for(unsigned int i = 0; i < Super::m_cElements; i++)
368 {
369 if (Super::m_pArray[i] != NULL)
370 {
371 Super::m_pArray[i]->Neuter();
372 }
373 }
374
375 Super::Clear();
376 }
377};
378
379
380//-----------------------------------------------------------------------------
381//
382// Simple array holder of RSExtSmartPtrs (external pointers).
383// Holds a reference to each element.
384//
385// Notes:
386// This derived class clears the array in its destructor.
387//
388
389template< typename T, typename HOLDER_T = RSExtSmartPtr<T> > // We need to use HOLDER_T to make gcc happy.
390class RSExtPtrArray : public BaseRSPtrArray<T, HOLDER_T>
391{
392private:
393 typedef BaseRSPtrArray<T, HOLDER_T> Super;
394
395public:
396 ~RSExtPtrArray()
397 {
398 Super::Clear();
399 }
400};
401
402
403
404//-----------------------------------------------------------------------------
405// Table for RSptrs
406// This lets us map cookies <--> RSPTR_*,
407// Then we just put the cookie in the IPC block instead of the raw RSPTR.
408// This will also adjust the internal-reference count on the T* object.
409// This isolates the RS from bugs in the LS.
410// We templatize by type for type safety.
411// Caller must syncrhonize all access (preferably w/ the stop-go lock).
412//-----------------------------------------------------------------------------
413template <class T>
414class RsPtrTable
415{
416public:
417 RsPtrTable()
418 {
419 m_pTable = NULL;
420 m_cEntries = 0;
421 }
422 ~RsPtrTable()
423 {
424 Clear();
425 }
426 void Clear()
427 {
428 for(UINT i = 0; i < m_cEntries; i++)
429 {
430 if (m_pTable[i])
431 {
432 m_pTable[i]->InternalRelease();
433 }
434 }
435 delete [] m_pTable;
436 m_pTable = NULL;
437 m_cEntries = 0;
438 }
439
440 // Add a value into table. Value can't be NULL.
441 // Returns 0 on failure (such as oom),
442 // Returns a non-zero cookie on success.
443 UINT Add(T* pValue)
444 {
445 _ASSERTE(pValue != NULL);
446 // skip 0 because it's an invalid handle.
447 for(UINT i = 1; ; i++)
448 {
449 // If we've run out of space, allocate new space
450 if( i >= m_cEntries )
451 {
452 if( !Grow() )
453 {
454 return 0; // failed to grow
455 }
456 _ASSERTE( i < m_cEntries );
457 _ASSERTE( m_pTable[i] == NULL );
458 // Since we grew, the next slot should now be open.
459 }
460
461 if (m_pTable[i] == NULL)
462 {
463 m_pTable[i] = pValue;
464 pValue->InternalAddRef();
465 return i;
466 }
467 }
468 UNREACHABLE();
469 }
470
471 // Lookup the value based off the cookie, which was obtained via "Add".
472 // return NULL on error.
473 T* Lookup(UINT cookie)
474 {
475 _ASSERTE(cookie != 0);
476 if (cookie >= m_cEntries)
477 {
478 CONSISTENCY_CHECK_MSGF(false, ("Cookie out of range.Cookie=0x%x. Size=0x%x.\n", cookie, m_cEntries));
479 return NULL;
480 }
481 T* p = m_pTable[cookie];
482 if (p == NULL)
483 {
484 CONSISTENCY_CHECK_MSGF(false, ("Cookie is for empty slot.Cookie=0x%x.\n", cookie));
485 return NULL; // empty!
486 }
487 return p;
488 }
489
490 T* LookupAndRemove(UINT cookie)
491 {
492 _ASSERTE(cookie != 0);
493 T* p = Lookup(cookie);
494 if (p != NULL)
495 {
496 m_pTable[cookie] = NULL;
497 p->InternalRelease();
498 }
499 return p;
500 }
501
502protected:
503 // Resize the m_pTable array.
504 bool Grow()
505 {
506 if (m_pTable == NULL)
507 {
508 _ASSERTE(m_cEntries == 0);
509 size_t cSize = 10;
510 m_pTable = new (nothrow) T*[cSize];
511 if (m_pTable == NULL)
512 {
513 return false;
514 }
515 m_cEntries = cSize;
516 ZeroMemory(m_pTable, sizeof(T*) * m_cEntries);
517 return true;
518 }
519 size_t cNewSize = (m_cEntries * 3 / 2) + 1;
520 _ASSERTE(cNewSize > m_cEntries);
521 T** p = new (nothrow) T*[cNewSize];
522 if (p == NULL)
523 {
524 return false;
525 }
526 ZeroMemory(p, sizeof(T*) * cNewSize);
527
528
529 // Copy over old stuff
530 memcpy(p, m_pTable, sizeof(T*) * m_cEntries);
531 delete [] m_pTable;
532
533 m_pTable = p;
534 m_cEntries = cNewSize;
535 return true;
536 }
537
538 T** m_pTable;
539 size_t m_cEntries;
540};
541
542
543
544//-----------------------------------------------------------------------------
545// Simple Holder for RS object intialization to cooperate with Neutering
546// semantics.
547// The ctor will do an addref.
548// The dtor (invoked in exception) will neuter and release the object. This
549// release will likely be the final release to cause a delete.
550// If the object is created successfully, caller should do a SuppressRelease()
551// to avoid it getting neutered.
552//
553// Example:
554// RSInitHolder<CordbFoo> pFoo(new CordbFoo(x,y,z));
555// pFoo->InitMore(a,b,c);
556// GiveOwnershipToSomebodyElse(pFoo); // now somebody else owns and will clean up
557// pFoo.ClearAndMarkDontNeuter(); // we no longer need to
558//
559// So if an exception is thrown before ClearAndMarkDontNeuter(), the dtor is invoked
560// and the object is properly destroyed (deleted and neutered).
561//
562// Another common pattern is when initializing an object to hand off to an external:
563// RSInitHolder<CordbFoo> pFoo(new CordbFoo(x,y,z));
564// pFoo->InitMore(a,b,c);
565// pFoo.TransferOwnershipExternal(ppOutParameter);
566// TransferOwnershipExternal will assign to ppOutParameter, inc external ref, and
567// call ClearAndMarkDontNeuter()
568//-----------------------------------------------------------------------------
569template<class T>
570class RSInitHolder
571{
572public:
573 // Default ctor. Must call Assign() later.
574 RSInitHolder()
575 {
576 };
577 RSInitHolder(T * pObject)
578 {
579 Assign(pObject);
580 }
581
582 void Assign(T * pObject)
583 {
584 _ASSERTE(m_pObject == NULL); // only assign once.
585 m_pObject.Assign(pObject);
586 }
587 ~RSInitHolder();
588
589 FORCEINLINE operator T *() const
590 {
591 return m_pObject;
592
593 }
594 FORCEINLINE T * operator->()
595 {
596 return m_pObject;
597 }
598
599 // This will null out m_pObject such that the dtor will not neuter it.
600 // This will also release the ref we took in the ctor.
601 // This will clear the current pointer.
602 void ClearAndMarkDontNeuter()
603 {
604 m_pObject.Clear();
605 }
606
607 //
608 // Transfer ownership to a pointer
609 //
610 // Arguments:
611 // ppOutParam - pointer to get ownership. External Reference is incremented.
612 // this pointer should do an external release.
613 //
614 // Notes:
615 // This calls ClearAndMarkDontNeuter(). This holder is Empty after this.
616 template <class TOther>
617 void TransferOwnershipExternal(TOther ** ppOutParam)
618 {
619 *ppOutParam = static_cast<TOther*> (m_pObject);
620 m_pObject->ExternalAddRef();
621
622 ClearAndMarkDontNeuter();
623 }
624
625
626 //
627 // Transfer the ownership of the wrapped object to the given hash table.
628 //
629 // Arguments:
630 // pHashTable - hash table to take ownership.
631 //
632 // Returns:
633 // the contianing object for convenience. Throws on error (particularly
634 // if it fails adding to the hash).
635 //
636 // Notes:
637 // This calls ClearAndMarkDontNeuter(). This holder is Empty after this.
638 T* TransferOwnershipToHash(CordbSafeHashTable<T> * pHashtable)
639 {
640 T* pObject = m_pObject;
641 pHashtable->AddBaseOrThrow(m_pObject);
642 ClearAndMarkDontNeuter();
643 return pObject;
644 }
645
646 //
647 // Used to pass into a function that will assign to us.
648 //
649 // Returns:
650 // Address of this holder. This is like the & operator.
651 // This is provided for consistency with other holders which
652 // override the &operator.
653 RSInitHolder<T> * GetAddr()
654 {
655 return this;
656 }
657
658
659protected:
660 RSSmartPtr<T> m_pObject;
661};
662
663
664
665//-----------------------------------------------------------------------------
666// Have the extra level of indirection is useful for catching Cordbg errors.
667//-----------------------------------------------------------------------------
668#ifdef _DEBUG
669 // On debug, we have an opportunity to catch failing hresults during reproes.
670 #define ErrWrapper(hr) ErrWrapperHelper(hr, __FILE__, __LINE__)
671
672 inline HRESULT ErrWrapperHelper(HRESULT hr, const char * szFile, int line)
673 {
674 if (FAILED(hr))
675 {
676 DWORD dwErr = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgBreakOnErr);
677 if (dwErr)
678 {
679 CONSISTENCY_CHECK_MSGF(false, ("Dbg Error break, hr=0x%08x, '%s':%d", hr, szFile, line));
680 }
681 }
682 return hr;
683 }
684#else
685 // On release, it's just an identity function
686 #define ErrWrapper(hr) (hr)
687#endif
688
689//-----------------------------------------------------------------------------
690// Quick helpers for threading semantics
691//-----------------------------------------------------------------------------
692
693bool IsWin32EventThread(CordbProcess* p);
694bool IsRCEventThread(Cordb* p);
695
696/* ------------------------------------------------------------------------- *
697 * Typedefs
698 * ------------------------------------------------------------------------- */
699
700typedef void* REMOTE_PTR;
701
702
703//-----------------------------------------------------------------------------
704// Wrapper class for locks. This is like Crst on the LS
705//-----------------------------------------------------------------------------
706
707class RSLock
708{
709public:
710 // Attrs, can be bitwise-or together.
711 enum ELockAttr
712 {
713 cLockUninit = 0x00000000,
714 cLockReentrant = 0x00000001,
715 cLockFlat = 0x00000002,
716
717 // (unusual). Not considered a debug API lock, for purposes of deciding whether
718 // to count this lock in m_cTotalDbgApiLocks, which is asserted to be 0 on entry
719 // to public APIs. Example of such a lock: LL_SHIM_PROCESS_DISPOSE_LOCK
720 cLockNonDbgApi = 0x00000004,
721 };
722
723 // To prevent deadlocks, we order all locks.
724 // A thread must acquire higher-numbered locks before lower numbered locks.
725 // These are used as indices into an array, so number them accordingly!
726 enum ERSLockLevel
727 {
728 // Size of the array..
729 LL_MAX = 6,
730
731 // The Stop-Go lock is used to make Stop + Continue be atomic operations.
732 // These methods will toggle the Process-lock b/c they go between multiple threads.
733 // This lock can never be taken on the Win32 ET.
734 LL_STOP_GO_LOCK = 5,
735
736 // The win32-event-thread behaves as if it held a lock at this level.
737 LL_WIN32_EVENT_THREAD = 4,
738
739 // This held for the duration of ShimProcess::Dispose(), and protects
740 // ShimProcess::m_fIsDisposed, so that other ShimProcess functions can
741 // safely execute serially with ShimProcess::Dispose(). This needs to be
742 // a high-level lock, since ShimProcess methods that take this lock also
743 // call into CorDb* objects which take many of the other locks. In contrast,
744 // LL_SHIM_LOCK must remain low-level, as there exists at least one place where
745 // LL_SHIM_LOCK is taken while the CorDbProcess lock is also held (see
746 // CordbThread::GetActiveFunctions which takes the CorDbProcess lock while
747 // calling GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this), which
748 // takes LL_SHIM_LOCK).
749 LL_SHIM_PROCESS_DISPOSE_LOCK = 3,
750
751 // The process lock is the primary lock for a CordbProcess object. It synchronizes
752 // between RCET, W32ET, and user threads.
753 LL_PROCESS_LOCK = 2,
754
755#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
756 LL_DBG_TRANSPORT_MANAGER_LOCK = 1,
757
758 LL_DBG_TRANSPORT_TARGET_LOCK = 0,
759
760 LL_DD_MARSHAL_LOCK = 0,
761#endif // FEATURE_DBGIPC_TRANSPORT_DI
762
763 // These are all leaf locks (they don't take any other lock once they're held).
764 LL_PROCESS_LIST_LOCK = 0,
765
766 // Win32 send lock is shared by all processes accessing a single w32et.
767 LL_WIN32_SEND_LOCK = 0,
768
769 // Small lock around sending IPC events to support workarounds in func-eval abort.
770 // See code:CordbEval::Abort for details.
771 LL_FUNC_EVAL_ABORT_HACK_LOCK = 0,
772
773 // Leaf-level lock used in the shim.
774 LL_SHIM_LOCK = 0
775 };
776
777 // Initialize a lock w/ debugging info. szTag must be a string literal.
778 void Init(const char * szTag, int eAttr, ERSLockLevel level);
779 void Destroy();
780
781 void Lock();
782 void Unlock();
783
784protected:
785 // Accessors for holders.
786 static void HolderEnter(RSLock * pLock)
787 {
788 pLock->Lock();
789 }
790 static void HolderLeave(RSLock * pLock)
791 {
792 pLock->Unlock();
793 }
794
795
796 CRITICAL_SECTION m_lock;
797
798#ifdef _DEBUG
799public:
800 RSLock();
801 ~RSLock();
802
803 const char * Name() { return m_szTag; }
804
805 // Returns true if this thread has the lock.
806 bool HasLock();
807
808 // Returns true if this is safe to take on this thread (ie, this thread
809 // doesn't already hold bigger locks).
810 // bool IsSafeToTake();
811
812 ERSLockLevel GetLevel() { return m_level; }
813
814 // If we're inited, we must have either cLockReentrant or cLockFlat specified.
815 bool IsInit() { return m_eAttr != 0; }
816 bool IsReentrant() { return (m_eAttr & cLockReentrant) == cLockReentrant; }
817 bool IsDbgApiLock() { return ((m_eAttr & cLockNonDbgApi) == 0); }
818
819protected:
820 ERSLockLevel m_level;
821 int m_eAttr; // Bitwise combination of ELockAttr values
822 int m_count;
823 DWORD m_tidOwner;
824 const char * m_szTag;
825
826#endif // #if debug
827
828public:
829 typedef Holder<RSLock *, RSLock::HolderEnter, RSLock::HolderLeave> RSLockHolder;
830 typedef Holder<RSLock *, RSLock::HolderLeave, RSLock::HolderEnter> RSInverseLockHolder;
831
832};
833
834typedef RSLock::RSLockHolder RSLockHolder;
835typedef RSLock::RSInverseLockHolder RSInverseLockHolder;
836
837// In the RS, we should be using RSLocks instead of raw critical sections.
838#define CRITICAL_SECTION USE_RSLOCK_INSTEAD_OF_CRITICAL_SECTION
839
840
841/* ------------------------------------------------------------------------- *
842 * Helper macros. Use the ATT_* macros below instead of these.
843 * ------------------------------------------------------------------------- */
844
845// This serves as glue for exceptions. Eventually, we shouldn't have unrecoverable
846// error, and instead, errors should just propogate up.
847#define SetUnrecoverableIfFailed(__p, __hr) \
848 if (FAILED(__hr)) \
849 { \
850 CORDBSetUnrecoverableError(__p, __hr, 0); \
851 }
852
853#define CORDBSetUnrecoverableError(__p, __hr, __code) \
854 ((__p)->UnrecoverableError((__hr), (__code), __FILE__, __LINE__))
855
856#define _CORDBCheckProcessStateOK(__p) \
857 (!((__p)->m_unrecoverableError) && !((__p)->m_terminated) && !((__p)->m_detached))
858
859#define _CORDBCheckProcessStateOKAndSync(__p, __c) \
860 (!((__p)->m_unrecoverableError) && !((__p)->m_terminated) && !((__p)->m_detached) && \
861 (__p)->GetSynchronized())
862
863// Worker to get failure HR from given state. If not in a failure state, it yields __defaultHR.
864// If a caller knows that we're in a failure state, it can pass in a failure value for __defaultHR.
865#define CORDBHRFromProcessStateWorker(__p, __c, __defaultHR) \
866 ((__p)->m_unrecoverableError ? CORDBG_E_UNRECOVERABLE_ERROR : \
867 ((__p)->m_detached ? CORDBG_E_PROCESS_DETACHED : \
868 ((__p)->m_terminated ? CORDBG_E_PROCESS_TERMINATED : \
869 (!(__p)->GetSynchronized() ? CORDBG_E_PROCESS_NOT_SYNCHRONIZED \
870 : (__defaultHR)))))
871
872#define CORDBHRFromProcessState(__p, __c) \
873 CORDBHRFromProcessStateWorker(__p, __c, S_OK) \
874
875
876// Have a set of helper macros to check the process state and return a failure code.
877// These only should be used at public interface boundaries, in which case we should
878// not be holding the process lock. But we have enough places where we use them internally,
879// so we can't really assert that we're not holding the lock.
880
881// We're very restricted in what APIs we can call on the w32et. Have
882// a convenient check for this.
883// If we have no shim, then nop this check because everything becomes like the w32-event-thread.
884#define CORDBFailOrThrowIfOnWin32EventThread(__p, errorAction) \
885 { \
886 if (((__p)->GetShim() != NULL) && (__p)->IsWin32EventThread()) \
887 { \
888 _ASSERTE(!"Don't call on this thread"); \
889 errorAction(ErrWrapper(CORDBG_E_CANT_CALL_ON_THIS_THREAD)); \
890 } \
891 }
892
893#define CORDBFailIfOnWin32EventThread(__p) CORDBFailOrThrowIfOnWin32EventThread(__p, return)
894
895#define CORDBRequireProcessStateOK(__p) { \
896 if (!_CORDBCheckProcessStateOK(__p)) \
897 return ErrWrapper(CORDBHRFromProcessState(__p, NULL)); }
898
899// If we need to be synced, then we shouldn't be on the win32 Event-Thread.
900#define CORDBRequireProcessStateOKAndSync(__p,__c) { \
901 CORDBFailIfOnWin32EventThread(__p); \
902 if (!_CORDBCheckProcessStateOKAndSync(__p, __c)) \
903 return ErrWrapper(CORDBHRFromProcessState(__p, __c)); }
904
905#define CORDBRequireProcessSynchronized(__p, __c) { \
906 CORDBFailIfOnWin32EventThread(__p); \
907 if (!(__p)->GetSynchronized()) return ErrWrapper(CORDBG_E_PROCESS_NOT_SYNCHRONIZED);}
908
909
910
911
912//-----------------------------------------------------------------------------
913// All public APIS fall into 2 categories regarding their API Threading Type (ATT)
914// We use a standard set of macros to define & enforce each type.
915//
916// (1) ATT_REQUIRE_STOPPED
917// We must be stopped (either synced or at a win32 event) to call this API.
918// - We'll fail if we're not stopped.
919// - If we're stopped, we'll sync. Thus after this API, we're always synced,
920// and Cordbg must call Continue to resume the process.
921// - We'll take the Stop-Go-lock. This prevents another thread from continuing underneath us.
922// - We may send IPC events.
923// Common for APIs like Stacktracing
924//
925// (2) ATT_ALLOW_LIVE
926// We do not have to be stopped to call this API.
927// - We can be live, thus we can not take the stop-go lock (unless it's from a SC-holder).
928// - If we're going to send IPC events, we must use a Stop-Continue holder.
929// - Our stop-status is the same after this API as it was before.
930// Common usage: read-only APIs.
931//
932// (2b) ATT_ALLOW_LIVE_DO_STOPGO.
933// - shortcut macro to do #2, but throw in a stop-continue holder. These really
934// should be in camp #1, but that would require an interface change.
935//-----------------------------------------------------------------------------
936
937// Helper macros for the ATT stuff
938
939// Do checks that need to be done before we take the SG lock. These include checks
940// where if we fail them, taking the SG lock could deadlock (such as being on win32 thread).
941#define DO_PRE_STOP_GO_CHECKS(errorAction) \
942 CORDBFailOrThrowIfOnWin32EventThread(__proc_for_ATT, errorAction) \
943 if ((__proc_for_ATT)->m_unrecoverableError) { errorAction(CORDBG_E_UNRECOVERABLE_ERROR); } \
944
945// Do checks after we take the SG lock. These include checks that rely on state protected
946// by the SG lock.
947#define DO_POST_STOP_GO_CHECKS(errorAction) \
948 _ASSERTE((this->GetProcess() == __proc_for_ATT) || this->IsNeutered()); \
949 if (this->IsNeutered()) { errorAction(CORDBG_E_OBJECT_NEUTERED); } \
950
951// #1
952// The exact details here are rocket-science.
953// 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).
954// This is essential in case __proc is something like "this->GetProcess()" and which can start returning NULL if 'this'
955// gets neutered underneath us. Caching guarantees that we'll be able to make it to the StopGo-lock.
956//
957// We explicitily check some things before taking the Stop-Go lock:
958// - CORDBG_E_UNRECOVERABLE_ERROR before the lock because if that's set,
959// we may have leaked locks to the outside world, so taking the StopGo lock later could fail.
960// - Are we on the W32et - can't take sg lock if on W32et
961// Then we immediately take the stop-go lock to prevent another thread from continuing underneath us.
962// Then, if we're stopped, we ensure that we're also synced.
963// Stopped includes:
964// - Win32-stopped
965// - fake win32-stopped. Eg, between SuspendUnmanagedThreads & ResumeUnmanagedThreads
966// (one way to get here is getting debug events during the special-deferment region)
967// - synchronized
968// If we're not stopped, then we fail. This macro must never return S_OK.
969//
970// If not-shimmed (using V3 pipeline), then skip all checks about stop-state.
971#define ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(__proc, errorAction) \
972 CordbProcess * __proc_for_ATT = (__proc); \
973 DO_PRE_STOP_GO_CHECKS(errorAction); \
974 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
975 DO_POST_STOP_GO_CHECKS(errorAction); \
976 if ((__proc_for_ATT)->GetShim() != NULL) { \
977 if (!__proc_for_ATT->m_initialized) { errorAction(CORDBG_E_NOTREADY); } \
978 if ((__proc_for_ATT)->IsStopped()) { \
979 HRESULT _hr2 = (__proc_for_ATT)->StartSyncFromWin32Stop(NULL); \
980 if (FAILED(_hr2)) errorAction(_hr2); \
981 } \
982 if (!_CORDBCheckProcessStateOKAndSync(__proc_for_ATT, NULL)) \
983 errorAction(CORDBHRFromProcessStateWorker(__proc_for_ATT, NULL, E_FAIL)); \
984 }
985
986#define ATT_REQUIRE_STOPPED_MAY_FAIL(__proc)ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(__proc, return)
987
988// #1b - allows it to be non-inited. This should look just like ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW
989// except it doesn't do SSFW32Stop and doesn't have the m_initialized check.
990#define ATT_REQUIRE_SYNCED_OR_NONINIT_MAY_FAIL(__proc) \
991 CordbProcess * __proc_for_ATT = (__proc); \
992 DO_PRE_STOP_GO_CHECKS(return); \
993 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
994 DO_POST_STOP_GO_CHECKS(return); \
995 if ((__proc_for_ATT)->GetShim() != NULL) { \
996 if (!_CORDBCheckProcessStateOKAndSync(__proc_for_ATT, NULL)) \
997 return CORDBHRFromProcessStateWorker(__proc_for_ATT, NULL, E_FAIL); \
998 }
999
1000
1001
1002// Gross variant on #1.
1003// This is a very dangerous ATT contract; but we need to support it for backwards compat.
1004// Some APIs, like ICDProcess:EnumerateThreads can be used before the process is actually
1005// initialized (kind of for interop-debugging).
1006// These can't check the m_initialized flag b/c that may not be set yet.
1007// They also can't sync the runtime.
1008// This should only be used for non-blocking leaf activity.
1009#define ATT_EVERETT_HACK_REQUIRE_STOPPED_ALLOW_NONINIT(__proc) \
1010 CordbProcess * __proc_for_ATT = (__proc); \
1011 DO_PRE_STOP_GO_CHECKS(return); \
1012 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
1013 DO_POST_STOP_GO_CHECKS(return); \
1014 if (((__proc_for_ATT)->GetShim() != NULL) && !(__proc_for_ATT)->IsStopped()) { return CORDBG_E_PROCESS_NOT_SYNCHRONIZED; } \
1015
1016
1017// #2 - caller may think debuggee is live, but throw in a Stop-Continue holder.
1018#define ATT_ALLOW_LIVE_DO_STOPGO(__proc) \
1019 CordbProcess * __proc_for_ATT = (__proc); \
1020 DO_PRE_STOP_GO_CHECKS(return); \
1021 CORDBRequireProcessStateOK(__proc_for_ATT); \
1022 RSLockHolder __ch(__proc_for_ATT->GetStopGoLock()); \
1023 DO_POST_STOP_GO_CHECKS(return); \
1024 StopContinueHolder __hStopGo; \
1025 if ((__proc_for_ATT)->GetShim() != NULL) \
1026 { \
1027 HRESULT _hr2 = __hStopGo.Init(__proc_for_ATT); \
1028 if (FAILED(_hr2)) return _hr2; \
1029 _ASSERTE((__proc_for_ATT)->GetSynchronized()); \
1030 } \
1031
1032
1033
1034
1035//-----------------------------------------------------------------------------
1036// StopContinueHolder. Ensure that we're synced during a certain region.
1037// (Particularly when sending an IPCEvent)
1038// Calls ICorDebugProcess::Stop & IMDArocess::Continue.
1039// Example usage:
1040//
1041// {
1042// StopContinueHolder h;
1043// IfFailRet(h.Init(process))
1044// SendIPCEvent
1045// } // continue automatically called.
1046//-----------------------------------------------------------------------------
1047
1048class CordbProcess;
1049class StopContinueHolder
1050{
1051public:
1052 StopContinueHolder() : m_p(NULL) { };
1053
1054 HRESULT Init(CordbProcess * p);
1055 ~StopContinueHolder();
1056
1057protected:
1058 CordbProcess * m_p;
1059};
1060
1061
1062/* ------------------------------------------------------------------------- *
1063 * Base class
1064 * ------------------------------------------------------------------------- */
1065
1066#define COM_METHOD HRESULT STDMETHODCALLTYPE
1067
1068typedef enum {
1069 enumCordbUnknown, // 0
1070 enumCordb, // 1 1 [1]x1
1071 enumCordbProcess, // 2 1 [1]x1
1072 enumCordbAppDomain, // 3 1 [1]x1
1073 enumCordbAssembly, // 4
1074 enumCordbModule, // 5 15 [27-38,55-57]x1
1075 enumCordbClass, // 6
1076 enumCordbFunction, // 7
1077 enumCordbThread, // 8 2 [4,7]x1
1078 enumCordbCode, // 9
1079 enumCordbChain, // 10
1080 enumCordbChainEnum, // 11
1081 enumCordbContext, // 12
1082 enumCordbFrame, // 13
1083 enumCordbFrameEnum, // 14
1084 enumCordbValueEnum, // 15
1085 enumCordbRegisterSet, // 16
1086 enumCordbJITILFrame, // 17
1087 enumCordbBreakpoint, // 18
1088 enumCordbStepper, // 19
1089 enumCordbValue, // 20
1090 enumCordbEnCSnapshot, // 21
1091 enumCordbEval, // 22
1092 enumCordbUnmanagedThread,// 23
1093 enumCorpubPublish, // 24
1094 enumCorpubProcess, // 25
1095 enumCorpubAppDomain, // 26
1096 enumCorpubProcessEnum, // 27
1097 enumCorpubAppDomainEnum,// 28
1098 enumCordbEnumFilter, // 29
1099 enumCordbEnCErrorInfo, // 30
1100 enumCordbEnCErrorInfoEnum,//31
1101 enumCordbUnmanagedEvent,// 32
1102 enumCordbWin32EventThread,//33
1103 enumCordbRCEventThread, // 34
1104 enumCordbNativeFrame, // 35
1105 enumCordbObjectValue, // 36
1106 enumCordbType, // 37
1107 enumCordbNativeCode, // 38
1108 enumCordbILCode, // 39
1109 enumCordbEval2, // 40
1110 enumCordbMDA, // 41
1111 enumCordbHashTableEnum, // 42
1112 enumCordbCodeEnum, // 43
1113 enumCordbStackWalk, // 44
1114 enumCordbEnumerator, // 45
1115 enumCordbHeap, // 48
1116 enumCordbHeapSegments, // 47
1117 enumMaxDerived, //
1118 enumMaxThis = 1024
1119} enumCordbDerived;
1120
1121
1122
1123//-----------------------------------------------------------------------------
1124// Support for Native Breakpoints
1125//-----------------------------------------------------------------------------
1126struct NativePatch
1127{
1128 void * pAddress; // pointer into the LS address space.
1129 PRD_TYPE opcode; // opcode to restore with.
1130
1131 inline bool operator==(NativePatch p2)
1132 {
1133 return memcmp(this, &p2, sizeof(p2)) == 0;
1134 }
1135};
1136
1137//-----------------------------------------------------------------------------
1138// Cross-platform patch operations
1139//-----------------------------------------------------------------------------
1140
1141// Remove the int3 from the remote address
1142HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE opcode);
1143
1144// This flavor is assuming our caller already knows the opcode.
1145HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress);
1146
1147// Apply the patch and get the opcode that we're replacing.
1148HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE * pOpcode);
1149
1150
1151class CordbHashTable;
1152
1153#define CORDB_COMMON_BASE_SIGNATURE 0x0d00d96a
1154#define CORDB_COMMON_BASE_SIGNATURE_DEAD 0x0dead0b1
1155
1156// Common base for both CorPublish + CorDebug objects.
1157class CordbCommonBase : public IUnknown
1158{
1159public:
1160 // GENERIC: made this private as I'm changing the use of m_id for CordbClass, and
1161 // I want to make sure I catch all the places where m_id is used directly and cast
1162 // to/from tokens and/or (void*).
1163 UINT_PTR m_id;
1164
1165#ifdef _DEBUG
1166 static LONG m_saDwInstance[enumMaxDerived]; // instance x this
1167 static LONG m_saDwAlive[enumMaxDerived];
1168 static PVOID m_sdThis[enumMaxDerived][enumMaxThis];
1169 DWORD m_dwInstance;
1170 enumCordbDerived m_type;
1171#endif
1172
1173
1174
1175private:
1176 DWORD m_signature : 30;
1177
1178 // Sticky bit set when we neuter an object. All methods (besides AddRef,Release,QI)
1179 // should check this bit and fail via the FAIL_IF_NEUTERED macro.
1180 DWORD m_fIsNeutered : 1;
1181
1182 // Mark that this object can be "neutered at will". NeuterList::SweepAllNeuterAtWillObjects
1183 // looks at this bit.
1184 // For some objects, we don't explicitly mark when the lifetime is up. The only way
1185 // we know is when external count goes to 0. This avoids forcing us to do cleanup
1186 // in the dtor (which may come at a bad time). Sticky bit set in BaseRelease().
1187 DWORD m_fNeuterAtWill : 1;
1188public:
1189
1190 static LONG s_CordbObjectUID; // Unique ID for each object.
1191 static LONG s_TotalObjectCount; // total number of outstanding objects.
1192
1193
1194 void ValidateObject()
1195 {
1196 if( !IsValidObject() )
1197 {
1198 STRESS_LOG1(LF_ASSERT, LL_ALWAYS, "CordbCommonBase::IsValidObject() failed: %x\n", this);
1199 _ASSERTE(!"CordbCommonBase::IsValidObject() failed");
1200 FreeBuildDebugBreak();
1201 }
1202 }
1203
1204 bool IsValidObject()
1205 {
1206 return (m_signature == CORDB_COMMON_BASE_SIGNATURE);
1207 }
1208
1209 CordbCommonBase(UINT_PTR id, enumCordbDerived type)
1210 {
1211 init(id, type);
1212 }
1213
1214 CordbCommonBase(UINT_PTR id)
1215 {
1216 init(id, enumCordbUnknown);
1217 }
1218
1219 void init(UINT_PTR id, enumCordbDerived type)
1220 {
1221 // To help us track object leaks, we want to log when we create & destory CordbBase objects.
1222#ifdef _DEBUG
1223 InterlockedIncrement(&s_TotalObjectCount);
1224 InterlockedIncrement(&s_CordbObjectUID);
1225
1226 LOG((LF_CORDB, LL_EVERYTHING, "Memory: CordbBase object allocated: this=%p, count=%d, id=%p, Type=%d\n", this, s_CordbObjectUID, id, type));
1227#endif
1228
1229 m_signature = CORDB_COMMON_BASE_SIGNATURE;
1230 m_fNeuterAtWill = 0;
1231 m_fIsNeutered = 0;
1232
1233 m_id = id;
1234 m_RefCount = 0;
1235
1236#ifdef _DEBUG
1237 m_type = type;
1238 //m_dwInstance = CordbBase::m_saDwInstance[m_type];
1239 //InterlockedIncrement(&CordbBase::m_saDwInstance[m_type]);
1240 //InterlockedIncrement(&CordbBase::m_saDwAlive[m_type]);
1241 //if (m_dwInstance < enumMaxThis)
1242 //{
1243 // m_sdThis[m_type][m_dwInstance] = this;
1244 //}
1245#endif
1246 }
1247
1248 virtual ~CordbCommonBase()
1249 {
1250 // If we're deleting, we really should have released any outstanding reference.
1251 // If we call Release() on a deleted object, we'll av (especially b/c Release
1252 // may call delete again).
1253 CONSISTENCY_CHECK_MSGF(m_RefCount == 0, ("Deleting w/ non-zero ref count. 0x%08x", m_RefCount));
1254
1255#ifdef _DEBUG
1256 //InterlockedDecrement(&CordbBase::m_saDwAlive[m_type]);
1257 //if (m_dwInstance < enumMaxThis)
1258 //{
1259 // m_sdThis[m_type][m_dwInstance] = NULL;
1260 //}
1261#endif
1262 // To help us track object leaks, we want to log when we create & destory CordbBase objects.
1263 LOG((LF_CORDB, LL_EVERYTHING, "Memory: CordbBase object deleted: this=%p, id=%p, Refcount=0x%x\n", this, m_id, m_RefCount));
1264
1265#ifdef _DEBUG
1266 LONG newTotalObjectsCount = InterlockedDecrement(&s_TotalObjectCount);
1267 _ASSERTE(newTotalObjectsCount >= 0);
1268#endif
1269
1270 // Don't shutdown logic until everybody is done with it.
1271 // If we leak objects, this may mean that we never shutdown logging at all!
1272#if defined(_DEBUG) && defined(LOGGING)
1273 if (newTotalObjectsCount == 0)
1274 {
1275 ShutdownLogging();
1276 }
1277#endif
1278 }
1279
1280 /*
1281 Member function behavior of a neutered COM object:
1282
1283 1. AddRef(), Release(), QueryInterface() work as normal.
1284 a. This gives folks who are responsible for pairing a Release() with
1285 an AddRef() a chance to dereference their pointer and call Release()
1286 when they are informed, explicitly or implicitly, that the object is neutered.
1287
1288 2. Any other member function will return an error code unless documented.
1289 a. If a member function returns information when the COM object is
1290 neutered then the semantics of that function need to be documented.
1291 (ie. If an AppDomain is unloaded and you have a reference to the COM
1292 object representing the AppDomain, how _should_ it behave? That behavior
1293 should be documented)
1294
1295
1296 Postcondions of Neuter():
1297
1298 1. All circular references (aka back-pointers) are "broken". They are broken
1299 by calling Release() on all "Weak References" to the object. If you're a purist,
1300 these pointers should also be NULLed out.
1301 a. Weak References/Strong References:
1302 i. If any objects are not "reachable" from the root (ie. stack or from global pointers)
1303 they should be reclaimed. If they are not, they are leaked and there is an issue.
1304 ii. There must be a partial order on the objects such that if A < B then:
1305 1. A has a reference to B. This reference is a "strong reference"
1306 2. A, and thus B, is reachable from the root
1307 iii. If a reference belongs in the partial order then it is a "strong reference" else
1308 it is a weak reference.
1309 *** 2. Sufficient conditions to ensure no COM objects are leaked: ***
1310 a. When Neuter() is invoked:
1311 i. Calles Release on all its weak references.
1312 ii. Then, for each strong reference:
1313 1. invoke Neuter()
1314 2. invoke Release()
1315 iii. If it's derived from a CordbXXX class, call Neuter() on the base class.
1316 1. Sense Neuter() is virtual, use the scope specifier Cordb[BaseClass]::Neuter().
1317 3. All members return error codes, except:
1318 a. Members of IUknown, AddRef(), Release(), QueryInterfac()
1319 b. Those documented to have functionality when the object is neutered.
1320 i. Neuter() still works w/o error. If it is invoke a second time it will have already
1321 released all its strong and weak references so it could just return.
1322
1323
1324 Alternate design ideas:
1325
1326 DESIGN: Note that it's possible for object B to have two parents in the partial order
1327 and it must be documented which one is responsible for calling Neuter() on B.
1328 1. For example, CordbCode could reasonably be a sibling of CordbFunction and CordbNativeFrame.
1329 Which one should call Release()? For now we have CordbFunction call Release() on CordbCode.
1330
1331 DESIGN: It is not a necessary condition in that Neuter() invoke Release() on all
1332 it's strong references. Instead, it would be sufficient to ensure all object are released, that
1333 each object call Release() on all its strong pointers in its destructor.
1334 1. This might be done if its necessary for some member to return "tombstone"
1335 information after the object has been netuered() which involves the siblings (wrt poset)
1336 of the object. However, no sibling could access a parent (wrt poset) because
1337 Neuter called Release() on all its weak pointers.
1338
1339 DESIGN: Rename Neuter() to some name that more accurately reflect the semantics.
1340 1. The three operations are:
1341 a. ReleaseWeakPointers()
1342 b. NeuterStrongPointers()
1343 c. ReleaseStrongPointers()
1344 1. Assert that it's done after NeuterStrongPointers()
1345 2. That would introduce a bunch of functions... but it would be clear.
1346
1347 DESIGN: CordbBase could provide a function to register strong and weak references. That way CordbBase
1348 could implement a general version of ReleaseWeak/ReleaseStrong/NeuterStrongPointers(). This
1349 would provide a very error resistant framework for extending the object model plus it would
1350 be very explicit about what is going on.
1351 One thing that might trip this is idea up is that if an object has two parents,
1352 like the CordbCode might, then either both objects call Neuter or one is reference
1353 is made weak.
1354
1355
1356 Our implementation:
1357
1358 The graph formed by the strong references must remain acyclic.
1359 It's up to the developer (YOU!) to ensure that each Neuter
1360 function maintains that invariant.
1361
1362 Here is the current Partial Order on CordbXXX objects. (All these classes
1363 eventually chain to CordbBase.Neuter() for completeness.)
1364
1365 Cordb
1366 CordbProcess
1367 CordbAppDomain
1368 CordbBreakPoints
1369 CordbAssembly
1370 CordbModule
1371 CordbClass
1372 CordbFunction
1373 CordbCode (Can we assert a thread will not reference
1374 the same CordbCode as a CordbFunction?)
1375 CordbThread
1376 CordbChains
1377 CordbNativeFrame -> CordbFrame (Chain to baseClass)
1378 CordbJITILFrame
1379
1380
1381 <TODO>TODO: Some Neuter functions have not yet been implemented due to time restrictions.</TODO>
1382
1383 <TODO>TODO: Some weak references never have AddRef() called on them. If that's cool then
1384 it should be stated in the documentation. Else it should be changed.</TODO>
1385*/
1386
1387 virtual void Neuter();
1388
1389 // Unsafe neuter for an object that's already dead.
1390 void UnsafeNeuterDeadObject();
1391
1392
1393#ifdef _DEBUG
1394 // For debugging (asserts, logging, etc) provide a pretty name (this is 1:1 w/ the VTable)
1395 // We provide a default impl in the base object in case this gets called from a dtor (virtuals
1396 // called from dtors use the base version, not the derived). A pure call would AV in that case.
1397 virtual const char * DbgGetName() { return "CordbBase"; };
1398#endif
1399
1400 bool IsNeutered() const {LIMITED_METHOD_CONTRACT; return m_fIsNeutered == 1; }
1401 bool IsNeuterAtWill() const { LIMITED_METHOD_CONTRACT; return m_fNeuterAtWill == 1; }
1402 void MarkNeuterAtWill() { LIMITED_METHOD_CONTRACT; m_fNeuterAtWill = 1; }
1403
1404 //-----------------------------------------------------------
1405 // IUnknown support
1406 //----------------------------------------------------------
1407
1408private:
1409 // We maintain both an internal + external refcount. This allows us to catch
1410 // if an external caller has too many releases.
1411 // low bits are internal count, high bits are external count
1412 // so Total count = (m_RefCount & CordbBase_InternalRefCountMask) + (m_RefCount >> CordbBase_ExternalRefCountShift);
1413 typedef LONGLONG MixedRefCountSigned;
1414 typedef ULONGLONG MixedRefCountUnsigned;
1415 typedef LONG ExternalRefCount;
1416 MixedRefCountUnsigned m_RefCount;
1417public:
1418
1419 // Adjust the internal ref count.
1420 // These aren't available to the external world, so only internal code can manipulate the internal count.
1421 void InternalAddRef();
1422 void InternalRelease();
1423
1424 // Derived versions of AddRef / Release will call these.
1425 // External AddRef & Release
1426 // These do not have any additional Asserts to enforce that we're not manipulating the external count
1427 // from internal.
1428 ULONG STDMETHODCALLTYPE BaseAddRef();
1429 ULONG STDMETHODCALLTYPE BaseRelease();
1430
1431 // External ref count versions, with extra debug count to enforce that this is done externally.
1432 // When derive classes use these versions, it Asserts that we're not adjusting external counts from inside.
1433 // Thus we can be confident that we're *never* leaking external refs to these objects.
1434 // @todo - eventually everything should use these.
1435 ULONG STDMETHODCALLTYPE BaseAddRefEnforceExternal();
1436 ULONG STDMETHODCALLTYPE BaseReleaseEnforceExternal();
1437
1438 // Do an AddRef against the External count. This is a semantics issue.
1439 // We use this when an internal component Addrefs out-parameters (which Cordbg will call Release on).
1440 // This just does a regular external AddRef().
1441 void ExternalAddRef();
1442
1443protected:
1444
1445 static void InitializeCommon();
1446
1447private:
1448 static void AddDebugPrivilege();
1449};
1450
1451#define CordbBase_ExternalRefCountShift 32
1452#define CordbBase_InternalRefCountMask 0xFFFFFFFF
1453#define CordbBase_InternalRefCountMax 0x7FFFFFFF
1454
1455#ifdef _DEBUG
1456// Does the given Cordb object type have affinity to a CordbProcess object?
1457// This is only used for certain asserts.
1458inline bool DoesCordbObjectTypeHaveProcessPtr(enumCordbDerived type)
1459{
1460 return
1461 (type != enumCordbCodeEnum) &&
1462 (type != enumCordb) &&
1463 (type != enumCordbHashTableEnum);
1464}
1465#endif
1466
1467// Base class specifically for CorDebug objects
1468class CordbBase : public CordbCommonBase
1469{
1470public:
1471 CordbBase(CordbProcess * pProcess, UINT_PTR id, enumCordbDerived type) : CordbCommonBase(id, type)
1472 {
1473 // CordbProcess can't pass 'this' to base class, per error C4355. So we pass null and set later.
1474 _ASSERTE((pProcess != NULL) ||
1475 ((type) == enumCordbProcess) ||
1476 !DoesCordbObjectTypeHaveProcessPtr(type));
1477
1478 m_pProcess.Assign(pProcess);
1479 }
1480
1481 CordbBase(CordbProcess * pProcess, UINT_PTR id) : CordbCommonBase(id)
1482 {
1483 _ASSERTE(pProcess != NULL);
1484 m_pProcess.Assign(pProcess);
1485 }
1486
1487 virtual ~CordbBase()
1488 {
1489 // Derived classes should not have cleared out our pointer.
1490 // CordbProcess's Neuter explicitly nulls out its pointer to avoid circular reference.
1491 _ASSERTE(m_pProcess!= NULL ||
1492 (CordbCommonBase::m_type == enumCordbProcess) ||
1493 !DoesCordbObjectTypeHaveProcessPtr(CordbCommonBase::m_type));
1494
1495 // Ideally, all CorDebug objects to be neutered by the time their dtor is called.
1496 // @todo - we're still working out neutering semantics for a few remaining objects, so we exclude
1497 // those from the assert.
1498 _ASSERTE(IsNeutered() ||
1499 (m_type == enumCordbBreakpoint) ||
1500 (m_type == enumCordbStepper));
1501 }
1502
1503 // Neuter just the right-side state.
1504 virtual void Neuter();
1505
1506 // Neuter both left-side state and right-side state.
1507 virtual void NeuterLeftSideResources();
1508
1509 // Get the CordbProcess object that this CordbBase object is associated with (or NULL if there's none).
1510 CordbProcess * GetProcess() const
1511 {
1512 return m_pProcess;
1513 }
1514protected:
1515 // All objects need a strong pointer back to the process so that they can get access to key locks
1516 // held by the process (StopGo lock) so that they can synchronize their operations against neutering.
1517 // This pointer is cleared in our dtor, and not when we're neutered. Since we can't control when the
1518 // dtor is called (it's controlled by external references), we classify this as an external reference too.
1519 //
1520 // This is the only "strong" reference backpointer that objects need have. All other backpointers can be weak references
1521 // because when a parent object is neutered, it will null out all weak reference pointers in all of its children.
1522 // That will also break any potential cycles.
1523 RSUnsafeExternalSmartPtr<CordbProcess> m_pProcess;
1524
1525};
1526
1527
1528
1529
1530
1531//-----------------------------------------------------------------------------
1532// Macro to check if a CordbXXX object is neutered, and return a standard
1533// error code if it is.
1534// We pass the 'this' pointer of the object in because it gives us some extra
1535// flexibility and lets us log debug info.
1536// It is an API breach to access a neutered object.
1537//-----------------------------------------------------------------------------
1538#define FAIL_IF_NEUTERED(pThis) \
1539int _____Neuter_Status_Already_Marked; \
1540_____Neuter_Status_Already_Marked = 0; \
1541{\
1542 if (pThis->IsNeutered()) { \
1543 LOG((LF_CORDB, LL_ALWAYS, "Accessing a neutered object at %p\n", pThis)); \
1544 return ErrWrapper(CORDBG_E_OBJECT_NEUTERED); \
1545 } \
1546}
1547
1548//-----------------------------------------------------------------------------
1549// Macro to check if a CordbXXX object is neutered, and return a standard
1550// error code if it is.
1551// We pass the 'this' pointer of the object in because it gives us some extra
1552// flexibility and lets us log debug info.
1553// It is an API breach to access a neutered object.
1554//-----------------------------------------------------------------------------
1555#define THROW_IF_NEUTERED(pThis) \
1556int _____Neuter_Status_Already_Marked; \
1557_____Neuter_Status_Already_Marked = 0; \
1558{\
1559 if (pThis->IsNeutered()) { \
1560 LOG((LF_CORDB, LL_ALWAYS, "Accessing a neutered object at %p\n", pThis)); \
1561 ThrowHR(CORDBG_E_OBJECT_NEUTERED); \
1562 } \
1563}
1564
1565// We have an OK_IF_NEUTERED macro to say that this method can be safely
1566// called if we're neutered. Mostly for semantic benefits.
1567// Also, if a method is marked OK, then somebody won't go and add a 'fail'
1568// This is an extremely dangerous quality because:
1569// 1) it means that we have no synchronization (can't take the Stop-Go lock)
1570// 2) none of our backpointers are usable (they may be nulled out at anytime by another thread).
1571// - this also means we absolutely can't send IPC events (since that requires a CordbProcess)
1572// 3) The only safe data are blittalbe embedded fields (eg, a pid or stack range)
1573//
1574// Any usage of this macro should clearly specify why this is safe.
1575#define OK_IF_NEUTERED(pThis) \
1576int _____Neuter_Status_Already_Marked; \
1577_____Neuter_Status_Already_Marked = 0;
1578
1579
1580//-------------------------------------------------------------------------------
1581// Simple COM enumerator pattern on a fixed list of items
1582//--------------------------------------------------------------------------------
1583template< typename ElemType,
1584 typename ElemPublicType,
1585 typename EnumInterfaceType,
1586 ElemPublicType (*GetPublicType)(ElemType)>
1587class CordbEnumerator : public CordbBase, public EnumInterfaceType
1588{
1589private:
1590 // the list of items being enumerated over
1591 ElemType *m_items;
1592 // the number of items in the list
1593 DWORD m_countItems;
1594 // the index of the next item to be returned in the enumeration
1595 DWORD m_nextIndex;
1596
1597public:
1598 // makes a copy of the elements in the "items" array
1599 CordbEnumerator(CordbProcess* pProcess, ElemType *items, DWORD elemCount);
1600 // assumes ownership of the elements in the "*items" array.
1601 // this avoids an extra allocation + copy
1602 CordbEnumerator(CordbProcess* pProcess, ElemType **items, DWORD elemCount);
1603 ~CordbEnumerator();
1604
1605// IUnknown interface
1606 virtual COM_METHOD QueryInterface(REFIID riid, VOID** ppInterface);
1607 virtual ULONG STDMETHODCALLTYPE AddRef();
1608 virtual ULONG STDMETHODCALLTYPE Release();
1609
1610// ICorDebugEnum interface
1611 virtual COM_METHOD Clone(ICorDebugEnum **ppEnum);
1612 virtual COM_METHOD GetCount(ULONG *pcelt);
1613 virtual COM_METHOD Reset();
1614 virtual COM_METHOD Skip(ULONG celt);
1615
1616// ICorDebugXXXEnum interface
1617 virtual COM_METHOD Next(ULONG celt, ElemPublicType items[], ULONG *pceltFetched);
1618
1619// CordbBase overrides
1620 virtual VOID Neuter();
1621};
1622
1623// Converts T to U* by using QueryInterface
1624template<typename T, typename U>
1625U* QueryInterfaceConvert(T obj);
1626
1627// No conversion, just returns the argument
1628template<typename T>
1629T IdentityConvert(T obj);
1630
1631// CorDebugGuidToTypeMapping-adapter used by CordbGuidToTypeEnumerator
1632// in the CordbEnumerator pattern
1633struct RsGuidToTypeMapping
1634{
1635 GUID iid;
1636 RSSmartPtr<CordbType> spType;
1637};
1638
1639inline
1640CorDebugGuidToTypeMapping GuidToTypeMappingConvert(RsGuidToTypeMapping m)
1641{
1642 CorDebugGuidToTypeMapping result;
1643 result.iid = m.iid;
1644 result.pType = (ICorDebugType*)(m.spType.GetValue());
1645 result.pType->AddRef();
1646 return result;
1647}
1648
1649//
1650// Some useful enumerators
1651//
1652typedef CordbEnumerator<RSSmartPtr<CordbThread>,
1653 ICorDebugThread*,
1654 ICorDebugThreadEnum,
1655 QueryInterfaceConvert<RSSmartPtr<CordbThread>, ICorDebugThread> > CordbThreadEnumerator;
1656
1657typedef CordbEnumerator<CorDebugBlockingObject,
1658 CorDebugBlockingObject,
1659 ICorDebugBlockingObjectEnum,
1660 IdentityConvert<CorDebugBlockingObject> > CordbBlockingObjectEnumerator;
1661
1662// Template classes must be fully defined rather than just declared in the header
1663#include "rsenumerator.hpp"
1664
1665
1666typedef CordbEnumerator<COR_SEGMENT,
1667 COR_SEGMENT,
1668 ICorDebugHeapSegmentEnum,
1669 IdentityConvert<COR_SEGMENT> > CordbHeapSegmentEnumerator;
1670
1671typedef CordbEnumerator<CorDebugExceptionObjectStackFrame,
1672 CorDebugExceptionObjectStackFrame,
1673 ICorDebugExceptionObjectCallStackEnum,
1674 IdentityConvert<CorDebugExceptionObjectStackFrame> > CordbExceptionObjectCallStackEnumerator;
1675
1676typedef CordbEnumerator<RsGuidToTypeMapping,
1677 CorDebugGuidToTypeMapping,
1678 ICorDebugGuidToTypeEnum,
1679 GuidToTypeMappingConvert > CordbGuidToTypeEnumerator;
1680
1681typedef CordbEnumerator<RSSmartPtr<CordbVariableHome>,
1682 ICorDebugVariableHome*,
1683 ICorDebugVariableHomeEnum,
1684 QueryInterfaceConvert<RSSmartPtr<CordbVariableHome>, ICorDebugVariableHome> > CordbVariableHomeEnumerator;
1685
1686// ----------------------------------------------------------------------------
1687// Hash table for CordbBase objects.
1688// - Uses Internal AddRef/Release (not external)
1689// - Templatize for type-safety w/ Cordb objects
1690// - Many hashtables are implicitly protected by a lock. For debug-only, we
1691// explicitly associate w/ an optional RSLock and assert that lock is held on access.
1692// ----------------------------------------------------------------------------
1693
1694struct CordbHashEntry
1695{
1696 FREEHASHENTRY entry;
1697 CordbBase *pBase;
1698};
1699
1700class CordbHashTable : private CHashTableAndData<CNewDataNoThrow>
1701{
1702private:
1703 bool m_initialized;
1704 SIZE_T m_count;
1705
1706 BOOL Cmp(SIZE_T k1, const HASHENTRY * pc2)
1707 {
1708 LIMITED_METHOD_CONTRACT;
1709
1710 return ((ULONG_PTR)k1) != (reinterpret_cast<const CordbHashEntry *>(pc2))->pBase->m_id;
1711 }
1712
1713 ULONG HASH(ULONG_PTR id)
1714 {
1715 return (ULONG)(id);
1716 }
1717
1718 SIZE_T KEY(UINT_PTR id)
1719 {
1720 return (SIZE_T)id;
1721 }
1722
1723public:
1724 bool IsInitialized();
1725
1726#ifndef DACCESS_COMPILE
1727 CordbHashTable(ULONG size)
1728 : CHashTableAndData<CNewDataNoThrow>(size), m_initialized(false), m_count(0)
1729 {
1730#ifdef _DEBUG
1731 m_pDbgLock = NULL;
1732 m_dbgChangeCount = 0;
1733#endif
1734 }
1735 virtual ~CordbHashTable();
1736
1737#ifdef _DEBUG
1738 // CordbHashTables may be protected by a lock. For debug-builds, we can associate
1739 // the hash w/ that lock and then assert if it's not held.
1740 void DebugSetRSLock(RSLock * pLock)
1741 {
1742 m_pDbgLock = pLock;
1743 }
1744 int GetChangeCount() { return m_dbgChangeCount; }
1745private:
1746 void AssertIsProtected();
1747
1748 // Increment the Change count. This can be used to check if the hashtable changes while being enumerated.
1749 void DbgIncChangeCount() { m_dbgChangeCount++; }
1750
1751 int m_dbgChangeCount;
1752 RSLock * m_pDbgLock;
1753#else
1754 // RSLock association is a no-op on free builds.
1755 void AssertIsProtected() { };
1756 void DbgIncChangeCount() { };
1757#endif // _DEBUG
1758
1759public:
1760
1761
1762#endif
1763
1764 ULONG32 GetCount()
1765 {
1766 return ((ULONG32)m_count);
1767 }
1768
1769 // These operators are unsafe b/c they have no typesafety.
1770 // Use a derived CordbSafeHashTable<T> instead.
1771 HRESULT UnsafeAddBase(CordbBase *pBase);
1772 HRESULT UnsafeSwapBase(CordbBase* pBaseOld, CordbBase* pBaseNew);
1773 CordbBase *UnsafeGetBase(ULONG_PTR id, BOOL fFab = TRUE);
1774 CordbBase *UnsafeRemoveBase(ULONG_PTR id);
1775
1776 CordbBase *UnsafeFindFirst(HASHFIND *find);
1777 CordbBase *UnsafeFindNext(HASHFIND *find);
1778
1779 // Unlocked versions don't assert that the lock us held.
1780 CordbBase *UnsafeUnlockedFindFirst(HASHFIND *find);
1781 CordbBase *UnsafeUnlockedFindNext(HASHFIND *find);
1782
1783};
1784
1785
1786// Typesafe wrapper around a normal hash table
1787// T is expected to be a derived clas of CordbBase
1788// Note that this still isn't fully typesafe. Ideally we'd take a strongly-typed key
1789// instead of UINT_PTR (the type could have a fixed relationship to T, or could be
1790// an additional template argument like standard template hash tables like std::hash_map<K,V>)
1791template <class T>
1792class CordbSafeHashTable : public CordbHashTable
1793{
1794public:
1795#ifndef DACCESS_COMPILE
1796 CordbSafeHashTable<T>(ULONG size) : CordbHashTable(size)
1797 {
1798 }
1799#endif
1800 // Typesafe wrappers
1801 HRESULT AddBase(T * pBase) { return UnsafeAddBase(pBase); }
1802
1803 // Either add (eg, future cals to GetBase will succeed) or throw.
1804 void AddBaseOrThrow(T * pBase)
1805 {
1806 HRESULT hr = AddBase(pBase);
1807 IfFailThrow(hr);
1808 }
1809 HRESULT SwapBase(T* pBaseOld, T* pBaseNew) { return UnsafeSwapBase(pBaseOld, pBaseNew); }
1810 // Move the function definition of GetBase to rspriv.inl to work around gcc 2.9.5 warnings
1811 T* GetBase(ULONG_PTR id, BOOL fFab = TRUE);
1812 T* GetBaseOrThrow(ULONG_PTR id, BOOL fFab = TRUE);
1813
1814 T* RemoveBase(ULONG_PTR id) { return static_cast<T*>(UnsafeRemoveBase(id)); }
1815
1816 T* FindFirst(HASHFIND *find) { return static_cast<T*>(UnsafeFindFirst(find)); }
1817 T* FindNext(HASHFIND *find) { return static_cast<T*>(UnsafeFindNext(find)); }
1818
1819 // Neuter all items and clear
1820 void NeuterAndClear(RSLock * pLock);
1821
1822 void CopyToArray(RSPtrArray<T> * pArray);
1823 void TransferToArray(RSPtrArray<T> * pArray);
1824};
1825
1826
1827class CordbHashTableEnum : public CordbBase,
1828public ICorDebugProcessEnum,
1829public ICorDebugBreakpointEnum,
1830public ICorDebugStepperEnum,
1831public ICorDebugThreadEnum,
1832public ICorDebugModuleEnum,
1833public ICorDebugAppDomainEnum,
1834public ICorDebugAssemblyEnum
1835{
1836 // Private ctors. Use build function to access.
1837 CordbHashTableEnum(
1838 CordbBase * pOwnerObj,
1839 NeuterList * pOwnerList,
1840 CordbHashTable *table,
1841 const _GUID &id);
1842
1843public:
1844 static void BuildOrThrow(
1845 CordbBase * pOwnerObj,
1846 NeuterList * pOwnerList,
1847 CordbHashTable *table,
1848 const _GUID &id,
1849 RSInitHolder<CordbHashTableEnum> * pHolder);
1850
1851 CordbHashTableEnum(CordbHashTableEnum *cloneSrc);
1852
1853 ~CordbHashTableEnum();
1854 virtual void Neuter();
1855
1856
1857#ifdef _DEBUG
1858 // For debugging (asserts, logging, etc) provide a pretty name (this is 1:1 w/ the VTable)
1859 virtual const char * DbgGetName() { return "CordbHashTableEnum"; };
1860#endif
1861
1862
1863 HRESULT Next(ULONG celt, CordbBase *bases[], ULONG *pceltFetched);
1864
1865 //-----------------------------------------------------------
1866 // IUnknown
1867 //-----------------------------------------------------------
1868
1869 ULONG STDMETHODCALLTYPE AddRef()
1870 {
1871 return (BaseAddRef());
1872 }
1873 ULONG STDMETHODCALLTYPE Release()
1874 {
1875 return (BaseRelease());
1876 }
1877 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
1878
1879 //-----------------------------------------------------------
1880 // ICorDebugEnum
1881 //-----------------------------------------------------------
1882
1883 COM_METHOD Skip(ULONG celt);
1884 COM_METHOD Reset();
1885 COM_METHOD Clone(ICorDebugEnum **ppEnum);
1886 COM_METHOD GetCount(ULONG *pcelt);
1887
1888 //-----------------------------------------------------------
1889 // ICorDebugProcessEnum
1890 //-----------------------------------------------------------
1891
1892 COM_METHOD Next(ULONG celt, ICorDebugProcess *processes[],
1893 ULONG *pceltFetched)
1894 {
1895 VALIDATE_POINTER_TO_OBJECT_ARRAY(processes, ICorDebugProcess *,
1896 celt, true, true);
1897 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1898
1899 return (Next(celt, (CordbBase **)processes, pceltFetched));
1900 }
1901
1902 //-----------------------------------------------------------
1903 // ICorDebugBreakpointEnum
1904 //-----------------------------------------------------------
1905
1906 COM_METHOD Next(ULONG celt, ICorDebugBreakpoint *breakpoints[],
1907 ULONG *pceltFetched)
1908 {
1909 VALIDATE_POINTER_TO_OBJECT_ARRAY(breakpoints, ICorDebugBreakpoint *,
1910 celt, true, true);
1911 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1912
1913 return (Next(celt, (CordbBase **)breakpoints, pceltFetched));
1914 }
1915
1916 //-----------------------------------------------------------
1917 // ICorDebugStepperEnum
1918 //-----------------------------------------------------------
1919
1920 COM_METHOD Next(ULONG celt, ICorDebugStepper *steppers[],
1921 ULONG *pceltFetched)
1922 {
1923 VALIDATE_POINTER_TO_OBJECT_ARRAY(steppers, ICorDebugStepper *,
1924 celt, true, true);
1925 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1926
1927 return (Next(celt, (CordbBase **)steppers, pceltFetched));
1928 }
1929
1930 //-----------------------------------------------------------
1931 // ICorDebugThreadEnum
1932 //-----------------------------------------------------------
1933
1934 COM_METHOD Next(ULONG celt, ICorDebugThread *threads[],
1935 ULONG *pceltFetched)
1936 {
1937 VALIDATE_POINTER_TO_OBJECT_ARRAY(threads, ICorDebugThread *,
1938 celt, true, true);
1939 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1940
1941 return (Next(celt, (CordbBase **)threads, pceltFetched));
1942 }
1943
1944 //-----------------------------------------------------------
1945 // ICorDebugModuleEnum
1946 //-----------------------------------------------------------
1947
1948 COM_METHOD Next(ULONG celt, ICorDebugModule *modules[],
1949 ULONG *pceltFetched)
1950 {
1951 VALIDATE_POINTER_TO_OBJECT_ARRAY(modules, ICorDebugModule *,
1952 celt, true, true);
1953 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1954
1955 return (Next(celt, (CordbBase **)modules, pceltFetched));
1956 }
1957
1958 //-----------------------------------------------------------
1959 // ICorDebugAppDomainEnum
1960 //-----------------------------------------------------------
1961
1962 COM_METHOD Next(ULONG celt, ICorDebugAppDomain *appdomains[],
1963 ULONG *pceltFetched)
1964 {
1965 VALIDATE_POINTER_TO_OBJECT_ARRAY(appdomains, ICorDebugAppDomain *,
1966 celt, true, true);
1967 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1968
1969 return (Next(celt, (CordbBase **)appdomains, pceltFetched));
1970 }
1971 //-----------------------------------------------------------
1972 // ICorDebugAssemblyEnum
1973 //-----------------------------------------------------------
1974
1975 COM_METHOD Next(ULONG celt, ICorDebugAssembly *assemblies[],
1976 ULONG *pceltFetched)
1977 {
1978 VALIDATE_POINTER_TO_OBJECT_ARRAY(assemblies, ICorDebugAssembly *,
1979 celt, true, true);
1980 VALIDATE_POINTER_TO_OBJECT(pceltFetched, ULONG *);
1981
1982 return (Next(celt, (CordbBase **)assemblies, pceltFetched));
1983 }
1984private:
1985 // Owning object is our link to the CordbProcess* tree. Never null until we're neutered.
1986 // NeuterList is related to the owning object. Need to cache it so that we can pass it on
1987 // to our clones.
1988 CordbBase * m_pOwnerObj; // provides us w/ a CordbProcess*
1989 NeuterList * m_pOwnerNeuterList;
1990
1991
1992 CordbHashTable *m_table;
1993 bool m_started;
1994 bool m_done;
1995 HASHFIND m_hashfind;
1996 REFIID m_guid;
1997 ULONG m_iCurElt;
1998 ULONG m_count;
1999 BOOL m_fCountInit;
2000
2001#ifdef _DEBUG
2002 // timestampt of hashtable when we start enumerating it. Useful for detecting if the table
2003 // changes underneath us.
2004 int m_DbgChangeCount;
2005 void AssertValid();
2006#else
2007 void AssertValid() { }
2008#endif
2009
2010private:
2011 //These factor code between Next & Skip
2012 HRESULT PrepForEnum(CordbBase **pBase);
2013
2014 // Note that the set of types advanced by Pre & by Post are disjoint, and
2015 // that the union of these two sets are all possible types enuerated by
2016 // the CordbHashTableEnum.
2017 HRESULT AdvancePreAssign(CordbBase **pBase);
2018 HRESULT AdvancePostAssign(CordbBase **pBase,
2019 CordbBase **b,
2020 CordbBase **bEnd);
2021
2022 // This factors some code that initializes the module enumerator.
2023 HRESULT SetupModuleEnum();
2024
2025};
2026
2027
2028//-----------------------------------------------------------------------------
2029// Neuter List
2030// Dtors can be called at any time (whenever Cordbg calls Release, which is outside
2031// of our control), so we never want to do significant work in a dtor
2032// (this includes sending IPC events + neutering).
2033// So objects can queue themselves up to be neutered at a safe time.
2034//
2035// Items in a NeuterList should only contain state in the Right-Side.
2036// If the item holds resources in the left-side, it should be placed on a
2037// code:LeftSideResourceCleanupList
2038//-----------------------------------------------------------------------------
2039class NeuterList
2040{
2041public:
2042 NeuterList();
2043 ~NeuterList();
2044
2045 // Add an object to be neutered.
2046 // Anybody calls this to add themselves to the list.
2047 // This will add it to the list and maintain an internal reference to it.
2048 void Add(CordbProcess * pProcess, CordbBase * pObject);
2049
2050 // Add w/o checking for safety. Should only be used by Process-list enum.
2051 void UnsafeAdd(CordbProcess * pProcess, CordbBase * pObject);
2052
2053 // Neuter everything on the list.
2054 // This should only be called by the "owner", but we can't really enforce that.
2055 // This will release all internal references and empty the list.
2056 void NeuterAndClear(CordbProcess * pProcess);
2057
2058 // Sweep for all objects that are marked as 'm_fNeuterAtWill'.
2059 // Neuter and remove these.
2060 void SweepAllNeuterAtWillObjects(CordbProcess * pProcess);
2061
2062protected:
2063 struct Node
2064 {
2065 RSSmartPtr<CordbBase> m_pObject;
2066 Node * m_pNext;
2067 };
2068
2069 // Manipulating the list is done under the Process lock.
2070 Node * m_pHead;
2071};
2072
2073//-----------------------------------------------------------------------------
2074// This list is for objects that hold left-side resources.
2075// If the object does not hold left-side resources, it can be placed on a
2076// code:NeuterList
2077//-----------------------------------------------------------------------------
2078class LeftSideResourceCleanupList : public NeuterList
2079{
2080public:
2081 // dispose everything contained in the list by calling SafeDispose() on each element
2082 void SweepNeuterLeftSideResources(CordbProcess * pProcess);
2083 void NeuterLeftSideResourcesAndClear(CordbProcess * pProcess);
2084};
2085
2086//-------------------------------------------------------------------------
2087//
2088// Optional<T>
2089// Stores a value along with a bit indicating whether the value is valid.
2090//
2091// This is particularly useful for LS data read via DAC. We need to gracefully
2092// handle missing data, and we may want to track independent pieces of data
2093// separately (often with lazy initialization). It's essential that we can't
2094// easily lose track of whether the data has been cached yet or not. So
2095// rather than have extra "isValid" bools everywhere, we use this class to
2096// encapsulate the validity bit in with the data, and ASSERT that it is true
2097// whenever reading out the data.
2098// Note that the client must still remember to call GetValue only when HasValue
2099// is true. Since C++ doesn't have type-safe sum types, we can't enforce this
2100// explicitly at compile time (ML-style datatypes and pattern matching is perfect
2101// for this).
2102//
2103// Note that we could consider adding some operator overloads to make using
2104// instances of this class more transparent. Experience will tell if this
2105// is a good idea or not.
2106//
2107template <typename T>
2108class Optional
2109{
2110public:
2111 // By default, initialize to invalid
2112 Optional() : m_fHasValue(false), m_value(T()) {}
2113
2114 // Allow implicit initialization from a value (for copyable T)
2115 Optional(const T& val) : m_fHasValue(true), m_value(val) {}
2116
2117 // Returns true if a value has been stored
2118 bool HasValue() const { return m_fHasValue; }
2119
2120 // Extract the value. Can only be called when HasValue is true.
2121 const T& GetValue() { _ASSERTE(m_fHasValue); return m_value; }
2122
2123 // Get a writable pointer to the value structure, for filling in uncopyable data structures
2124 T * GetValueAddr() { return &m_value; }
2125
2126 // Explicitly mark this object as having a value (for use after writing to it directly using
2127 // GetValueAddr. Not necessary for simple/primitive types).
2128 void SetHasValue() { m_fHasValue = true; }
2129
2130 // Also gets compiler-default copy constructor and assignment operator if T has them
2131
2132private:
2133 bool m_fHasValue;
2134 T m_value;
2135};
2136
2137
2138/* ------------------------------------------------------------------------- *
2139 * Cordb class
2140 * ------------------------------------------------------------------------- */
2141
2142class Cordb : public CordbBase, public ICorDebug, public ICorDebugRemote
2143{
2144public:
2145 Cordb(CorDebugInterfaceVersion iDebuggerVersion);
2146 virtual ~Cordb();
2147 virtual void Neuter();
2148
2149
2150
2151#ifdef _DEBUG_IMPL
2152 virtual const char * DbgGetName() { return "Cordb"; }
2153
2154 // Under Debug, we keep some extra state for tracking leaks. The goal is that
2155 // we can assert that we aren't leaking internal refs. We'd like to assert that
2156 // we're not leaking external refs, but since we can't force Cordbg to release,
2157 // we can't really assert that.
2158 // So the idea is that when Cordbg has released its last Cordb object, that
2159 // all internal references have been released.
2160 // Unfortunately, certain CordbBase objects are unrooted and thus we have no
2161 // good time to neuter them and clean up any internal references they may hold.
2162 // So we keep count of those guys too.
2163 static LONG s_DbgMemTotalOutstandingCordb;
2164 static LONG s_DbgMemTotalOutstandingInternalRefs;
2165#endif
2166
2167 //
2168 // Turn this on to enable an array which will contain all objects that have
2169 // not been completely released.
2170 //
2171 // #define TRACK_OUTSTANDING_OBJECTS 1
2172
2173#ifdef TRACK_OUTSTANDING_OBJECTS
2174
2175#define MAX_TRACKED_OUTSTANDING_OBJECTS 256
2176 static void *Cordb::s_DbgMemOutstandingObjects[MAX_TRACKED_OUTSTANDING_OBJECTS];
2177 static LONG Cordb::s_DbgMemOutstandingObjectMax;
2178#endif
2179
2180
2181 //-----------------------------------------------------------
2182 // IUnknown
2183 //-----------------------------------------------------------
2184
2185 ULONG STDMETHODCALLTYPE AddRef()
2186 {
2187 return (BaseAddRef());
2188 }
2189 ULONG STDMETHODCALLTYPE Release()
2190 {
2191 return (BaseRelease());
2192 }
2193 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2194
2195 //-----------------------------------------------------------
2196 // ICorDebug
2197 //-----------------------------------------------------------
2198
2199 HRESULT SetTargetCLR(HMODULE hmodTargetCLR);
2200
2201 COM_METHOD Initialize();
2202 COM_METHOD Terminate();
2203 COM_METHOD SetManagedHandler(ICorDebugManagedCallback *pCallback);
2204 COM_METHOD SetUnmanagedHandler(ICorDebugUnmanagedCallback *pCallback);
2205 COM_METHOD CreateProcess(LPCWSTR lpApplicationName,
2206 __in_z LPWSTR lpCommandLine,
2207 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2208 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2209 BOOL bInheritHandles,
2210 DWORD dwCreationFlags,
2211 PVOID lpEnvironment,
2212 LPCWSTR lpCurrentDirectory,
2213 LPSTARTUPINFOW lpStartupInfo,
2214 LPPROCESS_INFORMATION lpProcessInformation,
2215 CorDebugCreateProcessFlags debuggingFlags,
2216 ICorDebugProcess **ppProcess);
2217 COM_METHOD DebugActiveProcess(DWORD dwProcessId, BOOL fWin32Attach, ICorDebugProcess **ppProcess);
2218 COM_METHOD EnumerateProcesses(ICorDebugProcessEnum **ppProcess);
2219 COM_METHOD GetProcess(DWORD dwProcessId, ICorDebugProcess **ppProcess);
2220 COM_METHOD CanLaunchOrAttach(DWORD dwProcessId, BOOL win32DebuggingEnabled);
2221
2222 //-----------------------------------------------------------
2223 // CorDebug
2224 //-----------------------------------------------------------
2225
2226 static COM_METHOD CreateObjectV1(REFIID id, void **object);
2227#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
2228 static COM_METHOD CreateObjectTelesto(REFIID id, void ** pObject);
2229#endif // FEATURE_DBGIPC_TRANSPORT_DI
2230 static COM_METHOD CreateObject(CorDebugInterfaceVersion iDebuggerVersion, DWORD pid, LPCWSTR lpApplicationGroupId, REFIID id, void **object);
2231
2232 //-----------------------------------------------------------
2233 // ICorDebugRemote
2234 //-----------------------------------------------------------
2235
2236 COM_METHOD CreateProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
2237 LPCWSTR lpApplicationName,
2238 __in_z LPWSTR lpCommandLine,
2239 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2240 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2241 BOOL bInheritHandles,
2242 DWORD dwCreationFlags,
2243 PVOID lpEnvironment,
2244 LPCWSTR lpCurrentDirectory,
2245 LPSTARTUPINFOW lpStartupInfo,
2246 LPPROCESS_INFORMATION lpProcessInformation,
2247 CorDebugCreateProcessFlags debuggingFlags,
2248 ICorDebugProcess ** ppProcess);
2249
2250 COM_METHOD DebugActiveProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
2251 DWORD dwProcessId,
2252 BOOL fWin32Attach,
2253 ICorDebugProcess ** ppProcess);
2254
2255
2256 //-----------------------------------------------------------
2257 // Methods not exposed via a COM interface.
2258 //-----------------------------------------------------------
2259
2260 HRESULT CreateProcessCommon(ICorDebugRemoteTarget * pRemoteTarget,
2261 LPCWSTR lpApplicationName,
2262 __in_z LPWSTR lpCommandLine,
2263 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2264 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2265 BOOL bInheritHandles,
2266 DWORD dwCreationFlags,
2267 PVOID lpEnvironment,
2268 LPCWSTR lpCurrentDirectory,
2269 LPSTARTUPINFOW lpStartupInfo,
2270 LPPROCESS_INFORMATION lpProcessInformation,
2271 CorDebugCreateProcessFlags debuggingFlags,
2272 ICorDebugProcess **ppProcess);
2273
2274 HRESULT DebugActiveProcessCommon(ICorDebugRemoteTarget * pRemoteTarget, DWORD id, BOOL win32Attach, ICorDebugProcess **ppProcess);
2275
2276 void EnsureCanLaunchOrAttach(BOOL fWin32DebuggingEnabled);
2277
2278 void EnsureAllowAnotherProcess();
2279 void AddProcess(CordbProcess* process);
2280 void RemoveProcess(CordbProcess* process);
2281 CordbSafeHashTable<CordbProcess> *GetProcessList();
2282
2283 void LockProcessList();
2284 void UnlockProcessList();
2285
2286 #ifdef _DEBUG
2287 bool ThreadHasProcessListLock();
2288 #endif
2289
2290
2291 HRESULT SendIPCEvent(CordbProcess * pProcess,
2292 DebuggerIPCEvent * pEvent,
2293 SIZE_T eventSize);
2294
2295 void ProcessStateChanged();
2296
2297 HRESULT WaitForIPCEventFromProcess(CordbProcess* process,
2298 CordbAppDomain *appDomain,
2299 DebuggerIPCEvent* event);
2300
2301private:
2302 Cordb(CorDebugInterfaceVersion iDebuggerVersion, const ProcessDescriptor& pd);
2303
2304 //-----------------------------------------------------------
2305 // Data members
2306 //-----------------------------------------------------------
2307
2308public:
2309 RSExtSmartPtr<ICorDebugManagedCallback> m_managedCallback;
2310 RSExtSmartPtr<ICorDebugManagedCallback2> m_managedCallback2;
2311 RSExtSmartPtr<ICorDebugManagedCallback3> m_managedCallback3;
2312 RSExtSmartPtr<ICorDebugManagedCallback4> m_managedCallback4;
2313 RSExtSmartPtr<ICorDebugUnmanagedCallback> m_unmanagedCallback;
2314
2315 CordbRCEventThread* m_rcEventThread;
2316
2317 CorDebugInterfaceVersion GetDebuggerVersion() const;
2318
2319#ifdef FEATURE_CORESYSTEM
2320 HMODULE GetTargetCLR() { return m_targetCLR; }
2321#endif
2322
2323private:
2324 bool IsCreateProcessSupported();
2325 bool IsInteropDebuggingSupported();
2326 void CheckCompatibility();
2327
2328 CordbSafeHashTable<CordbProcess> m_processes;
2329
2330 // List to track outstanding CordbProcessEnum objects.
2331 NeuterList m_pProcessEnumList;
2332
2333 RSLock m_processListMutex;
2334 BOOL m_initialized;
2335
2336 // This is the version of the ICorDebug APIs that the debugger believes it's consuming.
2337 CorDebugInterfaceVersion m_debuggerSpecifiedVersion;
2338
2339 // Store information about the process to be debugged
2340 ProcessDescriptor m_pd;
2341
2342//Note - this code could be useful outside coresystem, but keeping the change localized
2343// because we are late in the win8 release
2344#ifdef FEATURE_CORESYSTEM
2345 HMODULE m_targetCLR;
2346#endif
2347};
2348
2349
2350
2351
2352/* ------------------------------------------------------------------------- *
2353 * AppDomain class
2354 * ------------------------------------------------------------------------- */
2355
2356// Provides the implementation for ICorDebugAppDomain, ICorDebugAppDomain2,
2357// and ICorDebugAppDomain3
2358class CordbAppDomain : public CordbBase,
2359 public ICorDebugAppDomain,
2360 public ICorDebugAppDomain2,
2361 public ICorDebugAppDomain3,
2362 public ICorDebugAppDomain4
2363{
2364public:
2365 // Create a CordbAppDomain object based on a pointer to the AppDomain instance in the CLR
2366 CordbAppDomain(CordbProcess * pProcess,
2367 VMPTR_AppDomain vmAppDomain);
2368
2369 virtual ~CordbAppDomain();
2370
2371 virtual void Neuter();
2372
2373 using CordbBase::GetProcess;
2374
2375#ifdef _DEBUG
2376 virtual const char * DbgGetName() { return "CordbAppDomain"; }
2377#endif
2378
2379
2380 //-----------------------------------------------------------
2381 // IUnknown
2382 //-----------------------------------------------------------
2383
2384 ULONG STDMETHODCALLTYPE AddRef()
2385 {
2386 return (BaseAddRef());
2387 }
2388 ULONG STDMETHODCALLTYPE Release()
2389 {
2390 return (BaseRelease());
2391 }
2392 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2393
2394 //-----------------------------------------------------------
2395 // ICorDebugController
2396 //-----------------------------------------------------------
2397
2398 COM_METHOD Stop(DWORD dwTimeout);
2399 COM_METHOD Continue(BOOL fIsOutOfBand);
2400 COM_METHOD IsRunning(BOOL * pbRunning);
2401 COM_METHOD HasQueuedCallbacks(ICorDebugThread * pThread,
2402 BOOL * pbQueued);
2403 COM_METHOD EnumerateThreads(ICorDebugThreadEnum ** ppThreads);
2404 COM_METHOD SetAllThreadsDebugState(CorDebugThreadState state, ICorDebugThread * pExceptThisThread);
2405
2406 // Deprecated, returns E_NOTIMPL
2407 COM_METHOD Detach();
2408
2409 COM_METHOD Terminate(unsigned int exitCode);
2410
2411 COM_METHOD CanCommitChanges(
2412 ULONG cSnapshots,
2413 ICorDebugEditAndContinueSnapshot * pSnapshots[],
2414 ICorDebugErrorInfoEnum ** pError);
2415
2416 COM_METHOD CommitChanges(
2417 ULONG cSnapshots,
2418 ICorDebugEditAndContinueSnapshot * pSnapshots[],
2419 ICorDebugErrorInfoEnum ** pError);
2420
2421 //-----------------------------------------------------------
2422 // ICorDebugAppDomain
2423 //-----------------------------------------------------------
2424 /*
2425 * GetProcess returns the process containing the app domain
2426 */
2427
2428 COM_METHOD GetProcess(ICorDebugProcess ** ppProcess);
2429
2430 /*
2431 * EnumerateAssemblies enumerates all assemblies in the app domain
2432 */
2433
2434 COM_METHOD EnumerateAssemblies(ICorDebugAssemblyEnum ** ppAssemblies);
2435
2436 COM_METHOD GetModuleFromMetaDataInterface(IUnknown * pIMetaData,
2437 ICorDebugModule ** ppModule);
2438 /*
2439 * EnumerateBreakpoints returns an enum of all active breakpoints
2440 * in the app domain. This includes all types of breakpoints :
2441 * function breakpoints, data breakpoints, etc.
2442 */
2443
2444 COM_METHOD EnumerateBreakpoints(ICorDebugBreakpointEnum ** ppBreakpoints);
2445
2446 /*
2447 * EnumerateSteppers returns an enum of all active steppers in the app domain.
2448 */
2449
2450 COM_METHOD EnumerateSteppers(ICorDebugStepperEnum ** ppSteppers);
2451
2452 // Deprecated, always returns true.
2453 COM_METHOD IsAttached(BOOL * pfAttached);
2454
2455 // Returns the friendly name of the AppDomain
2456 COM_METHOD GetName(ULONG32 cchName,
2457 ULONG32 * pcchName,
2458 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2459
2460 /*
2461 * GetObject returns the runtime app domain object.
2462 * Note: This method is not yet implemented.
2463 */
2464
2465 COM_METHOD GetObject(ICorDebugValue ** ppObject);
2466
2467 // Deprecated, does nothing
2468 COM_METHOD Attach();
2469 COM_METHOD GetID(ULONG32 * pId);
2470
2471 //-----------------------------------------------------------
2472 // ICorDebugAppDomain2 APIs
2473 //-----------------------------------------------------------
2474 COM_METHOD GetArrayOrPointerType(CorElementType elementType,
2475 ULONG32 nRank,
2476 ICorDebugType * pTypeArg,
2477 ICorDebugType ** ppResultType);
2478
2479 COM_METHOD GetFunctionPointerType(ULONG32 cTypeArgs,
2480 ICorDebugType * rgpTypeArgs[],
2481 ICorDebugType ** ppResultType);
2482
2483 //-----------------------------------------------------------
2484 // ICorDebugAppDomain3 APIs
2485 //-----------------------------------------------------------
2486 COM_METHOD GetCachedWinRTTypesForIIDs(
2487 ULONG32 cGuids,
2488 GUID * guids,
2489 ICorDebugTypeEnum * * ppTypesEnum);
2490
2491 COM_METHOD GetCachedWinRTTypes(
2492 ICorDebugGuidToTypeEnum * * ppType);
2493
2494 //-----------------------------------------------------------
2495 // ICorDebugAppDomain4
2496 //-----------------------------------------------------------
2497 COM_METHOD GetObjectForCCW(CORDB_ADDRESS ccwPointer, ICorDebugValue **ppManagedObject);
2498
2499 // Get the VMPTR for this appdomain.
2500 VMPTR_AppDomain GetADToken() { return m_vmAppDomain; }
2501
2502 // Given a metadata interface, find the module in this appdomain that matches it.
2503 CordbModule * GetModuleFromMetaDataInterface(IUnknown *pIMetaData);
2504
2505 // Lookup a module from the cache. Create and to the cache if needed.
2506 CordbModule * LookupOrCreateModule(VMPTR_Module vmModuleToken, VMPTR_DomainFile vmDomainFileToken);
2507
2508 // Lookup a module from the cache. Create and to the cache if needed.
2509 CordbModule * LookupOrCreateModule(VMPTR_DomainFile vmDomainFileToken);
2510
2511 // Callback from DAC for module enumeration
2512 static void ModuleEnumerationCallback(VMPTR_DomainFile vmModule, void * pUserData);
2513
2514 // Use DAC to add any modules for this assembly.
2515 void PrepopulateModules();
2516
2517 void InvalidateName() { m_strAppDomainName.Clear(); }
2518
2519public:
2520 ULONG m_AppDomainId;
2521
2522 CordbAssembly * LookupOrCreateAssembly(VMPTR_DomainAssembly vmDomainAssembly);
2523 CordbAssembly * LookupOrCreateAssembly(VMPTR_Assembly vmAssembly);
2524 void RemoveAssemblyFromCache(VMPTR_DomainAssembly vmDomainAssembly);
2525
2526
2527 CordbSafeHashTable<CordbBreakpoint> m_breakpoints;
2528
2529 // Unique objects that represent the use of some
2530 // basic ELEMENT_TYPE's as type parameters. These
2531 // are shared acrosss the entire process. We could
2532 // go and try to find the classes corresponding to these
2533 // element types but it seems simpler just to keep
2534 // them as special cases.
2535 CordbSafeHashTable<CordbType> m_sharedtypes;
2536
2537 CordbAssembly * CacheAssembly(VMPTR_DomainAssembly vmDomainAssembly);
2538 CordbAssembly * CacheAssembly(VMPTR_Assembly vmAssembly);
2539
2540
2541 // Cache of modules in this appdomain. In the VM, modules live in an assembly.
2542 // This cache lives on the appdomain because we generally want to do appdomain (or process)
2543 // wide lookup.
2544 // This is indexed by VMPTR_DomainFile, which has appdomain affinity.
2545 // This is populated by code:CordbAppDomain::LookupOrCreateModule (which may be invoked
2546 // anytime the RS gets hold of a VMPTR), and are removed at the unload event.
2547 CordbSafeHashTable<CordbModule> m_modules;
2548private:
2549 // Cache of assemblies in this appdomain.
2550 // This is indexed by VMPTR_DomainAssembly, which has appdomain affinity.
2551 // This is populated by code:CordbAppDomain::LookupOrCreateAssembly (which may be invoked
2552 // anytime the RS gets hold of a VMPTR), and are removed at the unload event.
2553 CordbSafeHashTable<CordbAssembly> m_assemblies;
2554
2555 static void AssemblyEnumerationCallback(VMPTR_DomainAssembly vmDomainAssembly, void * pThis);
2556 void PrepopulateAssembliesOrThrow();
2557
2558 // Use DAC to refresh our name
2559 HRESULT RefreshName();
2560
2561 StringCopyHolder m_strAppDomainName;
2562
2563 NeuterList m_TypeNeuterList; // List of types owned by this AppDomain.
2564
2565 // List of Sweepable objects owned by this AppDomain.
2566 // This includes some objects taht hold resources in the left-side (mainly
2567 // as CordbHandleValue, see code:CordbHandleValue::Dispose), as well as:
2568 // - Cordb*Value objects that survive across continues and have appdomain affinity.
2569 LeftSideResourceCleanupList m_SweepableNeuterList;
2570
2571 VMPTR_AppDomain m_vmAppDomain;
2572public:
2573 // The "Long" exit list is for items that don't get neutered until the appdomain exits.
2574 // The "Sweepable" exit list is for items that may be neuterable sooner than AD exit.
2575 // By splitting out the list, we can just try to sweep the "Sweepable" list and we
2576 // don't waste any time sweeping things on the "Long" list that aren't neuterable anyways.
2577 NeuterList * GetLongExitNeuterList() { return &m_TypeNeuterList; }
2578 LeftSideResourceCleanupList * GetSweepableExitNeuterList() { return &m_SweepableNeuterList; }
2579
2580 void AddToTypeList(CordbBase *pObject);
2581
2582};
2583
2584
2585/* ------------------------------------------------------------------------- *
2586 * Assembly class
2587 * ------------------------------------------------------------------------- */
2588
2589class CordbAssembly : public CordbBase, public ICorDebugAssembly, ICorDebugAssembly2
2590{
2591public:
2592 CordbAssembly(CordbAppDomain * pAppDomain,
2593 VMPTR_Assembly vmAssembly,
2594 VMPTR_DomainAssembly vmDomainAssembly);
2595 virtual ~CordbAssembly();
2596 virtual void Neuter();
2597
2598 using CordbBase::GetProcess;
2599
2600#ifdef _DEBUG
2601 virtual const char * DbgGetName() { return "CordbAssembly"; }
2602#endif
2603
2604
2605 //-----------------------------------------------------------
2606 // IUnknown
2607 //-----------------------------------------------------------
2608
2609 ULONG STDMETHODCALLTYPE AddRef()
2610 {
2611 return (BaseAddRef());
2612 }
2613 ULONG STDMETHODCALLTYPE Release()
2614 {
2615 return (BaseRelease());
2616 }
2617 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
2618
2619 //-----------------------------------------------------------
2620 // ICorDebugAssembly
2621 //-----------------------------------------------------------
2622
2623 /*
2624 * GetProcess returns the process containing the assembly
2625 */
2626 COM_METHOD GetProcess(ICorDebugProcess ** ppProcess);
2627
2628 // Gets the AppDomain containing this assembly
2629 COM_METHOD GetAppDomain(ICorDebugAppDomain ** ppAppDomain);
2630
2631 /*
2632 * EnumerateModules enumerates all modules in the assembly
2633 */
2634 COM_METHOD EnumerateModules(ICorDebugModuleEnum ** ppModules);
2635
2636 /*
2637 * GetCodeBase returns the code base used to load the assembly
2638 */
2639 COM_METHOD GetCodeBase(ULONG32 cchName,
2640 ULONG32 * pcchName,
2641 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2642
2643 // returns the filename of the assembly, or "<unknown>" for in-memory assemblies
2644 COM_METHOD GetName(ULONG32 cchName,
2645 ULONG32 * pcchName,
2646 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
2647
2648
2649 //-----------------------------------------------------------
2650 // ICorDebugAssembly2
2651 //-----------------------------------------------------------
2652
2653 /*
2654 * IsFullyTrusted returns a flag indicating whether the security system
2655 * has granted the assembly full trust.
2656 */
2657 COM_METHOD IsFullyTrusted(BOOL * pbFullyTrusted);
2658
2659 //-----------------------------------------------------------
2660 // internal accessors
2661 //-----------------------------------------------------------
2662
2663#ifdef _DEBUG
2664 void DbgAssertAssemblyDeleted();
2665
2666 static void DbgAssertAssemblyDeletedCallback(VMPTR_DomainAssembly vmDomainAssembly, void * pUserData);
2667#endif // _DEBUG
2668
2669 CordbAppDomain * GetAppDomain() { return m_pAppDomain; }
2670
2671 VMPTR_DomainAssembly GetDomainAssemblyPtr() { return m_vmDomainAssembly; }
2672private:
2673 VMPTR_Assembly m_vmAssembly;
2674 VMPTR_DomainAssembly m_vmDomainAssembly;
2675 CordbAppDomain * m_pAppDomain;
2676
2677 StringCopyHolder m_strAssemblyFileName;
2678 Optional<BOOL> m_foptIsFullTrust;
2679};
2680
2681
2682//-----------------------------------------------------------------------------
2683// Describe what to do w/ a win32 debug event
2684//-----------------------------------------------------------------------------
2685class Reaction
2686{
2687public:
2688 enum Type
2689 {
2690 // Inband events: Dispatch to Cordbg
2691 // safe for stopping the shell and communicating with the runtime
2692 cInband,
2693
2694 // workaround. Inband event, but NewEvent =false
2695 cInband_NotNewEvent,
2696
2697 // This is a debug event that corresponds with getting to the beginning
2698 // of a first chance hijack.
2699 cFirstChanceHijackStarted,
2700
2701 // This is the debug event that corresponds with getting to the end of
2702 // a hijack. To continue we need to restore an unhijacked context
2703 cInbandHijackComplete,
2704
2705 // This is a debug event which corresponds to re-hiting a previous
2706 // IB event after returning from the hijack. Now we have already dispatched it
2707 // so we know how the user wants it to be continued
2708 // Continue immediately with the previously determined
2709 cInbandExceptionRetrigger,
2710
2711 // This debug event is a breakpoint in unmanaged code that we placed. It will need
2712 // the M2UHandoffHijack to run the in process breakpoint handling code.
2713 cBreakpointRequiringHijack,
2714
2715 // Oob events: Dispatch to Cordbg
2716 // Not safe stopping events. They must be continued immediately.
2717 cOOB,
2718
2719 // CLR internal exception, Continue(not_handled), don't dispatch
2720 // The CLR expects this exception and will deal with it properly.
2721 cCLR,
2722
2723 // Don't dispatch. Continue(DBG_CONTINUE).
2724 // Common for flare.
2725 cIgnore
2726 };
2727
2728 Type GetType() const { return m_type; };
2729
2730#ifdef _DEBUG
2731 const char * GetReactionName()
2732 {
2733 switch(m_type)
2734 {
2735 case cInband: return "cInband";
2736 case cInband_NotNewEvent: return "cInband_NotNewEvent";
2737 case cFirstChanceHijackStarted: return "cFirstChanceHijackStarted";
2738 case cInbandHijackComplete: return "cInbandHijackComplete";
2739 case cInbandExceptionRetrigger: return "cInbandExceptionRetrigger";
2740 case cBreakpointRequiringHijack: return "cBreakpointRequiringHijack";
2741 case cOOB: return "cOOB";
2742 case cCLR: return "cCLR";
2743 case cIgnore: return "cIgnore";
2744 default: return "<unknown>";
2745 }
2746 }
2747 int GetLine()
2748 {
2749 return m_line;
2750 }
2751#endif
2752
2753 Reaction(Type t, int line) : m_type(t) {
2754#ifdef _DEBUG
2755 m_line = line;
2756
2757 LOG((LF_CORDB, LL_EVERYTHING, "Reaction:%s (determined on line: %d)\n", GetReactionName(), line));
2758#endif
2759 };
2760
2761 void operator=(const Reaction & other)
2762 {
2763 m_type = other.m_type;
2764#ifdef _DEBUG
2765 m_line = other.m_line;
2766#endif
2767 }
2768
2769protected:
2770 Type m_type;
2771
2772#ifdef _DEBUG
2773 // Under a debug build, track the line # for where this came from.
2774 int m_line;
2775#endif
2776};
2777
2778// Macro for creating a Reaction.
2779#define REACTION(type) Reaction(Reaction::type, __LINE__)
2780
2781// Different forms of Unmanaged Continue
2782enum EUMContinueType
2783{
2784 cOobUMContinue,
2785 cInternalUMContinue,
2786 cRealUMContinue
2787};
2788
2789/* ------------------------------------------------------------------------- *
2790 * Process class
2791 * ------------------------------------------------------------------------- */
2792
2793
2794#ifdef _DEBUG
2795// On debug, we can afford a larger native event queue..
2796const int DEBUG_EVENTQUEUE_SIZE = 30;
2797#else
2798const int DEBUG_EVENTQUEUE_SIZE = 10;
2799#endif
2800
2801void DeleteIPCEventHelper(DebuggerIPCEvent *pDel);
2802
2803
2804// Private interface on CordbProcess that ShimProcess needs to emulate V2 functionality.
2805// The fact that we need private hooks means that V3 is not sufficiently finished to allow building
2806// a V2 debugger. This interface should shrink over time (and eventually go away) as the functionality gets exposed
2807// publicly.
2808// CordbProcess calls back into ShimProcess too, so the public surface of code:ShimProcess plus
2809// the spots in CordbProcess that call them are additional surface area that may need to addressed
2810// to make the shim public.
2811class IProcessShimHooks
2812{
2813public:
2814 // Get the OS Process descriptor of the target.
2815 virtual const ProcessDescriptor* GetProcessDescriptor() = 0;
2816
2817 // Request a synchronization for attach.
2818 // This essentially just sends an AsyncBreak to the left-side. Once the target is
2819 // synchronized, the Shim can use inspection to send all the various fake-attach events.
2820 //
2821 // Once the shim has a way of requesting a synchronization from out-of-process for an
2822 // arbitrary running target that's not stopped at a managed debug event, we can
2823 // remove this.
2824 virtual void QueueManagedAttachIfNeeded() = 0;
2825
2826 // Hijack a thread at an unhandled exception to allow us to resume executing the target so
2827 // that the helper thread can run and service IPC requests. This is also needed to allow
2828 // func-eval at a 2nd-chance exception
2829 //
2830 // This will require an architectural change to remove. Either:
2831 // - actions like func-eval / synchronization may call this directly themselves.
2832 // - the CLR's managed Unhandled-exception event is moved out of the native
2833 // unhandled-exception event, thus making native unhandled exceptions uninteresting to ICorDebug.
2834 // - everything is out-of-process, and so the CLR doesn't need to continue after an unhandled
2835 // native exception.
2836 virtual BOOL HijackThreadForUnhandledExceptionIfNeeded(DWORD dwThreadId) = 0;
2837
2838#ifdef FEATURE_INTEROP_DEBUGGING
2839 // Private hook to do the bulk of the interop-debugging goo. This includes hijacking inband
2840 // events and queueing them so that the helper-thread can run.
2841 //
2842 // We can remove this once we kill the helper-thread, or after enough functionality is
2843 // out-of-process that the debugger doesn't need the helper thread when stopped at an event.
2844 virtual void HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEvent) = 0;
2845#endif // FEATURE_INTEROP_DEBUGGING
2846
2847 // Get the modules in the order that they were loaded. This is needed to send the fake-attach events
2848 // for module load in the right order.
2849 //
2850 // This can be removed once ICorDebug's enumerations are ordered.
2851 virtual void GetModulesInLoadOrder(
2852 ICorDebugAssembly * pAssembly,
2853 RSExtSmartPtr<ICorDebugModule>* pModules,
2854 ULONG countModules) = 0;
2855
2856 // Get the assemblies in the order that they were loaded. This is needed to send the fake-attach events
2857 // for assembly load in the right order.
2858 //
2859 // This can be removed once ICorDebug's enumerations are ordered.
2860 virtual void GetAssembliesInLoadOrder(
2861 ICorDebugAppDomain * pAppDomain,
2862 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
2863 ULONG countAssemblies) = 0;
2864
2865 // Queue up fake connection events for attach.
2866 // ICorDebug doesn't expose any enumeration for connections, so the shim needs to call into a
2867 // private hook to enumerate them for attach.
2868 virtual void QueueFakeConnectionEvents() = 0;
2869
2870 // This finishes initializing the IPC channel between the LS + RS, which includes duplicating
2871 // some handles and events.
2872 //
2873 // This can be removed once the IPC channel is completely gone and all communication goes
2874 // soley through the data-target.
2875 virtual void FinishInitializeIPCChannel() = 0;
2876
2877 // Called when stopped at a managed debug event to request a synchronization.
2878 // This can be replaced when we expose synchronization from ICorDebug.
2879 // The fact that the debuggee is at a managed debug event greatly simplifies the request here
2880 // (in contrast to QueueManagedAttachIfNeeded). It means that we can just flip a flag from
2881 // out-of-process, and when the debuggee thread resumes, it can check that flag and do the
2882 // synchronization from in-process.
2883 virtual void RequestSyncAtEvent()= 0;
2884
2885 virtual bool IsThreadSuspendedOrHijacked(ICorDebugThread * pThread) = 0;
2886};
2887
2888
2889// entry for the array of connections in EnumerateConnectionsData
2890struct EnumerateConnectionsEntry
2891{
2892public:
2893 StringCopyHolder m_pName; // name of the connection
2894 DWORD m_dwID; // ID of the connection
2895};
2896
2897// data structure used in the callback for enumerating connections (code:CordbProcess::QueueFakeConnectionEvents)
2898struct EnumerateConnectionsData
2899{
2900public:
2901 ~EnumerateConnectionsData()
2902 {
2903 if (m_pEntryArray != NULL)
2904 {
2905 delete [] m_pEntryArray;
2906 m_pEntryArray = NULL;
2907 }
2908 }
2909
2910 CordbProcess * m_pThis; // the "this" process
2911 EnumerateConnectionsEntry * m_pEntryArray; // an array of connections to be filled in
2912 UINT32 m_uIndex; // the next entry in the array to be filled
2913};
2914
2915// data structure used in the callback for asserting that an appdomain has been deleted
2916// (code:CordbProcess::DbgAssertAppDomainDeleted)
2917struct DbgAssertAppDomainDeletedData
2918{
2919public:
2920 CordbProcess * m_pThis;
2921 VMPTR_AppDomain m_vmAppDomainDeleted;
2922};
2923
2924class CordbProcess :
2925 public CordbBase,
2926 public ICorDebugProcess,
2927 public ICorDebugProcess2,
2928 public ICorDebugProcess3,
2929 public ICorDebugProcess4,
2930 public ICorDebugProcess5,
2931 public ICorDebugProcess7,
2932 public ICorDebugProcess8,
2933 public ICorDebugProcess10,
2934 public IDacDbiInterface::IAllocator,
2935 public IDacDbiInterface::IMetaDataLookup,
2936 public IProcessShimHooks
2937#ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
2938 , public ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly
2939#endif
2940{
2941 // Ctor is private. Use OpenVirtualProcess instead.
2942 CordbProcess(ULONG64 clrInstanceId, IUnknown * pDataTarget, HMODULE hDacModule, Cordb * pCordb, const ProcessDescriptor * pProcessDescriptor, ShimProcess * pShim);
2943
2944public:
2945
2946 virtual ~CordbProcess();
2947 virtual void Neuter();
2948
2949 // Neuter left-side resources for all children
2950 void NeuterChildrenLeftSideResources();
2951
2952 // Neuter all of all children, but not the actual process object.
2953 void NeuterChildren();
2954
2955
2956 // The way to instantiate a new CordbProcess object.
2957 // @dbgtodo managed pipeline - this is not fully active in all scenarios yet.
2958 static HRESULT OpenVirtualProcess(ULONG64 clrInstanceId,
2959 IUnknown * pDataTarget,
2960 HMODULE hDacModule,
2961 Cordb * pCordb,
2962 const ProcessDescriptor * pProcessDescriptor,
2963 ShimProcess * pShim,
2964 CordbProcess ** ppProcess);
2965
2966 // Helper function to determine whether this ICorDebug is compatibile with a debugger
2967 // designed for the specified major version
2968 static bool IsCompatibleWith(DWORD clrMajorVersion);
2969
2970 //-----------------------------------------------------------
2971 // IMetaDataLookup
2972 // -----------------------------------------------------------
2973 IMDInternalImport * LookupMetaData(VMPTR_PEFile vmPEFile, bool &isILMetaDataForNGENImage);
2974
2975 // Helper functions for LookupMetaData implementation
2976 IMDInternalImport * LookupMetaDataFromDebugger(VMPTR_PEFile vmPEFile,
2977 bool &isILMetaDataForNGENImage,
2978 CordbModule * pModule);
2979
2980 IMDInternalImport * LookupMetaDataFromDebuggerForSingleFile(CordbModule * pModule,
2981 LPCWSTR pwszImagePath,
2982 DWORD dwTimeStamp,
2983 DWORD dwImageSize);
2984
2985
2986 //-----------------------------------------------------------
2987 // IDacDbiInterface::IAllocator
2988 //-----------------------------------------------------------
2989
2990 void * Alloc(SIZE_T lenBytes);
2991 void Free(void * p);
2992
2993#ifdef _DEBUG
2994 virtual const char * DbgGetName() { return "CordbProcess"; }
2995#endif
2996
2997 //-----------------------------------------------------------
2998 // IUnknown
2999 //-----------------------------------------------------------
3000
3001 ULONG STDMETHODCALLTYPE AddRef()
3002 {
3003 return BaseAddRefEnforceExternal();
3004 }
3005 ULONG STDMETHODCALLTYPE Release()
3006 {
3007 return BaseReleaseEnforceExternal();
3008 }
3009 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
3010
3011 //-----------------------------------------------------------
3012 // ICorDebugController
3013 //-----------------------------------------------------------
3014
3015 COM_METHOD Stop(DWORD dwTimeout);
3016 COM_METHOD Deprecated_Continue();
3017 COM_METHOD IsRunning(BOOL *pbRunning);
3018 COM_METHOD HasQueuedCallbacks(ICorDebugThread *pThread, BOOL *pbQueued);
3019 COM_METHOD EnumerateThreads(ICorDebugThreadEnum **ppThreads);
3020 COM_METHOD SetAllThreadsDebugState(CorDebugThreadState state,
3021 ICorDebugThread *pExceptThisThread);
3022 COM_METHOD Detach();
3023 COM_METHOD Terminate(unsigned int exitCode);
3024
3025 COM_METHOD CanCommitChanges(
3026 ULONG cSnapshots,
3027 ICorDebugEditAndContinueSnapshot *pSnapshots[],
3028 ICorDebugErrorInfoEnum **pError);
3029
3030 COM_METHOD CommitChanges(
3031 ULONG cSnapshots,
3032 ICorDebugEditAndContinueSnapshot *pSnapshots[],
3033 ICorDebugErrorInfoEnum **pError);
3034
3035 COM_METHOD Continue(BOOL fIsOutOfBand);
3036 COM_METHOD ThreadForFiberCookie(DWORD fiberCookie,
3037 ICorDebugThread **ppThread);
3038 COM_METHOD GetHelperThreadID(DWORD *pThreadID);
3039
3040 //-----------------------------------------------------------
3041 // ICorDebugProcess
3042 //-----------------------------------------------------------
3043
3044 COM_METHOD GetID(DWORD *pdwProcessId);
3045 COM_METHOD GetHandle(HANDLE *phProcessHandle);
3046 COM_METHOD EnableSynchronization(BOOL bEnableSynchronization);
3047 COM_METHOD GetThread(DWORD dwThreadId, ICorDebugThread **ppThread);
3048 COM_METHOD EnumerateBreakpoints(ICorDebugBreakpointEnum **ppBreakpoints);
3049 COM_METHOD EnumerateSteppers(ICorDebugStepperEnum **ppSteppers);
3050 COM_METHOD EnumerateObjects(ICorDebugObjectEnum **ppObjects);
3051 COM_METHOD IsTransitionStub(CORDB_ADDRESS address, BOOL *pbTransitionStub);
3052 COM_METHOD EnumerateModules(ICorDebugModuleEnum **ppModules);
3053 COM_METHOD GetModuleFromMetaDataInterface(IUnknown *pIMetaData,
3054 ICorDebugModule **ppModule);
3055 COM_METHOD SetStopState(DWORD threadID, CorDebugThreadState state);
3056 COM_METHOD IsOSSuspended(DWORD threadID, BOOL *pbSuspended);
3057 COM_METHOD GetThreadContext(DWORD threadID, ULONG32 contextSize,
3058 BYTE context[]);
3059 COM_METHOD SetThreadContext(DWORD threadID, ULONG32 contextSize,
3060 BYTE context[]);
3061 COM_METHOD ReadMemory(CORDB_ADDRESS address, DWORD size, BYTE buffer[],
3062 SIZE_T *read);
3063 COM_METHOD WriteMemory(CORDB_ADDRESS address, DWORD size, BYTE buffer[],
3064 SIZE_T *written);
3065
3066 COM_METHOD ClearCurrentException(DWORD threadID);
3067
3068 /*
3069 * EnableLogMessages enables/disables sending of log messages to the
3070 * debugger for logging.
3071 */
3072 COM_METHOD EnableLogMessages(BOOL fOnOff);
3073
3074 /*
3075 * ModifyLogSwitch modifies the specified switch's severity level.
3076 */
3077 COM_METHOD ModifyLogSwitch(__in_z WCHAR *pLogSwitchName, LONG lLevel);
3078
3079 COM_METHOD EnumerateAppDomains(ICorDebugAppDomainEnum **ppAppDomains);
3080 COM_METHOD GetObject(ICorDebugValue **ppObject);
3081
3082 //-----------------------------------------------------------
3083 // ICorDebugProcess2
3084 //-----------------------------------------------------------
3085
3086 COM_METHOD GetThreadForTaskID(TASKID taskId, ICorDebugThread2 ** ppThread);
3087 COM_METHOD GetVersion(COR_VERSION* pInfo);
3088
3089 COM_METHOD SetUnmanagedBreakpoint(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen);
3090 COM_METHOD ClearUnmanagedBreakpoint(CORDB_ADDRESS address);
3091 COM_METHOD GetCodeAtAddress(CORDB_ADDRESS address, ICorDebugCode ** pCode, ULONG32 * offset);
3092
3093 COM_METHOD SetDesiredNGENCompilerFlags(DWORD pdwFlags);
3094 COM_METHOD GetDesiredNGENCompilerFlags(DWORD *pdwFlags );
3095
3096 COM_METHOD GetReferenceValueFromGCHandle(UINT_PTR handle, ICorDebugReferenceValue **pOutValue);
3097
3098 //-----------------------------------------------------------
3099 // ICorDebugProcess3
3100 //-----------------------------------------------------------
3101
3102 // enables or disables CustomNotifications of a given type
3103 COM_METHOD SetEnableCustomNotification(ICorDebugClass * pClass, BOOL fEnable);
3104
3105 //-----------------------------------------------------------
3106 // ICorDebugProcess4
3107 //-----------------------------------------------------------
3108 COM_METHOD Filter(
3109 const BYTE pRecord[],
3110 DWORD countBytes,
3111 CorDebugRecordFormat format,
3112 DWORD dwFlags,
3113 DWORD dwThreadId,
3114 ICorDebugManagedCallback *pCallback,
3115 DWORD * pContinueStatus);
3116
3117 COM_METHOD ProcessStateChanged(CorDebugStateChange eChange);
3118
3119 //-----------------------------------------------------------
3120 // ICorDebugProcess5
3121 //-----------------------------------------------------------
3122 COM_METHOD GetGCHeapInformation(COR_HEAPINFO *pHeapInfo);
3123 COM_METHOD EnumerateHeap(ICorDebugHeapEnum **ppObjects);
3124 COM_METHOD EnumerateHeapRegions(ICorDebugHeapSegmentEnum **ppRegions);
3125 COM_METHOD GetObject(CORDB_ADDRESS addr, ICorDebugObjectValue **pObject);
3126 COM_METHOD EnableNGENPolicy(CorDebugNGENPolicy ePolicy);
3127 COM_METHOD EnumerateGCReferences(BOOL enumerateWeakReferences, ICorDebugGCReferenceEnum **ppEnum);
3128 COM_METHOD EnumerateHandles(CorGCReferenceType types, ICorDebugGCReferenceEnum **ppEnum);
3129 COM_METHOD GetTypeID(CORDB_ADDRESS obj, COR_TYPEID *pId);
3130 COM_METHOD GetTypeForTypeID(COR_TYPEID id, ICorDebugType **ppType);
3131 COM_METHOD GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout);
3132 COM_METHOD GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout);
3133 COM_METHOD GetTypeFields(COR_TYPEID id, ULONG32 celt, COR_FIELD fields[], ULONG32 *pceltNeeded);
3134
3135 //-----------------------------------------------------------
3136 // ICorDebugProcess7
3137 //-----------------------------------------------------------
3138 COM_METHOD SetWriteableMetadataUpdateMode(WriteableMetadataUpdateMode flags);
3139
3140 //-----------------------------------------------------------
3141 // ICorDebugProcess8
3142 //-----------------------------------------------------------
3143 COM_METHOD EnableExceptionCallbacksOutsideOfMyCode(BOOL enableExceptionsOutsideOfJMC);
3144
3145 //-----------------------------------------------------------
3146 // ICorDebugProcess10
3147 //-----------------------------------------------------------
3148 COM_METHOD EnableGCNotificationEvents(BOOL fEnable);
3149
3150#ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
3151 // ---------------------------------------------------------------
3152 // ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly
3153 // ---------------------------------------------------------------
3154
3155 COM_METHOD InvokePauseCallback();
3156 COM_METHOD InvokeResumeCallback();
3157
3158#endif
3159
3160 //-----------------------------------------------------------
3161 // Methods not exposed via a COM interface.
3162 //-----------------------------------------------------------
3163
3164 HRESULT ContinueInternal(BOOL fIsOutOfBand);
3165 HRESULT StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainToken);
3166
3167 // Sets an unmanaged breakpoint at the target address
3168 HRESULT SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen);
3169
3170 // Allocate a buffer within the target and return the range. Throws on error.
3171 TargetBuffer GetRemoteBuffer(ULONG cbBuffer); // throws
3172
3173 // Same as above except also copy-in the contents of a RS buffer using WriteProcessMemory
3174 HRESULT GetAndWriteRemoteBuffer(CordbAppDomain *pDomain, unsigned int bufferSize, const void *bufferFrom, void **ppBuffer);
3175
3176 /*
3177 * This will release a previously allocated left side buffer.
3178 * Often they are deallocated by the LS itself.
3179 */
3180 HRESULT ReleaseRemoteBuffer(void **ppBuffer);
3181
3182
3183 void TargetConsistencyCheck(bool fExpression);
3184
3185 // Activate interop-debugging, after the process has initially been Init()
3186 void EnableInteropDebugging();
3187
3188 HRESULT Init();
3189 void DeleteQueuedEvents();
3190 void CleanupHalfBakedLeftSide();
3191 void Terminating(BOOL fDetach);
3192
3193 CordbThread * TryLookupThread(VMPTR_Thread vmThread);
3194 CordbThread * TryLookupOrCreateThreadByVolatileOSId(DWORD dwThreadId);
3195 CordbThread * TryLookupThreadByVolatileOSId(DWORD dwThreadId);
3196 CordbThread * LookupOrCreateThread(VMPTR_Thread vmThread);
3197
3198 void QueueManagedAttachIfNeeded();
3199 void QueueManagedAttachIfNeededWorker();
3200 HRESULT QueueManagedAttach();
3201
3202 void DetachShim();
3203
3204 // Flush for when the process is running.
3205 void FlushProcessRunning();
3206
3207 // Flush all state.
3208 void FlushAll();
3209
3210 BOOL HijackThreadForUnhandledExceptionIfNeeded(DWORD dwThreadId);
3211
3212 // Filter a CLR notification (subset of exceptions).
3213 void FilterClrNotification(
3214 DebuggerIPCEvent * pManagedEvent,
3215 RSLockHolder * pLockHolder,
3216 ICorDebugManagedCallback * pCallback);
3217
3218 // Wrapper to invoke IClrDataTarget4::ContinueStatusChanged
3219 void ContinueStatusChanged(DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus);
3220
3221
3222 // Request a synchronization to occur after a debug event is dispatched.
3223 void RequestSyncAtEvent();
3224
3225 //
3226 // Basic managed event plumbing
3227 //
3228
3229 // This is called on the first IPC event from the debuggee. It initializes state.
3230 void FinishInitializeIPCChannel();
3231 void FinishInitializeIPCChannelWorker();
3232
3233 // This is called on each IPC event from the debuggee.
3234 void HandleRCEvent(DebuggerIPCEvent * pManagedEvent, RSLockHolder * pLockHolder, ICorDebugManagedCallback * pCallback);
3235
3236 // Queue the RC event.
3237 void QueueRCEvent(DebuggerIPCEvent * pManagedEvent);
3238
3239 // This marshals a managed debug event from the
3240 void MarshalManagedEvent(DebuggerIPCEvent * pManagedEvent);
3241
3242 // This copies a managed debug event from the IPC block and to pManagedEvent.
3243 // The event still needs to be marshalled.
3244 void CopyRCEventFromIPCBlock(DebuggerIPCEvent * pManagedEvent);
3245
3246 // This copies a managed debug event out of the Native-Debug event envelope.
3247 // The event still needs to be marshalled.
3248 bool CopyManagedEventFromTarget(const EXCEPTION_RECORD * pRecord, DebuggerIPCEvent * pLocalManagedEvent);
3249
3250 // Helper for Filter() to verify parameters and return a type-safe exception record.
3251 const EXCEPTION_RECORD * ValidateExceptionRecord(
3252 const BYTE pRawRecord[],
3253 DWORD countBytes,
3254 CorDebugRecordFormat format);
3255
3256 // Helper to read a structure from the target.
3257 template<typename T>
3258 HRESULT SafeReadStruct(CORDB_ADDRESS pRemotePtr, T* pLocalBuffer);
3259
3260 // Helper to write a structure into the target.
3261 template<typename T>
3262 HRESULT SafeWriteStruct(CORDB_ADDRESS pRemotePtr, const T* pLocalBuffer);
3263
3264 // Reads a buffer from the target
3265 HRESULT SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer, BOOL throwOnError = TRUE);
3266
3267 // Writes a buffer to the target
3268 void SafeWriteBuffer(TargetBuffer tb, const BYTE * pLocalBuffer);
3269
3270#if defined(FEATURE_INTEROP_DEBUGGING)
3271 void DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle);
3272#endif // FEATURE_INTEROP_DEBUGGING
3273
3274 bool IsThreadSuspendedOrHijacked(ICorDebugThread * pICorDebugThread);
3275
3276 // Helper to get ProcessDescriptor internally.
3277 const ProcessDescriptor* GetProcessDescriptor();
3278
3279 HRESULT GetRuntimeOffsets();
3280
3281 // Are we blocked waiting fo ran OOB event to be continue?
3282 bool IsWaitingForOOBEvent()
3283 {
3284#ifdef FEATURE_INTEROP_DEBUGGING
3285 return m_outOfBandEventQueue != NULL;
3286#else
3287 // If no interop, then we're never waiting for an OOB event.
3288 return false;
3289#endif
3290 }
3291
3292 //
3293 // Shim callbacks to simulate fake attach events.
3294 //
3295
3296
3297 // Callback for Shim to get the assemblies in load order
3298 void GetAssembliesInLoadOrder(
3299 ICorDebugAppDomain * pAppDomain,
3300 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
3301 ULONG countAssemblies);
3302
3303 // Callback for Shim to get the modules in load order
3304 void GetModulesInLoadOrder(
3305 ICorDebugAssembly * pAssembly,
3306 RSExtSmartPtr<ICorDebugModule>* pModules,
3307 ULONG countModules);
3308
3309 // Functions to queue fake Connection events on attach.
3310 static void CountConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData);
3311 static void EnumerateConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData);
3312 void QueueFakeConnectionEvents();
3313
3314
3315
3316 void DispatchRCEvent();
3317
3318 // Dispatch a single event via the callbacks.
3319 void RawDispatchEvent(
3320 DebuggerIPCEvent * pEvent,
3321 RSLockHolder * pLockHolder,
3322 ICorDebugManagedCallback * pCallback1,
3323 ICorDebugManagedCallback2 * pCallback2,
3324 ICorDebugManagedCallback3 * pCallback3,
3325 ICorDebugManagedCallback4 * pCallback4);
3326
3327 void MarkAllThreadsDirty();
3328
3329 bool CheckIfLSExited();
3330
3331 void Lock()
3332 {
3333 // Lock Hierarchy - shouldn't have List lock when taking/release the process lock.
3334
3335 m_processMutex.Lock();
3336 LOG((LF_CORDB, LL_EVERYTHING, "P::Lock enter, this=0x%p\n", this));
3337 }
3338
3339 void Unlock()
3340 {
3341 // Lock Hierarchy - shouldn't have List lock when taking/releasing the process lock.
3342
3343 LOG((LF_CORDB, LL_EVERYTHING, "P::Lock leave, this=0x%p\n", this));
3344 m_processMutex.Unlock();
3345 }
3346
3347#ifdef _DEBUG
3348 bool ThreadHoldsProcessLock()
3349 {
3350 return m_processMutex.HasLock();
3351 }
3352#endif
3353
3354 // Expose the process lock.
3355 // This is the main lock in V3.
3356 RSLock * GetProcessLock()
3357 {
3358 return &m_processMutex;
3359 }
3360
3361
3362 // @dbgtodo synchronization - the SG lock goes away in V3.
3363 // Expose the stop-go lock b/c varios Cordb objects in our process tree may need to take it.
3364 RSLock * GetStopGoLock()
3365 {
3366 return &m_StopGoLock;
3367 }
3368
3369
3370 void UnrecoverableError(HRESULT errorHR,
3371 unsigned int errorCode,
3372 const char *errorFile,
3373 unsigned int errorLine);
3374 HRESULT CheckForUnrecoverableError();
3375 void VerifyControlBlock();
3376
3377 // The implementation of EnumerateThreads without the public API error checks
3378 VOID InternalEnumerateThreads(RSInitHolder<CordbHashTableEnum> * ppThreads);
3379
3380 //-----------------------------------------------------------
3381 // Convenience routines
3382 //-----------------------------------------------------------
3383
3384 // Is it safe to send events to the LS?
3385 bool IsSafeToSendEvents() { return !m_unrecoverableError && !m_terminated && !m_detached; }
3386
3387 bool IsWin32EventThread();
3388
3389 void HandleSyncCompleteRecieved();
3390
3391 // Send a truly asynchronous IPC event.
3392 void SendAsyncIPCEvent(DebuggerIPCEventType t);
3393
3394 HRESULT SendIPCEvent(DebuggerIPCEvent *event, SIZE_T eventSize)
3395 {
3396 // @dbgtodo - eventually remove this when all IPC events are gone.
3397 // In V3 paths, we can't send IPC events.
3398 if (GetShim() == NULL)
3399 {
3400 STRESS_LOG1(LF_CORDB, LL_INFO1000, "!! Can't send IPC event in V3. %s", IPCENames::GetName(event->type));
3401 return E_NOTIMPL;
3402 }
3403 _ASSERTE(m_cordb != NULL);
3404 return (m_cordb->SendIPCEvent(this, event, eventSize));
3405 }
3406
3407 void InitAsyncIPCEvent(DebuggerIPCEvent *ipce,
3408 DebuggerIPCEventType type,
3409 VMPTR_AppDomain vmAppDomain)
3410 {
3411 // Async events only allowed for the following:
3412 _ASSERTE(type == DB_IPCE_ATTACHING);
3413
3414 InitIPCEvent(ipce, type, false, vmAppDomain);
3415 ipce->asyncSend = true;
3416 }
3417
3418 void InitIPCEvent(DebuggerIPCEvent *ipce,
3419 DebuggerIPCEventType type,
3420 bool twoWay,
3421 VMPTR_AppDomain vmAppDomain
3422 )
3423 {
3424 // zero out the event in case we try and use any uninitialized fields
3425 memset( ipce, 0, sizeof(DebuggerIPCEvent) );
3426
3427 _ASSERTE((!vmAppDomain.IsNull()) ||
3428 type == DB_IPCE_GET_GCHANDLE_INFO ||
3429 type == DB_IPCE_ENABLE_LOG_MESSAGES ||
3430 type == DB_IPCE_MODIFY_LOGSWITCH ||
3431 type == DB_IPCE_ASYNC_BREAK ||
3432 type == DB_IPCE_CONTINUE ||
3433 type == DB_IPCE_GET_BUFFER ||
3434 type == DB_IPCE_RELEASE_BUFFER ||
3435 type == DB_IPCE_IS_TRANSITION_STUB ||
3436 type == DB_IPCE_ATTACHING ||
3437 type == DB_IPCE_APPLY_CHANGES ||
3438 type == DB_IPCE_CONTROL_C_EVENT_RESULT ||
3439 type == DB_IPCE_SET_REFERENCE ||
3440 type == DB_IPCE_SET_ALL_DEBUG_STATE ||
3441 type == DB_IPCE_GET_THREAD_FOR_TASKID ||
3442 type == DB_IPCE_DETACH_FROM_PROCESS ||
3443 type == DB_IPCE_INTERCEPT_EXCEPTION ||
3444 type == DB_IPCE_GET_NGEN_COMPILER_FLAGS ||
3445 type == DB_IPCE_SET_NGEN_COMPILER_FLAGS ||
3446 type == DB_IPCE_SET_VALUE_CLASS);
3447
3448 ipce->type = type;
3449 ipce->hr = S_OK;
3450 ipce->processId = 0;
3451 ipce->vmAppDomain = vmAppDomain;
3452 ipce->vmThread = VMPTR_Thread::NullPtr();
3453 ipce->replyRequired = twoWay;
3454 ipce->asyncSend = false;
3455 ipce->next = NULL;
3456 }
3457
3458 // Looks up a previously constructed CordbClass instance without creating. May return NULL if the
3459 // CordbClass instance doesn't exist.
3460 CordbClass * LookupClass(ICorDebugAppDomain * pAppDomain, VMPTR_DomainFile vmDomainFile, mdTypeDef classToken);
3461
3462 CordbModule * LookupOrCreateModule(VMPTR_DomainFile vmDomainFile);
3463
3464#ifdef FEATURE_INTEROP_DEBUGGING
3465 CordbUnmanagedThread *GetUnmanagedThread(DWORD dwThreadId)
3466 {
3467 _ASSERTE(ThreadHoldsProcessLock());
3468 return m_unmanagedThreads.GetBase(dwThreadId);
3469 }
3470#endif // FEATURE_INTEROP_DEBUGGING
3471
3472 /*
3473 * This will cleanup the patch table, releasing memory,etc.
3474 */
3475 void ClearPatchTable();
3476
3477 /*
3478 * This will grab the patch table from the left side & go through
3479 * it to gather info needed for faster access. If address,size,buffer
3480 * are passed in, while going through the table we'll undo patches
3481 * in buffer at the same time
3482 */
3483 HRESULT RefreshPatchTable(CORDB_ADDRESS address = NULL, SIZE_T size = NULL, BYTE buffer[] = NULL);
3484
3485 // Find if a patch exists at a given address.
3486 HRESULT FindPatchByAddress(CORDB_ADDRESS address, bool *patchFound, bool *patchIsUnmanaged);
3487
3488 enum AB_MODE
3489 {
3490 AB_READ,
3491 AB_WRITE
3492 };
3493
3494 /*
3495 * Once we've called RefreshPatchTable to get the patch table,
3496 * this routine will iterate through the patches & either apply
3497 * or unapply the patches to buffer. AB_READ => Replaces patches
3498 * in buffer with the original opcode, AB_WRTE => replace opcode
3499 * with breakpoint instruction, caller is responsible for
3500 * updating the patchtable back to the left side.
3501 *
3502 * <TODO>@todo Perf Instead of a copy, undo the changes
3503 * Since the 'buffer' arg is an [in] param, we're not supposed to
3504 * change it. If we do, we'll allocate & copy it to bufferCopy
3505 * (we'll also set *pbUpdatePatchTable to true), otherwise we
3506 * don't manipuldate bufferCopy (so passing a NULL in for
3507 * reading is fine).</TODO>
3508 */
3509 HRESULT AdjustBuffer(CORDB_ADDRESS address,
3510 SIZE_T size,
3511 BYTE buffer[],
3512 BYTE **bufferCopy,
3513 AB_MODE mode,
3514 BOOL *pbUpdatePatchTable = NULL);
3515
3516 /*
3517 * AdjustBuffer, above, doesn't actually update the local patch table
3518 * if asked to do a write. It stores the changes alongside the table,
3519 * and this will cause the changes to be written to the table (for
3520 * a range of left-side addresses
3521 */
3522 void CommitBufferAdjustments(CORDB_ADDRESS start,
3523 CORDB_ADDRESS end);
3524
3525 /*
3526 * Clear the stored changes, or they'll sit there until we
3527 * accidentally commit them
3528 */
3529 void ClearBufferAdjustments();
3530
3531
3532
3533
3534 //-----------------------------------------------------------
3535 // Accessors for key synchronization fields.
3536 //-----------------------------------------------------------
3537
3538 // If CAD is NULL, returns true if all appdomains (ie, the entire process)
3539 // is synchronized. Otherwise, returns true if the specified appdomain is
3540 // synch'd.
3541 bool GetSynchronized();
3542 void SetSynchronized(bool fSynch);
3543
3544 void IncStopCount();
3545 void DecStopCount();
3546
3547 // Gets the exact stop count. You need the Proecss lock for this.
3548 int GetStopCount();
3549
3550 // Just gets whether we're stopped or not (m_stopped > 0).
3551 // You only need the StopGo lock for this.
3552 // This is biases towards returning false.
3553 bool IsStopped();
3554
3555 bool GetSyncCompleteRecv();
3556 void SetSyncCompleteRecv(bool fSyncRecv);
3557
3558
3559 // Cordbg may not always continue during a callback; but we really shouldn't do meaningful
3560 // work after a callback has returned yet before they've called continue. Thus we may need
3561 // to remember some state at the time of dispatch so that we do stuff at continue.
3562 // Only example here is neutering... we'd like to Neuter an object X after the ExitX callback,
3563 // but we can't neuter it until Continue. So remember X when we dispatch, and neuter this at continue.
3564 // Use a smart ptr to keep it alive until we neuter it.
3565
3566 // Add objects to various neuter lists.
3567 // NeuterOnContinue is for all objects that can be neutered once we continue.
3568 // NeuterOnExit is for all objects that can survive continues (but are neutered on process shutdown).
3569 // If an object's external ref count goes to 0, it gets promoted to the NeuterOnContinue list.
3570 void AddToNeuterOnExitList(CordbBase *pObject);
3571 void AddToNeuterOnContinueList(CordbBase *pObject);
3572
3573 NeuterList * GetContinueNeuterList() { return &m_ContinueNeuterList; }
3574 NeuterList * GetExitNeuterList() { return &m_ExitNeuterList; }
3575
3576 void AddToLeftSideResourceCleanupList(CordbBase * pObject);
3577
3578 // Routines to read and write thread context records between the processes safely.
3579 HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, DT_CONTEXT * pCtx);
3580 HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, const DT_CONTEXT * pCtx);
3581
3582#ifdef FEATURE_INTEROP_DEBUGGING
3583 // Record a win32 event for debugging purposes.
3584 void DebugRecordWin32Event(const DEBUG_EVENT * pEvent, CordbUnmanagedThread * pUThread);
3585#endif // FEATURE_INTEROP_DEBUGGING
3586
3587 //-----------------------------------------------------------
3588 // Interop Helpers
3589 //-----------------------------------------------------------
3590
3591 // Get the DAC interface.
3592 IDacDbiInterface * GetDAC();
3593
3594 // Get the data-target, which provides access to the debuggee.
3595 ICorDebugDataTarget * GetDataTarget();
3596
3597 BOOL IsDacInitialized();
3598
3599 void ForceDacFlush();
3600
3601
3602#ifdef FEATURE_INTEROP_DEBUGGING
3603 // Deal with native debug events for the interop-debugging scenario.
3604 void HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEvent);
3605
3606 void ResumeHijackedThreads();
3607
3608 //@todo - We should try to make these all private
3609 CordbUnmanagedThread *HandleUnmanagedCreateThread(DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase);
3610
3611 HRESULT ContinueOOB();
3612 void QueueUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3613 void DequeueUnmanagedEvent(CordbUnmanagedThread *pUThread);
3614 void QueueOOBUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3615 void DequeueOOBUnmanagedEvent(CordbUnmanagedThread *pUThread);
3616 void DispatchUnmanagedInBandEvent();
3617 void DispatchUnmanagedOOBEvent();
3618 bool ExceptionIsFlare(DWORD exceptionCode, const void *exceptionAddress);
3619
3620 bool IsSpecialStackOverflowCase(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent);
3621
3622 HRESULT SuspendUnmanagedThreads();
3623 HRESULT ResumeUnmanagedThreads();
3624
3625 HRESULT HijackIBEvent(CordbUnmanagedEvent * pUnmanagedEvent);
3626
3627 BOOL HasUndispatchedNativeEvents();
3628 BOOL HasUserUncontinuedNativeEvents();
3629#endif // FEATURE_INTEROP_DEBUGGING
3630
3631 HRESULT StartSyncFromWin32Stop(BOOL * pfAsyncBreakSent);
3632
3633
3634 // For interop attach, we first do native, and then once Cordbg continues from
3635 // the loader-bp, we kick off the managed attach. This field remembers that
3636 // whether we need the managed attach.
3637 // @dbgtodo managed pipeline - hoist to shim.
3638 bool m_fDoDelayedManagedAttached;
3639
3640
3641
3642 // Table of CordbEval objects that we've sent over to the LS.
3643 // This is synced via the process lock.
3644 RsPtrTable<CordbEval> m_EvalTable;
3645
3646 void PrepopulateThreadsOrThrow();
3647
3648 // Lookup or create an appdomain.
3649 CordbAppDomain * LookupOrCreateAppDomain(VMPTR_AppDomain vmAppDomain);
3650
3651 // Get the shared app domain.
3652 CordbAppDomain * GetSharedAppDomain();
3653
3654 // Get metadata dispenser.
3655 IMetaDataDispenserEx * GetDispenser();
3656
3657 // Sets a bitfield reflecting the managed debugging state at the time of
3658 // the jit attach.
3659 HRESULT GetAttachStateFlags(CLR_DEBUGGING_PROCESS_FLAGS *pFlags);
3660
3661 HRESULT GetTypeForObject(CORDB_ADDRESS obj, CordbAppDomain* pAppDomainOverride, CordbType **ppType, CordbAppDomain **pAppDomain = NULL);
3662
3663 WriteableMetadataUpdateMode GetWriteableMetadataUpdateMode() { return m_writableMetadataUpdateMode; }
3664private:
3665
3666#ifdef _DEBUG
3667 // Assert that vmAppDomainDeleted doesn't show up in dac enumerations
3668 void DbgAssertAppDomainDeleted(VMPTR_AppDomain vmAppDomainDeleted);
3669
3670 // Callback helper for DbgAssertAppDomainDeleted.
3671 static void DbgAssertAppDomainDeletedCallback(VMPTR_AppDomain vmAppDomain, void * pUserData);
3672#endif // _DEBUG
3673
3674 static void ThreadEnumerationCallback(VMPTR_Thread vmThread, void * pUserData);
3675
3676
3677 // Callback for AppDomain enumeration
3678 static void AppDomainEnumerationCallback(VMPTR_AppDomain vmAppDomain, void * pUserData);
3679
3680 // Helper to create a new CordbAppDomain around the vmptr and cache it
3681 CordbAppDomain * CacheAppDomain(VMPTR_AppDomain vmAppDomain);
3682
3683 // Helper to traverse Appdomains in target and build up our cache.
3684 void PrepopulateAppDomainsOrThrow();
3685
3686
3687 void ProcessFirstLogMessage (DebuggerIPCEvent *event);
3688 void ProcessContinuedLogMessage (DebuggerIPCEvent *event);
3689
3690 void CloseIPCHandles();
3691 void UpdateThreadsForAdUnload( CordbAppDomain* pAppDomain );
3692
3693#ifdef FEATURE_INTEROP_DEBUGGING
3694 // Each win32 debug event needs to be triaged to get a Reaction.
3695 Reaction TriageBreakpoint(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3696 Reaction TriageSyncComplete();
3697 Reaction Triage1stChanceNonSpecial(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3698 Reaction TriageExcep1stChanceAndInit(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3699 Reaction TriageExcep2ndChanceAndInit(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3700 Reaction TriageWin32DebugEvent(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent);
3701#endif // FEATURE_INTEROP_DEBUGGING
3702
3703 //-----------------------------------------------------------
3704 // Data members
3705 //-----------------------------------------------------------
3706
3707public:
3708 RSSmartPtr<Cordb> m_cordb;
3709
3710private:
3711 // OS process handle to live process.
3712 // @dbgtodo - , Move this into the Shim. This should only be needed in the live-process
3713 // case. Get rid of this since it breaks the data-target abstraction.
3714 // For Mac debugging, this handle is of course not the real process handle. This is just a handle to
3715 // wait on for process termination.
3716 HANDLE m_handle;
3717
3718 // Process descriptor - holds PID and App group ID for Mac debugging
3719 ProcessDescriptor m_processDescriptor;
3720
3721public:
3722 // Wrapper to get the OS process handle. This is unsafe because it breaks the data-target abstraction.
3723 // The only things that need this should be calls to DuplicateHandle, and some shimming work.
3724 HANDLE UnsafeGetProcessHandle()
3725 {
3726 return m_handle;
3727 }
3728
3729 // Set when code:CordbProcess::Detach is called.
3730 // Public APIs can check this and return CORDBG_E_PROCESS_DETACHED.
3731 // @dbgtodo managed pipeline - really could merge this with neuter.
3732 bool m_detached;
3733
3734 // True if we code:CordbProcess::Stop is called before the managed CreateProcess event.
3735 // In this case, m_initialized is false, and we can't send an AsyncBreak event to the LS.
3736 // (since the LS isn't going to send a SyncComplete event back since the CLR isn't loaded/ready).
3737 // @dbgtodo managed pipeline - move into shim, along with Stop/Continue.
3738 bool m_uninitializedStop;
3739
3740
3741 // m_exiting is true if we know the LS is starting to exit (if the
3742 // RS is telling the LS to exit) or if we know the LS has already exited.
3743 bool m_exiting;
3744
3745
3746 // m_terminated can only be set to true if we know 100% the LS has exited (ie, somebody
3747 // waited on the LS process handle).
3748 bool m_terminated;
3749
3750 bool m_unrecoverableError;
3751
3752 bool m_specialDeferment;
3753 bool m_helperThreadDead; // flag used for interop
3754
3755 // This tracks if the loader breakpoint has been received during interop-debugging.
3756 // The Loader Breakpoint is an breakpoint event raised by the OS once the debugger is attached.
3757 // It comes in both Attach and Launch scenarios.
3758 // This is also used in fake-native debugging scenarios.
3759 bool m_loaderBPReceived;
3760
3761private:
3762
3763 // MetaData dispenser.
3764 RSExtSmartPtr<IMetaDataDispenserEx> m_pMetaDispenser;
3765
3766 //
3767 // Count of the number of outstanding CordbEvals in the process.
3768 //
3769 LONG m_cOutstandingEvals;
3770
3771 // Number of oustanding code:CordbHandleValue objects containing
3772 // Left-side resources. This can be used to tell if ICorDebug needs to
3773 // cleanup gc handles.
3774 LONG m_cOutstandingHandles;
3775
3776 // Pointer to the CordbModule instance that can currently change the Jit flags.
3777 // There can be at most one of these. It will represent a module that has just been loaded, before the
3778 // Continue is sent. See code:CordbProcess::RawDispatchEvent and code:CordbProcess::ContinueInternal.
3779 CordbModule * m_pModuleThatCanChangeJitFlags;
3780
3781public:
3782 LONG OutstandingEvalCount()
3783 {
3784 return m_cOutstandingEvals;
3785 }
3786
3787 void IncrementOutstandingEvalCount()
3788 {
3789 InterlockedIncrement(&m_cOutstandingEvals);
3790 }
3791
3792 void DecrementOutstandingEvalCount()
3793 {
3794 InterlockedDecrement(&m_cOutstandingEvals);
3795 }
3796
3797 LONG OutstandingHandles();
3798 void IncrementOutstandingHandles();
3799 void DecrementOutstandingHandles();
3800
3801 //
3802 // Is it OK to detach at this time
3803 //
3804 HRESULT IsReadyForDetach();
3805
3806
3807private:
3808 // This is a target pointer that uniquely identifies the runtime in the target.
3809 // This lets ICD discriminate between multiple CLRs within a single process.
3810 // On windows, this is the base-address of mscorwks.dll in the target.
3811 // If this is 0, then we have V2 semantics where there was only 1 CLR in the target.
3812 // In that case, we can lazily initialize it in code:CordbProcess::CopyManagedEventFromTarget.
3813 // This is just used for backwards compat.
3814 CORDB_ADDRESS m_clrInstanceId;
3815
3816 // List of things that get neutered on process exit and Continue respectively.
3817 NeuterList m_ExitNeuterList;
3818 NeuterList m_ContinueNeuterList;
3819
3820 // List of objects that hold resources into the left-side.
3821 // This is currently for funceval, which cleans up resources in code:CordbEval::SendCleanup.
3822 // @dbgtodo - , (func-eval feature crew): we can get rid of this
3823 // list if we make func-eval not hold resources after it's complete.
3824 LeftSideResourceCleanupList m_LeftSideResourceCleanupList;
3825
3826 // m_stopCount, m_synchronized, & m_syncCompleteReceived are key fields describing
3827 // the processes' sync status.
3828 DWORD m_stopCount;
3829
3830 // m_synchronized is the Debugger's view of SyncStatus. It will go high & low for each
3831 // callback. Continue() will set this to false.
3832 // This flag is true roughly from the time that we've dispatched a managed callback
3833 // until the time that it's continued.
3834 bool m_synchronized;
3835
3836 // m_syncCompleteReceived tells us if the runtime is _actually_ sychronized. It goes
3837 // high once we get a SyncComplete, and it goes low once we actually send the continue.
3838 // This is always set by the thread that receives the sync-complete. In interop, that's the w32et.
3839 // Thus this is the most accurate indication of wether the Debuggee is _actually_ synchronized or not.
3840 bool m_syncCompleteReceived;
3841
3842
3843 // Back pointer to Shim process. This is used for hooks back into the shim.
3844 // If this is Non-null, then we're emulating the V2 case. If this is NULL, then it's the real V3 pipeline.
3845 RSExtSmartPtr<ShimProcess> m_pShim;
3846
3847 CordbSafeHashTable<CordbThread> m_userThreads;
3848
3849public:
3850 ShimProcess* GetShim();
3851
3852 bool m_oddSync;
3853
3854
3855 void BuildThreadEnum(CordbBase * pOwnerObj, NeuterList * pOwnerList, RSInitHolder<CordbHashTableEnum> * pHolder);
3856
3857#ifdef FEATURE_INTEROP_DEBUGGING
3858 // List of unmanaged threads. This is only populated for interop-debugging.
3859 CordbSafeHashTable<CordbUnmanagedThread> m_unmanagedThreads;
3860#endif // FEATURE_INTEROP_DEBUGGING
3861
3862 CordbSafeHashTable<CordbAppDomain> m_appDomains;
3863
3864 CordbAppDomain * m_sharedAppDomain;
3865
3866 // Since a stepper can begin in one appdomain, and complete in another,
3867 // we put the hashtable here, rather than on specific appdomains.
3868 CordbSafeHashTable<CordbStepper> m_steppers;
3869
3870 // Used to figure out if we have to refresh any reference objects
3871 // on the left side. Gets incremented each time a continue is called, or
3872 // global debugee state is modified in some other way.
3873 UINT m_continueCounter;
3874
3875 // Used to track whether the DAC cache has been flushed.
3876 // We use this information to determine whether CordbStackWalk instances need to
3877 // be refreshed.
3878 UINT m_flushCounter;
3879
3880 // The DCB is essentially a buffer area used to temporarily hold information read from the debugger
3881 // control block residing on the LS helper thread. We make no assumptions about the validity of this
3882 // information over time, so before using a value from it on the RS, we will always update this buffer
3883 // with a call to UpdateRightSideDCB. This uses a ReadProcessMemory to get the current information from
3884 // the LS DCB.
3885 DebuggerIPCControlBlock * GetDCB() {return ((m_pEventChannel == NULL) ? NULL : m_pEventChannel->GetDCB());}
3886
3887
3888 DebuggerIPCRuntimeOffsets m_runtimeOffsets;
3889 HANDLE m_leftSideEventAvailable;
3890 HANDLE m_leftSideEventRead;
3891#if defined(FEATURE_INTEROP_DEBUGGING)
3892 HANDLE m_leftSideUnmanagedWaitEvent;
3893#endif // FEATURE_INTEROP_DEBUGGING
3894
3895
3896 // This becomes true when the RS receives its first managed event.
3897 // This goes false in shutdown cases.
3898 // If this is true, we can assume:
3899 // - the CLR is loaded.
3900 // - the IPC block is opened and initialized.
3901 // - DAC is initialized (see code:CordbProcess::IsDacInitialized)
3902 //
3903 // If this is false, we can assume:
3904 // - the CLR may not be loaded into the target process.
3905 // - We can't send IPC events to the LS (because we can't expect a response)
3906 //
3907 // Many APIs can check this bit and return CORDBG_E_NOTREADY if it's false.
3908 bool m_initialized;
3909
3910#ifdef _DEBUG
3911 void * m_pDBGLastIPCEventType;
3912#endif
3913
3914 bool m_stopRequested;
3915 HANDLE m_stopWaitEvent;
3916 RSLock m_processMutex;
3917
3918#ifdef FEATURE_INTEROP_DEBUGGING
3919 // The number of threads which are IsFirstChanceHijacked
3920 DWORD m_cFirstChanceHijackedThreads;
3921
3922 CordbUnmanagedEvent *m_unmanagedEventQueue;
3923 CordbUnmanagedEvent *m_lastQueuedUnmanagedEvent;
3924 CordbUnmanagedEvent *m_lastQueuedOOBEvent;
3925 CordbUnmanagedEvent *m_outOfBandEventQueue;
3926
3927 CordbUnmanagedEvent *m_lastDispatchedIBEvent;
3928 bool m_dispatchingUnmanagedEvent;
3929 bool m_dispatchingOOBEvent;
3930 bool m_doRealContinueAfterOOBBlock;
3931
3932 enum
3933 {
3934 PS_WIN32_STOPPED = 0x0001,
3935 PS_HIJACKS_IN_PLACE = 0x0002,
3936 PS_SOME_THREADS_SUSPENDED = 0x0004,
3937 PS_WIN32_ATTACHED = 0x0008,
3938 PS_WIN32_OUTOFBAND_STOPPED = 0x0010,
3939 };
3940
3941 unsigned int m_state;
3942#endif // FEATURE_INTEROP_DEBUGGING
3943
3944 // True if we're interop-debugging, else false.
3945 bool IsInteropDebugging();
3946
3947 DWORD m_helperThreadId; // helper thread ID calculated from sniffing from UM thread-create events.
3948
3949 // Is the given thread id a helper thread (real or worker?)
3950 bool IsHelperThreadWorked(DWORD tid);
3951
3952 //
3953 // We cache the LS patch table on the RS.
3954 //
3955
3956 // The array of entries. (The patchtable is a hash implemented as a single-array)
3957 // This array includes empty entries.
3958 // There is an auxillary bucket structure used to map hash codes to array indices.
3959 // We traverse the array, and we recognize an empty slot
3960 // if DebuggerControllerPatch::opcode == 0.
3961 // If we haven't gotten the table, then m_pPatchTable is NULL
3962 BYTE* m_pPatchTable;
3963
3964 // The number of entries (both used & unused) in m_pPatchTable.
3965 UINT m_cPatch;
3966
3967 // so we know where to write the changes patchtable back to
3968 // This has m_cPatch elements.
3969 BYTE *m_rgData;
3970
3971 // Cached value of iNext entries such that:
3972 // m_rgNextPatch[i] = ((DebuggerControllerPatch*)m_pPatchTable)[i]->iNext;
3973 // where 0 <= i < m_cPatch
3974 // This provides a linked list (via indices) to traverse the used entries of m_pPatchTable.
3975 // This has m_cPatch elements.
3976 ULONG *m_rgNextPatch;
3977
3978 // This has m_cPatch elements.
3979 PRD_TYPE *m_rgUncommitedOpcode;
3980
3981 // CORDB_ADDRESS's are UINT_PTR's (64 bit under _WIN64, 32 bit otherwise)
3982#if defined(DBG_TARGET_WIN64)
3983#define MAX_ADDRESS (_UI64_MAX)
3984#else
3985#define MAX_ADDRESS (ULONG_MAX)
3986#endif
3987#define MIN_ADDRESS (0x0)
3988 CORDB_ADDRESS m_minPatchAddr; //smallest patch in table
3989 CORDB_ADDRESS m_maxPatchAddr;
3990
3991 // <TODO>@todo port : if slots of CHashTable change, so should these</TODO>
3992#define DPT_TERMINATING_INDEX (UINT32_MAX)
3993 // Index into m_pPatchTable of the first patch (first used entry).
3994 ULONG m_iFirstPatch;
3995
3996 // Initializes the DAC
3997 void InitDac();
3998
3999 // copy new data from LS DCB to RS buffer
4000 void UpdateRightSideDCB();
4001
4002 // copy new data from RS DCB buffer to LS DCB
4003 void UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size);
4004
4005 // allocate and initialize the RS DCB buffer
4006 void GetEventBlock(BOOL * pfBlockExists);
4007
4008 IEventChannel * GetEventChannel();
4009
4010 bool SupportsVersion(CorDebugInterfaceVersion featureVersion);
4011
4012 void StartEventDispatch(DebuggerIPCEventType event);
4013 void FinishEventDispatch();
4014 bool AreDispatchingEvent();
4015
4016 HANDLE GetHelperThreadHandle() { return m_hHelperThread; }
4017
4018 CordbAppDomain* GetDefaultAppDomain() { return m_pDefaultAppDomain; }
4019
4020#ifdef FEATURE_INTEROP_DEBUGGING
4021 // Lookup if there's a native BP at the given address. Return NULL not found.
4022 NativePatch * GetNativePatch(const void * pAddress);
4023#endif // FEATURE_INTEROP_DEBUGGING
4024
4025 bool IsBreakOpcodeAtAddress(const void * address);
4026
4027private:
4028 //
4029 // handle to helper thread. Used for managed debugging.
4030 // Initialized only after we get the tid from the DCB.
4031 HANDLE m_hHelperThread;
4032
4033 DebuggerIPCEventType m_dispatchedEvent; // what event are we currently dispatching?
4034
4035 RSLock m_StopGoLock;
4036
4037 // Each process has exactly one Default AppDomain
4038 // @dbgtodo appdomain : We should try and simplify things by removing this.
4039 // At the moment it's necessary for CordbProcess::UpdateThreadsForAdUnload.
4040 CordbAppDomain* m_pDefaultAppDomain; // owned by m_appDomains
4041
4042#ifdef FEATURE_INTEROP_DEBUGGING
4043 // Helpers
4044 CordbUnmanagedThread * GetUnmanagedThreadFromEvent(const DEBUG_EVENT * pEvent);
4045#endif // FEATURE_INTEROP_DEBUGGING
4046
4047 // Ensure we have a CLR Instance ID to debug
4048 HRESULT EnsureClrInstanceIdSet();
4049
4050#ifdef FEATURE_INTEROP_DEBUGGING
4051 // // The full debug event is too large, so we just remember the important stuff.
4052 struct MiniDebugEvent
4053 {
4054 BYTE code; // event code from the debug event
4055 CordbUnmanagedThread * pUThread; // unmanaged thread this was on.
4056 // @todo - we should have some misc data.
4057 union
4058 {
4059 struct {
4060 void * pAddress; // address of an exception
4061 DWORD dwCode;
4062 } ExceptionData;
4063 struct {
4064 void * pBaseAddress; // for module load & unload
4065 } ModuleData;
4066 } u;
4067 };
4068
4069 // Group fields that are just used for debug support here.
4070 // Some are included even in retail builds to help debug retail failures.
4071 struct DebugSupport
4072 {
4073 // For debugging, we keep a rolling queue of the last N Win32 debug events.
4074 MiniDebugEvent m_DebugEventQueue[DEBUG_EVENTQUEUE_SIZE];
4075 int m_DebugEventQueueIdx;
4076 int m_TotalNativeEvents;
4077
4078 // Breakdown of different types of native events
4079 int m_TotalIB;
4080 int m_TotalOOB;
4081 int m_TotalCLR;
4082 } m_DbgSupport;
4083
4084 CUnorderedArray<NativePatch, 10> m_NativePatchList;
4085#endif // FEATURE_INTEROP_DEBUGGING
4086
4087 //
4088 // DAC
4089 //
4090
4091 // Try to initalize DAC, may fail
4092 BOOL TryInitializeDac();
4093
4094 // Expect DAC initialize to succeed.
4095 void InitializeDac();
4096
4097
4098 void CreateDacDbiInterface();
4099
4100 // Free DAC.
4101 void FreeDac();
4102
4103
4104 HModuleHolder m_hDacModule;
4105 RSExtSmartPtr<ICorDebugDataTarget> m_pDACDataTarget;
4106
4107 // The mutable version of the data target, or null if read-only
4108 RSExtSmartPtr<ICorDebugMutableDataTarget> m_pMutableDataTarget;
4109
4110 RSExtSmartPtr<ICorDebugMetaDataLocator> m_pMetaDataLocator;
4111
4112 IDacDbiInterface * m_pDacPrimitives;
4113
4114 IEventChannel * m_pEventChannel;
4115
4116 // If true, then we'll ASSERT if we detect the target is corrupt or inconsistent
4117 // This switch is for diagnostics purposes only and should always be false in retail builds.
4118 bool m_fAssertOnTargetInconsistency;
4119
4120 // When a successful attempt to read runtime offsets from LS occurs, this flag is set.
4121 bool m_runtimeOffsetsInitialized;
4122
4123 // controls how metadata updated in the target is handled
4124 WriteableMetadataUpdateMode m_writableMetadataUpdateMode;
4125
4126 COM_METHOD GetObjectInternal(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, ICorDebugObjectValue **pObject);
4127};
4128
4129// Some IMDArocess APIs are supported as interop-only.
4130#define FAIL_IF_MANAGED_ONLY(pProcess) \
4131{ CordbProcess * __Proc = pProcess; if (!__Proc->IsInteropDebugging()) return CORDBG_E_MUST_BE_INTEROP_DEBUGGING; }
4132
4133
4134/* ------------------------------------------------------------------------- *
4135 * Module class
4136 * ------------------------------------------------------------------------- */
4137
4138class CordbModule : public CordbBase,
4139 public ICorDebugModule,
4140 public ICorDebugModule2,
4141 public ICorDebugModule3
4142{
4143public:
4144 CordbModule(CordbProcess * process,
4145 VMPTR_Module vmModule,
4146 VMPTR_DomainFile vmDomainFile);
4147
4148 virtual ~CordbModule();
4149 virtual void Neuter();
4150
4151 using CordbBase::GetProcess;
4152
4153#ifdef _DEBUG
4154 virtual const char * DbgGetName() { return "CordbModule"; }
4155#endif
4156
4157
4158 //-----------------------------------------------------------
4159 // IUnknown
4160 //-----------------------------------------------------------
4161
4162 ULONG STDMETHODCALLTYPE AddRef()
4163 {
4164 return (BaseAddRef());
4165 }
4166 ULONG STDMETHODCALLTYPE Release()
4167 {
4168 return (BaseRelease());
4169 }
4170 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4171
4172 //-----------------------------------------------------------
4173 // ICorDebugModule
4174 //-----------------------------------------------------------
4175
4176 COM_METHOD GetProcess(ICorDebugProcess **ppProcess);
4177 COM_METHOD GetBaseAddress(CORDB_ADDRESS *pAddress);
4178 COM_METHOD GetAssembly(ICorDebugAssembly **ppAssembly);
4179 COM_METHOD GetName(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4180 COM_METHOD EnableJITDebugging(BOOL bTrackJITInfo, BOOL bAllowJitOpts);
4181 COM_METHOD EnableClassLoadCallbacks(BOOL bClassLoadCallbacks);
4182
4183 // Gets the latest version of a function given the methodDef token
4184 COM_METHOD GetFunctionFromToken(mdMethodDef methodDef,
4185 ICorDebugFunction **ppFunction);
4186 COM_METHOD GetFunctionFromRVA(CORDB_ADDRESS rva, ICorDebugFunction **ppFunction);
4187 COM_METHOD GetClassFromToken(mdTypeDef typeDef,
4188 ICorDebugClass **ppClass);
4189 COM_METHOD CreateBreakpoint(ICorDebugModuleBreakpoint **ppBreakpoint);
4190
4191 // Not implemented - legacy
4192 COM_METHOD GetEditAndContinueSnapshot(
4193 ICorDebugEditAndContinueSnapshot **ppEditAndContinueSnapshot);
4194
4195 COM_METHOD GetMetaDataInterface(REFIID riid, IUnknown **ppObj);
4196 COM_METHOD GetToken(mdModule *pToken);
4197 COM_METHOD IsDynamic(BOOL *pDynamic);
4198 COM_METHOD GetGlobalVariableValue(mdFieldDef fieldDef,
4199 ICorDebugValue **ppValue);
4200 COM_METHOD GetSize(ULONG32 *pcBytes);
4201 COM_METHOD IsInMemory(BOOL *pInMemory);
4202
4203 //-----------------------------------------------------------
4204 // ICorDebugModule2
4205 //-----------------------------------------------------------
4206 COM_METHOD SetJMCStatus(
4207 BOOL fIsUserCode,
4208 ULONG32 cOthers,
4209 mdToken others[]);
4210
4211 // Applies an EnC edit to the module
4212 COM_METHOD ApplyChanges(
4213 ULONG cbMetaData,
4214 BYTE pbMetaData[],
4215 ULONG cbIL,
4216 BYTE pbIL[]);
4217
4218 // Resolve an assembly given an AssemblyRef token. Note that
4219 // this will not trigger the loading of assembly. If assembly is not yet loaded,
4220 // this will return an CORDBG_E_CANNOT_RESOLVE_ASSEMBLY error
4221 COM_METHOD ResolveAssembly(mdToken tkAssemblyRef,
4222 ICorDebugAssembly **ppAssembly);
4223
4224 // Sets EnC and optimization flags
4225 COM_METHOD SetJITCompilerFlags(DWORD dwFlags);
4226
4227 // Gets EnC and optimization flags
4228 COM_METHOD GetJITCompilerFlags(DWORD *pdwFlags);
4229
4230 //-----------------------------------------------------------
4231 // ICorDebugModule3
4232 //-----------------------------------------------------------
4233 COM_METHOD CreateReaderForInMemorySymbols(REFIID riid,
4234 void** ppObj);
4235
4236 //-----------------------------------------------------------
4237 // Internal members
4238 //-----------------------------------------------------------
4239
4240#ifdef _DEBUG
4241 // Debug helper to ensure that module is no longer discoverable
4242 void DbgAssertModuleDeleted();
4243#endif // _DEBUG
4244
4245 // Internal help to get the "name" (filename or pretty name) of the module.
4246 HRESULT GetNameWorker(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4247
4248 // Marks that the module's metadata has become invalid and needs to be refetched.
4249 void RefreshMetaData();
4250
4251 // Cache the current continue counter as the one that the LoadEvent is
4252 // dispatched in.
4253 void SetLoadEventContinueMarker();
4254
4255 // Return CORDBG_E_MUST_BE_IN_LOAD_MODULE if this module is not in its load callback.
4256 HRESULT EnsureModuleIsInLoadCallback();
4257
4258 BOOL IsDynamic();
4259
4260 // Gets the latest version of the function for the methodDef, if any
4261 CordbFunction * LookupFunctionLatestVersion(mdMethodDef methodToken);
4262
4263 // Gets the latest version of the function. Creates a new instance if none exists yet.
4264 CordbFunction* LookupOrCreateFunctionLatestVersion(mdMethodDef funcMetaDataToken);
4265
4266 // Finds or creates a function for the first time (not for use on EnC if function doesn't exist yet)
4267 CordbFunction * LookupOrCreateFunction(mdMethodDef token, SIZE_T enCVersion);
4268
4269 // Creates an CordbFunction instances for the first time (not for use on EnC)
4270 CordbFunction * CreateFunction(mdMethodDef token, SIZE_T enCVersion);
4271
4272 // Creates a CordbFunction object to represent the specified EnC version
4273 HRESULT UpdateFunction(mdMethodDef token,
4274 SIZE_T newEnCVersion,
4275 CordbFunction** ppFunction);
4276
4277 CordbClass* LookupClass(mdTypeDef classToken);
4278 HRESULT LookupOrCreateClass(mdTypeDef classToken, CordbClass** ppClass);
4279 HRESULT CreateClass(mdTypeDef classToken, CordbClass** ppClass);
4280 HRESULT LookupClassByToken(mdTypeDef token, CordbClass **ppClass);
4281 HRESULT ResolveTypeRef(mdTypeRef token, CordbClass **ppClass);
4282 HRESULT ResolveTypeRefOrDef(mdToken token, CordbClass **ppClass);
4283
4284 // Sends the event to the left side to apply the changes to the debugee
4285 HRESULT ApplyChangesInternal(
4286 ULONG cbMetaData,
4287 BYTE pbMetaData[],
4288 ULONG cbIL,
4289 BYTE pbIL[]);
4290
4291 // Pulls new metadata if needed in order to ensure the availability of
4292 // the given token
4293 void UpdateMetaDataCacheIfNeeded(mdToken token);
4294
4295 HRESULT InitPublicMetaDataFromFile(const WCHAR * pszFullPathName, DWORD dwOpenFlags, bool validateFileInfo);
4296
4297 // Creates a CordbNativeCode (if it's not already created) and adds it to the
4298 // hash table of CordbNativeCodes belonging to the module.
4299 CordbNativeCode * LookupOrCreateNativeCode(mdMethodDef methodToken,
4300 VMPTR_MethodDesc methodDesc,
4301 CORDB_ADDRESS startAddress);
4302
4303private:
4304 // Set the metadata (both public and internal) for the module.
4305 void InitMetaData(TargetBuffer buffer, BOOL useFileMappingOptimization);
4306
4307 // Checks if the given token is in the cached metadata
4308 BOOL CheckIfTokenInMetaData(mdToken token);
4309
4310 // Update the public metadata given a buffer in the target.
4311 void UpdatePublicMetaDataFromRemote(TargetBuffer bufferRemoteMetaData);
4312
4313 // Initialize just the public metadata by reading from an on-disk module
4314 HRESULT InitPublicMetaDataFromFile();
4315 // Initialize just the public metadata by reading new metadata from the buffer
4316 void InitPublicMetaData(TargetBuffer buffer);
4317
4318 // Rebuild the internal metadata given the public one.
4319 void UpdateInternalMetaData();
4320
4321 // Determines whether the on-disk metadata for this module is usable as the
4322 // current metadata
4323 BOOL IsFileMetaDataValid();
4324
4325 // Helper to copy metadata buffer from the Target to the host.
4326 void CopyRemoteMetaData(TargetBuffer buffer, CoTaskMemHolder<VOID> * pLocalBuffer);
4327
4328
4329 CordbAssembly * ResolveAssemblyInternal(mdToken tkAssemblyRef);
4330
4331 BOOL IsWinMD();
4332
4333 //-----------------------------------------------------------
4334 // Convenience routines
4335 //-----------------------------------------------------------
4336
4337public:
4338 CordbAppDomain *GetAppDomain()
4339 {
4340 return m_pAppDomain;
4341 }
4342
4343 CordbAssembly * GetCordbAssembly ();
4344
4345 // Get the module filename, or NULL if none. Throws on error.
4346 const WCHAR * GetModulePath();
4347
4348 const WCHAR * GetNGenImagePath();
4349
4350 const VMPTR_DomainFile GetRuntimeDomainFile ()
4351 {
4352 return m_vmDomainFile;
4353 }
4354
4355 const VMPTR_Module GetRuntimeModule()
4356 {
4357 return m_vmModule;
4358 }
4359
4360 // Get symbol stream for in-memory modules.
4361 IDacDbiInterface::SymbolFormat GetInMemorySymbolStream(IStream ** ppStream);
4362
4363 // accessor for PE file
4364 VMPTR_PEFile GetPEFile();
4365
4366
4367 IMetaDataImport * GetMetaDataImporter();
4368
4369 // accessor for Internal MetaData importer.
4370 IMDInternalImport * GetInternalMD();
4371
4372 //-----------------------------------------------------------
4373 // Data members
4374 //-----------------------------------------------------------
4375
4376public:
4377 CordbAssembly* m_pAssembly;
4378 CordbAppDomain* m_pAppDomain;
4379 CordbSafeHashTable<CordbClass> m_classes;
4380
4381 // A collection, indexed by methodDef, of the latest version of functions in this module
4382 // The collection is filled lazily by LookupOrCreateFunction
4383 CordbSafeHashTable<CordbFunction> m_functions;
4384
4385 // The real handle into the VM for a module. This is appdomain aware.
4386 // This is the primary VM counterpart for the CordbModule.
4387 VMPTR_DomainFile m_vmDomainFile;
4388
4389 VMPTR_Module m_vmModule;
4390
4391 DWORD m_EnCCount;
4392
4393private:
4394
4395 enum ILWinMDState
4396 {
4397 Uninitialized,
4398 False,
4399 True
4400 };
4401
4402 // Base Address and size of this module in debuggee's process. Maybe null if unknown.
4403 TargetBuffer m_PEBuffer;
4404
4405 BOOL m_fDynamic; // Dynamic modules can grow (like Reflection Emit)
4406 BOOL m_fInMemory; // In memory modules don't have file-backing.
4407 ILWinMDState m_isIlWinMD; // WinMD modules don't support all metadata interfaces
4408
4409 // Indicates that the module must serialize its metadata in process as part of metadata
4410 // refresh. This is required for modules updated on the fly by the profiler
4411 BOOL m_fForceMetaDataSerialize;
4412
4413 // Full path to module's image, if any. Empty if none, NULL if not yet set.
4414 StringCopyHolder m_strModulePath;
4415
4416 // Full path to the ngen file. Empty if not ngenned, NULL if not yet set.
4417 // This isn't exposed publicly, but we may use it internally for loading metadata.
4418 StringCopyHolder m_strNGenImagePath;
4419
4420 // "Global" class for this module. Global functions + vars exist in this class.
4421 RSSmartPtr<CordbClass> m_pClass;
4422
4423 // Handle to PEFile, useful for metadata lookups.
4424 // this should always be non-null.
4425 VMPTR_PEFile m_vmPEFile;
4426
4427
4428 // Public metadata importer. This is lazily initialized and accessed from code:GetMetaDataImporter
4429 // This is handed out to debugger clients via code:CordbModule::GetMetaDataInterface
4430 // This is also tightly coupled to the internal metadata importer, m_pInternalMetaDataImport.
4431 RSExtSmartPtr<IMetaDataImport> m_pIMImport;
4432
4433 // Internal metadata object. This is closely tied to the public metadata object (m_pIMImport).
4434 // They share the same backing storage, but expose different interfaces to that storage.
4435 // Debugger authors and tools use the public interfaces.
4436 // DAC-ized operations in the VM require an IMDInternalImport.
4437 // The public and internal must be updated together.
4438 // This ultimately gets handed back to DAC via code:CordbProcess::LookupMetaData
4439 RSExtSmartPtr<IMDInternalImport> m_pInternalMetaDataImport;
4440
4441 // Continue counter of when the module was loaded.
4442 // See code:CordbModule::SetLoadEventContinueMarker for details
4443 UINT m_nLoadEventContinueCounter;
4444
4445 // This is a table of all NativeCode objects in the module indexed
4446 // by start address
4447 // The collection is filled lazily by LookupOrCreateNativeCode
4448 CordbSafeHashTable<CordbNativeCode> m_nativeCodeTable;
4449};
4450
4451
4452//-----------------------------------------------------------------------------
4453// Cordb MDA notification
4454//-----------------------------------------------------------------------------
4455class CordbMDA : public CordbBase, public ICorDebugMDA
4456{
4457public:
4458 CordbMDA(CordbProcess * pProc, DebuggerMDANotification * pData);
4459 ~CordbMDA();
4460
4461 virtual void Neuter();
4462
4463#ifdef _DEBUG
4464 virtual const char * DbgGetName() { return "CordbMDA"; }
4465#endif
4466
4467 //-----------------------------------------------------------
4468 // IUnknown
4469 //-----------------------------------------------------------
4470
4471 ULONG STDMETHODCALLTYPE AddRef()
4472 {
4473 return (BaseAddRefEnforceExternal());
4474 }
4475 ULONG STDMETHODCALLTYPE Release()
4476 {
4477 return (BaseReleaseEnforceExternal());
4478 }
4479 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4480
4481 //-----------------------------------------------------------
4482 // ICorDebugMDA
4483 //-----------------------------------------------------------
4484
4485 // Get the string for the type of the MDA. Never empty.
4486 // This is a convenient performant alternative to getting the XML stream and extracting
4487 // the type from that based off the schema.
4488 COM_METHOD GetName(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4489
4490 // Get a string description of the MDA. This may be empty (0-length).
4491 COM_METHOD GetDescription(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4492
4493 // Get the full associated XML for the MDA. This may be empty.
4494 // This could be a potentially expensive operation if the xml stream is large.
4495 // See the MDA documentation for the schema for this XML stream.
4496 COM_METHOD GetXML(ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
4497
4498 COM_METHOD GetFlags(CorDebugMDAFlags * pFlags);
4499
4500 // Thread that the MDA is fired on. We use the os tid instead of an ICDThread in case an MDA is fired on a
4501 // native thread (or a managed thread that hasn't yet entered managed code and so we don't have a ICDThread
4502 // object for it yet)
4503 COM_METHOD GetOSThreadId(DWORD * pOsTid);
4504
4505private:
4506 NewArrayHolder<WCHAR> m_szName;
4507 NewArrayHolder<WCHAR> m_szDescription;
4508 NewArrayHolder<WCHAR> m_szXml;
4509
4510 DWORD m_dwOSTID;
4511 CorDebugMDAFlags m_flags;
4512};
4513
4514
4515
4516struct CordbHangingField
4517{
4518 FREEHASHENTRY entry;
4519 FieldData data;
4520};
4521
4522// A hashtable for storing EnC hanging field information
4523// FieldData.m_fldMetadataToken is the key
4524class CordbHangingFieldTable : public CHashTableAndData<CNewDataNoThrow>
4525{
4526 private:
4527
4528 BOOL Cmp(SIZE_T k1, const HASHENTRY *pc2)
4529 {
4530 LIMITED_METHOD_CONTRACT;
4531 return (ULONG)(UINT_PTR)(k1) !=
4532 (reinterpret_cast<const CordbHangingField *>(pc2))->data.m_fldMetadataToken;
4533 }
4534
4535 ULONG HASH(mdFieldDef fldToken)
4536 {
4537 LIMITED_METHOD_CONTRACT;
4538 return fldToken;
4539 }
4540
4541 SIZE_T KEY(mdFieldDef fldToken)
4542 {
4543 return (SIZE_T)fldToken;
4544 }
4545
4546 public:
4547
4548#ifndef DACCESS_COMPILE
4549
4550 CordbHangingFieldTable() : CHashTableAndData<CNewDataNoThrow>(11)
4551 {
4552 NewInit(11, sizeof(CordbHangingField), 11);
4553 }
4554
4555 FieldData * AddFieldInfo(FieldData * pInfo)
4556 {
4557 _ASSERTE(pInfo != NULL);
4558
4559 CordbHangingField *pEntry = (CordbHangingField *)Add(HASH(pInfo->m_fldMetadataToken));
4560 pEntry->data = *pInfo; // copy everything over
4561
4562 // Return a pointer to the data
4563 return &(pEntry->data);
4564 }
4565
4566 void RemoveFieldInfo(mdFieldDef fldToken)
4567 {
4568 CordbHangingField *entry = (CordbHangingField*)Find(HASH(fldToken), KEY(fldToken));
4569 _ASSERTE(entry != NULL);
4570 Delete(HASH(fldToken), (HASHENTRY*)entry);
4571 }
4572
4573#endif // #ifndef DACCESS_COMPILE
4574
4575 FieldData * GetFieldInfo(mdFieldDef fldToken)
4576 {
4577 CordbHangingField * entry = (CordbHangingField *)Find(HASH(fldToken), KEY(fldToken));
4578 return (entry!=NULL?&(entry->data):NULL);
4579 }
4580};
4581
4582
4583/* ------------------------------------------------------------------------- *
4584 * Instantiation.
4585 *
4586 * This struct stores a set of type parameters. It is used in
4587 * the heap-allocated data structures CordbType and CordbNativeCode.
4588 *
4589 * CordbType::m_inst. Stores the class type parameters if any,
4590 * or the solitary array type parameter, or the solitary parameter
4591 * to a byref type.
4592 *
4593 * CordbJITILFrame::m_genericArgs. Stores exact generic parameters for the generic method frame if available
4594 * Need not be identicial if code is shared between generic instantiations.
4595 * May be inexact if real instantiation has been optimized away off
4596 * the frame (nb this gets reported by the left side)
4597 *
4598 * This is conceptually an array of Type-parameters, with the split (m_cClassTyPars) between
4599 * where the Type's type-parameters end and the Method's type-parameters begin.
4600 * ------------------------------------------------------------------------- */
4601class Instantiation
4602{
4603public:
4604 // Empty ctor
4605 Instantiation()
4606 : m_cInst(0), m_ppInst(NULL), m_cClassTyPars (0)
4607 { }
4608
4609 // Instantiation for Type. 0 Method type-parameters.
4610 Instantiation(unsigned int _cClassInst, CordbType **_ppClassInst)
4611 : m_cInst(_cClassInst), m_ppInst(_ppClassInst), m_cClassTyPars(_cClassInst)
4612 {LIMITED_METHOD_CONTRACT; }
4613
4614 // Instantiation for Type + Function.
4615 Instantiation(unsigned int _cInst, CordbType **_ppInst, unsigned int numClassTyPars)
4616 : m_cInst(_cInst), m_ppInst(_ppInst),
4617 m_cClassTyPars (numClassTyPars)
4618 { }
4619
4620 // Copy constructor.
4621 Instantiation(const Instantiation &inst)
4622 : m_cInst(inst.m_cInst), m_ppInst(inst.m_ppInst), m_cClassTyPars (inst.m_cClassTyPars)
4623 { }
4624
4625 // Number of elements in array pointed to by m_ppInst
4626 unsigned int m_cInst;
4627
4628 // Pointer to array of CordbType objects. Length of array is m_cInst.
4629 // Array is Class Type parameters followed by Function's Type parameters.
4630 // Eg, Instantiation for Class<Foo, Goo>::Func<Bar> would be {Foo, Goo, Bar}.
4631 // m_cInst = 3, m_cClassTyPars = 2.
4632 // In contrast, Instantiation for Class::Func<Foo, Goo, Bar> would have same
4633 // array, but m_cClassTyPars = 0.
4634 CordbType **m_ppInst;
4635
4636 // Track the split between Type vs. Method type-params.
4637 unsigned int m_cClassTyPars;
4638};
4639
4640//------------------------------------------------------------------------
4641// CordbType: replaces the use of signatures.
4642//
4643// Left Side & Right Side
4644// ---------------------------
4645// CordbTypes may come from either the Right Side (via being built up from
4646// ICorDebug), or from the Left-Side (being handed back from LS operations
4647// like getting the type from an Object the LS handed back).
4648// The RightSide CordbType corresponds to a Left-Side TypeHandle.
4649// CordbTypes are communicated across the LS/RS boundary by marshalling
4650// to BasicTypeData + ExpandedTypeData IPC events.
4651//
4652//
4653// Invariants on CordbType
4654// ---------------------------
4655//
4656// The m_elementType is NEVER ELEMENT_TYPE_VAR or ELEMENT_TYPE_MVAR or ELEMENT_TYPE_GENERICINST
4657// CordbTypes are always _ground_ types (fully instantiated generics or non-generic types). If
4658// they represent an instantiated type like List<int> then m_inst will be non-empty.
4659//
4660//
4661// !!!! The m_elementType is NEVER ELEMENT_TYPE_VALUETYPE !!!!
4662// !!!! To find out if it is a value type call CordbType::IsValueType() !!!!
4663//
4664// Where CordbTypes are stored
4665// ---------------------------
4666//
4667// Because we could have a significant number of different instantiations for a given templated type,
4668// we need an efficient way to store and retrieve the CordbType instances for these instantiations.
4669// For this reason, we use a tree-like scheme to hash-cons types. To implement this we use the following
4670// scheme:
4671// - CordbTypes are created for "partially instantiated" types,
4672// e.g. CordbTypes exist for "Dict" and "Dict<int>" even if the real
4673// type being manipulated by the user is "Dict<int,string>"
4674// - Subordinate types (E.g. Dict<int,string> is subordinate to Dict<int>,
4675// which is itself subordinate to the type for Dict) get stored
4676// in the m_spinetypes hash table of the parent type.
4677// - In m_spinetypes the pointers of the CordbTypes themselves
4678// are used for the unique ids for entries in the table.
4679// Note that CordbType instances that are created for "partially instantiated" types
4680// are never used for any purpose other than efficient hashing. Specifically, the debugger will
4681// never have reason to expose a partially instantiated type outside of the hashing algorithm.
4682//
4683// CordbTypes have object identity: if 2 CordbTypes represent the same type (in the same AppDomain),
4684// then they will be the same CordbType instance.
4685//
4686// Thus the representation for "Dict<class String,class Foo, class Foo* >" goes as follows:
4687// 1. Assume the type Foo is represented by CordbClass *5678x
4688// 1b. Assume the hashtable m_sharedtypes in the AppDomain maps E_T_STRING to the CordbType *0ABCx
4689// Assume m_type in class Foo (i.e. CordbClass *5678x) is the CordbType *0DEFx
4690// Assume m_type in class Foo maps E_T_PTR to the CordbType *0647x
4691// 2. The hash table m_spinetypes in "Dict" maps "0ABCx" to a new CordbType
4692// representing Dict<String> (a single type application)
4693// 3. The hash table m_spinetypes in this new CordbType maps "0DEFx" to a
4694// new CordbType representing Dict<class String,class Foo>
4695// 3. The hash table m_spinetypes in this new CordbType maps "0647" to a
4696// new CordbType representing Dict<class String,class Foo, class Foo*>
4697//
4698// This lets us reuse the existing hash table scheme to build
4699// up instantiated types of arbitrary size.
4700//
4701// Array types are similar, excpet that they start with a head type
4702// for the "type constructor", e.g. "_ []" is a type constructor with rank 1
4703// and m_elementType = ELEMENT_TYPE_SZARRAY. These head constructors are
4704// stored in the m_sharedtypes table in the appdomain. The actual instantiations
4705// of the array types are then subordinate types to the array constructor type.
4706//
4707// Other types are simpler, and have unique objects stored in the m_sharedtypes
4708// table in the appdomain. This table is indexed by CORDBTYPE_ID in RsType.cpp
4709//
4710//
4711// Memory Management of CordbTypes
4712// ---------------------------
4713// All CordbTypes are ultimately stored off the CordbAppDomain object.
4714// The most common place is in the AppDomain's neuter-list.
4715//
4716// See definition of ICorDebugType for further invariants on types.
4717//
4718
4719class CordbType : public CordbBase, public ICorDebugType, public ICorDebugType2
4720{
4721public:
4722 CordbType(CordbAppDomain *appdomain, CorElementType ty, unsigned int rank);
4723 CordbType(CordbAppDomain *appdomain, CorElementType ty, CordbClass *c);
4724 CordbType(CordbType *tycon, CordbType *tyarg);
4725 virtual ~CordbType();
4726 virtual void Neuter();
4727
4728#ifdef _DEBUG
4729 virtual const char * DbgGetName() { return "CordbType"; }
4730#endif
4731
4732 // If you want to force the init to happen even if we think the class
4733 // is up to date, set fForceInit to TRUE
4734 HRESULT Init(BOOL fForceInit);
4735
4736 //-----------------------------------------------------------
4737 // IUnknown
4738 //-----------------------------------------------------------
4739
4740 ULONG STDMETHODCALLTYPE AddRef();
4741 ULONG STDMETHODCALLTYPE Release();
4742 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4743
4744 //-----------------------------------------------------------
4745 // ICorDebugType
4746 //-----------------------------------------------------------
4747
4748 COM_METHOD GetType(CorElementType *ty);
4749 COM_METHOD GetClass(ICorDebugClass **ppClass);
4750 COM_METHOD EnumerateTypeParameters(ICorDebugTypeEnum **ppTyParEnum);
4751 COM_METHOD GetFirstTypeParameter(ICorDebugType **ppType);
4752 COM_METHOD GetBase(ICorDebugType **ppType);
4753 COM_METHOD GetStaticFieldValue(mdFieldDef fieldDef,
4754 ICorDebugFrame * pFrame,
4755 ICorDebugValue ** ppValue);
4756 COM_METHOD GetRank(ULONG32 *pnRank);
4757
4758 //-----------------------------------------------------------
4759 // ICorDebugType2
4760 //-----------------------------------------------------------
4761 COM_METHOD GetTypeID(COR_TYPEID *pId);
4762
4763 //-----------------------------------------------------------
4764 // Non-COM members
4765 //-----------------------------------------------------------
4766
4767 //-----------------------------------------------------------
4768 // Basic constructor operations for the algebra of types.
4769 // These all create unique objects within an AppDomain.
4770 //-----------------------------------------------------------
4771
4772 // This one is used to create simple types, e.g. int32, int64, typedbyref etc.
4773 static HRESULT MkType(CordbAppDomain * pAppDomain,
4774 CorElementType elementType,
4775 CordbType ** ppResultType);
4776
4777 // This one is used to create array, pointer and byref types
4778 static HRESULT MkType(CordbAppDomain * pAppDomain,
4779 CorElementType elementType,
4780 ULONG rank,
4781 CordbType * pType,
4782 CordbType ** ppResultType);
4783
4784 // This one is used to create function pointer types. et must be ELEMENT_TYPE_FNPTR
4785 static HRESULT MkType(CordbAppDomain * pAppDomain,
4786 CorElementType elementType,
4787 const Instantiation * pInst,
4788 CordbType ** ppResultType);
4789
4790 // This one is used to class and value class types, e.g. "class MyClass" or "class ArrayList<int>"
4791 static HRESULT MkType(CordbAppDomain * pAppDomain,
4792 CorElementType elementType,
4793 CordbClass * pClass,
4794 const Instantiation * pInst,
4795 CordbType ** ppResultType);
4796
4797 // Some derived constructors... Use this one if the type is definitely not
4798 // a paramterized type, e.g. to implement functions on the API where types cannot
4799 // be parameterized.
4800 static HRESULT MkUnparameterizedType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cl, CordbType **ppType);
4801
4802 //-----------------------------------------------------------
4803 // Basic destructor operations over the algebra
4804 //-----------------------------------------------------------
4805 void DestUnaryType(CordbType **pRes) ;
4806 void DestConstructedType(CordbClass **pClass, Instantiation *pInst);
4807 void DestNaryType(Instantiation *pInst);
4808
4809 CorElementType GetElementType() { return m_elementType; }
4810 VMPTR_DomainFile GetDomainFile();
4811 VMPTR_Module GetModule();
4812
4813 // If this is a ptr type, get the CordbType that it points to.
4814 // Eg, for CordbType("Int*"), returns CordbType("Int").
4815 // If not a ptr type, returns null.
4816 // Since it's all internal, no reference counting.
4817 // This is effectively a specialized version of DestUnaryType.
4818 CordbType * GetPointerElementType();
4819
4820
4821 // Create a type from metadata
4822 static HRESULT SigToType(CordbModule * pModule, SigParser * pSigParser, const Instantiation * pInst, CordbType ** ppResultType);
4823
4824 // Create a type from from the data received from the left-side
4825 static HRESULT TypeDataToType(CordbAppDomain *appdomain, DebuggerIPCE_ExpandedTypeData *data, CordbType **pRes);
4826 static HRESULT TypeDataToType(CordbAppDomain *appdomain, DebuggerIPCE_BasicTypeData *data, CordbType **pRes);
4827 static HRESULT InstantiateFromTypeHandle(CordbAppDomain * appdomain,
4828 VMPTR_TypeHandle vmTypeHandle,
4829 CorElementType et,
4830 CordbClass * tycon,
4831 CordbType ** pRes);
4832
4833 // Prepare data to send back to left-side during Init() and FuncEval. Fail if the the exact
4834 // type data is requested but was not fetched correctly during Init()
4835 HRESULT TypeToBasicTypeData(DebuggerIPCE_BasicTypeData *data);
4836 void TypeToExpandedTypeData(DebuggerIPCE_ExpandedTypeData *data);
4837 void TypeToTypeArgData(DebuggerIPCE_TypeArgData *data);
4838
4839 void CountTypeDataNodes(unsigned int *count);
4840 static void CountTypeDataNodesForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], unsigned int *count);
4841 static void GatherTypeData(CordbType *type, DebuggerIPCE_TypeArgData **curr_tyargData);
4842 static void GatherTypeDataForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], DebuggerIPCE_TypeArgData **curr_tyargData);
4843
4844 HRESULT GetParentType(CordbClass * baseClass, CordbType ** ppRes);
4845
4846 // These are available after Init() has been called....
4847 HRESULT GetUnboxedObjectSize(ULONG32 *res);
4848 HRESULT GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData);
4849
4850 CordbAppDomain *GetAppDomain() { return m_appdomain; }
4851
4852 bool IsValueType();
4853
4854 // Is this type a GC-root.
4855 bool IsGCRoot();
4856
4857#ifdef FEATURE_64BIT_ALIGNMENT
4858 // checks if the type requires 8-byte alignment.
4859 // this is not exposed via ICorDebug at present.
4860 HRESULT CordbType::RequiresAlign8(BOOL* isRequired);
4861#endif
4862
4863 //-----------------------------------------------------------
4864 // Data members
4865 //-----------------------------------------------------------
4866
4867public:
4868 // Internal representation of the element type. This may not map exactly to the public element type.
4869 // Specifically, m_elementType is NEVER:
4870 // ELEMENT_TYPE_VAR, ELEMENT_TYPE_MVAR, ELEMENT_TYPE_GENERICINST,
4871 // or ELEMENT_TYPE_VALUETYPE.
4872 // To find out if this CordbType corresponds to a value type (instead of Reference type) call CordbType::IsValueType()
4873 CorElementType m_elementType;
4874
4875 // The appdomain that this type lives in. Types (and their type-parameters) are all contained in a single appdomain.
4876 // (alhtough the types may be from different modules).
4877 // This is valid for all CordbType objects, regardless of m_elementType;
4878 CordbAppDomain * m_appdomain;
4879
4880 // The matching class for this type.
4881 // Initially only set for E_T_CLASS, lazily computed for E_T_STRING and E_T_OBJECT if needed
4882 CordbClass * m_pClass;
4883
4884 ULONG m_rank; // Only set for E_T_ARRAY etc.
4885
4886 // Array of Type Parameters for this Type.
4887 Instantiation m_inst;
4888
4889 // A unique mapping from CordbType objects that are type parameters to CordbType objects. Each mapping
4890 // represents the use of the containing type as type constructor. e.g. If the containing type
4891 // is CordbType(CordbClass "List") then the table here will map parameters such as (CordbType(CordbClass "String")) to
4892 // the constructed type CordbType(CordbClass "List", <CordbType(CordbClass "String")>)
4893 // @dbgtodo synchronization - this is currently protected by the Stop-Go lock. Transition to process-lock.
4894 CordbSafeHashTable<CordbType> m_spinetypes;
4895
4896 // Valid after Init(), only for E_T_ARRAY etc.and E_T_CLASS when m_pClass->m_classInfo.m_genericArgsCount > 0.
4897 // m_typeHandleExact is the precise Runtime type handle for this type.
4898 VMPTR_TypeHandle m_typeHandleExact;
4899
4900 // Valid after Init(), only for E_T_CLASS, and when m_pClass->m_classInfo.m_genericArgsCount > 0.
4901 // May not be set correctly if m_fieldInfoNeedsInit.
4902 SIZE_T m_objectSize;
4903
4904 // DON'T KEEP POINTERS TO ELEMENTS OF m_pFields AROUND!!
4905 // This may be deleted if the class gets EnC'd.
4906 //
4907 // Valid after Init(), only for E_T_CLASS, and when m_pClass->m_classInfo.m_genericArgsCount > 0
4908 // All fields will be valid if we have m_typeHandleExact.
4909 //
4910 // Only some fields will be valid if we have called Init() but still have m_fieldInfoNeedsInit.
4911 DacDbiArrayList<FieldData> m_fieldList;
4912
4913 HRESULT ReturnedByValue();
4914
4915private:
4916 static HRESULT MkTyAppType(CordbAppDomain * pAddDomain,
4917 CordbType * pType,
4918 const Instantiation * pInst,
4919 CordbType ** pResultType);
4920
4921 BOOL m_fieldInfoNeedsInit;
4922
4923private:
4924 HRESULT InitInstantiationTypeHandle(BOOL fForceInit);
4925 HRESULT InitInstantiationFieldInfo(BOOL fForceInit);
4926 HRESULT InitStringOrObjectClass(BOOL fForceInit);
4927};
4928
4929/* ------------------------------------------------------------------------- *
4930 * Class class
4931 * ------------------------------------------------------------------------- */
4932
4933class CordbClass : public CordbBase, public ICorDebugClass, public ICorDebugClass2
4934{
4935public:
4936 CordbClass(CordbModule* m, mdTypeDef token);
4937 virtual ~CordbClass();
4938 virtual void Neuter();
4939
4940 using CordbBase::GetProcess;
4941
4942#ifdef _DEBUG
4943 virtual const char * DbgGetName() { return "CordbClass"; }
4944#endif
4945
4946
4947 //-----------------------------------------------------------
4948 // IUnknown
4949 //-----------------------------------------------------------
4950
4951 ULONG STDMETHODCALLTYPE AddRef()
4952 {
4953 return (BaseAddRef());
4954 }
4955 ULONG STDMETHODCALLTYPE Release()
4956 {
4957 return (BaseRelease());
4958 }
4959 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
4960
4961 //-----------------------------------------------------------
4962 // ICorDebugClass
4963 //-----------------------------------------------------------
4964
4965 COM_METHOD GetStaticFieldValue(mdFieldDef fieldDef,
4966 ICorDebugFrame *pFrame,
4967 ICorDebugValue **ppValue);
4968 COM_METHOD GetModule(ICorDebugModule **pModule);
4969 COM_METHOD GetToken(mdTypeDef *pTypeDef);
4970 //-----------------------------------------------------------
4971 // ICorDebugClass2
4972 //-----------------------------------------------------------
4973 COM_METHOD GetParameterizedType(CorElementType elementType,
4974 ULONG32 cTypeArgs,
4975 ICorDebugType * rgpTypeArgs[],
4976 ICorDebugType ** ppType);
4977
4978 COM_METHOD SetJMCStatus(BOOL fIsUserCode);
4979
4980 //-----------------------------------------------------------
4981 // Convenience routines and Accessors
4982 //-----------------------------------------------------------
4983
4984 // Helper to get containing module
4985 CordbModule * GetModule()
4986 {
4987 return m_pModule;
4988 }
4989
4990 // get the metadata token for this class
4991 mdTypeDef GetToken() { return m_token; }
4992
4993 // Helper to get the AppDomain the class lives in.
4994 CordbAppDomain * GetAppDomain()
4995 {
4996 return m_pModule->GetAppDomain();
4997 }
4998
4999 // This only very roughly resembles the CLASS_LOAD_LEVEL concept in the VM.
5000 // because DBI's needs are far more coarse grained. Also DBI
5001 // may contain more, equal, or less information than what is available in
5002 // native runtime data structures. We can have less when we are being lazy
5003 // and haven't yet fetched it. We can have more if use an independent data
5004 // source such as the metadata blob and then compute some type data ourselves
5005 typedef enum
5006 {
5007 // At this state the constructor has been run.
5008 // m_module and m_token will be valid
5009 Constructed,
5010
5011 // At this state we have additionally certain to have initialized
5012 // m_fIsValueClass and m_fHasTypeParams
5013 // Calls to IsValueClass() and HasTypeParams() are valid
5014 // This stage should be achievable as long as a runtime type handle
5015 // exists, even if it is unrestored
5016 BasicInfo,
5017
5018 //Everything is loaded, or at least anything created lazily from this
5019 //point on should be certain to succeed (ie m_type)
5020 FullInfo
5021 }
5022 ClassLoadLevel;
5023
5024 ClassLoadLevel GetLoadLevel()
5025 {
5026 return m_loadLevel;
5027 }
5028
5029 // determine if a load event has been sent for this class
5030 BOOL LoadEventSent() { return m_fLoadEventSent; }
5031
5032 // set value of m_fLoadEventSent
5033 void SetLoadEventSent(BOOL fEventSent) { m_fLoadEventSent = fEventSent; }
5034
5035 // determine if the class has been unloaded
5036 BOOL HasBeenUnloaded() { return m_fHasBeenUnloaded; }
5037
5038 // set value of m_fHasBeenUnloaded
5039 void SetHasBeenUnloaded(BOOL fUnloaded) { m_fHasBeenUnloaded = (fUnloaded == TRUE); }
5040
5041 // determine if this is a value class
5042 BOOL IsValueClassNoInit() { return m_fIsValueClass; }
5043
5044 // set value of m_fIsValueClass
5045 void SetIsValueClass(BOOL fIsValueClass) { m_fIsValueClass = (fIsValueClass == TRUE); }
5046
5047 // determine if the value class is known
5048 BOOL IsValueClassKnown() { return m_fIsValueClassKnown; }
5049
5050 // set value of m_fIsValueClassKnown
5051 void SetIsValueClassKnown(BOOL fIsValueClassKnown) { m_fIsValueClassKnown = (fIsValueClassKnown == TRUE); }
5052
5053 // get value of m_type
5054 CordbType * GetType() { return m_type; }
5055
5056 void SetType(CordbType * pType) { m_type.Assign(pType); }
5057
5058 // get the type parameter count
5059 bool HasTypeParams() { _ASSERTE(m_loadLevel >= BasicInfo); return m_fHasTypeParams; }
5060
5061 // get the object size
5062 SIZE_T ObjectSize() { return m_classInfo.m_objectSize; }
5063
5064 // get the metadata token for this class
5065 mdTypeDef MDToken() { return m_token; }
5066
5067 // get the number of fields
5068 unsigned int FieldCount() { return m_classInfo.m_fieldList.Count(); }
5069
5070 //-----------------------------------------------------------
5071 // Functionality shared for CordbType and CordbClass
5072 //-----------------------------------------------------------
5073
5074 static HRESULT SearchFieldInfo(CordbModule * module,
5075 DacDbiArrayList<FieldData> * pFieldList,
5076 mdTypeDef classToken,
5077 mdFieldDef fldToken,
5078 FieldData ** ppFieldData);
5079
5080 static HRESULT GetStaticFieldValue2(CordbModule * pModule,
5081 FieldData * pFieldData,
5082 BOOL fEnCHangingField,
5083 const Instantiation * pInst,
5084 ICorDebugFrame * pFrame,
5085 ICorDebugValue ** ppValue);
5086
5087 //-----------------------------------------------------------
5088 // Non-COM methods
5089 //-----------------------------------------------------------
5090
5091 // Get information about a field that was added by EnC
5092 HRESULT GetEnCHangingField(mdFieldDef fldToken,
5093 FieldData ** ppFieldData,
5094 CordbObjectValue * pObject);
5095
5096private:
5097 // Get information via the DAC about a field added with Edit and Continue.
5098 FieldData * GetEnCFieldFromDac(BOOL fStatic,
5099 CordbObjectValue * pObject,
5100 mdFieldDef fieldToken);
5101
5102 // Initialize an instance of EnCHangingFieldInfo.
5103 void InitEnCFieldInfo(EnCHangingFieldInfo * pEncField,
5104 BOOL fStatic,
5105 CordbObjectValue * pObject,
5106 mdFieldDef fieldToken,
5107 mdTypeDef classToken);
5108
5109
5110public:
5111
5112 // set or clear the custom notifications flag to control whether we ignore custom debugger notifications
5113 void SetCustomNotifications(BOOL fEnable) { m_fCustomNotificationsEnabled = fEnable; }
5114 BOOL CustomNotificationsEnabled () { return m_fCustomNotificationsEnabled; }
5115
5116 HRESULT GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData);
5117
5118 // If you want to force the init to happen even if we think the class
5119 // is up to date, set fForceInit to TRUE
5120 void Init(ClassLoadLevel desiredLoadLevel = FullInfo);
5121
5122 // determine if any fields for a type are unallocated statics
5123 BOOL GotUnallocatedStatic(DacDbiArrayList<FieldData> * pFieldList);
5124
5125 bool IsValueClass();
5126 HRESULT GetThisType(const Instantiation * pInst, CordbType ** ppResultType);
5127 static HRESULT PostProcessUnavailableHRESULT(HRESULT hr,
5128 IMetaDataImport *pImport,
5129 mdFieldDef fieldDef);
5130 mdTypeDef GetTypeDef() { return (mdTypeDef)m_id; }
5131
5132#ifdef EnC_SUPPORTED
5133 // when we get an added field or method, mark the class to force re-init when we access it
5134 void MakeOld()
5135 {
5136 m_loadLevel = Constructed;
5137 }
5138#endif // EnC_SUPPORTED
5139
5140 //-----------------------------------------------------------
5141 // Data members
5142 //-----------------------------------------------------------
5143private:
5144 // contains information about the type: size and
5145 // field information
5146 ClassInfo m_classInfo;
5147
5148 ClassLoadLevel m_loadLevel;
5149
5150 // @dbgtodo managed pipeline - can we get rid of both of these fields?
5151 BOOL m_fLoadEventSent;
5152 bool m_fHasBeenUnloaded;
5153
5154 // [m_type] is the type object for when this class is used
5155 // as a type. If the class is a value class then it can represent
5156 // either the boxed or unboxed type - it depends on the context where the
5157 // type is used. For example on a CordbBoxValue it represents the type of the
5158 // boxed VC, on a CordbVCObjectValue it represents the type of the unboxed VC.
5159 //
5160 // The type field starts of NULL as there
5161 // is no need to create the type object until it is needed.
5162 RSSmartPtr<CordbType> m_type;
5163
5164 // Module that this Class lives in. Valid at the Constructed type level.
5165 CordbModule * m_pModule;
5166
5167 // the token for the type constructor - m_id cannot be used for constructed types
5168 // valid at the Constructed type level
5169 mdTypeDef m_token;
5170
5171 // Whether the class is a VC or not is discovered either by
5172 // seeing the class used in a signature after ELEMENT_TYPE_VALUETYPE
5173 // or ELEMENT_TYPE_CLASS or by going and asking the EE.
5174 bool m_fIsValueClassKnown;
5175
5176 // Whether the class is a VC or not
5177 bool m_fIsValueClass;
5178
5179 // Whether the class has generic type parameters in its definition
5180 bool m_fHasTypeParams;
5181
5182 // Timestamp from GetProcess()->m_continueCounter, which we can use to tell if
5183 // the process has been continued since we last took a snapshot.
5184 UINT m_continueCounterLastSync;
5185
5186 // if we add static fields with EnC after this class is loaded (in the debuggee),
5187 // their value will be hung off the FieldDesc. Hold information about such fields here.
5188 CordbHangingFieldTable m_hangingFieldsStatic;
5189
5190 // this indicates whether we should send custom debugger notifications
5191 BOOL m_fCustomNotificationsEnabled;
5192
5193};
5194
5195
5196/* ------------------------------------------------------------------------- *
5197 * TypeParameter enumerator class
5198 * ------------------------------------------------------------------------- */
5199
5200class CordbTypeEnum : public CordbBase, public ICorDebugTypeEnum
5201{
5202public:
5203 // Factory method: Create a new instance of this class. Returns NULL on out-of-memory.
5204 // On success, returns a new initialized instance of CordbTypeEnum with ref-count 0 (just like a ctor).
5205 // the life expectancy of the enumerator varies by caller so we require them to specify the applicable neuter list here.
5206 static CordbTypeEnum* Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, CordbType **ppTypars);
5207 static CordbTypeEnum* Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, RSSmartPtr<CordbType>*ppTypars);
5208
5209 virtual ~CordbTypeEnum() ;
5210
5211 virtual void Neuter();
5212
5213
5214#ifdef _DEBUG
5215 virtual const char * DbgGetName() { return "CordbTypeEnum"; }
5216#endif
5217
5218
5219 //-----------------------------------------------------------
5220 // IUnknown
5221 //-----------------------------------------------------------
5222
5223 ULONG STDMETHODCALLTYPE AddRef()
5224 {
5225 return (BaseAddRef());
5226 }
5227 ULONG STDMETHODCALLTYPE Release()
5228 {
5229 return (BaseRelease());
5230 }
5231 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5232
5233 //-----------------------------------------------------------
5234 // ICorDebugEnum
5235 //-----------------------------------------------------------
5236
5237 COM_METHOD Skip(ULONG celt);
5238 COM_METHOD Reset();
5239 COM_METHOD Clone(ICorDebugEnum **ppEnum);
5240 COM_METHOD GetCount(ULONG *pcelt);
5241
5242 //-----------------------------------------------------------
5243 // ICorDebugTypeEnum
5244 //-----------------------------------------------------------
5245
5246 COM_METHOD Next(ULONG celt, ICorDebugType *Types[], ULONG *pceltFetched);
5247
5248private:
5249 // Private constructor, only partially initializes the object.
5250 // Clients should use the 'Build' factory method to create an instance of this class.
5251 CordbTypeEnum( CordbAppDomain * pAppDomain, NeuterList * pNeuterList );
5252 template<class T> static CordbTypeEnum* BuildImpl(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, T* ppTypars );
5253
5254 // Owning object.
5255 CordbAppDomain * m_pAppDomain;
5256
5257 // Array of Types. We own the array, and share refs to the types.
5258 // @todo- since these are guaranteed to be kept alive as long as we're not neutered,
5259 // we don't need to keep refs to them.
5260 RSSmartPtr<CordbType> * m_ppTypars;
5261 UINT m_iCurrent;
5262 UINT m_iMax;
5263};
5264
5265/* ------------------------------------------------------------------------- *
5266 * Code enumerator class
5267 * ------------------------------------------------------------------------- */
5268
5269class CordbCodeEnum : public CordbBase, public ICorDebugCodeEnum
5270{
5271public:
5272 CordbCodeEnum(unsigned int cCode, RSSmartPtr<CordbCode> * ppCode);
5273 virtual ~CordbCodeEnum() ;
5274
5275
5276#ifdef _DEBUG
5277 virtual const char * DbgGetName() { return "CordbCodeEnum"; }
5278#endif
5279
5280
5281 //-----------------------------------------------------------
5282 // IUnknown
5283 //-----------------------------------------------------------
5284
5285 ULONG STDMETHODCALLTYPE AddRef()
5286 {
5287 return (BaseAddRef());
5288 }
5289 ULONG STDMETHODCALLTYPE Release()
5290 {
5291 return (BaseRelease());
5292 }
5293 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5294
5295 //-----------------------------------------------------------
5296 // ICorDebugEnum
5297 //-----------------------------------------------------------
5298
5299 COM_METHOD Skip(ULONG celt);
5300 COM_METHOD Reset();
5301 COM_METHOD Clone(ICorDebugEnum **ppEnum);
5302 COM_METHOD GetCount(ULONG *pcelt);
5303
5304 //-----------------------------------------------------------
5305 // ICorDebugCodeEnum
5306 //-----------------------------------------------------------
5307
5308 COM_METHOD Next(ULONG celt, ICorDebugCode *Codes[], ULONG *pceltFetched);
5309
5310private:
5311 // Ptr to an array of CordbCode*
5312 // We own the array.
5313 RSSmartPtr<CordbCode> * m_ppCodes;
5314 UINT m_iCurrent;
5315 UINT m_iMax;
5316};
5317
5318
5319
5320
5321
5322typedef CUnorderedArray<CordbCode*,11> UnorderedCodeArray;
5323//<TODO>@todo port: different SIZE_T size/</TODO>
5324const int DMI_VERSION_INVALID = 0;
5325const int DMI_VERSION_MOST_RECENTLY_JITTED = 1;
5326const int DMI_VERSION_MOST_RECENTLY_EnCED = 2;
5327
5328
5329/* ------------------------------------------------------------------------- *
5330 * Function class
5331 *
5332 * @review . The CordbFunction class now keeps a multiple MethodDescInfo
5333 * structures in a hash table indexed by tokens provided by the left-side.
5334 * In 99.9% of cases this hash table will only contain one entry - we only
5335 * use a hashtable to cover the case where we have multiple JITtings of
5336 * a single version of a function, in particular multiple JITtings of generic
5337 * code under different instantiations. This will increase space usage.
5338 * The way around it is to store one CordbNativeCode in-line in the CordbFunction
5339 * class, or at least store one such pointer so no hash table will normally
5340 * be needed. This is similar to other cases, e.g. the hash table in
5341 * CordbClass used to indicate different CordbTypes made from that class -
5342 * again in the normal case these tables will only contain one element.
5343 *
5344 * However, for the moment I've focused on correctness and we can minimize
5345 * this space usage in due course.
5346 * ------------------------------------------------------------------------- */
5347
5348const BOOL bNativeCode = FALSE;
5349const BOOL bILCode = TRUE;
5350
5351//
5352// Each E&C version gets its own function object. So the IL that a function
5353// is associated w/ does not change.
5354// B/C of generics, a single IL function may get jitted multiple times and
5355// be associated w/ multiple native code blobs (CordbNativeCode).
5356//
5357class CordbFunction : public CordbBase,
5358 public ICorDebugFunction,
5359 public ICorDebugFunction2,
5360 public ICorDebugFunction3,
5361 public ICorDebugFunction4
5362{
5363public:
5364 //-----------------------------------------------------------
5365 // Create from scope and member objects.
5366 //-----------------------------------------------------------
5367 CordbFunction(CordbModule * m,
5368 mdMethodDef token,
5369 SIZE_T enCVersion);
5370 virtual ~CordbFunction();
5371 virtual void Neuter();
5372
5373
5374
5375#ifdef _DEBUG
5376 virtual const char * DbgGetName() { return "CordbFunction"; }
5377#endif
5378
5379
5380 //-----------------------------------------------------------
5381 // IUnknown
5382 //-----------------------------------------------------------
5383
5384 ULONG STDMETHODCALLTYPE AddRef()
5385 {
5386 return (BaseAddRef());
5387 }
5388 ULONG STDMETHODCALLTYPE Release()
5389 {
5390 return (BaseRelease());
5391 }
5392 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5393
5394 //-----------------------------------------------------------
5395 // ICorDebugFunction
5396 //-----------------------------------------------------------
5397 COM_METHOD GetModule(ICorDebugModule **pModule);
5398 COM_METHOD GetClass(ICorDebugClass **ppClass);
5399 COM_METHOD GetToken(mdMethodDef *pMemberDef);
5400 COM_METHOD GetILCode(ICorDebugCode **ppCode);
5401 COM_METHOD GetNativeCode(ICorDebugCode **ppCode);
5402 COM_METHOD CreateBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint);
5403 COM_METHOD GetLocalVarSigToken(mdSignature *pmdSig);
5404 COM_METHOD GetCurrentVersionNumber(ULONG32 *pnCurrentVersion);
5405
5406 //-----------------------------------------------------------
5407 // ICorDebugFunction2
5408 //-----------------------------------------------------------
5409 COM_METHOD SetJMCStatus(BOOL fIsUserCode);
5410 COM_METHOD GetJMCStatus(BOOL * pfIsUserCode);
5411 COM_METHOD EnumerateNativeCode(ICorDebugCodeEnum **ppCodeEnum) { return E_NOTIMPL; }
5412 COM_METHOD GetVersionNumber(ULONG32 *pnCurrentVersion);
5413
5414 //-----------------------------------------------------------
5415 // ICorDebugFunction3
5416 //-----------------------------------------------------------
5417 COM_METHOD GetActiveReJitRequestILCode(ICorDebugILCode **ppReJitedILCode);
5418
5419 //-----------------------------------------------------------
5420 // ICorDebugFunction4
5421 //-----------------------------------------------------------
5422 COM_METHOD CreateNativeBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint);
5423
5424 //-----------------------------------------------------------
5425 // Internal members
5426 //-----------------------------------------------------------
5427protected:
5428 // Returns the function's ILCode and SigToken
5429 HRESULT GetILCodeAndSigToken();
5430
5431 // Get the metadata token for the class to which a function belongs.
5432 mdTypeDef InitParentClassOfFunctionHelper(mdToken funcMetaDataToken);
5433
5434 // Get information about one of the native code blobs for this function
5435 HRESULT InitNativeCodeInfo();
5436
5437public:
5438
5439 // Get the class to which a given function belongs
5440 HRESULT InitParentClassOfFunction();
5441
5442 void NotifyCodeCreated(CordbNativeCode* nativeCode);
5443
5444 HRESULT GetSig(SigParser *pMethodSigParser,
5445 ULONG *pFunctionArgCount,
5446 BOOL *pFunctionIsStatic);
5447
5448 HRESULT GetArgumentType(DWORD dwIndex, const Instantiation * pInst, CordbType ** ppResultType);
5449
5450
5451 //-----------------------------------------------------------
5452 // Internal routines
5453 //-----------------------------------------------------------
5454
5455 // Get the existing IL code object
5456 HRESULT GetILCode(CordbILCode ** ppCode);
5457
5458 // Finds or creates an ILCode for a given rejit request
5459 HRESULT LookupOrCreateReJitILCode(VMPTR_ILCodeVersionNode vmILCodeVersionNode,
5460 CordbReJitILCode** ppILCode);
5461
5462
5463#ifdef EnC_SUPPORTED
5464 void MakeOld();
5465#endif
5466
5467 //-----------------------------------------------------------
5468 // Accessors
5469 //-----------------------------------------------------------
5470
5471 // Get the AppDomain that this function lives in.
5472 CordbAppDomain * GetAppDomain()
5473 {
5474 return (m_pModule->GetAppDomain());
5475 }
5476
5477 // Get the CordbModule that this Function lives in.
5478 CordbModule * GetModule()
5479 {
5480 return m_pModule;
5481 }
5482
5483 // Get the CordbClass this of which this function is a member
5484 CordbClass * GetClass()
5485 {
5486 return m_pClass;
5487 }
5488
5489 // Get the IL code blob corresponding to this function
5490 CordbILCode * GetILCode()
5491 {
5492 return m_pILCode;
5493 }
5494
5495 // Get metadata token for this function
5496 mdMethodDef GetMetadataToken()
5497 {
5498 return m_MDToken;
5499 }
5500
5501 SIZE_T GetEnCVersionNumber()
5502 {
5503 return m_dwEnCVersionNumber;
5504 }
5505
5506 CordbFunction * GetPrevVersion()
5507 {
5508 return m_pPrevVersion;
5509 }
5510
5511 void SetPrevVersion(CordbFunction * prevVersion)
5512 {
5513 m_pPrevVersion.Assign(prevVersion);
5514 }
5515
5516 typedef enum {kNativeOnly, kHasIL, kUnknownImpl} ImplementationKind;
5517 ImplementationKind IsNativeImpl()
5518 {
5519 return (m_fIsNativeImpl);
5520 }
5521
5522 // determine whether we have a native-only implementation
5523 void InitNativeImpl();
5524
5525
5526 //-----------------------------------------------------------
5527 // Data members
5528 //-----------------------------------------------------------
5529
5530private:
5531 // The module that this Function is contained in. It maintains a strong reference to this object
5532 // and will neuter this object.
5533 CordbModule * m_pModule;
5534
5535 // The Class that this function is contained in.
5536 CordbClass * m_pClass;
5537
5538 // We only have 1 IL blob associated with a given Function object.
5539 RSSmartPtr<CordbILCode> m_pILCode;
5540
5541
5542 // Generics allow a single IL method to be instantiated to multiple native
5543 // code blobs. So CordbFunction : CordbNativeCode is 1:n.
5544 // This pointer is to arbitrary one of those n code bodies.
5545 // Someday we may need to get access to all N of them but not today
5546 RSSmartPtr<CordbNativeCode> m_nativeCode;
5547
5548 // Metadata Token for the IL function. Scoped to m_module.
5549 mdMethodDef m_MDToken;
5550
5551 // EnC version number of this instance
5552 SIZE_T m_dwEnCVersionNumber;
5553
5554 // link to previous version of this function
5555 RSSmartPtr<CordbFunction> m_pPrevVersion;
5556
5557 // Is the function implemented natively in the runtime?? (eg, it has no IL, may be an Ecall/fcall)
5558 ImplementationKind m_fIsNativeImpl;
5559
5560 // True if method signature (argument) values are cached.
5561 BOOL m_fCachedMethodValuesValid;
5562
5563 // Cached SigParser for this Function's argument signature.
5564 // Only valid if m_fCachedMethodValuesValid is set.
5565 SigParser m_methodSigParserCached;
5566
5567 // Cached Count of arguments in the argument signature.
5568 // Only valid if m_fCachedMethodValuesValid is set.
5569 ULONG m_argCountCached;
5570
5571 // Cached boolean if method is static or instance (part of the argument signature).
5572 // Only valid if m_fCachedMethodValuesValid is set.
5573 BOOL m_fIsStaticCached;
5574
5575 // A collection, indexed by VMPTR_SharedReJitInfo, of IL code for rejit requests
5576 // The collection is filled lazily by LookupOrCreateReJitILCode
5577 CordbSafeHashTable<CordbReJitILCode> m_reJitILCodes;
5578};
5579
5580//-----------------------------------------------------------------------------
5581// class CordbCode
5582// Represents either IL or Native code blobs associated with a function.
5583//
5584// See the comments at the ICorDebugCode definition for invariants about Code objects.
5585//
5586//-----------------------------------------------------------------------------
5587class CordbCode : public CordbBase, public ICorDebugCode
5588{
5589protected:
5590 CordbCode(CordbFunction * pFunction, UINT_PTR id, SIZE_T encVersion, BOOL fIsIL);
5591
5592public:
5593 virtual ~CordbCode();
5594 virtual void Neuter();
5595
5596#ifdef _DEBUG
5597 virtual const char * DbgGetName() = 0;
5598#endif
5599
5600
5601 //-----------------------------------------------------------
5602 // IUnknown
5603 //-----------------------------------------------------------
5604
5605 ULONG STDMETHODCALLTYPE AddRef()
5606 {
5607 return (BaseAddRef());
5608 }
5609 ULONG STDMETHODCALLTYPE Release()
5610 {
5611 return (BaseRelease());
5612 }
5613 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5614
5615 //-----------------------------------------------------------
5616 // ICorDebugCode
5617 //-----------------------------------------------------------
5618
5619 COM_METHOD IsIL(BOOL * pbIL);
5620 COM_METHOD GetFunction(ICorDebugFunction ** ppFunction);
5621 COM_METHOD GetAddress(CORDB_ADDRESS * pStart) = 0;
5622 COM_METHOD GetSize(ULONG32 * pcBytes);
5623 COM_METHOD CreateBreakpoint(ULONG32 offset,
5624 ICorDebugFunctionBreakpoint ** ppBreakpoint);
5625 COM_METHOD GetCode(ULONG32 startOffset, ULONG32 endOffset,
5626 ULONG32 cBufferAlloc,
5627 BYTE buffer[],
5628 ULONG32 * pcBufferSize);
5629 COM_METHOD GetVersionNumber( ULONG32 * nVersion);
5630 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5631 ULONG32 * pcMap,
5632 COR_DEBUG_IL_TO_NATIVE_MAP map[]) = 0;
5633 COM_METHOD GetEnCRemapSequencePoints(ULONG32 cMap,
5634 ULONG32 * pcMap,
5635 ULONG32 offsets[]);
5636
5637 //-----------------------------------------------------------
5638 // Accessors and convenience routines
5639 //-----------------------------------------------------------
5640
5641 // get the CordbFunction instance for this code object
5642 CordbFunction * GetFunction();
5643
5644 // get the actual code bytes for this function
5645 virtual HRESULT ReadCodeBytes() = 0;
5646
5647 // get the size in bytes of this function
5648 virtual ULONG32 GetSize() = 0;
5649
5650
5651 // get the metadata token for this code object
5652 mdMethodDef GetMetadataToken()
5653 {
5654 _ASSERTE(m_pFunction != NULL);
5655 return (m_pFunction->GetMetadataToken());
5656 }
5657
5658 // get the module this code object belongs to
5659 CordbModule * GetModule()
5660 {
5661 _ASSERTE(m_pFunction != NULL);
5662 return (m_pFunction->GetModule());
5663 }
5664
5665 // get the function signature for this code blob or throw on failure
5666 void GetSig(SigParser *pMethodSigParser,
5667 ULONG *pFunctionArgCount,
5668 BOOL *pFunctionIsStatic)
5669 {
5670 _ASSERTE(m_pFunction != NULL);
5671 IfFailThrow(m_pFunction->GetSig(pMethodSigParser, pFunctionArgCount, pFunctionIsStatic));
5672 }
5673
5674 // get the class to which this code blob belongs
5675 CordbClass * GetClass()
5676 {
5677 _ASSERTE(m_pFunction != NULL);
5678 return (m_pFunction->GetClass());
5679 }
5680
5681 // Quick helper to get the AppDomain that this code object lives in.
5682 CordbAppDomain *GetAppDomain()
5683 {
5684 _ASSERTE(m_pFunction != NULL);
5685 return (m_pFunction->GetAppDomain());
5686 }
5687
5688 // Get the EnC version of this blob
5689 SIZE_T GetVersion() { return m_nVersion; };
5690
5691 // Return true if this is an IL code blob. Else return false.
5692 BOOL IsIL() { return m_fIsIL; }
5693
5694 // convert to CordbNativeCode as long as m_fIsIl is false.
5695 CordbNativeCode * AsNativeCode()
5696 {
5697 _ASSERTE(m_fIsIL == FALSE);
5698 return reinterpret_cast<CordbNativeCode *>(this);
5699 }
5700
5701 // convert to CordbILCode as long as m_fIsIl is true.
5702 CordbILCode * AsILCode()
5703 {
5704 _ASSERTE(m_fIsIL == TRUE);
5705 return reinterpret_cast<CordbILCode *>(this);
5706 }
5707
5708 //-----------------------------------------------------------
5709 // Data members
5710 //-----------------------------------------------------------
5711
5712private:
5713 UINT m_fIsIL : 1;
5714
5715 // EnC version number.
5716 SIZE_T m_nVersion;
5717
5718protected:
5719 // Our local copy of the code. It will be GetSize() bytes long.
5720 BYTE * m_rgbCode; // will be NULL if we can't fit it into memory
5721
5722 UINT m_continueCounterLastSync;
5723
5724 // Owning Function associated with this code.
5725 CordbFunction * m_pFunction;
5726}; //class CordbCode
5727
5728
5729
5730
5731
5732/* ------------------------------------------------------------------------- *
5733* CordbILCode class
5734* This class represents an IL code blob for a particular EnC version. Thus it is
5735* 1:1 with a given instantiation of CordbFunction. Provided functionality includes
5736* methods to get the starting address and size of an IL code blob and to read
5737* the actual bytes of IL into a buffer.
5738 * ------------------------------------------------------------------------- */
5739
5740class CordbILCode : public CordbCode
5741{
5742public:
5743 // Initialize a new CordbILCode instance
5744 CordbILCode(CordbFunction *pFunction, TargetBuffer codeRegionInfo, SIZE_T nVersion, mdSignature localVarSigToken, UINT_PTR id = 0);
5745
5746#ifdef _DEBUG
5747 const char * DbgGetName() { return "CordbILCode"; };
5748#endif // _DEBUG
5749
5750 COM_METHOD GetAddress(CORDB_ADDRESS * pStart);
5751 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5752 ULONG32 * pcMap,
5753 COR_DEBUG_IL_TO_NATIVE_MAP map[]);
5754 // Quick helper for internal access to: GetAddress(CORDB_ADDRESS *pStart);
5755 CORDB_ADDRESS GetAddress() { return m_codeRegionInfo.pAddress; }
5756
5757 // get total size of the IL code
5758 ULONG32 GetSize() { return m_codeRegionInfo.cbSize; }
5759
5760#ifdef EnC_SUPPORTED
5761 void MakeOld();
5762#endif // EnC_SUPPORTED
5763
5764 HRESULT GetLocalVarSig(SigParser *pLocalsSigParser, ULONG *pLocalVarCount);
5765 HRESULT GetLocalVariableType(DWORD dwIndex, const Instantiation * pInst, CordbType ** ppResultType);
5766 mdSignature GetLocalVarSigToken();
5767
5768 COM_METHOD CreateNativeBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint);
5769
5770private:
5771 // Read the actual bytes of IL code into the data member m_rgbCode.
5772 // Helper routine for GetCode
5773 HRESULT ReadCodeBytes();
5774
5775 //-----------------------------------------------------------
5776 // Data members
5777 //-----------------------------------------------------------
5778
5779private:
5780#ifdef EnC_SUPPORTED
5781 UINT m_fIsOld : 1; // marks this instance as an old EnC version
5782 bool m_encBreakpointsApplied;
5783#endif
5784
5785 // derived types can init this
5786protected:
5787 TargetBuffer m_codeRegionInfo; // stores the starting address and size of the
5788 // IL code blob
5789
5790 // Metadata token for local's signature.
5791 mdSignature m_localVarSigToken;
5792
5793}; // class CordbILCode
5794
5795/* ------------------------------------------------------------------------- *
5796* CordbReJitILCode class
5797* This class represents an IL code blob for a particular EnC version and
5798* rejitID. Thus it is 1:N with a given instantiation of CordbFunction.
5799* ------------------------------------------------------------------------- */
5800
5801class CordbReJitILCode : public CordbILCode,
5802 public ICorDebugILCode,
5803 public ICorDebugILCode2
5804{
5805public:
5806 // Initialize a new CordbILCode instance
5807 CordbReJitILCode(CordbFunction *pFunction, SIZE_T encVersion, VMPTR_ILCodeVersionNode vmILCodeVersionNode);
5808
5809 //-----------------------------------------------------------
5810 // IUnknown
5811 //-----------------------------------------------------------
5812 ULONG STDMETHODCALLTYPE AddRef();
5813 ULONG STDMETHODCALLTYPE Release();
5814 COM_METHOD QueryInterface(REFIID riid, void** ppInterface);
5815
5816
5817 //-----------------------------------------------------------
5818 // ICorDebugILCode
5819 //-----------------------------------------------------------
5820 COM_METHOD GetEHClauses(ULONG32 cClauses, ULONG32 * pcClauses, CorDebugEHClause clauses[]);
5821
5822
5823 //-----------------------------------------------------------
5824 // ICorDebugILCode2
5825 //-----------------------------------------------------------
5826 COM_METHOD GetLocalVarSigToken(mdSignature *pmdSig);
5827 COM_METHOD GetInstrumentedILMap(ULONG32 cMap, ULONG32 *pcMap, COR_IL_MAP map[]);
5828
5829private:
5830 HRESULT Init(DacSharedReJitInfo* pSharedReJitInfo);
5831
5832private:
5833 ULONG32 m_cClauses;
5834 NewArrayHolder<CorDebugEHClause> m_pClauses;
5835 ULONG32 m_cbLocalIL;
5836 NewArrayHolder<BYTE> m_pLocalIL;
5837 ULONG32 m_cILMap;
5838 NewArrayHolder<COR_IL_MAP> m_pILMap;
5839};
5840
5841/* ------------------------------------------------------------------------- *
5842 * CordbNativeCode class. These correspond to MethodDesc's on the left-side.
5843 * There may or may not be a DebuggerJitInfo associated with the MethodDesc.
5844 * At most one CordbNativeCode is created for each native code compilation of each method
5845 * that is seen by the right-side. Note that if each method were JITted only once
5846 * then this information could go in CordbFunction, however generics allow
5847 * methods to be compiled more than once.
5848 *
5849 * The purpose of this class is to encapsulate details about a blob of jitted/ngen'ed
5850 * code, including an optional set of mappings from IL to offsets in the native Code.
5851 * ------------------------------------------------------------------------- */
5852
5853class CordbNativeCode : public CordbCode,
5854 public ICorDebugCode2,
5855 public ICorDebugCode3,
5856 public ICorDebugCode4
5857{
5858public:
5859 CordbNativeCode(CordbFunction * pFunction,
5860 const NativeCodeFunctionData * pJitData,
5861 BOOL fIsInstantiatedGeneric);
5862#ifdef _DEBUG
5863 const char * DbgGetName() { return "CordbNativeCode"; };
5864#endif // _DEBUG
5865
5866 ULONG STDMETHODCALLTYPE AddRef()
5867 {
5868 return (BaseAddRef());
5869 }
5870 ULONG STDMETHODCALLTYPE Release()
5871 {
5872 return (BaseRelease());
5873 }
5874 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
5875
5876 //-----------------------------------------------------------
5877 // ICorDebugCode
5878 //-----------------------------------------------------------
5879 COM_METHOD GetAddress(CORDB_ADDRESS * pStart);
5880 COM_METHOD GetILToNativeMapping(ULONG32 cMap,
5881 ULONG32 * pcMap,
5882 COR_DEBUG_IL_TO_NATIVE_MAP map[]);
5883 //-----------------------------------------------------------
5884 // ICorDebugCode2
5885 //-----------------------------------------------------------
5886 COM_METHOD GetCodeChunks(ULONG32 cbufSize, ULONG32 * pcnumChunks, CodeChunkInfo chunks[]);
5887
5888 COM_METHOD GetCompilerFlags(DWORD * pdwFlags);
5889
5890 //-----------------------------------------------------------
5891 // ICorDebugCode3
5892 //-----------------------------------------------------------
5893 COM_METHOD GetReturnValueLiveOffset(ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets);
5894
5895
5896 //-----------------------------------------------------------
5897 // ICorDebugCode4
5898 //-----------------------------------------------------------
5899 COM_METHOD EnumerateVariableHomes(ICorDebugVariableHomeEnum **ppEnum);
5900
5901 //-----------------------------------------------------------
5902 // Internal members
5903 //-----------------------------------------------------------
5904
5905 HRESULT ILVariableToNative(DWORD dwIndex,
5906 SIZE_T ip,
5907 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
5908 void LoadNativeInfo();
5909
5910 //-----------------------------------------------------------
5911 // Accessors and convenience routines
5912 //-----------------------------------------------------------
5913
5914 // get the argument type for a generic
5915 void GetArgumentType(DWORD dwIndex,
5916 const Instantiation * pInst,
5917 CordbType ** ppResultType)
5918 {
5919 CordbFunction * pFunction = GetFunction();
5920 _ASSERTE(pFunction != NULL);
5921 IfFailThrow(pFunction->GetArgumentType(dwIndex, pInst, ppResultType));
5922 }
5923
5924 // Quick helper for internall access to: GetAddress(CORDB_ADDRESS *pStart);
5925 CORDB_ADDRESS GetAddress() { return m_rgCodeRegions[kHot].pAddress; };
5926
5927 VMPTR_MethodDesc GetVMNativeCodeMethodDescToken() { return m_vmNativeCodeMethodDescToken; };
5928
5929 // Worker function for GetReturnValueLiveOffset.
5930 HRESULT GetReturnValueLiveOffsetImpl(Instantiation *currentInstantiation, ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets);
5931
5932 // get total size of the code including both hot and cold regions
5933 ULONG32 GetSize();
5934
5935 // get the size of the cold region(s) only
5936 ULONG32 GetColdSize();
5937
5938 // Return true if the Code is split into hot + cold regions.
5939 bool HasColdRegion() { return m_rgCodeRegions[kCold].pAddress != NULL; }
5940
5941 // Get the number of fixed arguments for this function (the "this"
5942 // but not varargs)
5943 unsigned int GetFixedArgCount()
5944 {
5945 return m_nativeVarData.GetFixedArgCount();
5946 }
5947
5948 // Get the number of all arguments for this function
5949 // ("this" pointer, fixed args and varargs)
5950 ULONG32 GetAllArgsCount()
5951 {
5952 return m_nativeVarData.GetAllArgsCount();
5953 }
5954
5955 void SetAllArgsCount(ULONG32 count)
5956 {
5957 m_nativeVarData.SetAllArgsCount(count);
5958 }
5959
5960 // Determine whether this is an instantiation of a generic function
5961 BOOL IsInstantiatedGeneric()
5962 {
5963 return m_fIsInstantiatedGeneric != 0;
5964 }
5965
5966 // Determine whether we have initialized the native variable and
5967 // sequence point offsets
5968 BOOL IsNativeCodeValid ()
5969 {
5970 return ((m_nativeVarData.IsInitialized() != 0) &&
5971 (m_sequencePoints.IsInitialized() != 0));
5972 }
5973
5974 SequencePoints * GetSequencePoints()
5975 {
5976 return &m_sequencePoints;
5977 }
5978
5979
5980 // Given an ILOffset in the current function, return the class token and function token of the IL call target at that
5981 // location. Also fill "methodSig" with the method's signature and "genericSig" with the method's generic signature.
5982 HRESULT GetCallSignature(ULONG32 ILOffset, mdToken *pClass, mdToken *pMDFunction, SigParser &methodSig, SigParser &genericSig);
5983
5984 // Moves a method signature from the start of the signature to the location of the return value (passing out the
5985 // number of generic parameters in the method).
5986 static HRESULT SkipToReturn(SigParser &parser, ULONG *genArgCount = 0);
5987
5988private:
5989 // Read the actual bytes of native code into the data member m_rgbCode.
5990 // Helper routine for GetCode
5991 HRESULT ReadCodeBytes();
5992
5993 // Returns a failure HRESULT if we cannot handle the return value of the given
5994 // methodref, methoddef, or methodspec token, otherwise S_OK. Does NOT return S_FALSE;
5995 HRESULT EnsureReturnValueAllowed(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics);
5996 HRESULT EnsureReturnValueAllowedWorker(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics, ULONG genCount);
5997
5998 // Grabs the appropriate signature parser for a methodref, methoddef, methodspec.
5999 HRESULT GetSigParserFromFunction(mdToken mdFunction, mdToken *pClass, SigParser &methodSig, SigParser &genericSig);
6000
6001 int GetCallInstructionLength(BYTE *buffer, ULONG32 len);
6002
6003 //-----------------------------------------------------------
6004 // Data members
6005 //-----------------------------------------------------------
6006private:
6007 // offset of the beginning of the last sequence point in the sequence point map
6008 SIZE_T m_lastIL;
6009
6010 // start address(es) and size(s) of hot and cold regions
6011 TargetBuffer m_rgCodeRegions[MAX_REGIONS];
6012
6013 // LS data structure--method desc for this instantiation.
6014 VMPTR_MethodDesc m_vmNativeCodeMethodDescToken;
6015
6016 bool m_fCodeAvailable; // true iff the code has been jitted but not pitched
6017
6018 bool m_fIsInstantiatedGeneric; // true iff this is an instantiated generic
6019
6020 // information in the following two classes tracks native offsets and is initialized on demand.
6021
6022 // location and ID information for local variables. See code:NativeVarData for details.
6023 NativeVarData m_nativeVarData;
6024
6025 // mapping between IL and native code sequence points.
6026 SequencePoints m_sequencePoints;
6027
6028}; //class CordbNativeCode
6029
6030//---------------------------------------------------------------------------------------
6031//
6032// GetActiveInternalFramesData is used to enumerate internal frames on a specific thread.
6033// It is used in conjunction with code:CordbThread::GetActiveInternalFramesCallback.
6034// We store each internal frame in ppInternalFrames as we enumerate them.
6035//
6036
6037struct GetActiveInternalFramesData
6038{
6039public:
6040 // the thread we are walking
6041 CordbThread * pThis;
6042
6043 // an array to store the internal frames
6044 RSPtrArray<CordbInternalFrame> pInternalFrames;
6045
6046 // next element in the array to be filled
6047 ULONG32 uIndex;
6048};
6049
6050
6051/* ------------------------------------------------------------------------- *
6052 * Thread classes
6053 * ------------------------------------------------------------------------- */
6054
6055class CordbThread : public CordbBase, public ICorDebugThread,
6056 public ICorDebugThread2,
6057 public ICorDebugThread3,
6058 public ICorDebugThread4
6059{
6060public:
6061 CordbThread(CordbProcess * pProcess, VMPTR_Thread);
6062
6063 virtual ~CordbThread();
6064 virtual void Neuter();
6065
6066 using CordbBase::GetProcess;
6067
6068#ifdef _DEBUG
6069 virtual const char * DbgGetName() { return "CordbThread"; }
6070#endif
6071
6072 //-----------------------------------------------------------
6073 // IUnknown
6074 //-----------------------------------------------------------
6075
6076 ULONG STDMETHODCALLTYPE AddRef()
6077 {
6078 // there's an external add ref from within RS in CordbEnumFilter
6079 return (BaseAddRef());
6080 }
6081 ULONG STDMETHODCALLTYPE Release()
6082 {
6083 return (BaseRelease());
6084 }
6085 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6086
6087 //-----------------------------------------------------------
6088 // ICorDebugThread
6089 //-----------------------------------------------------------
6090
6091 COM_METHOD GetProcess(ICorDebugProcess **ppProcess);
6092 COM_METHOD GetID(DWORD *pdwThreadId);
6093 COM_METHOD GetHandle(HANDLE * phThreadHandle);
6094 COM_METHOD GetAppDomain(ICorDebugAppDomain **ppAppDomain);
6095 COM_METHOD SetDebugState(CorDebugThreadState state);
6096 COM_METHOD GetDebugState(CorDebugThreadState *pState);
6097 COM_METHOD GetUserState(CorDebugUserState *pState);
6098 COM_METHOD GetCurrentException(ICorDebugValue ** ppExceptionObject);
6099 COM_METHOD ClearCurrentException();
6100 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
6101 COM_METHOD EnumerateChains(ICorDebugChainEnum **ppChains);
6102 COM_METHOD GetActiveChain(ICorDebugChain **ppChain);
6103 COM_METHOD GetActiveFrame(ICorDebugFrame **ppFrame);
6104 COM_METHOD GetRegisterSet(ICorDebugRegisterSet **ppRegisters);
6105 COM_METHOD CreateEval(ICorDebugEval **ppEval);
6106 COM_METHOD GetObject(ICorDebugValue ** ppObject);
6107
6108 // ICorDebugThread2
6109 COM_METHOD GetConnectionID(CONNID * pConnectionID);
6110 COM_METHOD GetTaskID(TASKID * pTaskID);
6111 COM_METHOD GetVolatileOSThreadID(DWORD * pdwTID);
6112 COM_METHOD GetActiveFunctions(ULONG32 cFunctions, ULONG32 * pcFunctions, COR_ACTIVE_FUNCTION pFunctions[]);
6113 // Intercept the current exception at the specified frame. pFrame must be a valid ICDFrame, possibly from
6114 // a previous stackwalk.
6115 COM_METHOD InterceptCurrentException(ICorDebugFrame * pFrame);
6116
6117
6118
6119 // ICorDebugThread3
6120 COM_METHOD CreateStackWalk(ICorDebugStackWalk **ppStackWalk);
6121
6122 COM_METHOD GetActiveInternalFrames(ULONG32 cInternalFrames,
6123 ULONG32 * pcInternalFrames,
6124 ICorDebugInternalFrame2 * ppInternalFrames[]);
6125
6126 // ICorDebugThread4
6127 COM_METHOD HasUnhandledException();
6128
6129 COM_METHOD GetBlockingObjects(ICorDebugBlockingObjectEnum **ppBlockingObjectEnum);
6130
6131 // Gets the current CustomNotification object from the thread or NULL if no such object exists
6132 COM_METHOD GetCurrentCustomDebuggerNotification(ICorDebugValue ** ppNotificationObject);
6133 //-----------------------------------------------------------
6134 // Internal members
6135 //-----------------------------------------------------------
6136
6137 // callback used to enumerate the internal frames on a thread
6138 static void GetActiveInternalFramesCallback(const DebuggerIPCE_STRData * pFrameData,
6139 void * pUserData);
6140
6141 CorDebugUserState GetUserState();
6142
6143 // Given a FramePointer, find the matching CordbFrame.
6144 HRESULT FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp);
6145
6146 // Get the task ID for this thread.
6147 TASKID GetTaskID();
6148
6149 void RefreshStack();
6150 void CleanupStack();
6151 void MarkStackFramesDirty();
6152
6153
6154#if defined(DBG_TARGET_X86)
6155 // Converts the values in the floating point register area of the context to real number values.
6156 void Get32bitFPRegisters(CONTEXT * pContext);
6157
6158#elif defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_ARM64) || defined(DBG_TARGET_ARM)
6159 // Converts the values in the floating point register area of the context to real number values.
6160 void Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters);
6161
6162#endif // DBG_TARGET_X86
6163
6164 // Initializes the float state members of this instance of CordbThread. This function gets the context and
6165 // converts the floating point values from their context representation to real number values.
6166 void LoadFloatState();
6167
6168
6169 HRESULT SetIP( bool fCanSetIPOnly,
6170 CordbNativeCode * pNativeCode,
6171 SIZE_T offset,
6172 bool fIsIL );
6173
6174 // Tells the LS to remap to the latest version of the function
6175 HRESULT SetRemapIP(SIZE_T offset);
6176
6177 // Ask the left-side for the current (up-to-date) AppDomain of this thread's IP.
6178 // This should be preferred over using the cached value from GetAppDomain.
6179 HRESULT GetCurrentAppDomain(CordbAppDomain ** ppAppDomain);
6180
6181 //-----------------------------------------------------------
6182 // Convenience routines
6183 //-----------------------------------------------------------
6184
6185 // The last domain from which a debug event for this thread was sent.
6186 // This usually (but not always) the domain the thread is currently executing in.
6187 // Since this is a cache, it may sometimes be out-of-date. I believe all current
6188 // usage of this is OK (we pass AppDomains around a lot without really using them),
6189 // but no new code should rely on this value.
6190 // TODO: eliminate this and the m_pAppDomain field entirely
6191 CordbAppDomain *GetAppDomain()
6192 {
6193 return (m_pAppDomain);
6194 }
6195
6196 DWORD GetVolatileOSThreadID();
6197
6198 //////////////////////////////////////////////////////////////////////////
6199 //
6200 // Get Context
6201 //
6202 // <TODO>TODO: Since Thread will share the memory with RegisterSets, how
6203 // do we know that the RegisterSets have relinquished all pointers
6204 // to the m_pContext structure?</TODO>
6205 //
6206 // Returns: NULL if the thread's CONTEXT structure couldn't be obtained
6207 // A pointer to the CONTEXT otherwise.
6208 //
6209 //
6210 //////////////////////////////////////////////////////////////////////////
6211 HRESULT GetManagedContext( DT_CONTEXT ** ppContext );
6212 HRESULT SetManagedContext( DT_CONTEXT * pContext );
6213
6214 // API to retrieve the thread handle from the LS.
6215 void InternalGetHandle(HANDLE * phThread);
6216 void RefreshHandle(HANDLE * phThread);
6217
6218 // NeuterList that's executed when this Thread's stack is refreshed.
6219 // Chain + Frame + some Value enums can be held on this.
6220 NeuterList * GetRefreshStackNeuterList()
6221 {
6222 return &m_RefreshStackNeuterList;
6223 }
6224
6225 DWORD GetUniqueId();
6226
6227
6228 // Hijack a thread at a 2nd-chance exception so that it can execute the CLR's UEF
6229 void HijackForUnhandledException();
6230
6231 // check whether the specified frame lives on the stack of the current thread
6232 bool OwnsFrame(CordbFrame *pFrame);
6233
6234 // Specify that there's an outstanding exception on this thread.
6235 void SetExInfo(VMPTR_OBJECTHANDLE vmExcepObjHandle);
6236
6237 VMPTR_OBJECTHANDLE GetThreadExceptionRawObjectHandle() { return m_vmExcepObjHandle; }
6238 bool HasException() { return m_fException; }
6239
6240 void SetUnhandledNativeException(const EXCEPTION_RECORD * pExceptionRecord);
6241 bool HasUnhandledNativeException();
6242
6243#ifdef _DEBUG
6244 // Helper to assert that this thread no longer appears in dac-dbi enumerations
6245 void DbgAssertThreadDeleted();
6246
6247 // Callback for DbgAssertThreadDeleted
6248 static void DbgAssertThreadDeletedCallback(VMPTR_Thread vmThread, void * pUserData);
6249#endif // _DEBUG
6250
6251 // Determine if the thread's current exception is managed or unmanaged.
6252 BOOL IsThreadExceptionManaged();
6253
6254 // This is a private hook for the shim to create a CordbRegisterSet for a ShimChain.
6255 void CreateCordbRegisterSet(DT_CONTEXT * pContext,
6256 BOOL fActive,
6257 CorDebugChainReason reason,
6258 ICorDebugRegisterSet ** ppRegSet);
6259
6260 // This is a private hook for the shim to convert an ICDFrame into an ICDInternalFrame for a dynamic
6261 // method. Refer to the function header for more information.
6262 BOOL ConvertFrameForILMethodWithoutMetadata(ICorDebugFrame * pFrame,
6263 ICorDebugInternalFrame2 ** ppInternalFrame2);
6264
6265 // Gets/sets m_fCreationEventQueued
6266 bool CreateEventWasQueued();
6267 void SetCreateEventQueued();
6268
6269 //-----------------------------------------------------------
6270 // Data members
6271 //-----------------------------------------------------------
6272
6273public:
6274 // RS Cache for LS context.
6275 // NULL if we haven't allocated memory for a Right side context
6276 DT_CONTEXT * m_pContext;
6277
6278 // Set to the CONTEXT pointer in the LS if this LS thread is
6279 // stopped in managed code. This may be either stopped for execution control
6280 // (breakpoint / single-step exception) or hijacked w/ a redirected frame because
6281 // another thread synced the LS.
6282 // This context is used by the RS to set enregistered vars.
6283 VMPTR_CONTEXT m_vmLeftSideContext;
6284
6285 // indicates whether m_pContext is up-to-date
6286 bool m_fContextFresh;
6287
6288 // last domain we've seen this thread.
6289 // If the appdomain exits, it will clear out this value.
6290 CordbAppDomain *m_pAppDomain;
6291
6292 // Handle to VM's Thread* object. This is the primary key for a CordbThread object
6293 // @dbgtodo ICDThread - merge with m_id;
6294 VMPTR_Thread m_vmThreadToken;
6295
6296 // Unique ID for this thread. See code:CordbThread::GetID for semantics of this field.
6297 DWORD m_dwUniqueID;
6298
6299 CorDebugThreadState m_debugState; // Note that this is for resume
6300 // purposes, NOT the current state of
6301 // the thread.
6302
6303 // The frames are all protected under the Stop-Go lock.
6304 // This field indicates whether the stack is valid (i.e. no update is necessary).
6305 bool m_fFramesFresh;
6306
6307 // This is a cache of V3 ICDFrames. The cache is only used by two functions:
6308 // - code:CordbThread::GetActiveFunctions
6309 // - code:CordbThread::InterceptCurrentException.
6310 //
6311 // We don't clear the cache in CleanupStack() because we don't refresh the cache every time we stop.
6312 // Instead, we mark m_fFramesFresh in CleanupStack() and clear the cache only when it is used next time.
6313 CDynArray<CordbFrame *> m_stackFrames;
6314
6315 bool m_fFloatStateValid;
6316 unsigned int m_floatStackTop;
6317 double m_floatValues[DebuggerIPCE_FloatCount];
6318
6319private:
6320 // True for the window after an Exception callback, but before it's been continued.
6321 // We dispatch two exception events in a row (ICDManagedCallback::Exception and ICDManagedCallback2::Exception),
6322 // and a debugger may normally just skip the first one knowing it can stop on the 2nd once.
6323 // Both events will set this bit high. Be careful not to reset this bit inbetween them.
6324 bool m_fException;
6325
6326 // True if a creation event has been queued for this thread
6327 // The event may or may not have been dispatched yet
6328 // Bugfix DevDiv2\DevDiv 77523 - this is only being set from ShimProcess::QueueFakeThreadAttachEventsNativeOrder
6329 bool m_fCreationEventQueued;
6330
6331 // Object handle for Exception object in debuggee.
6332 VMPTR_OBJECTHANDLE m_vmExcepObjHandle;
6333
6334public:
6335
6336 //Returns true if current user state of a thread is USER_WAIT_SLEEP_JOIN
6337 bool IsThreadWaitingOrSleeping();
6338
6339 // Returns true if the thread is dead. See function header for definition.
6340 bool IsThreadDead();
6341
6342 // Return CORDBG_E_BAD_THREAD_STATE if the thread is dead.
6343 HRESULT EnsureThreadIsAlive();
6344
6345 // On a RemapBreakpoint, the debugger will eventually call RemapFunction and
6346 // we need to communicate the IP back to LS. So we stash the address of where
6347 // to store the IP here and stuff it in on RemapFunction.
6348 // If we're not at an outstanding RemapOpportunity, this will be NULL
6349 REMOTE_PTR m_EnCRemapFunctionIP;
6350
6351private:
6352 void ClearStackFrameCache();
6353
6354 // True iff this thread has an unhandled exception on it.
6355 // Set high when Filter() gets noitifed of an unhandled exception.
6356 // Set Low if the thread is hijacked.
6357 bool m_fHasUnhandledException;
6358
6359 // Exception record for last unhandled exception on this thread.
6360 // Lazily initialized.
6361 EXCEPTION_RECORD * m_pExceptionRecord;
6362
6363 static const CorDebugUserState kInvalidUserState = CorDebugUserState(-1);
6364 CorDebugUserState m_userState; // This is the current state of the
6365 // thread, at the time that the
6366 // left side synchronized
6367
6368 // NeuterList that's executed when this Thread's stack is refreshed.
6369 // This list is for everything related to stackwalking, i.e. everything which is invalidated
6370 // if the stack changes in any way. This list is cleared when any of the following is called:
6371 // 1) Continue()
6372 // 2) SetIP()
6373 // 3) RemapFunction()
6374 // 4) ICDProcess::SetThreadContext()
6375 NeuterList m_RefreshStackNeuterList;
6376
6377 // The following two data members are used for caching thread handles.
6378 // @dbgtodo - Remove in V3 (can't have local handles with data-target abstraction);
6379 // offload to the shim to support V2 scenarios.
6380 HANDLE m_hCachedThread;
6381 HANDLE m_hCachedOutOfProcThread;
6382};
6383
6384/* ------------------------------------------------------------------------- *
6385 * StackWalk class
6386 * ------------------------------------------------------------------------- */
6387
6388class CordbStackWalk : public CordbBase, public ICorDebugStackWalk
6389{
6390public:
6391 CordbStackWalk(CordbThread * pCordbThread);
6392 virtual ~CordbStackWalk();
6393 virtual void Neuter();
6394
6395 // helper function for Neuter
6396 virtual void DeleteAll();
6397
6398 using CordbBase::GetProcess;
6399
6400#ifdef _DEBUG
6401 virtual const char * DbgGetName() { return "CordbStackWalk"; }
6402#endif
6403
6404 //-----------------------------------------------------------
6405 // IUnknown
6406 //-----------------------------------------------------------
6407
6408 ULONG STDMETHODCALLTYPE AddRef()
6409 {
6410 return (BaseAddRef());
6411 }
6412 ULONG STDMETHODCALLTYPE Release()
6413 {
6414 return (BaseRelease());
6415 }
6416 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6417
6418 //-----------------------------------------------------------
6419 // ICorDebugStackWalk
6420 //-----------------------------------------------------------
6421
6422 COM_METHOD GetContext(ULONG32 contextFlags,
6423 ULONG32 contextBufSize,
6424 ULONG32 * pContextSize,
6425 BYTE pbContextBuf[]);
6426 COM_METHOD SetContext(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[]);
6427 COM_METHOD Next();
6428 COM_METHOD GetFrame(ICorDebugFrame **ppFrame);
6429
6430 //-----------------------------------------------------------
6431 // Internal members
6432 //-----------------------------------------------------------
6433
6434 void SetContextWorker(CorDebugSetContextFlag flag, ULONG32 contextSize, BYTE context[]);
6435 HRESULT GetFrameWorker(ICorDebugFrame **ppFrame);
6436
6437 //-----------------------------------------------------------
6438 // Data members
6439 //-----------------------------------------------------------
6440
6441public:
6442 void Init();
6443
6444private:
6445 // handle legacy V2 hijacking for unhandled hardware exceptions
6446 void CheckForLegacyHijackCase();
6447
6448 // refresh the data for this instance of CordbStackWalk if we have had an IPC event followed by a
6449 // continue since we got the information.
6450 void RefreshIfNeeded();
6451
6452 // unwind the frame and update m_context with the new context
6453 BOOL UnwindStackFrame();
6454
6455 // the thread on which this CordbStackWalk is created
6456 CordbThread * m_pCordbThread;
6457
6458 // This is the same iterator used by the runtime itself.
6459 IDacDbiInterface::StackWalkHandle m_pSFIHandle;
6460
6461 // buffers used for stackwalking
6462 DT_CONTEXT m_context;
6463
6464 // Used to figure out if we have to refresh any reference objects
6465 // on the left side. We set it to CordbProcess::m_flushCounter on
6466 // creation and will check it against that value when we call GetFrame or Next.
6467 // If it doesn't match, an IPC event has occurred and the values will need to be
6468 // refreshed via the DAC.
6469 UINT m_lastSyncFlushCounter;
6470
6471 // cached flag used for refreshing a CordbStackWalk
6472 CorDebugSetContextFlag m_cachedSetContextFlag;
6473
6474 // We unwind one frame ahead of time to get the FramePointer on x86.
6475 // These fields are used for the bookkeeping.
6476 RSSmartPtr<CordbFrame> m_pCachedFrame;
6477 HRESULT m_cachedHR;
6478 bool m_fIsOneFrameAhead;
6479};
6480
6481
6482class CordbContext : public CordbBase, public ICorDebugContext
6483{
6484public:
6485
6486 CordbContext() : CordbBase(NULL, 0, enumCordbContext) {}
6487
6488
6489
6490#ifdef _DEBUG
6491 virtual const char * DbgGetName() { return "CordbContext"; }
6492#endif
6493
6494
6495 //-----------------------------------------------------------
6496 // IUnknown
6497 //-----------------------------------------------------------
6498
6499 ULONG STDMETHODCALLTYPE AddRef()
6500 {
6501 return (BaseAddRef());
6502 }
6503 ULONG STDMETHODCALLTYPE Release()
6504 {
6505 return (BaseRelease());
6506 }
6507 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6508
6509 //-----------------------------------------------------------
6510 // ICorDebugContext
6511 //-----------------------------------------------------------
6512private:
6513
6514} ;
6515
6516
6517/* ------------------------------------------------------------------------- *
6518 * Frame class
6519 * ------------------------------------------------------------------------- */
6520
6521class CordbFrame : public CordbBase, public ICorDebugFrame
6522{
6523protected:
6524 // Ctor to provide dummy frame that just wraps a frame-pointer
6525 CordbFrame(CordbProcess * pProcess, FramePointer fp);
6526
6527public:
6528 CordbFrame(CordbThread * pThread,
6529 FramePointer fp,
6530 SIZE_T ip,
6531 CordbAppDomain * pCurrentAppDomain);
6532
6533 virtual ~CordbFrame();
6534 virtual void Neuter();
6535
6536#ifdef _DEBUG
6537 virtual const char * DbgGetName() { return "CordbFrame"; }
6538#endif
6539
6540 //-----------------------------------------------------------
6541 // IUnknown
6542 //-----------------------------------------------------------
6543
6544 ULONG STDMETHODCALLTYPE AddRef()
6545 {
6546 return (BaseAddRef());
6547 }
6548 ULONG STDMETHODCALLTYPE Release()
6549 {
6550 return (BaseRelease());
6551 }
6552 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6553
6554 //-----------------------------------------------------------
6555 // ICorDebugFrame
6556 //-----------------------------------------------------------
6557
6558 COM_METHOD GetChain(ICorDebugChain **ppChain);
6559
6560 // Derived versions of Frame will implement GetCode.
6561 COM_METHOD GetCode(ICorDebugCode **ppCode) = 0;
6562
6563 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
6564 COM_METHOD GetFunctionToken(mdMethodDef *pToken);
6565
6566 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
6567 COM_METHOD GetCaller(ICorDebugFrame **ppFrame);
6568 COM_METHOD GetCallee(ICorDebugFrame **ppFrame);
6569 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
6570
6571 //-----------------------------------------------------------
6572 // Convenience routines
6573 //-----------------------------------------------------------
6574
6575 CordbAppDomain *GetCurrentAppDomain()
6576 {
6577 return m_currentAppDomain;
6578 }
6579
6580 // Internal helper to get a CordbFunction for this frame.
6581 virtual CordbFunction *GetFunction() = 0;
6582
6583 FramePointer GetFramePointer()
6584 {
6585 return m_fp;
6586 }
6587
6588 //-----------------------------------------------------------
6589 // Data members
6590 //-----------------------------------------------------------
6591
6592 // Accessors to return NULL or typesafe cast to derived frame
6593 virtual CordbInternalFrame * GetAsInternalFrame() { return NULL; }
6594 virtual CordbNativeFrame * GetAsNativeFrame() { return NULL; }
6595
6596 // determine if the frame pointer is in the stack range owned by the frame
6597 bool IsContainedInFrame(FramePointer fp);
6598
6599 // This is basically a complicated cast function. We are casting from an ICorDebugFrame to a CordbFrame.
6600 static CordbFrame* GetCordbFrameFromInterface(ICorDebugFrame *pFrame);
6601
6602 virtual const DT_CONTEXT * GetContext() const { return NULL; }
6603
6604public:
6605 // this represents the IL offset for a CordbJITILFrame, the native offset for a CordbNativeFrame,
6606 // and 0 for a CordbInternalFrame
6607 SIZE_T m_ip;
6608
6609 CordbThread * m_pThread;
6610
6611 CordbAppDomain *m_currentAppDomain;
6612 FramePointer m_fp;
6613
6614protected:
6615 // indicates whether this frame is the leaf frame; lazily initialized
6616 mutable Optional<bool> m_optfIsLeafFrame;
6617
6618private:
6619#ifdef _DEBUG
6620 // For tracking down neutering bugs;
6621 UINT m_DbgContinueCounter;
6622#endif
6623};
6624
6625// Dummy frame that just wraps a frame pointer.
6626// This is used to pass a FramePointer back in the Exception2 callback.
6627// Currently, the callback passes back an ICorDebugFrame as a way of exposing a cross-platform
6628// frame pointer. However passing back an ICDFrame means we need to do a stackwalk, and
6629// that may not be possible in V3:
6630// - the stackwalk is very chatty, and may be too much work just to give an exception notification.
6631// - in 64-bit, we may not even be able to do the stackwalk ourselves.
6632//
6633// The shim can take the framePointer and do the stackwalk and resolve it to a real frame,
6634// so V2 emulation scenarios will continue to work.
6635// @dbgtodo exception - resolve this when we iron out exceptions in V3.
6636class CordbPlaceholderFrame : public CordbFrame
6637{
6638public:
6639 // Ctor to provide dummy frame that just wraps a frame-pointer
6640 CordbPlaceholderFrame(CordbProcess * pProcess, FramePointer fp)
6641 : CordbFrame(pProcess, fp)
6642 {
6643 }
6644
6645#ifdef _DEBUG
6646 virtual const char * DbgGetName() { return "CordbFrame"; }
6647#endif
6648
6649 // Provide dummy implementation for some methods. These should never be called.
6650 COM_METHOD GetCode(ICorDebugCode **ppCode)
6651 {
6652 _ASSERTE(!"Don't call this");
6653 return E_NOTIMPL;
6654 }
6655 virtual CordbFunction *GetFunction()
6656 {
6657 _ASSERTE(!"Don't call this");
6658 return NULL;
6659 }
6660};
6661
6662class CordbInternalFrame : public CordbFrame, public ICorDebugInternalFrame, public ICorDebugInternalFrame2
6663{
6664public:
6665 CordbInternalFrame(CordbThread * pThread,
6666 FramePointer fp,
6667 CordbAppDomain * pCurrentAppDomain,
6668 const DebuggerIPCE_STRData * pData);
6669
6670 CordbInternalFrame(CordbThread * pThread,
6671 FramePointer fp,
6672 CordbAppDomain * pCurrentAppDomain,
6673 CorDebugInternalFrameType frameType,
6674 mdMethodDef funcMetadataToken,
6675 CordbFunction * pFunction,
6676 VMPTR_MethodDesc vmMethodDesc);
6677
6678 virtual void Neuter();
6679
6680#ifdef _DEBUG
6681 virtual const char * DbgGetName() { return "CordbInternalFrame"; }
6682#endif
6683
6684 //-----------------------------------------------------------
6685 // IUnknown
6686 //-----------------------------------------------------------
6687
6688 ULONG STDMETHODCALLTYPE AddRef()
6689 {
6690 return (BaseAddRef());
6691 }
6692 ULONG STDMETHODCALLTYPE Release()
6693 {
6694 return (BaseRelease());
6695 }
6696 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6697
6698 //-----------------------------------------------------------
6699 // ICorDebugFrame
6700 //-----------------------------------------------------------
6701
6702 COM_METHOD GetChain(ICorDebugChain **ppChain)
6703 {
6704 return (CordbFrame::GetChain(ppChain));
6705 }
6706
6707 // We don't expose a code-object for stubs.
6708 COM_METHOD GetCode(ICorDebugCode **ppCode)
6709 {
6710 return CORDBG_E_CODE_NOT_AVAILABLE;
6711 }
6712
6713 COM_METHOD GetFunction(ICorDebugFunction **ppFunction)
6714 {
6715 return (CordbFrame::GetFunction(ppFunction));
6716 }
6717 COM_METHOD GetFunctionToken(mdMethodDef *pToken)
6718 {
6719 return (CordbFrame::GetFunctionToken(pToken));
6720 }
6721
6722 COM_METHOD GetCaller(ICorDebugFrame **ppFrame)
6723 {
6724 return (CordbFrame::GetCaller(ppFrame));
6725 }
6726 COM_METHOD GetCallee(ICorDebugFrame **ppFrame)
6727 {
6728 return (CordbFrame::GetCallee(ppFrame));
6729 }
6730 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper)
6731 {
6732 return E_NOTIMPL;
6733 }
6734
6735 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
6736
6737 //-----------------------------------------------------------
6738 // ICorDebugInternalFrame
6739 //-----------------------------------------------------------
6740
6741 // Get the type of internal frame. This will never be STUBFRAME_NONE.
6742 COM_METHOD GetFrameType(CorDebugInternalFrameType * pType)
6743 {
6744 VALIDATE_POINTER_TO_OBJECT(pType, CorDebugInternalFrameType)
6745 *pType = m_eFrameType;
6746 return S_OK;
6747 }
6748
6749 //-----------------------------------------------------------
6750 // ICorDebugInternalFrame2
6751 //-----------------------------------------------------------
6752
6753 COM_METHOD GetAddress(CORDB_ADDRESS * pAddress);
6754 COM_METHOD IsCloserToLeaf(ICorDebugFrame * pFrameToCompare,
6755 BOOL * pIsCloser);
6756
6757 BOOL IsCloserToLeafWorker(ICorDebugFrame * pFrameToCompare);
6758
6759 //-----------------------------------------------------------
6760 // Non COM methods
6761 //-----------------------------------------------------------
6762
6763 virtual CordbFunction *GetFunction();
6764
6765
6766 // Accessors to return NULL or typesafe cast to derived frame
6767 virtual CordbInternalFrame * GetAsInternalFrame() { return this; }
6768
6769 // accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata
6770 BOOL ConvertInternalFrameForILMethodWithoutMetadata(ICorDebugInternalFrame2 ** ppInternalFrame2);
6771
6772protected:
6773 // the frame type
6774 CorDebugInternalFrameType m_eFrameType;
6775
6776 // the method token of the method (if any) associated with the internal frame
6777 mdMethodDef m_funcMetadataToken;
6778
6779 // the method (if any) associated with the internal frame
6780 RSSmartPtr<CordbFunction> m_function;
6781
6782 VMPTR_MethodDesc m_vmMethodDesc;
6783};
6784
6785//---------------------------------------------------------------------------------------
6786//
6787// This class implements ICorDebugRuntimeUnwindableFrame. It is used to mark a native stack frame
6788// which requires special unwinding and which doesn't correspond to any IL code. It is really
6789// just a marker to tell the debugger to use the managed unwinder. The debugger is still responsible
6790// to do all the inspection and symbol lookup. An example is the hijack stub.
6791//
6792
6793class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUnwindableFrame
6794{
6795public:
6796 CordbRuntimeUnwindableFrame(CordbThread * pThread,
6797 FramePointer fp,
6798 CordbAppDomain * pCurrentAppDomain,
6799 DT_CONTEXT * pContext);
6800
6801 virtual void Neuter();
6802
6803#ifdef _DEBUG
6804 virtual const char * DbgGetName() { return "CordbRuntimeUnwindableFrame"; }
6805#endif
6806
6807 //-----------------------------------------------------------
6808 // IUnknown
6809 //-----------------------------------------------------------
6810
6811 ULONG STDMETHODCALLTYPE AddRef()
6812 {
6813 return (BaseAddRef());
6814 }
6815
6816 ULONG STDMETHODCALLTYPE Release()
6817 {
6818 return (BaseRelease());
6819 }
6820
6821 COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
6822
6823 //-----------------------------------------------------------
6824 // ICorDebugFrame
6825 //-----------------------------------------------------------
6826
6827 //
6828 // Just return E_NOTIMPL for everything.
6829 // See the class comment.
6830 //
6831
6832 COM_METHOD GetChain(ICorDebugChain ** ppChain)
6833 {
6834 return E_NOTIMPL;
6835 }
6836
6837 COM_METHOD GetCode(ICorDebugCode ** ppCode)
6838 {
6839 return E_NOTIMPL;
6840 }
6841
6842 COM_METHOD GetFunction(ICorDebugFunction ** ppFunction)
6843 {
6844 return E_NOTIMPL;
6845 }
6846
6847 COM_METHOD GetFunctionToken(mdMethodDef * pToken)
6848 {
6849 return E_NOTIMPL;
6850 }
6851
6852 COM_METHOD GetCaller(ICorDebugFrame ** ppFrame)
6853 {
6854 return E_NOTIMPL;
6855 }
6856
6857 COM_METHOD GetCallee(ICorDebugFrame ** ppFrame)
6858 {
6859 return E_NOTIMPL;
6860 }
6861
6862 COM_METHOD CreateStepper(ICorDebugStepper ** ppStepper)
6863 {
6864 return E_NOTIMPL;
6865 }
6866
6867 COM_METHOD GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd)
6868 {
6869 return E_NOTIMPL;
6870 }
6871
6872 //-----------------------------------------------------------
6873 // Non COM methods
6874 //-----------------------------------------------------------
6875
6876 virtual CordbFunction * GetFunction()
6877 {
6878 return NULL;
6879 }
6880
6881 virtual const DT_CONTEXT * GetContext() const;
6882
6883private:
6884 DT_CONTEXT m_context;
6885};
6886
6887
6888class CordbValueEnum : public CordbBase, public ICorDebugValueEnum
6889{
6890public:
6891 enum ValueEnumMode {
6892 LOCAL_VARS_ORIGINAL_IL,
6893 LOCAL_VARS_REJIT_IL,
6894 ARGS,
6895 } ;
6896
6897 CordbValueEnum(CordbNativeFrame *frame, ValueEnumMode mode);
6898 HRESULT Init();
6899 ~CordbValueEnum();
6900 virtual void Neuter();
6901
6902#ifdef _DEBUG
6903 virtual const char * DbgGetName() { return "CordbValueEnum"; }
6904#endif
6905
6906
6907 //-----------------------------------------------------------
6908 // IUnknown
6909 //-----------------------------------------------------------
6910
6911 ULONG STDMETHODCALLTYPE AddRef()
6912 {
6913 return (BaseAddRef());
6914 }
6915 ULONG STDMETHODCALLTYPE Release()
6916 {
6917 return (BaseRelease());
6918 }
6919 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
6920
6921 //-----------------------------------------------------------
6922 // ICorDebugEnum
6923 //-----------------------------------------------------------
6924
6925 COM_METHOD Skip(ULONG celt);
6926 COM_METHOD Reset();
6927 COM_METHOD Clone(ICorDebugEnum **ppEnum);
6928 COM_METHOD GetCount(ULONG *pcelt);
6929
6930 //-----------------------------------------------------------
6931 // ICorDebugValueEnum
6932 //-----------------------------------------------------------
6933
6934 COM_METHOD Next(ULONG celt, ICorDebugValue *values[], ULONG *pceltFetched);
6935
6936private:
6937 CordbNativeFrame* m_frame;
6938 ValueEnumMode m_mode;
6939 UINT m_iCurrent;
6940 UINT m_iMax;
6941};
6942
6943
6944/* ------------------------------------------------------------------------- *
6945 * Misc Info for the Native Frame class
6946 * ------------------------------------------------------------------------- */
6947
6948struct CordbMiscFrame
6949{
6950public:
6951 CordbMiscFrame();
6952
6953 // new-style constructor
6954 CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData);
6955
6956#ifdef WIN64EXCEPTIONS
6957 SIZE_T parentIP;
6958 FramePointer fpParentOrSelf;
6959 bool fIsFilterFunclet;
6960#endif // WIN64EXCEPTIONS
6961};
6962
6963
6964/* ------------------------------------------------------------------------- *
6965 * Native Frame class
6966 * ------------------------------------------------------------------------- */
6967
6968class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public ICorDebugNativeFrame2
6969{
6970public:
6971 CordbNativeFrame(CordbThread * pThread,
6972 FramePointer fp,
6973 CordbNativeCode * pNativeCode,
6974 SIZE_T ip,
6975 DebuggerREGDISPLAY * pDRD,
6976 TADDR addrAmbientESP,
6977 bool fQuicklyUnwound,
6978 CordbAppDomain * pCurrentAppDomain,
6979 CordbMiscFrame * pMisc = NULL,
6980 DT_CONTEXT * pContext = NULL);
6981 virtual ~CordbNativeFrame();
6982 virtual void Neuter();
6983
6984#ifdef _DEBUG
6985 virtual const char * DbgGetName() { return "CordbNativeFrame"; }
6986#endif
6987
6988 //-----------------------------------------------------------
6989 // IUnknown
6990 //-----------------------------------------------------------
6991
6992 ULONG STDMETHODCALLTYPE AddRef()
6993 {
6994 return (BaseAddRef());
6995 }
6996 ULONG STDMETHODCALLTYPE Release()
6997 {
6998 return (BaseRelease());
6999 }
7000 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7001
7002 //-----------------------------------------------------------
7003 // ICorDebugFrame
7004 //-----------------------------------------------------------
7005
7006 COM_METHOD GetChain(ICorDebugChain **ppChain)
7007 {
7008 return (CordbFrame::GetChain(ppChain));
7009 }
7010 COM_METHOD GetCode(ICorDebugCode **ppCode);
7011 COM_METHOD GetFunction(ICorDebugFunction **ppFunction)
7012 {
7013 return (CordbFrame::GetFunction(ppFunction));
7014 }
7015 COM_METHOD GetFunctionToken(mdMethodDef *pToken)
7016 {
7017 return (CordbFrame::GetFunctionToken(pToken));
7018 }
7019 COM_METHOD GetCaller(ICorDebugFrame **ppFrame)
7020 {
7021 return (CordbFrame::GetCaller(ppFrame));
7022 }
7023 COM_METHOD GetCallee(ICorDebugFrame **ppFrame)
7024 {
7025 return (CordbFrame::GetCallee(ppFrame));
7026 }
7027 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper)
7028 {
7029 return (CordbFrame::CreateStepper(ppStepper));
7030 }
7031
7032 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
7033
7034 //-----------------------------------------------------------
7035 // ICorDebugNativeFrame
7036 //-----------------------------------------------------------
7037
7038 COM_METHOD GetIP(ULONG32* pnOffset);
7039 COM_METHOD SetIP(ULONG32 nOffset);
7040 COM_METHOD GetRegisterSet(ICorDebugRegisterSet **ppRegisters);
7041 COM_METHOD GetLocalRegisterValue(CorDebugRegister reg,
7042 ULONG cbSigBlob,
7043 PCCOR_SIGNATURE pvSigBlob,
7044 ICorDebugValue ** ppValue);
7045
7046 COM_METHOD GetLocalDoubleRegisterValue(CorDebugRegister highWordReg,
7047 CorDebugRegister lowWordReg,
7048 ULONG cbSigBlob,
7049 PCCOR_SIGNATURE pvSigBlob,
7050 ICorDebugValue ** ppValue);
7051
7052 COM_METHOD GetLocalMemoryValue(CORDB_ADDRESS address,
7053 ULONG cbSigBlob,
7054 PCCOR_SIGNATURE pvSigBlob,
7055 ICorDebugValue ** ppValue);
7056
7057 COM_METHOD GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
7058 CORDB_ADDRESS lowWordAddress,
7059 ULONG cbSigBlob,
7060 PCCOR_SIGNATURE pvSigBlob,
7061 ICorDebugValue ** ppValue);
7062
7063 COM_METHOD GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
7064 CorDebugRegister lowWordRegister,
7065 ULONG cbSigBlob,
7066 PCCOR_SIGNATURE pvSigBlob,
7067 ICorDebugValue ** ppValue);
7068
7069 COM_METHOD CanSetIP(ULONG32 nOffset);
7070
7071 //-----------------------------------------------------------
7072 // ICorDebugNativeFrame2
7073 //-----------------------------------------------------------
7074
7075 COM_METHOD IsChild(BOOL * pIsChild);
7076
7077 COM_METHOD IsMatchingParentFrame(ICorDebugNativeFrame2 *pPotentialParentFrame,
7078 BOOL * pIsParent);
7079
7080 COM_METHOD GetStackParameterSize(ULONG32 * pSize);
7081
7082 //-----------------------------------------------------------
7083 // Non-COM members
7084 //-----------------------------------------------------------
7085
7086 // Accessors to return NULL or typesafe cast to derived frame
7087 virtual CordbNativeFrame * GetAsNativeFrame() { return this; }
7088
7089 CordbFunction * GetFunction();
7090 CordbNativeCode * GetNativeCode();
7091 virtual const DT_CONTEXT * GetContext() const;
7092
7093 // Given the native variable information of a variable, return its value.
7094 // This function assumes that the value is either in a register or on the stack
7095 // (i.e. VLT_REG or VLT_STK).
7096 SIZE_T GetRegisterOrStackValue(const ICorDebugInfo::NativeVarInfo * pNativeVarInfo);
7097
7098 HRESULT GetLocalRegisterValue(CorDebugRegister reg,
7099 CordbType * pType,
7100 ICorDebugValue **ppValue);
7101 HRESULT GetLocalDoubleRegisterValue(CorDebugRegister highWordReg,
7102 CorDebugRegister lowWordReg,
7103 CordbType * pType,
7104 ICorDebugValue **ppValue);
7105 HRESULT GetLocalMemoryValue(CORDB_ADDRESS address,
7106 CordbType * pType,
7107 ICorDebugValue **ppValue);
7108 HRESULT GetLocalByRefMemoryValue(CORDB_ADDRESS address,
7109 CordbType * pType,
7110 ICorDebugValue **ppValue);
7111 HRESULT GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
7112 CORDB_ADDRESS lowWordAddress,
7113 CordbType * pType,
7114 ICorDebugValue **ppValue);
7115 HRESULT GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
7116 CorDebugRegister lowWordRegister,
7117 CordbType * pType,
7118 ICorDebugValue **ppValue);
7119 UINT_PTR * GetAddressOfRegister(CorDebugRegister regNum) const;
7120 CORDB_ADDRESS GetLeftSideAddressOfRegister(CorDebugRegister regNum) const;
7121 HRESULT GetLocalFloatingPointValue(DWORD index,
7122 CordbType * pType,
7123 ICorDebugValue **ppValue);
7124
7125
7126 CORDB_ADDRESS GetLSStackAddress(ICorDebugInfo::RegNum regNum, signed offset);
7127
7128 bool IsLeafFrame() const;
7129
7130 // Return the offset used for inspection purposes.
7131 // Refer to the comment at the beginning of the function definition in RsThread.cpp for more information.
7132 SIZE_T GetInspectionIP();
7133
7134 ULONG32 GetIPOffset();
7135
7136 // whether this is a funclet frame
7137 bool IsFunclet();
7138 bool IsFilterFunclet();
7139
7140#ifdef WIN64EXCEPTIONS
7141 // return the offset of the parent method frame at which an exception occurs
7142 SIZE_T GetParentIP();
7143#endif // WIN64EXCEPTIONS
7144
7145 TADDR GetAmbientESP() { return m_taAmbientESP; }
7146 TADDR GetReturnRegisterValue();
7147
7148 // accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata
7149 BOOL ConvertNativeFrameForILMethodWithoutMetadata(ICorDebugInternalFrame2 ** ppInternalFrame2);
7150
7151 //-----------------------------------------------------------
7152 // Data members
7153 //-----------------------------------------------------------
7154
7155public:
7156 // the register set
7157 DebuggerREGDISPLAY m_rd;
7158
7159 // This field is only true for Enter-Managed chain. It means that the register set is invalid.
7160 bool m_quicklyUnwound;
7161
7162 // each CordbNativeFrame corresponds to exactly one CordbJITILFrame and one CordbNativeCode
7163 RSSmartPtr<CordbJITILFrame> m_JITILFrame;
7164 RSSmartPtr<CordbNativeCode> m_nativeCode;
7165
7166 // auxiliary information only used on 64-bit to find the parent stack pointer and offset for funclets
7167 CordbMiscFrame m_misc;
7168
7169private:
7170 // the ambient SP value only used on x86 to retrieve sp-relative local variables
7171 // (most likely in a frameless method)
7172 TADDR m_taAmbientESP;
7173
7174 // @dbgtodo inspection - When we DACize the various Cordb*Value classes, we should consider getting rid of the
7175 // DebuggerREGDISPLAY and just use the CONTEXT. A lot of simplification can be done here.
7176 DT_CONTEXT m_context;
7177};
7178
7179
7180/* ------------------------------------------------------------------------- *
7181 * CordbRegisterSet class
7182 *
7183 * This can be obtained via GetRegisterSet from
7184 * CordbNativeFrame
7185 * CordbThread
7186 *
7187 * ------------------------------------------------------------------------- */
7188
7189#define SETBITULONG64( x ) ( (ULONG64)1 << (x) )
7190#define SET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] |= (1 << ((_reg) & 7)))
7191#define RESET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] &= ~(1 << ((_reg) & 7)))
7192#define IS_SET_BIT_MASK(_mask, _reg) (_mask[(_reg) >> 3] & (1 << ((_reg) & 7)))
7193
7194
7195class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public ICorDebugRegisterSet2
7196{
7197public:
7198 CordbRegisterSet(DebuggerREGDISPLAY * pRegDisplay,
7199 CordbThread * pThread,
7200 bool fActive,
7201 bool fQuickUnwind,
7202 bool fTakeOwnershipOfDRD = false);
7203
7204
7205 ~CordbRegisterSet();
7206
7207
7208
7209 virtual void Neuter();
7210
7211#ifdef _DEBUG
7212 virtual const char * DbgGetName() { return "CordbRegisterSet"; }
7213#endif
7214
7215 //-----------------------------------------------------------
7216 // IUnknown
7217 //-----------------------------------------------------------
7218
7219 ULONG STDMETHODCALLTYPE AddRef()
7220 {
7221 return (BaseAddRefEnforceExternal());
7222 }
7223 ULONG STDMETHODCALLTYPE Release()
7224 {
7225 return (BaseReleaseEnforceExternal());
7226 }
7227
7228 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7229
7230
7231
7232 //-----------------------------------------------------------
7233 // ICorDebugRegisterSet
7234 // More extensive explanation are in Src/inc/CorDebug.idl
7235 //-----------------------------------------------------------
7236 COM_METHOD GetRegistersAvailable(ULONG64 *pAvailable);
7237
7238 COM_METHOD GetRegisters(ULONG64 mask,
7239 ULONG32 regCount,
7240 CORDB_REGISTER regBuffer[]);
7241 COM_METHOD SetRegisters( ULONG64 mask,
7242 ULONG32 regCount,
7243 CORDB_REGISTER regBuffer[])
7244 {
7245 LIMITED_METHOD_CONTRACT;
7246
7247 VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER,
7248 regCount, true, true);
7249
7250 return E_NOTIMPL;
7251 }
7252
7253 COM_METHOD GetThreadContext(ULONG32 contextSize, BYTE context[]);
7254
7255 // SetThreadContexthad a very problematic implementation in v1.1.
7256 // We've ripped it out in V2.0 and E_NOTIMPL it. See V1.1 sources for what it used to look like
7257 // in case we ever want to re-add it.
7258 // If we ever re-implement it consider the following:
7259 // - must fail on non-leaf frames (just check m_active).
7260 // - must make sure that GetThreadContext() is fully accurate. If we don't have SetThCtx, then
7261 // GetThreadCtx bugs are much more benign.
7262 // - be sure to update any shared reg displays (what if a frame + chain have the same rd) and
7263 // also update any cached contexts (such as CordbThread::m_context).
7264 // - be sure to honor the context flags and only setting what we can set.
7265 //
7266 // Friday, July 16, 2004. (This date will be useful for Source control history)
7267 COM_METHOD SetThreadContext(ULONG32 contextSize, BYTE context[])
7268 {
7269 return E_NOTIMPL;
7270 }
7271
7272 //-----------------------------------------------------------
7273 // ICorDebugRegisterSet2
7274 // More extensive explanation are in Src/inc/CorDebug.idl
7275 //-----------------------------------------------------------
7276 COM_METHOD GetRegistersAvailable(ULONG32 regCount,
7277 BYTE pAvailable[]);
7278
7279 COM_METHOD GetRegisters(ULONG32 maskCount,
7280 BYTE mask[],
7281 ULONG32 regCount,
7282 CORDB_REGISTER regBuffer[]);
7283
7284 COM_METHOD SetRegisters(ULONG32 maskCount,
7285 BYTE mask[],
7286 ULONG32 regCount,
7287 CORDB_REGISTER regBuffer[])
7288 {
7289 LIMITED_METHOD_CONTRACT;
7290
7291 VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER,
7292 regCount, true, true);
7293
7294 return E_NOTIMPL;
7295 }
7296
7297protected:
7298 // Platform specific helper for GetThreadContext.
7299 void InternalCopyRDToContext(DT_CONTEXT * pContext);
7300
7301 // Adapters to impl v2.0 interfaces on top of v1.0 interfaces.
7302 HRESULT GetRegistersAvailableAdapter(ULONG32 regCount, BYTE pAvailable[]);
7303 HRESULT GetRegistersAdapter(ULONG32 maskCount, BYTE mask[], ULONG32 regCount, CORDB_REGISTER regBuffer[]);
7304
7305
7306 // This CordbRegisterSet is responsible to free this memory if m_fTakeOwnershipOfDRD is true. Otherwise,
7307 // this memory is freed by the CordbNativeFrame or CordbThread which creates this CordbRegisterSet.
7308 DebuggerREGDISPLAY *m_rd;
7309 CordbThread *m_thread;
7310 bool m_active; // true if we're the leafmost register set.
7311 bool m_quickUnwind;
7312
7313 // true if the CordbRegisterSet owns the DebuggerREGDISPLAY pointer and needs to free the memory
7314 bool m_fTakeOwnershipOfDRD;
7315} ;
7316
7317
7318
7319
7320/* ------------------------------------------------------------------------- *
7321 * JIT-IL Frame class
7322 * ------------------------------------------------------------------------- */
7323
7324class CordbJITILFrame : public CordbBase, public ICorDebugILFrame, public ICorDebugILFrame2, public ICorDebugILFrame3, public ICorDebugILFrame4
7325{
7326public:
7327 CordbJITILFrame(CordbNativeFrame * pNativeFrame,
7328 CordbILCode * pCode,
7329 UINT_PTR ip,
7330 CorDebugMappingResult mapping,
7331 GENERICS_TYPE_TOKEN exactGenericArgsToken,
7332 DWORD dwExactGenericArgsTokenIndex,
7333 bool fVarArgFnx,
7334 CordbReJitILCode * pReJitCode);
7335 HRESULT Init();
7336 virtual ~CordbJITILFrame();
7337 virtual void Neuter();
7338
7339
7340#ifdef _DEBUG
7341 virtual const char * DbgGetName() { return "CordbJITILFrame"; }
7342#endif
7343
7344 //-----------------------------------------------------------
7345 // IUnknown
7346 //-----------------------------------------------------------
7347
7348 ULONG STDMETHODCALLTYPE AddRef()
7349 {
7350 return (BaseAddRef());
7351 }
7352 ULONG STDMETHODCALLTYPE Release()
7353 {
7354 return (BaseRelease());
7355 }
7356 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7357
7358 //-----------------------------------------------------------
7359 // ICorDebugFrame
7360 //-----------------------------------------------------------
7361
7362 COM_METHOD GetChain(ICorDebugChain **ppChain);
7363 COM_METHOD GetCode(ICorDebugCode **ppCode);
7364 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
7365 COM_METHOD GetFunctionToken(mdMethodDef *pToken);
7366 COM_METHOD GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd);
7367 COM_METHOD CreateStepper(ICorDebugStepper **ppStepper);
7368 COM_METHOD GetCaller(ICorDebugFrame **ppFrame);
7369 COM_METHOD GetCallee(ICorDebugFrame **ppFrame);
7370
7371 //-----------------------------------------------------------
7372 // ICorDebugILFrame
7373 //-----------------------------------------------------------
7374
7375 COM_METHOD GetIP(ULONG32* pnOffset, CorDebugMappingResult *pMappingResult);
7376 COM_METHOD SetIP(ULONG32 nOffset);
7377 COM_METHOD EnumerateLocalVariables(ICorDebugValueEnum **ppValueEnum);
7378 COM_METHOD GetLocalVariable(DWORD dwIndex, ICorDebugValue **ppValue);
7379 COM_METHOD EnumerateArguments(ICorDebugValueEnum **ppValueEnum);
7380 COM_METHOD GetArgument(DWORD dwIndex, ICorDebugValue ** ppValue);
7381 COM_METHOD GetStackDepth(ULONG32 *pDepth);
7382 COM_METHOD GetStackValue(DWORD dwIndex, ICorDebugValue **ppValue);
7383 COM_METHOD CanSetIP(ULONG32 nOffset);
7384
7385 //-----------------------------------------------------------
7386 // ICorDebugILFrame2
7387 //-----------------------------------------------------------
7388
7389 // Called at an EnC remap opportunity to remap to the latest version of a function
7390 COM_METHOD RemapFunction(ULONG32 nOffset);
7391
7392 COM_METHOD EnumerateTypeParameters(ICorDebugTypeEnum **ppTyParEnum);
7393
7394 //-----------------------------------------------------------
7395 // ICorDebugILFrame3
7396 //-----------------------------------------------------------
7397
7398 COM_METHOD GetReturnValueForILOffset(ULONG32 ILoffset, ICorDebugValue** ppReturnValue);
7399
7400 //-----------------------------------------------------------
7401 // ICorDebugILFrame4
7402 //-----------------------------------------------------------
7403
7404 COM_METHOD EnumerateLocalVariablesEx(ILCodeKind flags, ICorDebugValueEnum **ppValueEnum);
7405 COM_METHOD GetLocalVariableEx(ILCodeKind flags, DWORD dwIndex, ICorDebugValue **ppValue);
7406 COM_METHOD GetCodeEx(ILCodeKind flags, ICorDebugCode **ppCode);
7407
7408 //-----------------------------------------------------------
7409 // Non-COM methods
7410 //-----------------------------------------------------------
7411
7412 CordbModule *GetModule();
7413
7414 HRESULT GetNativeVariable(CordbType *type,
7415 const ICorDebugInfo::NativeVarInfo *pNativeVarInfo,
7416 ICorDebugValue **ppValue);
7417
7418 CordbAppDomain *GetCurrentAppDomain();
7419
7420 CordbFunction *GetFunction();
7421
7422 // ILVariableToNative serves to let the frame intercept accesses
7423 // to var args variables.
7424 HRESULT ILVariableToNative(DWORD dwIndex,
7425 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
7426
7427 // Fills in our array of var args variables
7428 HRESULT FabricateNativeInfo(DWORD dwIndex,
7429 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo);
7430
7431 HRESULT GetArgumentType(DWORD dwIndex,
7432 CordbType ** ppResultType);
7433
7434 // load the generics type and method arguments into a cache
7435 void LoadGenericArgs();
7436
7437 HRESULT QueryInterfaceInternal(REFIID id, void** pInterface);
7438
7439 // Builds an generic Instaniation object from the mdClass and generic signature
7440 // for what we are calling into.
7441 static HRESULT BuildInstantiationForCallsite(CordbModule *pModule, NewArrayHolder<CordbType*> &types, Instantiation &inst, Instantiation *currentInstantiation, mdToken targetClass, SigParser funcGenerics);
7442
7443 CordbILCode* GetOriginalILCode();
7444 CordbReJitILCode* GetReJitILCode();
7445
7446private:
7447 void RefreshCachedVarArgSigParserIfNeeded();
7448
7449 // Worker function for GetReturnValueForILOffset.
7450 HRESULT GetReturnValueForILOffsetImpl(ULONG32 ILoffset, ICorDebugValue** ppReturnValue);
7451
7452 // Given pType, fills ppReturnValue with the correct value.
7453 HRESULT GetReturnValueForType(CordbType *pType, ICorDebugValue **ppReturnValue);
7454
7455 //-----------------------------------------------------------
7456 // Data members
7457 //-----------------------------------------------------------
7458
7459public:
7460 // each CordbJITILFrame corresponds to exactly one CordbNativeFrame and one CordbILCode
7461 CordbNativeFrame * m_nativeFrame;
7462 CordbILCode * m_ilCode;
7463
7464 // the IL offset and the mapping result for the offset
7465 UINT_PTR m_ip;
7466 CorDebugMappingResult m_mapping;
7467
7468 // <vararg-specific fields>
7469
7470 // whether this is a vararg function
7471 bool m_fVarArgFnx;
7472
7473 // the number of arguments, including the var args
7474 ULONG m_allArgsCount;
7475
7476 // This byte array is used to store the signature for vararg methods.
7477 // It points to the underlying memory used by m_sigParserCached, and it enables us to easily delete
7478 // the underlying memory when the CordbJITILFrame is neutered.
7479 BYTE * m_rgbSigParserBuf;
7480
7481 // Do not mutate this, instead make copies of it and use the copies, that way we are guaranteed to
7482 // start at the correct position in the signature each time.
7483 // The underlying memory used for the signature in the SigParser must not be in the DAC cache.
7484 // Otherwise it may be flushed underneath us, and we would AV when we try to access it.
7485 SigParser m_sigParserCached;
7486
7487 // the address of the first arg; only used for vararg functions
7488 CORDB_ADDRESS m_FirstArgAddr;
7489
7490 // This is an array of variable information for the arguments.
7491 // The variable information is fabricated by the RS.
7492 ICorDebugInfo::NativeVarInfo * m_rgNVI;
7493
7494 // </vararg-specific fields>
7495
7496 Instantiation m_genericArgs; // the generics type arguments
7497 BOOL m_genericArgsLoaded; // whether we have loaded and cached the generics type arguments
7498
7499 // An extra token to help fetch information about any generic
7500 // parameters passed to the method, perhaps dynamically.
7501 // This is the so-called generics type context/token.
7502 //
7503 // This token comes from the stackwalker and it may be NULL, in which case we need to retrieve the token
7504 // ourselves using m_dwFrameParamsTokenIndex and the variable lifetime information.
7505 GENERICS_TYPE_TOKEN m_frameParamsToken;
7506
7507 // IL Variable index of the Generics Arg Token.
7508 DWORD m_dwFrameParamsTokenIndex;
7509
7510 // if this frame is instrumented with rejit, this will point to the instrumented IL code
7511 RSSmartPtr<CordbReJitILCode> m_pReJitCode;
7512};
7513
7514/* ------------------------------------------------------------------------- *
7515 * Breakpoint class
7516 * ------------------------------------------------------------------------- */
7517
7518enum CordbBreakpointType
7519{
7520 CBT_FUNCTION,
7521 CBT_MODULE,
7522 CBT_VALUE
7523};
7524
7525class CordbBreakpoint : public CordbBase, public ICorDebugBreakpoint
7526{
7527public:
7528 CordbBreakpoint(CordbProcess * pProcess, CordbBreakpointType bpType);
7529 virtual void Neuter();
7530
7531#ifdef _DEBUG
7532 virtual const char * DbgGetName() { return "CordbBreakpoint"; }
7533#endif
7534
7535 //-----------------------------------------------------------
7536 // IUnknown
7537 //-----------------------------------------------------------
7538
7539 ULONG STDMETHODCALLTYPE AddRef()
7540 {
7541 return (BaseAddRef());
7542 }
7543 ULONG STDMETHODCALLTYPE Release()
7544 {
7545 return (BaseRelease());
7546 }
7547 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7548
7549 //-----------------------------------------------------------
7550 // ICorDebugBreakpoint
7551 //-----------------------------------------------------------
7552
7553 COM_METHOD BaseIsActive(BOOL *pbActive);
7554
7555 //-----------------------------------------------------------
7556 // Non-COM methods
7557 //-----------------------------------------------------------
7558 CordbBreakpointType GetBPType()
7559 {
7560 return m_type;
7561 }
7562
7563 virtual void Disconnect() {}
7564
7565 CordbAppDomain *GetAppDomain()
7566 {
7567 return m_pAppDomain;
7568 }
7569 //-----------------------------------------------------------
7570 // Data members
7571 //-----------------------------------------------------------
7572
7573public:
7574 bool m_active;
7575 CordbAppDomain *m_pAppDomain;
7576 CordbBreakpointType m_type;
7577};
7578
7579/* ------------------------------------------------------------------------- *
7580 * Function Breakpoint class
7581 * ------------------------------------------------------------------------- */
7582
7583class CordbFunctionBreakpoint : public CordbBreakpoint,
7584 public ICorDebugFunctionBreakpoint
7585{
7586public:
7587 CordbFunctionBreakpoint(CordbCode *code, SIZE_T offset, BOOL offsetIsIl);
7588 ~CordbFunctionBreakpoint();
7589
7590 virtual void Neuter();
7591#ifdef _DEBUG
7592 virtual const char * DbgGetName() { return "CordbFunctionBreakpoint"; }
7593#endif
7594
7595
7596 //-----------------------------------------------------------
7597 // IUnknown
7598 //-----------------------------------------------------------
7599
7600 ULONG STDMETHODCALLTYPE AddRef()
7601 {
7602 return (BaseAddRef());
7603 }
7604 ULONG STDMETHODCALLTYPE Release()
7605 {
7606 return (BaseRelease());
7607 }
7608 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7609
7610 //-----------------------------------------------------------
7611 // ICorDebugBreakpoint
7612 //-----------------------------------------------------------
7613
7614 COM_METHOD GetFunction(ICorDebugFunction **ppFunction);
7615 COM_METHOD GetOffset(ULONG32 *pnOffset);
7616 COM_METHOD Activate(BOOL bActive);
7617 COM_METHOD IsActive(BOOL *pbActive)
7618 {
7619 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
7620
7621 return BaseIsActive(pbActive);
7622 }
7623
7624 //-----------------------------------------------------------
7625 // Non-COM methods
7626 //-----------------------------------------------------------
7627
7628 void Disconnect();
7629
7630 //-----------------------------------------------------------
7631 // Convenience routines
7632 //-----------------------------------------------------------
7633
7634
7635 //-----------------------------------------------------------
7636 // Data members
7637 //-----------------------------------------------------------
7638
7639 // Get a point to the LS BP object.
7640 LSPTR_BREAKPOINT GetLsPtrBP();
7641public:
7642
7643 // We need to have a strong pointer because we may access the m_code object after we're neutered.
7644 // @todo - use external pointer b/c Breakpoints aren't yet rooted, and so this reference could be
7645 // leaked.
7646 RSExtSmartPtr<CordbCode> m_code;
7647 SIZE_T m_offset;
7648 BOOL m_offsetIsIl;
7649};
7650
7651/* ------------------------------------------------------------------------- *
7652 * Module Breakpoint class
7653 * ------------------------------------------------------------------------- */
7654
7655class CordbModuleBreakpoint : public CordbBreakpoint,
7656 public ICorDebugModuleBreakpoint
7657{
7658public:
7659 CordbModuleBreakpoint(CordbModule *pModule);
7660
7661
7662
7663#ifdef _DEBUG
7664 virtual const char * DbgGetName() { return "CordbModuleBreakpoint"; }
7665#endif
7666
7667
7668 //-----------------------------------------------------------
7669 // IUnknown
7670 //-----------------------------------------------------------
7671
7672 ULONG STDMETHODCALLTYPE AddRef()
7673 {
7674 return (BaseAddRef());
7675 }
7676 ULONG STDMETHODCALLTYPE Release()
7677 {
7678 return (BaseRelease());
7679 }
7680 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7681
7682 //-----------------------------------------------------------
7683 // ICorDebugModuleBreakpoint
7684 //-----------------------------------------------------------
7685
7686 COM_METHOD GetModule(ICorDebugModule **ppModule);
7687 COM_METHOD Activate(BOOL bActive);
7688 COM_METHOD IsActive(BOOL *pbActive)
7689 {
7690 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
7691
7692 return BaseIsActive(pbActive);
7693 }
7694
7695 //-----------------------------------------------------------
7696 // Non-COM methods
7697 //-----------------------------------------------------------
7698
7699 void Disconnect();
7700
7701public:
7702 CordbModule *m_module;
7703};
7704
7705
7706/* ------------------------------------------------------------------------- *
7707 * Stepper class
7708 * ------------------------------------------------------------------------- */
7709
7710class CordbStepper : public CordbBase, public ICorDebugStepper, public ICorDebugStepper2
7711{
7712public:
7713 CordbStepper(CordbThread *thread, CordbFrame *frame = NULL);
7714
7715
7716
7717#ifdef _DEBUG
7718 virtual const char * DbgGetName() { return "CordbStepper"; }
7719#endif
7720
7721
7722 //-----------------------------------------------------------
7723 // IUnknown
7724 //-----------------------------------------------------------
7725
7726 ULONG STDMETHODCALLTYPE AddRef()
7727 {
7728 return (BaseAddRef());
7729 }
7730 ULONG STDMETHODCALLTYPE Release()
7731 {
7732 return (BaseRelease());
7733 }
7734 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
7735
7736 //-----------------------------------------------------------
7737 // ICorDebugStepper
7738 //-----------------------------------------------------------
7739
7740 COM_METHOD IsActive(BOOL *pbActive);
7741 COM_METHOD Deactivate();
7742 COM_METHOD SetInterceptMask(CorDebugIntercept mask);
7743 COM_METHOD SetUnmappedStopMask(CorDebugUnmappedStop mask);
7744 COM_METHOD Step(BOOL bStepIn);
7745 COM_METHOD StepRange(BOOL bStepIn,
7746 COR_DEBUG_STEP_RANGE ranges[],
7747 ULONG32 cRangeCount);
7748 COM_METHOD StepOut();
7749 COM_METHOD SetRangeIL(BOOL bIL);
7750
7751 //-----------------------------------------------------------
7752 // ICorDebugStepper2
7753 //-----------------------------------------------------------
7754 COM_METHOD SetJMC(BOOL fIsJMCStepper);
7755
7756 //-----------------------------------------------------------
7757 // Convenience routines
7758 //-----------------------------------------------------------
7759
7760 CordbAppDomain *GetAppDomain()
7761 {
7762 return (m_thread->GetAppDomain());
7763 }
7764
7765 LSPTR_STEPPER GetLsPtrStepper();
7766
7767 //-----------------------------------------------------------
7768 // Data members
7769 //-----------------------------------------------------------
7770
7771 CordbThread *m_thread;
7772 CordbFrame *m_frame;
7773 REMOTE_PTR m_stepperToken;
7774 bool m_active;
7775 bool m_rangeIL;
7776 bool m_fIsJMCStepper;
7777 CorDebugUnmappedStop m_rgfMappingStop;
7778 CorDebugIntercept m_rgfInterceptStop;
7779};
7780
7781#define REG_SIZE sizeof(SIZE_T)
7782
7783// class RegisterInfo: encapsulates information necessary to identify and access a specific register in a
7784// register display
7785class RegisterInfo
7786{
7787public:
7788 // constructor for an instance of RegisterInfo
7789 // Arguments:
7790 // input: kNumber - value from CorDebugRegister to identify the register
7791 // addr - address in remote register display that holds the value
7792 // output: no out parameters, but this instance of RegisterInfo has been initialized
7793 RegisterInfo(const CorDebugRegister kNumber, CORDB_ADDRESS addr, SIZE_T value):
7794 m_kRegNumber((CorDebugRegister)kNumber),
7795 m_regAddr(addr),
7796 m_regValue(value)
7797 {};
7798
7799
7800 // copy constructor
7801 // Arguments:
7802 // input: regInfo - register info from which the values for this instance will come
7803 // output: no out parameters, but this instance of RegisterInfo has been initialized
7804 RegisterInfo(const RegisterInfo * pRegInfo):
7805 m_kRegNumber(pRegInfo->m_kRegNumber),
7806 m_regAddr(pRegInfo->m_regAddr),
7807 m_regValue(pRegInfo->m_regValue)
7808 {};
7809
7810
7811 //-------------------------------------
7812 // data members
7813 //-------------------------------------
7814
7815 // enumeration value to identify the register, e.g., REGISTER_X86_EAX, or REGISTER_AMD64_XMM0
7816 CorDebugRegister m_kRegNumber;
7817
7818 // address in a context or frame register display of the register value
7819 CORDB_ADDRESS m_regAddr;
7820
7821 // the actual value of the register
7822 SIZE_T m_regValue;
7823}; // class RegisterInfo
7824
7825// class EnregisteredValueHome: abstract class to encapsulate basic information for a register value, and
7826// serve as a base class for values residing in register-based locations, such as a single register, a
7827// register pair, or a register and memory location.
7828class EnregisteredValueHome
7829{
7830public:
7831
7832 // constructor to initialize an instance of EnregisteredValueHome
7833 EnregisteredValueHome(const CordbNativeFrame * pFrame);
7834
7835 virtual ~EnregisteredValueHome() {}
7836
7837 // virtual "copy constructor" to make a copy of "this" to be owned by a different instance of
7838 // Cordb*Value. If an instance of CordbVCObjectValue represents an enregistered value class, it means
7839 // there is a single field. This implies that the register for the CordbVCObject instance is the same as
7840 // the register for its field. When we create a Cordb*Value to represent this field, we need to make a
7841 // copy of the EnregisteredValueHome belonging to the CordbVCObject instance to become the
7842 // EnregisteredValueHome of the Cord*Value representing the field.
7843 // returns:
7844 // a new cloned copy of this object, allocated on the heap.
7845 // Caller is responsible for deleting the memory (using the standard delete operator).
7846 // note:
7847 // C++ allows derived implementations to differ on return type, thus allowing
7848 // derived impls to return the cloned copy as its actual derived type, and not just as a base type.
7849
7850
7851 virtual
7852 EnregisteredValueHome * Clone() const = 0;
7853
7854 // set a remote enregistered location to a new value
7855 // Arguments:
7856 // input: pNewValue - buffer containing the new value along with its size
7857 // pContext - context from which the value comes
7858 // fIsSigned - indicates whether the value is signed or not. The value provided may be smaller than
7859 // a register, in which case we'll need to extend it to a full register width. To do this
7860 // correctly, we need to know whether to sign extend or zero extend. Currently, only
7861 // the RegValueHome virtual function uses this, but we may need it if we introduce
7862 // types that don't completely occupy the size of two registers.
7863 // output: updates the remote enregistered value on success
7864 // Note: Throws E_FAIL for invalid input or various HRESULTs from an
7865 // unsuccessful call to WriteProcessMemory
7866 virtual
7867 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) = 0;
7868
7869 // Gets an enregistered value and returns it to the caller
7870 // Arguments:
7871 // input: pValueOutBuffer - buffer in which to return the value, along with its size
7872 // output: pValueOutBuffer - filled with the value
7873 // Note: Throws E_NOTIMPL for attempts to get an enregistered value for a float register
7874 // (implementation for derived class FloatRegValueHome)
7875 virtual
7876 void GetEnregisteredValue(MemoryRange valueOutBuffer) = 0;
7877
7878 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
7879 // instance of a derived class of EnregisteredValueHome
7880 // Arguments: input: none--uses fields of "this"
7881 // output: pRegAddr - address of an instance of RemoteAddress with field values set to corresponding
7882 // field values of "this"
7883 virtual
7884 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
7885
7886 // accessor
7887 const CordbNativeFrame * GetFrame() const { return m_pFrame; };
7888
7889 //-------------------------------------
7890 // data members
7891 //-------------------------------------
7892protected:
7893 // The frame on which the value resides
7894 const CordbNativeFrame * m_pFrame;
7895
7896}; // class EnregisteredValueHome
7897
7898typedef NewHolder<EnregisteredValueHome> EnregisteredValueHomeHolder;
7899
7900// class RegValueHome: encapsulates basic information for a value that resides in a single register
7901// and serves as a base class for values residing in a register pair.
7902class RegValueHome: public EnregisteredValueHome
7903{
7904public:
7905
7906 // initializing constructor
7907 // Arguments:
7908 // input: pFrame - frame to which the value belongs
7909 // regNum - enumeration value corresponding to the particular hardware register in
7910 // which the value resides
7911 // regAddr - remote address within a register display (in a context or frame) of the
7912 // register value
7913 // output: no out parameters, but the instance has been initialized
7914 RegValueHome(const CordbNativeFrame * pFrame,
7915 CorDebugRegister regNum):
7916 EnregisteredValueHome(pFrame),
7917 m_reg1Info(regNum,
7918 pFrame->GetLeftSideAddressOfRegister(regNum),
7919 *(pFrame->GetAddressOfRegister(regNum)))
7920 {};
7921
7922 // copy constructor
7923 // Arguments:
7924 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
7925 // instance will come
7926 // output: no out parameters, but the instance has been initialized
7927 RegValueHome(const RegValueHome * pRemoteRegAddr):
7928 EnregisteredValueHome(pRemoteRegAddr->m_pFrame),
7929 m_reg1Info(pRemoteRegAddr->m_reg1Info)
7930 {};
7931
7932 // make a copy of this instance of RegValueHome
7933 virtual
7934 RegValueHome * Clone() const { return new RegValueHome(*this); };
7935
7936 // updates a register in a given context, and in the regdisplay of a given frame.
7937 void SetContextRegister(DT_CONTEXT * pContext,
7938 CorDebugRegister regNum,
7939 SIZE_T newVal);
7940
7941 // set the value of a remote enregistered value
7942 virtual
7943 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
7944
7945 // Gets an enregistered value and returns it to the caller
7946 virtual
7947 void GetEnregisteredValue(MemoryRange valueOutBuffer);
7948 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
7949 // instance of a derived class of RegValueHome
7950 virtual
7951 void CopyToIPCEType(RemoteAddress * pRegAddr);
7952
7953 //-------------------------------------
7954 // data members
7955 //-------------------------------------
7956protected:
7957 // The information for the register in which the value resides.
7958 const RegisterInfo m_reg1Info;
7959}; // class RegValueHome
7960
7961// class RegRegValueHome
7962// derived class to add a second register for values that live in a pair of registers
7963class RegRegValueHome: public RegValueHome
7964{
7965public:
7966 // initializing constructor
7967 // Arguments:
7968 // input: pFrame - frame to which the value belongs
7969 // reg1Num - enumeration value corresponding to the first particular hardware register in
7970 // which the value resides
7971 // reg1Addr - remote address within a register display (in a context or frame) of the
7972 // first register
7973 // reg2Num - enumeration value corresponding to the second particular hardware register in
7974 // which the value resides
7975 // reg2Addr - remote address within a register display (in a context or frame) of the
7976 // second register
7977 // output: no out parameters, but the instance has been initialized
7978 RegRegValueHome(const CordbNativeFrame * pFrame,
7979 CorDebugRegister reg1Num,
7980 CorDebugRegister reg2Num):
7981 RegValueHome(pFrame, reg1Num),
7982 m_reg2Info(reg2Num,
7983 pFrame->GetLeftSideAddressOfRegister(reg2Num),
7984 *(pFrame->GetAddressOfRegister(reg2Num)))
7985 {};
7986
7987 // copy constructor
7988 // Arguments:
7989 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
7990 // instance will come
7991 // output: no out parameters, but the instance has been initialized
7992 RegRegValueHome(const RegRegValueHome * pRemoteRegAddr):
7993 RegValueHome(pRemoteRegAddr),
7994 m_reg2Info(pRemoteRegAddr->m_reg2Info)
7995 {};
7996
7997 // make a copy of this instance of RegRegValueHome
7998 virtual
7999 RegRegValueHome * Clone() const { return new RegRegValueHome(*this); };
8000
8001 // set the value of a remote enregistered value
8002 virtual
8003 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8004
8005 // Gets an enregistered value and returns it to the caller
8006 virtual
8007 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8008
8009 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8010 // instance of a derived class of EnregisteredValueHome
8011 void CopyToIPCEType(RemoteAddress * pRegAddr);
8012
8013 //-------------------------------------
8014 // data members
8015 //-------------------------------------
8016
8017protected:
8018 // The information for the second of two registers in which the value resides.
8019 const RegisterInfo m_reg2Info;
8020}; // class RegRegValueHome
8021
8022// class RegAndMemBaseValueHome
8023// derived from RegValueHome, this class is also a base class for RegMemValueHome
8024// and MemRegValueHome, which add a memory location for reg-mem or mem-reg values
8025class RegAndMemBaseValueHome: public RegValueHome
8026{
8027public:
8028 // initializing constructor
8029 // Arguments:
8030 // input: pFrame - frame to which the value belongs
8031 // reg1Num - enumeration value corresponding to the first particular hardware register in
8032 // which the value resides
8033 // reg1Addr - remote address within a register display (in a context or frame) of the
8034 // register component of the value
8035 // memAddr - remote address for the memory component of the value
8036 // output: no out parameters, but the instance has been initialized
8037 RegAndMemBaseValueHome(const CordbNativeFrame * pFrame,
8038 CorDebugRegister reg1Num,
8039 CORDB_ADDRESS memAddr):
8040 RegValueHome(pFrame, reg1Num),
8041 m_memAddr(memAddr)
8042 {};
8043
8044 // copy constructor
8045 // Arguments:
8046 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8047 // instance will come
8048 // output: no out parameters, but the instance has been initialized
8049 RegAndMemBaseValueHome(const RegAndMemBaseValueHome * pRemoteRegAddr):
8050 RegValueHome(pRemoteRegAddr),
8051 m_memAddr()
8052 {};
8053
8054 // make a copy of this instance of RegRegValueHome
8055 virtual
8056 RegAndMemBaseValueHome * Clone() const = 0;
8057
8058 // set the value of a remote enregistered value
8059 virtual
8060 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * DT_pContext, bool fIsSigned) = 0;
8061
8062 // Gets an enregistered value and returns it to the caller
8063 virtual
8064 void GetEnregisteredValue(MemoryRange valueOutBuffer) = 0;
8065
8066 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8067 // instance of a derived class of EnregisteredValueHome
8068 virtual
8069 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
8070
8071 //-------------------------------------
8072 // data members
8073 //-------------------------------------
8074
8075protected:
8076 // remote address for the memory component of the value
8077 CORDB_ADDRESS m_memAddr;
8078
8079}; // class RegAndMemBaseValueHome;
8080
8081// class RegMemValueHome
8082// type derived from abstract class RegAndMemBaseValueHome to represent a Register/Memory location where the
8083// high order part of the value is kept in a register, and the low order part is kept in memory
8084class RegMemValueHome: public RegAndMemBaseValueHome
8085{
8086public:
8087
8088 // initializing constructor
8089 // Arguments:
8090 // input: pFrame - frame to which the value belongs
8091 // reg1Num - enumeration value corresponding to the first particular hardware register in
8092 // which the value resides
8093 // reg1Addr - remote address within a register display (in a context or frame) of the
8094 // register component of the value
8095 // memAddr - remote address for the memory component of the value
8096 // output: no out parameters, but the instance has been initialized
8097 RegMemValueHome(const CordbNativeFrame * pFrame,
8098 CorDebugRegister reg1Num,
8099 CORDB_ADDRESS memAddr):
8100 RegAndMemBaseValueHome(pFrame, reg1Num, memAddr)
8101 {};
8102
8103 // copy constructor
8104 // Arguments:
8105 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8106 // instance will come
8107 // output: no out parameters, but the instance has been initialized
8108 RegMemValueHome(const RegMemValueHome * pRemoteRegAddr):
8109 RegAndMemBaseValueHome(pRemoteRegAddr)
8110 {};
8111
8112 // make a copy of this instance of RegMemValueHome
8113 virtual
8114 RegMemValueHome * Clone() const { return new RegMemValueHome(*this); };
8115
8116 // set the value of a remote enregistered value
8117 virtual
8118 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8119
8120 // Gets an enregistered value and returns it to the caller
8121 virtual
8122 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8123
8124 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8125 // instance of a derived class of EnregisteredValueHome
8126 virtual
8127 void CopyToIPCEType(RemoteAddress * pRegAddr);
8128
8129}; // class RegMemValueHome;
8130
8131// class MemRegValueHome
8132// type derived from abstract class RegAndMemBaseValueHome to represent a Register/Memory location where the
8133// low order part of the value is kept in a register, and the high order part is kept in memory
8134class MemRegValueHome: public RegAndMemBaseValueHome
8135{
8136public:
8137
8138 // initializing constructor
8139 // Arguments:
8140 // input: pFrame - frame to which the value belongs
8141 // reg1Num - enumeration value corresponding to the first particular hardware register in
8142 // which the value resides
8143 // reg1Addr - remote address within a register display (in a context or frame) of the
8144 // register component of the value
8145 // memAddr - remote address for the memory component of the value
8146 // output: no out parameters, but the instance has been initialized
8147 MemRegValueHome(const CordbNativeFrame * pFrame,
8148 CorDebugRegister reg1Num,
8149 CORDB_ADDRESS memAddr):
8150 RegAndMemBaseValueHome(pFrame, reg1Num, memAddr)
8151 {};
8152
8153 // copy constructor
8154 // Arguments:
8155 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8156 // instance will come
8157 // output: no out parameters, but the instance has been initialized
8158 MemRegValueHome(const MemRegValueHome * pRemoteRegAddr):
8159 RegAndMemBaseValueHome(pRemoteRegAddr)
8160 {};
8161
8162 // make a copy of this instance of MemRegValueHome
8163 virtual
8164 MemRegValueHome * Clone() const { return new MemRegValueHome(*this); };
8165
8166 // set the value of a remote enregistered value
8167 virtual
8168 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8169
8170 // Gets an enregistered value and returns it to the caller
8171 virtual
8172 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8173
8174 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8175 // instance of a derived class of EnregisteredValueHome
8176 virtual
8177 void CopyToIPCEType(RemoteAddress * pRegAddr);
8178
8179}; // class MemRegValueHome;
8180
8181// class FloatRegValueHome
8182// derived class to add an index into the FP register stack for a floating point value
8183class FloatRegValueHome: public EnregisteredValueHome
8184{
8185public:
8186 // initializing constructor
8187 // Arguments:
8188 // input: pFrame - frame to which the value belongs
8189 // index - index into the floating point stack where the value resides
8190 // output: no out parameters, but the instance has been initialized
8191 FloatRegValueHome(const CordbNativeFrame * pFrame,
8192 DWORD index):
8193 EnregisteredValueHome(pFrame),
8194 m_floatIndex(index)
8195 {};
8196
8197 // copy constructor
8198 // Arguments:
8199 // input: pRemoteRegAddr - instance of a remote register address from which the values for this
8200 // instance will come
8201 // output: no out parameters, but the instance has been initialized
8202 FloatRegValueHome(const FloatRegValueHome * pRemoteRegAddr):
8203 EnregisteredValueHome(pRemoteRegAddr->m_pFrame),
8204 m_floatIndex(pRemoteRegAddr->m_floatIndex)
8205 {};
8206
8207 // make a copy of this instance of FloatRegValueHome
8208 virtual
8209 FloatRegValueHome * Clone() const { return new FloatRegValueHome(*this); };
8210
8211 // set the value of a remote enregistered value
8212 virtual
8213 void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned);
8214
8215 // Gets an enregistered value and returns it to the caller
8216 virtual
8217 void GetEnregisteredValue(MemoryRange valueOutBuffer);
8218
8219 // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this
8220 // instance of a derived class of EnregisteredValueHome
8221 virtual
8222 void CopyToIPCEType(RemoteAddress * pRegAddr);
8223
8224 //-------------------------------------
8225 // data members
8226 //-------------------------------------
8227
8228protected:
8229 // index into the FP registers for the register in which the floating point value resides
8230 const DWORD m_floatIndex;
8231 }; // class FloatRegValueHome
8232
8233// ----------------------------------------------------------------------------
8234// Type hierarchy for value locations
8235// ValueHome
8236// | | |
8237// ------------------ | -------------------
8238// | | |
8239// RemoteValueHome RegisterValueHome HandleValueHome
8240// | |
8241// -------- -------
8242// | |
8243// VCRemoteValueHome RefRemoteValueHome
8244//
8245// ValueHome: abstract base class, provides remote read and write utilities
8246// RemoteValueHome: used for CordbObjectValue, CordbArrayValue, and CordbBoxValue instances,
8247// which have only remote locations, and for other ICDValues with a remote address
8248// RegisterValueHome: used for CordbGenericValue and CordbReferenceValue instances with
8249// only a register location
8250// HandleValueHome: used for CordbReferenceValue instances with only an object handle
8251// VCRemoteValueHome: used for CordbVCObjectValue instances to supply special operation CreateInternalValue for
8252// value class objects with only a remote location
8253// RefRemoteValueHome: used for CordbReferenceValue instances with only a remote location
8254//
8255// In addition, we have a special type for the ValueHome field for CordbReferenceValue instances:
8256// RefValueHome. This will have a field of type ValueHome and will implement extra operations only relevant
8257// for object references.
8258//
8259// ----------------------------------------------------------------------------
8260//
8261class ValueHome
8262{
8263public:
8264 ValueHome(CordbProcess * pProcess):
8265 m_pProcess(pProcess) { _ASSERTE(pProcess != NULL); };
8266
8267 virtual
8268 ~ValueHome() {}
8269
8270 // releases resources as necessary
8271 virtual
8272 void Clear() = 0;
8273
8274 // gets the remote address for the value or returns NULL if none exists
8275 virtual
8276 CORDB_ADDRESS GetAddress() = 0;
8277
8278 // Gets a value and returns it in dest
8279 // Argument:
8280 // input: none (uses fields of the instance)
8281 // output: dest - buffer containing the value retrieved as long as the returned HRESULT doesn't
8282 // indicate an error.
8283 // Note: Throws errors from read process memory operation or GetThreadContext operation
8284 virtual
8285 void GetValue(MemoryRange dest) = 0;
8286
8287 // Sets a location to the value provided in src
8288 // Arguments:
8289 // input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller
8290 // pType - type information about the value
8291 // output: none, but on success, changes m_remoteValue to hold the new value
8292 // Note: Throws errors from SafeWriteBuffer
8293 virtual
8294 void SetValue(MemoryRange src, CordbType * pType) = 0;
8295
8296 // creates an ICDValue for a field or array element or for the value type of a boxed object
8297 // Arguments:
8298 // input: pType - type of the internal value
8299 // offset - offset to the internal value
8300 // localAddress - address of thelogical buffer within the parent class' local cached
8301 // copy that holds the internal element
8302 // size - size of the internal value
8303 // output: ppValue - the newly created ICDValue instance
8304 // Note: Throws for a variety of possible failures: OOM, E_FAIL, errors from
8305 // ReadProcessMemory.
8306 virtual
8307 void CreateInternalValue(CordbType * pType,
8308 SIZE_T offset,
8309 void * localAddress,
8310 ULONG32 size,
8311 ICorDebugValue ** ppValue) = 0;
8312
8313 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8314 // Arguments
8315 // input: offset - offset within the value to the internal field or element
8316 // output: dest - buffer to hold the value--memory for this buffer is owned by the caller
8317 // Note: Throws process memory write errors
8318 virtual
8319 void GetInternalValue(MemoryRange dest, SIZE_T offset) = 0;
8320
8321 // copies register information from this to a RemoteAddress instance for FuncEval
8322 // Arguments:
8323 // output: pRegAddr - copy of information in m_pRemoteRegAddr, converted to
8324 // an instance of RemoteAddress
8325 virtual
8326 void CopyToIPCEType(RemoteAddress * pRegAddr) = 0;
8327
8328private:
8329 // unimplemented copy constructor to prevent passing by value
8330 ValueHome(ValueHome * pValHome);
8331
8332protected:
8333 // --------------
8334 // data member
8335 // --------------
8336 CordbProcess * m_pProcess;
8337}; // class ValueHome
8338
8339// ============================================================================
8340// RemoteValueHome class
8341// ============================================================================
8342// to be used for CordbObjectValue, CordbArrayValue, and CordbBoxValue, none of which ever have anything but
8343// a remote address
8344class RemoteValueHome: public ValueHome
8345{
8346public:
8347 // constructor
8348 // Note: It's possible that remoteValue.pAddress may be NULL--FuncEval makes
8349 // empty GenericValues for literals in which case we would have neither a remote address nor a
8350 // register address
8351 RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue);
8352
8353 // gets the remote address for the value
8354 virtual
8355 CORDB_ADDRESS GetAddress() { return m_remoteValue.pAddress; };
8356
8357 // releases resources as necessary
8358 virtual
8359 void Clear() {};
8360
8361 // Gets a value and returns it in dest
8362 virtual
8363 void GetValue(MemoryRange dest);
8364
8365 // Sets a location to the value provided in src
8366 virtual
8367 void SetValue(MemoryRange src, CordbType * pType);
8368
8369 // creates an ICDValue for a field or array element or for the value type of a boxed object
8370 virtual
8371 void CreateInternalValue(CordbType * pType,
8372 SIZE_T offset,
8373 void * localAddress,
8374 ULONG32 size,
8375 ICorDebugValue ** ppValue);
8376
8377 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8378 virtual
8379 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8380
8381 // copies register information from this to a RemoteAddress instance for FuncEval
8382 virtual
8383 void CopyToIPCEType(RemoteAddress * pRegAddr);
8384
8385
8386 // ----------------
8387 // data member
8388 // ----------------
8389
8390protected:
8391 TargetBuffer m_remoteValue;
8392}; // class RemoteValueHome
8393
8394// ============================================================================
8395// RegisterValueHome class
8396// ============================================================================
8397// for values that may either have a remote location or be enregistered--
8398// to be used for CordbGenericValue, and as base for CordbVCObjectValue and CordbReferenceValue
8399class RegisterValueHome: public ValueHome
8400{
8401public:
8402 // constructor
8403 RegisterValueHome(CordbProcess * pProcess,
8404 EnregisteredValueHomeHolder * ppRemoteRegAddr);
8405
8406 // clean up resources
8407 virtual
8408 void Clear();
8409
8410 // gets the remote address for the value or returns NULL if none exists
8411 virtual
8412 CORDB_ADDRESS GetAddress() { return NULL; };
8413
8414 // Gets a value and returns it in dest
8415 virtual
8416 void GetValue(MemoryRange dest);
8417
8418 // Sets a location to the value provided in src
8419 virtual
8420 void SetValue(MemoryRange src, CordbType * pType);
8421
8422 // creates an ICDValue for a field or array element or for the value type of a boxed object
8423 virtual
8424 void CreateInternalValue(CordbType * pType,
8425 SIZE_T offset,
8426 void * localAddress,
8427 ULONG32 size,
8428 ICorDebugValue ** ppValue);
8429
8430 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8431 virtual
8432 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8433
8434 // copies the register information from this to a RemoteAddress instance
8435 virtual
8436 void CopyToIPCEType(RemoteAddress * pRegAddr);
8437
8438protected:
8439
8440 // sets a remote enregistered location to a new value
8441 void SetEnregisteredValue(MemoryRange src, bool fIsSigned);
8442
8443 // gets a value from an enregistered location
8444 void GetEnregisteredValue(MemoryRange dest);
8445
8446 bool IsSigned(CorElementType elementType);
8447
8448 // ----------------
8449 // data member
8450 // ----------------
8451
8452protected:
8453 // Left Side register location info for various kinds of (partly) enregistered values.
8454 EnregisteredValueHome * m_pRemoteRegAddr;
8455
8456}; // class RegisterValueHome
8457
8458// ============================================================================
8459// HandleValueHome class
8460// ============================================================================
8461
8462class HandleValueHome: public ValueHome
8463{
8464public:
8465 // constructor
8466 // Arguments:
8467 // input: pProcess - process to which the value belongs
8468 // vmObjHandle - objectHandle holding the object address
8469 HandleValueHome(CordbProcess * pProcess, VMPTR_OBJECTHANDLE vmObjHandle):
8470 ValueHome(pProcess),
8471 m_vmObjectHandle(vmObjHandle) {};
8472
8473 // releases resources as necessary
8474 virtual
8475 void Clear() {};
8476
8477 // gets the remote address for the value or returns NULL if none exists
8478 virtual
8479 CORDB_ADDRESS GetAddress();
8480
8481 // Gets a value and returns it in dest
8482 virtual
8483 void GetValue(MemoryRange dest);
8484
8485 // Sets a location to the value provided in src
8486 virtual
8487 void SetValue(MemoryRange src, CordbType * pType);
8488
8489 // creates an ICDValue for a field or array element or for the value type of a boxed object
8490 virtual
8491 void CreateInternalValue(CordbType * pType,
8492 SIZE_T offset,
8493 void * localAddress,
8494 ULONG32 size,
8495 ICorDebugValue ** ppValue);
8496
8497 // Gets the value of a field or element of an existing ICDValue instance and returns it in dest
8498 virtual
8499 void GetInternalValue(MemoryRange dest, SIZE_T offset);
8500
8501 // copies the register information from this to a RemoteAddress instance
8502 virtual
8503 void CopyToIPCEType(RemoteAddress * pRegAddr);
8504
8505 // ----------------
8506 // data member
8507 // ----------------
8508private:
8509 VMPTR_OBJECTHANDLE m_vmObjectHandle;
8510}; // class HandleValueHome;
8511
8512// ============================================================================
8513// VCRemoteValueHome class
8514// ============================================================================
8515// used only for CordbVCObjectValue
8516class VCRemoteValueHome: public RemoteValueHome
8517{
8518public:
8519 // constructor
8520 VCRemoteValueHome(CordbProcess * pProcess,
8521 TargetBuffer remoteValue):
8522 RemoteValueHome(pProcess, remoteValue) {};
8523
8524 // Sets a location to the value provided in src
8525 virtual
8526 void SetValue(MemoryRange src, CordbType * pType);
8527
8528}; // class VCRemoteValueHome
8529
8530// ============================================================================
8531// RefRemoteValueHome class
8532// ============================================================================
8533
8534// used only for CordbReferenceValue
8535class RefRemoteValueHome: public RemoteValueHome
8536{
8537public:
8538 // constructor
8539 // Arguments
8540 RefRemoteValueHome(CordbProcess * pProcess,
8541 TargetBuffer remoteValue);
8542
8543 // Sets a location to the value provided in src
8544 virtual
8545 void SetValue(MemoryRange src, CordbType * pType);
8546
8547}; // class RefRemoteValueHome
8548
8549// ============================================================================
8550// RefValueHome class
8551// ============================================================================
8552
8553// abstract superclass for derivations RefRemoteValueHome and RefRegValueHome
8554class RefValueHome
8555{
8556public:
8557 // constructor
8558 RefValueHome() { m_pHome = NULL; m_fNullObjHandle = true; };
8559
8560 // constructor
8561 RefValueHome(CordbProcess * pProcess,
8562 TargetBuffer remoteValue,
8563 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8564 VMPTR_OBJECTHANDLE vmObjHandle);
8565
8566 // indicates whether the object handle is null
8567 bool ObjHandleIsNull() { return m_fNullObjHandle; };
8568 void SetObjHandleFlag(bool isNull) { m_fNullObjHandle = isNull; };
8569
8570 // ----------------
8571 // data members
8572 // ----------------
8573 // appropriate instantiation of ValueHome
8574 ValueHome * m_pHome;
8575
8576private:
8577 // true iff m_pHome is an instantiation of RemoteValueHome or RegisterValueHome
8578 bool m_fNullObjHandle;
8579}; // class RefValueHome
8580
8581typedef enum {kUnboxed, kBoxed} BoxedValue;
8582#define EMPTY_BUFFER TargetBuffer(PTR_TO_CORDB_ADDRESS((void *)NULL), 0)
8583
8584/* ------------------------------------------------------------------------- *
8585 * Variable Home class
8586 * ------------------------------------------------------------------------- */
8587class CordbVariableHome : public CordbBase, public ICorDebugVariableHome
8588{
8589public:
8590 CordbVariableHome(CordbNativeCode *pCode,
8591 const ICorDebugInfo::NativeVarInfo nativeVarInfo,
8592 BOOL isLoc,
8593 ULONG index);
8594 ~CordbVariableHome();
8595 virtual void Neuter();
8596
8597#ifdef _DEBUG
8598 virtual const char * DbgGetName() { return "CordbVariableHome"; }
8599#endif
8600
8601 //-----------------------------------------------------------
8602 // IUnknown
8603 //-----------------------------------------------------------
8604 ULONG STDMETHODCALLTYPE AddRef()
8605 {
8606 return (BaseAddRef());
8607 }
8608 ULONG STDMETHODCALLTYPE Release()
8609 {
8610 return (BaseRelease());
8611 }
8612
8613 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8614
8615 //-----------------------------------------------------------
8616 // ICorDebugVariableHome
8617 //-----------------------------------------------------------
8618
8619 COM_METHOD GetCode(ICorDebugCode **ppCode);
8620
8621 COM_METHOD GetSlotIndex(ULONG32 *pSlotIndex);
8622
8623 COM_METHOD GetArgumentIndex(ULONG32* pArgumentIndex);
8624
8625 COM_METHOD GetLiveRange(ULONG32* pStartOffset,
8626 ULONG32 *pEndOffset);
8627
8628 COM_METHOD GetLocationType(VariableLocationType *pLocationType);
8629
8630 COM_METHOD GetRegister(CorDebugRegister *pRegister);
8631
8632 COM_METHOD GetOffset(LONG *pOffset);
8633private:
8634 RSSmartPtr<CordbNativeCode> m_pCode;
8635 ICorDebugInfo::NativeVarInfo m_nativeVarInfo;
8636 BOOL m_isLocal;
8637 ULONG m_index;
8638};
8639
8640
8641// for an inheritance graph of the ICDValue types, // See file:./ICorDebugValueTypes.vsd for a diagram of the types.
8642/* ------------------------------------------------------------------------- *
8643 * Value class
8644 * ------------------------------------------------------------------------- */
8645
8646class CordbValue : public CordbBase
8647{
8648public:
8649 //-----------------------------------------------------------
8650 // Constructor/destructor
8651 //-----------------------------------------------------------
8652 CordbValue(CordbAppDomain * appdomain,
8653 CordbType * type,
8654 CORDB_ADDRESS id,
8655 bool isLiteral,
8656 NeuterList * pList = NULL);
8657
8658 virtual ~CordbValue();
8659 virtual void Neuter();
8660
8661 //-----------------------------------------------------------
8662 // IUnknown
8663 //-----------------------------------------------------------
8664
8665 ULONG STDMETHODCALLTYPE AddRef()
8666 {
8667 return (BaseAddRef());
8668 }
8669 ULONG STDMETHODCALLTYPE Release()
8670 {
8671 return (BaseRelease());
8672 }
8673
8674 //-----------------------------------------------------------
8675 // ICorDebugValue
8676 //-----------------------------------------------------------
8677
8678 COM_METHOD GetType(CorElementType *pType)
8679 {
8680 LIMITED_METHOD_CONTRACT;
8681
8682 FAIL_IF_NEUTERED(this);
8683 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
8684
8685 *pType = m_type->m_elementType;
8686 return (S_OK);
8687 }
8688
8689 COM_METHOD GetSize(ULONG32 *pSize)
8690 {
8691 LIMITED_METHOD_CONTRACT;
8692
8693 FAIL_IF_NEUTERED(this);
8694 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG32 *);
8695
8696 if (m_size > ULONG_MAX)
8697 {
8698 *pSize = ULONG_MAX;
8699 return (COR_E_OVERFLOW);
8700 }
8701
8702 *pSize = (ULONG)m_size;
8703 return (S_OK);
8704 }
8705
8706 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
8707
8708 //-----------------------------------------------------------
8709 // ICorDebugValue2
8710 //-----------------------------------------------------------
8711
8712 COM_METHOD GetExactType(ICorDebugType **ppType);
8713
8714 //-----------------------------------------------------------
8715 // ICorDebugValue3
8716 //-----------------------------------------------------------
8717
8718 COM_METHOD GetSize64(ULONG64 *pSize)
8719 {
8720 LIMITED_METHOD_CONTRACT;
8721
8722 FAIL_IF_NEUTERED(this);
8723 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG64 *);
8724
8725 *pSize = m_size;
8726 return (S_OK);
8727 }
8728
8729 virtual HRESULT STDMETHODCALLTYPE GetAddress(CORDB_ADDRESS *pAddress) = 0;
8730
8731 //-----------------------------------------------------------
8732 // Methods not exported through COM
8733 //-----------------------------------------------------------
8734
8735 // Helper for code:CordbValue::CreateValueByType. Create a new instance of CordbGenericValue
8736 static
8737 void CreateGenericValue(CordbAppDomain * pAppdomain,
8738 CordbType * pType,
8739 TargetBuffer remoteValue,
8740 MemoryRange localValue,
8741 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8742 ICorDebugValue** ppValue);
8743
8744 // Helper for code:CordbValue::CreateValueByType. Create a new instance of CordbVCObjectValue or
8745 // CordbReferenceValue
8746 static
8747 void CreateVCObjOrRefValue(CordbAppDomain * pAppdomain,
8748 CordbType * pType,
8749 bool boxed,
8750 TargetBuffer remoteValue,
8751 MemoryRange localValue,
8752 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8753 ICorDebugValue** ppValue);
8754
8755 // Create the proper ICDValue instance based on the given element type.
8756 static void CreateValueByType(CordbAppDomain * appdomain,
8757 CordbType * type,
8758 bool boxed,
8759 TargetBuffer remoteValue,
8760 MemoryRange localValue,
8761 EnregisteredValueHomeHolder * ppRemoteRegAddr,
8762 ICorDebugValue** ppValue);
8763
8764 // Create the proper ICDValue instance based on the given remote heap object
8765 static ICorDebugValue* CreateHeapValue(CordbAppDomain* pAppDomain,
8766 VMPTR_Object vmObj);
8767
8768
8769 // Returns a pointer to the ValueHome field of this instance of CordbValue if one exists or NULL
8770 // otherwise. Therefore, this also tells us indirectly whether this instance of CordbValue is also an
8771 // instance of one of its derived types and thus has a ValueHome field.
8772 virtual
8773 ValueHome * GetValueHome() { return NULL; };
8774
8775 static ULONG32 GetSizeForType(CordbType * pType, BoxedValue boxing);
8776
8777 virtual CordbAppDomain *GetAppDomain()
8778 {
8779 return m_appdomain;
8780 }
8781
8782 HRESULT InternalCreateHandle(
8783 CorDebugHandleType handleType,
8784 ICorDebugHandleValue ** ppHandle);
8785
8786 //-----------------------------------------------------------
8787 // Data members
8788 //-----------------------------------------------------------
8789
8790public:
8791 CordbAppDomain * m_appdomain;
8792 RSSmartPtr<CordbType> m_type;
8793
8794 // size of the value
8795 SIZE_T m_size;
8796
8797 // true if the value is a RS fabrication.
8798 bool m_isLiteral;
8799
8800};
8801
8802/* ------------------------------------------------------------------------- *
8803* Value Breakpoint class
8804* ------------------------------------------------------------------------- */
8805
8806class CordbValueBreakpoint : public CordbBreakpoint,
8807 public ICorDebugValueBreakpoint
8808{
8809public:
8810 CordbValueBreakpoint(CordbValue *pValue);
8811
8812
8813#ifdef _DEBUG
8814 virtual const char * DbgGetName() { return "CordbValueBreakpoint"; }
8815#endif
8816
8817 //-----------------------------------------------------------
8818 // IUnknown
8819 //-----------------------------------------------------------
8820
8821 ULONG STDMETHODCALLTYPE AddRef()
8822 {
8823 return (BaseAddRef());
8824 }
8825 ULONG STDMETHODCALLTYPE Release()
8826 {
8827 return (BaseRelease());
8828 }
8829 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8830
8831 //-----------------------------------------------------------
8832 // ICorDebugValueBreakpoint
8833 //-----------------------------------------------------------
8834
8835 COM_METHOD GetValue(ICorDebugValue **ppValue);
8836 COM_METHOD Activate(BOOL bActive);
8837 COM_METHOD IsActive(BOOL *pbActive)
8838 {
8839 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
8840
8841 return BaseIsActive(pbActive);
8842 }
8843
8844 //-----------------------------------------------------------
8845 // Non-COM methods
8846 //-----------------------------------------------------------
8847
8848 void Disconnect();
8849
8850public:
8851 CordbValue * m_value;
8852};
8853
8854/* ------------------------------------------------------------------------- *
8855* Generic Value class
8856* ------------------------------------------------------------------------- */
8857
8858class CordbGenericValue : public CordbValue, public ICorDebugGenericValue, public ICorDebugValue2, public ICorDebugValue3
8859{
8860public:
8861 CordbGenericValue(CordbAppDomain * appdomain,
8862 CordbType * type,
8863 TargetBuffer remoteValue,
8864 EnregisteredValueHomeHolder * ppRemoteRegAddr);
8865
8866 CordbGenericValue(CordbType * pType);
8867 // destructor
8868 ~CordbGenericValue();
8869
8870#ifdef _DEBUG
8871 virtual const char * DbgGetName() { return "CordbGenericValue"; }
8872#endif
8873
8874
8875 //-----------------------------------------------------------
8876 // IUnknown
8877 //-----------------------------------------------------------
8878
8879 ULONG STDMETHODCALLTYPE AddRef()
8880 {
8881 return (BaseAddRef());
8882 }
8883 ULONG STDMETHODCALLTYPE Release()
8884 {
8885 return (BaseRelease());
8886 }
8887 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
8888
8889 //-----------------------------------------------------------
8890 // ICorDebugValue
8891 //-----------------------------------------------------------
8892
8893 // gets the type of the value
8894 // Arguments:
8895 // output: pType - the type of the value. The caller must guarantee that pType is non-null.
8896 // Return Value: S_OK on success, E_INVALIDARG on failure
8897 COM_METHOD GetType(CorElementType *pType)
8898 {
8899 return (CordbValue::GetType(pType));
8900 }
8901
8902 // gets the size of the value
8903 // Arguments:
8904 // output: pSize - the size of the value. The caller must guarantee that pSize is non-null.
8905 // Return Value: S_OK on success, E_INVALIDARG on failure
8906 COM_METHOD GetSize(ULONG32 *pSize)
8907 {
8908 return (CordbValue::GetSize(pSize));
8909 }
8910 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
8911 {
8912 return (CordbValue::CreateBreakpoint(ppBreakpoint));
8913 }
8914
8915 // gets the remote (LS) address of the value. This may return NULL if the
8916 // value is a literal or resides in a register.
8917 // Arguments:
8918 // output: pAddress - the address of the value. The caller must guarantee is
8919 // non-Null
8920 // Return Value: S_OK on success or E_INVALIDARG if pAddress is null
8921 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
8922 {
8923 LIMITED_METHOD_CONTRACT;
8924
8925 FAIL_IF_NEUTERED(this);
8926 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pAddress, CORDB_ADDRESS *);
8927
8928 *pAddress = m_pValueHome ? m_pValueHome->GetAddress() : NULL;
8929 return (S_OK);
8930 }
8931
8932 //-----------------------------------------------------------
8933 // ICorDebugValue2
8934 //-----------------------------------------------------------
8935
8936 COM_METHOD GetExactType(ICorDebugType **ppType)
8937 {
8938 return (CordbValue::GetExactType(ppType));
8939 }
8940
8941 //-----------------------------------------------------------
8942 // ICorDebugValue3
8943 //-----------------------------------------------------------
8944
8945 COM_METHOD GetSize64(ULONG64 *pSize)
8946 {
8947 return (CordbValue::GetSize64(pSize));
8948 }
8949
8950 //-----------------------------------------------------------
8951 // ICorDebugGenericValue
8952 //-----------------------------------------------------------
8953
8954 COM_METHOD GetValue(void *pTo);
8955 COM_METHOD SetValue(void *pFrom);
8956
8957 //-----------------------------------------------------------
8958 // Non-COM methods
8959 //-----------------------------------------------------------
8960
8961 // initialize a generic value by copying the necessary data, either
8962 // from the remote process or from another value in this process.
8963 void Init(MemoryRange localValue);
8964 bool CopyLiteralData(BYTE *pBuffer);
8965
8966 // Returns a pointer to the ValueHome field
8967 virtual
8968 ValueHome * GetValueHome() { return m_pValueHome; };
8969
8970 //-----------------------------------------------------------
8971 // Data members
8972 //-----------------------------------------------------------
8973
8974private:
8975 // hold copies of up to 64-bit values.
8976 BYTE m_pCopyOfData[8];
8977
8978 // location information--remote or register address
8979 ValueHome * m_pValueHome;
8980};
8981
8982
8983/* ------------------------------------------------------------------------- *
8984 * Reference Value class
8985 * ------------------------------------------------------------------------- */
8986
8987class CordbReferenceValue : public CordbValue, public ICorDebugReferenceValue, public ICorDebugValue2, public ICorDebugValue3
8988{
8989public:
8990 CordbReferenceValue(CordbAppDomain * pAppdomain,
8991 CordbType * pType,
8992 MemoryRange localValue,
8993 TargetBuffer remoteValue,
8994 EnregisteredValueHomeHolder * ppRegAddr,
8995 VMPTR_OBJECTHANDLE vmObjectHandle);
8996 CordbReferenceValue(CordbType * pType);
8997 virtual ~CordbReferenceValue();
8998 virtual void Neuter();
8999
9000
9001#ifdef _DEBUG
9002 virtual const char * DbgGetName() { return "CordbReferenceValue"; }
9003#endif
9004
9005 //-----------------------------------------------------------
9006 // IUnknown
9007 //-----------------------------------------------------------
9008
9009 ULONG STDMETHODCALLTYPE AddRef()
9010 {
9011 return (BaseAddRef());
9012 }
9013 ULONG STDMETHODCALLTYPE Release()
9014 {
9015 return (BaseRelease());
9016 }
9017 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9018
9019 //-----------------------------------------------------------
9020 // ICorDebugValue
9021 //-----------------------------------------------------------
9022
9023 COM_METHOD GetType(CorElementType *pType);
9024
9025 // get the size of the reference
9026 // Arguments:
9027 // output: pSize - the size of the value--this must be non-NULL
9028 // Return Value: S_OK on success or E_INVALIDARG
9029 COM_METHOD GetSize(ULONG32 *pSize)
9030 {
9031 return (CordbValue::GetSize(pSize));
9032 }
9033
9034 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress);
9035 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9036 {
9037 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9038 }
9039
9040 //-----------------------------------------------------------
9041 // ICorDebugValue2
9042 //-----------------------------------------------------------
9043
9044 COM_METHOD GetExactType(ICorDebugType **ppType)
9045 {
9046 return (CordbValue::GetExactType(ppType));
9047 }
9048
9049 //-----------------------------------------------------------
9050 // ICorDebugValue3
9051 //-----------------------------------------------------------
9052
9053 COM_METHOD GetSize64(ULONG64 *pSize)
9054 {
9055 return (CordbValue::GetSize64(pSize));
9056 }
9057
9058 //-----------------------------------------------------------
9059 // ICorDebugReferenceValue
9060 //-----------------------------------------------------------
9061
9062 COM_METHOD IsNull(BOOL * pfIsNull);
9063 COM_METHOD GetValue(CORDB_ADDRESS *pAddress);
9064 COM_METHOD SetValue(CORDB_ADDRESS address);
9065 COM_METHOD Dereference(ICorDebugValue **ppValue);
9066 COM_METHOD DereferenceStrong(ICorDebugValue **ppValue);
9067
9068 //-----------------------------------------------------------
9069 // Non-COM methods
9070 //-----------------------------------------------------------
9071
9072 // Helper function for SanityCheckPointer. Make an attempt to read memory at the address which is the
9073 // value of the reference.
9074 void TryDereferencingTarget();
9075
9076 // Do a sanity check on the pointer which is the value of the object reference. We can't efficiently
9077 // ensure that the pointer is really good, so we settle for a quick check just to make sure the memory at
9078 // the address is readable. We're actually just checking that we can dereference the pointer.
9079 // If the address is invalid, this will throw.
9080 void SanityCheckPointer (CorElementType type);
9081
9082 // get information about the reference when it's not an object address but another kind of pointer type:
9083 // ELEMENT_TYPE_BYREF, ELEMENT_TYPE_PTR or ELEMENT_TYPE_FNPTR
9084 void GetPointerData(CorElementType type, MemoryRange localValue);
9085
9086 // get basic object specific data when a reference points to an object, plus extra data if the object is
9087 // an array or string
9088 static
9089 void GetObjectData(CordbProcess * pProcess,
9090 void * objectAddress,
9091 CorElementType type,
9092 VMPTR_AppDomain vmAppdomain,
9093 DebuggerIPCE_ObjectData * pInfo);
9094
9095 // get information about a TypedByRef object when the reference is the address of a TypedByRef structure.
9096 static
9097 void GetTypedByRefData(CordbProcess * pProcess,
9098 CORDB_ADDRESS pTypedByRef,
9099 CorElementType type,
9100 VMPTR_AppDomain vmAppDomain,
9101 DebuggerIPCE_ObjectData * pInfo);
9102
9103 // get the address of the object referenced
9104 void * GetObjectAddress(MemoryRange localValue);
9105
9106 // update type information after initializing -- when we initialize, we may get more exact type
9107 // information than we previously had
9108 void UpdateTypeInfo();
9109
9110 // Initialize this CordbReferenceValue. This may involve inspecting the LS to get information about the
9111 // referent.
9112 HRESULT InitRef(MemoryRange localValue);
9113
9114 bool CopyLiteralData(BYTE *pBuffer);
9115
9116 static HRESULT Build(CordbAppDomain * appdomain,
9117 CordbType * type,
9118 TargetBuffer remoteValue,
9119 MemoryRange localValue,
9120 VMPTR_OBJECTHANDLE vmObjectHandle,
9121 EnregisteredValueHomeHolder * ppRemoteRegAddr,
9122 CordbReferenceValue** ppValue);
9123
9124 static HRESULT BuildFromGCHandle(CordbAppDomain *pAppDomain, VMPTR_OBJECTHANDLE gcHandle, ICorDebugReferenceValue ** pOutRef);
9125
9126 // Common dereference routine shared by both CordbReferenceValue + CordbHandleValue
9127 static HRESULT DereferenceCommon(CordbAppDomain * pAppDomain,
9128 CordbType * pType,
9129 CordbType * pRealTypeOfTypedByref,
9130 DebuggerIPCE_ObjectData * m_pInfo,
9131 ICorDebugValue ** ppValue);
9132
9133 // Returns a pointer to the ValueHome field
9134 virtual
9135 ValueHome * GetValueHome() { return m_valueHome.m_pHome; };
9136
9137 //-----------------------------------------------------------
9138 // Data members
9139 //-----------------------------------------------------------
9140
9141public:
9142 DebuggerIPCE_ObjectData m_info;
9143 CordbType * m_realTypeOfTypedByref; // weak ref
9144
9145 RefValueHome m_valueHome;
9146
9147 // Indicates when we last syncronized our stored data (m_info) from the left side
9148 UINT m_continueCounterLastSync;
9149};
9150
9151/* ------------------------------------------------------------------------- *
9152 * Object Value class
9153 *
9154 * Because of the oddness of string objects in the Runtime we have one
9155 * object that implements both ObjectValue and StringValue. There is a
9156 * definite string type, but its really just an object of the string
9157 * class. Furthermore, you can have a variable whose type is listed as
9158 * "class", but its an instance of the string class and therefore needs
9159 * to be treated like a string.
9160 * ------------------------------------------------------------------------- */
9161
9162class CordbObjectValue : public CordbValue,
9163 public ICorDebugObjectValue,
9164 public ICorDebugObjectValue2,
9165 public ICorDebugGenericValue,
9166 public ICorDebugStringValue,
9167 public ICorDebugValue2,
9168 public ICorDebugValue3,
9169 public ICorDebugHeapValue2,
9170 public ICorDebugHeapValue3,
9171 public ICorDebugExceptionObjectValue,
9172 public ICorDebugComObjectValue
9173{
9174public:
9175
9176 CordbObjectValue(CordbAppDomain * appdomain,
9177 CordbType * type,
9178 TargetBuffer remoteValue,
9179 DebuggerIPCE_ObjectData * pObjectData );
9180
9181 virtual ~CordbObjectValue();
9182
9183
9184 virtual void Neuter();
9185#ifdef _DEBUG
9186 virtual const char * DbgGetName() { return "CordbObjectValue"; }
9187#endif
9188
9189 //-----------------------------------------------------------
9190 // IUnknown
9191 //-----------------------------------------------------------
9192
9193 ULONG STDMETHODCALLTYPE AddRef()
9194 {
9195 return (BaseAddRef());
9196 }
9197 ULONG STDMETHODCALLTYPE Release()
9198 {
9199 return (BaseRelease());
9200 }
9201 COM_METHOD QueryInterface(REFIID riid, void ** ppInterface);
9202
9203 //-----------------------------------------------------------
9204 // ICorDebugValue
9205 //-----------------------------------------------------------
9206
9207 COM_METHOD GetType(CorElementType * pType);
9208 COM_METHOD GetSize(ULONG32 * pSize);
9209 COM_METHOD GetAddress(CORDB_ADDRESS * pAddress);
9210 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint ** ppBreakpoint);
9211
9212 //-----------------------------------------------------------
9213 // ICorDebugValue2
9214 //-----------------------------------------------------------
9215
9216 COM_METHOD GetExactType(ICorDebugType ** ppType)
9217 {
9218 return (CordbValue::GetExactType(ppType));
9219 }
9220
9221 //-----------------------------------------------------------
9222 // ICorDebugValue3
9223 //-----------------------------------------------------------
9224
9225 COM_METHOD GetSize64(ULONG64 *pSize);
9226
9227 //-----------------------------------------------------------
9228 // ICorDebugHeapValue
9229 //-----------------------------------------------------------
9230
9231 COM_METHOD IsValid(BOOL * pfIsValid);
9232 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint ** ppBreakpoint);
9233
9234 //-----------------------------------------------------------
9235 // ICorDebugHeapValue2
9236 //-----------------------------------------------------------
9237 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9238
9239 //-----------------------------------------------------------
9240 // ICorDebugHeapValue3
9241 //-----------------------------------------------------------
9242 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9243 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9244
9245 //-----------------------------------------------------------
9246 // ICorDebugObjectValue
9247 //-----------------------------------------------------------
9248
9249 COM_METHOD GetClass(ICorDebugClass ** ppClass);
9250 COM_METHOD GetFieldValue(ICorDebugClass * pClass,
9251 mdFieldDef fieldDef,
9252 ICorDebugValue ** ppValue);
9253 COM_METHOD GetVirtualMethod(mdMemberRef memberRef,
9254 ICorDebugFunction **ppFunction);
9255 COM_METHOD GetContext(ICorDebugContext ** ppContext);
9256 COM_METHOD IsValueClass(BOOL * pfIsValueClass);
9257 COM_METHOD GetManagedCopy(IUnknown ** ppObject);
9258 COM_METHOD SetFromManagedCopy(IUnknown * pObject);
9259
9260 COM_METHOD GetFieldValueForType(ICorDebugType * pType,
9261 mdFieldDef fieldDef,
9262 ICorDebugValue ** ppValue);
9263
9264 COM_METHOD GetVirtualMethodAndType(mdMemberRef memberRef,
9265 ICorDebugFunction ** ppFunction,
9266 ICorDebugType ** ppType);
9267
9268 //-----------------------------------------------------------
9269 // ICorDebugGenericValue
9270 //-----------------------------------------------------------
9271
9272 COM_METHOD GetValue(void * pTo);
9273 COM_METHOD SetValue(void * pFrom);
9274
9275 //-----------------------------------------------------------
9276 // ICorDebugStringValue
9277 //-----------------------------------------------------------
9278 COM_METHOD GetLength(ULONG32 * pcchString);
9279 COM_METHOD GetString(ULONG32 cchString,
9280 ULONG32 * ppcchStrin,
9281 __out_ecount_opt(cchString) WCHAR szString[]);
9282
9283 //-----------------------------------------------------------
9284 // ICorDebugExceptionObjectValue
9285 //-----------------------------------------------------------
9286 COM_METHOD EnumerateExceptionCallStack(ICorDebugExceptionObjectCallStackEnum** ppCallStackEnum);
9287
9288 //-----------------------------------------------------------
9289 // ICorDebugComObjectValue
9290 //-----------------------------------------------------------
9291 COM_METHOD GetCachedInterfaceTypes(BOOL bIInspectableOnly,
9292 ICorDebugTypeEnum** ppInterfacesEnum);
9293
9294 COM_METHOD GetCachedInterfacePointers(BOOL bIInspectableOnly,
9295 ULONG32 celt,
9296 ULONG32 *pcEltFetched,
9297 CORDB_ADDRESS * ptrs);
9298
9299 //-----------------------------------------------------------
9300 // Non-COM methods
9301 //-----------------------------------------------------------
9302
9303 HRESULT Init();
9304
9305 DebuggerIPCE_ObjectData GetInfo() { return m_info; }
9306 CordbHangingFieldTable * GetHangingFieldTable() { return &m_hangingFieldsInstance; }
9307
9308 // Returns a pointer to the ValueHome field
9309 virtual
9310 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9311
9312protected:
9313 //-----------------------------------------------------------
9314 // Data members
9315 //-----------------------------------------------------------
9316 DebuggerIPCE_ObjectData m_info;
9317 BYTE * m_pObjectCopy; // local cached copy of the object
9318 BYTE * m_objectLocalVars; // var base in _this_ process
9319 // points _into_ m_pObjectCopy
9320 BYTE * m_stringBuffer; // points _into_ m_pObjectCopy
9321
9322 // remote location information
9323 RemoteValueHome m_valueHome;
9324
9325 // If instances fields are added by EnC, their storage will be off the objects
9326 // syncblock. Cache per-object information about such fields here.
9327 CordbHangingFieldTable m_hangingFieldsInstance;
9328
9329private:
9330 HRESULT IsExceptionObject();
9331
9332 BOOL m_fIsExceptionObject;
9333
9334 HRESULT IsRcw();
9335
9336 BOOL m_fIsRcw;
9337};
9338
9339/* ------------------------------------------------------------------------- *
9340 * Value Class Object Value class
9341 * ------------------------------------------------------------------------- */
9342
9343class CordbVCObjectValue : public CordbValue,
9344 public ICorDebugObjectValue, public ICorDebugObjectValue2,
9345 public ICorDebugGenericValue, public ICorDebugValue2,
9346 public ICorDebugValue3
9347{
9348public:
9349 CordbVCObjectValue(CordbAppDomain * pAppdomain,
9350 CordbType * pType,
9351 TargetBuffer remoteValue,
9352 EnregisteredValueHomeHolder * ppRemoteRegAddr);
9353 virtual ~CordbVCObjectValue();
9354
9355#ifdef _DEBUG
9356 virtual const char * DbgGetName() { return "CordbVCObjectValue"; }
9357#endif
9358
9359 //-----------------------------------------------------------
9360 // IUnknown
9361 //-----------------------------------------------------------
9362
9363 ULONG STDMETHODCALLTYPE AddRef()
9364 {
9365 return (BaseAddRef());
9366 }
9367 ULONG STDMETHODCALLTYPE Release()
9368 {
9369 return (BaseRelease());
9370 }
9371 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9372
9373 //-----------------------------------------------------------
9374 // ICorDebugValue
9375 //-----------------------------------------------------------
9376
9377 COM_METHOD GetType(CorElementType *pType);
9378
9379 COM_METHOD GetSize(ULONG32 *pSize)
9380 {
9381 return (CordbValue::GetSize(pSize));
9382 }
9383 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9384 {
9385 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9386 }
9387
9388 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9389 {
9390 LIMITED_METHOD_CONTRACT;
9391
9392 FAIL_IF_NEUTERED(this);
9393 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9394
9395 *pAddress = m_pValueHome->GetAddress();
9396 return (S_OK);
9397 }
9398
9399 //-----------------------------------------------------------
9400 // ICorDebugValue2
9401 //-----------------------------------------------------------
9402
9403 COM_METHOD GetExactType(ICorDebugType **ppType)
9404 {
9405 return (CordbValue::GetExactType(ppType));
9406 }
9407
9408 //-----------------------------------------------------------
9409 // ICorDebugValue3
9410 //-----------------------------------------------------------
9411
9412 COM_METHOD GetSize64(ULONG64 *pSize)
9413 {
9414 return (CordbValue::GetSize64(pSize));
9415 }
9416
9417 //-----------------------------------------------------------
9418 // ICorDebugObjectValue
9419 //-----------------------------------------------------------
9420
9421 COM_METHOD GetClass(ICorDebugClass **ppClass);
9422 COM_METHOD GetFieldValue(ICorDebugClass *pClass,
9423 mdFieldDef fieldDef,
9424 ICorDebugValue **ppValue);
9425 COM_METHOD GetVirtualMethod(mdMemberRef memberRef,
9426 ICorDebugFunction **ppFunction);
9427 COM_METHOD GetContext(ICorDebugContext **ppContext);
9428 COM_METHOD IsValueClass(BOOL *pbIsValueClass);
9429 COM_METHOD GetManagedCopy(IUnknown **ppObject);
9430 COM_METHOD SetFromManagedCopy(IUnknown *pObject);
9431 COM_METHOD GetFieldValueForType(ICorDebugType * pType,
9432 mdFieldDef fieldDef,
9433 ICorDebugValue ** ppValue);
9434 COM_METHOD GetVirtualMethodAndType(mdMemberRef memberRef,
9435 ICorDebugFunction **ppFunction,
9436 ICorDebugType **ppType);
9437
9438 //-----------------------------------------------------------
9439 // ICorDebugGenericValue
9440 //-----------------------------------------------------------
9441
9442 COM_METHOD GetValue(void *pTo);
9443 COM_METHOD SetValue(void *pFrom);
9444
9445 //-----------------------------------------------------------
9446 // Non-COM methods
9447 //-----------------------------------------------------------
9448
9449 // Initializes the Right-Side's representation of a Value Class object.
9450 HRESULT Init(MemoryRange localValue);
9451 //HRESULT ResolveValueClass();
9452 CordbClass *GetClass();
9453
9454 // Returns a pointer to the ValueHome field
9455 virtual
9456 ValueHome * GetValueHome() { return m_pValueHome; };
9457
9458 //-----------------------------------------------------------
9459 // Data members
9460 //-----------------------------------------------------------
9461
9462private:
9463
9464 // local cached copy of the value class
9465 BYTE * m_pObjectCopy;
9466
9467 // location information
9468 ValueHome * m_pValueHome;
9469};
9470
9471
9472/* ------------------------------------------------------------------------- *
9473 * Box Value class
9474 * ------------------------------------------------------------------------- */
9475
9476class CordbBoxValue : public CordbValue,
9477 public ICorDebugBoxValue,
9478 public ICorDebugGenericValue,
9479 public ICorDebugValue2,
9480 public ICorDebugValue3,
9481 public ICorDebugHeapValue2,
9482 public ICorDebugHeapValue3
9483{
9484public:
9485 CordbBoxValue(CordbAppDomain * appdomain,
9486 CordbType * type,
9487 TargetBuffer remoteValue,
9488 ULONG32 size,
9489 SIZE_T offsetToVars);
9490 virtual ~CordbBoxValue();
9491
9492#ifdef _DEBUG
9493 virtual const char * DbgGetName() { return "CordbBoxValue"; }
9494#endif
9495
9496 //-----------------------------------------------------------
9497 // IUnknown
9498 //-----------------------------------------------------------
9499
9500 ULONG STDMETHODCALLTYPE AddRef()
9501 {
9502 return (BaseAddRef());
9503 }
9504 ULONG STDMETHODCALLTYPE Release()
9505 {
9506 return (BaseRelease());
9507 }
9508 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9509
9510 //-----------------------------------------------------------
9511 // ICorDebugValue
9512 //-----------------------------------------------------------
9513
9514 COM_METHOD GetType(CorElementType *pType);
9515
9516 COM_METHOD GetSize(ULONG32 *pSize)
9517 {
9518 return (CordbValue::GetSize(pSize));
9519 }
9520 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9521 {
9522 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9523 }
9524
9525 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9526 {
9527 LIMITED_METHOD_CONTRACT;
9528
9529 FAIL_IF_NEUTERED(this);
9530 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9531
9532 *pAddress = m_valueHome.GetAddress();
9533 return (S_OK);
9534 }
9535
9536 //-----------------------------------------------------------
9537 // ICorDebugValue2
9538 //-----------------------------------------------------------
9539
9540 COM_METHOD GetExactType(ICorDebugType **ppType)
9541 {
9542 return (CordbValue::GetExactType(ppType));
9543 }
9544
9545 //-----------------------------------------------------------
9546 // ICorDebugValue3
9547 //-----------------------------------------------------------
9548
9549 COM_METHOD GetSize64(ULONG64 *pSize)
9550 {
9551 return (CordbValue::GetSize64(pSize));
9552 }
9553
9554 //-----------------------------------------------------------
9555 // ICorDebugHeapValue
9556 //-----------------------------------------------------------
9557
9558 COM_METHOD IsValid(BOOL *pbValid);
9559 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9560
9561 //-----------------------------------------------------------
9562 // ICorDebugHeapValue2
9563 //-----------------------------------------------------------
9564 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9565
9566 //-----------------------------------------------------------
9567 // ICorDebugHeapValue3
9568 //-----------------------------------------------------------
9569 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9570 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9571
9572 //-----------------------------------------------------------
9573 // ICorDebugGenericValue
9574 //-----------------------------------------------------------
9575
9576 COM_METHOD GetValue(void *pTo);
9577 COM_METHOD SetValue(void *pFrom);
9578
9579 //-----------------------------------------------------------
9580 // ICorDebugBoxValue
9581 //-----------------------------------------------------------
9582 COM_METHOD GetObject(ICorDebugObjectValue **ppObject);
9583
9584 // Returns a pointer to the ValueHome field
9585 virtual
9586 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9587
9588 //-----------------------------------------------------------
9589 // Data members
9590 //-----------------------------------------------------------
9591
9592private:
9593 SIZE_T m_offsetToVars;
9594
9595 // remote location information
9596 RemoteValueHome m_valueHome;
9597
9598};
9599
9600/* ------------------------------------------------------------------------- *
9601 * Array Value class
9602 * ------------------------------------------------------------------------- */
9603
9604class CordbArrayValue : public CordbValue,
9605 public ICorDebugArrayValue,
9606 public ICorDebugGenericValue,
9607 public ICorDebugValue2,
9608 public ICorDebugValue3,
9609 public ICorDebugHeapValue2,
9610 public ICorDebugHeapValue3
9611{
9612public:
9613 CordbArrayValue(CordbAppDomain * appdomain,
9614 CordbType * type,
9615 DebuggerIPCE_ObjectData * pObjectInfo,
9616 TargetBuffer remoteValue);
9617 virtual ~CordbArrayValue();
9618
9619#ifdef _DEBUG
9620 virtual const char * DbgGetName() { return "CordbArrayValue"; }
9621#endif
9622
9623 //-----------------------------------------------------------
9624 // IUnknown
9625 //-----------------------------------------------------------
9626
9627 ULONG STDMETHODCALLTYPE AddRef()
9628 {
9629 return (BaseAddRef());
9630 }
9631 ULONG STDMETHODCALLTYPE Release()
9632 {
9633 return (BaseRelease());
9634 }
9635 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9636
9637 //-----------------------------------------------------------
9638 // ICorDebugValue
9639 //-----------------------------------------------------------
9640
9641 COM_METHOD GetType(CorElementType *pType)
9642 {
9643 return (CordbValue::GetType(pType));
9644 }
9645 COM_METHOD GetSize(ULONG32 *pSize)
9646 {
9647 return (CordbValue::GetSize(pSize));
9648 }
9649 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress)
9650 {
9651 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
9652 *pAddress = m_valueHome.GetAddress();
9653 return (S_OK);
9654 }
9655 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
9656 {
9657 return (CordbValue::CreateBreakpoint(ppBreakpoint));
9658 }
9659
9660 //-----------------------------------------------------------
9661 // ICorDebugValue2
9662 //-----------------------------------------------------------
9663
9664 COM_METHOD GetExactType(ICorDebugType **ppType)
9665 {
9666 return (CordbValue::GetExactType(ppType));
9667 }
9668
9669 //-----------------------------------------------------------
9670 // ICorDebugValue3
9671 //-----------------------------------------------------------
9672
9673 COM_METHOD GetSize64(ULONG64 *pSize)
9674 {
9675 return (CordbValue::GetSize64(pSize));
9676 }
9677
9678 //-----------------------------------------------------------
9679 // ICorDebugHeapValue
9680 //-----------------------------------------------------------
9681
9682 COM_METHOD IsValid(BOOL *pbValid);
9683 COM_METHOD CreateRelocBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9684
9685 //-----------------------------------------------------------
9686 // ICorDebugHeapValue2
9687 //-----------------------------------------------------------
9688 COM_METHOD CreateHandle(CorDebugHandleType type, ICorDebugHandleValue ** ppHandle);
9689
9690 //-----------------------------------------------------------
9691 // ICorDebugHeapValue3
9692 //-----------------------------------------------------------
9693 COM_METHOD GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount);
9694 COM_METHOD GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum);
9695
9696 //-----------------------------------------------------------
9697 // ICorDebugArrayValue
9698 //-----------------------------------------------------------
9699
9700 COM_METHOD GetElementType(CorElementType * pType);
9701 COM_METHOD GetRank(ULONG32 * pnRank);
9702 COM_METHOD GetCount(ULONG32 * pnCount);
9703 COM_METHOD GetDimensions(ULONG32 cdim, ULONG32 dims[]);
9704 COM_METHOD HasBaseIndicies(BOOL * pbHasBaseIndices);
9705 COM_METHOD GetBaseIndicies(ULONG32 cdim, ULONG32 indices[]);
9706 COM_METHOD GetElement(ULONG32 cdim, ULONG32 indices[], ICorDebugValue ** ppValue);
9707 COM_METHOD GetElementAtPosition(ULONG32 nIndex, ICorDebugValue ** ppValue);
9708
9709 //-----------------------------------------------------------
9710 // ICorDebugGenericValue
9711 //-----------------------------------------------------------
9712
9713 COM_METHOD GetValue(void *pTo);
9714 COM_METHOD SetValue(void *pFrom);
9715
9716 //-----------------------------------------------------------
9717 // Non-COM methods
9718 //-----------------------------------------------------------
9719
9720 HRESULT Init();
9721
9722 // Returns a pointer to the ValueHome field
9723 virtual
9724 RemoteValueHome * GetValueHome() { return &m_valueHome; };
9725
9726 //-----------------------------------------------------------
9727 // Data members
9728 //-----------------------------------------------------------
9729
9730private:
9731 // contains information about the array, such as rank, number of elements, element size, etc.
9732 DebuggerIPCE_ObjectData m_info;
9733
9734 // type of the elements
9735 CordbType *m_elemtype;
9736
9737 // consists of three parts: a vector containing the lower bounds for each dimension,
9738 // a vector containing the upper bounds for each dimension,
9739 // a local cached copy of (part of) the array--initialized lazily when we
9740 // request a particular element. If the array is large, we will store only
9741 // part of it, swapping out the cached segment as necessary to retrieve
9742 // requested elements.
9743 BYTE * m_pObjectCopy;
9744
9745 // points to the beginning of the vector containing the lower bounds for each dimension in m_pObjectCopy
9746 DWORD * m_arrayLowerBase;
9747
9748 // points to the beginning of the vector containing the lower bounds for each dimension in m_pObjectCopy
9749 DWORD * m_arrayUpperBase;
9750 // index of lower bound of data currently stored in m_pObjectCopy
9751 SIZE_T m_idxLower;
9752
9753 // index of upper bound of data currently stored in m_pObjectCopy
9754 SIZE_T m_idxUpper;
9755
9756 // remote location information
9757 RemoteValueHome m_valueHome;
9758
9759};
9760
9761class CordbHandleValue : public CordbValue, public ICorDebugHandleValue, public ICorDebugValue2, public ICorDebugValue3
9762{
9763public:
9764 CordbHandleValue(CordbAppDomain *appdomain,
9765 CordbType *type,
9766 CorDebugHandleType handleType);
9767 HRESULT Init(VMPTR_OBJECTHANDLE pHandle);
9768
9769 virtual ~CordbHandleValue();
9770
9771 virtual void Neuter();
9772 virtual void NeuterLeftSideResources();
9773
9774#ifdef _DEBUG
9775 virtual const char * DbgGetName() { return "CordbHandleValue"; }
9776#endif
9777
9778
9779 //-----------------------------------------------------------
9780 // IUnknown
9781 //-----------------------------------------------------------
9782
9783 ULONG STDMETHODCALLTYPE AddRef()
9784 {
9785 return (BaseAddRef());
9786 }
9787 ULONG STDMETHODCALLTYPE Release()
9788 {
9789 return (BaseRelease());
9790 }
9791 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9792
9793 //-----------------------------------------------------------
9794 // ICorDebugHandleValue interface
9795 //-----------------------------------------------------------
9796 COM_METHOD GetHandleType(CorDebugHandleType *pType);
9797
9798
9799 /*
9800 * The final release of the interface will also dispose of the handle. This
9801 * API provides the ability for client to early dispose the handle.
9802 *
9803 */
9804 COM_METHOD Dispose();
9805
9806 //-----------------------------------------------------------
9807 // ICorDebugValue interface
9808 //-----------------------------------------------------------
9809 COM_METHOD GetType(CorElementType *pType);
9810 COM_METHOD GetSize(ULONG32 *pSize);
9811 COM_METHOD GetAddress(CORDB_ADDRESS *pAddress);
9812 COM_METHOD CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint);
9813
9814 //-----------------------------------------------------------
9815 // ICorDebugValue2
9816 //-----------------------------------------------------------
9817
9818 COM_METHOD GetExactType(ICorDebugType **ppType)
9819 {
9820 FAIL_IF_NEUTERED(this);
9821
9822 // If AppDomain is already unloaded, return error
9823 if (m_appdomain->IsNeutered() == TRUE)
9824 {
9825 return COR_E_APPDOMAINUNLOADED;
9826 }
9827 if (m_vmHandle.IsNull())
9828 {
9829 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
9830 }
9831
9832 return (CordbValue::GetExactType(ppType));
9833 }
9834
9835 //-----------------------------------------------------------
9836 // ICorDebugValue3
9837 //-----------------------------------------------------------
9838
9839 COM_METHOD GetSize64(ULONG64 *pSize);
9840
9841 //-----------------------------------------------------------
9842 // ICorDebugReferenceValue interface
9843 //-----------------------------------------------------------
9844
9845 COM_METHOD IsNull(BOOL *pbNull);
9846 COM_METHOD GetValue(CORDB_ADDRESS *pValue);
9847 COM_METHOD SetValue(CORDB_ADDRESS value);
9848 COM_METHOD Dereference(ICorDebugValue **ppValue);
9849 COM_METHOD DereferenceStrong(ICorDebugValue **ppValue);
9850
9851 //-----------------------------------------------------------
9852 // Non-COM methods
9853 //-----------------------------------------------------------
9854
9855 // Returns a pointer to the ValueHome field
9856 virtual
9857 RemoteValueHome * GetValueHome() { return NULL; };
9858
9859private:
9860 //BOOL RefreshHandleValue(void **pObjectToken);
9861 HRESULT RefreshHandleValue();
9862
9863 // EE object handle pointer. Can be casted to OBJECTHANDLE when go to LS
9864 // This instance owns the handle object and must call into the VM to release
9865 // it.
9866 // If this is non-null, then we increment code:CordbProces::IncrementOutstandingHandles.
9867 // Once it goes null, we should decrement the count.
9868 // Use AssignHandle, ClearHandle to keep this in sync.
9869 VMPTR_OBJECTHANDLE m_vmHandle;
9870
9871
9872 void AssignHandle(VMPTR_OBJECTHANDLE handle);
9873 void ClearHandle();
9874
9875 BOOL m_fCanBeValid; // true if object "can" be valid. False when object is no longer valid.
9876 CorDebugHandleType m_handleType; // handle type can be strong or weak
9877 DebuggerIPCE_ObjectData m_info;
9878; // ICORDebugClass of this object when we create the handle
9879};
9880
9881// This class actually has the implementation for ICorDebugHeap3 interfaces. Any value which implements
9882// the interface just delegates to these static calls.
9883class CordbHeapValue3Impl
9884{
9885public:
9886 static HRESULT GetThreadOwningMonitorLock(CordbProcess* pProcess,
9887 CORDB_ADDRESS remoteObjAddress,
9888 ICorDebugThread **ppThread,
9889 DWORD *pAcquistionCount);
9890 static HRESULT GetMonitorEventWaitList(CordbProcess* pProcess,
9891 CORDB_ADDRESS remoteObjAddress,
9892 ICorDebugThreadEnum **ppThreadEnum);
9893};
9894
9895/* ------------------------------------------------------------------------- *
9896 * Eval class
9897 * ------------------------------------------------------------------------- */
9898
9899class CordbEval : public CordbBase, public ICorDebugEval, public ICorDebugEval2
9900{
9901public:
9902 CordbEval(CordbThread* pThread);
9903 virtual ~CordbEval();
9904
9905#ifdef _DEBUG
9906 virtual const char * DbgGetName() { return "CordbEval"; }
9907#endif
9908
9909 virtual void Neuter();
9910 virtual void NeuterLeftSideResources();
9911
9912 //-----------------------------------------------------------
9913 // IUnknown
9914 //-----------------------------------------------------------
9915
9916 ULONG STDMETHODCALLTYPE AddRef()
9917 {
9918 return (BaseAddRef());
9919 }
9920 ULONG STDMETHODCALLTYPE Release()
9921 {
9922 return (BaseRelease());
9923 }
9924 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
9925
9926 //-----------------------------------------------------------
9927 // ICorDebugEval
9928 //-----------------------------------------------------------
9929
9930 COM_METHOD CallFunction(ICorDebugFunction *pFunction,
9931 ULONG32 nArgs,
9932 ICorDebugValue *ppArgs[]);
9933 COM_METHOD NewObject(ICorDebugFunction *pConstructor,
9934 ULONG32 nArgs,
9935 ICorDebugValue *ppArgs[]);
9936 COM_METHOD NewObjectNoConstructor(ICorDebugClass *pClass);
9937 COM_METHOD NewString(LPCWSTR string);
9938 COM_METHOD NewArray(CorElementType elementType,
9939 ICorDebugClass *pElementClass,
9940 ULONG32 rank,
9941 ULONG32 dims[],
9942 ULONG32 lowBounds[]);
9943 COM_METHOD IsActive(BOOL *pbActive);
9944 COM_METHOD Abort();
9945 COM_METHOD GetResult(ICorDebugValue **ppResult);
9946 COM_METHOD GetThread(ICorDebugThread **ppThread);
9947 COM_METHOD CreateValue(CorElementType elementType,
9948 ICorDebugClass *pElementClass,
9949 ICorDebugValue **ppValue);
9950 COM_METHOD NewStringWithLength(LPCWSTR wszString, UINT iLength);
9951
9952 COM_METHOD CallParameterizedFunction(ICorDebugFunction * pFunction,
9953 ULONG32 nTypeArgs,
9954 ICorDebugType * rgpTypeArgs[],
9955 ULONG32 nArgs,
9956 ICorDebugValue * rgpArgs[]);
9957
9958 COM_METHOD CreateValueForType(ICorDebugType *pType,
9959 ICorDebugValue **ppValue);
9960
9961 COM_METHOD NewParameterizedObject(ICorDebugFunction * pConstructor,
9962 ULONG32 nTypeArgs,
9963 ICorDebugType * rgpTypeArgs[],
9964 ULONG32 nArgs,
9965 ICorDebugValue * rgpArgs[]);
9966
9967 COM_METHOD NewParameterizedObjectNoConstructor(ICorDebugClass * pClass,
9968 ULONG32 nTypeArgs,
9969 ICorDebugType * rgpTypeArgs[]);
9970
9971 COM_METHOD NewParameterizedArray(ICorDebugType * pElementType,
9972 ULONG32 rank,
9973 ULONG32 dims[],
9974 ULONG32 lowBounds[]);
9975
9976 //-----------------------------------------------------------
9977 // ICorDebugEval2
9978 //-----------------------------------------------------------
9979
9980 COM_METHOD RudeAbort();
9981
9982 //-----------------------------------------------------------
9983 // Non-COM methods
9984 //-----------------------------------------------------------
9985 HRESULT GatherArgInfo(ICorDebugValue *pValue,
9986 DebuggerIPCE_FuncEvalArgData *argData);
9987 HRESULT SendCleanup();
9988
9989 // Create a RS literal for primitive type funceval result. In case the result is used as an argument for
9990 // another funceval, we need to make sure that we're not relying on the LS value, which will be freed and
9991 // thus unavailable.
9992 HRESULT CreatePrimitiveLiteral(CordbType * pType,
9993 ICorDebugValue ** ppValue);
9994
9995 //-----------------------------------------------------------
9996 // Data members
9997 //-----------------------------------------------------------
9998
9999 bool IsEvalDuringException() { return m_evalDuringException; }
10000private:
10001 // We must keep a strong reference to the thread so we can properly fail out of SendCleanup if someone releases an
10002 // ICorDebugEval after the process has completely gone away.
10003 RSSmartPtr<CordbThread> m_thread;
10004
10005 CordbFunction *m_function;
10006 CordbClass *m_class;
10007 DebuggerIPCE_FuncEvalType m_evalType;
10008
10009 HRESULT SendFuncEval(unsigned int genericArgsCount, ICorDebugType *genericArgs[], void *argData1, unsigned int argData1Size, void *argData2, unsigned int argData2Size, DebuggerIPCEvent * event);
10010 HRESULT FilterHR(HRESULT hr);
10011 BOOL DoAppDomainsMatch( CordbAppDomain* pAppDomain, ULONG32 nTypes, ICorDebugType *pTypes[], ULONG32 nValues, ICorDebugValue *pValues[] );
10012
10013public:
10014 bool m_complete;
10015 bool m_successful;
10016 bool m_aborted;
10017 void *m_resultAddr;
10018
10019 // This is an OBJECTHANDLE on the LS if func-eval creates a strong handle.
10020 // This is a resource in the left-side and must be cleaned up in the left-side.
10021 // This gets handled off to a CordbHandleValue (m_pHandleValue) once code:CordbEval::GetResult
10022 // and then the CordbHandle is responsible for releasing it in the left-side.
10023 // Issue!! This will be leaked if nobody calls GetResult().
10024 VMPTR_OBJECTHANDLE m_vmObjectHandle;
10025
10026 // This is the corresponding cached CordbHandleValue for GetResult.
10027 // This takes ownership of the strong handle, m_objectHandle.
10028 // This is an External reference, which keeps the Value from being neutered
10029 // on a NeuterAtWill sweep.
10030 RSExtSmartPtr<CordbHandleValue> m_pHandleValue;
10031
10032 DebuggerIPCE_ExpandedTypeData m_resultType;
10033 VMPTR_AppDomain m_resultAppDomainToken;
10034
10035 // Left-side memory that needs to be freed.
10036 LSPTR_DEBUGGEREVAL m_debuggerEvalKey;
10037
10038
10039 // If we're evalling during a thread's exception, remember the info so that we can restore it when we're done.
10040 bool m_evalDuringException; // flag whether we're during the thread's exception.
10041 VMPTR_OBJECTHANDLE m_vmThreadOldExceptionHandle; // object handle for thread's managed exception object.
10042
10043#ifdef _DEBUG
10044 // Func-eval should perturb the the thread's current appdomain. So we remember it at start
10045 // and then ensure that the func-eval complete restores it.
10046 CordbAppDomain * m_DbgAppDomainStarted;
10047#endif
10048};
10049
10050
10051/* ------------------------------------------------------------------------- *
10052 * Win32 Event Thread class
10053 * ------------------------------------------------------------------------- */
10054const unsigned int CW32ET_UNKNOWN_PROCESS_SLOT = 0xFFffFFff; // it's a managed process,
10055 //but we don't know which slot it's in - for Detach.
10056
10057//---------------------------------------------------------------------------------------
10058//
10059// Dedicated thread for win32 debugging operations.
10060//
10061// Notes:
10062// This is owned by the ShimProcess object. That will both create this and destroy it.
10063// OS restriction is that all win32 debugging APIs (CreateProcess, DebugActiveProcess,
10064// DebugActiveProcessStop, WaitForDebugEvent, ContinueDebugEvent, etc) are on the same thread.
10065//
10066class CordbWin32EventThread
10067{
10068 friend class CordbProcess; //so that Detach can call ExitProcess
10069public:
10070 CordbWin32EventThread(Cordb * pCordb, ShimProcess * pShim);
10071 virtual ~CordbWin32EventThread();
10072
10073 //
10074 // You create a new instance of this class, call Init() to set it up,
10075 // then call Start() start processing events. Stop() terminates the
10076 // thread and deleting the instance cleans all the handles and such
10077 // up.
10078 //
10079 HRESULT Init();
10080 HRESULT Start();
10081 HRESULT Stop();
10082
10083 HRESULT SendCreateProcessEvent(MachineInfo machineInfo,
10084 LPCWSTR programName,
10085 __in_z LPWSTR programArgs,
10086 LPSECURITY_ATTRIBUTES lpProcessAttributes,
10087 LPSECURITY_ATTRIBUTES lpThreadAttributes,
10088 BOOL bInheritHandles,
10089 DWORD dwCreationFlags,
10090 PVOID lpEnvironment,
10091 LPCWSTR lpCurrentDirectory,
10092 LPSTARTUPINFOW lpStartupInfo,
10093 LPPROCESS_INFORMATION lpProcessInformation,
10094 CorDebugCreateProcessFlags corDebugFlags);
10095
10096 HRESULT SendDebugActiveProcessEvent(MachineInfo machineInfo,
10097 const ProcessDescriptor *pProcessDescriptor,
10098 bool fWin32Attach,
10099 CordbProcess *pProcess);
10100
10101 HRESULT SendDetachProcessEvent(CordbProcess *pProcess);
10102
10103#ifdef FEATURE_INTEROP_DEBUGGING
10104 HRESULT SendUnmanagedContinue(CordbProcess *pProcess,
10105 EUMContinueType eContType);
10106 HRESULT UnmanagedContinue(CordbProcess *pProcess,
10107 EUMContinueType eContType);
10108 void DoDbgContinue(CordbProcess * pProcess,
10109 CordbUnmanagedEvent * pUnmanagedEvent);
10110 void ForceDbgContinue(CordbProcess *pProcess,
10111 CordbUnmanagedThread *ut,
10112 DWORD contType,
10113 bool contProcess);
10114
10115#endif //FEATURE_INTEROP_DEBUGGING
10116
10117 void LockSendToWin32EventThreadMutex()
10118 {
10119 LOG((LF_CORDB, LL_INFO10000, "W32ET::LockSendToWin32EventThreadMutex\n"));
10120 m_sendToWin32EventThreadMutex.Lock();
10121 }
10122
10123 void UnlockSendToWin32EventThreadMutex()
10124 {
10125 m_sendToWin32EventThreadMutex.Unlock();
10126 LOG((LF_CORDB, LL_INFO10000, "W32ET::UnlockSendToWin32EventThreadMutex\n"));
10127 }
10128
10129 bool IsWin32EventThread()
10130 {
10131 return (m_threadId == GetCurrentThreadId());
10132 }
10133
10134 void Win32EventLoop();
10135
10136
10137 INativeEventPipeline * GetNativePipeline();
10138private:
10139 void ThreadProc();
10140 static DWORD WINAPI ThreadProc(LPVOID parameter);
10141
10142 void CreateProcess();
10143
10144
10145 INativeEventPipeline * m_pNativePipeline;
10146
10147
10148 void AttachProcess();
10149
10150 void HandleUnmanagedContinue();
10151
10152 void ExitProcess(bool fDetach);
10153
10154private:
10155 RSSmartPtr<Cordb> m_cordb;
10156
10157 HANDLE m_thread;
10158 DWORD m_threadId;
10159 HANDLE m_threadControlEvent;
10160 HANDLE m_actionTakenEvent;
10161 BOOL m_run;
10162
10163 // The process that we're 1:1 with.
10164 // This is set when we get a Create / Attach event.
10165 // This is only used on the W32ET, which guarantees it will free of races.
10166 RSSmartPtr<CordbProcess> m_pProcess;
10167
10168
10169 ShimProcess * m_pShim;
10170
10171 // @todo - convert this into Stop-Go lock?
10172 RSLock m_sendToWin32EventThreadMutex;
10173
10174 unsigned int m_action;
10175 HRESULT m_actionResult;
10176 union
10177 {
10178 struct
10179 {
10180 MachineInfo machineInfo;
10181 LPCWSTR programName;
10182 LPWSTR programArgs;
10183 LPSECURITY_ATTRIBUTES lpProcessAttributes;
10184 LPSECURITY_ATTRIBUTES lpThreadAttributes;
10185 BOOL bInheritHandles;
10186 DWORD dwCreationFlags;
10187 PVOID lpEnvironment;
10188 LPCWSTR lpCurrentDirectory;
10189 LPSTARTUPINFOW lpStartupInfo;
10190 LPPROCESS_INFORMATION lpProcessInformation;
10191 CorDebugCreateProcessFlags corDebugFlags;
10192 } createData;
10193
10194 struct
10195 {
10196 MachineInfo machineInfo;
10197 ProcessDescriptor processDescriptor;
10198#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10199 bool fWin32Attach;
10200#endif
10201 CordbProcess *pProcess;
10202
10203 // Wrapper to determine if we're interop-debugging.
10204 bool IsInteropDebugging()
10205 {
10206#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10207 return fWin32Attach;
10208#else
10209 return false;
10210#endif
10211 }
10212 } attachData;
10213
10214 struct
10215 {
10216 CordbProcess *pProcess;
10217 } detachData;
10218
10219 struct
10220 {
10221 CordbProcess *process;
10222 EUMContinueType eContType;
10223 } continueData;
10224 } m_actionData;
10225};
10226
10227
10228// Thread-safe stack which.
10229template <typename T>
10230class InterlockedStack
10231{
10232public:
10233 InterlockedStack();
10234 ~InterlockedStack();
10235
10236 // Thread safe pushes + pops.
10237 // Many threads can push simultaneously.
10238 // Only 1 thread can pop.
10239 void Push(T * pItem);
10240 T * Pop();
10241
10242protected:
10243 T * m_pHead;
10244};
10245
10246//-----------------------------------------------------------------------------
10247// Workitem to be placed on RCET worker queue.
10248// There's 1 RCET for to be shared by all processes.
10249//-----------------------------------------------------------------------------
10250class RCETWorkItem
10251{
10252public:
10253
10254 virtual ~RCETWorkItem() {}
10255
10256 // Item is executed and then removed from the list and deleted.
10257 virtual void Do() = 0;
10258
10259 CordbProcess * GetProcess() { return m_pProcess; }
10260
10261protected:
10262 RCETWorkItem(CordbProcess * pProcess)
10263 {
10264 m_pProcess.Assign(pProcess);
10265 m_next = NULL;
10266 }
10267
10268 RSSmartPtr<CordbProcess> m_pProcess;
10269
10270 // This field is accessed by the InterlockedStack.
10271 friend class InterlockedStack<RCETWorkItem>;
10272 RCETWorkItem * m_next;
10273};
10274
10275
10276// Item to do Neutering work on ExitProcess.
10277class ExitProcessWorkItem : public RCETWorkItem
10278{
10279public:
10280 ExitProcessWorkItem(CordbProcess * pProc) : RCETWorkItem(pProc)
10281 {
10282 }
10283
10284 virtual void Do();
10285};
10286
10287// Item to do send Attach event.
10288class SendAttachProcessWorkItem : public RCETWorkItem
10289{
10290public:
10291 SendAttachProcessWorkItem(CordbProcess * pProc) : RCETWorkItem(pProc)
10292 {
10293 }
10294
10295 virtual void Do();
10296};
10297
10298
10299/* ------------------------------------------------------------------------- *
10300 * Runtime Controller Event Thread class
10301 * ------------------------------------------------------------------------- */
10302
10303class CordbRCEventThread
10304{
10305public:
10306 CordbRCEventThread(Cordb* cordb);
10307 virtual ~CordbRCEventThread();
10308
10309 //
10310 // You create a new instance of this class, call Init() to set it up,
10311 // then call Start() start processing events. Stop() terminates the
10312 // thread and deleting the instance cleans all the handles and such
10313 // up.
10314 //
10315 HRESULT Init();
10316 HRESULT Start();
10317 HRESULT Stop();
10318
10319 // RCET will take ownership of this item and delete it.
10320 void QueueAsyncWorkItem(RCETWorkItem * pItem);
10321
10322 HRESULT SendIPCEvent(CordbProcess* process,
10323 DebuggerIPCEvent* event,
10324 SIZE_T eventSize);
10325
10326 void ProcessStateChanged();
10327 void FlushQueuedEvents(CordbProcess* process);
10328
10329 HRESULT WaitForIPCEventFromProcess(CordbProcess* process,
10330 CordbAppDomain *pAppDomain,
10331 DebuggerIPCEvent* event);
10332
10333 bool IsRCEventThread();
10334
10335private:
10336 void DrainWorkerQueue();
10337
10338 void ThreadProc();
10339 static DWORD WINAPI ThreadProc(LPVOID parameter);
10340
10341
10342private:
10343 InterlockedStack<class RCETWorkItem> m_WorkerStack;
10344
10345 RSSmartPtr<Cordb> m_cordb;
10346 HANDLE m_thread;
10347 DWORD m_threadId;
10348 BOOL m_run;
10349 HANDLE m_threadControlEvent;
10350 BOOL m_processStateChanged;
10351};
10352
10353#ifdef FEATURE_INTEROP_DEBUGGING
10354/* ------------------------------------------------------------------------- *
10355 * Unmanaged Event struct
10356 * ------------------------------------------------------------------------- */
10357
10358enum CordbUnmanagedEventState
10359{
10360
10361 // The continued flags get set in one of a few patterns.
10362 // 1) The event is continued having never been hijacked =>
10363 // EventContinuedUnhijacked is set
10364 // 2) The event is continued having been hijacked and then the process terminates or
10365 // an error occurs before the hijack finishes =>
10366 // EventContinuedHijacked is set
10367 // 3) The event is continued having been hijacked, then the hijack completes and
10368 // execution resumes in the debuggee
10369 // EventContinuedHijacked is set
10370 // EventContinuedUnhijacked is set
10371
10372 CUES_None = 0x00,
10373 CUES_ExceptionCleared = 0x01,
10374 CUES_EventContinuedHijacked = 0x02,
10375 CUES_EventContinuedUnhijacked = 0x04,
10376 CUES_Dispatched = 0x08,
10377 CUES_ExceptionUnclearable = 0x10,
10378
10379 // This is set when a user continues the event by calling
10380 // Continue()
10381 CUES_UserContinued = 0x20,
10382 // This is true if the event is an IB event
10383 CUES_IsIBEvent = 0x40,
10384};
10385
10386struct CordbUnmanagedEvent
10387{
10388public:
10389 BOOL IsExceptionCleared() { return m_state & CUES_ExceptionCleared; }
10390 BOOL IsEventContinuedHijacked() { return m_state & CUES_EventContinuedHijacked; }
10391 BOOL IsEventContinuedUnhijacked() { return m_state & CUES_EventContinuedUnhijacked; }
10392 BOOL IsEventUserContinued() { return m_state & CUES_UserContinued; }
10393 BOOL IsEventWaitingForContinue()
10394 {
10395 return (!IsEventContinuedHijacked() && !IsEventContinuedUnhijacked());
10396 }
10397 BOOL IsDispatched() { return m_state & CUES_Dispatched; }
10398 BOOL IsExceptionUnclearable() { return m_state & CUES_ExceptionUnclearable; }
10399 BOOL IsIBEvent() { return m_state & CUES_IsIBEvent; }
10400
10401 void SetState(CordbUnmanagedEventState state) { m_state = (CordbUnmanagedEventState)(m_state | state); }
10402 void ClearState(CordbUnmanagedEventState state) { m_state = (CordbUnmanagedEventState)(m_state & ~state); }
10403
10404 CordbUnmanagedThread *m_owner;
10405 CordbUnmanagedEventState m_state;
10406 DEBUG_EVENT m_currentDebugEvent;
10407 CordbUnmanagedEvent *m_next;
10408};
10409
10410
10411/* ------------------------------------------------------------------------- *
10412 * Unmanaged Thread class
10413 * ------------------------------------------------------------------------- */
10414
10415enum CordbUnmanagedThreadState
10416{
10417 CUTS_None = 0x0000,
10418 CUTS_Deleted = 0x0001,
10419 CUTS_FirstChanceHijacked = 0x0002,
10420 // Set when interop debugging needs the SS flag to be enabled
10421 // regardless of what the user wants it to be
10422 CUTS_IsSSFlagNeeded = 0x0004,
10423 CUTS_GenericHijacked = 0x0008,
10424 // when the m_raiseExceptionEntryContext is valid
10425 CUTS_HasRaiseExceptionEntryCtx = 0x0010,
10426 CUTS_BlockingForSync = 0x0020,
10427 CUTS_Suspended = 0x0040,
10428 CUTS_IsSpecialDebuggerThread = 0x0080,
10429 // when the thread is re-executing RaiseException to retrigger an exception
10430 CUTS_IsRaiseExceptionHijacked = 0x0100,
10431 CUTS_HasIBEvent = 0x0200,
10432 CUTS_HasOOBEvent = 0x0400,
10433 CUTS_HasSpecialStackOverflowCase = 0x0800,
10434#ifdef _DEBUG
10435 CUTS_DEBUG_SingleStep = 0x1000,
10436#endif
10437 CUTS_SkippingNativePatch = 0x2000,
10438 CUTS_HasContextSet = 0x4000,
10439 // Set when interop debugging is making use of the single step flag
10440 // but the user has not set it
10441 CUTS_IsSSFlagHidden = 0x8000
10442
10443};
10444
10445class CordbUnmanagedThread : public CordbBase
10446{
10447public:
10448 CordbUnmanagedThread(CordbProcess *pProcess, DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase);
10449 ~CordbUnmanagedThread();
10450
10451 using CordbBase::GetProcess;
10452
10453#ifdef _DEBUG
10454 virtual const char * DbgGetName() { return "CordbUnmanagedThread"; }
10455#endif
10456
10457 // CordbUnmanagedThread is a purely internal object. It's not exposed via ICorDebug APIs and so
10458 // we should never use External AddRef.
10459 ULONG STDMETHODCALLTYPE AddRef() { _ASSERTE(!"Don't use external addref on a CordbUnmanagedThread"); return (BaseAddRef());}
10460 ULONG STDMETHODCALLTYPE Release() { _ASSERTE(!"Don't use external release on a CordbUnmanagedThread"); return (BaseRelease());}
10461
10462 COM_METHOD QueryInterface(REFIID riid, void **ppInterface)
10463 {
10464 _ASSERTE(!"Don't use QI on a CordbUnmanagedThread");
10465 // Not really used since we never expose this class. If we ever do expose this class via the ICorDebug API then
10466 // we should, of course, implement this.
10467 return E_NOINTERFACE;
10468 }
10469
10470 HRESULT LoadTLSArrayPtr();
10471
10472 // Hijacks this thread to a hijack worker function which recieves the current
10473 // context and the provided exception record. The reason determines what code
10474 // the hijack worker executes
10475 HRESULT SetupFirstChanceHijack(EHijackReason::EHijackReason reason, const EXCEPTION_RECORD * pExceptionRecord);
10476 HRESULT SetupFirstChanceHijackForSync();
10477
10478 HRESULT SetupGenericHijack(DWORD eventCode, const EXCEPTION_RECORD * pRecord);
10479 HRESULT FixupFromGenericHijack();
10480
10481 HRESULT FixupAfterOOBException(CordbUnmanagedEvent * ue);
10482
10483 void SetupForSkipBreakpoint(NativePatch * pNativePatch);
10484 void FixupForSkipBreakpoint();
10485 bool IsCantStop();
10486
10487 // These are wrappers for the OS calls which hide
10488 // the effects of hijacking and internal SS flag usage
10489 HRESULT GetThreadContext(DT_CONTEXT * pContext);
10490 HRESULT SetThreadContext(DT_CONTEXT * pContext);
10491
10492 // Turns on and off the internal usage of the SS flag
10493 VOID BeginStepping();
10494 VOID EndStepping();
10495
10496 // An accessor for &m_context, this value generally stores
10497 // a context we may need to restore after a hijack completes
10498 DT_CONTEXT * GetHijackCtx();
10499
10500private:
10501 CORDB_ADDRESS m_stackBase;
10502 CORDB_ADDRESS m_stackLimit;
10503
10504public:
10505 BOOL GetStackRange(CORDB_ADDRESS *pBase, CORDB_ADDRESS *pLimit);
10506
10507 BOOL IsDeleted() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_Deleted; }
10508 BOOL IsFirstChanceHijacked() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_FirstChanceHijacked; }
10509 BOOL IsGenericHijacked() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_GenericHijacked; }
10510 BOOL IsBlockingForSync() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_BlockingForSync; }
10511 BOOL IsSuspended() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_Suspended; }
10512 BOOL IsSpecialDebuggerThread() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSpecialDebuggerThread; }
10513 BOOL HasIBEvent() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasIBEvent; }
10514 BOOL HasOOBEvent() { return m_state & CUTS_HasOOBEvent; }
10515 BOOL HasSpecialStackOverflowCase() {LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasSpecialStackOverflowCase; }
10516#ifdef _DEBUG
10517 BOOL IsDEBUGTrace() { return m_state & CUTS_DEBUG_SingleStep; }
10518#endif
10519 BOOL IsSkippingNativePatch() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_SkippingNativePatch; }
10520 BOOL IsContextSet() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasContextSet; }
10521 BOOL IsSSFlagNeeded() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSSFlagNeeded; }
10522 BOOL IsSSFlagHidden() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsSSFlagHidden; }
10523 BOOL HasRaiseExceptionEntryCtx() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_HasRaiseExceptionEntryCtx; }
10524 BOOL IsRaiseExceptionHijacked() { LIMITED_METHOD_CONTRACT; return m_state & CUTS_IsRaiseExceptionHijacked; }
10525
10526 void SetState(CordbUnmanagedThreadState state)
10527 {
10528 LIMITED_METHOD_CONTRACT;
10529 m_state = (CordbUnmanagedThreadState)(m_state | state);
10530 _ASSERTE(!IsSuspended() || !IsBlockingForSync());
10531 _ASSERTE(!IsSuspended() || !IsFirstChanceHijacked());
10532 }
10533 void ClearState(CordbUnmanagedThreadState state) {LIMITED_METHOD_CONTRACT; m_state = (CordbUnmanagedThreadState)(m_state & ~state); }
10534
10535 void HijackToRaiseException();
10536 void RestoreFromRaiseExceptionHijack();
10537 void SaveRaiseExceptionEntryContext();
10538 void ClearRaiseExceptionEntryContext();
10539 BOOL IsExceptionFromLastRaiseException(const EXCEPTION_RECORD* pExceptionRecord);
10540
10541 CordbUnmanagedEvent *IBEvent() {LIMITED_METHOD_CONTRACT; return &m_IBEvent; }
10542 CordbUnmanagedEvent *IBEvent2() {LIMITED_METHOD_CONTRACT; return &m_IBEvent2; }
10543 CordbUnmanagedEvent *OOBEvent() { return &m_OOBEvent; }
10544
10545 DWORD GetOSTid()
10546 {
10547 return (DWORD) this->m_id;
10548 }
10549
10550#ifdef DBG_TARGET_X86
10551 // Stores the thread's current leaf SEH handler
10552 HRESULT SaveCurrentLeafSeh();
10553 // Restores the thread's leaf SEH handler from the previously saved value
10554 HRESULT RestoreLeafSeh();
10555#endif
10556
10557 // Logs basic data about a context to the debugging log
10558 static VOID LogContext(DT_CONTEXT* pContext);
10559
10560public:
10561 HANDLE m_handle;
10562
10563 // @dbgtodo - the TLS reading is only used for interop hijacks; which goes away in Arrowhead.
10564 // Target address of the Thread Information Block (TIB).
10565 void *m_threadLocalBase;
10566
10567 // Target address of the Thread Local Storage (TLS) array. This is for slots 0 -63.
10568 void *m_pTLSArray;
10569
10570 // Target Address of extended Thread local Storage array. These are for slots about 63.
10571 // This may be NULL if extended storage is not yet allocated.
10572 void *m_pTLSExtendedArray;
10573
10574
10575 CordbUnmanagedThreadState m_state;
10576
10577 CordbUnmanagedEvent m_IBEvent;
10578 CordbUnmanagedEvent m_IBEvent2;
10579 CordbUnmanagedEvent m_OOBEvent;
10580
10581 LSPTR_CONTEXT m_pLeftSideContext;
10582 void *m_originalHandler;
10583
10584private:
10585 // Spare context used for various purposes.
10586 // See CordbUnmanagedThread::GetThreadContext for details
10587 DT_CONTEXT m_context;
10588
10589 // The context of the thread the last time it called into kernel32!RaiseException
10590 DT_CONTEXT m_raiseExceptionEntryContext;
10591
10592 DWORD m_raiseExceptionExceptionCode;
10593 DWORD m_raiseExceptionExceptionFlags;
10594 DWORD m_raiseExceptionNumberParameters;
10595 ULONG_PTR m_raiseExceptionExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
10596
10597
10598#ifdef DBG_TARGET_X86
10599 // the SEH handler which was the leaf when SaveCurrentSeh was called (prior to hijack)
10600 REMOTE_PTR m_pSavedLeafSeh;
10601#endif
10602
10603 HRESULT EnableSSAfterBP();
10604 bool GetEEThreadCantStopHelper();
10605
10606 HRESULT GetTlsSlot(DWORD slot, REMOTE_PTR *pValue);
10607 HRESULT SetTlsSlot(DWORD slot, REMOTE_PTR value);
10608 REMOTE_PTR GetPreDefTlsSlot(SIZE_T slot, bool * pRead);
10609
10610 void * m_pPatchSkipAddress;
10611
10612 UINT m_continueCountCached;
10613
10614 DWORD_PTR GetEEThreadValue();
10615 REMOTE_PTR GetEETlsDataBlock();
10616 HRESULT GetClrModuleTlsDataAddress(REMOTE_PTR* pAddress);
10617
10618public:
10619 HRESULT GetEEDebuggerWord(REMOTE_PTR *pValue);
10620 HRESULT SetEEDebuggerWord(REMOTE_PTR value);
10621 HRESULT GetEEThreadPtr(REMOTE_PTR *ppEEThread);
10622
10623 bool GetEEPGCDisabled();
10624 void GetEEState(bool *threadStepping, bool *specialManagedException);
10625 bool GetEEFrame();
10626};
10627#endif // FEATURE_INTEROP_DEBUGGING
10628
10629
10630//********************************************************************************
10631//**************** App Domain Publishing Service API *****************************
10632//********************************************************************************
10633
10634
10635class EnumElement
10636{
10637public:
10638 EnumElement()
10639 {
10640 m_pData = NULL;
10641 m_pNext = NULL;
10642 }
10643
10644 void SetData (void *pData) { m_pData = pData;}
10645 void *GetData () { return m_pData;}
10646 void SetNext (EnumElement *pNext) { m_pNext = pNext;}
10647 EnumElement *GetNext () { return m_pNext;}
10648
10649private:
10650 void *m_pData;
10651 EnumElement *m_pNext;
10652};
10653
10654#if defined(FEATURE_DBG_PUBLISH)
10655
10656// Prototype of psapi!GetModuleFileNameEx.
10657typedef DWORD FPGetModuleFileNameEx(HANDLE, HMODULE, LPTSTR, DWORD);
10658
10659
10660class CorpubPublish : public CordbCommonBase, public ICorPublish
10661{
10662public:
10663 CorpubPublish();
10664 virtual ~CorpubPublish();
10665
10666#ifdef _DEBUG
10667 virtual const char * DbgGetName() { return "CordbPublish"; }
10668#endif
10669
10670 //-----------------------------------------------------------
10671 // IUnknown
10672 //-----------------------------------------------------------
10673
10674 ULONG STDMETHODCALLTYPE AddRef()
10675 {
10676 return (BaseAddRef());
10677 }
10678 ULONG STDMETHODCALLTYPE Release()
10679 {
10680 return (BaseRelease());
10681 }
10682 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10683
10684 //-----------------------------------------------------------
10685 // ICorPublish
10686 //-----------------------------------------------------------
10687
10688 COM_METHOD EnumProcesses(
10689 COR_PUB_ENUMPROCESS Type,
10690 ICorPublishProcessEnum **ppIEnum);
10691
10692 COM_METHOD GetProcess(
10693 unsigned pid,
10694 ICorPublishProcess **ppProcess);
10695
10696 //-----------------------------------------------------------
10697 // CreateObject
10698 //-----------------------------------------------------------
10699 static COM_METHOD CreateObject(REFIID id, void **object)
10700 {
10701 *object = NULL;
10702
10703 if (id != IID_IUnknown && id != IID_ICorPublish)
10704 return (E_NOINTERFACE);
10705
10706 CorpubPublish *pCorPub = new (nothrow) CorpubPublish();
10707
10708 if (pCorPub == NULL)
10709 return (E_OUTOFMEMORY);
10710
10711 *object = (ICorPublish*)pCorPub;
10712 pCorPub->AddRef();
10713
10714 return (S_OK);
10715 }
10716
10717private:
10718 HRESULT GetProcessInternal( unsigned pid, CorpubProcess **ppProcess );
10719
10720 // Cached information to get the process name. Not available on all platforms, so may be null.
10721 HModuleHolder m_hPSAPIdll;
10722 FPGetModuleFileNameEx * m_fpGetModuleFileNameEx;
10723};
10724
10725class CorpubProcess : public CordbCommonBase, public ICorPublishProcess
10726{
10727public:
10728 CorpubProcess(const ProcessDescriptor * pProcessDescriptor,
10729 bool fManaged,
10730 HANDLE hProcess,
10731 HANDLE hMutex,
10732 AppDomainEnumerationIPCBlock *pAD,
10733#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10734 IPCReaderInterface *pIPCReader,
10735#endif // !FEATURE_DBGIPC_TRANSPORT_DI
10736 FPGetModuleFileNameEx * fpGetModuleFileNameEx);
10737 virtual ~CorpubProcess();
10738
10739#ifdef _DEBUG
10740 virtual const char * DbgGetName() { return "CorpubProcess"; }
10741#endif
10742
10743
10744 //-----------------------------------------------------------
10745 // IUnknown
10746 //-----------------------------------------------------------
10747
10748 ULONG STDMETHODCALLTYPE AddRef()
10749 {
10750 return (BaseAddRef());
10751 }
10752 ULONG STDMETHODCALLTYPE Release()
10753 {
10754 return (BaseRelease());
10755 }
10756 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10757
10758 //-----------------------------------------------------------
10759 // ICorPublishProcess
10760 //-----------------------------------------------------------
10761 COM_METHOD IsManaged(BOOL *pbManaged);
10762
10763 /*
10764 * Enumerate the list of known application domains in the target process.
10765 */
10766 COM_METHOD EnumAppDomains(ICorPublishAppDomainEnum **ppEnum);
10767
10768 /*
10769 * Returns the OS ID for the process in question.
10770 */
10771 COM_METHOD GetProcessID(unsigned *pid);
10772
10773 /*
10774 * Get the display name for a process.
10775 */
10776 COM_METHOD GetDisplayName(ULONG32 cchName,
10777 ULONG32 *pcchName,
10778 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
10779
10780 CorpubProcess *GetNextProcess () { return m_pNext;}
10781 void SetNext (CorpubProcess *pNext) { m_pNext = pNext;}
10782
10783 // Helper to tell if this process has exited
10784 bool IsExited();
10785
10786public:
10787 ProcessDescriptor m_processDescriptor;
10788
10789private:
10790 bool m_fIsManaged;
10791 HANDLE m_hProcess;
10792 HANDLE m_hMutex;
10793 AppDomainEnumerationIPCBlock *m_AppDomainCB;
10794#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
10795 IPCReaderInterface *m_pIPCReader; // controls the lifetime of the AppDomainEnumerationIPCBlock
10796#endif // !FEATURE_DBGIPC_TRANSPORT_DI
10797 CorpubProcess *m_pNext; // pointer to the next process in the process list
10798 WCHAR *m_szProcessName;
10799
10800};
10801
10802class CorpubAppDomain : public CordbCommonBase, public ICorPublishAppDomain
10803{
10804public:
10805 CorpubAppDomain (__in LPWSTR szAppDomainName, ULONG Id);
10806 virtual ~CorpubAppDomain();
10807
10808#ifdef _DEBUG
10809 virtual const char * DbgGetName() { return "CorpubAppDomain"; }
10810#endif
10811
10812 //-----------------------------------------------------------
10813 // IUnknown
10814 //-----------------------------------------------------------
10815
10816 ULONG STDMETHODCALLTYPE AddRef()
10817 {
10818 return (BaseAddRef());
10819 }
10820 ULONG STDMETHODCALLTYPE Release()
10821 {
10822 return (BaseRelease());
10823 }
10824 COM_METHOD QueryInterface (REFIID riid, void **ppInterface);
10825
10826 //-----------------------------------------------------------
10827 // ICorPublishAppDomain
10828 //-----------------------------------------------------------
10829
10830 /*
10831 * Get the name and ID for an application domain.
10832 */
10833 COM_METHOD GetID (ULONG32 *pId);
10834
10835 /*
10836 * Get the name for an application domain.
10837 */
10838 COM_METHOD GetName (ULONG32 cchName,
10839 ULONG32 *pcchName,
10840 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
10841
10842 CorpubAppDomain *GetNextAppDomain () { return m_pNext;}
10843 void SetNext (CorpubAppDomain *pNext) { m_pNext = pNext;}
10844
10845private:
10846 CorpubAppDomain *m_pNext;
10847 WCHAR *m_szAppDomainName;
10848 ULONG m_id;
10849
10850};
10851
10852class CorpubProcessEnum : public CordbCommonBase, public ICorPublishProcessEnum
10853{
10854public:
10855 CorpubProcessEnum(CorpubProcess *pFirst);
10856 virtual ~CorpubProcessEnum();
10857
10858#ifdef _DEBUG
10859 virtual const char * DbgGetName() { return "CorpubProcessEnum"; }
10860#endif
10861
10862
10863 //-----------------------------------------------------------
10864 // IUnknown
10865 //-----------------------------------------------------------
10866
10867 ULONG STDMETHODCALLTYPE AddRef()
10868 {
10869 return (BaseAddRef());
10870 }
10871 ULONG STDMETHODCALLTYPE Release()
10872 {
10873 return (BaseRelease());
10874 }
10875 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10876
10877 //-----------------------------------------------------------
10878 // ICorPublishProcessEnum
10879 //-----------------------------------------------------------
10880
10881 COM_METHOD Skip(ULONG celt);
10882 COM_METHOD Reset();
10883 COM_METHOD Clone(ICorPublishEnum **ppEnum);
10884 COM_METHOD GetCount(ULONG *pcelt);
10885 COM_METHOD Next(ULONG celt,
10886 ICorPublishProcess *objects[],
10887 ULONG *pceltFetched);
10888
10889private:
10890 CorpubProcess *m_pFirst;
10891 CorpubProcess *m_pCurrent;
10892
10893};
10894
10895class CorpubAppDomainEnum : public CordbCommonBase, public ICorPublishAppDomainEnum
10896{
10897public:
10898 CorpubAppDomainEnum(CorpubAppDomain *pFirst);
10899 virtual ~CorpubAppDomainEnum();
10900
10901
10902#ifdef _DEBUG
10903 virtual const char * DbgGetName() { return "CordbAppDomainEnum"; }
10904#endif
10905
10906
10907 //-----------------------------------------------------------
10908 // IUnknown
10909 //-----------------------------------------------------------
10910
10911 ULONG STDMETHODCALLTYPE AddRef()
10912 {
10913 return (BaseAddRef());
10914 }
10915 ULONG STDMETHODCALLTYPE Release()
10916 {
10917 return (BaseRelease());
10918 }
10919 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10920
10921 //-----------------------------------------------------------
10922 // ICorPublishAppDomainEnum
10923 //-----------------------------------------------------------
10924 COM_METHOD Skip(ULONG celt);
10925 COM_METHOD Reset();
10926 COM_METHOD Clone(ICorPublishEnum **ppEnum);
10927 COM_METHOD GetCount(ULONG *pcelt);
10928
10929 COM_METHOD Next(ULONG celt,
10930 ICorPublishAppDomain *objects[],
10931 ULONG *pceltFetched);
10932
10933private:
10934 CorpubAppDomain *m_pFirst;
10935 CorpubAppDomain *m_pCurrent;
10936
10937};
10938
10939#endif // defined(FEATURE_DBG_PUBLISH)
10940
10941class CordbHeapEnum : public CordbBase, public ICorDebugHeapEnum
10942{
10943public:
10944 CordbHeapEnum(CordbProcess *proc);
10945
10946#ifdef _DEBUG
10947 virtual const char * DbgGetName() { return "CordbHeapEnum"; }
10948#endif
10949
10950 //-----------------------------------------------------------
10951 // IUnknown
10952 //-----------------------------------------------------------
10953 ULONG STDMETHODCALLTYPE AddRef()
10954 {
10955 return (BaseAddRef());
10956 }
10957 ULONG STDMETHODCALLTYPE Release()
10958 {
10959 return (BaseRelease());
10960 }
10961 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
10962
10963 COM_METHOD Skip(ULONG celt);
10964 COM_METHOD Reset();
10965 COM_METHOD Clone(ICorDebugEnum **ppEnum);
10966 COM_METHOD GetCount(ULONG *pcelt);
10967
10968 COM_METHOD Next(ULONG celt,
10969 COR_HEAPOBJECT objects[],
10970 ULONG *pceltFetched);
10971
10972 virtual void Neuter()
10973 {
10974 Clear();
10975 CordbBase::Neuter();
10976 }
10977private:
10978 void Clear();
10979
10980private:
10981 IDacDbiInterface::HeapWalkHandle mHeapHandle;
10982};
10983
10984
10985class CordbRefEnum : public CordbBase, public ICorDebugGCReferenceEnum
10986{
10987public:
10988 CordbRefEnum(CordbProcess *proc, BOOL walkWeakRefs);
10989 CordbRefEnum(CordbProcess *proc, CorGCReferenceType types);
10990
10991#ifdef _DEBUG
10992 virtual const char * DbgGetName() { return "CordbHeapEnum"; }
10993#endif
10994
10995 //-----------------------------------------------------------
10996 // IUnknown
10997 //-----------------------------------------------------------
10998 ULONG STDMETHODCALLTYPE AddRef()
10999 {
11000 return (BaseAddRef());
11001 }
11002 ULONG STDMETHODCALLTYPE Release()
11003 {
11004 return (BaseRelease());
11005 }
11006 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
11007
11008 COM_METHOD Skip(ULONG celt);
11009 COM_METHOD Reset();
11010 COM_METHOD Clone(ICorDebugEnum **ppEnum);
11011 COM_METHOD GetCount(ULONG *pcelt);
11012
11013 COM_METHOD Next(ULONG celt,
11014 COR_GC_REFERENCE refs[],
11015 ULONG *pceltFetched);
11016
11017 virtual void Neuter();
11018
11019private:
11020 RefWalkHandle mRefHandle;
11021 BOOL mEnumStacksFQ;
11022 UINT32 mHandleMask;
11023};
11024
11025// Since the hash table of modules is per app domain (and
11026// threads is per process) (for fast lookup from the appdomain/process),
11027// we need this wrapper
11028// here which allows us to iterate through an assembly's
11029// modules. Is basically filters out modules/threads that aren't
11030// in the assembly/appdomain. This slow & awkward for assemblies, but fast
11031// for the common case - appdomain lookup.
11032class CordbEnumFilter : public CordbBase,
11033 public ICorDebugThreadEnum,
11034 public ICorDebugModuleEnum
11035{
11036public:
11037 CordbEnumFilter(CordbBase * pOwnerObj, NeuterList * pOwnerList);
11038 CordbEnumFilter(CordbEnumFilter*src);
11039 virtual ~CordbEnumFilter();
11040
11041 virtual void Neuter();
11042
11043
11044#ifdef _DEBUG
11045 virtual const char * DbgGetName() { return "CordbEnumFilter"; }
11046#endif
11047
11048
11049 //-----------------------------------------------------------
11050 // IUnknown
11051 //-----------------------------------------------------------
11052
11053 ULONG STDMETHODCALLTYPE AddRef()
11054 {
11055 return (BaseAddRef());
11056 }
11057 ULONG STDMETHODCALLTYPE Release()
11058 {
11059 return (BaseRelease());
11060 }
11061 COM_METHOD QueryInterface(REFIID riid, void **ppInterface);
11062
11063 //-----------------------------------------------------------
11064 // Common methods
11065 //-----------------------------------------------------------
11066 COM_METHOD Skip(ULONG celt);
11067 COM_METHOD Reset();
11068 COM_METHOD Clone(ICorDebugEnum **ppEnum);
11069 COM_METHOD GetCount(ULONG *pcelt);
11070 //-----------------------------------------------------------
11071 // ICorDebugModuleEnum
11072 //-----------------------------------------------------------
11073 COM_METHOD Next(ULONG celt,
11074 ICorDebugModule *objects[],
11075 ULONG *pceltFetched);
11076
11077 //-----------------------------------------------------------
11078 // ICorDebugThreadEnum
11079 //-----------------------------------------------------------
11080 COM_METHOD Next(ULONG celt,
11081 ICorDebugThread *objects[],
11082 ULONG *pceltFetched);
11083
11084 HRESULT Init (ICorDebugModuleEnum *pModEnum, CordbAssembly *pAssembly);
11085 HRESULT Init (ICorDebugThreadEnum *pThreadEnum, CordbAppDomain *pAppDomain);
11086
11087
11088private:
11089 HRESULT NextWorker(ULONG celt, ICorDebugModule *objects[], ULONG *pceltFetched);
11090 HRESULT NextWorker(ULONG celt,ICorDebugThread *objects[], ULONG *pceltFetched);
11091
11092 // Owning object is our link to the CordbProcess* tree. Never null until we're neutered.
11093 // NeuterList is related to the owning object. Need to cache it so that we can pass it on
11094 // to our clones.
11095 CordbBase * m_pOwnerObj; // provides us w/ a CordbProcess*
11096 NeuterList * m_pOwnerNeuterList;
11097
11098
11099 EnumElement *m_pFirst;
11100 EnumElement *m_pCurrent;
11101 int m_iCount;
11102};
11103
11104// Helpers to double-check the RS results against DAC.
11105#if defined(_DEBUG)
11106void CheckAgainstDAC(CordbFunction * pFunc, void * pIP, mdMethodDef mdExpected);
11107#endif
11108
11109HRESULT CopyOutString(const WCHAR * pInputString, ULONG32 cchName, ULONG32 * pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[]);
11110
11111
11112
11113inline UINT AllocCookieCordbEval(CordbProcess *pProc, CordbEval* p)
11114{
11115 _ASSERTE(pProc->GetProcessLock()->HasLock());
11116 return pProc->m_EvalTable.Add(p);
11117}
11118inline CordbEval * UnwrapCookieCordbEval(CordbProcess *pProc, UINT cookie)
11119{
11120 _ASSERTE(pProc->GetProcessLock()->HasLock());
11121 return pProc->m_EvalTable.LookupAndRemove(cookie);
11122}
11123
11124
11125// We defined this at the top of the file - undef it now so that we don't pollute other files.
11126#undef CRITICAL_SECTION
11127
11128
11129#ifdef RSCONTRACTS
11130
11131//-----------------------------------------------------------------------------
11132// For debug builds, we maintain some thread-state to track debug bits
11133// to help us do some more aggressive asserts.
11134//-----------------------------------------------------------------------------
11135
11136class PublicAPIHolder;
11137class PublicReentrantAPIHolder;
11138class PublicCallbackHolder;
11139class PublicDebuggerErrorCallbackHolder;
11140
11141class DbgRSThread
11142{
11143public:
11144 friend class PublicAPIHolder;
11145 friend class PublicReentrantAPIHolder;
11146 friend class PublicCallbackHolder;
11147 friend class PublicDebuggerErrorCallbackHolder;
11148 friend class PrivateShimCallbackHolder;
11149
11150 DbgRSThread();
11151
11152 // The TLS slot that we'll put this thread object in.
11153 static DWORD s_TlsSlot;
11154
11155 static LONG s_Total; // Total count of thread objects
11156
11157 // Get a thread object for the current thread via a TLS lookup.
11158 static DbgRSThread * GetThread();
11159
11160 // Call during DllMain to release this.
11161 static DbgRSThread * Create()
11162 {
11163 InterlockedIncrement(&s_Total);
11164
11165 DbgRSThread * p = new (nothrow) DbgRSThread();
11166 BOOL f = TlsSetValue(s_TlsSlot, p);
11167 _ASSERT(f);
11168 return p;
11169 }
11170
11171 void Destroy()
11172 {
11173 InterlockedDecrement(&s_Total);
11174
11175 BOOL f = TlsSetValue(s_TlsSlot, NULL);
11176 _ASSERT(f);
11177
11178 delete this;
11179 }
11180
11181 // Return true if this thread is inside the RS.
11182 bool IsInRS() { return m_cInsideRS > 0; }
11183
11184 // Locking API..
11185 // These will assert if the operation is unsafe.
11186 void NotifyTakeLock(RSLock * pLock);
11187 void NotifyReleaseLock(RSLock * pLock);
11188
11189 // Used to map other resources (like thread access) into the lock hierachy.
11190 // Note this only effects lock leveling checks and doesn't effect HoldsAnyLock().
11191 void TakeVirtualLock(RSLock::ERSLockLevel level);
11192 void ReleaseVirtualLock(RSLock::ERSLockLevel level);
11193
11194 // return true if this thread is holding any RS locks. Useful to check on Public API transition boundaries.
11195 bool HoldsAnyDbgApiLocks() { return m_cTotalDbgApiLocks > 0; }
11196
11197 enum EThreadType
11198 {
11199 cOther,
11200 cW32ET
11201 };
11202 void SetThreadType(EThreadType e) { m_eThreadType = e; }
11203
11204 bool IsWin32EventThread() { return m_eThreadType == cW32ET; }
11205
11206 void SetUnrecoverableCallback(bool fIsUnrecoverableErrorCallback)
11207 {
11208 // Not reentrant.
11209 _ASSERTE(m_fIsUnrecoverableErrorCallback != fIsUnrecoverableErrorCallback);
11210
11211 m_fIsUnrecoverableErrorCallback = fIsUnrecoverableErrorCallback;
11212 }
11213
11214 inline void AssertThreadIsLockFree()
11215 {
11216 // If we're in an unrecoverable callback, we may hold locks.
11217 _ASSERTE(m_fIsUnrecoverableErrorCallback
11218 || !HoldsAnyDbgApiLocks() ||
11219 !"Thread should not have locks on public/internal transition");
11220 }
11221
11222protected:
11223 EThreadType m_eThreadType;
11224
11225 // More debugging tidbits - tid that we're on, and a sanity checking cookie.
11226 DWORD m_tid;
11227 DWORD m_Cookie;
11228
11229 enum ECookie
11230 {
11231 COOKIE_VALUE = 0x12345678
11232 };
11233
11234
11235 // This tells us if the thread is currently in the scope of a PublicAPIHolder.
11236 int m_cInsideRS;
11237
11238 // This tells us if a thread is currently being dispatched via a callback.
11239 bool m_fIsInCallback;
11240
11241 // We explicitly track if this thread is in an unrecoverable error callback
11242 // b/c that will weaken some other asserts.
11243 // It would be nice to clean up the unrecoverable error callback and have it
11244 // behave like all the other callbacks. Then we can remove this.
11245 bool m_fIsUnrecoverableErrorCallback;
11246
11247 // Locking context. Used to tell what levels of locks we hold so we can determine if a lock is safe to take.
11248 int m_cLocks[RSLock::LL_MAX];
11249 int m_cTotalDbgApiLocks;
11250};
11251
11252//-----------------------------------------------------------------------------
11253// Mark when we enter / exit public APIs
11254//-----------------------------------------------------------------------------
11255
11256// Holder for Non-reentrant Public API (this is the vast majority)
11257class PublicAPIHolder
11258{
11259public:
11260 PublicAPIHolder()
11261 {
11262 // on entry
11263 DbgRSThread * pThread = DbgRSThread::GetThread();
11264 pThread->m_cInsideRS++;
11265 _ASSERTE(pThread->m_cInsideRS == 1 || !"Non-reentrant API being called re-entrantly");
11266
11267 // Should never be in public w/ these locks
11268 pThread->AssertThreadIsLockFree();
11269 }
11270 ~PublicAPIHolder() {
11271 // On exit.
11272 DbgRSThread * pThread = DbgRSThread::GetThread();
11273 pThread->m_cInsideRS--;
11274 _ASSERTE(!pThread->IsInRS());
11275
11276 // Should never be in public w/ these locks. If we assert here,
11277 // then we're leaking locks.
11278 pThread->AssertThreadIsLockFree();
11279 }
11280};
11281
11282// Holder for reentrant public API
11283class PublicReentrantAPIHolder
11284{
11285public:
11286 PublicReentrantAPIHolder()
11287 {
11288 // on entry
11289 DbgRSThread * pThread = DbgRSThread::GetThread();
11290 pThread->m_cInsideRS++;
11291
11292 // Cache count now so that we can calidate it in the dtor.
11293 m_oldCount = pThread->m_cInsideRS;
11294 // Since a we may have been called from within the RS, we may hold locks
11295 }
11296 ~PublicReentrantAPIHolder()
11297 {
11298
11299 // On exit.
11300 DbgRSThread * pThread = DbgRSThread::GetThread();
11301
11302 // Ensure that our children were balanced
11303 _ASSERTE(pThread->m_cInsideRS == m_oldCount);
11304
11305 pThread->m_cInsideRS--;
11306 _ASSERTE(pThread->m_cInsideRS >= 0);
11307
11308 // Since a we may have been called from within the RS, we may hold locks
11309 }
11310private:
11311 int m_oldCount;
11312};
11313
11314// Special holder for DebuggerError callback. This adjusts InsideRS count w/o
11315// verifying locks. This is very dangerous. We allow this b/c the Debugger Error callback can come at any time.
11316class PublicDebuggerErrorCallbackHolder
11317{
11318public:
11319 PublicDebuggerErrorCallbackHolder()
11320 {
11321 // Exiting from RS; entering Cordbg via a callback
11322 DbgRSThread * pThread = DbgRSThread::GetThread();
11323
11324 // This callback is called from within the RS
11325 _ASSERTE(pThread->IsInRS());
11326
11327 // Debugger error callback may be called from deep within the RS (after many nestings).
11328 // So immediately jump to outside. We'll restore this in dtor.
11329 m_oldCount = pThread->m_cInsideRS;
11330 pThread->m_cInsideRS = 0;
11331
11332 _ASSERTE(!pThread->IsInRS());
11333
11334 // We may be leaking locks for the unrecoverable callback. We mark that so that
11335 // the asserts about locking can be relaxed.
11336 pThread->SetUnrecoverableCallback(true);
11337 }
11338
11339 ~PublicDebuggerErrorCallbackHolder()
11340 {
11341 // Re-entering RS from after a callback.
11342 DbgRSThread * pThread = DbgRSThread::GetThread();
11343
11344 pThread->SetUnrecoverableCallback(false);
11345 pThread->m_cInsideRS = m_oldCount;
11346
11347 // Our status of being "Inside the RS" is now restored.
11348 _ASSERTE(pThread->IsInRS());
11349 }
11350private:
11351 int m_oldCount;
11352};
11353
11354//---------------------------------------------------------------------------------------
11355//
11356// This is the same as the PublicCallbackHolder, except that this class doesn't assert that we are not holding
11357// any locks when we call out to the shim.
11358//
11359// Notes:
11360// @dbgtodo shim, synchronization - We need to settle on one consistent relationshipo between the RS
11361// and the shim. Then we can clean up the sychronization story. Right now some code considers the shim
11362// to be outside of the RS, and so we cannot hold any locks when we call out to the shim. However, there
11363// are cases where we must hold a lock when we call out to the shim. For example, when we call out to the
11364// shim to do a V2-style stackwalk, we need to be holding the stop-go lock so that another thread can't
11365// come in and call Continue(). Finally, when we fix this, we should fix
11366// PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM() as well.
11367//
11368
11369class PrivateShimCallbackHolder
11370{
11371public:
11372 PrivateShimCallbackHolder()
11373 {
11374 // Exiting from RS; entering Cordbg via a callback
11375 DbgRSThread * pThread = DbgRSThread::GetThread();
11376
11377 // This callback is called from within the RS
11378 _ASSERTE(pThread->IsInRS());
11379
11380 // Debugger error callback may be called from deep within the RS (after many nestings).
11381 // So immediately jump to outside. We'll restore this in dtor.
11382 m_oldCount = pThread->m_cInsideRS;
11383 pThread->m_cInsideRS = 0;
11384
11385 _ASSERTE(!pThread->IsInRS());
11386 }
11387
11388 ~PrivateShimCallbackHolder()
11389 {
11390 // Re-entering RS from after a callback.
11391 DbgRSThread * pThread = DbgRSThread::GetThread();
11392
11393 pThread->m_cInsideRS = m_oldCount;
11394
11395 // Our status of being "Inside the RS" is now restored.
11396 _ASSERTE(pThread->IsInRS());
11397 }
11398private:
11399 int m_oldCount;
11400};
11401
11402class InternalAPIHolder
11403{
11404public:
11405 InternalAPIHolder()
11406 {
11407 DbgRSThread * pThread = DbgRSThread::GetThread();
11408
11409 // Internal APIs should already be inside the RS.
11410 _ASSERTE(pThread->IsInRS() ||!"Internal API being called directly from outside (there should be a public API on the stack)");
11411 }
11412 void dummy() {}
11413};
11414
11415//---------------------------------------------------------------------------------------
11416//
11417// This is a simple holder to assert that the current thread is holding the process lock. The purpose of
11418// having this holder is to enforce a lock ordering between the process lock in the RS and the DD lock in DAC.
11419// If a thread needs to take the process lock, it must do so BEFORE taking the DD lock. Otherwise we could have
11420// a deadlock between the process lock and the DD lock.
11421//
11422// Normally we take the process lock before calling out to DAC, and every DAC API takes the DD lock on entry.
11423// Moreover, normally DAC doesn't call back into the RS. The exceptions we currently have are:
11424// 1) enumeration callbacks (e.g. code:CordbProcess::AppDomainEnumerationCallback)
11425// 2) code:IDacDbiInterface::IMetaDataLookup
11426// 3) code:IDacDbiInterface::IAllocator
11427// 4) code:IStringHolder
11428//
11429// Note that the last two are fine because they don't need to take the process lock. The first two categories
11430// need to take the process lock before calling into DAC to avoid potential deadlocks.
11431//
11432
11433class InternalDacCallbackHolder
11434{
11435public:
11436 InternalDacCallbackHolder(CordbProcess * pProcess)
11437 {
11438 _ASSERTE(pProcess->ThreadHoldsProcessLock());
11439 }
11440};
11441
11442// cotract that occurs at public builds.
11443#define PUBLIC_CONTRACT \
11444 CONTRACTL { NOTHROW; } CONTRACTL_END;
11445
11446
11447// Private hook for Shim to call into DBI.
11448// Since Shim is considered outside DBI, we need to mark that we've re-entered.
11449// Big difference is that we can throw across this boundary.
11450// @dbgtodo private shim hook - Eventually, these will all go away since the shim will be fully public.
11451#define PUBLIC_API_ENTRY_FOR_SHIM(_pThis) \
11452 PublicAPIHolder __pah;
11453
11454
11455#define PUBLIC_API_UNSAFE_ENTRY_FOR_SHIM(_pThis) \
11456 PublicDebuggerErrorCallbackHolder __pahCallback;
11457
11458// @dbgtodo shim, synchronization - Because of the problem mentioned in the comments for
11459// PrivateShimCallbackHolder, we need this macro so that we don't hit an assertion when we come back into
11460// the RS from the shim.
11461#define PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(_pThis) \
11462 PublicReentrantAPIHolder __pah;
11463
11464//-----------------------------------------------------------------------------
11465// Declare whether an API is public or internal
11466// Public APIs have the following:
11467// - We may be called concurrently from multiple threads (ie, not thread safe)
11468// - This thread does not hold any RS Locks while entering or leaving this function.
11469// - May or May-not be reentrant.
11470// Internal APIs:
11471// - let us specifically mark that we're not a public API, and
11472// - we're only being called through a public API.
11473//-----------------------------------------------------------------------------
11474#define PUBLIC_API_ENTRY(_pThis) \
11475 STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API '%s', this=0x%p]\n", __FUNCTION__, _pThis); \
11476 PUBLIC_CONTRACT; \
11477 PublicAPIHolder __pah;
11478
11479// Mark public APIs that are re-entrant.
11480// Very few of our APIs should be re-entrant. Even for field access APIs (like GetXXX), the
11481// public version is heavier (eg, checking the HRESULT) so we benefit from having a fast
11482// internal version and calling that directly.
11483#define PUBLIC_REENTRANT_API_ENTRY(_pThis) \
11484 STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API (re) '%s', this=0x%p]\n", __FUNCTION__, _pThis); \
11485 PUBLIC_CONTRACT; \
11486 PublicReentrantAPIHolder __pah;
11487
11488
11489
11490// Mark internal APIs.
11491// All internal APIs are reentrant (duh)
11492#define INTERNAL_API_ENTRY(_pThis) InternalAPIHolder __pah; __pah.dummy();
11493
11494// Mark an internal API from ATT_REQUIRE_STOP / ATT_ALLOW_LIVE_DO_STOP_GO.
11495// This can assert that we're safe to send IPC events (that we're stopped and hold the SG lock)
11496// @dbgtodo synchronization - in V2, this would assert that we were synced.
11497// In V3, our definition of Sync is in flux. Need to resolve this with the synchronization feature crew.
11498#define INTERNAL_SYNC_API_ENTRY(pProc) \
11499 CordbProcess * __pProc = (pProc); \
11500 _ASSERTE(__pProc->GetStopGoLock()->HasLock() || !"Must have stop go lock for internal-sync-api"); \
11501 InternalAPIHolder __pah; __pah.dummy();
11502
11503
11504
11505// Mark that a thread is owned by us. Thus the thread's "Inside RS" count > 0.
11506#define INTERNAL_THREAD_ENTRY(_pThis) \
11507 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[Internal thread started, this=0x%p]\n", _pThis); \
11508 PUBLIC_CONTRACT; \
11509 PublicAPIHolder __pah;
11510
11511// @dbgtodo unrecoverable error - This sould be deprecated once we deprecate UnrecoverableError.
11512#define PUBLIC_CALLBACK_IN_THIS_SCOPE_DEBUGGERERROR(_pThis) \
11513 PublicDebuggerErrorCallbackHolder __pahCallback;
11514
11515#define PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(_pThis) \
11516 PrivateShimCallbackHolder __pahCallback;
11517
11518// Mark places where DAC may call back into DBI. We need to assert that we are holding the process lock in
11519// these places, since otherwise we could deadlock between the DD lock and the process lock.
11520#define INTERNAL_DAC_CALLBACK(__pProcess) \
11521 InternalDacCallbackHolder __idch(__pProcess);
11522
11523
11524// Helper to log debug events.
11525inline void StressLogNativeDebugEvent(const DEBUG_EVENT * pDebugEvent, bool fOOB)
11526{
11527 if ((pDebugEvent)->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
11528 {
11529 STRESS_LOG4(LF_CORDB, LL_EVERYTHING, "[Dispatching Win32 code=1 (EXCEPTION_DEBUG_EVENT, tid=%x, oob=%d, code=0x%x, 1st=%d]\n",
11530 pDebugEvent->dwThreadId,
11531 fOOB,
11532 pDebugEvent->u.Exception.ExceptionRecord.ExceptionCode,
11533 pDebugEvent->u.Exception.dwFirstChance);
11534 }
11535 else
11536 {
11537 STRESS_LOG3(LF_CORDB, LL_EVERYTHING, "[Dispatching Win32 code=%d, tid=%x, oob=%d.]\n",
11538 pDebugEvent->dwDebugEventCode, pDebugEvent->dwThreadId, fOOB);
11539 }
11540
11541}
11542
11543#define PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(_pThis, _pDebugEvent, _fOOB) \
11544 StressLogNativeDebugEvent(_pDebugEvent, _fOOB); \
11545 PublicCallbackHolder __pahCallback(DB_IPCE_INVALID_EVENT);
11546
11547// Visisbility spec for dtors.
11548// Currently, dtors are like public methods b/c they can be called from Release.
11549// But they're also reentrant since they may be called from an internal-release.
11550// @todo - we'd like to get all "useful" work out of the dtor; in which case we may
11551// be able to change this to something more aggressive.
11552#define DTOR_ENTRY(_pThis) PUBLIC_REENTRANT_API_ENTRY(_pThis)
11553
11554
11555//-----------------------------------------------------------------------------
11556// Typesafe bool for thread safety. This typesafety forces us to use
11557// an specific reason for thread-safety, taken from a well-known list.
11558// This is mostly concerned w/ being serialized.
11559// Note that this assertion must be done on a per function basis and we
11560// can't have any sort of 'ThreadSafetyReason CallerIsSafe()' b/c we can't
11561// enforce that all of our callers are thread safe (only that our current caller is safe).
11562//-----------------------------------------------------------------------------
11563struct ThreadSafetyReason
11564{
11565public:
11566 ThreadSafetyReason(bool f) { fIsSafe = f; }
11567
11568 bool fIsSafe;
11569};
11570
11571// Different valid reasons that we may be threads safe.
11572inline ThreadSafetyReason HoldsLock(RSLock * pLock)
11573{
11574 _ASSERTE(pLock != NULL);
11575 return ThreadSafetyReason(pLock->HasLock());
11576}
11577inline ThreadSafetyReason OnW32ET(CordbProcess * pProc)
11578{
11579 return ThreadSafetyReason(IsWin32EventThread(pProc));
11580}
11581
11582inline ThreadSafetyReason OnRCET(Cordb *pCordb)
11583{
11584 return ThreadSafetyReason (IsRCEventThread(pCordb));
11585}
11586
11587// We use this when we assume that a function is thread-safe (b/c it's serialized).
11588// The reason also lets us assert that our assumption is true.
11589// By using a function, we enforce typesafety and thus require a valid reason
11590// (as opposed to an arbitrary bool)
11591inline void AssertThreadSafeHelper(ThreadSafetyReason r) {
11592 _ASSERTE(r.fIsSafe);
11593}
11594
11595//-----------------------------------------------------------------------------
11596// Assert that the given scope is always called on a single thread b/c of
11597// xReason. Common reasons may be b/c we hold a lock or we're always
11598// called on a specific thread (Eg w32et).
11599// The only valid reasons are of type ThreadSafetyReason (thus forcing us to
11600// choose from a well-known list of valid reasons).
11601//-----------------------------------------------------------------------------
11602#define ASSERT_SINGLE_THREAD_ONLY(xReason) \
11603 AssertThreadSafeHelper(xReason);
11604
11605#else
11606
11607//-----------------------------------------------------------------------------
11608// Retail versions just nop. See the debug implementation for these
11609// for their semantics.
11610//-----------------------------------------------------------------------------
11611
11612#define PUBLIC_CONTRACT
11613#define PUBLIC_API_ENTRY_FOR_SHIM(_pThis)
11614#define PUBLIC_API_UNSAFE_ENTRY_FOR_SHIM(_pThis)
11615#define PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(_pThis)
11616#define PUBLIC_API_ENTRY(_pThis)
11617#define PUBLIC_REENTRANT_API_ENTRY(_pThis)
11618#define INTERNAL_API_ENTRY(_pThis)
11619#define INTERNAL_SYNC_API_ENTRY(pProc)
11620#define INTERNAL_THREAD_ENTRY(_pThis)
11621#define PUBLIC_CALLBACK_IN_THIS_SCOPE_DEBUGGERERROR(_pThis)
11622#define PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(_pThis)
11623#define INTERNAL_DAC_CALLBACK(__pProcess)
11624#define PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(_pThis, _pDebugEvent, _fOOB)
11625#define DTOR_ENTRY(_pThis)
11626
11627
11628#define ASSERT_SINGLE_THREAD_ONLY(x)
11629
11630#endif // #if RSCONTRACTS
11631
11632
11633class PublicCallbackHolder
11634{
11635public:
11636 PublicCallbackHolder(RSLockHolder * pHolder, DebuggerIPCEventType type)
11637 {
11638 m_pHolder = pHolder;
11639 _ASSERTE(!pHolder->IsNull()); // acquired
11640
11641 // Release the lock. We'll reacquire it at the dtor.
11642 m_pHolder->Release();
11643
11644 Init(type);
11645 }
11646
11647 PublicCallbackHolder(DebuggerIPCEventType type)
11648 {
11649 m_pHolder = NULL;
11650 Init(type);
11651 }
11652
11653 void Init(DebuggerIPCEventType type)
11654 {
11655 m_type = type;
11656
11657#if defined(RSCONTRACTS)
11658 // Exiting from RS; entering Cordbg via a callback
11659 DbgRSThread * pThread = DbgRSThread::GetThread();
11660
11661 // m_cInsideRS may be arbitrarily large if we're called from a PUBLIC_REENTRANT_API,
11662 // so just remember the current count and blast it back to 0.
11663 m_oldCount = pThread->m_cInsideRS;
11664 pThread->m_cInsideRS = 0;
11665
11666 _ASSERTE(!pThread->IsInRS());
11667
11668 // Should never be in public w/ these locks. (Even if we're re-entrant.)
11669 pThread->AssertThreadIsLockFree();
11670#endif // RSCONTRACTS
11671 }
11672
11673 ~PublicCallbackHolder()
11674 {
11675#if defined(RSCONTRACTS)
11676 // Re-entering RS from after a callback.
11677 DbgRSThread * pThread = DbgRSThread::GetThread();
11678 _ASSERTE(!pThread->IsInRS());
11679
11680 pThread->m_cInsideRS = m_oldCount;
11681
11682 // Should never be in public w/ these locks. (Even if we're re-entrant.)
11683 pThread->AssertThreadIsLockFree();
11684#endif // RSCONTRACTS
11685
11686 // Reacquire the lock
11687 if (m_pHolder != NULL)
11688 {
11689 m_pHolder->Acquire();
11690 }
11691 }
11692protected:
11693 int m_oldCount;
11694 DebuggerIPCEventType m_type;
11695 RSLockHolder * m_pHolder;
11696};
11697
11698
11699// Mark that a thread is calling out via a callback. This will adjust the "Inside RS" counter.
11700#define PUBLIC_CALLBACK_IN_THIS_SCOPE(_pThis, pLockHolder, event) \
11701 STRESS_LOG1(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s']\n", IPCENames::GetName((event)->type)); \
11702 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11703
11704#define PUBLIC_CALLBACK_IN_THIS_SCOPE1(_pThis, pLockHolder, event, formatLiteralString, arg0) \
11705 STRESS_LOG2(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0); \
11706 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11707
11708#define PUBLIC_CALLBACK_IN_THIS_SCOPE2(_pThis, pLockHolder, event, formatLiteralString, arg0, arg1) \
11709 STRESS_LOG3(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0, arg1); \
11710 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11711
11712#define PUBLIC_CALLBACK_IN_THIS_SCOPE3(_pThis, pLockHolder, event, formatLiteralString, arg0, arg1, arg2) \
11713 STRESS_LOG4(LF_CORDB, LL_EVERYTHING, "[Dispatching '%s' " formatLiteralString "]\n", IPCENames::GetName((event)->type), arg0, arg1, arg2); \
11714 PublicCallbackHolder __pahCallback(pLockHolder, (event)->type);
11715
11716
11717#define PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(_pThis) \
11718 PublicCallbackHolder __pahCallback(DB_IPCE_INVALID_EVENT);
11719
11720#define PUBLIC_CALLBACK_IN_THIS_SCOPE0(_pThis, pLockHolder) \
11721 PublicCallbackHolder __pahCallback(pLockHolder, DB_IPCE_INVALID_EVENT);
11722
11723
11724//-----------------------------------------------------------------------------
11725// Helpers
11726inline void ValidateOrThrow(const void * p)
11727{
11728 if (p == NULL)
11729 {
11730 ThrowHR(E_INVALIDARG);
11731 }
11732}
11733
11734// aligns argBase on platforms that require it else it's a no-op
11735inline void AlignAddressForType(CordbType* pArgType, CORDB_ADDRESS& argBase)
11736{
11737#ifdef DBG_TARGET_ARM
11738// TODO: review the following
11739#ifdef FEATURE_64BIT_ALIGNMENT
11740 BOOL align = FALSE;
11741 HRESULT hr = pArgType->RequiresAlign8(&align);
11742 _ASSERTE(SUCCEEDED(hr));
11743
11744 if (align)
11745 argBase = ALIGN_ADDRESS(argBase, 8);
11746#endif // FEATURE_64BIT_ALIGNMENT
11747#endif // DBG_TARGET_ARM
11748}
11749
11750//-----------------------------------------------------------------------------
11751// Macros to mark public ICorDebug functions
11752// Usage:
11753//
11754// HRESULT CordbXYZ:Function(...)
11755// {
11756// HRESULT hr = S_OK;
11757// PUBLIC_API_BEGIN(this);
11758// // body, may throw
11759// PUBLIC_API_END(hr);
11760// return hr;
11761// }
11762#define PUBLIC_API_BEGIN(__this) \
11763 CordbBase * __pThis = (__this); \
11764 PUBLIC_API_ENTRY(__pThis); \
11765 EX_TRY { \
11766 RSLockHolder __lockHolder(__pThis->GetProcess()->GetProcessLock()); \
11767 THROW_IF_NEUTERED(__pThis); \
11768
11769// You should not use this in general. We're adding it as a temporary workaround for a
11770// particular scenario until we do the synchronization feature crew
11771#define PUBLIC_API_NO_LOCK_BEGIN(__this) \
11772 CordbBase * __pThis = (__this); \
11773 PUBLIC_API_ENTRY(__pThis); \
11774 EX_TRY { \
11775 THROW_IF_NEUTERED(__pThis); \
11776
11777// Some APIs (that invoke callbacks), need to toggle the lock.
11778#define GET_PUBLIC_LOCK_HOLDER() (&__lockHolder)
11779
11780#define PUBLIC_API_END(__hr) \
11781 } EX_CATCH_HRESULT(__hr); \
11782
11783// @todo: clean up API constracts. Should we really be taking the Process lock for
11784// reentrant APIS??
11785#define PUBLIC_REENTRANT_API_BEGIN(__this) \
11786 CordbBase * __pThis = (__this); \
11787 PUBLIC_REENTRANT_API_ENTRY(__pThis); \
11788 EX_TRY { \
11789 RSLockHolder __lockHolder(__pThis->GetProcess()->GetProcessLock()); \
11790 THROW_IF_NEUTERED(__pThis); \
11791
11792#define PUBLIC_REENTRANT_API_END(__hr) \
11793 } EX_CATCH_HRESULT(__hr); \
11794
11795// If an API needs to take the stop/go lock as well as the process lock, the
11796// stop/go lock has to be taken first. This is an alternative to PUBLIC_REENTRANT_API_BEGIN
11797// that allows this, since it doesn't take the process lock. It should be closed with
11798// PUBLIC_REENTRANT_API_END
11799#define PUBLIC_REENTRANT_API_NO_LOCK_BEGIN(__this) \
11800 CordbBase * __pThis = (__this); \
11801 PUBLIC_REENTRANT_API_ENTRY(__pThis); \
11802 EX_TRY { \
11803 THROW_IF_NEUTERED(__pThis); \
11804
11805
11806//-----------------------------------------------------------------------------
11807// For debugging ease, cache some global values.
11808// Include these in retail & free because that's where we need them the most!!
11809// Optimized builds may not let us view locals & parameters. So Having these
11810// cached as global values should let us inspect almost all of
11811// the interesting parts of the RS even in a Retail build!
11812//-----------------------------------------------------------------------------
11813struct RSDebuggingInfo
11814{
11815 // There should only be 1 global Cordb object. Store it here.
11816 Cordb * m_Cordb;
11817
11818 // We have lots of processes. Keep a pointer to the most recently touched
11819 // (subjective) process, as a hint about what our "current" process is.
11820 // If we're only debugging 1 process, this will be sufficient.
11821 CordbProcess * m_MRUprocess;
11822
11823 CordbRCEventThread * m_RCET;
11824};
11825
11826#include "rspriv.inl"
11827
11828#endif // #if RSPRIV_H
11829
11830
11831