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// File: RsMain.cpp
6//
7
8// Random RS utility stuff, plus root ICorCordbug implementation
9//
10//*****************************************************************************
11#include "stdafx.h"
12#include "primitives.h"
13#include "safewrap.h"
14
15#include "check.h"
16
17#include <tlhelp32.h>
18#include "wtsapi32.h"
19
20#ifndef SM_REMOTESESSION
21#define SM_REMOTESESSION 0x1000
22#endif
23
24#include "corpriv.h"
25#include "../../dlls/mscorrc/resource.h"
26#include <limits.h>
27
28
29// The top level Cordb object is built around the Shim
30#include "shimpriv.h"
31
32//-----------------------------------------------------------------------------
33// For debugging ease, cache some global values.
34// Include these in retail & free because that's where we need them the most!!
35// Optimized builds may not let us view locals & parameters. So Having these
36// cached as global values should let us inspect almost all of
37// the interesting parts of the RS even in a Retail build!
38//-----------------------------------------------------------------------------
39
40RSDebuggingInfo g_RSDebuggingInfo_OutOfProc = {0 }; // set to NULL
41RSDebuggingInfo * g_pRSDebuggingInfo = &g_RSDebuggingInfo_OutOfProc;
42
43// The following instances are used for invoking overloaded new/delete
44forDbiWorker forDbi;
45
46#ifdef _DEBUG
47// For logs, we can print the string name for the debug codes.
48const char * GetDebugCodeName(DWORD dwCode)
49{
50 if (dwCode < 1 || dwCode > 9)
51 {
52 return "!Invalid Debug Event Code!";
53 }
54
55 static const char * const szNames[] = {
56 "(1) EXCEPTION_DEBUG_EVENT",
57 "(2) CREATE_THREAD_DEBUG_EVENT",
58 "(3) CREATE_PROCESS_DEBUG_EVENT",
59 "(4) EXIT_THREAD_DEBUG_EVENT",
60 "(5) EXIT_PROCESS_DEBUG_EVENT",
61 "(6) LOAD_DLL_DEBUG_EVENT",
62 "(7) UNLOAD_DLL_DEBUG_EVENT",
63 "(8) OUTPUT_DEBUG_STRING_EVENT",
64 "(9) RIP_EVENT",// <-- only on Win9X
65 };
66
67 return szNames[dwCode - 1];
68}
69
70#endif
71
72
73//-----------------------------------------------------------------------------
74// Per-thread state for Debug builds...
75//-----------------------------------------------------------------------------
76#ifdef RSCONTRACTS
77DWORD DbgRSThread::s_TlsSlot = TLS_OUT_OF_INDEXES;
78LONG DbgRSThread::s_Total = 0;
79
80DbgRSThread::DbgRSThread()
81{
82 m_cInsideRS = 0;
83 m_fIsInCallback = false;
84 m_fIsUnrecoverableErrorCallback = false;
85
86 m_cTotalDbgApiLocks = 0;
87 for(int i = 0; i < RSLock::LL_MAX; i++)
88 {
89 m_cLocks[i] = 0;
90 }
91
92 // Initialize Identity info
93 m_Cookie = COOKIE_VALUE;
94 m_tid = GetCurrentThreadId();
95}
96
97// NotifyTakeLock & NotifyReleaseLock are called by RSLock to update the per-thread locking context.
98// This will assert if the operation is unsafe (ie, violates lock order).
99void DbgRSThread::NotifyTakeLock(RSLock * pLock)
100{
101 if (pLock->HasLock())
102 {
103 return;
104 }
105
106 int iLevel = pLock->GetLevel();
107
108 // Is it safe to take this lock?
109 // Must take "bigger" locks first. We shouldn't hold any locks at our current level either.
110 // If this lock is re-entrant and we're double-taking it, we would have returned already.
111 // And the locking model on the RS forbids taking multiple locks at the same level.
112 for(int i = iLevel; i >= 0; i --)
113 {
114 bool fHasLowerLock = m_cLocks[i] > 0;
115 CONSISTENCY_CHECK_MSGF(!fHasLowerLock, (
116 "RSLock violation. Trying to take lock '%s (%d)', but already have smaller lock at level %d'\n",
117 pLock->Name(), iLevel,
118 i));
119 }
120
121 // Update the counts
122 _ASSERTE(m_cLocks[iLevel] == 0);
123 m_cLocks[iLevel]++;
124
125 if (pLock->IsDbgApiLock())
126 m_cTotalDbgApiLocks++;
127}
128
129void DbgRSThread::NotifyReleaseLock(RSLock * pLock)
130{
131 if (pLock->HasLock())
132 {
133 return;
134 }
135
136 int iLevel = pLock->GetLevel();
137 m_cLocks[iLevel]--;
138 _ASSERTE(m_cLocks[iLevel] == 0);
139
140 if (pLock->IsDbgApiLock())
141 m_cTotalDbgApiLocks--;
142
143 _ASSERTE(m_cTotalDbgApiLocks >= 0);
144}
145
146void DbgRSThread::TakeVirtualLock(RSLock::ERSLockLevel level)
147{
148 m_cLocks[level]++;
149}
150
151void DbgRSThread::ReleaseVirtualLock(RSLock::ERSLockLevel level)
152{
153 m_cLocks[level]--;
154 _ASSERTE(m_cLocks[level] >= 0);
155}
156
157
158// Get a DbgRSThread for the current OS thread id; lazily create if needed.
159DbgRSThread * DbgRSThread::GetThread()
160{
161 _ASSERTE(DbgRSThread::s_TlsSlot != TLS_OUT_OF_INDEXES);
162
163 void * p2 = TlsGetValue(DbgRSThread::s_TlsSlot);
164 if (p2 == NULL)
165 {
166 // We lazily create for threads that haven't gone through DllMain
167 // Since this is per-thread, we don't need to lock.
168 p2 = DbgRSThread::Create();
169 }
170 DbgRSThread * p = reinterpret_cast<DbgRSThread*> (p2);
171
172 _ASSERTE(p->m_Cookie == COOKIE_VALUE);
173
174 return p;
175}
176
177
178
179#endif // RSCONTRACTS
180
181
182
183
184
185
186#ifdef _DEBUG
187LONG CordbCommonBase::s_TotalObjectCount = 0;
188LONG CordbCommonBase::s_CordbObjectUID = 0;
189
190
191LONG CordbCommonBase::m_saDwInstance[enumMaxDerived];
192LONG CordbCommonBase::m_saDwAlive[enumMaxDerived];
193PVOID CordbCommonBase::m_sdThis[enumMaxDerived][enumMaxThis];
194
195#endif
196
197#ifdef _DEBUG_IMPL
198// Mem tracking
199LONG Cordb::s_DbgMemTotalOutstandingCordb = 0;
200LONG Cordb::s_DbgMemTotalOutstandingInternalRefs = 0;
201#endif
202
203#ifdef TRACK_OUTSTANDING_OBJECTS
204void *Cordb::s_DbgMemOutstandingObjects[MAX_TRACKED_OUTSTANDING_OBJECTS] = { NULL };
205LONG Cordb::s_DbgMemOutstandingObjectMax = 0;
206#endif
207
208// Default implementation for neutering left-side resources.
209void CordbBase::NeuterLeftSideResources()
210{
211 LIMITED_METHOD_CONTRACT;
212
213 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
214 Neuter();
215}
216
217// Default implementation for neutering.
218// All derived objects should eventually chain to this.
219void CordbBase::Neuter()
220{
221 // Neutering occurs under the process lock. Neuter can be called twice
222 // and so locking protects against races in double-delete.
223 // @dbgtodo - , some CordbBase objects (Cordb, CordbProcessEnum),
224 // don't have process affinity these should eventually be hoisted to the shim,
225 // and then we can enforce.
226 CordbProcess * pProcess = GetProcess();
227 if (pProcess != NULL)
228 {
229 _ASSERTE(pProcess->ThreadHoldsProcessLock());
230 }
231 CordbCommonBase::Neuter();
232}
233
234//-----------------------------------------------------------------------------
235// NeuterLists
236//-----------------------------------------------------------------------------
237
238NeuterList::NeuterList()
239{
240 m_pHead = NULL;
241}
242
243NeuterList::~NeuterList()
244{
245 // Our owner should have neutered us before deleting us.
246 // Thus we should be empty.
247 CONSISTENCY_CHECK_MSGF(m_pHead == NULL, ("NeuterList not empty on shutdown. this=0x%p", this));
248}
249
250// Wrapper around code:NeuterList::UnsafeAdd
251void NeuterList::Add(CordbProcess * pProcess, CordbBase * pObject)
252{
253 CONTRACTL
254 {
255 THROWS;
256 }
257 CONTRACTL_END;
258
259 UnsafeAdd(pProcess, pObject);
260}
261
262//
263// Add an object to be neutered.
264//
265// Arguments:
266// pProcess - process that holds lock that will protect the neuter list
267// pObject - object to add
268//
269// Returns:
270// Throws on error.
271//
272// Notes:
273// This will add it to the list and maintain an internal reference to it.
274// This will take the process lock.
275//
276void NeuterList::UnsafeAdd(CordbProcess * pProcess, CordbBase * pObject)
277{
278 _ASSERTE(pObject != NULL);
279
280 // Lock if needed.
281 RSLock * pLock = (pProcess != NULL) ? pProcess->GetProcessLock() : NULL;
282 RSLockHolder lockHolder(pLock, FALSE);
283 if (pLock != NULL) lockHolder.Acquire();
284
285
286 Node * pNode = new Node(); // throws on error.
287 pNode->m_pObject.Assign(pObject);
288 pNode->m_pNext = m_pHead;
289
290 m_pHead = pNode;
291}
292
293// Neuter everything on the list and clear it
294//
295// Arguments:
296// pProcess - process tree that this neuterlist belongs in
297// ticket - neuter ticket proving caller ensured we're safe to neuter.
298//
299// Assumptions:
300// Caller ensures we're safe to neuter (required to obtain NeuterTicket)
301//
302// Notes:
303// This will release all internal references and empty the list.
304void NeuterList::NeuterAndClear(CordbProcess * pProcess)
305{
306 RSLock * pLock = (pProcess != NULL) ? pProcess->GetProcessLock() : NULL;
307 (void)pLock; //prevent "unused variable" error from GCC
308 _ASSERTE((pLock == NULL) || pLock->HasLock());
309
310 while (m_pHead != NULL)
311 {
312 Node * pTemp = m_pHead;
313 m_pHead = m_pHead->m_pNext;
314
315 pTemp->m_pObject->Neuter();
316 delete pTemp; // will implicitly release
317 }
318}
319
320// Only neuter objects that are marked.
321// Removes neutered objects from the list.
322void NeuterList::SweepAllNeuterAtWillObjects(CordbProcess * pProcess)
323{
324 _ASSERTE(pProcess != NULL);
325 RSLock * pLock = pProcess->GetProcessLock();
326 RSLockHolder lockHolder(pLock);
327
328 Node ** ppLast = &m_pHead;
329 Node * pCur = m_pHead;
330
331 while (pCur != NULL)
332 {
333 CordbBase * pObject = pCur->m_pObject;
334 if (pObject->IsNeuterAtWill() || pObject->IsNeutered())
335 {
336 // Delete
337 pObject->Neuter();
338
339 Node * pNext = pCur->m_pNext;
340 delete pCur; // dtor will implicitly release the internal ref to pObject
341 pCur = *ppLast = pNext;
342 }
343 else
344 {
345 // Move to next.
346 ppLast = &pCur->m_pNext;
347 pCur = pCur->m_pNext;
348 }
349 }
350}
351
352//-----------------------------------------------------------------------------
353// Neuters all objects in the list and empties the list.
354//
355// Notes:
356// See also code:LeftSideResourceCleanupList::SweepNeuterLeftSideResources,
357// which only neuters objects that have been marked as NeuterAtWill (external
358// ref count has gone to 0).
359void LeftSideResourceCleanupList::NeuterLeftSideResourcesAndClear(CordbProcess * pProcess)
360{
361 // Traversal protected under Process-lock.
362 // SG-lock must already be held to do neutering.
363 // Stop-Go lock is bigger than Process-lock.
364 // Neutering requires the Stop-Go lock (until we get rid of IPC events)
365 // But we want to be able to add to the Neuter list under the Process-lock.
366 // So we just need to protected m_pHead under process-lock.
367
368 // "Privatize" the list under the lock.
369 _ASSERTE(pProcess != NULL);
370 RSLock * pLock = pProcess->GetProcessLock();
371
372 Node * pCur = NULL;
373 {
374 RSLockHolder lockHolder(pLock); // only acquire lock if we have one
375 pCur = m_pHead;
376 m_pHead = NULL;
377 }
378
379 // @dbgtodo - eventually everything can be under the process lock.
380 _ASSERTE(!pLock->HasLock()); // Can't hold Process lock while calling NeuterLeftSideResources
381
382 // Now we're operating on local data, so traversing doesn't need to be under the lock.
383 while (pCur != NULL)
384 {
385 Node * pTemp = pCur;
386 pCur = pCur->m_pNext;
387
388 pTemp->m_pObject->NeuterLeftSideResources();
389 delete pTemp; // will implicitly release
390 }
391
392}
393
394//-----------------------------------------------------------------------------
395// Only neuter objects that are marked. Removes neutered objects from the list.
396//
397// Arguments:
398// pProcess - non-null process owning the objects in the list
399//
400// Notes:
401// this cleans up left-side resources held by objects in the list.
402// It may send IPC events to do this.
403void LeftSideResourceCleanupList::SweepNeuterLeftSideResources(CordbProcess * pProcess)
404{
405 _ASSERTE(pProcess != NULL);
406
407 // Must be safe to send IPC events.
408 _ASSERTE(pProcess->GetStopGoLock()->HasLock()); // holds this for neutering
409 _ASSERTE(pProcess->GetSynchronized());
410
411 RSLock * pLock = pProcess->GetProcessLock();
412
413 // Lock while we "privatize" the head.
414 RSLockHolder lockHolder(pLock);
415 Node * pHead = m_pHead;
416 m_pHead = NULL;
417 lockHolder.Release();
418
419 Node ** ppLast = &pHead;
420 Node * pCur = pHead;
421
422 // Can't hold the process-lock while calling Neuter.
423 while (pCur != NULL)
424 {
425 CordbBase * pObject = pCur->m_pObject;
426 if (pObject->IsNeuterAtWill() || pObject->IsNeutered())
427 {
428 // HeavyNueter can not be done under the process-lock because
429 // it may take the Stop-Go lock and send events.
430 pObject->NeuterLeftSideResources();
431
432 // Delete
433 Node * pNext = pCur->m_pNext;
434 delete pCur; // dtor will implicitly release the internal ref to pObject
435 pCur = *ppLast = pNext;
436 }
437 else
438 {
439 // Move to next.
440 ppLast = &pCur->m_pNext;
441 pCur = pCur->m_pNext;
442 }
443 }
444
445 // Now link back in. m_pHead may have changed while we were unlocked.
446 // The list does not need to be ordered.
447
448 lockHolder.Acquire();
449 *ppLast = m_pHead;
450 m_pHead = pHead;
451}
452
453
454
455/* ------------------------------------------------------------------------- *
456 * CordbBase class
457 * ------------------------------------------------------------------------- */
458
459// Do any initialization necessary for both CorPublish and CorDebug
460// This includes enabling logging and adding the SEDebug priv.
461void CordbCommonBase::InitializeCommon()
462{
463 static bool IsInitialized = false;
464 if( IsInitialized )
465 {
466 return;
467 }
468
469#ifdef STRESS_LOG
470 {
471 bool fStressLog = false;
472
473#ifdef _DEBUG
474 // default for stress log is on debug build
475 fStressLog = true;
476#endif // DEBUG
477
478 // StressLog will turn on stress logging for the entire runtime.
479 // RSStressLog is only used here and only effects just the RS.
480 fStressLog =
481 (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0) ||
482 (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_RSStressLog) != 0);
483
484 if (fStressLog == true)
485 {
486 unsigned facilities = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LF_ALL);
487 unsigned level = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
488 unsigned bytesPerThread = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 2);
489 unsigned totalBytes = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
490#ifndef FEATURE_PAL
491 StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, GetModuleInst());
492#else
493 StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, NULL);
494#endif
495 }
496 }
497
498#endif // STRESS_LOG
499
500#ifdef LOGGING
501 InitializeLogging();
502#endif
503
504 // Add debug privilege. This will let us call OpenProcess() on anything, regardless of ACL.
505 AddDebugPrivilege();
506
507 IsInitialized = true;
508}
509
510// Adjust the permissions of this process to ensure that we have
511// the debugging priviledge. If we can't make the adjustment, it
512// only means that we won't be able to attach to a service under
513// NT, so we won't treat that as a critical failure.
514// This also will let us call OpenProcess() on anything, regardless of DACL. This allows an
515// Admin debugger to attach to a debuggee in the guest account.
516// Ideally, the debugger would set this (and we wouldn't mess with privileges at all). However, we've been
517// setting this since V1.0 and removing it may be a breaking change.
518void CordbCommonBase::AddDebugPrivilege()
519{
520#ifndef FEATURE_PAL
521 HANDLE hToken;
522 TOKEN_PRIVILEGES Privileges;
523 BOOL fSucc;
524
525 LUID SeDebugLuid = {0, 0};
526
527 fSucc = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &SeDebugLuid);
528 DWORD err = GetLastError();
529
530 if (!fSucc)
531 {
532 STRESS_LOG1(LF_CORDB, LL_INFO1000, "Unable to adjust permissions of this process to include SE_DEBUG. Lookup failed %d\n", err);
533 return;
534 }
535
536
537 // Retrieve a handle of the access token
538 fSucc = OpenProcessToken(GetCurrentProcess(),
539 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
540 &hToken);
541
542 if (fSucc)
543 {
544 Privileges.PrivilegeCount = 1;
545 Privileges.Privileges[0].Luid = SeDebugLuid;
546 Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
547
548 AdjustTokenPrivileges(hToken,
549 FALSE,
550 &Privileges,
551 sizeof(TOKEN_PRIVILEGES),
552 (PTOKEN_PRIVILEGES) NULL,
553 (PDWORD) NULL);
554 err = GetLastError();
555 // The return value of AdjustTokenPrivileges cannot be tested.
556 if (err != ERROR_SUCCESS)
557 {
558 STRESS_LOG1(LF_CORDB, LL_INFO1000,
559 "Unable to adjust permissions of this process to include SE_DEBUG. Adjust failed %d\n", err);
560 }
561 else
562 {
563 LOG((LF_CORDB, LL_INFO1000, "Adjusted process permissions to include SE_DEBUG.\n"));
564 }
565 CloseHandle(hToken);
566 }
567#endif
568}
569
570
571namespace
572{
573
574 //
575 // DefaultManagedCallback2
576 //
577 // In the event that the debugger is of an older version than the Right Side & Left Side, the Right Side may issue
578 // new callbacks that the debugger is not expecting. In this case, we need to provide a default behavior for those
579 // new callbacks, if for nothing else than to force the debugger to Continue().
580 //
581 class DefaultManagedCallback2 : public ICorDebugManagedCallback2
582 {
583 public:
584 DefaultManagedCallback2(ICorDebug* pDebug);
585 virtual ~DefaultManagedCallback2() { }
586 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** pInterface);
587 virtual ULONG STDMETHODCALLTYPE AddRef();
588 virtual ULONG STDMETHODCALLTYPE Release();
589 COM_METHOD FunctionRemapOpportunity(ICorDebugAppDomain* pAppDomain,
590 ICorDebugThread* pThread,
591 ICorDebugFunction* pOldFunction,
592 ICorDebugFunction* pNewFunction,
593 ULONG32 oldILOffset);
594 COM_METHOD FunctionRemapComplete(ICorDebugAppDomain *pAppDomain,
595 ICorDebugThread *pThread,
596 ICorDebugFunction *pFunction);
597
598 COM_METHOD CreateConnection(ICorDebugProcess *pProcess,
599 CONNID dwConnectionId,
600 __in_z WCHAR* pConnectionName);
601 COM_METHOD ChangeConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId);
602 COM_METHOD DestroyConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId);
603
604 COM_METHOD Exception(ICorDebugAppDomain *pAddDomain,
605 ICorDebugThread *pThread,
606 ICorDebugFrame *pFrame,
607 ULONG32 nOffset,
608 CorDebugExceptionCallbackType eventType,
609 DWORD dwFlags );
610
611 COM_METHOD ExceptionUnwind(ICorDebugAppDomain *pAddDomain,
612 ICorDebugThread *pThread,
613 CorDebugExceptionUnwindCallbackType eventType,
614 DWORD dwFlags );
615 COM_METHOD MDANotification(
616 ICorDebugController * pController,
617 ICorDebugThread *pThread,
618 ICorDebugMDA * pMDA
619 ) { return E_NOTIMPL; }
620
621 private:
622 // not implemented
623 DefaultManagedCallback2(const DefaultManagedCallback2&);
624 DefaultManagedCallback2& operator=(const DefaultManagedCallback2&);
625
626 ICorDebug* m_pDebug;
627 LONG m_refCount;
628 };
629
630
631
632
633 DefaultManagedCallback2::DefaultManagedCallback2(ICorDebug* pDebug) : m_pDebug(pDebug), m_refCount(0)
634 {
635 }
636
637 HRESULT
638 DefaultManagedCallback2::QueryInterface(REFIID iid, void** pInterface)
639 {
640 if (IID_ICorDebugManagedCallback2 == iid)
641 {
642 *pInterface = static_cast<ICorDebugManagedCallback2*>(this);
643 }
644 else if (IID_IUnknown == iid)
645 {
646 *pInterface = static_cast<IUnknown*>(this);
647 }
648 else
649 {
650 *pInterface = NULL;
651 return E_NOINTERFACE;
652 }
653
654 this->AddRef();
655 return S_OK;
656 }
657
658 ULONG
659 DefaultManagedCallback2::AddRef()
660 {
661 return InterlockedIncrement(&m_refCount);
662 }
663
664 ULONG
665 DefaultManagedCallback2::Release()
666 {
667 ULONG ulRef = InterlockedDecrement(&m_refCount);
668 if (0 == ulRef)
669 {
670 delete this;
671 }
672
673 return ulRef;
674 }
675
676 HRESULT
677 DefaultManagedCallback2::FunctionRemapOpportunity(ICorDebugAppDomain* pAppDomain,
678 ICorDebugThread* pThread,
679 ICorDebugFunction* pOldFunction,
680 ICorDebugFunction* pNewFunction,
681 ULONG32 oldILOffset)
682 {
683
684 //
685 // In theory, this function should never be reached. To get here, we'd have to have a debugger which doesn't
686 // support edit and continue somehow turn on edit & continue features.
687 //
688 _ASSERTE(!"Edit & Continue callback reached when debugger doesn't support Edit And Continue");
689
690
691 // If you ignore this assertion, or you're in a retail build, there are two options as far as how to proceed
692 // from this point
693 // o We can do nothing, and let the debugee process hang, or
694 // o We can silently ignore the FunctionRemapOpportunity, and tell the debugee to Continue running.
695 //
696 // For now, we'll silently ignore the function remapping.
697 pAppDomain->Continue(false);
698 pAppDomain->Release();
699
700 return S_OK;
701 }
702
703
704 HRESULT
705 DefaultManagedCallback2::FunctionRemapComplete(ICorDebugAppDomain *pAppDomain,
706 ICorDebugThread *pThread,
707 ICorDebugFunction *pFunction)
708 {
709 //
710 // In theory, this function should never be reached. To get here, we'd have to have a debugger which doesn't
711 // support edit and continue somehow turn on edit & continue features.
712 //
713 _ASSERTE(!"Edit & Continue callback reached when debugger doesn't support Edit And Continue");
714 return E_NOTIMPL;
715 }
716
717 //
718 // <TODO>
719 // These methods are current left unimplemented.
720 //
721 // Create/Change/Destroy Connection *should* force the Process/AppDomain/Thread to Continue(). Currently the
722 // arguments to these functions don't provide the relevant Process/AppDomain/Thread, so there is no way to figure
723 // out which Threads should be forced to Continue().
724 //
725 // </TODO>
726 //
727 HRESULT
728 DefaultManagedCallback2::CreateConnection(ICorDebugProcess *pProcess,
729 CONNID dwConnectionId,
730 __in_z WCHAR* pConnectionName)
731 {
732 _ASSERTE(!"DefaultManagedCallback2::CreateConnection not implemented");
733 return E_NOTIMPL;
734 }
735
736 HRESULT
737 DefaultManagedCallback2::ChangeConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId)
738 {
739 _ASSERTE(!"DefaultManagedCallback2::ChangeConnection not implemented");
740 return E_NOTIMPL;
741 }
742
743 HRESULT
744 DefaultManagedCallback2::DestroyConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId)
745 {
746 _ASSERTE(!"DefaultManagedCallback2::DestroyConnection not implemented");
747 return E_NOTIMPL;
748 }
749
750 HRESULT
751 DefaultManagedCallback2::Exception(ICorDebugAppDomain *pAppDomain,
752 ICorDebugThread *pThread,
753 ICorDebugFrame *pFrame,
754 ULONG32 nOffset,
755 CorDebugExceptionCallbackType eventType,
756 DWORD dwFlags )
757 {
758 //
759 // Just ignore and continue the process.
760 //
761 pAppDomain->Continue(false);
762 return S_OK;
763 }
764
765 HRESULT
766 DefaultManagedCallback2::ExceptionUnwind(ICorDebugAppDomain *pAppDomain,
767 ICorDebugThread *pThread,
768 CorDebugExceptionUnwindCallbackType eventType,
769 DWORD dwFlags )
770 {
771 //
772 // Just ignore and continue the process.
773 //
774 pAppDomain->Continue(false);
775 return S_OK;
776 }
777
778 //
779 // DefaultManagedCallback3
780 //
781 // In the event that the debugger is of an older version than the Right Side & Left Side, the Right Side may issue
782 // new callbacks that the debugger is not expecting. In this case, we need to provide a default behavior for those
783 // new callbacks, if for nothing else than to force the debugger to Continue().
784 //
785 class DefaultManagedCallback3 : public ICorDebugManagedCallback3
786 {
787 public:
788 DefaultManagedCallback3(ICorDebug* pDebug);
789 virtual ~DefaultManagedCallback3() { }
790 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** pInterface);
791 virtual ULONG STDMETHODCALLTYPE AddRef();
792 virtual ULONG STDMETHODCALLTYPE Release();
793 COM_METHOD CustomNotification(ICorDebugThread * pThread, ICorDebugAppDomain * pAppDomain);
794 private:
795 // not implemented
796 DefaultManagedCallback3(const DefaultManagedCallback3&);
797 DefaultManagedCallback3& operator=(const DefaultManagedCallback3&);
798
799 ICorDebug* m_pDebug;
800 LONG m_refCount;
801 };
802
803 DefaultManagedCallback3::DefaultManagedCallback3(ICorDebug* pDebug) : m_pDebug(pDebug), m_refCount(0)
804 {
805 }
806
807 HRESULT
808 DefaultManagedCallback3::QueryInterface(REFIID iid, void** pInterface)
809 {
810 if (IID_ICorDebugManagedCallback3 == iid)
811 {
812 *pInterface = static_cast<ICorDebugManagedCallback3*>(this);
813 }
814 else if (IID_IUnknown == iid)
815 {
816 *pInterface = static_cast<IUnknown*>(this);
817 }
818 else
819 {
820 *pInterface = NULL;
821 return E_NOINTERFACE;
822 }
823
824 this->AddRef();
825 return S_OK;
826 }
827
828 ULONG
829 DefaultManagedCallback3::AddRef()
830 {
831 return InterlockedIncrement(&m_refCount);
832 }
833
834 ULONG
835 DefaultManagedCallback3::Release()
836 {
837 ULONG ulRef = InterlockedDecrement(&m_refCount);
838 if (0 == ulRef)
839 {
840 delete this;
841 }
842
843 return ulRef;
844 }
845
846 HRESULT
847 DefaultManagedCallback3::CustomNotification(ICorDebugThread * pThread, ICorDebugAppDomain * pAppDomain)
848 {
849 //
850 // Just ignore and continue the process.
851 //
852 pAppDomain->Continue(false);
853 return S_OK;
854 }
855
856 //
857 // DefaultManagedCallback4
858 //
859 // In the event that the debugger is of an older version than the Right Side & Left Side, the Right Side may issue
860 // new callbacks that the debugger is not expecting. In this case, we need to provide a default behavior for those
861 // new callbacks, if for nothing else than to force the debugger to Continue().
862 //
863 class DefaultManagedCallback4 : public ICorDebugManagedCallback4
864 {
865 public:
866 DefaultManagedCallback4(ICorDebug* pDebug);
867 virtual ~DefaultManagedCallback4() { }
868 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** pInterface);
869 virtual ULONG STDMETHODCALLTYPE AddRef();
870 virtual ULONG STDMETHODCALLTYPE Release();
871 COM_METHOD BeforeGarbageCollection(ICorDebugProcess* pProcess);
872 COM_METHOD AfterGarbageCollection(ICorDebugProcess* pProcess);
873 COM_METHOD DataBreakpoint(ICorDebugProcess* pProcess, ICorDebugThread* pThread, BYTE* pContext, ULONG32 contextSize);
874 private:
875 // not implemented
876 DefaultManagedCallback4(const DefaultManagedCallback4&);
877 DefaultManagedCallback4& operator=(const DefaultManagedCallback4&);
878
879 ICorDebug* m_pDebug;
880 LONG m_refCount;
881 };
882
883 DefaultManagedCallback4::DefaultManagedCallback4(ICorDebug* pDebug) : m_pDebug(pDebug), m_refCount(0)
884 {
885 }
886
887 HRESULT
888 DefaultManagedCallback4::QueryInterface(REFIID iid, void** pInterface)
889 {
890 if (IID_ICorDebugManagedCallback4 == iid)
891 {
892 *pInterface = static_cast<ICorDebugManagedCallback4*>(this);
893 }
894 else if (IID_IUnknown == iid)
895 {
896 *pInterface = static_cast<IUnknown*>(this);
897 }
898 else
899 {
900 *pInterface = NULL;
901 return E_NOINTERFACE;
902 }
903
904 this->AddRef();
905 return S_OK;
906 }
907
908 ULONG
909 DefaultManagedCallback4::AddRef()
910 {
911 return InterlockedIncrement(&m_refCount);
912 }
913
914 ULONG
915 DefaultManagedCallback4::Release()
916 {
917 ULONG ulRef = InterlockedDecrement(&m_refCount);
918 if (0 == ulRef)
919 {
920 delete this;
921 }
922
923 return ulRef;
924 }
925
926 HRESULT
927 DefaultManagedCallback4::BeforeGarbageCollection(ICorDebugProcess* pProcess)
928 {
929 //
930 // Just ignore and continue the process.
931 //
932 pProcess->Continue(false);
933 return S_OK;
934 }
935
936 HRESULT
937 DefaultManagedCallback4::AfterGarbageCollection(ICorDebugProcess* pProcess)
938 {
939 //
940 // Just ignore and continue the process.
941 //
942 pProcess->Continue(false);
943 return S_OK;
944 }
945
946 HRESULT
947 DefaultManagedCallback4::DataBreakpoint(ICorDebugProcess* pProcess, ICorDebugThread* pThread, BYTE* pContext, ULONG32 contextSize)
948 {
949 //
950 // Just ignore and continue the process.
951 //
952 pProcess->Continue(false);
953 return S_OK;
954 }
955}
956
957/* ------------------------------------------------------------------------- *
958 * Cordb class
959 * ------------------------------------------------------------------------- */
960Cordb::Cordb(CorDebugInterfaceVersion iDebuggerVersion)
961 : Cordb(iDebuggerVersion, ProcessDescriptor::CreateUninitialized())
962{
963}
964
965Cordb::Cordb(CorDebugInterfaceVersion iDebuggerVersion, const ProcessDescriptor& pd)
966 : CordbBase(NULL, 0, enumCordb),
967 m_processes(11),
968 m_initialized(false),
969 m_debuggerSpecifiedVersion(iDebuggerVersion),
970 m_pd(pd)
971#ifdef FEATURE_CORESYSTEM
972 ,
973 m_targetCLR(0)
974#endif
975{
976 g_pRSDebuggingInfo->m_Cordb = this;
977
978#ifdef _DEBUG_IMPL
979 // Memory leak detection
980 InterlockedIncrement(&s_DbgMemTotalOutstandingCordb);
981#endif
982}
983
984Cordb::~Cordb()
985{
986 LOG((LF_CORDB, LL_INFO10, "C::~C Terminating Cordb object.\n"));
987 if (m_pd.m_ApplicationGroupId != NULL)
988 {
989 delete [] m_pd.m_ApplicationGroupId;
990 }
991 g_pRSDebuggingInfo->m_Cordb = NULL;
992}
993
994void Cordb::Neuter()
995{
996 if (this->IsNeutered())
997 {
998 return;
999 }
1000
1001
1002 RSLockHolder lockHolder(&m_processListMutex);
1003 m_pProcessEnumList.NeuterAndClear(NULL);
1004
1005
1006 HRESULT hr = S_OK;
1007 EX_TRY // @dbgtodo push this up.
1008 {
1009 // Iterating needs to be done under the processList lock (small), while neutering
1010 // needs to be able to take the process lock (big).
1011 RSPtrArray<CordbProcess> list;
1012 m_processes.TransferToArray(&list); // throws
1013
1014 // can't hold list lock while calling CordbProcess::Neuter (which
1015 // will take the Process-lock).
1016 lockHolder.Release();
1017
1018 list.NeuterAndClear();
1019 // List dtor calls release on each element
1020 }
1021 EX_CATCH_HRESULT(hr);
1022 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
1023
1024 CordbCommonBase::Neuter();
1025
1026 // Implicit release from smart ptr.
1027}
1028
1029#ifdef _DEBUG_IMPL
1030void CheckMemLeaks()
1031{
1032 // Memory leak detection.
1033 LONG l = InterlockedDecrement(&Cordb::s_DbgMemTotalOutstandingCordb);
1034 if (l == 0)
1035 {
1036 // If we just released our final Cordb root object, then we expect no internal references at all.
1037 // Note that there may still be external references (and thus not all objects may have been
1038 // deleted yet).
1039 bool fLeakedInternal = (Cordb::s_DbgMemTotalOutstandingInternalRefs > 0);
1040
1041 // Some Cordb objects (such as CordbValues) may not be rooted, and thus we can't neuter
1042 // them and thus an external ref may keep them alive. Since these objects may have internal refs,
1043 // This means that external refs can keep internal refs.
1044 // Thus this assert must be tempered if unrooted objects are leaked. (But that means we can always
1045 // assert the tempered version; regardless of bugs in Cordbg).
1046 CONSISTENCY_CHECK_MSGF(!fLeakedInternal,
1047 ("'%d' Outstanding internal references at final Cordb::Terminate\n",
1048 Cordb::s_DbgMemTotalOutstandingInternalRefs));
1049
1050 DWORD dLeakCheck = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgLeakCheck);
1051 if (dLeakCheck > 0)
1052 {
1053 // We have 1 ref for this Cordb root object. All other refs should have been deleted.
1054 CONSISTENCY_CHECK_MSGF(Cordb::s_TotalObjectCount == 1, ("'%d' total cordbBase objects are leaked.\n",
1055 Cordb::s_TotalObjectCount-1));
1056 }
1057 }
1058}
1059#endif
1060
1061// This shuts down ICorDebug.
1062// All CordbProcess objects owned by this Cordb object must have either:
1063// - returned for a Detach() call
1064// - returned from dispatching the ExitProcess() callback.
1065// In both cases, CordbProcess::NeuterChildren has been called, although the Process object itself
1066// may not yet be neutered. This condition will ensure that the CordbProcess objects don't need
1067// any resources that we're about to release.
1068HRESULT Cordb::Terminate()
1069{
1070 LOG((LF_CORDB, LL_INFO10000, "[%x] Terminating Cordb\n", GetCurrentThreadId()));
1071
1072 if (!m_initialized)
1073 return E_FAIL;
1074
1075 FAIL_IF_NEUTERED(this);
1076
1077 // We can't terminate the debugging services from within a callback.
1078 // Caller is supposed to be out of all callbacks when they call this.
1079 // This also avoids a deadlock because we'll shutdown the RCET, which would block if we're
1080 // in the RCET.
1081 if (m_rcEventThread->IsRCEventThread())
1082 {
1083 STRESS_LOG0(LF_CORDB, LL_INFO10, "C::T: failed on RCET\n");
1084 _ASSERTE(!"Gross API Misuse: Debugger shouldn't call ICorDebug::Terminate from within a managed callback.");
1085 return CORDBG_E_CANT_CALL_ON_THIS_THREAD;
1086 }
1087
1088 // @todo - do we need to throw some switch to prevent new processes from being added now?
1089
1090 // VS must stop all debugging before terminating. Fail if we have any non-neutered processes
1091 // (b/c those processes should have been either shutdown or detached).
1092 // We are in an undefined state if this check fails.
1093 // Process are removed from this list before Process::Detach() returns and before the ExitProcess callback is dispatched.
1094 // Thus any processes in this list should be live or have an unrecoverable error.
1095 {
1096 RSLockHolder ch(&m_processListMutex);
1097
1098 HASHFIND hfDT;
1099 CordbProcess * pProcess;
1100
1101 for (pProcess= (CordbProcess*) m_processes.FindFirst(&hfDT);
1102 pProcess != NULL;
1103 pProcess = (CordbProcess*) m_processes.FindNext(&hfDT))
1104 {
1105 _ASSERTE(pProcess->IsSafeToSendEvents() || pProcess->m_unrecoverableError);
1106 if (pProcess->IsSafeToSendEvents() && !pProcess->m_unrecoverableError)
1107 {
1108 CONSISTENCY_CHECK_MSGF(false, ("Gross API misuses. Callling terminate with live process:0x%p\n", pProcess));
1109 STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::Terminate b/c of non-neutered process '%p'\n", pProcess);
1110 // This is very bad.
1111 // GROSS API MISUSES - Debugger is calling ICorDebug::Terminate while there
1112 // are still outstanding (non-neutered) ICorDebugProcess.
1113 // ICorDebug is now in an undefined state.
1114 // We will also leak memory b/c we're leaving the EventThreads up (which will in turn
1115 // keep a reference to this Cordb object).
1116 return ErrWrapper(CORDBG_E_ILLEGAL_SHUTDOWN_ORDER);
1117 }
1118 }
1119 }
1120
1121 // @todo- ideally, we'd wait for all threads to get outside of ICorDebug before we proceed.
1122 // That's tough to implement in practice; but we at least wait for both ET to exit. As these
1123 // guys dispatch callbacks, that means at least we'll wait until VS is outside of any callback.
1124 //
1125 // Stop the event handling threads.
1126 //
1127 if (m_rcEventThread != NULL)
1128 {
1129 // Stop may do significant work b/c if it drains the worker queue.
1130 m_rcEventThread->Stop();
1131 delete m_rcEventThread;
1132 m_rcEventThread = NULL;
1133 }
1134
1135
1136#ifdef _DEBUG
1137 // @todo - this disables thread-safety asserts on the process-list-hash. We clearly
1138 // can't hold the lock while neutering it. (lock violation since who knows what neuter may do)
1139 // @todo- we may have races beteen Cordb::Terminate and Cordb::CreateProcess as both
1140 // modify the process list. This is mitigated since Terminate is supposed to be the last method called.
1141 m_processes.DebugSetRSLock(NULL);
1142#endif
1143
1144 //
1145 // We expect the debugger to neuter all processes before calling Terminate(), so do not neuter them here.
1146 //
1147
1148#ifdef _DEBUG
1149 {
1150 HASHFIND find;
1151 _ASSERTE(m_processes.FindFirst(&find) == NULL); // should be emptied by neuter
1152 }
1153#endif //_DEBUG
1154
1155 // Officially mark us as neutered.
1156 this->Neuter();
1157
1158 m_processListMutex.Destroy();
1159
1160 //
1161 // Release the callbacks
1162 //
1163 m_managedCallback.Clear();
1164 m_managedCallback2.Clear();
1165 m_managedCallback3.Clear();
1166 m_managedCallback4.Clear();
1167 m_unmanagedCallback.Clear();
1168
1169 // The Shell may still have outstanding references, so we don't want to shutdown logging yet.
1170 // But everything should be neutered anyways.
1171
1172 m_initialized = FALSE;
1173
1174
1175 // After this, all outstanding Cordb objects should be neutered.
1176 LOG((LF_CORDB, LL_EVERYTHING, "Cordb finished terminating.\n"));
1177
1178#if defined(_DEBUG)
1179 //
1180 // Assert that there are no outstanding object references within the debugging
1181 // API itself.
1182 //
1183 CheckMemLeaks();
1184#endif
1185
1186 return S_OK;
1187}
1188
1189HRESULT Cordb::QueryInterface(REFIID id, void **pInterface)
1190{
1191 if (id == IID_ICorDebug)
1192 *pInterface = static_cast<ICorDebug*>(this);
1193 else if (id == IID_IUnknown)
1194 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebug*>(this));
1195 else
1196 {
1197 *pInterface = NULL;
1198 return E_NOINTERFACE;
1199 }
1200
1201 ExternalAddRef();
1202 return S_OK;
1203}
1204
1205
1206
1207//
1208// Initialize -- setup the ICorDebug object by creating any objects
1209// that the object needs to operate and starting the two needed IPC
1210// threads.
1211//
1212HRESULT Cordb::Initialize(void)
1213{
1214 HRESULT hr = S_OK;
1215
1216 FAIL_IF_NEUTERED(this);
1217
1218 if (!m_initialized)
1219 {
1220 CordbCommonBase::InitializeCommon();
1221
1222 // Since logging wasn't active when we called CordbBase, do it now.
1223 LOG((LF_CORDB, LL_EVERYTHING, "Memory: CordbBase object allocated: this=%p, count=%d, RootObject\n", this, s_TotalObjectCount));
1224 LOG((LF_CORDB, LL_INFO10, "Initializing ICorDebug...\n"));
1225
1226 // Ensure someone hasn't messed up the IPC buffer size
1227 _ASSERTE(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE);
1228
1229 //
1230 // Init things that the Cordb will need to operate
1231 //
1232 m_processListMutex.Init("Process-List Lock", RSLock::cLockReentrant, RSLock::LL_PROCESS_LIST_LOCK);
1233
1234#ifdef _DEBUG
1235 m_processes.DebugSetRSLock(&m_processListMutex);
1236#endif
1237
1238 //
1239 // Create the runtime controller event listening thread
1240 //
1241 m_rcEventThread = new (nothrow) CordbRCEventThread(this);
1242
1243 if (m_rcEventThread == NULL)
1244 {
1245 hr = E_OUTOFMEMORY;
1246 }
1247 else
1248 {
1249 // This stuff only creates events & starts the thread
1250 hr = m_rcEventThread->Init();
1251
1252 if (SUCCEEDED(hr))
1253 hr = m_rcEventThread->Start();
1254
1255 if (FAILED(hr))
1256 {
1257 delete m_rcEventThread;
1258 m_rcEventThread = NULL;
1259 }
1260 }
1261
1262 if (FAILED(hr))
1263 goto exit;
1264
1265 m_initialized = TRUE;
1266 }
1267
1268exit:
1269 return hr;
1270}
1271
1272//---------------------------------------------------------------------------------------
1273//
1274// Throw if no more process can be debugged with this Cordb object.
1275//
1276// Notes:
1277// This is highly dependent on the wait sets in the Win32 & RCET threads.
1278// @dbgtodo- this will end up in the shim.
1279
1280void Cordb::EnsureAllowAnotherProcess()
1281{
1282 CONTRACTL
1283 {
1284 THROWS;
1285 }
1286 CONTRACTL_END;
1287
1288 RSLockHolder ch(&m_processListMutex);
1289
1290 // Cordb, Win32, and RCET all have process sets, but Cordb's is the
1291 // best count of total debuggees. The RCET set is volatile (processes
1292 // are added / removed when they become synchronized), and Win32's set
1293 // doesn't include all processes.
1294 int cCurProcess = GetProcessList()->GetCount();
1295
1296 // In order to accept another debuggee, we must have a free slot in all
1297 // wait sets. Currently, we don't expose the size of those sets, but
1298 // we know they're MAXIMUM_WAIT_OBJECTS. Note that we lose one slot
1299 // to the control event.
1300 if (cCurProcess >= MAXIMUM_WAIT_OBJECTS - 1)
1301 {
1302 ThrowHR(CORDBG_E_TOO_MANY_PROCESSES);
1303 }
1304}
1305
1306//---------------------------------------------------------------------------------------
1307//
1308// Add process to the list.
1309//
1310// Notes:
1311// AddProcess -- add a process object to this ICorDebug's hash of processes.
1312// This also tells this ICorDebug's runtime controller thread that the
1313// process set has changed so it can update its list of wait events.
1314//
1315void Cordb::AddProcess(CordbProcess* process)
1316{
1317 // At this point, we should have already checked that we
1318 // can have another debuggee.
1319 STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::AddProcess %08x...\n", process);
1320
1321 if ((m_managedCallback == NULL) || (m_managedCallback2 == NULL) || (m_managedCallback3 == NULL) || (m_managedCallback4 == NULL))
1322 {
1323 ThrowHR(E_FAIL);
1324 }
1325
1326
1327
1328 RSLockHolder lockHolder(&m_processListMutex);
1329
1330 // Once we add another process, all outstanding process-enumerators become invalid.
1331 m_pProcessEnumList.NeuterAndClear(NULL);
1332
1333 GetProcessList()->AddBaseOrThrow(process);
1334 m_rcEventThread->ProcessStateChanged();
1335}
1336
1337//
1338// RemoveProcess -- remove a process object from this ICorDebug's hash of
1339// processes. This also tells this ICorDebug's runtime controller thread
1340// that the process set has changed so it can update its list of wait events.
1341//
1342void Cordb::RemoveProcess(CordbProcess* process)
1343{
1344 STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::RemoveProcess %08x...\n", process);
1345
1346 LockProcessList();
1347 GetProcessList()->RemoveBase((ULONG_PTR)process->m_id);
1348
1349 m_rcEventThread->ProcessStateChanged();
1350
1351 UnlockProcessList();
1352}
1353
1354//
1355// LockProcessList -- Lock the process list.
1356//
1357void Cordb::LockProcessList(void)
1358{
1359 m_processListMutex.Lock();
1360}
1361
1362//
1363// UnlockProcessList -- Unlock the process list.
1364//
1365void Cordb::UnlockProcessList(void)
1366{
1367 m_processListMutex.Unlock();
1368}
1369
1370#ifdef _DEBUG
1371// Return true iff this thread owns the ProcessList lock
1372bool Cordb::ThreadHasProcessListLock()
1373{
1374 return m_processListMutex.HasLock();
1375}
1376#endif
1377
1378
1379// Get the hash that has the process.
1380CordbSafeHashTable<CordbProcess> *Cordb::GetProcessList()
1381{
1382 // If we're accessing the hash, we'd better be locked.
1383 _ASSERTE(ThreadHasProcessListLock());
1384
1385 return &m_processes;
1386}
1387
1388
1389HRESULT Cordb::SendIPCEvent(CordbProcess * pProcess,
1390 DebuggerIPCEvent * pEvent,
1391 SIZE_T eventSize)
1392{
1393 HRESULT hr = S_OK;
1394
1395 LOG((LF_CORDB, LL_EVERYTHING, "SendIPCEvent in Cordb called\n"));
1396 EX_TRY
1397 {
1398 hr = m_rcEventThread->SendIPCEvent(pProcess, pEvent, eventSize);
1399 }
1400 EX_CATCH_HRESULT(hr)
1401 return hr;
1402}
1403
1404
1405void Cordb::ProcessStateChanged(void)
1406{
1407 m_rcEventThread->ProcessStateChanged();
1408}
1409
1410
1411HRESULT Cordb::WaitForIPCEventFromProcess(CordbProcess* process,
1412 CordbAppDomain *pAppDomain,
1413 DebuggerIPCEvent* event)
1414{
1415 return m_rcEventThread->WaitForIPCEventFromProcess(process,
1416 pAppDomain,
1417 event);
1418}
1419
1420HRESULT Cordb::SetTargetCLR(HMODULE hmodTargetCLR)
1421{
1422 if (m_initialized)
1423 return E_FAIL;
1424
1425#ifdef FEATURE_CORESYSTEM
1426 m_targetCLR = hmodTargetCLR;
1427#endif
1428
1429 // @REVIEW: are we happy with this workaround? It allows us to use the existing
1430 // infrastructure for instance name decoration, but it really doesn't fit
1431 // the same model because coreclr.dll isn't in this process and hmodTargetCLR
1432 // is the debuggee target, not the coreclr.dll to bind utilcode to..
1433
1434 CoreClrCallbacks cccallbacks;
1435 cccallbacks.m_hmodCoreCLR = hmodTargetCLR;
1436 cccallbacks.m_pfnIEE = NULL;
1437 cccallbacks.m_pfnGetCORSystemDirectory = NULL;
1438 cccallbacks.m_pfnGetCLRFunction = NULL;
1439 InitUtilcode(cccallbacks);
1440
1441 return S_OK;
1442}
1443
1444//-----------------------------------------------------------
1445// ICorDebug
1446//-----------------------------------------------------------
1447
1448// Set the handler for callbacks on managed events
1449// This can not be NULL.
1450// If we're debugging V2.0 apps, pCallback must implement ICDManagedCallback2
1451// @todo- what if somebody calls this after we've already initialized? (eg, changes
1452// the callback underneath us)
1453HRESULT Cordb::SetManagedHandler(ICorDebugManagedCallback *pCallback)
1454{
1455 if (!m_initialized)
1456 return E_FAIL;
1457
1458 FAIL_IF_NEUTERED(this);
1459 VALIDATE_POINTER_TO_OBJECT(pCallback, ICorDebugManagedCallback*);
1460
1461 m_managedCallback.Clear();
1462 m_managedCallback2.Clear();
1463 m_managedCallback3.Clear();
1464 m_managedCallback4.Clear();
1465
1466 // For SxS, V2.0 debuggers must implement ManagedCallback2 to handle v2.0 debug events.
1467 // For Single-CLR, A v1.0 debugger may actually geta V2.0 debuggee.
1468 pCallback->QueryInterface(IID_ICorDebugManagedCallback2, (void **)&m_managedCallback2);
1469 if (m_managedCallback2 == NULL)
1470 {
1471 if (GetDebuggerVersion() >= CorDebugVersion_2_0)
1472 {
1473 // This will leave our internal callbacks null, which future operations (Create/Attach) will
1474 // use to know that we're not sufficiently initialized.
1475 return E_NOINTERFACE;
1476 }
1477 else
1478 {
1479 // This should only be used in a single-CLR shimming scenario.
1480 m_managedCallback2.Assign(new (nothrow) DefaultManagedCallback2(this));
1481
1482 if (m_managedCallback2 == NULL)
1483 {
1484 return E_OUTOFMEMORY;
1485 }
1486 }
1487 }
1488
1489 pCallback->QueryInterface(IID_ICorDebugManagedCallback3, (void **)&m_managedCallback3);
1490 if (m_managedCallback3 == NULL)
1491 {
1492 m_managedCallback3.Assign(new (nothrow) DefaultManagedCallback3(this));
1493 }
1494
1495 if (m_managedCallback3 == NULL)
1496 {
1497 return E_OUTOFMEMORY;
1498 }
1499
1500 pCallback->QueryInterface(IID_ICorDebugManagedCallback4, (void **)&m_managedCallback4);
1501 if (m_managedCallback4 == NULL)
1502 {
1503 m_managedCallback4.Assign(new (nothrow) DefaultManagedCallback4(this));
1504 }
1505
1506 if (m_managedCallback4 == NULL)
1507 {
1508 return E_OUTOFMEMORY;
1509 }
1510
1511 m_managedCallback.Assign(pCallback);
1512 return S_OK;
1513}
1514
1515HRESULT Cordb::SetUnmanagedHandler(ICorDebugUnmanagedCallback *pCallback)
1516{
1517 if (!m_initialized)
1518 return E_FAIL;
1519
1520 FAIL_IF_NEUTERED(this);
1521 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pCallback, ICorDebugUnmanagedCallback*);
1522
1523 m_unmanagedCallback.Assign(pCallback);
1524
1525 return S_OK;
1526}
1527
1528// CreateProcess() isn't supported on Windows CoreCLR.
1529// It is currently supported on Mac CoreCLR, but that may change.
1530bool Cordb::IsCreateProcessSupported()
1531{
1532#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
1533 return false;
1534#else
1535 return true;
1536#endif
1537}
1538
1539// Given everything we know about our configuration, can we support interop-debugging
1540bool Cordb::IsInteropDebuggingSupported()
1541{
1542 // We explicitly refrain from checking the unmanaged callback. See comment in
1543 // ICorDebug::SetUnmanagedHandler for details.
1544#ifdef FEATURE_INTEROP_DEBUGGING
1545
1546#if !defined(FEATURE_CORESYSTEM)
1547 // Interop debugging is only supported internally on CoreCLR.
1548 // Check if the special reg key is set. If not, then we don't allow interop debugging.
1549 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgEnableMixedModeDebugging) == 0)
1550 {
1551 return false;
1552 }
1553#endif // FEATURE_CORESYSTEM
1554
1555 return true;
1556#else
1557 return false;
1558#endif
1559}
1560
1561
1562//---------------------------------------------------------------------------------------
1563//
1564// Implementation of ICorDebug::CreateProcess.
1565// Creates a process.
1566//
1567// Arguments:
1568// The following arguments are passed thru unmodified to the OS CreateProcess API and
1569// are defined by that API.
1570// lpApplicationName
1571// lpCommandLine
1572// lpProcessAttributes
1573// lpThreadAttributes
1574// bInheritHandles
1575// dwCreationFlags
1576// lpCurrentDirectory
1577// lpStartupInfo
1578// lpProcessInformation
1579// debuggingFlags
1580//
1581// ppProcess - Space to fill in for the resulting process, returned as a valid pointer
1582// on any success HRESULT.
1583//
1584// Return Value:
1585// Normal HRESULT semantics.
1586//
1587//---------------------------------------------------------------------------------------
1588HRESULT Cordb::CreateProcess(LPCWSTR lpApplicationName,
1589 __in_z LPWSTR lpCommandLine,
1590 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1591 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1592 BOOL bInheritHandles,
1593 DWORD dwCreationFlags,
1594 PVOID lpEnvironment,
1595 LPCWSTR lpCurrentDirectory,
1596 LPSTARTUPINFOW lpStartupInfo,
1597 LPPROCESS_INFORMATION lpProcessInformation,
1598 CorDebugCreateProcessFlags debuggingFlags,
1599 ICorDebugProcess **ppProcess)
1600{
1601 return CreateProcessCommon(NULL,
1602 lpApplicationName,
1603 lpCommandLine,
1604 lpProcessAttributes,
1605 lpThreadAttributes,
1606 bInheritHandles,
1607 dwCreationFlags,
1608 lpEnvironment,
1609 lpCurrentDirectory,
1610 lpStartupInfo,
1611 lpProcessInformation,
1612 debuggingFlags,
1613 ppProcess);
1614}
1615
1616HRESULT Cordb::CreateProcessCommon(ICorDebugRemoteTarget * pRemoteTarget,
1617 LPCWSTR lpApplicationName,
1618 __in_z LPWSTR lpCommandLine,
1619 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1620 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1621 BOOL bInheritHandles,
1622 DWORD dwCreationFlags,
1623 PVOID lpEnvironment,
1624 LPCWSTR lpCurrentDirectory,
1625 LPSTARTUPINFOW lpStartupInfo,
1626 LPPROCESS_INFORMATION lpProcessInformation,
1627 CorDebugCreateProcessFlags debuggingFlags,
1628 ICorDebugProcess ** ppProcess)
1629{
1630 // If you hit this assert, it means that you are attempting to create a process without specifying the version
1631 // number.
1632 _ASSERTE(CorDebugInvalidVersion != m_debuggerSpecifiedVersion);
1633
1634 PUBLIC_API_ENTRY(this);
1635 FAIL_IF_NEUTERED(this);
1636 VALIDATE_POINTER_TO_OBJECT(ppProcess, ICorDebugProcess**);
1637
1638 HRESULT hr = S_OK;
1639
1640 EX_TRY
1641 {
1642 if (!m_initialized)
1643 {
1644 ThrowHR(E_FAIL);
1645 }
1646
1647 // Check that we support the debugger version
1648 CheckCompatibility();
1649
1650 #ifdef FEATURE_INTEROP_DEBUGGING
1651 // DEBUG_PROCESS (=0x1) means debug this process & all future children.
1652 // DEBUG_ONLY_THIS_PROCESS =(0x2) means just debug the immediate process.
1653 // If we want to support DEBUG_PROCESS, then we need to have the RS sniff for new CREATE_PROCESS
1654 // events and spawn new CordbProcess for them.
1655 switch(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
1656 {
1657 // 1) managed-only debugging
1658 case 0:
1659 break;
1660
1661 // 2) failure - returns E_NOTIMPL. (as this would involve debugging all of our children processes).
1662 case DEBUG_PROCESS:
1663 ThrowHR(E_NOTIMPL);
1664
1665 // 3) Interop-debugging.
1666 // Note that MSDN (at least as of Jan 2003) is wrong about this flag. MSDN claims
1667 // DEBUG_ONLY_THIS_PROCESS w/o DEBUG_PROCESS should be ignored.
1668 // But it really should do launch as a debuggee (but not auto-attach to child processes).
1669 case DEBUG_ONLY_THIS_PROCESS:
1670 // Emprically, this is the common case for native / interop-debugging.
1671 break;
1672
1673 // 4) Interop.
1674 // The spec for ICorDebug::CreateProcess says this is the one to use for interop-debugging.
1675 case DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS:
1676 // Win2k does not honor these flags properly. So we just use
1677 // It treats (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) as if it were DEBUG_PROCESS.
1678 // We'll just always touch up the flags, even though WinXP and above is fine here.
1679 // Per win2k issue, strip off DEBUG_PROCESS, so that we're just left w/ DEBUG_ONLY_THIS_PROCESS.
1680 dwCreationFlags &= ~(DEBUG_PROCESS);
1681 break;
1682
1683 default:
1684 __assume(0);
1685 }
1686
1687 #endif // FEATURE_INTEROP_DEBUGGING
1688
1689 // Must have a managed-callback by now.
1690 if ((m_managedCallback == NULL) || (m_managedCallback2 == NULL) || (m_managedCallback3 == NULL) || (m_managedCallback4 == NULL))
1691 {
1692 ThrowHR(E_FAIL);
1693 }
1694
1695 if (!IsCreateProcessSupported())
1696 {
1697 ThrowHR(E_NOTIMPL);
1698 }
1699
1700 if (!IsInteropDebuggingSupported() &&
1701 ((dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) != 0))
1702 {
1703 ThrowHR(CORDBG_E_INTEROP_NOT_SUPPORTED);
1704 }
1705
1706 // Check that we can even accept another debuggee before trying anything.
1707 EnsureAllowAnotherProcess();
1708
1709 } EX_CATCH_HRESULT(hr);
1710 if (FAILED(hr))
1711 {
1712 return hr;
1713 }
1714
1715 hr = ShimProcess::CreateProcess(this,
1716 pRemoteTarget,
1717 lpApplicationName,
1718 lpCommandLine,
1719 lpProcessAttributes,
1720 lpThreadAttributes,
1721 bInheritHandles,
1722 dwCreationFlags,
1723 lpEnvironment,
1724 lpCurrentDirectory,
1725 lpStartupInfo,
1726 lpProcessInformation,
1727 debuggingFlags
1728 );
1729
1730 LOG((LF_CORDB, LL_EVERYTHING, "Handle in Cordb::CreateProcess is: %.I64x\n", lpProcessInformation->hProcess));
1731
1732 if (SUCCEEDED(hr))
1733 {
1734 LockProcessList();
1735
1736 CordbProcess * pProcess = GetProcessList()->GetBase(lpProcessInformation->dwProcessId);
1737
1738 UnlockProcessList();
1739
1740 PREFIX_ASSUME(pProcess != NULL);
1741
1742 pProcess->ExternalAddRef();
1743 *ppProcess = (ICorDebugProcess *)pProcess;
1744 }
1745
1746 return hr;
1747}
1748
1749
1750HRESULT Cordb::CreateProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
1751 LPCWSTR lpApplicationName,
1752 __in_z LPWSTR lpCommandLine,
1753 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1754 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1755 BOOL bInheritHandles,
1756 DWORD dwCreationFlags,
1757 PVOID lpEnvironment,
1758 LPCWSTR lpCurrentDirectory,
1759 LPSTARTUPINFOW lpStartupInfo,
1760 LPPROCESS_INFORMATION lpProcessInformation,
1761 CorDebugCreateProcessFlags debuggingFlags,
1762 ICorDebugProcess ** ppProcess)
1763{
1764 if (pRemoteTarget == NULL)
1765 {
1766 return E_INVALIDARG;
1767 }
1768
1769 return CreateProcessCommon(pRemoteTarget,
1770 lpApplicationName,
1771 lpCommandLine,
1772 lpProcessAttributes,
1773 lpThreadAttributes,
1774 bInheritHandles,
1775 dwCreationFlags,
1776 lpEnvironment,
1777 lpCurrentDirectory,
1778 lpStartupInfo,
1779 lpProcessInformation,
1780 debuggingFlags,
1781 ppProcess);
1782}
1783
1784
1785//---------------------------------------------------------------------------------------
1786//
1787// Attachs to an existing process.
1788//
1789// Arguments:
1790// dwProcessID - The PID to attach to
1791// fWin32Attach - Flag to tell whether to attach as the Win32 debugger or not.
1792// ppProcess - Space to fill in for the resulting process, returned as a valid pointer
1793// on any success HRESULT.
1794//
1795// Return Value:
1796// Normal HRESULT semantics.
1797//
1798//---------------------------------------------------------------------------------------
1799HRESULT Cordb::DebugActiveProcess(DWORD dwProcessId,
1800 BOOL fWin32Attach,
1801 ICorDebugProcess **ppProcess)
1802{
1803 return DebugActiveProcessCommon(NULL, dwProcessId, fWin32Attach, ppProcess);
1804}
1805
1806HRESULT Cordb::DebugActiveProcessCommon(ICorDebugRemoteTarget * pRemoteTarget,
1807 DWORD dwProcessId,
1808 BOOL fWin32Attach,
1809 ICorDebugProcess ** ppProcess)
1810{
1811 PUBLIC_API_ENTRY(this);
1812 FAIL_IF_NEUTERED(this);
1813 VALIDATE_POINTER_TO_OBJECT(ppProcess, ICorDebugProcess **);
1814
1815 HRESULT hr = S_OK;
1816
1817 EX_TRY
1818 {
1819 if (!m_initialized)
1820 {
1821 ThrowHR(E_FAIL);
1822 }
1823
1824 // Must have a managed-callback by now.
1825 if ((m_managedCallback == NULL) || (m_managedCallback2 == NULL) || (m_managedCallback3 == NULL) || (m_managedCallback4 == NULL))
1826 {
1827 ThrowHR(E_FAIL);
1828 }
1829
1830 // Verify that given process ID, matches the process ID for which the object was created
1831 if (m_pd.IsInitialized() && m_pd.m_Pid != dwProcessId)
1832 {
1833 ThrowHR(E_INVALIDARG);
1834 }
1835
1836 // See the comment in Cordb::CreateProcess
1837 _ASSERTE(CorDebugInvalidVersion != m_debuggerSpecifiedVersion);
1838
1839 // Check that we support the debugger version
1840 CheckCompatibility();
1841
1842 // Check that we can even accept another debuggee before trying anything.
1843 EnsureAllowAnotherProcess();
1844
1845 // Check if we're allowed to do interop.
1846 bool fAllowInterop = IsInteropDebuggingSupported();
1847
1848 if (!fAllowInterop && fWin32Attach)
1849 {
1850 ThrowHR(CORDBG_E_INTEROP_NOT_SUPPORTED);
1851 }
1852
1853 } EX_CATCH_HRESULT(hr)
1854 if (FAILED(hr))
1855 {
1856 return hr;
1857 }
1858
1859 hr = ShimProcess::DebugActiveProcess(
1860 this,
1861 pRemoteTarget,
1862 &m_pd,
1863 fWin32Attach == TRUE);
1864
1865 // If that worked, then there will be a process object...
1866 if (SUCCEEDED(hr))
1867 {
1868 LockProcessList();
1869 CordbProcess * pProcess = GetProcessList()->GetBase(dwProcessId);
1870
1871 if (pProcess != NULL)
1872 {
1873 // Add a reference now so process won't go away
1874 pProcess->ExternalAddRef();
1875 }
1876 UnlockProcessList();
1877
1878 if (pProcess == NULL)
1879 {
1880 // This can happen if we add the process into process hash in
1881 // SendDebugActiveProcessEvent and then process exit
1882 // before we attemp to retrieve it again from GetBase.
1883 //
1884 *ppProcess = NULL;
1885 return S_FALSE;
1886 }
1887
1888#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
1889 // This is where we queue the managed attach event in Whidbey. In the new architecture, the Windows
1890 // pipeline gets a loader breakpoint when native attach is completed, and that's where we queue the
1891 // managed attach event. See how we handle the loader breakpoint in code:ShimProcess::DefaultEventHandler.
1892 // However, the Mac debugging transport gets no such breakpoint, and so we need to do this here.
1893 //
1894 // @dbgtodo Mac - Ideally we should hide this in our pipeline implementation, or at least move
1895 // this to the shim.
1896 _ASSERTE(!fWin32Attach);
1897 {
1898 pProcess->Lock();
1899 hr = pProcess->QueueManagedAttach();
1900 pProcess->Unlock();
1901 }
1902#endif // FEATURE_DBGIPC_TRANSPORT_DI
1903
1904 *ppProcess = (ICorDebugProcess*) pProcess;
1905 }
1906
1907 return hr;
1908}
1909
1910// Make sure we want to support the debugger that's using us
1911void Cordb::CheckCompatibility()
1912{
1913 // Get the debugger version specified by the startup APIs and convert it to a CLR major version number
1914 CorDebugInterfaceVersion debuggerVersion = GetDebuggerVersion();
1915 DWORD clrMajor;
1916 if (debuggerVersion <= CorDebugVersion_1_0 || debuggerVersion == CorDebugVersion_1_1)
1917 clrMajor = 1;
1918 else if (debuggerVersion <= CorDebugVersion_2_0)
1919 clrMajor = 2;
1920 else if (debuggerVersion <= CorDebugVersion_4_0)
1921 clrMajor = 4;
1922 else
1923 clrMajor = 5; // some unrecognized future version
1924
1925 if(!CordbProcess::IsCompatibleWith(clrMajor))
1926 {
1927 // Carefully choose our error-code to get an appropriate error-message from VS 2008
1928 // If GetDebuggerVersion is >= 4, we could consider using the more-appropriate (but not
1929 // added until V4) HRESULT CORDBG_E_UNSUPPORTED_FORWARD_COMPAT that is used by
1930 // OpenVirtualProcess, but it's probably simpler to keep ICorDebug APIs returning
1931 // consistent error codes.
1932 ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL);
1933 }
1934}
1935
1936HRESULT Cordb::DebugActiveProcessEx(ICorDebugRemoteTarget * pRemoteTarget,
1937 DWORD dwProcessId,
1938 BOOL fWin32Attach,
1939 ICorDebugProcess ** ppProcess)
1940{
1941 if (pRemoteTarget == NULL)
1942 {
1943 return E_INVALIDARG;
1944 }
1945
1946 return DebugActiveProcessCommon(pRemoteTarget, dwProcessId, fWin32Attach, ppProcess);
1947}
1948
1949
1950HRESULT Cordb::GetProcess(DWORD dwProcessId, ICorDebugProcess **ppProcess)
1951{
1952 PUBLIC_API_ENTRY(this);
1953 FAIL_IF_NEUTERED(this);
1954 VALIDATE_POINTER_TO_OBJECT(ppProcess, ICorDebugProcess**);
1955
1956 if (!m_initialized)
1957 {
1958 return E_FAIL;
1959 }
1960
1961 LockProcessList();
1962 CordbProcess *p = GetProcessList()->GetBase(dwProcessId);
1963 UnlockProcessList();
1964
1965 if (p == NULL)
1966 return E_INVALIDARG;
1967
1968 p->ExternalAddRef();
1969 *ppProcess = static_cast<ICorDebugProcess*> (p);
1970
1971 return S_OK;
1972}
1973
1974HRESULT Cordb::EnumerateProcesses(ICorDebugProcessEnum **ppProcesses)
1975{
1976 PUBLIC_API_ENTRY(this);
1977 FAIL_IF_NEUTERED(this);
1978 VALIDATE_POINTER_TO_OBJECT(ppProcesses, ICorDebugProcessEnum **);
1979
1980 HRESULT hr = S_OK;
1981 EX_TRY
1982 {
1983 if (!m_initialized)
1984 {
1985 ThrowHR(E_FAIL);
1986 }
1987
1988 // Locking here just means that the enumerator gets initialized against a consistent
1989 // process-list. If we add/remove processes w/ an outstanding enumerator, things
1990 // could still get out of sync.
1991 RSLockHolder lockHolder(&this->m_processListMutex);
1992
1993 RSInitHolder<CordbHashTableEnum> pEnum;
1994 CordbHashTableEnum::BuildOrThrow(
1995 this,
1996 &m_pProcessEnumList,
1997 GetProcessList(),
1998 IID_ICorDebugProcessEnum,
1999 pEnum.GetAddr());
2000
2001
2002 pEnum.TransferOwnershipExternal(ppProcesses);
2003 }
2004 EX_CATCH_HRESULT(hr);
2005 return hr;
2006}
2007
2008
2009//
2010// Note: the following defs and structs are copied from various NT headers. I wasn't able to include those headers (like
2011// ntexapi.h) due to loads of redef problems and other conflicts with headers that we already pull in.
2012//
2013typedef LONG NTSTATUS;
2014
2015#ifndef FEATURE_PAL
2016typedef BOOL (*NTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS SystemInformationClass,
2017 PVOID SystemInformation,
2018 ULONG SystemInformationLength,
2019 PULONG ReturnLength);
2020#endif
2021
2022// Implementation of ICorDebug::CanLaunchOrAttach
2023// @dbgtodo- this all goes away in V3.
2024// @dbgtodo- this should go away in Dev11.
2025HRESULT Cordb::CanLaunchOrAttach(DWORD dwProcessId, BOOL fWin32DebuggingEnabled)
2026{
2027 PUBLIC_API_ENTRY(this);
2028 FAIL_IF_NEUTERED(this);
2029
2030 HRESULT hr = S_OK;
2031 EX_TRY
2032 {
2033 EnsureCanLaunchOrAttach(fWin32DebuggingEnabled);
2034 }
2035 EX_CATCH_HRESULT(hr);
2036
2037 return hr;
2038}
2039
2040//---------------------------------------------------------------------------------------
2041//
2042// Throw an expcetion if we can't launch/attach.
2043//
2044// Arguments:
2045// fWin32DebuggingEnabled - true if interop-debugging, else false
2046//
2047// Return Value:
2048// None. If this returns, then it's safe to launch/attach.
2049// Else this throws an exception on failure.
2050//
2051// Assumptions:
2052//
2053// Notes:
2054// It should always be safe to launch/attach except in exceptional cases.
2055// @dbgtodo- this all goes away in V3.
2056// @dbgtodo- this should go away in Dev11.
2057//
2058void Cordb::EnsureCanLaunchOrAttach(BOOL fWin32DebuggingEnabled)
2059{
2060 CONTRACTL
2061 {
2062 THROWS;
2063 }
2064 CONTRACTL_END;
2065 if (!m_initialized)
2066 {
2067 ThrowHR(E_FAIL);
2068 }
2069
2070 EnsureAllowAnotherProcess();
2071
2072 if (!IsInteropDebuggingSupported() && fWin32DebuggingEnabled)
2073 {
2074 ThrowHR(CORDBG_E_INTEROP_NOT_SUPPORTED);
2075 }
2076
2077 // Made it this far, we succeeded.
2078}
2079
2080HRESULT Cordb::CreateObjectV1(REFIID id, void **object)
2081{
2082 return CreateObject(CorDebugVersion_1_0, ProcessDescriptor::UNINITIALIZED_PID, NULL, id, object);
2083}
2084
2085#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
2086// CoreCLR activates debugger objects via direct COM rather than the shim (just like V1). For now we share the
2087// same debug engine version as V2, though this may change in the future.
2088HRESULT Cordb::CreateObjectTelesto(REFIID id, void ** pObject)
2089{
2090 return CreateObject(CorDebugVersion_2_0, ProcessDescriptor::UNINITIALIZED_PID, NULL, id, pObject);
2091}
2092#endif // FEATURE_DBGIPC_TRANSPORT_DI
2093
2094// Static
2095// Used to create an instance for a ClassFactory (thus an external ref).
2096HRESULT Cordb::CreateObject(CorDebugInterfaceVersion iDebuggerVersion, DWORD pid, LPCWSTR lpApplicationGroupId, REFIID id, void **object)
2097{
2098 if (id != IID_IUnknown && id != IID_ICorDebug)
2099 return (E_NOINTERFACE);
2100
2101 LPSTR applicationGroupId = NULL;
2102 if (lpApplicationGroupId != NULL)
2103 {
2104 // Get length of target string
2105 int cbMultiByte = WideCharToMultiByte(CP_ACP, 0, lpApplicationGroupId, -1, NULL, 0, NULL, NULL);
2106 if (cbMultiByte == 0)
2107 {
2108 return E_FAIL;
2109 }
2110
2111 applicationGroupId = new (nothrow) CHAR[cbMultiByte];
2112 if (applicationGroupId == NULL)
2113 {
2114 return (E_OUTOFMEMORY);
2115 }
2116
2117 /* Convert to ASCII */
2118 cbMultiByte = WideCharToMultiByte(CP_ACP, 0, lpApplicationGroupId, -1, applicationGroupId, cbMultiByte, NULL, NULL);
2119 if (cbMultiByte == 0)
2120 {
2121 return E_FAIL;
2122 }
2123 }
2124
2125 ProcessDescriptor pd = ProcessDescriptor::Create(pid, applicationGroupId);
2126
2127 Cordb *db = new (nothrow) Cordb(iDebuggerVersion, pd);
2128
2129 if (db == NULL)
2130 {
2131 if (applicationGroupId != NULL)
2132 delete [] applicationGroupId;
2133
2134 return (E_OUTOFMEMORY);
2135 }
2136
2137 *object = static_cast<ICorDebug*> (db);
2138 db->ExternalAddRef();
2139
2140 return (S_OK);
2141}
2142
2143
2144// This is the version of the ICorDebug APIs that the debugger believes it's consuming.
2145// If this is a different version than that of the debuggee, we have the option of shimming
2146// behavior.
2147CorDebugInterfaceVersion
2148Cordb::GetDebuggerVersion() const
2149{
2150 return m_debuggerSpecifiedVersion;
2151}
2152
2153//***********************************************************************
2154// ICorDebugTMEnum (Thread and Module enumerator)
2155//***********************************************************************
2156CordbEnumFilter::CordbEnumFilter(CordbBase * pOwnerObj, NeuterList * pOwnerList)
2157 : CordbBase (pOwnerObj->GetProcess(), 0),
2158 m_pOwnerObj(pOwnerObj),
2159 m_pOwnerNeuterList(pOwnerList),
2160 m_pFirst (NULL),
2161 m_pCurrent (NULL),
2162 m_iCount (0)
2163{
2164 _ASSERTE(m_pOwnerNeuterList != NULL);
2165
2166 HRESULT hr = S_OK;
2167 EX_TRY
2168 {
2169 m_pOwnerNeuterList->Add(pOwnerObj->GetProcess(), this);
2170 }
2171 EX_CATCH_HRESULT(hr);
2172 SetUnrecoverableIfFailed(GetProcess(), hr);
2173
2174}
2175
2176CordbEnumFilter::CordbEnumFilter(CordbEnumFilter *src)
2177 : CordbBase (src->GetProcess(), 0),
2178 m_pOwnerObj(src->m_pOwnerObj),
2179 m_pOwnerNeuterList(src->m_pOwnerNeuterList),
2180 m_pFirst (NULL),
2181 m_pCurrent (NULL)
2182{
2183 _ASSERTE(m_pOwnerNeuterList != NULL);
2184
2185 HRESULT hr = S_OK;
2186 EX_TRY
2187 {
2188 m_pOwnerNeuterList->Add(src->GetProcess(), this);
2189 }
2190 EX_CATCH_HRESULT(hr);
2191 SetUnrecoverableIfFailed(GetProcess(), hr);
2192
2193
2194
2195 int iCountSanityCheck = 0;
2196 EnumElement *pElementCur = NULL;
2197 EnumElement *pElementNew = NULL;
2198 EnumElement *pElementNewPrev = NULL;
2199
2200 m_iCount = src->m_iCount;
2201
2202 pElementCur = src->m_pFirst;
2203
2204 while (pElementCur != NULL)
2205 {
2206 pElementNew = new (nothrow) EnumElement;
2207 if (pElementNew == NULL)
2208 {
2209 // Out of memory. Clean up and bail out.
2210 goto Error;
2211 }
2212
2213 if (pElementNewPrev == NULL)
2214 {
2215 m_pFirst = pElementNew;
2216 }
2217 else
2218 {
2219 pElementNewPrev->SetNext(pElementNew);
2220 }
2221
2222 pElementNewPrev = pElementNew;
2223
2224 // Copy the element, including the AddRef part
2225 pElementNew->SetData(pElementCur->GetData());
2226 IUnknown *iu = (IUnknown *)pElementCur->GetData();
2227 iu->AddRef();
2228
2229 if (pElementCur == src->m_pCurrent)
2230 m_pCurrent = pElementNew;
2231
2232 pElementCur = pElementCur->GetNext();
2233 iCountSanityCheck++;
2234 }
2235
2236 _ASSERTE(iCountSanityCheck == m_iCount);
2237
2238 return;
2239Error:
2240 // release all the allocated memory before returning
2241 pElementCur = m_pFirst;
2242
2243 while (pElementCur != NULL)
2244 {
2245 pElementNewPrev = pElementCur;
2246 pElementCur = pElementCur->GetNext();
2247
2248 ((ICorDebugModule *)pElementNewPrev->GetData())->Release();
2249 delete pElementNewPrev;
2250 }
2251}
2252
2253CordbEnumFilter::~CordbEnumFilter()
2254{
2255 _ASSERTE(this->IsNeutered());
2256
2257 _ASSERTE(m_pFirst == NULL);
2258}
2259
2260void CordbEnumFilter::Neuter()
2261{
2262 EnumElement *pElement = m_pFirst;
2263 EnumElement *pPrevious = NULL;
2264
2265 while (pElement != NULL)
2266 {
2267 pPrevious = pElement;
2268 pElement = pElement->GetNext();
2269 delete pPrevious;
2270 }
2271
2272 // Null out the head in case we get neutered again.
2273 m_pFirst = NULL;
2274 m_pCurrent = NULL;
2275
2276 CordbBase::Neuter();
2277}
2278
2279
2280
2281HRESULT CordbEnumFilter::QueryInterface(REFIID id, void **ppInterface)
2282{
2283 // if we QI with the IID of the base type, we can't just return a pointer ICorDebugEnum directly, because
2284 // the cast is ambiguous. This happens because CordbEnumFilter implements both ICorDebugModuleEnum and
2285 // ICorDebugThreadEnum, both of which derive in turn from ICorDebugEnum. This produces a diamond inheritance
2286 // graph. Thus we need a double cast. It doesn't really matter whether we pick ICorDebugThreadEnum or
2287 // ICorDebugModuleEnum, because it will be backed by the same object regardless.
2288 if (id == IID_ICorDebugEnum)
2289 *ppInterface = static_cast<ICorDebugEnum *>(static_cast<ICorDebugThreadEnum *>(this));
2290 else if (id == IID_ICorDebugModuleEnum)
2291 *ppInterface = (ICorDebugModuleEnum*)this;
2292 else if (id == IID_ICorDebugThreadEnum)
2293 *ppInterface = (ICorDebugThreadEnum*)this;
2294 else if (id == IID_IUnknown)
2295 *ppInterface = this;
2296 else
2297 {
2298 *ppInterface = NULL;
2299 return E_NOINTERFACE;
2300 }
2301
2302 ExternalAddRef();
2303 return S_OK;
2304}
2305
2306HRESULT CordbEnumFilter::Skip(ULONG celt)
2307{
2308 HRESULT hr = S_OK;
2309 PUBLIC_API_BEGIN(this);
2310 {
2311 while ((celt-- > 0) && (m_pCurrent != NULL))
2312 {
2313 m_pCurrent = m_pCurrent->GetNext();
2314 }
2315 }
2316 PUBLIC_API_END(hr);
2317 return hr;
2318}
2319
2320HRESULT CordbEnumFilter::Reset()
2321{
2322 HRESULT hr = S_OK;
2323 PUBLIC_API_BEGIN(this);
2324 {
2325 m_pCurrent = m_pFirst;
2326 }
2327 PUBLIC_API_END(hr);
2328 return hr;
2329}
2330
2331HRESULT CordbEnumFilter::Clone(ICorDebugEnum **ppEnum)
2332{
2333 HRESULT hr = S_OK;
2334 PUBLIC_API_BEGIN(this);
2335 {
2336 ValidateOrThrow(ppEnum);
2337
2338 CordbEnumFilter * pClone = new CordbEnumFilter(this);
2339
2340 // Ambiguous conversion from CordbEnumFilter to ICorDebugEnum, so
2341 // we explicitly convert it through ICorDebugThreadEnum.
2342 pClone->ExternalAddRef();
2343 (*ppEnum) = static_cast<ICorDebugThreadEnum *> (pClone);
2344 }
2345 PUBLIC_API_END(hr);
2346 return hr;
2347}
2348
2349HRESULT CordbEnumFilter::GetCount(ULONG *pcelt)
2350{
2351 HRESULT hr = S_OK;
2352 PUBLIC_API_BEGIN(this);
2353 {
2354 ValidateOrThrow(pcelt);
2355 *pcelt = (ULONG)m_iCount;
2356 }
2357 PUBLIC_API_END(hr);
2358 return hr;
2359}
2360
2361HRESULT CordbEnumFilter::Next(ULONG celt,
2362 ICorDebugModule *objects[],
2363 ULONG *pceltFetched)
2364{
2365 HRESULT hr = S_OK;
2366 PUBLIC_API_BEGIN(this);
2367 {
2368 hr = NextWorker(celt, objects, pceltFetched);
2369 }
2370 PUBLIC_API_END(hr);
2371 return hr;
2372}
2373
2374HRESULT CordbEnumFilter::NextWorker(ULONG celt, ICorDebugModule *objects[], ULONG *pceltFetched)
2375{
2376 // <TODO>
2377 //
2378 // nickbe 11/20/2002 10:43:39
2379 // This function allows you to enumerate threads that "belong" to a
2380 // particular AppDomain. While this operation makes some sense, it makes
2381 // very little sense to
2382 // (a) enumerate the list of threads in the enter process
2383 // (b) build up a hand-rolled singly linked list (grrr)
2384 // </TODO>
2385 VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorDebugModule *,
2386 celt, true, true);
2387 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
2388
2389 if ((pceltFetched == NULL) && (celt != 1))
2390 {
2391 return E_INVALIDARG;
2392 }
2393
2394 if (celt == 0)
2395 {
2396 if (pceltFetched != NULL)
2397 {
2398 *pceltFetched = 0;
2399 }
2400 return S_OK;
2401 }
2402
2403 HRESULT hr = S_OK;
2404
2405 ULONG count = 0;
2406
2407 while ((m_pCurrent != NULL) && (count < celt))
2408 {
2409 objects[count] = (ICorDebugModule *)m_pCurrent->GetData();
2410 m_pCurrent = m_pCurrent->GetNext();
2411 count++;
2412 }
2413
2414 if (pceltFetched != NULL)
2415 {
2416 *pceltFetched = count;
2417 }
2418
2419 //
2420 // If we reached the end of the enumeration, but not the end
2421 // of the number of requested items, we return S_FALSE.
2422 //
2423 if (count < celt)
2424 {
2425 return S_FALSE;
2426 }
2427
2428 return hr;
2429}
2430
2431
2432HRESULT CordbEnumFilter::Next(ULONG celt,
2433 ICorDebugThread *objects[],
2434 ULONG *pceltFetched)
2435{
2436 HRESULT hr = S_OK;
2437 PUBLIC_API_BEGIN(this);
2438 {
2439 hr = NextWorker(celt, objects, pceltFetched);
2440 }
2441 PUBLIC_API_END(hr);
2442 return hr;
2443}
2444
2445HRESULT CordbEnumFilter::NextWorker(ULONG celt, ICorDebugThread *objects[], ULONG *pceltFetched)
2446{
2447 // @TODO remove this class
2448 VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorDebugThread *, celt, true, true);
2449 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
2450
2451 if ((pceltFetched == NULL) && (celt != 1))
2452 {
2453 return E_INVALIDARG;
2454 }
2455
2456 if (celt == 0)
2457 {
2458 if (pceltFetched != NULL)
2459 {
2460 *pceltFetched = 0;
2461 }
2462 return S_OK;
2463 }
2464
2465 HRESULT hr = S_OK;
2466
2467 ULONG count = 0;
2468
2469 while ((m_pCurrent != NULL) && (count < celt))
2470 {
2471 objects[count] = (ICorDebugThread *)m_pCurrent->GetData();
2472 m_pCurrent = m_pCurrent->GetNext();
2473 count++;
2474 }
2475
2476 if (pceltFetched != NULL)
2477 {
2478 *pceltFetched = count;
2479 }
2480
2481 //
2482 // If we reached the end of the enumeration, but not the end
2483 // of the number of requested items, we return S_FALSE.
2484 //
2485 if (count < celt)
2486 {
2487 return S_FALSE;
2488 }
2489
2490 return hr;
2491}
2492
2493
2494
2495HRESULT CordbEnumFilter::Init (ICorDebugModuleEnum * pModEnum, CordbAssembly *pAssembly)
2496{
2497 INTERNAL_API_ENTRY(GetProcess());
2498
2499 ICorDebugModule *pCorModule = NULL;
2500 CordbModule *pModule = NULL;
2501 ULONG ulDummy = 0;
2502
2503 HRESULT hr = pModEnum->Next(1, &pCorModule, &ulDummy);
2504
2505 //
2506 // Next returns E_FAIL if there is no next item, along with
2507 // the count being 0. Convert that to just being S_OK.
2508 //
2509 if ((hr == E_FAIL) && (ulDummy == 0))
2510 {
2511 hr = S_OK;
2512 }
2513
2514 if (FAILED (hr))
2515 return hr;
2516
2517 EnumElement *pPrevious = NULL;
2518 EnumElement *pElement = NULL;
2519
2520 while (ulDummy != 0)
2521 {
2522 pModule = (CordbModule *)(ICorDebugModule *)pCorModule;
2523 // Is this module part of the assembly for which we're enumerating?
2524 if (pModule->m_pAssembly == pAssembly)
2525 {
2526 pElement = new (nothrow) EnumElement;
2527 if (pElement == NULL)
2528 {
2529 // Out of memory. Clean up and bail out.
2530 hr = E_OUTOFMEMORY;
2531 goto Error;
2532 }
2533
2534 pElement->SetData ((void *)pCorModule);
2535 m_iCount++;
2536
2537 if (m_pFirst == NULL)
2538 {
2539 m_pFirst = pElement;
2540 }
2541 else
2542 {
2543 PREFIX_ASSUME(pPrevious != NULL);
2544 pPrevious->SetNext (pElement);
2545 }
2546 pPrevious = pElement;
2547 }
2548 else
2549 ((ICorDebugModule *)pModule)->Release();
2550
2551 hr = pModEnum->Next(1, &pCorModule, &ulDummy);
2552
2553 //
2554 // Next returns E_FAIL if there is no next item, along with
2555 // the count being 0. Convert that to just being S_OK.
2556 //
2557 if ((hr == E_FAIL) && (ulDummy == 0))
2558 {
2559 hr = S_OK;
2560 }
2561
2562 if (FAILED (hr))
2563 goto Error;
2564 }
2565
2566 m_pCurrent = m_pFirst;
2567
2568 return S_OK;
2569
2570Error:
2571 // release all the allocated memory before returning
2572 pElement = m_pFirst;
2573
2574 while (pElement != NULL)
2575 {
2576 pPrevious = pElement;
2577 pElement = pElement->GetNext();
2578
2579 ((ICorDebugModule *)pPrevious->GetData())->Release();
2580 delete pPrevious;
2581 }
2582
2583 return hr;
2584}
2585
2586HRESULT CordbEnumFilter::Init (ICorDebugThreadEnum *pThreadEnum, CordbAppDomain *pAppDomain)
2587{
2588 INTERNAL_API_ENTRY(GetProcess());
2589
2590 ICorDebugThread *pCorThread = NULL;
2591 CordbThread *pThread = NULL;
2592 ULONG ulDummy = 0;
2593
2594 HRESULT hr = pThreadEnum->Next(1, &pCorThread, &ulDummy);
2595
2596 //
2597 // Next returns E_FAIL if there is no next item, but we want to consider this
2598 // ok in this context.
2599 //
2600 if ((hr == E_FAIL) && (ulDummy == 0))
2601 {
2602 hr = S_OK;
2603 }
2604
2605 if (FAILED(hr))
2606 {
2607 return hr;
2608 }
2609
2610 EnumElement *pPrevious = NULL;
2611 EnumElement *pElement = NULL;
2612
2613 while (ulDummy > 0)
2614 {
2615 pThread = (CordbThread *)(ICorDebugThread *) pCorThread;
2616
2617 // Is this module part of the appdomain for which we're enumerating?
2618 // Note that this is rather inefficient (we call into the left side for every AppDomain),
2619 // but the whole idea of enumerating the threads of an AppDomain is pretty bad,
2620 // and we don't expect this to be used much if at all.
2621 CordbAppDomain* pThreadDomain;
2622 hr = pThread->GetCurrentAppDomain( &pThreadDomain );
2623 if( FAILED(hr) )
2624 {
2625 goto Error;
2626 }
2627
2628 if (pThreadDomain == pAppDomain)
2629 {
2630 pElement = new (nothrow) EnumElement;
2631 if (pElement == NULL)
2632 {
2633 // Out of memory. Clean up and bail out.
2634 hr = E_OUTOFMEMORY;
2635 goto Error;
2636 }
2637
2638 pElement->SetData ((void *)pCorThread);
2639 m_iCount++;
2640
2641 if (m_pFirst == NULL)
2642 {
2643 m_pFirst = pElement;
2644 }
2645 else
2646 {
2647 PREFIX_ASSUME(pPrevious != NULL);
2648 pPrevious->SetNext (pElement);
2649 }
2650
2651 pPrevious = pElement;
2652 }
2653 else
2654 {
2655 ((ICorDebugThread *)pThread)->Release();
2656 }
2657
2658 // get the next thread in the thread list
2659 hr = pThreadEnum->Next(1, &pCorThread, &ulDummy);
2660
2661 //
2662 // Next returns E_FAIL if there is no next item, along with
2663 // the count being 0. Convert that to just being S_OK.
2664 //
2665 if ((hr == E_FAIL) && (ulDummy == 0))
2666 {
2667 hr = S_OK;
2668 }
2669
2670 if (FAILED (hr))
2671 goto Error;
2672 }
2673
2674 m_pCurrent = m_pFirst;
2675
2676 return S_OK;
2677
2678Error:
2679 // release all the allocated memory before returning
2680 pElement = m_pFirst;
2681
2682 while (pElement != NULL)
2683 {
2684 pPrevious = pElement;
2685 pElement = pElement->GetNext();
2686
2687 ((ICorDebugThread *)pPrevious->GetData())->Release();
2688 delete pPrevious;
2689 }
2690
2691 return hr;
2692}
2693
2694