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: process.cpp
6//
7
8//
9//*****************************************************************************
10#include "stdafx.h"
11#include "primitives.h"
12#include "safewrap.h"
13
14#include "check.h"
15
16#ifndef SM_REMOTESESSION
17#define SM_REMOTESESSION 0x1000
18#endif
19
20#include "corpriv.h"
21#include "corexcep.h"
22#include "../../dlls/mscorrc/resource.h"
23#include <limits.h>
24
25#include <sstring.h>
26
27// @dbgtodo shim: process has some private hooks into the shim.
28#include "shimpriv.h"
29
30#include "metadataexports.h"
31#include "readonlydatatargetfacade.h"
32#include "metahost.h"
33
34// Keep this around for retail debugging. It's very very useful because
35// it's global state that we can always find, regardless of how many locals the compiler
36// optimizes away ;)
37struct RSDebuggingInfo;
38extern RSDebuggingInfo * g_pRSDebuggingInfo;
39
40//---------------------------------------------------------------------------------------
41//
42// OpenVirtualProcessImpl method called by the shim to get an ICorDebugProcess4 instance
43//
44// Arguments:
45// clrInstanceId - target pointer identifying which CLR in the Target to debug.
46// pDataTarget - data target abstraction.
47// hDacModule - the handle of the appropriate DAC dll for this runtime
48// riid - interface ID to query for.
49// ppProcessOut - new object for target, interface ID matches riid.
50// ppFlagsOut - currently only has 1 bit to indicate whether or not this runtime
51// instance will send a managed event after attach
52//
53// Return Value:
54// S_OK on success. Else failure
55//
56// Assumptions:
57//
58// Notes:
59// The outgoing process object can be cleaned up by calling Detach (which
60// will reset the Attach bit.)
61// @dbgtodo attach-bit: need to determine fate of attach bit.
62//
63//---------------------------------------------------------------------------------------
64STDAPI OpenVirtualProcessImpl(
65 ULONG64 clrInstanceId,
66 IUnknown * pDataTarget,
67 HMODULE hDacModule,
68 CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
69 REFIID riid,
70 IUnknown ** ppInstance,
71 CLR_DEBUGGING_PROCESS_FLAGS* pFlagsOut)
72{
73 HRESULT hr = S_OK;
74 RSExtSmartPtr<CordbProcess> pProcess;
75 PUBLIC_API_ENTRY(NULL);
76 EX_TRY
77 {
78
79 if ( (pDataTarget == NULL) || (clrInstanceId == 0) || (pMaxDebuggerSupportedVersion == NULL) ||
80 ((pFlagsOut == NULL) && (ppInstance == NULL))
81 )
82 {
83 ThrowHR(E_INVALIDARG);
84 }
85
86 // We consider the top 8 bits of the struct version to be the only part that represents
87 // a breaking change. This gives us some freedom in the future to have the debugger
88 // opt into getting more data.
89 const WORD kMajorMask = 0xff00;
90 const WORD kMaxStructMajor = 0;
91 if ((pMaxDebuggerSupportedVersion->wStructVersion & kMajorMask) > kMaxStructMajor)
92 {
93 // Don't know how to interpret the version structure
94 ThrowHR(CORDBG_E_UNSUPPORTED_VERSION_STRUCT);
95 }
96
97 // This process object is intended to be used for the V3 pipeline, and so
98 // much of the process from V2 is not being used. For example,
99 // - there is no ShimProcess object
100 // - there is no w32et thread (all threads are effectively an event thread)
101 // - the stop state is 'live', which corresponds to CordbProcess not knowing what
102 // its stop state really is (because that is now controlled by the shim).
103 ProcessDescriptor pd = ProcessDescriptor::CreateUninitialized();
104 IfFailThrow(CordbProcess::OpenVirtualProcess(
105 clrInstanceId,
106 pDataTarget, // takes a reference
107 hDacModule,
108 NULL, // Cordb
109 &pd, // 0 for V3 cases (pShim == NULL).
110 NULL, // no Shim in V3 cases
111 &pProcess));
112
113 // CordbProcess::OpenVirtualProcess already did the external addref to pProcess.
114 // Since pProcess is a smart ptr, it will external release in this function.
115 // Living reference will be the one from the QI.
116
117 // get the managed debug event pending flag
118 if(pFlagsOut != NULL)
119 {
120 hr = pProcess->GetAttachStateFlags(pFlagsOut);
121 if(FAILED(hr))
122 {
123 ThrowHR(hr);
124 }
125 }
126
127 //
128 // Check to make sure the debugger supports debugging this version
129 // Note that it's important that we still store the flags (above) in this case
130 //
131 if (!CordbProcess::IsCompatibleWith(pMaxDebuggerSupportedVersion->wMajor))
132 {
133 // Not compatible - don't keep the process instance, and return this specific error-code
134 ThrowHR(CORDBG_E_UNSUPPORTED_FORWARD_COMPAT);
135 }
136
137 //
138 // Now Query for the requested interface
139 //
140 if(ppInstance != NULL)
141 {
142 IfFailThrow(pProcess->QueryInterface(riid, reinterpret_cast<void**> (ppInstance)));
143 }
144
145 // if you have to add code here that could fail make sure ppInstance gets released and NULL'ed at exit
146 }
147 EX_CATCH_HRESULT(hr);
148
149 if((FAILED(hr) || ppInstance == NULL) && pProcess != NULL)
150 {
151 // The process has a strong reference to itself which is only released by neutering it.
152 // Since we aren't handing out the ref then we need to clean it up
153 _ASSERTE(ppInstance == NULL || *ppInstance == NULL);
154 pProcess->Neuter();
155 }
156 return hr;
157};
158
159//---------------------------------------------------------------------------------------
160//
161// OpenVirtualProcessImpl2 method called by the dbgshim to get an ICorDebugProcess4 instance
162//
163// Arguments:
164// clrInstanceId - target pointer identifying which CLR in the Target to debug.
165// pDataTarget - data target abstraction.
166// pDacModulePath - the module path of the appropriate DAC dll for this runtime
167// riid - interface ID to query for.
168// ppProcessOut - new object for target, interface ID matches riid.
169// ppFlagsOut - currently only has 1 bit to indicate whether or not this runtime
170// instance will send a managed event after attach
171//
172// Return Value:
173// S_OK on success. Else failure
174//---------------------------------------------------------------------------------------
175STDAPI OpenVirtualProcessImpl2(
176 ULONG64 clrInstanceId,
177 IUnknown * pDataTarget,
178 LPCWSTR pDacModulePath,
179 CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
180 REFIID riid,
181 IUnknown ** ppInstance,
182 CLR_DEBUGGING_PROCESS_FLAGS* pFlagsOut)
183{
184 HMODULE hDac = LoadLibraryW(pDacModulePath);
185 if (hDac == NULL)
186 {
187 return HRESULT_FROM_WIN32(GetLastError());
188 }
189 return OpenVirtualProcessImpl(clrInstanceId, pDataTarget, hDac, pMaxDebuggerSupportedVersion, riid, ppInstance, pFlagsOut);
190}
191
192//---------------------------------------------------------------------------------------
193// DEPRECATED - use OpenVirtualProcessImpl
194// OpenVirtualProcess method used by the shim in CLR v4 Beta1
195// We'd like a beta1 shim/VS to still be able to open dumps using a CLR v4 Beta2+ mscordbi.dll,
196// so we'll leave this in place (at least until after Beta2 is in wide use).
197//---------------------------------------------------------------------------------------
198STDAPI OpenVirtualProcess2(
199 ULONG64 clrInstanceId,
200 IUnknown * pDataTarget,
201 HMODULE hDacModule,
202 REFIID riid,
203 IUnknown ** ppInstance,
204 CLR_DEBUGGING_PROCESS_FLAGS* pFlagsOut)
205{
206 CLR_DEBUGGING_VERSION maxVersion = {0};
207 maxVersion.wMajor = 4;
208 return OpenVirtualProcessImpl(clrInstanceId, pDataTarget, hDacModule, &maxVersion, riid, ppInstance, pFlagsOut);
209}
210
211//---------------------------------------------------------------------------------------
212// DEPRECATED - use OpenVirtualProcessImpl
213// Public OpenVirtualProcess method to get an ICorDebugProcess4 instance
214// Used directly in CLR v4 pre Beta1 - can probably be safely removed now
215//---------------------------------------------------------------------------------------
216STDAPI OpenVirtualProcess(
217 ULONG64 clrInstanceId,
218 IUnknown * pDataTarget,
219 REFIID riid,
220 IUnknown ** ppInstance)
221{
222 return OpenVirtualProcess2(clrInstanceId, pDataTarget, NULL, riid, ppInstance, NULL);
223};
224
225//-----------------------------------------------------------------------------
226// Most Hresults to Unrecoverable error indicate an internal error
227// in the Right-Side.
228// However, a few are legal (eg, "could actually happen in a retail scenario and
229// not indicate an issue in mscorbi"). Track that here.
230//-----------------------------------------------------------------------------
231
232bool IsLegalFatalError(HRESULT hr)
233{
234 return
235 (hr == CORDBG_E_INCOMPATIBLE_PROTOCOL) ||
236 (hr == CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS) ||
237 (hr == CORDBG_E_UNCOMPATIBLE_PLATFORMS) ||
238 (hr == CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS) ||
239 // This should only happen in the case of a security attack on us.
240 (hr == E_ACCESSDENIED) ||
241 (hr == E_FAIL);
242}
243
244//-----------------------------------------------------------------------------
245// Safe wait. Use this anytime we're waiting on:
246// - an event signaled by the helper thread.
247// - something signaled by a thread that holds the process lock.
248// Note that we must preserve GetLastError() semantics.
249//-----------------------------------------------------------------------------
250inline DWORD SafeWaitForSingleObject(CordbProcess * p, HANDLE h, DWORD dwTimeout)
251{
252 // Can't hold process lock while blocking
253 _ASSERTE(!p->ThreadHoldsProcessLock());
254
255 return ::WaitForSingleObject(h, dwTimeout);
256}
257
258#define CORDB_WAIT_TIMEOUT 360000 // milliseconds
259
260//---------------------------------------------------------------------------------------
261//
262// Get the timeout value used in waits.
263//
264// Return Value:
265// Number of milliseconds to waite or possible INFINITE (-1).
266//
267//
268// Notes:
269// Uses registry values for fine tuning.
270//
271
272// static
273static inline DWORD CordbGetWaitTimeout()
274{
275#ifdef _DEBUG
276 // 0 = Wait forever
277 // 1 = Wait for CORDB_WAIT_TIMEOUT
278 // n = Wait for n milliseconds
279 static ConfigDWORD cordbWaitTimeout;
280 DWORD dwTimeoutVal = cordbWaitTimeout.val(CLRConfig::INTERNAL_DbgWaitTimeout);
281 if (dwTimeoutVal == 0)
282 return DWORD(-1);
283 else if (dwTimeoutVal != 1)
284 return dwTimeoutVal;
285 else
286#endif
287 {
288 return CORDB_WAIT_TIMEOUT;
289 }
290}
291
292//----------------------------------------------------------------------------
293// Implementation of IDacDbiInterface::IMetaDataLookup.
294// lookup Internal Metadata Importer keyed by PEFile
295// isILMetaDataForNGENImage is true iff the IMDInternalImport returned represents a pointer to
296// metadata from an IL image when the module was an ngen'ed image.
297IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &isILMetaDataForNGENImage)
298{
299 INTERNAL_DAC_CALLBACK(this);
300
301 HASHFIND hashFindAppDomain;
302 HASHFIND hashFindModule;
303 IMDInternalImport * pMDII = NULL;
304 isILMetaDataForNGENImage = false;
305
306 // Check to see if one of the cached modules has the metadata we need
307 // If not we will do a more exhaustive search below
308 for (CordbAppDomain * pAppDomain = m_appDomains.FindFirst(&hashFindAppDomain);
309 pAppDomain != NULL;
310 pAppDomain = m_appDomains.FindNext(&hashFindAppDomain))
311 {
312 for (CordbModule * pModule = pAppDomain->m_modules.FindFirst(&hashFindModule);
313 pModule != NULL;
314 pModule = pAppDomain->m_modules.FindNext(&hashFindModule))
315 {
316 if (pModule->GetPEFile() == vmPEFile)
317 {
318 pMDII = NULL;
319 ALLOW_DATATARGET_MISSING_MEMORY(
320 pMDII = pModule->GetInternalMD();
321 );
322 if(pMDII != NULL)
323 return pMDII;
324 }
325 }
326 }
327
328 // Cache didn't have it... time to search harder
329 PrepopulateAppDomainsOrThrow();
330
331 // There may be perf issues here. The DAC may make a lot of metadata requests, and so
332 // this may be an area for potential perf optimizations if we find things running slow.
333
334 // enumerate through all Modules
335 for (CordbAppDomain * pAppDomain = m_appDomains.FindFirst(&hashFindAppDomain);
336 pAppDomain != NULL;
337 pAppDomain = m_appDomains.FindNext(&hashFindAppDomain))
338 {
339 pAppDomain->PrepopulateModules();
340
341 for (CordbModule * pModule = pAppDomain->m_modules.FindFirst(&hashFindModule);
342 pModule != NULL;
343 pModule = pAppDomain->m_modules.FindNext(&hashFindModule))
344 {
345 if (pModule->GetPEFile() == vmPEFile)
346 {
347 pMDII = NULL;
348 ALLOW_DATATARGET_MISSING_MEMORY(
349 pMDII = pModule->GetInternalMD();
350 );
351
352 if ( pMDII == NULL)
353 {
354 // If we couldn't get metadata from the CordbModule, then we need to ask the
355 // debugger if it can find the metadata elsewhere.
356 // If this was live debugging, we should have just gotten the memory contents.
357 // Thus this code is for dump debugging, when you don't have the metadata in the dump.
358 pMDII = LookupMetaDataFromDebugger(vmPEFile, isILMetaDataForNGENImage, pModule);
359 }
360 return pMDII;
361 }
362 }
363 }
364
365 return NULL;
366}
367
368
369IMDInternalImport * CordbProcess::LookupMetaDataFromDebugger(
370 VMPTR_PEFile vmPEFile,
371 bool &isILMetaDataForNGENImage,
372 CordbModule * pModule)
373{
374 DWORD dwImageTimeStamp = 0;
375 DWORD dwImageSize = 0;
376 bool isNGEN = false;
377 StringCopyHolder filePath;
378 IMDInternalImport * pMDII = NULL;
379
380 // First, see if the debugger can locate the exact metadata we want.
381 if (this->GetDAC()->GetMetaDataFileInfoFromPEFile(vmPEFile, dwImageTimeStamp, dwImageSize, isNGEN, &filePath))
382 {
383 _ASSERTE(filePath.IsSet());
384
385 // Since we track modules by their IL images, that presents a little bit of oddness here. The correct
386 // thing to do is preferentially load the NI content.
387 // We don't discriminate between timestamps & sizes becuase CLRv4 deterministic NGEN guarantees that the
388 // IL image and NGEN image have the same timestamp and size. Should that guarantee change, this code
389 // will be horribly broken.
390
391 // If we happen to have an NI file path, use it instead.
392 const WCHAR * pwszFilePath = pModule->GetNGenImagePath();
393 if (pwszFilePath)
394 {
395 // Force the issue, regardless of the older codepath's opinion.
396 isNGEN = true;
397 }
398 else
399 {
400 pwszFilePath = (WCHAR *)filePath;
401 }
402
403 ALLOW_DATATARGET_MISSING_MEMORY(
404 pMDII = LookupMetaDataFromDebuggerForSingleFile(pModule, pwszFilePath, dwImageTimeStamp, dwImageSize);
405 );
406
407 // If it's an ngen'ed image and the debugger couldn't find it, we can use the metadata from
408 // the corresponding IL image if the debugger can locate it.
409 filePath.Clear();
410 if ((pMDII == NULL) &&
411 (isNGEN) &&
412 (this->GetDAC()->GetILImageInfoFromNgenPEFile(vmPEFile, dwImageTimeStamp, dwImageSize, &filePath)))
413 {
414 _ASSERTE(filePath.IsSet());
415
416 WCHAR *mutableFilePath = (WCHAR *)filePath;
417
418#if defined(FEATURE_CORESYSTEM)
419 size_t pathLen = wcslen(mutableFilePath);
420
421 const wchar_t *nidll = W(".ni.dll");
422 const wchar_t *niexe = W(".ni.exe");
423 const size_t dllLen = wcslen(nidll); // used for ni.exe as well
424
425 const wchar_t *niwinmd = W(".ni.winmd");
426 const size_t winmdLen = wcslen(niwinmd);
427
428 if (pathLen > dllLen && _wcsicmp(mutableFilePath+pathLen-dllLen, nidll) == 0)
429 {
430 wcscpy_s(mutableFilePath+pathLen-dllLen, dllLen, W(".dll"));
431 }
432 else if (pathLen > dllLen && _wcsicmp(mutableFilePath+pathLen-dllLen, niexe) == 0)
433 {
434 wcscpy_s(mutableFilePath+pathLen-dllLen, dllLen, W(".exe"));
435 }
436 else if (pathLen > winmdLen && _wcsicmp(mutableFilePath+pathLen-winmdLen, niwinmd) == 0)
437 {
438 wcscpy_s(mutableFilePath+pathLen-winmdLen, winmdLen, W(".winmd"));
439 }
440#endif//FEATURE_CORESYSTEM
441
442 ALLOW_DATATARGET_MISSING_MEMORY(
443 pMDII = LookupMetaDataFromDebuggerForSingleFile(pModule, mutableFilePath, dwImageTimeStamp, dwImageSize);
444 );
445
446 if (pMDII != NULL)
447 {
448 isILMetaDataForNGENImage = true;
449 }
450 }
451 }
452 return pMDII;
453}
454
455// We do not know if the image being sent to us is an IL image or ngen image.
456// CordbProcess::LookupMetaDataFromDebugger() has this knowledge when it looks up the file to hand off
457// to this function.
458// DacDbiInterfaceImpl::GetMDImport() has this knowledge in the isNGEN flag.
459// The CLR v2 code that windbg used made a distinction whether the metadata came from
460// the exact binary or not (i.e. were we getting metadata from the IL image and using
461// it against the ngen image?) but that information was never used and so not brought forward.
462// It would probably be more interesting generally to track whether the debugger gives us back
463// a file that bears some relationship to the file we asked for, which would catch the NI/IL case
464// as well.
465IMDInternalImport * CordbProcess::LookupMetaDataFromDebuggerForSingleFile(
466 CordbModule * pModule,
467 LPCWSTR pwszFilePath,
468 DWORD dwTimeStamp,
469 DWORD dwSize)
470{
471 INTERNAL_DAC_CALLBACK(this);
472
473 ULONG32 cchLocalImagePath = MAX_LONGPATH;
474 ULONG32 cchLocalImagePathRequired;
475 NewArrayHolder<WCHAR> pwszLocalFilePath = NULL;
476 IMDInternalImport * pMDII = NULL;
477
478 const HRESULT E_NSF_BUFFER = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
479 HRESULT hr = E_NSF_BUFFER;
480 for(unsigned i=0; i<2 && hr == E_NSF_BUFFER; i++)
481 {
482 if (pwszLocalFilePath != NULL)
483 pwszLocalFilePath.Release();
484
485 if (NULL == (pwszLocalFilePath = new (nothrow) WCHAR[cchLocalImagePath+1]))
486 ThrowHR(E_OUTOFMEMORY);
487
488 cchLocalImagePathRequired = 0;
489
490 hr = m_pMetaDataLocator->GetMetaData(pwszFilePath,
491 dwTimeStamp,
492 dwSize,
493 cchLocalImagePath,
494 &cchLocalImagePathRequired,
495 pwszLocalFilePath);
496
497 pwszLocalFilePath[cchLocalImagePath] = W('\0');
498 cchLocalImagePath = cchLocalImagePathRequired;
499 }
500
501 if (SUCCEEDED(hr))
502 {
503 hr = pModule->InitPublicMetaDataFromFile(pwszLocalFilePath, ofReadOnly, false);
504 if (SUCCEEDED(hr))
505 {
506 // While we're successfully returning a metadata reader, remember that there's
507 // absolutely no guarantee this metadata is an exact match for the vmPEFile.
508 // The debugger could literally send us back a path to any managed file with
509 // metadata content that is readable and we'll 'succeed'.
510 // For now, this is by-design. A debugger should be allowed to decide if it wants
511 // to take a risk by returning 'mostly matching' metadata to see if debugging is
512 // possible in the absence of a true match.
513 pMDII = pModule->GetInternalMD();
514 }
515 }
516
517 return pMDII;
518}
519
520
521//---------------------------------------------------------------------------------------
522//
523// Implement IDacDbiInterface::IAllocator::Alloc
524// Expected to throws on error.
525//
526// Arguments:
527// lenBytes - size of the byte array to allocate
528//
529// Return Value:
530// Return the newly allocated byte array, or throw on OOM
531//
532// Notes:
533// Since this function is a callback from DAC, it must not take the process lock.
534// If it does, we may deadlock between the DD lock and the process lock.
535// If we really need to take the process lock for whatever reason, we must take it in the DBI functions
536// which call the DAC API that ends up calling this function.
537// See code:InternalDacCallbackHolder for more information.
538//
539
540void * CordbProcess::Alloc(SIZE_T lenBytes)
541{
542 return new BYTE[lenBytes]; // throws
543}
544
545//---------------------------------------------------------------------------------------
546//
547// Implements IDacDbiInterface::IAllocator::Free
548//
549// Arguments:
550// p - pointer to the memory to be released
551//
552// Notes:
553// Since this function is a callback from DAC, it must not take the process lock.
554// If it does, we may deadlock between the DD lock and the process lock.
555// If we really need to take the process lock for whatever reason, we must take it in the DBI functions
556// which call the DAC API that ends up calling this function.
557// See code:InternalDacCallbackHolder for more information.
558//
559
560void CordbProcess::Free(void * p)
561{
562 // This shouldn't throw.
563 delete [] ((BYTE *) p);
564}
565
566
567//---------------------------------------------------------------------------------------
568//
569// #DBIVersionChecking
570//
571// There are a few checks we need to do to make sure we are using the matching DBI and DAC for a particular
572// version of the runtime.
573//
574// 1. Runtime vs. DBI
575// - Desktop
576// This is done by making sure that the CorDebugInterfaceVersion passed to code:CreateCordbObject is
577// compatible with the version of the DBI.
578//
579// - Windows CoreCLR
580// This is done by dbgshim.dll. It checks whether the runtime DLL and the DBI DLL have the same
581// product version. See CreateDebuggingInterfaceForVersion() in dbgshim.cpp.
582//
583// - Remote transport (Mac CoreCLR + CoreSystem CoreCLR)
584// Since there is no dbgshim.dll for a remote CoreCLR, we have to do this check in some other place.
585// We do this in code:CordbProcess::CreateDacDbiInterface, by calling
586// code:DacDbiInterfaceImpl::CheckDbiVersion right after we have created the DDMarshal.
587// The IDacDbiInterface implementation on remote device checks the product version of the device
588// coreclr by:
589// mac - looking at the Info.plist file in the CoreCLR bundle.
590// CoreSystem - this check is skipped at the moment, but should be implemented if we release it
591//
592// The one twist here is that the DBI needs to communicate with the IDacDbiInterface
593// implementation on the device BEFORE it can verify the product versions. This means that we need to
594// have one IDacDbiInterface API which is consistent across all versions of the IDacDbiInterface.
595// This puts two constraints on CheckDbiVersion():
596//
597// 1. It has to be the first API on the IDacDbiInterface.
598// - Otherwise, a wrong version of the DBI may end up calling a different API on the
599// IDacDbiInterface and getting random results. (Really what matters is that it is
600// protocol message id 0, at present the source code position implies the message id)
601//
602// 2. Its parameters cannot change.
603// - Otherwise, we may run into random errors when we marshal/unmarshal the arguments for the
604// call to CheckDbiVersion(). Debugging will still fail, but we won't get the
605// version mismatch error. (Again, the protocol is what ultimately matters)
606// - To mitigate the impact of this constraint, we use the code:DbiVersion structure.
607// In addition to the DBI version, it also contains a format number (in case we decide to
608// check something else in the future), a breaking change number so that we can force
609// breaking changes between a DBI and a DAC, and space reserved for future use.
610//
611// 2. DBI vs. DAC
612// - Desktop and Windows CoreCLR (old architecture)
613// No verification is done. There is a transitive implication that if DBI matches runtime and DAC matches
614// runtime then DBI matches DAC. Technically because the DBI only matches runtime on major version number
615// runtime and DAC could be from different builds. However because we service all three binaries together
616// and DBI always loads the DAC that is sitting in the same directory DAC and DBI generally get tight
617// version coupling. A user with admin privleges could put different builds together and no version check
618// would ever fail though.
619//
620// - Desktop and Windows CoreCLR (new architecture)
621// No verification is done. Similar to above its implied that if DBI matches runtime and runtime matches
622// DAC then DBI matches DAC. The only difference is that here both the DBI and DAC are provided by the
623// debugger. We provide timestamp and filesize for both binaries which are relatively strongly bound hints,
624// but there is no enforcement on the returned binaries beyond the runtime compat checking.
625//
626// - Remote transport (Mac CoreCLR and CoreSystem CoreCLR)
627// Because the transport exists between DBI and DAC it becomes much more important to do a versioning check
628//
629// Mac - currently does a tightly bound version check between DBI and the runtime (CheckDbiVersion() above),
630// which transitively gives a tightly bound check to DAC. In same function there is also a check that is
631// logically a DAC DBI protocol check, verifying that the m_dwProtocolBreakingChangeCounter of DbiVersion
632// matches. However this check should be weaker than the build version check and doesn't add anything here.
633//
634// CoreSystem - currently skips the tightly bound version check to make internal deployment and usage easier.
635// We want to use old desktop side debugger components to target newer CoreCLR builds, only forcing a desktop
636// upgrade when the protocol actually does change. To do this we use two checks:
637// 1. The breaking change counter in CheckDbiVersion() whenever a dev knows they are breaking back
638// compat and wants to be explicit about it. This is the same as mac above.
639// 2. During the auto-generation of the DDMarshal classes we take an MD5 hash of IDacDbiInterface source
640// code and embed it in two DDMarshal functions, one which runs locally and one that runs remotely.
641// If both DBI and DAC were built from the same source then the local and remote hashes will match. If the
642// hashes don't match then we assume there has been a been a breaking change in the protocol. Note
643// this hash could have both false-positives and false-negatives. False positives could occur when
644// IDacDbiInterface is changed in a trivial way, such as changing a comment. False negatives could
645// occur when the semantics of the protocol are changed even though the interface is not. Another
646// case would be changing the DDMarshal proxy generation code. In addition to the hashes we also
647// embed timestamps when the auto-generated code was produced. However this isn't used for version
648// matching, only as a hint to indicate which of two mismatched versions is newer.
649//
650//
651// 3. Runtime vs. DAC
652// - Desktop, Windows CoreCLR, CoreSystem CoreCLR
653// In both cases we check this by matching the timestamp in the debug directory of the runtime image
654// and the timestamp we store in the DAC table when we generate the DAC dll. This is done in
655// code:ClrDataAccess::VerifyDlls.
656//
657// - Mac CoreCLR
658// On Mac, we don't have a timestamp in the runtime image. Instead, we rely on checking the 16-byte
659// UUID in the image. This UUID is used to check whether a symbol file matches the image, so
660// conceptually it's the same as the timestamp we use on Windows. This is also done in
661// code:ClrDataAccess::VerifyDlls.
662//
663//---------------------------------------------------------------------------------------
664//
665// Instantiates a DacDbi Interface object in a live-debugging scenario that matches
666// the current instance of mscorwks in this process.
667//
668// Return Value:
669// Returns on success. Else throws.
670//
671// Assumptions:
672// Client will code:CordbProcess::FreeDac when its done with the DacDbi interface.
673// Caller has initialized clrInstanceId.
674//
675// Notes:
676// This looks for the DAC next to this current DBI. This assumes that Dac and Dbi are both on
677// the local file system. That assumption will break in zero-copy deployment scenarios.
678//
679//---------------------------------------------------------------------------------------
680void
681CordbProcess::CreateDacDbiInterface()
682{
683 _ASSERTE(m_pDACDataTarget != NULL);
684 _ASSERTE(m_pDacPrimitives == NULL); // don't double-init
685
686 // Caller has already determined which CLR in the target is being debugged.
687 _ASSERTE(m_clrInstanceId != 0);
688
689 m_pDacPrimitives = NULL;
690
691 HRESULT hrStatus = S_OK;
692
693 // Non-marshalling path for live local dac.
694 // in the new arch we can get the module from OpenVirtualProcess2 but in the shim case
695 // and the deprecated OpenVirtualProcess case we must assume it comes from DAC in the
696 // same directory as DBI
697 if(m_hDacModule == NULL)
698 {
699 m_hDacModule.Assign(ShimProcess::GetDacModule());
700 }
701
702 //
703 // Get the access interface, passing our callback interfaces (data target, allocator and metadata lookup)
704 //
705
706 IDacDbiInterface::IAllocator * pAllocator = this;
707 IDacDbiInterface::IMetaDataLookup * pMetaDataLookup = this;
708
709
710 typedef HRESULT (STDAPICALLTYPE * PFN_DacDbiInterfaceInstance)(
711 ICorDebugDataTarget *,
712 CORDB_ADDRESS,
713 IDacDbiInterface::IAllocator *,
714 IDacDbiInterface::IMetaDataLookup *,
715 IDacDbiInterface **);
716
717 IDacDbiInterface* pInterfacePtr = NULL;
718 PFN_DacDbiInterfaceInstance pfnEntry = (PFN_DacDbiInterfaceInstance)GetProcAddress(m_hDacModule, "DacDbiInterfaceInstance");
719 if (!pfnEntry)
720 {
721 ThrowLastError();
722 }
723
724 hrStatus = pfnEntry(m_pDACDataTarget, m_clrInstanceId, pAllocator, pMetaDataLookup, &pInterfacePtr);
725 IfFailThrow(hrStatus);
726
727 // We now have a resource, pInterfacePtr, that needs to be freed.
728 m_pDacPrimitives = pInterfacePtr;
729
730 // Setup DAC target consistency checking based on what we're using for DBI
731 m_pDacPrimitives->DacSetTargetConsistencyChecks( m_fAssertOnTargetInconsistency );
732}
733
734//---------------------------------------------------------------------------------------
735//
736// Is the DAC/DBI interface initialized?
737//
738// Return Value:
739// TRUE iff init.
740//
741// Notes:
742// The RS will try to initialize DD as soon as it detects the runtime as loaded.
743// If the DD interface has not initialized, then it very likely the runtime has not
744// been loaded into the target.
745//
746BOOL CordbProcess::IsDacInitialized()
747{
748 return m_pDacPrimitives != NULL;
749}
750
751//---------------------------------------------------------------------------------------
752//
753// Get the DAC interface.
754//
755// Return Value:
756// the Dac/Dbi interface pointer to the process.
757// Never returns NULL.
758//
759// Assumptions:
760// Caller is responsible for ensuring Data-Target is safe to access (eg, not
761// currently running).
762// Caller is responsible for ensuring DAC-cache is flushed. Call code:CordbProcess::ForceDacFlush
763// as needed.
764//
765//---------------------------------------------------------------------------------------
766IDacDbiInterface * CordbProcess::GetDAC()
767{
768 // Since the DD primitives may throw, easiest way to model that is to make this throw.
769 CONTRACTL
770 {
771 THROWS;
772 }
773 CONTRACTL_END;
774
775 // We should always have the DAC/DBI interface.
776 _ASSERTE(m_pDacPrimitives != NULL);
777 return m_pDacPrimitives;
778}
779
780//---------------------------------------------------------------------------------------
781// Get the Data-Target
782//
783// Returns:
784// pointer to the data-target. Should be non-null.
785// Lifetime of the pointer is until this process object is neutered.
786//
787ICorDebugDataTarget * CordbProcess::GetDataTarget()
788{
789 return m_pDACDataTarget;
790}
791
792//---------------------------------------------------------------------------------------
793// Create a CordbProcess object around an existing OS process.
794//
795// Arguments:
796// pDataTarget - abstracts access to the debuggee.
797// clrInstanceId - identifies the CLR instance within the debuggee. (This is the
798// base address of mscorwks)
799// pCordb - Pointer to the implementation of the owning Cordb object implementing the
800// owning ICD interface.
801// This should go away - we can get the functionality from the pShim.
802// If this is null, then pShim must be null too.
803// processID - OS process ID of target process. 0 if pShim == NULL.
804// pShim - shim counter part object. This allows hooks back for v2 compat. This will
805// go away once we no longer support V2 backwards compat.
806// This must be non-null for any V2 paths (including non-DAC-ized code).
807// If this is null, then we're in a V3 path.
808// ppProcess - out parameter for new process object. This gets addreffed.
809//
810// Return Value:
811// S_OK on success, and *ppProcess set to newly created debuggee object. Else error.
812//
813// Notes:
814// @dbgtodo - , shim: Cordb, and pShim will all eventually go away.
815//
816//---------------------------------------------------------------------------------------
817
818// static
819HRESULT CordbProcess::OpenVirtualProcess(
820 ULONG64 clrInstanceId,
821 IUnknown * pDataTarget,
822 HMODULE hDacModule,
823 Cordb* pCordb,
824 const ProcessDescriptor * pProcessDescriptor,
825 ShimProcess * pShim,
826 CordbProcess ** ppProcess)
827{
828 _ASSERTE(pDataTarget != NULL);
829
830 // In DEBUG builds, verify that we do actually have an ICorDebugDataTarget (i.e. that
831 // someone hasn't messed up the COM interop marshalling, etc.).
832#ifdef _DEBUG
833 {
834 IUnknown * pTempDt;
835 HRESULT hrQi = pDataTarget->QueryInterface(IID_ICorDebugDataTarget, (void**)&pTempDt);
836 _ASSERTE_MSG(SUCCEEDED(hrQi), "OpenVirtualProcess was passed something that isn't actually an ICorDebugDataTarget");
837 pTempDt->Release();
838 }
839#endif
840
841 // If we're emulating V2, then both pCordb and pShim are non-NULL.
842 // If we're doing a real V3 path, then they're both NULL.
843 // Either way, they should have the same null-status.
844 _ASSERTE((pCordb == NULL) == (pShim == NULL));
845
846 // If we're doing real V3, then we must have a real instance ID
847 _ASSERTE(!((pShim == NULL) && (clrInstanceId == 0)));
848
849 *ppProcess = NULL;
850
851 HRESULT hr = S_OK;
852 RSUnsafeExternalSmartPtr<CordbProcess> pProcess;
853 pProcess.Assign(new (nothrow) CordbProcess(clrInstanceId, pDataTarget, hDacModule, pCordb, pProcessDescriptor, pShim));
854
855 if (pProcess == NULL)
856 {
857 return E_OUTOFMEMORY;
858 }
859
860 ICorDebugProcess * pThis = pProcess;
861 (void)pThis; //prevent "unused variable" error from GCC
862
863 // CordbProcess::Init may need shim hooks, so connect Shim now.
864 // This will bump reference count.
865 if (pShim != NULL)
866 {
867 pShim->SetProcess(pProcess);
868
869 _ASSERTE(pShim->GetProcess() == pThis);
870 _ASSERTE(pShim->GetWin32EventThread() != NULL);
871 }
872
873 hr = pProcess->Init();
874
875 if (SUCCEEDED(hr))
876 {
877 *ppProcess = pProcess;
878 pProcess->ExternalAddRef();
879 }
880 else
881 {
882 // handle failure path
883 pProcess->CleanupHalfBakedLeftSide();
884
885 if (pShim != NULL)
886 {
887 // Shim still needs to be disposed to clean up other resources.
888 pShim->SetProcess(NULL);
889 }
890
891 // In failure case, pProcess's dtor will do the final release.
892 }
893
894
895 return hr;
896}
897
898//---------------------------------------------------------------------------------------
899// CordbProcess constructor
900//
901// Arguments:
902// pDataTarget - Pointer to an implementation of ICorDebugDataTarget
903// (or ICorDebugMutableDataTarget), which virtualizes access to the process.
904// clrInstanceId - representation of the CLR to debug in the process. Must be specified
905// (non-zero) if pShim is NULL. If 0, use the first CLR that we see.
906// pCordb - Pointer to the implementation of the owning Cordb object implementing the
907// owning ICD interface.
908// pW32 - Pointer to the Win32 event thread to use when processing events for this
909// process.
910// dwProcessID - For V3, 0.
911// Else for shim codepaths, the processID of the process this object will represent.
912// pShim - Pointer to the shim for handling V2 debuggers on the V3 architecture.
913//
914//---------------------------------------------------------------------------------------
915
916CordbProcess::CordbProcess(ULONG64 clrInstanceId,
917 IUnknown * pDataTarget,
918 HMODULE hDacModule,
919 Cordb * pCordb,
920 const ProcessDescriptor * pProcessDescriptor,
921 ShimProcess * pShim)
922 : CordbBase(NULL, pProcessDescriptor->m_Pid, enumCordbProcess),
923 m_fDoDelayedManagedAttached(false),
924 m_cordb(pCordb),
925 m_handle(NULL),
926 m_processDescriptor(*pProcessDescriptor),
927 m_detached(false),
928 m_uninitializedStop(false),
929 m_exiting(false),
930 m_terminated(false),
931 m_unrecoverableError(false),
932 m_specialDeferment(false),
933 m_helperThreadDead(false),
934 m_loaderBPReceived(false),
935 m_cOutstandingEvals(0),
936 m_cOutstandingHandles(0),
937 m_clrInstanceId(clrInstanceId),
938 m_stopCount(0),
939 m_synchronized(false),
940 m_syncCompleteReceived(false),
941 m_pShim(pShim),
942 m_userThreads(11),
943 m_oddSync(false),
944#ifdef FEATURE_INTEROP_DEBUGGING
945 m_unmanagedThreads(11),
946#endif
947 m_appDomains(11),
948 m_sharedAppDomain(0),
949 m_steppers(11),
950 m_continueCounter(1),
951 m_flushCounter(0),
952 m_leftSideEventAvailable(NULL),
953 m_leftSideEventRead(NULL),
954#if defined(FEATURE_INTEROP_DEBUGGING)
955 m_leftSideUnmanagedWaitEvent(NULL),
956#endif // FEATURE_INTEROP_DEBUGGING
957 m_initialized(false),
958 m_stopRequested(false),
959 m_stopWaitEvent(NULL),
960#ifdef FEATURE_INTEROP_DEBUGGING
961 m_cFirstChanceHijackedThreads(0),
962 m_unmanagedEventQueue(NULL),
963 m_lastQueuedUnmanagedEvent(NULL),
964 m_lastQueuedOOBEvent(NULL),
965 m_outOfBandEventQueue(NULL),
966 m_lastDispatchedIBEvent(NULL),
967 m_dispatchingUnmanagedEvent(false),
968 m_dispatchingOOBEvent(false),
969 m_doRealContinueAfterOOBBlock(false),
970 m_state(0),
971#endif // FEATURE_INTEROP_DEBUGGING
972 m_helperThreadId(0),
973 m_pPatchTable(NULL),
974 m_cPatch(0),
975 m_rgData(NULL),
976 m_rgNextPatch(NULL),
977 m_rgUncommitedOpcode(NULL),
978 m_minPatchAddr(MAX_ADDRESS),
979 m_maxPatchAddr(MIN_ADDRESS),
980 m_iFirstPatch(0),
981 m_hHelperThread(NULL),
982 m_dispatchedEvent(DB_IPCE_DEBUGGER_INVALID),
983 m_pDefaultAppDomain(NULL),
984 m_hDacModule(hDacModule),
985 m_pDacPrimitives(NULL),
986 m_pEventChannel(NULL),
987 m_fAssertOnTargetInconsistency(false),
988 m_runtimeOffsetsInitialized(false),
989 m_writableMetadataUpdateMode(LegacyCompatPolicy)
990{
991 _ASSERTE((m_id == 0) == (pShim == NULL));
992
993 HRESULT hr = pDataTarget->QueryInterface(IID_ICorDebugDataTarget, reinterpret_cast<void **>(&m_pDACDataTarget));
994 IfFailThrow(hr);
995
996#ifdef FEATURE_INTEROP_DEBUGGING
997 m_DbgSupport.m_DebugEventQueueIdx = 0;
998 m_DbgSupport.m_TotalNativeEvents = 0;
999 m_DbgSupport.m_TotalIB = 0;
1000 m_DbgSupport.m_TotalOOB = 0;
1001 m_DbgSupport.m_TotalCLR = 0;
1002#endif // FEATURE_INTEROP_DEBUGGING
1003
1004 g_pRSDebuggingInfo->m_MRUprocess = this;
1005
1006 // This is a strong reference to ourselves.
1007 // This is cleared in code:CordbProcess::Neuter
1008 m_pProcess.Assign(this);
1009
1010#ifdef _DEBUG
1011 // On Debug builds, we'll ASSERT by default whenever the target appears to be corrupt or
1012 // otherwise inconsistent (both in DAC and DBI). But we also need the ability to
1013 // explicitly test corrupt targets.
1014 // Tests should set COMPlus_DbgIgnoreInconsistentTarget=1 to suppress these asserts
1015 // Note that this controls two things:
1016 // 1) DAC behavior - see code:IDacDbiInterface::DacSetTargetConsistencyChecks
1017 // 2) RS-only consistency asserts - see code:CordbProcess::TargetConsistencyCheck
1018 if( !CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgDisableTargetConsistencyAsserts) )
1019 {
1020 m_fAssertOnTargetInconsistency = true;
1021 }
1022#endif
1023}
1024
1025/*
1026 A list of which resources owned by this object are accounted for.
1027
1028 UNKNOWN
1029 Cordb* m_cordb;
1030 CordbHashTable m_unmanagedThreads; // Released in CordbProcess but not removed from hash
1031 DebuggerIPCEvent* m_lastQueuedEvent;
1032
1033 // CordbUnmannagedEvent is a struct which is not derrived from CordbBase.
1034 // It contains a CordbUnmannagedThread which may need to be released.
1035 CordbUnmanagedEvent *m_unmanagedEventQueue;
1036 CordbUnmanagedEvent *m_lastQueuedUnmanagedEvent;
1037 CordbUnmanagedEvent *m_outOfBandEventQueue;
1038 CordbUnmanagedEvent *m_lastQueuedOOBEvent;
1039
1040 BYTE* m_pPatchTable;
1041 BYTE *m_rgData;
1042 void *m_pbRemoteBuf;
1043
1044 RESOLVED
1045 // Nutered
1046 CordbHashTable m_userThreads;
1047 CordbHashTable m_appDomains;
1048
1049 // Cleaned up in ExitProcess
1050 DebuggerIPCEvent* m_queuedEventList;
1051
1052 CordbHashTable m_steppers; // Closed in ~CordbProcess
1053
1054 // Closed in CloseIPCEventHandles called from ~CordbProcess
1055 HANDLE m_leftSideEventAvailable;
1056 HANDLE m_leftSideEventRead;
1057
1058 // Closed in ~CordbProcess
1059 HANDLE m_handle;
1060 HANDLE m_leftSideUnmanagedWaitEvent;
1061 HANDLE m_stopWaitEvent;
1062
1063 // Deleted in ~CordbProcess
1064 CRITICAL_SECTION m_processMutex;
1065
1066*/
1067
1068
1069CordbProcess::~CordbProcess()
1070{
1071 LOG((LF_CORDB, LL_INFO1000, "CP::~CP: deleting process 0x%08x\n", this));
1072
1073 DTOR_ENTRY(this);
1074
1075 _ASSERTE(IsNeutered());
1076
1077 _ASSERTE(m_cordb == NULL);
1078
1079 // We shouldn't still be in Cordb's list of processes. Unfortunately, our root Cordb object
1080 // may have already been deleted b/c we're at the mercy of ref-counting, so we can't check.
1081
1082 _ASSERTE(m_sharedAppDomain == NULL);
1083
1084 m_processMutex.Destroy();
1085 m_StopGoLock.Destroy();
1086
1087 // These handles were cleared in neuter
1088 _ASSERTE(m_handle == NULL);
1089#if defined(FEATURE_INTEROP_DEBUGGING)
1090 _ASSERTE(m_leftSideUnmanagedWaitEvent == NULL);
1091#endif // FEATURE_INTEROP_DEBUGGING
1092 _ASSERTE(m_stopWaitEvent == NULL);
1093
1094 // Set this to mark that we really did cleanup.
1095}
1096
1097//-----------------------------------------------------------------------------
1098// Static build helper.
1099// This will create a process under the pCordb root, and add it to the list.
1100// We don't return the process - caller gets the pid and looks it up under
1101// the Cordb object.
1102//
1103// Arguments:
1104// pCordb - Pointer to the implementation of the owning Cordb object implementing the
1105// owning ICD interface.
1106// szProgramName - Name of the program to execute.
1107// szProgramArgs - Command line arguments for the process.
1108// lpProcessAttributes - OS-specific attributes for process creation.
1109// lpThreadAttributes - OS-specific attributes for thread creation.
1110// fInheritFlags - OS-specific flag for child process inheritance.
1111// dwCreationFlags - OS-specific creation flags.
1112// lpEnvironment - OS-specific environmental strings.
1113// szCurrentDirectory - OS-specific string for directory to run in.
1114// lpStartupInfo - OS-specific info on startup.
1115// lpProcessInformation - OS-specific process information buffer.
1116// corDebugFlags - What type of process to create, currently always managed.
1117//-----------------------------------------------------------------------------
1118HRESULT ShimProcess::CreateProcess(
1119 Cordb * pCordb,
1120 ICorDebugRemoteTarget * pRemoteTarget,
1121 LPCWSTR szProgramName,
1122 __in_z LPWSTR szProgramArgs,
1123 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1124 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1125 BOOL fInheritHandles,
1126 DWORD dwCreationFlags,
1127 PVOID lpEnvironment,
1128 LPCWSTR szCurrentDirectory,
1129 LPSTARTUPINFOW lpStartupInfo,
1130 LPPROCESS_INFORMATION lpProcessInformation,
1131 CorDebugCreateProcessFlags corDebugFlags
1132)
1133{
1134 _ASSERTE(pCordb != NULL);
1135
1136#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
1137 // The transport cannot deal with creating a suspended process (it needs the debugger to start up and
1138 // listen for connections).
1139 _ASSERTE((dwCreationFlags & CREATE_SUSPENDED) == 0);
1140#endif // FEATURE_DBGIPC_TRANSPORT_DI
1141
1142 HRESULT hr = S_OK;
1143
1144 RSExtSmartPtr<ShimProcess> pShim;
1145 EX_TRY
1146 {
1147 pShim.Assign(new ShimProcess());
1148
1149 // Indicate that this process was started under the debugger as opposed to attaching later.
1150 pShim->m_attached = false;
1151
1152 hr = pShim->CreateAndStartWin32ET(pCordb);
1153 IfFailThrow(hr);
1154
1155 // Call out to newly created Win32-event Thread to create the process.
1156 // If this succeeds, new CordbProcess will add a ref to the ShimProcess
1157 hr = pShim->GetWin32EventThread()->SendCreateProcessEvent(pShim->GetMachineInfo(),
1158 szProgramName,
1159 szProgramArgs,
1160 lpProcessAttributes,
1161 lpThreadAttributes,
1162 fInheritHandles,
1163 dwCreationFlags,
1164 lpEnvironment,
1165 szCurrentDirectory,
1166 lpStartupInfo,
1167 lpProcessInformation,
1168 corDebugFlags);
1169 IfFailThrow(hr);
1170 }
1171 EX_CATCH_HRESULT(hr);
1172
1173 // If this succeeds, then process takes ownership of thread. Else we need to kill it.
1174 if (FAILED(hr))
1175 {
1176 if (pShim != NULL)
1177 {
1178 pShim->Dispose();
1179 }
1180 }
1181 // Always release our ref to ShimProcess. If the Process was created, then it takes a reference.
1182
1183 return hr;
1184}
1185
1186//-----------------------------------------------------------------------------
1187// Static build helper for the attach case.
1188// On success, this will add the process to the pCordb list, and then
1189// callers can look it up there by pid.
1190//
1191// Arguments:
1192// pCordb - root under which this all lives
1193// dwProcessID - OS process ID to attach to
1194// fWin32Attach - are we interop debugging?
1195//-----------------------------------------------------------------------------
1196HRESULT ShimProcess::DebugActiveProcess(
1197 Cordb * pCordb,
1198 ICorDebugRemoteTarget * pRemoteTarget,
1199 const ProcessDescriptor * pProcessDescriptor,
1200 BOOL fWin32Attach
1201)
1202{
1203 _ASSERTE(pCordb != NULL);
1204
1205 HRESULT hr = S_OK;
1206
1207 RSExtSmartPtr<ShimProcess> pShim;
1208
1209 EX_TRY
1210 {
1211 pShim.Assign(new ShimProcess());
1212
1213 // Indicate that this process was attached to, asopposed to being started under the debugger.
1214 pShim->m_attached = true;
1215
1216 hr = pShim->CreateAndStartWin32ET(pCordb);
1217 IfFailThrow(hr);
1218
1219 // If this succeeds, new CordbProcess will add a ref to the ShimProcess
1220 hr = pShim->GetWin32EventThread()->SendDebugActiveProcessEvent(pShim->GetMachineInfo(),
1221 pProcessDescriptor,
1222 fWin32Attach == TRUE,
1223 NULL);
1224 IfFailThrow(hr);
1225
1226 _ASSERTE(SUCCEEDED(hr));
1227
1228#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
1229 // Don't do this when we are remote debugging since we won't be getting the loader breakpoint.
1230 // We don't support JIT attach in remote debugging scenarios anyway.
1231 //
1232 // When doing jit attach for pure managed debugging we allow the native attach event to be signaled
1233 // after DebugActiveProcess completes which means we must wait here long enough to have set the debuggee
1234 // bit indicating managed attach is coming.
1235 // However in interop debugging we can't do that because there are debug events which come before the
1236 // loader breakpoint (which is how far we need to get to set the debuggee bit). If we blocked
1237 // DebugActiveProcess there then the debug events would be refering to an ICorDebugProcess that hasn't
1238 // yet been returned to the caller of DebugActiveProcess. Instead, for interop debugging we force the
1239 // native debugger to wait until it gets the loader breakpoint to set the event. Note we can't converge
1240 // on that solution for the pure managed case because there is no loader breakpoint event. Hence pure
1241 // managed and interop debugging each require their own solution
1242 //
1243 // See bugs Dev10 600873 and 595322 for examples of what happens if we wait in interop or don't wait
1244 // in pure managed respectively
1245 //
1246 // Long term this should all go away because we won't need to set a managed attach pending bit because
1247 // there shouldn't be any IPC events involved in managed attach. There might not even be a notion of
1248 // being 'managed attached'
1249 if(!pShim->m_fIsInteropDebugging)
1250 {
1251 DWORD dwHandles = 2;
1252 HANDLE arrHandles[2];
1253
1254 arrHandles[0] = pShim->m_terminatingEvent;
1255 arrHandles[1] = pShim->m_markAttachPendingEvent;
1256
1257 // Wait for the completion of marking pending attach bit or debugger detaching
1258 WaitForMultipleObjectsEx(dwHandles, arrHandles, FALSE, INFINITE, FALSE);
1259 }
1260#endif //!FEATURE_DBGIPC_TRANSPORT_DI
1261 }
1262 EX_CATCH_HRESULT(hr);
1263
1264 // If this succeeds, then process takes ownership of thread. Else we need to kill it.
1265 if (FAILED(hr))
1266 {
1267 if (pShim!= NULL)
1268 {
1269 pShim->Dispose();
1270 }
1271 }
1272
1273 // Always release our ref to ShimProcess. If the Process was created, then it takes a reference.
1274
1275 return hr;
1276}
1277
1278//-----------------------------------------------------------------------------
1279// Neuter all of all children, but not the actual process object.
1280//
1281// Assumptions:
1282// This clears Right-side state. Assumptions about left-side state are either:
1283// 1. We're in a shutdown scenario, where all left-side state is already
1284// freed.
1285// 2. Caller already verified there are no left-side resources (eg, by calling
1286// code:CordbProcess::IsReadyForDetach)
1287// 3. Caller did code:CordbProcess::NeuterLeftSideResources first
1288// to clean up left-side resources.
1289//
1290// Notes:
1291// This could be called multiple times (code:CordbProcess::FlushAll), so
1292// be sure to null out any potential dangling pointers. State may be rebuilt
1293// up after each time.
1294void CordbProcess::NeuterChildren()
1295{
1296 _ASSERTE(GetProcessLock()->HasLock());
1297
1298 // Frees left-side resources. See assumptions above.
1299 m_LeftSideResourceCleanupList.NeuterAndClear(this);
1300
1301
1302 m_EvalTable.Clear();
1303
1304
1305 // Sweep neuter lists.
1306 m_ExitNeuterList.NeuterAndClear(this);
1307 m_ContinueNeuterList.NeuterAndClear(this);
1308
1309 m_userThreads.NeuterAndClear(GetProcessLock());
1310
1311 m_pDefaultAppDomain = NULL;
1312
1313 // Frees per-appdomain left-side resources. See assumptions above.
1314 m_appDomains.NeuterAndClear(GetProcessLock());
1315 if (m_sharedAppDomain != NULL)
1316 {
1317 m_sharedAppDomain->Neuter();
1318 m_sharedAppDomain->InternalRelease();
1319 m_sharedAppDomain = NULL;
1320 }
1321
1322 m_steppers.NeuterAndClear(GetProcessLock());
1323
1324#ifdef FEATURE_INTEROP_DEBUGGING
1325 m_unmanagedThreads.NeuterAndClear(GetProcessLock());
1326#endif // FEATURE_INTEROP_DEBUGGING
1327
1328 // Explicitly keep the Win32EventThread alive so that we can use it in the window
1329 // between NeuterChildren + Neuter.
1330}
1331
1332//-----------------------------------------------------------------------------
1333// Neuter
1334//
1335// When the process dies, remove all the resources associated with this object.
1336//
1337// Notes:
1338// Once we neuter ourself, we can no longer send IPC events. So this is useful
1339// on detach. This will be called on FlushAll (which has Whidbey detach
1340// semantics)
1341//-----------------------------------------------------------------------------
1342void CordbProcess::Neuter()
1343{
1344 // Process's Neuter is at the top of the neuter tree. So we take the process-lock
1345 // here and then all child items (appdomains, modules, etc) will assert
1346 // that they hold the lock.
1347 _ASSERTE(!this->ThreadHoldsProcessLock());
1348
1349 // Take the process lock.
1350 RSLockHolder lockHolder(GetProcessLock());
1351
1352
1353 NeuterChildren();
1354
1355 // Release the metadata interfaces
1356 m_pMetaDispenser.Clear();
1357
1358
1359 if (m_hHelperThread != NULL)
1360 {
1361 CloseHandle(m_hHelperThread);
1362 m_hHelperThread = NULL;
1363 }
1364
1365 {
1366 lockHolder.Release();
1367 {
1368 // We may still hold the Stop-Go lock.
1369 // @dbgtodo - left-side resources / shutdown, shim: Currently
1370 // the shim shutdown is too interwoven with CordbProcess to split
1371 // it out from the locks. Must fully hoist the W32ET and make
1372 // it safely outside the RS, and outside the protection of RS
1373 // locks.
1374 PUBLIC_API_UNSAFE_ENTRY_FOR_SHIM(this);
1375
1376 // Now that all of our children are neutered, it should be safe to kill the W32ET.
1377 // Shutdown the shim, and this will also shutdown the W32ET.
1378 // Do this outside of the process-lock so that we can shutdown the
1379 // W23ET.
1380 if (m_pShim != NULL)
1381 {
1382 m_pShim->Dispose();
1383 m_pShim.Clear();
1384 }
1385 }
1386
1387 lockHolder.Acquire();
1388 }
1389
1390 // Unload DAC, and then release our final data target references
1391 FreeDac();
1392 m_pDACDataTarget.Clear();
1393 m_pMutableDataTarget.Clear();
1394 m_pMetaDataLocator.Clear();
1395
1396 if (m_pEventChannel != NULL)
1397 {
1398 m_pEventChannel->Delete();
1399 m_pEventChannel = NULL;
1400 }
1401
1402 // Need process lock to clear the patch table
1403 ClearPatchTable();
1404
1405 CordbProcess::CloseIPCHandles();
1406
1407 CordbBase::Neuter();
1408
1409 m_cordb.Clear();
1410
1411 // Need to release this reference to ourselves. Other leaf objects may still hold
1412 // strong references back to this CordbProcess object.
1413 _ASSERTE(m_pProcess == this);
1414 m_pProcess.Clear();
1415}
1416
1417// Wrapper to return metadata dispenser.
1418//
1419// Notes:
1420// Does not adjust reference count of dispenser.
1421// Dispenser is destroyed in code:CordbProcess::Neuter
1422// Dispenser is non-null.
1423IMetaDataDispenserEx * CordbProcess::GetDispenser()
1424{
1425 _ASSERTE(m_pMetaDispenser != NULL);
1426 return m_pMetaDispenser;
1427}
1428
1429
1430void CordbProcess::CloseIPCHandles()
1431{
1432 INTERNAL_API_ENTRY(this);
1433
1434 // Close off Right Side's handles.
1435 if (m_leftSideEventAvailable != NULL)
1436 {
1437 CloseHandle(m_leftSideEventAvailable);
1438 m_leftSideEventAvailable = NULL;
1439 }
1440
1441 if (m_leftSideEventRead != NULL)
1442 {
1443 CloseHandle(m_leftSideEventRead);
1444 m_leftSideEventRead = NULL;
1445 }
1446
1447 if (m_handle != NULL)
1448 {
1449 // @dbgtodo - We should probably add asserts to all calls to CloseHandles(), but this has been
1450 // a particularly problematic spot in the past for Mac debugging.
1451 BOOL fSuccess = CloseHandle(m_handle);
1452 (void)fSuccess; //prevent "unused variable" error from GCC
1453 _ASSERTE(fSuccess);
1454
1455 m_handle = NULL;
1456 }
1457
1458#if defined(FEATURE_INTEROP_DEBUGGING)
1459 if (m_leftSideUnmanagedWaitEvent != NULL)
1460 {
1461 CloseHandle(m_leftSideUnmanagedWaitEvent);
1462 m_leftSideUnmanagedWaitEvent = NULL;
1463 }
1464#endif // FEATURE_INTEROP_DEBUGGING
1465
1466 if (m_stopWaitEvent != NULL)
1467 {
1468 CloseHandle(m_stopWaitEvent);
1469 m_stopWaitEvent = NULL;
1470 }
1471}
1472
1473
1474//-----------------------------------------------------------------------------
1475// Create new OS Thread for the Win32 Event Thread (the thread used in interop-debugging to sniff
1476// native debug events). This is 1:1 w/ a CordbProcess object.
1477// This will then be used to actuall create the CordbProcess object.
1478// The process object will then take ownership of the thread.
1479//
1480// Arguments:
1481// pCordb - the root object that the process lives under
1482//
1483// Return values:
1484// S_OK on success.
1485//-----------------------------------------------------------------------------
1486HRESULT ShimProcess::CreateAndStartWin32ET(Cordb * pCordb)
1487{
1488
1489 //
1490 // Create the win32 event listening thread
1491 //
1492 CordbWin32EventThread * pWin32EventThread = new (nothrow) CordbWin32EventThread(pCordb, this);
1493
1494 HRESULT hr = S_OK;
1495
1496 if (pWin32EventThread != NULL)
1497 {
1498 hr = pWin32EventThread->Init();
1499
1500 if (SUCCEEDED(hr))
1501 {
1502 hr = pWin32EventThread->Start();
1503 }
1504
1505 if (FAILED(hr))
1506 {
1507 delete pWin32EventThread;
1508 pWin32EventThread = NULL;
1509 }
1510 }
1511 else
1512 {
1513 hr = E_OUTOFMEMORY;
1514 }
1515
1516 m_pWin32EventThread = pWin32EventThread;
1517 return ErrWrapper(hr);
1518}
1519
1520
1521//---------------------------------------------------------------------------------------
1522//
1523// Try to initialize the DAC. Called in scenarios where it may fail.
1524//
1525// Return Value:
1526// TRUE - DAC is initialized.
1527// FALSE - Not initialized, but can try again later. Common case if
1528// target has not yet loaded the runtime.
1529// Throws exception - fatal.
1530//
1531// Assumptions:
1532// Target is stopped by OS, so we can safely inspect it without it moving on us.
1533//
1534// Notes:
1535// This can be called eagerly to sniff if the LS is initialized.
1536//
1537//---------------------------------------------------------------------------------------
1538BOOL CordbProcess::TryInitializeDac()
1539{
1540 CONTRACTL
1541 {
1542 THROWS;
1543 }
1544 CONTRACTL_END;
1545
1546 // Target is stopped by OS, so we can safely inspect it without it moving on us.
1547
1548 // We want to avoid exceptions in the normal case, so we do some pre-checks
1549 // to detect failure without relying on exceptions.
1550 // Can't initialize DAC until mscorwks is loaded. So that's a sanity test.
1551 HRESULT hr = EnsureClrInstanceIdSet();
1552 if (FAILED(hr))
1553 {
1554 return FALSE;
1555 }
1556
1557 // By this point, we know which CLR in the target to debug. That means there is a CLR
1558 // in the target, and it's safe to initialize DAC.
1559 _ASSERTE(m_clrInstanceId != 0);
1560
1561 // Now expect it to succeed
1562 InitializeDac();
1563 return TRUE;
1564}
1565
1566//---------------------------------------------------------------------------------------
1567//
1568// Load & Init DAC, expecting to succeed.
1569//
1570// Return Value:
1571// Throws on failure.
1572//
1573// Assumptions:
1574// Caller invokes this at a point where they can expect it to succeed.
1575// This is called early in the startup path because DAC is needed for accessing
1576// data in the target.
1577//
1578// Notes:
1579// This needs to succeed, and should always succeed (baring a bad installation)
1580// so we assert on failure paths.
1581// This may be called mutliple times.
1582//
1583//---------------------------------------------------------------------------------------
1584void CordbProcess::InitializeDac()
1585{
1586 CONTRACTL
1587 {
1588 THROWS;
1589 }
1590 CONTRACTL_END;
1591 INTERNAL_API_ENTRY(this);
1592
1593 // For Mac debugginger, m_hDacModule is not used, and it will always be NULL. To check whether DAC has
1594 // been initialized, we need to check something else, namely m_pDacPrimitives.
1595 if (m_pDacPrimitives == NULL)
1596 {
1597 LOG((LF_CORDB, LL_INFO1000, "About to load DAC\n"));
1598 CreateDacDbiInterface(); // throws
1599 }
1600 else
1601 {
1602 LOG((LF_CORDB, LL_INFO1000, "Dac already loaded, 0x%p\n", (HMODULE)m_hDacModule));
1603 }
1604
1605 // Always flush dac.
1606 ForceDacFlush();
1607}
1608
1609//---------------------------------------------------------------------------------------
1610//
1611// Free DAC resources
1612//
1613// Notes:
1614// This should clean up state such that code:CordbProcess::InitializeDac could be called again.
1615//
1616//---------------------------------------------------------------------------------------
1617void CordbProcess::FreeDac()
1618{
1619 CONTRACTL
1620 {
1621 NOTHROW; // backout code.
1622 }
1623 CONTRACTL_END;
1624
1625 if (m_pDacPrimitives != NULL)
1626 {
1627 m_pDacPrimitives->Destroy();
1628 m_pDacPrimitives = NULL;
1629 }
1630
1631 if (m_hDacModule != NULL)
1632 {
1633 LOG((LF_CORDB, LL_INFO1000, "Unloading DAC\n"));
1634 m_hDacModule.Clear();
1635 }
1636}
1637
1638IEventChannel * CordbProcess::GetEventChannel()
1639{
1640 _ASSERTE(m_pEventChannel != NULL);
1641 return m_pEventChannel;
1642}
1643
1644//---------------------------------------------------------------------------------------
1645// Mark that the process is being interop-debugged.
1646//
1647// Notes:
1648// @dbgtodo shim: this should eventually move into the shim or go away.
1649// It's only to support V2 legacy interop-debugging.
1650// Called after code:CordbProcess::Init if we want to enable interop debugging.
1651// This allows us to separate out Interop-debugging flags from the core initialization,
1652// and paves the way for us to eventually remove it.
1653//
1654// Since we're always on the naitve-pipeline, the Enabling interop debugging just changes
1655// how the native debug events are being handled. So this must be called after Init, but
1656// before any events are actually handled.
1657// This mus be calle on the win32 event thread to gaurantee that it's called before WFDE.
1658void CordbProcess::EnableInteropDebugging()
1659{
1660 CONTRACTL
1661 {
1662 THROWS;
1663 PRECONDITION(m_pShim != NULL);
1664 }
1665 CONTRACTL_END;
1666
1667 // Must be on W32ET to gaurantee that we're called after Init yet before WFDE (which
1668 // are both called on the W32et).
1669 _ASSERTE(IsWin32EventThread());
1670#ifdef FEATURE_INTEROP_DEBUGGING
1671
1672 m_state |= PS_WIN32_ATTACHED;
1673 if (GetDCB() != NULL)
1674 {
1675 GetDCB()->m_rightSideIsWin32Debugger = true;
1676 UpdateLeftSideDCBField(&(GetDCB()->m_rightSideIsWin32Debugger), sizeof(GetDCB()->m_rightSideIsWin32Debugger));
1677 }
1678
1679 // Tell the Shim we're interop-debugging.
1680 m_pShim->SetIsInteropDebugging(true);
1681#else
1682 ThrowHR(CORDBG_E_INTEROP_NOT_SUPPORTED);
1683#endif
1684}
1685
1686//---------------------------------------------------------------------------------------
1687//
1688// Init -- create any objects that the process object needs to operate.
1689//
1690// Arguments:
1691//
1692// Return Value:
1693// S_OK on success
1694//
1695// Assumptions:
1696// Called on Win32 Event Thread, after OS debugging pipeline is established but
1697// before WaitForDebugEvent / ContinueDebugEvent. This means the target is stopped.
1698//
1699// Notes:
1700// To enable interop-debugging, call code:CordbProcess::EnableInteropDebugging
1701//---------------------------------------------------------------------------------------
1702HRESULT CordbProcess::Init()
1703{
1704 INTERNAL_API_ENTRY(this);
1705
1706 HRESULT hr = S_OK;
1707 BOOL fIsLSStarted = FALSE; // see meaning below.
1708
1709 FAIL_IF_NEUTERED(this);
1710
1711
1712 EX_TRY
1713 {
1714 m_processMutex.Init("Process Lock", RSLock::cLockReentrant, RSLock::LL_PROCESS_LOCK);
1715 m_StopGoLock.Init("Stop-Go Lock", RSLock::cLockReentrant, RSLock::LL_STOP_GO_LOCK);
1716
1717#ifdef _DEBUG
1718 m_appDomains.DebugSetRSLock(GetProcessLock());
1719 m_userThreads.DebugSetRSLock(GetProcessLock());
1720#ifdef FEATURE_INTEROP_DEBUGGING
1721 m_unmanagedThreads.DebugSetRSLock(GetProcessLock());
1722#endif
1723 m_steppers.DebugSetRSLock(GetProcessLock());
1724#endif
1725
1726 // See if the data target is mutable, and cache the mutable interface if it is
1727 // We must initialize this before we try to use the data target to access the memory in the target process.
1728 m_pMutableDataTarget.Clear(); // if we were called already, release
1729 hr = m_pDACDataTarget->QueryInterface(IID_ICorDebugMutableDataTarget, (void**)&m_pMutableDataTarget);
1730 if (!SUCCEEDED(hr))
1731 {
1732 // The data target doesn't support mutation. We'll fail any requests that require mutation.
1733 m_pMutableDataTarget.Assign(new ReadOnlyDataTargetFacade());
1734 }
1735
1736 m_pMetaDataLocator.Clear();
1737 hr = m_pDACDataTarget->QueryInterface(IID_ICorDebugMetaDataLocator, reinterpret_cast<void **>(&m_pMetaDataLocator));
1738
1739 // Get the metadata dispenser.
1740 hr = InternalCreateMetaDataDispenser(IID_IMetaDataDispenserEx, (void **)&m_pMetaDispenser);
1741
1742 // We statically link in the dispenser. We expect it to succeed, except for OOM, which
1743 // debugger doesn't yet handle.
1744 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
1745 IfFailThrow(hr);
1746
1747 _ASSERTE(m_pMetaDispenser != NULL);
1748
1749 // In order to allow users to call the metadata reader from multiple threads we need to set
1750 // a flag on the dispenser to create threadsafe readers. This is done best-effort but
1751 // really shouldn't ever fail. See issue 696511.
1752 VARIANT optionValue;
1753 VariantInit(&optionValue);
1754 V_VT(&optionValue) = VT_UI4;
1755 V_UI4(&optionValue) = MDThreadSafetyOn;
1756 m_pMetaDispenser->SetOption(MetaDataThreadSafetyOptions, &optionValue);
1757
1758 //
1759 // Setup internal events.
1760 // @dbgtodo shim: these events should eventually be in the shim.
1761 //
1762
1763
1764 // Managed debugging is built on the native-pipeline, and that will detect against double-attaches.
1765
1766 // @dbgtodo shim: In V2, LSEA + LSER were used by the LS's helper thread. Now with the V3 pipeline,
1767 // that helper-thread uses native-debug events. The W32ET gets those events and then uses LSEA, LSER to
1768 // signal existing RS infrastructure. Eventually get rid of LSEA, LSER completely.
1769 //
1770
1771 m_leftSideEventAvailable = WszCreateEvent(NULL, FALSE, FALSE, NULL);
1772 if (m_leftSideEventAvailable == NULL)
1773 {
1774 ThrowLastError();
1775 }
1776
1777 m_leftSideEventRead = WszCreateEvent(NULL, FALSE, FALSE, NULL);
1778 if (m_leftSideEventRead == NULL)
1779 {
1780 ThrowLastError();
1781 }
1782
1783 m_stopWaitEvent = WszCreateEvent(NULL, TRUE, FALSE, NULL);
1784 if (m_stopWaitEvent == NULL)
1785 {
1786 ThrowLastError();
1787 }
1788
1789 if (m_pShim != NULL)
1790 {
1791 // Get a handle to the debuggee.
1792 // This is not needed in the V3 pipeline because we don't assume we have a live, local, process.
1793 m_handle = GetShim()->GetNativePipeline()->GetProcessHandle();
1794
1795 if (m_handle == NULL)
1796 {
1797 ThrowLastError();
1798 }
1799 }
1800
1801 // The LS startup goes through the following phases:
1802 // 1) mscorwks not yet loaded (eg, any unmanaged app)
1803 // 2) mscorwks loaded (DAC can now be used)
1804 // 3) IPC Block created at OS level
1805 // 4) IPC block data initialized (so we can read meainingful data from it)
1806 // 5) LS marks that it's initialized (queryable by a DAC primitive) (may not be atomic)
1807 // 6) LS fires a "Startup" exception (sniffed by WFDE).
1808 //
1809 // LS is currently stopped by OS debugging, so it's doesn't shift phases.
1810 // From the RS's perspective:
1811 // - after phase 5 is an attach
1812 // - before phase 6 is a launch.
1813 // This means there's an overlap: if we catch it at phase 5, we'll just get
1814 // an extra Startup exception from phase 6, which is safe. This overlap is good
1815 // because it means there's no bad window to do an attach in.
1816
1817 // fIsLSStarted means before phase 6 (eg, RS should expect a startup exception)
1818
1819 // Determines if the LS is started.
1820
1821 {
1822 BOOL fReady = TryInitializeDac();
1823
1824 if (fReady)
1825 {
1826 // Invoke DAC primitive.
1827 _ASSERTE(m_pDacPrimitives != NULL);
1828 fIsLSStarted = m_pDacPrimitives->IsLeftSideInitialized();
1829 }
1830 else
1831 {
1832 _ASSERTE(m_pDacPrimitives == NULL);
1833
1834 // DAC is not yet loaded, so we're at least before phase 2, which is before phase 6.
1835 // So leave fIsLSStarted = false. We'll get a startup exception later.
1836 _ASSERTE(!fIsLSStarted);
1837 }
1838 }
1839
1840
1841 if (fIsLSStarted)
1842 {
1843 // Left-side has started up. This is common for Attach cases when managed-code is already running.
1844
1845 if (m_pShim != NULL)
1846 {
1847 FinishInitializeIPCChannelWorker(); // throws
1848
1849 // At this point, the control block is complete and all four
1850 // events are available and valid for the remote process.
1851
1852 // Request that the process object send an Attach IPC event.
1853 // This is only used in an attach case.
1854 // @dbgtodo sync: this flag can go away once the
1855 // shim can use real sync APIs.
1856 m_fDoDelayedManagedAttached = true;
1857 }
1858 else
1859 {
1860 // In the V3 pipeline case, if we have the DD-interface, then the runtime is loaded
1861 // and we consider it initialized.
1862 if (IsDacInitialized())
1863 {
1864 m_initialized = true;
1865 }
1866 }
1867 }
1868 else
1869 {
1870 // LS is not started yet. This would be common for "Launch" cases.
1871 // We will get a Startup Exception notification when it does start.
1872 }
1873 }
1874 EX_CATCH_HRESULT(hr);
1875
1876 if (FAILED(hr))
1877 {
1878 CleanupHalfBakedLeftSide();
1879 }
1880
1881 return hr;
1882}
1883
1884
1885COM_METHOD CordbProcess::CanCommitChanges(ULONG cSnapshots,
1886 ICorDebugEditAndContinueSnapshot *pSnapshots[],
1887 ICorDebugErrorInfoEnum **pError)
1888{
1889 return E_NOTIMPL;
1890}
1891
1892COM_METHOD CordbProcess::CommitChanges(ULONG cSnapshots,
1893 ICorDebugEditAndContinueSnapshot *pSnapshots[],
1894 ICorDebugErrorInfoEnum **pError)
1895{
1896 return E_NOTIMPL;
1897}
1898
1899
1900//
1901// Terminating -- places the process into the terminated state. This should
1902// also get any blocking process functions unblocked so they'll return
1903// a failure code.
1904//
1905void CordbProcess::Terminating(BOOL fDetach)
1906{
1907 INTERNAL_API_ENTRY(this);
1908
1909 LOG((LF_CORDB, LL_INFO1000,"CP::T: Terminating process 0x%x detach=%d\n", m_id, fDetach));
1910 m_terminated = true;
1911
1912 m_cordb->ProcessStateChanged();
1913
1914 // Set events that may be blocking stuff.
1915 // But don't set RSER unless we actually read the event. We don't block on RSER
1916 // since that wait also checks the leftside's process handle.
1917 SetEvent(m_leftSideEventRead);
1918 SetEvent(m_leftSideEventAvailable);
1919 SetEvent(m_stopWaitEvent);
1920
1921 if (m_pShim != NULL)
1922 m_pShim->SetTerminatingEvent();
1923
1924 if (fDetach && (m_pEventChannel != NULL))
1925 {
1926 m_pEventChannel->Detach();
1927 }
1928}
1929
1930
1931// Wrapper to give shim access to code:CordbProcess::QueueManagedAttachIfNeededWorker
1932void CordbProcess::QueueManagedAttachIfNeeded()
1933{
1934 PUBLIC_API_ENTRY_FOR_SHIM(this);
1935 QueueManagedAttachIfNeededWorker();
1936}
1937
1938//---------------------------------------------------------------------------------------
1939// Hook from Shim to request a managed attach IPC event
1940//
1941// Notes:
1942// Called by shim after the loader-breakpoint is handled.
1943// @dbgtodo sync: ths should go away once the shim can initiate
1944// a sync
1945void CordbProcess::QueueManagedAttachIfNeededWorker()
1946{
1947 HRESULT hrQueue = S_OK;
1948
1949 // m_fDoDelayedManagedAttached ensures that we only send an Attach event if the LS is actually present.
1950 if (m_fDoDelayedManagedAttached && GetShim()->GetAttached())
1951 {
1952 RSLockHolder lockHolder(&this->m_processMutex);
1953 GetDAC()->MarkDebuggerAttachPending();
1954
1955 hrQueue = this->QueueManagedAttach();
1956 }
1957
1958 if (m_pShim != NULL)
1959 m_pShim->SetMarkAttachPendingEvent();
1960
1961 IfFailThrow(hrQueue);
1962}
1963
1964//---------------------------------------------------------------------------------------
1965//
1966// QueueManagedAttach
1967//
1968// Send a managed attach. This is asynchronous and will return immediately.
1969//
1970// Return Value:
1971// S_OK on success
1972//
1973//---------------------------------------------------------------------------------------
1974HRESULT CordbProcess::QueueManagedAttach()
1975{
1976 INTERNAL_API_ENTRY(this);
1977
1978 _ASSERTE(ThreadHoldsProcessLock());
1979
1980 _ASSERTE(m_fDoDelayedManagedAttached);
1981 m_fDoDelayedManagedAttached = false;
1982
1983 _ASSERTE(IsDacInitialized());
1984
1985 // We don't know what Queue it.
1986 SendAttachProcessWorkItem * pItem = new (nothrow) SendAttachProcessWorkItem(this);
1987
1988 if (pItem == NULL)
1989 {
1990 return E_OUTOFMEMORY;
1991 }
1992
1993 this->m_cordb->m_rcEventThread->QueueAsyncWorkItem(pItem);
1994
1995 return S_OK;
1996}
1997
1998// However, we still want to synchronize.
1999// @dbgtodo sync: when we hoist attaching, we can send an DB_IPCE_ASYNC_BREAK event instead or Attach
2000// (for V2 semantics, we still need to synchronize the process)?
2001void SendAttachProcessWorkItem::Do()
2002{
2003 HRESULT hr;
2004
2005 // This is being processed on the RCET, where it's safe to take the Stop-Go lock.
2006 RSLockHolder ch(this->GetProcess()->GetStopGoLock());
2007
2008 DebuggerIPCEvent *event = (DebuggerIPCEvent*) _alloca(CorDBIPC_BUFFER_SIZE);
2009
2010 // This just acts like an async-break, which will kick off things.
2011 // This will not induce any faked attach events from the VM (like it did in V2).
2012 // The Left-side will still slip foward allowing the async-break to happen, so
2013 // we may get normal debug events in addition to the sync-complete.
2014 //
2015 // 1. In the common attach case, we should just get a sync-complete.
2016 // 2. In Jit-attach cases, the LS is sending an event, and so we'll get that event and then the sync-complete.
2017 GetProcess()->InitAsyncIPCEvent(event, DB_IPCE_ATTACHING, VMPTR_AppDomain::NullPtr());
2018
2019 // This should result in a sync-complete from the Left-side, which will be raised as an exception
2020 // that the debugger passes into Filter and then internally goes through code:CordbProcess::TriageSyncComplete
2021 // and that triggers code:CordbRCEventThread::FlushQueuedEvents to be called on the RCET.
2022 // We already pre-queued a fake CreateProcess event.
2023
2024 // The left-side will also mark itself as attached in response to this event.
2025 // We explicitly don't mark it as attached from the right-side because we want to let the left-side
2026 // synchronize first (to stop all running threads) before marking the debugger as attached.
2027 LOG((LF_CORDB, LL_INFO1000, "[%x] CP::S: sending attach.\n", GetCurrentThreadId()));
2028
2029 hr = GetProcess()->SendIPCEvent(event, CorDBIPC_BUFFER_SIZE);
2030
2031 LOG((LF_CORDB, LL_INFO1000, "[%x] CP::S: sent attach.\n", GetCurrentThreadId()));
2032}
2033
2034//---------------------------------------------------------------------------------------
2035// Try to lookup a cached thread object
2036//
2037// Arguments:
2038// vmThread - vm identifier for thread.
2039//
2040// Returns:
2041// Thread object if cached; null if not yet cached.
2042//
2043// Notes:
2044// This does not create the thread object if it's not cached. Caching is unpredictable,
2045// and so this may appear to randomly return NULL.
2046// Callers should prefer code:CordbProcess::LookupOrCreateThread unless they expicitly
2047// want to check RS state.
2048CordbThread * CordbProcess::TryLookupThread(VMPTR_Thread vmThread)
2049{
2050 return m_userThreads.GetBase(VmPtrToCookie(vmThread));
2051}
2052
2053//---------------------------------------------------------------------------------------
2054// Lookup (or create) a CordbThread object by the given volatile OS id. Returns null if not a manged thread
2055//
2056// Arguments:
2057// dwThreadId - os thread id that a managed thread may be using.
2058//
2059// Returns:
2060// Thread instance if there is currently a managed thread scheduled to run on dwThreadId.
2061// NULL if this tid is not a valid Managed thread. (This is considered a common case)
2062// Throws on error.
2063//
2064// Notes:
2065// OS Thread ID is not fiber-safe, so this is a dangerous function to call.
2066// Avoid this as much as possible. Prefer using VMPTR_Thread and
2067// code:CordbProcess::LookupOrCreateThread instead of OS thread IDs.
2068// See code:CordbThread::GetID for details.
2069CordbThread * CordbProcess::TryLookupOrCreateThreadByVolatileOSId(DWORD dwThreadId)
2070{
2071 PrepopulateThreadsOrThrow();
2072 return TryLookupThreadByVolatileOSId(dwThreadId);
2073}
2074
2075//---------------------------------------------------------------------------------------
2076// Lookup a cached CordbThread object by the tid. Returns null if not in the cache (which
2077// includes unmanged thread)
2078//
2079// Arguments:
2080// dwThreadId - os thread id that a managed thread may be using.
2081//
2082// Returns:
2083// Thread instance if there is currently a managed thread scheduled to run on dwThreadId.
2084// NULL if this tid is not a valid Managed thread. (This is considered a common case)
2085// Throws on error.
2086//
2087// Notes:
2088// Avoids this method:
2089// * OS Thread ID is not fiber-safe, so this is a dangerous function to call.
2090// * This is juts a Lookup, not LookupOrCreate, so it should only be used by methods
2091// that care about the RS state (instead of just LS state).
2092// Prefer using VMPTR_Thread and code:CordbProcess::LookupOrCreateThread
2093//
2094CordbThread * CordbProcess::TryLookupThreadByVolatileOSId(DWORD dwThreadId)
2095{
2096 HASHFIND find;
2097 for (CordbThread * pThread = m_userThreads.FindFirst(&find);
2098 pThread != NULL;
2099 pThread = m_userThreads.FindNext(&find))
2100 {
2101 _ASSERTE(pThread != NULL);
2102
2103 // Get the OS tid. This returns 0 if the thread is switched out.
2104 DWORD dwThreadId2 = GetDAC()->TryGetVolatileOSThreadID(pThread->m_vmThreadToken);
2105 if (dwThreadId2 == dwThreadId)
2106 {
2107 return pThread;
2108 }
2109 }
2110
2111 // This OS thread ID does not match any managed thread id.
2112 return NULL;
2113}
2114
2115//---------------------------------------------------------------------------------------
2116// Preferred CordbThread lookup routine.
2117//
2118// Arguments:
2119// vmThread - LS thread to lookup. Must be non-null.
2120//
2121// Returns:
2122// CordbThread instance for given vmThread. May return a previously cached
2123// instance or create a new instance. Never returns NULL.
2124// Throw on error.
2125CordbThread * CordbProcess::LookupOrCreateThread(VMPTR_Thread vmThread)
2126{
2127 _ASSERTE(!vmThread.IsNull());
2128
2129 // Return if we have an existing instance.
2130 CordbThread * pReturn = TryLookupThread(vmThread);
2131 if (pReturn != NULL)
2132 {
2133 return pReturn;
2134 }
2135
2136 RSInitHolder<CordbThread> pThread(new CordbThread(this, vmThread)); // throws
2137 pReturn = pThread.TransferOwnershipToHash(&m_userThreads);
2138
2139 return pReturn;
2140}
2141
2142
2143
2144
2145HRESULT CordbProcess::QueryInterface(REFIID id, void **pInterface)
2146{
2147 if (id == IID_ICorDebugProcess)
2148 {
2149 *pInterface = static_cast<ICorDebugProcess*>(this);
2150 }
2151 else if (id == IID_ICorDebugController)
2152 {
2153 *pInterface = static_cast<ICorDebugController*>(static_cast<ICorDebugProcess*>(this));
2154 }
2155 else if (id == IID_ICorDebugProcess2)
2156
2157 {
2158 *pInterface = static_cast<ICorDebugProcess2*>(this);
2159 }
2160 else if (id == IID_ICorDebugProcess3)
2161 {
2162 *pInterface = static_cast<ICorDebugProcess3*>(this);
2163 }
2164 else if (id == IID_ICorDebugProcess4)
2165 {
2166 *pInterface = static_cast<ICorDebugProcess4*>(this);
2167 }
2168 else if (id == IID_ICorDebugProcess5)
2169 {
2170 *pInterface = static_cast<ICorDebugProcess5*>(this);
2171 }
2172 else if (id == IID_ICorDebugProcess7)
2173 {
2174 *pInterface = static_cast<ICorDebugProcess7*>(this);
2175 }
2176 else if (id == IID_ICorDebugProcess8)
2177 {
2178 *pInterface = static_cast<ICorDebugProcess8*>(this);
2179 }
2180 else if (id == IID_ICorDebugProcess10)
2181 {
2182 *pInterface = static_cast<ICorDebugProcess10*>(this);
2183 }
2184#ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
2185 else if (id == IID_ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly)
2186 {
2187 *pInterface = static_cast<ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly*>(this);
2188 }
2189#endif
2190 else if (id == IID_IUnknown)
2191 {
2192 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugProcess*>(this));
2193 }
2194
2195 else
2196 {
2197 *pInterface = NULL;
2198 return E_NOINTERFACE;
2199 }
2200
2201 ExternalAddRef();
2202 return S_OK;
2203}
2204
2205
2206
2207
2208// Public implementation of ICorDebugProcess4::ProcessStateChanged
2209HRESULT CordbProcess::ProcessStateChanged(CorDebugStateChange eChange)
2210{
2211 HRESULT hr = S_OK;
2212 PUBLIC_API_BEGIN(this)
2213 {
2214 switch(eChange)
2215 {
2216 case PROCESS_RUNNING:
2217 FlushProcessRunning();
2218 break;
2219
2220 case FLUSH_ALL:
2221 FlushAll();
2222 break;
2223
2224 default:
2225 ThrowHR(E_INVALIDARG);
2226
2227 }
2228 }
2229 PUBLIC_API_END(hr);
2230 return hr;
2231}
2232
2233
2234HRESULT CordbProcess::EnumerateHeap(ICorDebugHeapEnum **ppObjects)
2235{
2236 if (!ppObjects)
2237 return E_POINTER;
2238
2239 HRESULT hr = S_OK;
2240 PUBLIC_API_ENTRY(this);
2241 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2242
2243 EX_TRY
2244 {
2245 if (m_pDacPrimitives->AreGCStructuresValid())
2246 {
2247 CordbHeapEnum *pHeapEnum = new CordbHeapEnum(this);
2248 GetContinueNeuterList()->Add(this, pHeapEnum);
2249 hr = pHeapEnum->QueryInterface(__uuidof(ICorDebugHeapEnum), (void**)ppObjects);
2250 }
2251 else
2252 {
2253 hr = CORDBG_E_GC_STRUCTURES_INVALID;
2254 }
2255 }
2256 EX_CATCH_HRESULT(hr);
2257
2258 return hr;
2259}
2260
2261HRESULT CordbProcess::GetGCHeapInformation(COR_HEAPINFO *pHeapInfo)
2262{
2263 if (!pHeapInfo)
2264 return E_INVALIDARG;
2265
2266 HRESULT hr = S_OK;
2267 PUBLIC_API_ENTRY(this);
2268 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2269
2270 EX_TRY
2271 {
2272 GetDAC()->GetGCHeapInformation(pHeapInfo);
2273 }
2274 EX_CATCH_HRESULT(hr);
2275
2276 return hr;
2277}
2278
2279HRESULT CordbProcess::EnumerateHeapRegions(ICorDebugHeapSegmentEnum **ppRegions)
2280{
2281 if (!ppRegions)
2282 return E_INVALIDARG;
2283
2284 HRESULT hr = S_OK;
2285 PUBLIC_API_ENTRY(this);
2286 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2287
2288 EX_TRY
2289 {
2290 DacDbiArrayList<COR_SEGMENT> segments;
2291 hr = GetDAC()->GetHeapSegments(&segments);
2292
2293 if (SUCCEEDED(hr))
2294 {
2295 if (!segments.IsEmpty())
2296 {
2297 CordbHeapSegmentEnumerator *segEnum = new CordbHeapSegmentEnumerator(this, &segments[0], (DWORD)segments.Count());
2298 GetContinueNeuterList()->Add(this, segEnum);
2299 hr = segEnum->QueryInterface(__uuidof(ICorDebugHeapSegmentEnum), (void**)ppRegions);
2300 }
2301 else
2302 {
2303 hr = E_OUTOFMEMORY;
2304 }
2305 }
2306 }
2307 EX_CATCH_HRESULT(hr);
2308
2309 return hr;
2310}
2311
2312HRESULT CordbProcess::GetObject(CORDB_ADDRESS addr, ICorDebugObjectValue **ppObject)
2313{
2314 return this->GetObjectInternal(addr, nullptr, ppObject);
2315}
2316
2317HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, ICorDebugObjectValue **pObject)
2318{
2319 HRESULT hr = S_OK;
2320
2321 PUBLIC_REENTRANT_API_ENTRY(this);
2322 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2323
2324 EX_TRY
2325 {
2326 if (!m_pDacPrimitives->IsValidObject(addr))
2327 {
2328 hr = CORDBG_E_CORRUPT_OBJECT;
2329 }
2330 else if (pObject == NULL)
2331 {
2332 hr = E_INVALIDARG;
2333 }
2334 else
2335 {
2336 RSLockHolder ch(GetProcess()->GetStopGoLock());
2337 RSLockHolder procLock(this->GetProcess()->GetProcessLock());
2338
2339 CordbAppDomain *cdbAppDomain = NULL;
2340 CordbType *pType = NULL;
2341 hr = GetTypeForObject(addr, pAppDomainOverride, &pType, &cdbAppDomain);
2342
2343 if (SUCCEEDED(hr))
2344 {
2345 _ASSERTE(pType != NULL);
2346 _ASSERTE(cdbAppDomain != NULL);
2347
2348 DebuggerIPCE_ObjectData objData;
2349 m_pDacPrimitives->GetBasicObjectInfo(addr, ELEMENT_TYPE_CLASS, cdbAppDomain->GetADToken(), &objData);
2350
2351 NewHolder<CordbObjectValue> pNewObjectValue(new CordbObjectValue(cdbAppDomain, pType, TargetBuffer(addr, (ULONG)objData.objSize), &objData));
2352 hr = pNewObjectValue->Init();
2353
2354 if (SUCCEEDED(hr))
2355 {
2356 hr = pNewObjectValue->QueryInterface(__uuidof(ICorDebugObjectValue), (void**)pObject);
2357 if (SUCCEEDED(hr))
2358 pNewObjectValue.SuppressRelease();
2359 }
2360 }
2361 }
2362 }
2363 EX_CATCH_HRESULT(hr);
2364
2365 return hr;
2366}
2367
2368
2369HRESULT CordbProcess::EnumerateGCReferences(BOOL enumerateWeakReferences, ICorDebugGCReferenceEnum **ppEnum)
2370{
2371 if (!ppEnum)
2372 return E_POINTER;
2373
2374 HRESULT hr = S_OK;
2375 PUBLIC_API_ENTRY(this);
2376 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2377
2378 EX_TRY
2379 {
2380 CordbRefEnum *pRefEnum = new CordbRefEnum(this, enumerateWeakReferences);
2381 GetContinueNeuterList()->Add(this, pRefEnum);
2382 hr = pRefEnum->QueryInterface(IID_ICorDebugGCReferenceEnum, (void**)ppEnum);
2383 }
2384 EX_CATCH_HRESULT(hr);
2385 return hr;
2386}
2387
2388HRESULT CordbProcess::EnumerateHandles(CorGCReferenceType types, ICorDebugGCReferenceEnum **ppEnum)
2389{
2390 if (!ppEnum)
2391 return E_POINTER;
2392
2393 HRESULT hr = S_OK;
2394 PUBLIC_API_ENTRY(this);
2395 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2396
2397 EX_TRY
2398 {
2399 CordbRefEnum *pRefEnum = new CordbRefEnum(this, types);
2400 GetContinueNeuterList()->Add(this, pRefEnum);
2401 hr = pRefEnum->QueryInterface(IID_ICorDebugGCReferenceEnum, (void**)ppEnum);
2402 }
2403 EX_CATCH_HRESULT(hr);
2404
2405 return hr;
2406}
2407
2408HRESULT CordbProcess::EnableNGENPolicy(CorDebugNGENPolicy ePolicy)
2409{
2410 return E_NOTIMPL;
2411}
2412
2413
2414HRESULT CordbProcess::GetTypeID(CORDB_ADDRESS obj, COR_TYPEID *pId)
2415{
2416 if (pId == NULL)
2417 return E_POINTER;
2418
2419 HRESULT hr = S_OK;
2420 PUBLIC_API_ENTRY(this);
2421 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
2422
2423 EX_TRY
2424 {
2425 hr = GetProcess()->GetDAC()->GetTypeID(obj, pId);
2426 }
2427 EX_CATCH_HRESULT(hr);
2428
2429 return hr;
2430}
2431
2432HRESULT CordbProcess::GetTypeForTypeID(COR_TYPEID id, ICorDebugType **ppType)
2433{
2434 if (ppType == NULL)
2435 return E_POINTER;
2436
2437 HRESULT hr = S_OK;
2438
2439 PUBLIC_API_ENTRY(this);
2440 RSLockHolder stopGoLock(this->GetProcess()->GetStopGoLock());
2441 RSLockHolder procLock(this->GetProcess()->GetProcessLock());
2442
2443 EX_TRY
2444 {
2445 DebuggerIPCE_ExpandedTypeData data;
2446 GetDAC()->GetObjectExpandedTypeInfoFromID(AllBoxed, VMPTR_AppDomain::NullPtr(), id, &data);
2447
2448 CordbType *type = 0;
2449 hr = CordbType::TypeDataToType(GetSharedAppDomain(), &data, &type);
2450
2451 if (SUCCEEDED(hr))
2452 hr = type->QueryInterface(IID_ICorDebugType, (void**)ppType);
2453 }
2454 EX_CATCH_HRESULT(hr);
2455
2456 return hr;
2457}
2458
2459
2460COM_METHOD CordbProcess::GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout)
2461{
2462 if (pLayout == NULL)
2463 return E_POINTER;
2464
2465 HRESULT hr = S_OK;
2466 PUBLIC_API_BEGIN(this);
2467
2468 hr = GetProcess()->GetDAC()->GetArrayLayout(id, pLayout);
2469
2470 PUBLIC_API_END(hr);
2471 return hr;
2472}
2473
2474COM_METHOD CordbProcess::GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout)
2475{
2476 if (pLayout == NULL)
2477 return E_POINTER;
2478
2479 HRESULT hr = S_OK;
2480 PUBLIC_API_BEGIN(this);
2481
2482 hr = GetProcess()->GetDAC()->GetTypeLayout(id, pLayout);
2483
2484 PUBLIC_API_END(hr);
2485 return hr;
2486}
2487
2488COM_METHOD CordbProcess::GetTypeFields(COR_TYPEID id, ULONG32 celt, COR_FIELD fields[], ULONG32 *pceltNeeded)
2489{
2490 HRESULT hr = S_OK;
2491 PUBLIC_API_BEGIN(this);
2492
2493 hr = GetProcess()->GetDAC()->GetObjectFields(id, celt, fields, pceltNeeded);
2494
2495 PUBLIC_API_END(hr);
2496 return hr;
2497}
2498
2499COM_METHOD CordbProcess::SetWriteableMetadataUpdateMode(WriteableMetadataUpdateMode flags)
2500{
2501 HRESULT hr = S_OK;
2502 PUBLIC_API_BEGIN(this);
2503
2504 if(flags != LegacyCompatPolicy &&
2505 flags != AlwaysShowUpdates)
2506 {
2507 hr = E_INVALIDARG;
2508 }
2509 else if(m_pShim != NULL)
2510 {
2511 if(flags != LegacyCompatPolicy)
2512 {
2513 hr = CORDBG_E_UNSUPPORTED;
2514 }
2515 }
2516
2517 if(SUCCEEDED(hr))
2518 {
2519 m_writableMetadataUpdateMode = flags;
2520 }
2521
2522 PUBLIC_API_END(hr);
2523 return hr;
2524}
2525
2526COM_METHOD CordbProcess::EnableExceptionCallbacksOutsideOfMyCode(BOOL enableExceptionsOutsideOfJMC)
2527{
2528 HRESULT hr = S_OK;
2529 PUBLIC_API_BEGIN(this);
2530
2531 hr = GetProcess()->GetDAC()->SetSendExceptionsOutsideOfJMC(enableExceptionsOutsideOfJMC);
2532
2533 PUBLIC_API_END(hr);
2534 return hr;
2535}
2536
2537COM_METHOD CordbProcess::EnableGCNotificationEvents(BOOL fEnable)
2538{
2539 HRESULT hr = S_OK;
2540 PUBLIC_API_BEGIN(this)
2541 {
2542 hr = this->m_pDacPrimitives->EnableGCNotificationEvents(fEnable);
2543 }
2544 PUBLIC_API_END(hr);
2545 return hr;
2546}
2547
2548#ifdef FEATURE_LEGACYNETCF_DBG_HOST_CONTROL
2549
2550COM_METHOD CordbProcess::InvokePauseCallback()
2551{
2552 return S_OK;
2553}
2554
2555COM_METHOD CordbProcess::InvokeResumeCallback()
2556{
2557 return S_OK;
2558}
2559
2560#endif
2561
2562HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbAppDomain* pAppDomainOverride, CordbType **ppType, CordbAppDomain **pAppDomain)
2563{
2564 VMPTR_AppDomain appDomain;
2565 VMPTR_Module mod;
2566 VMPTR_DomainFile domainFile;
2567
2568 HRESULT hr = E_FAIL;
2569 if (GetDAC()->GetAppDomainForObject(addr, &appDomain, &mod, &domainFile))
2570 {
2571 if (pAppDomainOverride)
2572 {
2573 appDomain = pAppDomainOverride->GetADToken();
2574 }
2575 CordbAppDomain *cdbAppDomain = appDomain.IsNull() ? GetSharedAppDomain() : LookupOrCreateAppDomain(appDomain);
2576
2577 _ASSERTE(cdbAppDomain);
2578
2579 DebuggerIPCE_ExpandedTypeData data;
2580 GetDAC()->GetObjectExpandedTypeInfo(AllBoxed, appDomain, addr, &data);
2581
2582 CordbType *type = 0;
2583 hr = CordbType::TypeDataToType(cdbAppDomain, &data, &type);
2584
2585 if (SUCCEEDED(hr))
2586 {
2587 *ppType = type;
2588 if (pAppDomain)
2589 *pAppDomain = cdbAppDomain;
2590 }
2591 }
2592
2593 return hr;
2594}
2595
2596
2597// ******************************************
2598// CordbRefEnum
2599// ******************************************
2600CordbRefEnum::CordbRefEnum(CordbProcess *proc, BOOL walkWeakRefs)
2601 : CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacksFQ(TRUE),
2602 mHandleMask((UINT32)(walkWeakRefs ? CorHandleAll : CorHandleStrongOnly))
2603{
2604}
2605
2606CordbRefEnum::CordbRefEnum(CordbProcess *proc, CorGCReferenceType types)
2607 : CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacksFQ(FALSE),
2608 mHandleMask((UINT32)types)
2609{
2610}
2611
2612void CordbRefEnum::Neuter()
2613{
2614 EX_TRY
2615 {
2616 if (mRefHandle)
2617 {
2618 GetProcess()->GetDAC()->DeleteRefWalk(mRefHandle);
2619 mRefHandle = 0;
2620 }
2621 }
2622 EX_CATCH
2623 {
2624 _ASSERTE(!"Hit an error freeing a ref walk.");
2625 }
2626 EX_END_CATCH(SwallowAllExceptions)
2627
2628 CordbBase::Neuter();
2629}
2630
2631HRESULT CordbRefEnum::QueryInterface(REFIID riid, void **ppInterface)
2632{
2633 if (ppInterface == NULL)
2634 return E_INVALIDARG;
2635
2636 if (riid == IID_ICorDebugGCReferenceEnum)
2637 {
2638 *ppInterface = static_cast<ICorDebugGCReferenceEnum*>(this);
2639 }
2640 else if (riid == IID_IUnknown)
2641 {
2642 *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugGCReferenceEnum*>(this));
2643 }
2644 else
2645 {
2646 *ppInterface = NULL;
2647 return E_NOINTERFACE;
2648 }
2649
2650 ExternalAddRef();
2651 return S_OK;
2652}
2653
2654HRESULT CordbRefEnum::Skip(ULONG celt)
2655{
2656 return E_NOTIMPL;
2657}
2658
2659HRESULT CordbRefEnum::Reset()
2660{
2661 PUBLIC_API_ENTRY(this);
2662 HRESULT hr = S_OK;
2663 EX_TRY
2664 {
2665 if (mRefHandle)
2666 {
2667 GetProcess()->GetDAC()->DeleteRefWalk(mRefHandle);
2668 mRefHandle = 0;
2669 }
2670 }
2671 EX_CATCH_HRESULT(hr);
2672
2673 return hr;
2674}
2675
2676HRESULT CordbRefEnum::Clone(ICorDebugEnum **ppEnum)
2677{
2678 return E_NOTIMPL;
2679}
2680
2681HRESULT CordbRefEnum::GetCount(ULONG *pcelt)
2682{
2683 return E_NOTIMPL;
2684}
2685
2686
2687//
2688
2689HRESULT CordbRefEnum::Next(ULONG celt, COR_GC_REFERENCE refs[], ULONG *pceltFetched)
2690{
2691 if (refs == NULL || pceltFetched == NULL)
2692 return E_POINTER;
2693
2694 CordbProcess *process = GetProcess();
2695 HRESULT hr = S_OK;
2696
2697 PUBLIC_API_ENTRY(this);
2698 FAIL_IF_NEUTERED(this);
2699 ATT_REQUIRE_STOPPED_MAY_FAIL(process);
2700
2701 RSLockHolder procLockHolder(process->GetProcessLock());
2702
2703 EX_TRY
2704 {
2705 if (!mRefHandle)
2706 hr = process->GetDAC()->CreateRefWalk(&mRefHandle, mEnumStacksFQ, mEnumStacksFQ, mHandleMask);
2707
2708 if (SUCCEEDED(hr))
2709 {
2710 DacGcReference dacRefs[32];
2711 ULONG toFetch = _countof(dacRefs);
2712 ULONG total = 0;
2713
2714 for (ULONG c = 0; SUCCEEDED(hr) && c < (celt/_countof(dacRefs) + 1); ++c)
2715 {
2716 // Fetch 32 references at a time, the last time, only fetch the remainder (that is, if
2717 // the user didn't fetch a multiple of 32).
2718 if (c == celt/_countof(dacRefs))
2719 toFetch = celt % _countof(dacRefs);
2720
2721 ULONG fetched = 0;
2722 hr = process->GetDAC()->WalkRefs(mRefHandle, toFetch, dacRefs, &fetched);
2723
2724 if (SUCCEEDED(hr))
2725 {
2726 for (ULONG i = 0; i < fetched; ++i)
2727 {
2728 CordbAppDomain *pDomain = process->LookupOrCreateAppDomain(dacRefs[i].vmDomain);
2729
2730 ICorDebugAppDomain *pAppDomain;
2731 ICorDebugValue *pOutObject = NULL;
2732 if (dacRefs[i].pObject & 1)
2733 {
2734 dacRefs[i].pObject &= ~1;
2735 ICorDebugObjectValue *pObjValue = NULL;
2736
2737 hr = process->GetObject(dacRefs[i].pObject, &pObjValue);
2738
2739 if (SUCCEEDED(hr))
2740 {
2741 hr = pObjValue->QueryInterface(IID_ICorDebugValue, (void**)&pOutObject);
2742 pObjValue->Release();
2743 }
2744 }
2745 else
2746 {
2747 ICorDebugReferenceValue *tmpValue = NULL;
2748 IfFailThrow(CordbReferenceValue::BuildFromGCHandle(pDomain,
2749 dacRefs[i].objHnd,
2750 &tmpValue));
2751
2752 if (SUCCEEDED(hr))
2753 {
2754 hr = tmpValue->QueryInterface(IID_ICorDebugValue, (void**)&pOutObject);
2755 tmpValue->Release();
2756 }
2757 }
2758
2759 if (SUCCEEDED(hr) && pDomain)
2760 {
2761 hr = pDomain->QueryInterface(IID_ICorDebugAppDomain, (void**)&pAppDomain);
2762 }
2763
2764 if (FAILED(hr))
2765 break;
2766
2767 refs[total].Domain = pAppDomain;
2768 refs[total].Location = pOutObject;
2769 refs[total].Type = (CorGCReferenceType)dacRefs[i].dwType;
2770 refs[total].ExtraData = dacRefs[i].i64ExtraData;
2771
2772 total++;
2773 }
2774 }
2775 }
2776
2777 *pceltFetched = total;
2778 }
2779 }
2780 EX_CATCH_HRESULT(hr);
2781
2782 return hr;
2783}
2784
2785
2786// ******************************************
2787// CordbHeapEnum
2788// ******************************************
2789CordbHeapEnum::CordbHeapEnum(CordbProcess *proc)
2790 : CordbBase(proc, 0, enumCordbHeap), mHeapHandle(0)
2791{
2792}
2793
2794HRESULT CordbHeapEnum::QueryInterface(REFIID riid, void **ppInterface)
2795{
2796 if (ppInterface == NULL)
2797 return E_INVALIDARG;
2798
2799 if (riid == IID_ICorDebugHeapEnum)
2800 {
2801 *ppInterface = static_cast<ICorDebugHeapEnum*>(this);
2802 }
2803 else if (riid == IID_IUnknown)
2804 {
2805 *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugHeapEnum*>(this));
2806 }
2807 else
2808 {
2809 *ppInterface = NULL;
2810 return E_NOINTERFACE;
2811 }
2812
2813 ExternalAddRef();
2814 return S_OK;
2815}
2816
2817HRESULT CordbHeapEnum::Skip(ULONG celt)
2818{
2819 return E_NOTIMPL;
2820}
2821
2822HRESULT CordbHeapEnum::Reset()
2823{
2824 Clear();
2825 return S_OK;
2826}
2827
2828void CordbHeapEnum::Clear()
2829{
2830 EX_TRY
2831 {
2832 if (mHeapHandle)
2833 {
2834 GetProcess()->GetDAC()->DeleteHeapWalk(mHeapHandle);
2835 mHeapHandle = 0;
2836 }
2837 }
2838 EX_CATCH
2839 {
2840 _ASSERTE(!"Hit an error freeing the heap walk.");
2841 }
2842 EX_END_CATCH(SwallowAllExceptions)
2843}
2844
2845HRESULT CordbHeapEnum::Clone(ICorDebugEnum **ppEnum)
2846{
2847 return E_NOTIMPL;
2848}
2849
2850HRESULT CordbHeapEnum::GetCount(ULONG *pcelt)
2851{
2852 return E_NOTIMPL;
2853}
2854
2855HRESULT CordbHeapEnum::Next(ULONG celt, COR_HEAPOBJECT objects[], ULONG *pceltFetched)
2856{
2857 HRESULT hr = S_OK;
2858 PUBLIC_API_ENTRY(this);
2859 RSLockHolder stopGoLock(this->GetProcess()->GetStopGoLock());
2860 RSLockHolder procLock(this->GetProcess()->GetProcessLock());
2861 ULONG fetched = 0;
2862
2863 EX_TRY
2864 {
2865 if (mHeapHandle == 0)
2866 {
2867 hr = GetProcess()->GetDAC()->CreateHeapWalk(&mHeapHandle);
2868 }
2869
2870 if (SUCCEEDED(hr))
2871 {
2872 hr = GetProcess()->GetDAC()->WalkHeap(mHeapHandle, celt, objects, &fetched);
2873 _ASSERTE(fetched <= celt);
2874 }
2875
2876 if (SUCCEEDED(hr))
2877 {
2878 // Return S_FALSE if we've reached the end of the enum.
2879 if (fetched < celt)
2880 hr = S_FALSE;
2881 }
2882 }
2883 EX_CATCH_HRESULT(hr);
2884
2885 // Set the fetched parameter to reflect the number of elements (if any)
2886 // that were successfully saved to "objects"
2887 if (pceltFetched)
2888 *pceltFetched = fetched;
2889
2890 return hr;
2891}
2892
2893//---------------------------------------------------------------------------------------
2894// Flush state for when the process starts running.
2895//
2896// Notes:
2897// Helper for code:CordbProcess::ProcessStateChanged.
2898// Since ICD Arrowhead does not own the eventing pipeline, it needs the debugger to
2899// notifying it of when the process is running again. This is like the counterpart
2900// to code:CordbProcess::Filter
2901void CordbProcess::FlushProcessRunning()
2902{
2903 _ASSERTE(GetProcessLock()->HasLock());
2904
2905 // Update the continue counter.
2906 m_continueCounter++;
2907
2908 // Safely dispose anything that should be neutered on continue.
2909 MarkAllThreadsDirty();
2910 ForceDacFlush();
2911}
2912
2913//---------------------------------------------------------------------------------------
2914// Flush all cached state and bring us back to "cold startup"
2915//
2916// Notes:
2917// Helper for code:CordbProcess::ProcessStateChanged.
2918// This is used if the data-target changes underneath us in a way that is
2919// not consistent with the process running forward. For example, if for
2920// a time-travel debugger, the data-target may flow "backwards" in time.
2921//
2922void CordbProcess::FlushAll()
2923{
2924 CONTRACTL
2925 {
2926 THROWS;
2927 }
2928 CONTRACTL_END;
2929
2930 HRESULT hr;
2931 _ASSERTE(GetProcessLock()->HasLock());
2932
2933 //
2934 // First, determine if it's safe to Flush
2935 //
2936
2937 hr = IsReadyForDetach();
2938 IfFailThrow(hr);
2939
2940 // Check for outstanding CordbHandle values.
2941 if (OutstandingHandles())
2942 {
2943 ThrowHR(CORDBG_E_DETACH_FAILED_OUTSTANDING_TARGET_RESOURCES);
2944 }
2945
2946 // FlushAll is a superset of FlushProcessRunning.
2947 // This will also ensure we clear the DAC cache.
2948 FlushProcessRunning();
2949
2950 // If we detach before the CLR is loaded into the debuggee, then we can no-op a lot of work.
2951 // We sure can't be sending IPC events to the LS before it exists.
2952 NeuterChildren();
2953}
2954
2955//---------------------------------------------------------------------------------------
2956//
2957// Detach the Debugger from the LS process.
2958//
2959//
2960// Return Value:
2961// S_OK on successful detach. Else errror.
2962//
2963// Assumptions:
2964// Target is stopped.
2965//
2966// Notes:
2967// Once we're detached, the LS can resume running and exit.
2968// So it's possible to get an ExitProcess callback in the middle of the Detach phase. If that happens,
2969// we must return CORDBG_E_PROCESS_TERMINATED and pretend that the exit happened before we tried to detach.
2970// Else if we detach successfully, return S_OK.
2971//
2972// @dbgtodo attach-bit: need to figure out semantics of Detach
2973// in V3, especially w.r.t to an attach bit.
2974//---------------------------------------------------------------------------------------
2975HRESULT CordbProcess::Detach()
2976{
2977 PUBLIC_API_ENTRY(this);
2978
2979 FAIL_IF_NEUTERED(this);
2980
2981 if (IsInteropDebugging())
2982 {
2983 return CORDBG_E_INTEROP_NOT_SUPPORTED;
2984 }
2985
2986
2987 HRESULT hr = S_OK;
2988 // A very important note: we require that the process is synchronized before doing a detach. This ensures
2989 // that no events are on their way from the Left Side. We also require that the user has drained the
2990 // managed event queue, but there is currently no way to really enforce that here.
2991 // @todo- why can't we enforce that the managed event Q is drained?
2992 ATT_REQUIRE_SYNCED_OR_NONINIT_MAY_FAIL(this);
2993
2994
2995 hr = IsReadyForDetach();
2996 if (FAILED(hr))
2997 {
2998 // Avoid neutering. Gives client a chance to fix detach issue and retry.
2999 return hr;
3000 }
3001
3002 // Since the detach may resume the LS and allow it to exit, which may invoke the EP callback
3003 // which may destroy this process object, be sure to protect us w/ an extra AddRef/Release
3004 RSSmartPtr<CordbProcess> pRef(this);
3005
3006
3007
3008 LOG((LF_CORDB, LL_INFO1000, "CP::Detach - beginning\n"));
3009 if (m_pShim == NULL) // This API is moved off to the shim
3010 {
3011
3012 // This is still invasive.
3013 // Ignore failures. This will fail for a non-invasive target.
3014 if (IsDacInitialized())
3015 {
3016 HRESULT hrIgnore = S_OK;
3017 EX_TRY
3018 {
3019 GetDAC()->MarkDebuggerAttached(FALSE);
3020 }
3021 EX_CATCH_HRESULT(hrIgnore);
3022 }
3023 }
3024 else
3025 {
3026 EX_TRY
3027 {
3028 DetachShim();
3029 }
3030 EX_CATCH_HRESULT(hr);
3031 }
3032
3033 // Either way, neuter everything.
3034 this->Neuter();
3035
3036 // Implicit release on pRef
3037 LOG((LF_CORDB, LL_INFO1000, "CP::Detach - returning w/ hr=0x%x\n", hr));
3038 return hr;
3039}
3040
3041// Free up key left-side resources
3042//
3043// Called on detach
3044// This does key neutering of objects that hold left-side resources and require
3045// preemptively freeing the resources.
3046// After this, code:CordbProcess::Neuter should only affect right-side state.
3047void CordbProcess::NeuterChildrenLeftSideResources()
3048{
3049 _ASSERTE(GetStopGoLock()->HasLock());
3050
3051 _ASSERTE(!GetProcessLock()->HasLock());
3052 RSLockHolder lockHolder(GetProcessLock());
3053
3054
3055 // Need process-lock to operate on hashtable, but can't yet Neuter under process-lock,
3056 // so we have to copy the contents to an auxilary list which we can then traverse outside the lock.
3057 RSPtrArray<CordbAppDomain> listAppDomains;
3058 m_appDomains.CopyToArray(&listAppDomains);
3059
3060
3061
3062 // Must not hold process lock so that we can be safe to send IPC events
3063 // to cleanup left-side resources.
3064 lockHolder.Release();
3065 _ASSERTE(!GetProcessLock()->HasLock());
3066
3067 // Frees left-side resources. This may send IPC events.
3068 // This will make normal neutering a nop.
3069 m_LeftSideResourceCleanupList.NeuterLeftSideResourcesAndClear(this);
3070
3071 for(unsigned int idx = 0; idx < listAppDomains.Length(); idx++)
3072 {
3073 CordbAppDomain * pAppDomain = listAppDomains[idx];
3074
3075 // CordbHandleValue is in the appdomain exit list, and that needs
3076 // to send an IPC event to cleanup and release the handle from
3077 // the GCs handle table.
3078 pAppDomain->GetSweepableExitNeuterList()->NeuterLeftSideResourcesAndClear(this);
3079 }
3080 listAppDomains.Clear();
3081
3082}
3083
3084//---------------------------------------------------------------------------------------
3085// Detach the Debugger from the LS process for the V2 case
3086//
3087// Assumptions:
3088// This will NeuterChildren(), caller will do the real Neuter()
3089// Caller has already ensured that detach is safe.
3090//
3091// @dbgtodo attach-bit: this should be moved into the shim; need
3092// to figure out semantics for freeing left-side resources (especially GC
3093// handles) on detach.
3094void CordbProcess::DetachShim()
3095{
3096
3097 HASHFIND hashFind;
3098 HRESULT hr = S_OK;
3099
3100 // If we detach before the CLR is loaded into the debuggee, then we can no-op a lot of work.
3101 // We sure can't be sending IPC events to the LS before it exists.
3102 if (m_initialized)
3103 {
3104 // The managed event queue is not necessarily drained. Cordbg could call detach between any callback.
3105 // While the process is still stopped, neuter all of our children.
3106 // This will make our Neuter() a nop and saves the W32ET from having to do dangerous work.
3107 this->NeuterChildrenLeftSideResources();
3108 {
3109 RSLockHolder lockHolder(GetProcessLock());
3110 this->NeuterChildren();
3111 }
3112
3113 // Go ahead and detach from the entire process now. This is like sending a "Continue".
3114 DebuggerIPCEvent * pIPCEvent = (DebuggerIPCEvent *) _alloca(CorDBIPC_BUFFER_SIZE);
3115 InitIPCEvent(pIPCEvent, DB_IPCE_DETACH_FROM_PROCESS, true, VMPTR_AppDomain::NullPtr());
3116
3117 hr = m_cordb->SendIPCEvent(this, pIPCEvent, CorDBIPC_BUFFER_SIZE);
3118 hr = WORST_HR(hr, pIPCEvent->hr);
3119 IfFailThrow(hr);
3120 }
3121 else
3122 {
3123 // @dbgtodo attach-bit: push this up, once detach IPC event is hoisted.
3124 RSLockHolder lockHolder(GetProcessLock());
3125
3126 // Shouldn't have any appdomains.
3127 (void)hashFind; //prevent "unused variable" error from GCC
3128 _ASSERTE(m_appDomains.FindFirst(&hashFind) == NULL);
3129 }
3130
3131 LOG((LF_CORDB, LL_INFO10000, "CP::Detach - got reply from LS\n"));
3132
3133 // It's possible that the LS may exit after they reply to our detach_from_process, but
3134 // before we update our internal state that they're detached. So still have to check
3135 // failure codes here.
3136 hr = this->m_pShim->GetWin32EventThread()->SendDetachProcessEvent(this);
3137
3138
3139 // Since we're auto-continuing when we detach, we should set the stop count back to zero.
3140 // This (along w/ m_detached) prevents anyone from calling Continue on this process
3141 // after this call returns.
3142 m_stopCount = 0;
3143
3144 if (hr != CORDBG_E_PROCESS_TERMINATED)
3145 {
3146 // Remember that we've detached from this process object. This will prevent any further operations on
3147 // this process, just in case... :)
3148 // If LS exited, then don't set this flag because it overrides m_terminated when reporting errors;
3149 // and we want to provide a consistent story about whether we detached or whether the LS exited.
3150 m_detached = true;
3151 }
3152 IfFailThrow(hr);
3153
3154
3155 // Now that all complicated cleanup is done, caller can do a final neuter.
3156 // This will implicitly stop our Win32 event thread as well.
3157}
3158
3159// Delete all events from the queue without dispatching. This is useful in shutdown.
3160// An event that is currently dispatching is not on the queue.
3161void CordbProcess::DeleteQueuedEvents()
3162{
3163 INTERNAL_API_ENTRY(this);
3164 // We must have the process lock to ensure that no one is trying to add an event
3165 _ASSERTE(!ThreadHoldsProcessLock());
3166
3167 if (m_pShim != NULL)
3168 {
3169 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(this);
3170
3171 // DeleteAll() is part of the shim, and it will change external ref counts, so must really
3172 // be marked as outside the RS.
3173 m_pShim->GetManagedEventQueue()->DeleteAll();
3174 }
3175}
3176
3177//---------------------------------------------------------------------------------------
3178//
3179// Track that we're about to dispatch a managed event.
3180//
3181// Arguments:
3182// event - event being dispatched
3183//
3184// Assumptions:
3185// This is used to support code:CordbProcess::AreDispatchingEvent
3186// This is always called on the same thread as code:CordbProcess::FinishEventDispatch
3187void CordbProcess::StartEventDispatch(DebuggerIPCEventType event)
3188{
3189 LIMITED_METHOD_CONTRACT;
3190
3191 _ASSERTE(m_dispatchedEvent == DB_IPCE_DEBUGGER_INVALID);
3192 _ASSERTE(event != DB_IPCE_DEBUGGER_INVALID);
3193 m_dispatchedEvent = event;
3194}
3195
3196//---------------------------------------------------------------------------------------
3197//
3198// Track that we're done dispatching a managed event.
3199//
3200//
3201// Assumptions:
3202// This is always called on the same thread as code:CordbProcess::StartEventDispatch
3203//
3204// Notes:
3205// @dbgtodo shim: eventually this goes into the shim when we hoist Continue
3206void CordbProcess::FinishEventDispatch()
3207{
3208 LIMITED_METHOD_CONTRACT;
3209
3210 _ASSERTE(m_dispatchedEvent != DB_IPCE_DEBUGGER_INVALID);
3211 m_dispatchedEvent = DB_IPCE_DEBUGGER_INVALID;
3212}
3213
3214//---------------------------------------------------------------------------------------
3215//
3216// Are we in the middle of dispatching an event?
3217//
3218// Notes:
3219// This is used by code::CordbProcess::ContinueInternal. Continue logic takes
3220// a shortcut if the continue is called on the dispatch thread.
3221// It doesn't matter which event is being dispatch; only that we're on the dispatch thread.
3222// @dbgtodo shim: eventually this goes into the shim when we hoist Continue
3223bool CordbProcess::AreDispatchingEvent()
3224{
3225 LIMITED_METHOD_CONTRACT;
3226
3227 return m_dispatchedEvent != DB_IPCE_DEBUGGER_INVALID;
3228}
3229
3230
3231
3232
3233
3234// Terminate the app. We'll still dispatch an ExitProcess callback, so the app
3235// must wait for that before calling Cordb::Terminate.
3236// If this fails, the client can always call the OS's TerminateProcess command
3237// to rudely kill the debuggee.
3238HRESULT CordbProcess::Terminate(unsigned int exitCode)
3239{
3240 PUBLIC_API_ENTRY(this);
3241
3242 LOG((LF_CORDB, LL_INFO1000, "CP::Terminate: with exitcode %u\n", exitCode));
3243 FAIL_IF_NEUTERED(this);
3244
3245
3246 // @dbgtodo shutdown: eventually, all of Terminate() will be in the Shim.
3247 // Free all the remaining events. Since this will call into the shim, do this outside of any locks.
3248 // (ATT_ takes locks).
3249 DeleteQueuedEvents();
3250
3251 ATT_REQUIRE_SYNCED_OR_NONINIT_MAY_FAIL(this);
3252
3253 // When we terminate the process, it's handle will become signaled and
3254 // Win32 Event Thread will leap into action and call CordbWin32EventThread::ExitProcess
3255 // Unfortunately, that may destroy this object if the ExitProcess callback
3256 // decides to call Release() on the process.
3257
3258
3259 // Indicate that the process is exiting so that (among other things) we don't try and
3260 // send messages to the left side while it's being deleted.
3261 Lock();
3262
3263 // In case we're continuing from the loader bp, we don't want to try and kick off an attach. :)
3264 m_fDoDelayedManagedAttached = false;
3265 m_exiting = true;
3266
3267
3268
3269 // We'd like to just take a lock around everything here, but that may deadlock us
3270 // since W32ET will wait on the lock, and Continue may wait on W32ET.
3271 // So we just do an extra AddRef/Release to make sure we're still around.
3272 // @todo - could we move this smartptr up so that it's well-nested w/ the lock?
3273 RSSmartPtr<CordbProcess> pRef(this);
3274
3275 Unlock();
3276
3277
3278 // At any point after this call, the w32 ET may run the ExitProcess code which will race w/ the continue call.
3279 // This call only posts a request that the process terminate and does not guarantee the process actually
3280 // terminates. In particular, the process can not exit until any outstanding IO requests are done (on cancelled).
3281 // It also can not exit if we have an outstanding not-continued native-debug event.
3282 // Fortunately, the interesting work in terminate is done in ExitProcessWorkItem::Do, which can take the Stop-Go lock.
3283 // Since we're currently holding the stop-go lock, that means we at least get some serialization.
3284 //
3285 // Note that on Windows, the process isn't really terminated until we receive the EXIT_PROCESS_DEBUG_EVENT.
3286 // Before then, we can still still access the debuggee's address space. On the other, for Mac debugging,
3287 // the process can die any time after this call, and so we can no longer call into the DAC.
3288 GetShim()->GetNativePipeline()->TerminateProcess(exitCode);
3289
3290 // We just call Continue() so that the debugger doesn't have to. (It's arguably odd
3291 // to call Continue() after Terminate).
3292 // We're stopped & Synced.
3293 // For interop-debugging this is very important because the Terminate may not really kill the process
3294 // until after we continue from the current native debug event.
3295 ContinueInternal(FALSE);
3296
3297 // Implicit release on pRef here (since it's going out of scope)...
3298 // After this release, this object may be destroyed. So don't use any member functions
3299 // (including Locks) after here.
3300
3301
3302 return S_OK;
3303}
3304
3305// This can be called at any time, even if we're in an unrecoverable error state.
3306HRESULT CordbProcess::GetID(DWORD *pdwProcessId)
3307{
3308 PUBLIC_REENTRANT_API_ENTRY(this);
3309 OK_IF_NEUTERED(this);
3310 VALIDATE_POINTER_TO_OBJECT(pdwProcessId, DWORD *);
3311
3312 HRESULT hr = S_OK;
3313 EX_TRY
3314 {
3315 // This shouldn't be used in V3 paths. Normally, we can enforce that by checking against
3316 // m_pShim. However, this API can be called after being neutered, in which case m_pShim is cleared.
3317 // So check against 0 instead.
3318 if (m_id == 0)
3319 {
3320 *pdwProcessId = 0;
3321 ThrowHR(E_NOTIMPL);
3322 }
3323 *pdwProcessId = GetProcessDescriptor()->m_Pid;
3324 }
3325 EX_CATCH_HRESULT(hr);
3326 return hr;
3327}
3328
3329// Helper to get process descriptor internally. We know we'll always succeed.
3330// This is more convient for internal callers since they can just use it as an expression
3331// without having to check HRESULTS.
3332const ProcessDescriptor* CordbProcess::GetProcessDescriptor()
3333{
3334 // This shouldn't be used in V3 paths, in which case it's set to 0. Only the shim should be
3335 // calling this. Assert to catch anybody else.
3336 _ASSERTE(m_processDescriptor.IsInitialized());
3337
3338 return &m_processDescriptor;
3339}
3340
3341
3342HRESULT CordbProcess::GetHandle(HANDLE *phProcessHandle)
3343{
3344 PUBLIC_REENTRANT_API_ENTRY(this);
3345 FAIL_IF_NEUTERED(this); // Once we neuter the process, we close our OS handle to it.
3346 VALIDATE_POINTER_TO_OBJECT(phProcessHandle, HANDLE *);
3347
3348 if (m_pShim == NULL)
3349 {
3350 _ASSERTE(!"CordbProcess::GetHandle() should be not be called on the new architecture");
3351 *phProcessHandle = NULL;
3352 return E_NOTIMPL;
3353 }
3354 else
3355 {
3356 *phProcessHandle = m_handle;
3357 return S_OK;
3358 }
3359}
3360
3361HRESULT CordbProcess::IsRunning(BOOL *pbRunning)
3362{
3363 PUBLIC_API_ENTRY(this);
3364 FAIL_IF_NEUTERED(this);
3365 VALIDATE_POINTER_TO_OBJECT(pbRunning, BOOL*);
3366
3367 *pbRunning = !GetSynchronized();
3368
3369 return S_OK;
3370}
3371
3372HRESULT CordbProcess::EnableSynchronization(BOOL bEnableSynchronization)
3373{
3374 /* !!! */
3375 PUBLIC_API_ENTRY(this);
3376 return E_NOTIMPL;
3377}
3378
3379HRESULT CordbProcess::Stop(DWORD dwTimeout)
3380{
3381 PUBLIC_API_ENTRY(this);
3382 CORDBRequireProcessStateOK(this);
3383
3384 HRESULT hr = StopInternal(dwTimeout, VMPTR_AppDomain::NullPtr());
3385
3386 return ErrWrapper(hr);
3387}
3388
3389HRESULT CordbProcess::StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainToken)
3390{
3391 LOG((LF_CORDB, LL_INFO1000, "CP::S: stopping process 0x%x(%d) with timeout %d\n", m_id, m_id, dwTimeout));
3392
3393 INTERNAL_API_ENTRY(this);
3394
3395 // Stop + Continue are executed under the Stop-Go lock. This makes them atomic.
3396 // We'll toggle the process-lock (b/c we communicate w/ the W32et, so just the process-lock is
3397 // not sufficient to make this atomic).
3398 // It's ok to take this lock before checking if the CordbProcess has been neutered because
3399 // the lock is destroyed in the dtor after neutering.
3400 RSLockHolder ch(&m_StopGoLock);
3401
3402 // Check if this CordbProcess has been neutered under the SG lock.
3403 // Otherwise it's possible to race with Detach() and Terminate().
3404 FAIL_IF_NEUTERED(this);
3405 CORDBFailIfOnWin32EventThread(this);
3406
3407 if (m_pShim == NULL) // Stop/Go is moved off to the shim
3408 {
3409 return E_NOTIMPL;
3410 }
3411
3412
3413 DebuggerIPCEvent* event;
3414 HRESULT hr = S_OK;
3415
3416 STRESS_LOG2(LF_CORDB, LL_INFO1000, "CP::SI, timeout=%d, this=%p\n", dwTimeout, this);
3417
3418 // Stop() is a syncronous (blocking) operation. Furthermore, we have no way to cancel the async-break request.
3419 // Thus if we returned early on a timeout, then we'll be in a random state b/c the LS may get stopped at any
3420 // later spot.
3421 // One solution just require the param is INFINITE until we fix this and E_INVALIDARG if it's not.
3422 // But that could be a breaking change (what if a debugger passes in a really large value that's effectively
3423 // INFINITE).
3424 // So we'll just ignore it and always treat it as infinite.
3425 dwTimeout = INFINITE;
3426
3427 // Do the checks on the process state under the SG lock. This ensures that another thread cannot come in
3428 // after we do the checks and take the lock before we do. For example, Detach() can race with Stop() such
3429 // that:
3430 // 1. Thread A calls CordbProcess::Detach() and takes the stop-go lock
3431 // 2. Thread B calls CordbProcess::Stop(), passes all the checks, and then blocks on the stop-go lock
3432 // 3. Thread A finishes the detach, invalides the process state, cleans all the resources, and then
3433 // releases the stop-go lock
3434 // 4. Thread B gets the lock, but everything has changed
3435 CORDBRequireProcessStateOK(this);
3436
3437 Lock();
3438
3439 ASSERT_SINGLE_THREAD_ONLY(HoldsLock(&m_StopGoLock));
3440
3441 // Don't need to stop if the process hasn't even executed any managed code yet.
3442 if (!m_initialized)
3443 {
3444 LOG((LF_CORDB, LL_INFO1000, "CP::S: process isn't initialized yet.\n"));
3445
3446 // Mark the process as synchronized so no events will be dispatched until the thing is continued.
3447 SetSynchronized(true);
3448
3449 // Remember uninitialized stop...
3450 m_uninitializedStop = true;
3451
3452#ifdef FEATURE_INTEROP_DEBUGGING
3453 // If we're Win32 attached, then suspend all the unmanaged threads in the process.
3454 // We may or may not be stopped at a native debug event.
3455 if (IsInteropDebugging())
3456 {
3457 SuspendUnmanagedThreads();
3458 }
3459#endif // FEATURE_INTEROP_DEBUGGING
3460
3461 // Get the RC Event Thread to stop listening to the process.
3462 m_cordb->ProcessStateChanged();
3463
3464 hr = S_OK;
3465 goto Exit;
3466 }
3467
3468 // Don't need to stop if the process is already synchronized.
3469 // @todo - Issue 129917. It's possible that we'll get a call to Stop when the LS is already stopped.
3470 // Sending an AsyncBreak would deadlock here (b/c the LS will ignore the frivilous request,
3471 // and thus never send a SyncComplete, and thus our Waiting on the SyncComplete will deadlock).
3472 // We avoid this case by checking m_syncCompleteReceived (which should roughly correspond to
3473 // the LS's m_stopped variable).
3474 // One window this can happen is after a Continue() pings the RCET but before the RCET actually sweeps + flushes.
3475
3476 if (GetSynchronized() || GetSyncCompleteRecv())
3477 {
3478 LOG((LF_CORDB, LL_INFO1000, "CP::S: process was already synchronized. m_syncCompleteReceived=%d\n", GetSyncCompleteRecv()));
3479
3480 if (GetSyncCompleteRecv())
3481 {
3482 // We must be in that window alluded to above (while the RCET is sweeping). Re-ping the RCET.
3483 SetSynchronized(true);
3484 m_cordb->ProcessStateChanged();
3485 }
3486 hr = S_OK;
3487 goto Exit;
3488 }
3489
3490 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::S: process not sync'd, requesting stop.\n");
3491
3492 m_stopRequested = true;
3493
3494 // We don't want to dispatch any Win32 debug events while we're trying to stop.
3495 // Setting m_specialDeferment=true means that any debug event we get will be queued and not dispatched.
3496 // We do this to avoid a nested call to Continue.
3497 // These defered events will get dispatched when somebody calls continue (and since they're calling
3498 // stop now, they must call continue eventually).
3499 // Note that if we got a Win32 debug event between when we took the Stop-Go lock above and now,
3500 // that even may have been dispatched. We're ok because SSFW32Stop will hijack that event and continue it,
3501 // and then all future events will be queued.
3502 m_specialDeferment = true;
3503 Unlock();
3504
3505 BOOL asyncBreakSent;
3506
3507 // We need to ensure that the helper thread is alive.
3508 hr = this->StartSyncFromWin32Stop(&asyncBreakSent);
3509 if (FAILED(hr))
3510 {
3511 return hr;
3512 }
3513
3514
3515 if (asyncBreakSent)
3516 {
3517 hr = S_OK;
3518 Lock();
3519
3520 m_stopRequested = false;
3521
3522 goto Exit;
3523 }
3524
3525 // Send the async break event to the RC.
3526 event = (DebuggerIPCEvent*) _alloca(CorDBIPC_BUFFER_SIZE);
3527 InitIPCEvent(event, DB_IPCE_ASYNC_BREAK, false, pAppDomainToken);
3528
3529 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::S: sending async stop to appd 0x%x.\n", VmPtrToCookie(pAppDomainToken));
3530
3531 hr = m_cordb->SendIPCEvent(this, event, CorDBIPC_BUFFER_SIZE);
3532 hr = WORST_HR(hr, event->hr);
3533 if (FAILED(hr))
3534 {
3535 // We don't hold the lock so just return immediately. Don't adjust stop-count.
3536 _ASSERTE(!ThreadHoldsProcessLock());
3537 return hr;
3538 }
3539
3540 LOG((LF_CORDB, LL_INFO1000, "CP::S: sent async stop to appd 0x%x.\n", VmPtrToCookie(pAppDomainToken)));
3541
3542 // Wait for the sync complete message to come in. Note: when the sync complete message arrives to the RCEventThread,
3543 // it will mark the process as synchronized and _not_ dispatch any events. Instead, it will set m_stopWaitEvent
3544 // which will let this function return. If the user wants to process any queued events, they will need to call
3545 // Continue.
3546 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::S: waiting for event.\n");
3547
3548 DWORD ret;
3549 ret = SafeWaitForSingleObject(this, m_stopWaitEvent, dwTimeout);
3550
3551 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::S: got event, %d.\n", ret);
3552
3553 if (m_terminated)
3554 {
3555 return CORDBG_E_PROCESS_TERMINATED;
3556 }
3557
3558 if (ret == WAIT_OBJECT_0)
3559 {
3560 LOG((LF_CORDB, LL_INFO1000, "CP::S: process stopped.\n"));
3561
3562 m_stopRequested = false;
3563 m_cordb->ProcessStateChanged();
3564
3565 hr = S_OK;
3566 Lock();
3567 goto Exit;
3568 }
3569 else if (ret == WAIT_TIMEOUT)
3570 {
3571 hr = ErrWrapper(CORDBG_E_TIMEOUT);
3572 }
3573 else
3574 hr = HRESULT_FROM_GetLastError();
3575
3576 // We came out of the wait, but we weren't signaled because a sync complete event came in. Re-check the process and
3577 // remove the stop requested flag.
3578 Lock();
3579 m_stopRequested = false;
3580
3581 if (GetSynchronized())
3582 {
3583 LOG((LF_CORDB, LL_INFO1000, "CP::S: process stopped.\n"));
3584
3585 m_cordb->ProcessStateChanged();
3586
3587 hr = S_OK;
3588 }
3589
3590Exit:
3591 _ASSERTE(ThreadHoldsProcessLock());
3592
3593 // Stop queuing any Win32 Debug events. We should be synchronized now.
3594 m_specialDeferment = false;
3595
3596 if (SUCCEEDED(hr))
3597 {
3598 IncStopCount();
3599 }
3600
3601 STRESS_LOG2(LF_CORDB, LL_INFO1000, "CP::S: returning from Stop, hr=0x%08x, m_stopCount=%d.\n", hr, GetStopCount());
3602
3603 Unlock();
3604
3605 return hr;
3606}
3607
3608//---------------------------------------------------------------------------------------
3609// Clear all RS state on all CordbThread objects.
3610//
3611// Notes:
3612// This clears all the thread-related state that the RS may have cached,
3613// such as locals, frames, etc.
3614// This would be called if the debugger is resuming execution.
3615void CordbProcess::MarkAllThreadsDirty()
3616{
3617 INTERNAL_API_ENTRY(this);
3618 _ASSERTE(ThreadHoldsProcessLock());
3619
3620 CordbThread * pThread;
3621 HASHFIND find;
3622
3623 // We don't need to prepopulate here (to collect LS state) because we're just updating RS state.
3624 for (pThread = m_userThreads.FindFirst(&find);
3625 pThread != NULL;
3626 pThread = m_userThreads.FindNext(&find))
3627 {
3628 _ASSERTE(pThread != NULL);
3629 pThread->MarkStackFramesDirty();
3630 }
3631
3632 ClearPatchTable();
3633}
3634
3635HRESULT CordbProcess::Continue(BOOL fIsOutOfBand)
3636{
3637 PUBLIC_API_ENTRY(this);
3638
3639 if (m_pShim == NULL) // This API is moved off to the shim
3640 {
3641 // bias towards failing with CORDBG_E_NUETERED.
3642 FAIL_IF_NEUTERED(this);
3643 return E_NOTIMPL;
3644 }
3645
3646 HRESULT hr;
3647
3648 if (fIsOutOfBand)
3649 {
3650#ifdef FEATURE_INTEROP_DEBUGGING
3651 hr = ContinueOOB();
3652#else
3653 hr = E_INVALIDARG;
3654#endif // FEATURE_INTEROP_DEBUGGING
3655 }
3656 else
3657 {
3658 hr = ContinueInternal(fIsOutOfBand);
3659 }
3660
3661 return hr;
3662}
3663
3664#ifdef FEATURE_INTEROP_DEBUGGING
3665//---------------------------------------------------------------------------------------
3666//
3667// ContinueOOB
3668//
3669// Continue the Win32 event as an out-of-band event.
3670//
3671// Return Value:
3672// S_OK on successful continue. Else error.
3673//
3674//---------------------------------------------------------------------------------------
3675HRESULT CordbProcess::ContinueOOB()
3676{
3677 INTERNAL_API_ENTRY(this);
3678 FAIL_IF_NEUTERED(this);
3679
3680 HRESULT hr = S_OK;
3681
3682 // If we're continuing from an out-of-band unmanaged event, then just go
3683 // ahead and get the Win32 event thread to continue the process. No other
3684 // work needs to be done (i.e., don't need to send a managed continue message
3685 // or dispatch any events) because any processing done due to the out-of-band
3686 // message can't alter the synchronized state of the process.
3687
3688 Lock();
3689 _ASSERTE(m_outOfBandEventQueue != NULL);
3690
3691 // Are we calling this from the unmanaged callback?
3692 if (m_dispatchingOOBEvent)
3693 {
3694 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: continue while dispatching unmanaged out-of-band event.\n");
3695 // We don't know what thread we're on here.
3696
3697 // Tell the Win32 event thread to continue when it returns from handling its unmanaged callback.
3698 m_dispatchingOOBEvent = false;
3699
3700 Unlock();
3701 }
3702 else
3703 {
3704 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: continue outside of dispatching.\n");
3705
3706 // If we're not dispatching this, then they shouldn't be on the win32 event thread.
3707 _ASSERTE(!this->IsWin32EventThread());
3708
3709 Unlock();
3710
3711 // Send an event to the Win32 event thread to do the continue. This is an out-of-band continue.
3712 hr = this->m_pShim->GetWin32EventThread()->SendUnmanagedContinue(this, cOobUMContinue);
3713 }
3714
3715 return hr;
3716
3717
3718}
3719#endif // FEATURE_INTEROP_DEBUGGING
3720
3721//---------------------------------------------------------------------------------------
3722//
3723// ContinueInternal
3724//
3725// Continue the Win32 event.
3726//
3727// Return Value:
3728// S_OK on success. Else error.
3729//
3730//---------------------------------------------------------------------------------------
3731HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand)
3732{
3733 INTERNAL_API_ENTRY(this);
3734 FAIL_IF_NEUTERED(this);
3735
3736 // Continue has an ATT similar to ATT_REQUIRE_STOPPED_MAY_FAIL, but w/ some subtle differences.
3737 // - if we're stopped at a native DE, but not synchronized, we don't want to sync.
3738 // - We may get Debug events (especially native ones) at weird times, and thus we have to continue
3739 // at weird times.
3740
3741 // External APIs should not have the process lock.
3742 _ASSERTE(!ThreadHoldsProcessLock());
3743 _ASSERTE(m_pShim != NULL);
3744
3745 // OutOfBand should use ContinueOOB
3746 _ASSERTE(!fIsOutOfBand);
3747
3748 // Since Continue is process-wide, just use a null appdomain pointer.
3749 VMPTR_AppDomain pAppDomainToken = VMPTR_AppDomain::NullPtr();
3750
3751 HRESULT hr = S_OK;
3752
3753 if (m_unrecoverableError)
3754 {
3755 return CORDBHRFromProcessState(this, NULL);
3756 }
3757
3758
3759 // We can't call ContinueInternal for an inband event on the win32 event thread.
3760 // This is an issue in the CLR (or an API design decision, depending on your perspective).
3761 // Continue() may send an IPC event and we can't do that on the win32 event thread.
3762
3763 CORDBFailIfOnWin32EventThread(this);
3764
3765 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::CI: continuing IB, this=0x%X\n", this);
3766
3767 // Stop + Continue are executed under the Stop-Go lock. This makes them atomic.
3768 // We'll toggle the process-lock (b/c we communicate w/ the W32et, so that's not sufficient).
3769 RSLockHolder rsLockHolder(&m_StopGoLock);
3770
3771 // Check for other failures (do these after we have the SG lock).
3772 if (m_terminated)
3773 {
3774 return CORDBG_E_PROCESS_TERMINATED;
3775 }
3776 if (m_detached)
3777 {
3778 return CORDBG_E_PROCESS_DETACHED;
3779 }
3780
3781 Lock();
3782
3783 ASSERT_SINGLE_THREAD_ONLY(HoldsLock(&m_StopGoLock));
3784 _ASSERTE(fIsOutOfBand == FALSE);
3785
3786 // If we've got multiple Stop calls, we need a Continue for each one. So, if the stop count > 1, just go ahead and
3787 // return without doing anything. Note: this is only for in-band or managed events. OOB events are still handled as
3788 // normal above.
3789 _ASSERTE(GetStopCount() > 0);
3790
3791 if (GetStopCount() == 0)
3792 {
3793 Unlock();
3794 _ASSERTE(!"Superflous Continue. ICorDebugProcess.Continue() called too many times");
3795 return CORDBG_E_SUPERFLOUS_CONTINUE;
3796 }
3797
3798 DecStopCount();
3799
3800 // We give managed events priority over unmanaged events. That way, the entire queued managed state can drain before
3801 // we let any other unmanaged events through.
3802
3803 // Every stop or event must be matched by a corresponding Continue. m_stopCount counts outstanding stopping events
3804 // along with calls to Stop. If the count is high at this point, we simply return. This ensures that even if someone
3805 // calls Stop just as they're receiving an event that they can call Continue for that Stop and for that event
3806 // without problems.
3807 if (GetStopCount() > 0)
3808 {
3809 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::CI: m_stopCount=%d, Continue just returning S_OK...\n", GetStopCount());
3810
3811 Unlock();
3812 return S_OK;
3813 }
3814
3815 // We're no longer stopped, so reset the m_stopWaitEvent.
3816 ResetEvent(m_stopWaitEvent);
3817
3818 // If we're continuing from an uninitialized stop, then we don't need to do much at all. No event need be sent to
3819 // the Left Side (duh, it isn't even there yet.) We just need to get the RC Event Thread to start listening to the
3820 // process again, and resume any unmanaged threads if necessary.
3821 if (m_uninitializedStop)
3822 {
3823 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: continuing from uninitialized stop.\n");
3824
3825 // No longer synchronized (it was a partial sync in the first place.)
3826 SetSynchronized(false);
3827 MarkAllThreadsDirty();
3828
3829 // No longer in an uninitialized stop.
3830 m_uninitializedStop = false;
3831
3832 // Notify the RC Event Thread.
3833 m_cordb->ProcessStateChanged();
3834
3835 Unlock();
3836
3837#ifdef FEATURE_INTEROP_DEBUGGING
3838 // We may or may not have a native debug event queued here.
3839 // If Cordbg called Stop() from a native debug event (to get the process Synchronized), then
3840 // we'll have a native debug event, and we need to continue it.
3841 // If Cordbg called Stop() to do an AsyncBreak, then there's no native-debug event.
3842
3843 // If we're Win32 attached, resume all the unmanaged threads.
3844 if (IsInteropDebugging())
3845 {
3846 if(m_lastDispatchedIBEvent != NULL)
3847 {
3848 m_lastDispatchedIBEvent->SetState(CUES_UserContinued);
3849 }
3850
3851 // Send to the Win32 event thread to do the unmanaged continue for us.
3852 // If we're at a debug event, this will continue it.
3853 // Else it will degenerate into ResumeUnmanagedThreads();
3854 this->m_pShim->GetWin32EventThread()->SendUnmanagedContinue(this, cRealUMContinue);
3855 }
3856#endif // FEATURE_INTEROP_DEBUGGING
3857
3858
3859 return S_OK;
3860 }
3861
3862 // If there are more managed events, get them dispatched now.
3863 if (!m_pShim->GetManagedEventQueue()->IsEmpty() && GetSynchronized())
3864 {
3865 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: managed event queued.\n");
3866
3867 // Mark that we're not synchronized anymore.
3868 SetSynchronized(false);
3869
3870 // If the callback queue is not empty, then the LS is not actually continuing, and so our cached
3871 // state is still valid.
3872
3873 // If we're in the middle of dispatching a managed event, then simply return. This indicates to HandleRCEvent
3874 // that the user called Continue and HandleRCEvent will dispatch the next queued event. But if Continue was
3875 // called outside the managed callback, all we have to do is tell the RC event thread that something about the
3876 // process has changed and it will dispatch the next managed event.
3877 if (!AreDispatchingEvent())
3878 {
3879 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: continuing while not dispatching managed event.\n");
3880
3881 m_cordb->ProcessStateChanged();
3882 }
3883
3884 Unlock();
3885 return S_OK;
3886 }
3887
3888 // Neuter if we have an outstanding object.
3889 // Only do this if we're really continuining the debuggee. So don't do this if our stop-count is high b/c we
3890 // shouldn't neuter until we're done w/ the current event. And don't do this until we drain the current callback queue.
3891 // Note that we can't hold the process lock while we do this b/c Neutering may send IPC events.
3892 // However, we're still under the StopGo lock b/c that may help us serialize things.
3893
3894 // Sweep neuter list. This will catch anything that's marked as 'safe to neuter'. This includes
3895 // all objects added to the 'neuter-on-Continue'.
3896 // Only do this if we're synced- we don't want to do this if we're continuing from a Native Debug event.
3897 if (GetSynchronized())
3898 {
3899 // Need process-lock to operate on hashtable, but can't yet Neuter under process-lock,
3900 // so we have to copy the contents to an auxilary list which we can then traverse outside the lock.
3901 RSPtrArray<CordbAppDomain> listAppDomains;
3902 HRESULT hrCopy = S_OK;
3903 EX_TRY // @dbgtodo cleanup: push this up
3904 {
3905 m_appDomains.CopyToArray(&listAppDomains);
3906 }
3907 EX_CATCH_HRESULT(hrCopy);
3908 SetUnrecoverableIfFailed(GetProcess(), hrCopy);
3909
3910 m_ContinueNeuterList.NeuterAndClear(this);
3911
3912 // @dbgtodo left-side resources: eventually (once
3913 // NeuterLeftSideResources is process-lock safe), do this all under the
3914 // lock. Can't hold process lock b/c neutering left-side resources
3915 // may send events.
3916 Unlock();
3917
3918 // This may send IPC events.
3919 // This will make normal neutering a nop.
3920 // This will toggle the process lock.
3921 m_LeftSideResourceCleanupList.SweepNeuterLeftSideResources(this);
3922
3923
3924 // Many objects (especially CordbValue, FuncEval) don't have clear lifetime semantics and
3925 // so they must be put into an exit-neuter list (Process/AppDomain) for worst-case scenarios.
3926 // These objects are likely released early, and so we sweep them aggressively on each Continue (kind of like a mini-GC).
3927 //
3928 // One drawback is that there may be a lot of useless sweeping if the debugger creates a lot of
3929 // objects that it holds onto. Consider instead of sweeping, have the object explicitly post itself
3930 // to a list that's guaranteed to be cleared. This would let us avoid sweeping not-yet-ready objects.
3931 // This will toggle the process lock
3932 m_ExitNeuterList.SweepAllNeuterAtWillObjects(this);
3933
3934
3935 for(unsigned int idx = 0; idx < listAppDomains.Length(); idx++)
3936 {
3937 CordbAppDomain * pAppDomain = listAppDomains[idx];
3938
3939 // CordbHandleValue is in the appdomain exit list, and that needs
3940 // to send an IPC event to cleanup and release the handle from
3941 // the GCs handle table.
3942 // This will toggle the process lock.
3943 pAppDomain->GetSweepableExitNeuterList()->SweepNeuterLeftSideResources(this);
3944 }
3945 listAppDomains.Clear();
3946
3947 Lock();
3948 }
3949
3950
3951 // At this point, if the managed event queue is empty, m_synchronized may still be true if we had previously
3952 // synchronized.
3953
3954#ifdef FEATURE_INTEROP_DEBUGGING
3955 // Next, check for unmanaged events that may be queued. If there are some queued, then we need to get the Win32
3956 // event thread to go ahead and dispatch the next one. If there aren't any queued, then we can just fall through and
3957 // send the continue message to the left side. This works even if we have an outstanding ownership request, because
3958 // until that answer is received, its just like the event hasn't happened yet.
3959 //
3960 // If we're terminated, then we've already continued from the last win32 event and so don't continue.
3961 // @todo - or we could ensure the PS_SOME_THREADS_SUSPENDED | PS_HIJACKS_IN_PLACE are removed.
3962 // Either way, we're just protecting against exit-process at strange times.
3963 bool fDoWin32Continue = !m_terminated && ((m_state & (PS_WIN32_STOPPED | PS_SOME_THREADS_SUSPENDED | PS_HIJACKS_IN_PLACE)) != 0);
3964
3965 // We need to store this before marking the event user continued below
3966 BOOL fHasUserUncontinuedEvents = HasUserUncontinuedNativeEvents();
3967
3968 if(m_lastDispatchedIBEvent != NULL)
3969 {
3970 m_lastDispatchedIBEvent->SetState(CUES_UserContinued);
3971 }
3972
3973 if (fHasUserUncontinuedEvents)
3974 {
3975 // ExitProcess is the last debug event we'll get. The Process Handle is not signaled until
3976 // after we continue from ExitProcess. m_terminated is only set once we know the process is signaled.
3977 // (This isn't 100% true for the detach case, but since you can't do interop detach, we don't care)
3978 //_ASSERTE(!m_terminated);
3979
3980 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::CI: there are queued uncontinued events. m_dispatchingUnmanagedEvent = %d\n", m_dispatchingUnmanagedEvent);
3981
3982 // Are we being called while in the unmanaged event callback?
3983 if (m_dispatchingUnmanagedEvent)
3984 {
3985 LOG((LF_CORDB, LL_INFO1000, "CP::CI: continue while dispatching.\n"));
3986 // The Win32ET could have made a cross-thread call to Continue while dispatching,
3987 // so we don't know if this is the win32 ET.
3988
3989 // Tell the Win32 thread to continue when it returns from handling its unmanaged callback.
3990 m_dispatchingUnmanagedEvent = false;
3991
3992 // If there are no more unmanaged events, then we fall through and continue the process for real. Otherwise,
3993 // we can simply return.
3994 if (HasUndispatchedNativeEvents())
3995 {
3996 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: more unmanaged events need dispatching.\n");
3997
3998 // Note: if we tried to access the Left Side while stopped but couldn't, then m_oddSync will be true. We
3999 // need to reset it to false since we're continuing now.
4000 m_oddSync = false;
4001
4002 Unlock();
4003 return S_OK;
4004 }
4005 else
4006 {
4007 // Also, if there are no more unmanaged events, then when DispatchUnmanagedInBandEvent sees that
4008 // m_dispatchingUnmanagedEvent is false, it will continue the process. So we set doWin32Continue to
4009 // false here so that we don't try to double continue the process below.
4010 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: no more unmanaged events to dispatch.\n");
4011
4012 fDoWin32Continue = false;
4013 }
4014 }
4015 else
4016 {
4017 // after the DebugEvent callback returned the continue still had no been issued. Then later
4018 // on another thread the user called back to continue the event, which gets us to right here
4019 LOG((LF_CORDB, LL_INFO1000, "CP::CI: continue outside of dispatching.\n"));
4020
4021 // This should be the common place to Dispatch an IB event that was hijacked for sync.
4022
4023 // If we're not dispatching, this better not be the win32 event thread.
4024 _ASSERTE(!IsWin32EventThread());
4025
4026 // If the event at the head of the queue is really the last event, or if the event at the head of the queue
4027 // hasn't been dispatched yet, then we simply fall through and continue the process for real. However, if
4028 // its not the last event, we send to the Win32 event thread and get it to continue, then we return.
4029 if (HasUndispatchedNativeEvents())
4030 {
4031 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: more unmanaged events need dispatching.\n");
4032
4033 // Note: if we tried to access the Left Side while stopped but couldn't, then m_oddSync will be true. We
4034 // need to reset it to false since we're continuing now.
4035 m_oddSync = false;
4036
4037 Unlock();
4038
4039 hr = this->m_pShim->GetWin32EventThread()->SendUnmanagedContinue(this, cRealUMContinue);
4040
4041 return hr;
4042 }
4043 }
4044 }
4045#endif // FEATURE_INTEROP_DEBUGGING
4046
4047 // Both the managed and unmanaged event queues are now empty. Go
4048 // ahead and continue the process for real.
4049 LOG((LF_CORDB, LL_INFO1000, "CP::CI: headed for true continue.\n"));
4050
4051 // We need to check these while under the lock, but action must be
4052 // taked outside of the lock.
4053 bool fIsExiting = m_exiting;
4054 bool fWasSynchronized = GetSynchronized();
4055
4056 // Mark that we're no longer synchronized.
4057 if (fWasSynchronized)
4058 {
4059 LOG((LF_CORDB, LL_INFO1000, "CP::CI: process was synchronized.\n"));
4060
4061 SetSynchronized(false);
4062 SetSyncCompleteRecv(false);
4063
4064 // we're no longer in a callback, so set flags to indicate that we've finished.
4065 GetShim()->NotifyOnContinue();
4066
4067 // Flush will update state, including continue counter and marking
4068 // frames dirty.
4069 this->FlushProcessRunning();
4070
4071
4072 // Tell the RC event thread that something about this process has changed.
4073 m_cordb->ProcessStateChanged();
4074 }
4075
4076 m_continueCounter++;
4077
4078 // If m_oddSync is set, then out last synchronization was due to us syncing the process because we were Win32
4079 // stopped. Therefore, while we do need to do most of the work to continue the process below, we don't actually have
4080 // to send the managed continue event. Setting wasSynchronized to false here helps us do that.
4081 if (m_oddSync)
4082 {
4083 fWasSynchronized = false;
4084 m_oddSync = false;
4085 }
4086
4087#ifdef FEATURE_INTEROP_DEBUGGING
4088 // We must ensure that all managed threads are suspended here. We're about to let all managed threads run free via
4089 // the managed continue message to the Left Side. If we don't suspend the managed threads, then they may start
4090 // slipping forward even if we receive an in-band unmanaged event. We have to hijack in-band unmanaged events while
4091 // getting the managed continue message over to the Left Side to keep the process running free. Otherwise, the
4092 // SendIPCEvent will hang below. But in doing so, we could let managed threads slip to far. So we ensure they're all
4093 // suspended here.
4094 //
4095 // Note: we only do this suspension if the helper thread hasn't died yet. If the helper thread has died, then we
4096 // know that we're loosing the Runtime. No more managed code is going to run, so we don't bother trying to prevent
4097 // managed threads from slipping via the call below.
4098 //
4099 // Note: we just remember here, under the lock, so we can unlock then wait for the syncing thread to free the
4100 // debugger lock. Otherwise, we may block here and prevent someone from continuing from an OOB event, which also
4101 // prevents the syncing thread from releasing the debugger lock like we want it to.
4102 bool fNeedSuspend = fWasSynchronized && fDoWin32Continue && !m_helperThreadDead;
4103
4104 // If we receive a new in-band event once we unlock, we need to know to hijack it and keep going while we're still
4105 // trying to send the managed continue event to the process.
4106 if (fWasSynchronized && fDoWin32Continue && !fIsExiting)
4107 {
4108 m_specialDeferment = true;
4109 }
4110
4111 if (fNeedSuspend)
4112 {
4113 // @todo - what does this actually accomplish? We already suspended everything when we first synced.
4114
4115 // Any thread that may hold a lock blocking the helper is
4116 // inside of a can't stop region, and thus we won't suspend it.
4117 SuspendUnmanagedThreads();
4118 }
4119#endif // FEATURE_INTEROP_DEBUGGING
4120
4121 Unlock();
4122
4123 // Although we've released the Process-lock, we still have the Stop-Go lock.
4124 _ASSERTE(m_StopGoLock.HasLock());
4125
4126 // If we're processing an ExitProcess managed event, then we don't want to really continue the process, so just fall
4127 // thru. Note: we did let the unmanaged continue go through above for this case.
4128 if (fIsExiting)
4129 {
4130 LOG((LF_CORDB, LL_INFO1000, "CP::CI: continuing from exit case.\n"));
4131 }
4132 else if (fWasSynchronized)
4133 {
4134 LOG((LF_CORDB, LL_INFO1000, "CP::CI: Sending continue to AppD:0x%x.\n", VmPtrToCookie(pAppDomainToken)));
4135#ifdef FEATURE_INTEROP_DEBUGGING
4136 STRESS_LOG2(LF_CORDB, LL_INFO1000, "Continue flags:special=%d, dowin32=%d\n", m_specialDeferment, fDoWin32Continue);
4137#endif
4138 // Send to the RC to continue the process.
4139 DebuggerIPCEvent * pEvent = (DebuggerIPCEvent *) _alloca(CorDBIPC_BUFFER_SIZE);
4140
4141 InitIPCEvent(pEvent, DB_IPCE_CONTINUE, false, pAppDomainToken);
4142
4143 hr = m_cordb->SendIPCEvent(this, pEvent, CorDBIPC_BUFFER_SIZE);
4144
4145 // It is possible that we continue and then the process immediately exits before the helper
4146 // thread is finished continuing and can report success back to us. That's arguably a success
4147 // case sinceu the process did indeed continue, but since we didn't get the acknowledgement,
4148 // we can't be sure it's success. So we call it S_FALSE instead of S_OK.
4149 // @todo - how do we handle other failure here?
4150 if (hr == CORDBG_E_PROCESS_TERMINATED)
4151 {
4152 hr = S_FALSE;
4153 }
4154 _ASSERTE(SUCCEEDED(pEvent->hr));
4155
4156 LOG((LF_CORDB, LL_INFO1000, "CP::CI: Continue sent to AppD:0x%x.\n", VmPtrToCookie(pAppDomainToken)));
4157 }
4158
4159#ifdef FEATURE_INTEROP_DEBUGGING
4160 // If we're win32 attached to the Left side, then we need to win32 continue the process too (unless, of course, it's
4161 // already been done above.)
4162 //
4163 // Note: we do this here because we want to get the Left Side to receive and ack our continue message above if we
4164 // were sync'd. If we were sync'd, then by definition the process (and the helper thread) is running anyway, so all
4165 // this continue is going to do is to let the threads that have been suspended go.
4166 if (fDoWin32Continue)
4167 {
4168#ifdef _DEBUG
4169 {
4170 // A little pause here extends the special deferment region and thus causes native-debug
4171 // events to get hijacked. This test some wildly different corner case paths.
4172 // See VSWhidbey bugs 131905, 168971
4173 static DWORD dwRace = -1;
4174 if (dwRace == -1)
4175 dwRace = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgRace);
4176
4177 if ((dwRace & 1) == 1)
4178 {
4179 Sleep(30);
4180 }
4181 }
4182#endif
4183
4184 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: sending unmanaged continue.\n");
4185
4186 // Send to the Win32 event thread to do the unmanaged continue for us.
4187 hr = this->m_pShim->GetWin32EventThread()->SendUnmanagedContinue(this, cRealUMContinue);
4188 }
4189#endif // FEATURE_INTEROP_DEBUGGING
4190
4191 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::CI: continue done, returning.\n");
4192
4193 return hr;
4194}
4195
4196HRESULT CordbProcess::HasQueuedCallbacks(ICorDebugThread *pThread,
4197 BOOL *pbQueued)
4198{
4199 PUBLIC_REENTRANT_API_ENTRY(this);
4200 FAIL_IF_NEUTERED(this);
4201 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pThread,ICorDebugThread *);
4202 VALIDATE_POINTER_TO_OBJECT(pbQueued,BOOL *);
4203
4204 // Shim owns the event queue
4205 if (m_pShim != NULL)
4206 {
4207 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(this); // Calling to shim, leaving RS.
4208 *pbQueued = m_pShim->GetManagedEventQueue()->HasQueuedCallbacks(pThread);
4209 return S_OK;
4210 }
4211 return E_NOTIMPL; // Not implemented in V3.
4212}
4213
4214//
4215// A small helper function to convert a CordbBreakpoint to an ICorDebugBreakpoint based on its type.
4216//
4217static ICorDebugBreakpoint *CordbBreakpointToInterface(CordbBreakpoint * pBreakpoint)
4218{
4219 _ASSERTE(pBreakpoint != NULL);
4220
4221 //
4222 // I really dislike this. We've got three subclasses of CordbBreakpoint, but we store them all into the same hash
4223 // (m_breakpoints), so when we get one out of the hash, we don't really know what type it is. But we need to know
4224 // what type it is because we need to cast it to the proper interface before passing it out. I.e., when we create a
4225 // function breakpoint, we return the breakpoint casted to an ICorDebugFunctionBreakpoint. But if we grab that same
4226 // breakpoint out of the hash as a CordbBreakpoint and pass it out as an ICorDebugBreakpoint, then that's a
4227 // different pointer, and its wrong. So I've added the type to the breakpoint so we can cast properly here. I'd love
4228 // to do this a different way, though...
4229 //
4230 // -- Mon Dec 14 21:06:46 1998
4231 //
4232 switch(pBreakpoint->GetBPType())
4233 {
4234 case CBT_FUNCTION:
4235 return static_cast<ICorDebugFunctionBreakpoint *>(static_cast<CordbFunctionBreakpoint *> (pBreakpoint));
4236 break;
4237
4238 case CBT_MODULE:
4239 return static_cast<ICorDebugModuleBreakpoint*>(static_cast<CordbModuleBreakpoint *> (pBreakpoint));
4240 break;
4241
4242 case CBT_VALUE:
4243 return static_cast<ICorDebugValueBreakpoint *>(static_cast<CordbValueBreakpoint *> (pBreakpoint));
4244 break;
4245
4246 default:
4247 _ASSERTE(!"Invalid breakpoint type!");
4248 }
4249
4250 return NULL;
4251}
4252
4253
4254// Callback data for code:CordbProcess::GetAssembliesInLoadOrder
4255class ShimAssemblyCallbackData
4256{
4257public:
4258 // Ctor to intialize callback data
4259 //
4260 // Arguments:
4261 // pAppDomain - appdomain that the assemblies are in.
4262 // pAssemblies - preallocated array of smart pointers to hold assemblies
4263 // countAssemblies - size of pAssemblies in elements.
4264 ShimAssemblyCallbackData(
4265 CordbAppDomain * pAppDomain,
4266 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
4267 ULONG countAssemblies)
4268 {
4269 _ASSERTE(pAppDomain != NULL);
4270 _ASSERTE(pAssemblies != NULL);
4271
4272 m_pProcess = pAppDomain->GetProcess();
4273 m_pAppDomain = pAppDomain;
4274 m_pAssemblies = pAssemblies;
4275 m_countElements = countAssemblies;
4276 m_index = 0;
4277
4278 // Just to be safe, clear them all out
4279 for(ULONG i = 0; i < countAssemblies; i++)
4280 {
4281 pAssemblies[i].Clear();
4282 }
4283 }
4284
4285 // Dtor
4286 //
4287 // Notes:
4288 // This can assert end-of-enumeration invariants.
4289 ~ShimAssemblyCallbackData()
4290 {
4291 // Ensure that we went through all assemblies.
4292 _ASSERTE(m_index == m_countElements);
4293 }
4294
4295 // Callback invoked from DAC enumeration.
4296 //
4297 // arguments:
4298 // vmDomainAssembly - VMPTR for assembly
4299 // pData - a 'this' pointer
4300 //
4301 static void Callback(VMPTR_DomainAssembly vmDomainAssembly, void * pData)
4302 {
4303 ShimAssemblyCallbackData * pThis = static_cast<ShimAssemblyCallbackData *> (pData);
4304 INTERNAL_DAC_CALLBACK(pThis->m_pProcess);
4305
4306 CordbAssembly * pAssembly = pThis->m_pAppDomain->LookupOrCreateAssembly(vmDomainAssembly);
4307
4308 pThis->SetAndMoveNext(pAssembly);
4309 }
4310
4311 // Set the current index in the table and increment the cursor.
4312 //
4313 // Arguments:
4314 // pAssembly - assembly from DAC enumerator
4315 void SetAndMoveNext(CordbAssembly * pAssembly)
4316 {
4317 _ASSERTE(pAssembly != NULL);
4318
4319 if (m_index >= m_countElements)
4320 {
4321 // Enumerating the assemblies in the target should be fixed since
4322 // the target is not running.
4323 // We should never get here unless the target is unstable.
4324 // The caller (the shim) pre-allocated the table of assemblies.
4325 m_pProcess->TargetConsistencyCheck(!"Target changed assembly count");
4326 return;
4327 }
4328
4329 m_pAssemblies[m_index].Assign(pAssembly);
4330 m_index++;
4331 }
4332
4333protected:
4334 CordbProcess * m_pProcess;
4335 CordbAppDomain * m_pAppDomain;
4336 RSExtSmartPtr<ICorDebugAssembly>* m_pAssemblies;
4337 ULONG m_countElements;
4338 ULONG m_index;
4339};
4340
4341//---------------------------------------------------------------------------------------
4342// Shim Helper to enumerate the assemblies in the load-order
4343//
4344// Arguments:
4345// pAppdomain - non-null appdomain to enumerate assemblies.
4346// pAssemblies - caller pre-allocated array to hold assemblies
4347// countAssemblies - size of the array.
4348//
4349// Notes:
4350// Caller preallocated array (likely from ICorDebugAssemblyEnum::GetCount),
4351// and now this function fills in the assemblies in the order they were
4352// loaded.
4353//
4354// The target should be stable, such that the number of assemblies in the
4355// target is stable, and therefore countAssemblies as determined by the
4356// shim via ICorDebugAssemblyEnum::GetCount should match the number of
4357// assemblies enumerated here.
4358//
4359// Called by code:ShimProcess::QueueFakeAttachEvents.
4360// This provides the assemblies in load-order. In contrast,
4361// ICorDebugAppDomain::EnumerateAssemblies is a random order. The shim needs
4362// load-order to match Whidbey semantics for dispatching fake load-assembly
4363// callbacks on attach. The debugger then uses the order
4364// in its module display window.
4365//
4366void CordbProcess::GetAssembliesInLoadOrder(
4367 ICorDebugAppDomain * pAppDomain,
4368 RSExtSmartPtr<ICorDebugAssembly>* pAssemblies,
4369 ULONG countAssemblies)
4370{
4371 PUBLIC_API_ENTRY_FOR_SHIM(this);
4372 RSLockHolder lockHolder(GetProcessLock());
4373
4374 _ASSERTE(GetShim() != NULL);
4375
4376 CordbAppDomain * pAppDomainInternal = static_cast<CordbAppDomain *> (pAppDomain);
4377
4378 ShimAssemblyCallbackData data(pAppDomainInternal, pAssemblies, countAssemblies);
4379
4380 // Enumerate through and fill out pAssemblies table.
4381 GetDAC()->EnumerateAssembliesInAppDomain(
4382 pAppDomainInternal->GetADToken(),
4383 ShimAssemblyCallbackData::Callback,
4384 &data); // user data
4385
4386 // pAssemblies array has now been updated.
4387}
4388
4389// Callback data for code:CordbProcess::GetModulesInLoadOrder
4390class ShimModuleCallbackData
4391{
4392public:
4393 // Ctor to intialize callback data
4394 //
4395 // Arguments:
4396 // pAssembly - assembly that the Modules are in.
4397 // pModules - preallocated array of smart pointers to hold Modules
4398 // countModules - size of pModules in elements.
4399 ShimModuleCallbackData(
4400 CordbAssembly * pAssembly,
4401 RSExtSmartPtr<ICorDebugModule>* pModules,
4402 ULONG countModules)
4403 {
4404 _ASSERTE(pAssembly != NULL);
4405 _ASSERTE(pModules != NULL);
4406
4407 m_pProcess = pAssembly->GetAppDomain()->GetProcess();
4408 m_pAssembly = pAssembly;
4409 m_pModules = pModules;
4410 m_countElements = countModules;
4411 m_index = 0;
4412
4413 // Just to be safe, clear them all out
4414 for(ULONG i = 0; i < countModules; i++)
4415 {
4416 pModules[i].Clear();
4417 }
4418 }
4419
4420 // Dtor
4421 //
4422 // Notes:
4423 // This can assert end-of-enumeration invariants.
4424 ~ShimModuleCallbackData()
4425 {
4426 // Ensure that we went through all Modules.
4427 _ASSERTE(m_index == m_countElements);
4428 }
4429
4430 // Callback invoked from DAC enumeration.
4431 //
4432 // arguments:
4433 // vmDomainFile - VMPTR for Module
4434 // pData - a 'this' pointer
4435 //
4436 static void Callback(VMPTR_DomainFile vmDomainFile, void * pData)
4437 {
4438 ShimModuleCallbackData * pThis = static_cast<ShimModuleCallbackData *> (pData);
4439 INTERNAL_DAC_CALLBACK(pThis->m_pProcess);
4440
4441 CordbModule * pModule = pThis->m_pAssembly->GetAppDomain()->LookupOrCreateModule(vmDomainFile);
4442
4443 pThis->SetAndMoveNext(pModule);
4444 }
4445
4446 // Set the current index in the table and increment the cursor.
4447 //
4448 // Arguments:
4449 // pModule - Module from DAC enumerator
4450 void SetAndMoveNext(CordbModule * pModule)
4451 {
4452 _ASSERTE(pModule != NULL);
4453
4454 if (m_index >= m_countElements)
4455 {
4456 // Enumerating the Modules in the target should be fixed since
4457 // the target is not running.
4458 // We should never get here unless the target is unstable.
4459 // The caller (the shim) pre-allocated the table of Modules.
4460 m_pProcess->TargetConsistencyCheck(!"Target changed Module count");
4461 return;
4462 }
4463
4464 m_pModules[m_index].Assign(pModule);
4465 m_index++;
4466 }
4467
4468protected:
4469 CordbProcess * m_pProcess;
4470 CordbAssembly * m_pAssembly;
4471 RSExtSmartPtr<ICorDebugModule>* m_pModules;
4472 ULONG m_countElements;
4473 ULONG m_index;
4474};
4475
4476//---------------------------------------------------------------------------------------
4477// Shim Helper to enumerate the Modules in the load-order
4478//
4479// Arguments:
4480// pAppdomain - non-null appdomain to enumerate Modules.
4481// pModules - caller pre-allocated array to hold Modules
4482// countModules - size of the array.
4483//
4484// Notes:
4485// Caller preallocated array (likely from ICorDebugModuleEnum::GetCount),
4486// and now this function fills in the Modules in the order they were
4487// loaded.
4488//
4489// The target should be stable, such that the number of Modules in the
4490// target is stable, and therefore countModules as determined by the
4491// shim via ICorDebugModuleEnum::GetCount should match the number of
4492// Modules enumerated here.
4493//
4494// Called by code:ShimProcess::QueueFakeAssemblyAndModuleEvent.
4495// This provides the Modules in load-order. In contrast,
4496// ICorDebugAssembly::EnumerateModules is a random order. The shim needs
4497// load-order to match Whidbey semantics for dispatching fake load-Module
4498// callbacks on attach. The most important thing is that the manifest module
4499// gets a LodModule callback before any secondary modules. For dynamic
4500// modules, this is necessary for operations on the secondary module
4501// that rely on manifest metadata (eg. GetSimpleName).
4502//
4503// @dbgtodo : This is almost identical to GetAssembliesInLoadOrder, and
4504// (together wih the CallbackData classes) seems a HUGE amount of code and
4505// complexity for such a simple thing. We also have extra code to order
4506// AppDomains and Threads. We should try and rip all of this extra complexity
4507// out, and replace it with better data structures for storing these items.
4508// Eg., if we used std::map, we could have efficient lookups and ordered
4509// enumerations. However, we do need to be careful about exposing new invariants
4510// through ICorDebug that customers may depend on, which could place a long-term
4511// compatibility burden on us. We could have a simple generic data structure
4512// (eg. built on std::hash_map and std::list) which provided efficient look-up
4513// and both in-order and random enumeration.
4514//
4515void CordbProcess::GetModulesInLoadOrder(
4516 ICorDebugAssembly * pAssembly,
4517 RSExtSmartPtr<ICorDebugModule>* pModules,
4518 ULONG countModules)
4519{
4520 PUBLIC_API_ENTRY_FOR_SHIM(this);
4521 RSLockHolder lockHolder(GetProcessLock());
4522
4523 _ASSERTE(GetShim() != NULL);
4524
4525 CordbAssembly * pAssemblyInternal = static_cast<CordbAssembly *> (pAssembly);
4526
4527 ShimModuleCallbackData data(pAssemblyInternal, pModules, countModules);
4528
4529 // Enumerate through and fill out pModules table.
4530 GetDAC()->EnumerateModulesInAssembly(
4531 pAssemblyInternal->GetDomainAssemblyPtr(),
4532 ShimModuleCallbackData::Callback,
4533 &data); // user data
4534
4535 // pModules array has now been updated.
4536}
4537
4538
4539//---------------------------------------------------------------------------------------
4540// Callback to count the number of enumerations in a process.
4541//
4542// Arguments:
4543// id - the connection id.
4544// pName - name of the connection
4545// pUserData - an EnumerateConnectionsData
4546//
4547// Notes:
4548// Helper function for code:CordbProcess::QueueFakeConnectionEvents
4549//
4550// static
4551void CordbProcess::CountConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData)
4552{
4553}
4554
4555//---------------------------------------------------------------------------------------
4556// Callback to enumerate all the connections in a process.
4557//
4558// Arguments:
4559// id - the connection id.
4560// pName - name of the connection
4561// pUserData - an EnumerateConnectionsData
4562//
4563// Notes:
4564// Helper function for code:CordbProcess::QueueFakeConnectionEvents
4565//
4566// static
4567void CordbProcess::EnumerateConnectionsCallback(DWORD id, LPCWSTR pName, void * pUserData)
4568{
4569}
4570
4571//---------------------------------------------------------------------------------------
4572// Callback from Shim to queue fake Connection events on attach.
4573//
4574// Notes:
4575// See code:ShimProcess::QueueFakeAttachEvents
4576void CordbProcess::QueueFakeConnectionEvents()
4577{
4578 PUBLIC_API_ENTRY_FOR_SHIM(this);
4579
4580}
4581
4582//
4583// DispatchRCEvent -- dispatches a previously queued IPC event received
4584// from the runtime controller. This represents the last amount of processing
4585// the DI gets to do on an event before giving it to the user.
4586//
4587void CordbProcess::DispatchRCEvent()
4588{
4589 INTERNAL_API_ENTRY(this);
4590
4591 CONTRACTL
4592 {
4593 // This is happening on the RCET thread, so there's no place to propogate an error back up.
4594 NOTHROW;
4595 }
4596 CONTRACTL_END;
4597
4598 _ASSERTE(m_pShim != NULL); // V2 case
4599
4600 //
4601 // Note: the current thread should have the process locked when it
4602 // enters this method.
4603 //
4604 _ASSERTE(ThreadHoldsProcessLock());
4605
4606 // Create/Launch paths already ensured that we had a callback.
4607 _ASSERTE(m_cordb != NULL);
4608 _ASSERTE(m_cordb->m_managedCallback != NULL);
4609 _ASSERTE(m_cordb->m_managedCallback2 != NULL);
4610 _ASSERTE(m_cordb->m_managedCallback3 != NULL);
4611 _ASSERTE(m_cordb->m_managedCallback4 != NULL);
4612
4613
4614 // Bump up the stop count. Either we'll dispatch a managed event,
4615 // or the logic below will decide not to dispatch one and call
4616 // Continue itself. Either way, the stop count needs to go up by
4617 // one...
4618 _ASSERTE(this->GetSyncCompleteRecv());
4619 SetSynchronized(true);
4620 IncStopCount();
4621
4622 // As soon as we call Unlock(), we might get neutered and lose our reference to
4623 // the shim. Grab it now for use later.
4624 RSExtSmartPtr<ShimProcess> pShim(m_pShim);
4625
4626 Unlock();
4627
4628 _ASSERTE(!ThreadHoldsProcessLock());
4629
4630
4631 // We want to stay synced until after the callbacks return. This is b/c we're on the RCET,
4632 // and we may deadlock if we send IPC events on the RCET if we're not synced (see SendIPCEvent for details).
4633 // So here, stopcount=1. The StopContinueHolder bumps it up to 2.
4634 // - If Cordbg calls continue in the callback, that bumps it back down to 1, but doesn't actually continue.
4635 // The holder dtor then bumps it down to 0, doing the real continue.
4636 // - If Cordbg doesn't call continue in the callback, then stopcount stays at 2, holder dtor drops it down to 1,
4637 // and then the holder was just a nop.
4638 // This gives us delayed continues w/ no extra state flags.
4639
4640
4641 // The debugger may call Detach() immediately after it returns from the callback, but before this thread returns
4642 // from this function. Thus after we execute the callbacks, it's possible the CordbProcess object has been neutered.
4643
4644 // Since we're already sycned, the Stop from the holder here is practically a nop that just bumps up a count.
4645 // Create an extra scope for the StopContinueHolder.
4646 {
4647 StopContinueHolder h;
4648 HRESULT hr = h.Init(this);
4649 if (FAILED(hr))
4650 {
4651 CORDBSetUnrecoverableError(this, hr, 0);
4652 }
4653
4654 HRESULT hrCallback = S_OK;
4655 // It's possible a ICorDebugProcess::Detach() may have occurred by now.
4656 {
4657 // @dbgtodo shim: eventually the entire RCET should be considered outside the RS.
4658 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(this);
4659
4660
4661 // Snag the first event off the queue.
4662 // Holder will call Delete, which will invoke virtual Dtor that will release ICD objects.
4663 // Since these are external refs, we want to do it while "outside" the RS.
4664 NewHolder<ManagedEvent> pEvent(pShim->DequeueManagedEvent());
4665
4666 // Normally pEvent shouldn't be NULL, since this method is called when the queue is not empty.
4667 // But due to a race between CordbProcess::Terminate(), CordbWin32EventThread::ExitProcess() and this method
4668 // it is totally possible that the queue has already been cleaned up and we can't expect that event is always available.
4669 if (pEvent != NULL)
4670 {
4671 // Since we need to access a member (m_cordb), protect this block with a
4672 // lock and a check for Neutering (in case process detach has just
4673 // occurred). We'll release the lock around the dispatch later on.
4674 RSLockHolder lockHolder(GetProcessLock());
4675 if (!IsNeutered())
4676 {
4677#ifdef _DEBUG
4678 // On a debug build, keep track of the last IPC event we dispatched.
4679 m_pDBGLastIPCEventType = pEvent->GetDebugCookie();
4680#endif
4681
4682 ManagedEvent::DispatchArgs args(m_cordb->m_managedCallback, m_cordb->m_managedCallback2, m_cordb->m_managedCallback3, m_cordb->m_managedCallback4);
4683
4684 {
4685 // Release lock around the dispatch of the event
4686 RSInverseLockHolder inverseLockHolder(GetProcessLock());
4687
4688 EX_TRY
4689 {
4690 // This dispatches almost directly into the user's callbacks.
4691 // It does not update any RS state.
4692 hrCallback = pEvent->Dispatch(args);
4693 }
4694 EX_CATCH_HRESULT(hrCallback);
4695 }
4696 }
4697 }
4698
4699 } // we're now back inside the RS
4700
4701 if (hrCallback == E_NOTIMPL)
4702 {
4703 ContinueInternal(FALSE);
4704 }
4705
4706
4707 } // forces Continue to be called
4708
4709 Lock();
4710
4711};
4712
4713#ifdef _DEBUG
4714//---------------------------------------------------------------------------------------
4715// Debug-only callback to ensure that an appdomain is not available after the ExitAppDomain event.
4716//
4717// Arguments:
4718// vmAppDomain - appdomain from enumeration
4719// pUserData - pointer to a DbgAssertAppDomainDeletedData which contains the VMAppDomain that was just deleted.
4720// notes:
4721// see code:CordbProcess::DbgAssertAppDomainDeleted for details.
4722void CordbProcess::DbgAssertAppDomainDeletedCallback(VMPTR_AppDomain vmAppDomain, void * pUserData)
4723{
4724 DbgAssertAppDomainDeletedData * pCallbackData = reinterpret_cast<DbgAssertAppDomainDeletedData *>(pUserData);
4725 INTERNAL_DAC_CALLBACK(pCallbackData->m_pThis);
4726
4727 VMPTR_AppDomain vmAppDomainDeleted = pCallbackData->m_vmAppDomainDeleted;
4728 CONSISTENCY_CHECK_MSGF((vmAppDomain != vmAppDomainDeleted),
4729 ("An ExitAppDomain event was sent for appdomain, but it still shows up in the enumeration.\n vmAppDomain=%p\n",
4730 VmPtrToCookie(vmAppDomainDeleted)));
4731}
4732
4733//---------------------------------------------------------------------------------------
4734// Debug-only helper to Assert that VMPTR is actually removed.
4735//
4736// Arguments:
4737// vmAppDomainDeleted - vmptr of appdomain that we just got exit event for.
4738// This should not be discoverable from the RS.
4739//
4740// Notes:
4741// See code:IDacDbiInterface#Enumeration for rules that we're asserting.
4742// Once the exit appdomain event is dispatched, the appdomain should not be discoverable by the RS.
4743// Else the RS may use the AppDomain* after it's deleted.
4744// This asserts that the AppDomain* is not discoverable.
4745//
4746// Since this is a debug-only function, it should have no side-effects.
4747void CordbProcess::DbgAssertAppDomainDeleted(VMPTR_AppDomain vmAppDomainDeleted)
4748{
4749 DbgAssertAppDomainDeletedData callbackData;
4750 callbackData.m_pThis = this;
4751 callbackData.m_vmAppDomainDeleted = vmAppDomainDeleted;
4752
4753 GetDAC()->EnumerateAppDomains(
4754 CordbProcess::DbgAssertAppDomainDeletedCallback,
4755 &callbackData);
4756}
4757
4758#endif // _DEBUG
4759
4760//---------------------------------------------------------------------------------------
4761// Update state and potentially Dispatch a single event.
4762//
4763// Arguments:
4764// pEvent - non-null pointer to debug event.
4765// pCallback1 - callback object to dispatch on (for V1 callbacks)
4766// pCallback2 - 2nd callback object to dispatch on (for new V2 callbacks)
4767// pCallback3 - 3rd callback object to dispatch on (for new V4 callbacks)
4768//
4769//
4770// Returns:
4771// Nothing. Throws on error.
4772//
4773// Notes:
4774// Generally, this will dispatch exactly 1 callback. It may dispatch 0 callbacks if there is an error
4775// or in other corner cases (documented within the dispatch code below).
4776// Errors could occur because:
4777// - the event is corrupted (exceptional case)
4778// - the RS is corrupted / OOM (exceptional case)
4779// Exception errors here will propogate back to the Filter() call, and there's not really anything
4780// a debugger can do about an error here (perhaps report it to the user).
4781// Errors must leave IcorDebug in a consistent state.
4782//
4783// This is dispatched directly on the Win32Event Thread in response to calling Filter.
4784// Therefore, this can't send any IPC events (Not an issue once everything is DAC-ized).
4785// A V2 shim can provide a proxy calllack that takes these events and queues them and
4786// does the real dispatch to the user to emulate V2 semantics.
4787//
4788#ifdef _PREFAST_
4789#pragma warning(push)
4790#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4791#endif
4792void CordbProcess::RawDispatchEvent(
4793 DebuggerIPCEvent * pEvent,
4794 RSLockHolder * pLockHolder,
4795 ICorDebugManagedCallback * pCallback1,
4796 ICorDebugManagedCallback2 * pCallback2,
4797 ICorDebugManagedCallback3 * pCallback3,
4798 ICorDebugManagedCallback4 * pCallback4)
4799{
4800 CONTRACTL
4801 {
4802 THROWS;
4803 }
4804 CONTRACTL_END;
4805
4806 HRESULT hr = S_OK;
4807 // We start off with the lock, and we'll toggle it.
4808 _ASSERTE(ThreadHoldsProcessLock());
4809
4810
4811 //
4812 // Call StartEventDispatch to true to guard against calls to Continue()
4813 // from within the user's callback. We need Continue() to behave a little
4814 // bit differently in such a case.
4815 //
4816 // Also note that Win32EventThread::ExitProcess will take the lock and free all
4817 // events in the queue. (the current event is already off the queue, so
4818 // it will be ok). But we can't do the EP callback in the middle of this dispatch
4819 // so if this flag is set, EP will wait on the miscWaitEvent (which will
4820 // get set in FlushQueuedEvents when we return from here) and let us finish here.
4821 //
4822 StartEventDispatch(pEvent->type);
4823
4824 // Keep strong references to these objects in case a callback deletes them from underneath us.
4825 RSSmartPtr<CordbAppDomain> pAppDomain;
4826 CordbThread * pThread = NULL;
4827
4828
4829 // Get thread that this event is on. In attach scenarios, this may be the first time ICorDebug has seen this thread.
4830 if (!pEvent->vmThread.IsNull())
4831 {
4832 pThread = LookupOrCreateThread(pEvent->vmThread);
4833 }
4834
4835 if (!pEvent->vmAppDomain.IsNull())
4836 {
4837 pAppDomain.Assign(LookupOrCreateAppDomain(pEvent->vmAppDomain));
4838 }
4839
4840 DWORD dwVolatileThreadId = 0;
4841 if (pThread != NULL)
4842 {
4843 dwVolatileThreadId = pThread->GetUniqueId();
4844 }
4845
4846
4847 //
4848 // Update the app domain that this thread lives in.
4849 //
4850 if ((pThread != NULL) && (pAppDomain != NULL))
4851 {
4852 // It shouldn't be possible for us to see an exited AppDomain here
4853 _ASSERTE( !pAppDomain->IsNeutered() );
4854
4855 pThread->m_pAppDomain = pAppDomain;
4856 }
4857
4858 _ASSERTE(pEvent != NULL);
4859 _ASSERTE(pCallback1 != NULL);
4860 _ASSERTE(pCallback2 != NULL);
4861 _ASSERTE(pCallback3 != NULL);
4862 _ASSERTE(pCallback4 != NULL);
4863
4864 STRESS_LOG1(LF_CORDB, LL_EVERYTHING, "Pre-Dispatch IPC event: %s\n", IPCENames::GetName(pEvent->type));
4865
4866 switch (pEvent->type & DB_IPCE_TYPE_MASK)
4867 {
4868 case DB_IPCE_CREATE_PROCESS:
4869 {
4870 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
4871 pCallback1->CreateProcess(static_cast<ICorDebugProcess*> (this));
4872 }
4873 break;
4874
4875 case DB_IPCE_BREAKPOINT:
4876 {
4877 _ASSERTE(pThread != NULL);
4878 _ASSERTE(pAppDomain != NULL);
4879
4880 // Find the breakpoint object on this side.
4881 CordbBreakpoint *pBreakpoint = NULL;
4882
4883 // We've found cases out in the wild where we get this event on a thread we don't recognize.
4884 // We're not sure how this happens. Add a runtime check to protect ourselves to avoid the
4885 // an AV. We still assert because this should not be happening.
4886 // It likely means theres some issue where we failed to send a CreateThread notification.
4887 TargetConsistencyCheck(pThread != NULL);
4888 pBreakpoint = pAppDomain->m_breakpoints.GetBase(LsPtrToCookie(pEvent->BreakpointData.breakpointToken));
4889
4890 if (pBreakpoint != NULL)
4891 {
4892 ICorDebugBreakpoint * pIBreakpoint = CordbBreakpointToInterface(pBreakpoint);
4893 _ASSERTE(pIBreakpoint != NULL);
4894
4895 {
4896 PUBLIC_CALLBACK_IN_THIS_SCOPE2(this, pLockHolder, pEvent, "thread=0x%p, bp=0x%p", pThread, pBreakpoint);
4897 pCallback1->Breakpoint(pAppDomain, pThread, pIBreakpoint);
4898 }
4899 }
4900 }
4901 break;
4902
4903 case DB_IPCE_BEFORE_GARBAGE_COLLECTION:
4904 {
4905 {
4906 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
4907 pCallback4->BeforeGarbageCollection(static_cast<ICorDebugProcess*>(this));
4908 }
4909 break;
4910 }
4911
4912 case DB_IPCE_AFTER_GARBAGE_COLLECTION:
4913 {
4914 {
4915 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
4916 pCallback4->AfterGarbageCollection(static_cast<ICorDebugProcess*>(this));
4917 }
4918 break;
4919 }
4920#ifdef FEATURE_DATABREAKPOINT
4921 case DB_IPCE_DATA_BREAKPOINT:
4922 {
4923 _ASSERTE(pThread != NULL);
4924
4925 {
4926 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
4927 pCallback4->DataBreakpoint(static_cast<ICorDebugProcess*>(this), pThread, reinterpret_cast<BYTE*>(&(pEvent->DataBreakpointData.context)), sizeof(CONTEXT));
4928 }
4929 break;
4930 }
4931 break;
4932#endif
4933 case DB_IPCE_USER_BREAKPOINT:
4934 {
4935 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: user breakpoint.\n",
4936 GetCurrentThreadId());
4937
4938 _ASSERTE(pThread != NULL);
4939 _ASSERTE(pAppDomain != NULL);
4940 _ASSERTE(pThread->m_pAppDomain != NULL);
4941
4942 {
4943 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
4944 pCallback1->Break(pThread->m_pAppDomain, pThread);
4945 }
4946
4947 }
4948 break;
4949
4950 case DB_IPCE_STEP_COMPLETE:
4951 {
4952 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: step complete.\n",
4953 GetCurrentThreadId());
4954
4955 PREFIX_ASSUME(pThread != NULL);
4956
4957 CordbStepper * pStepper = m_steppers.GetBase(LsPtrToCookie(pEvent->StepData.stepperToken));
4958
4959 // It's possible the stepper is NULL if:
4960 // - event X & step-complete are both in the queue
4961 // - during dispatch for event X, Cordbg cancels the stepper (thus removing it from m_steppers)
4962 // - the Step-Complete still stays in the queue, and so we're here, but out stepper's been removed.
4963 // (This could happen for breakpoints too)
4964 // Don't dispatch a callback if the stepper is NULL.
4965 if (pStepper != NULL)
4966 {
4967 RSSmartPtr<CordbStepper> pRef(pStepper);
4968 pStepper->m_active = false;
4969 m_steppers.RemoveBase((ULONG_PTR)pStepper->m_id);
4970
4971 {
4972 _ASSERTE(pThread->m_pAppDomain != NULL);
4973 PUBLIC_CALLBACK_IN_THIS_SCOPE2(this, pLockHolder, pEvent, "thrad=0x%p, stepper=0x%p", pThread, pStepper);
4974 pCallback1->StepComplete(pThread->m_pAppDomain, pThread, pStepper, pEvent->StepData.reason);
4975 }
4976
4977 // implicit Release on pRef
4978 }
4979 }
4980 break;
4981
4982 case DB_IPCE_EXCEPTION:
4983 {
4984 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: exception.\n",
4985 GetCurrentThreadId());
4986
4987 _ASSERTE(pAppDomain != NULL);
4988
4989 // For some exceptions very early in startup (eg, TypeLoad), this may have occurred before we
4990 // even executed jitted code on the thread. We may have not received a CreateThread yet.
4991 // In V2, we detected this and sent a LogMessage on a random thread.
4992 // In V3, we lazily create the CordbThread objects (possibly before the CreateThread event),
4993 // and so we know we should have one.
4994 _ASSERTE(pThread != NULL);
4995
4996 pThread->SetExInfo(pEvent->Exception.vmExceptionHandle);
4997
4998 _ASSERTE(pThread->m_pAppDomain != NULL);
4999
5000 {
5001 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5002 pCallback1->Exception(pThread->m_pAppDomain, pThread, !pEvent->Exception.firstChance);
5003 }
5004
5005 }
5006 break;
5007
5008 case DB_IPCE_SYNC_COMPLETE:
5009 _ASSERTE(!"Should have never queued a sync complete pEvent.");
5010 break;
5011
5012 case DB_IPCE_THREAD_ATTACH:
5013 {
5014 STRESS_LOG1(LF_CORDB, LL_INFO100, "RCET::DRCE: thread attach : ID=%x.\n", dwVolatileThreadId);
5015
5016 TargetConsistencyCheck(pThread != NULL);
5017 {
5018 PUBLIC_CALLBACK_IN_THIS_SCOPE1(this, pLockHolder, pEvent, "thread=0x%p", pThread);
5019 pCallback1->CreateThread(pAppDomain, pThread);
5020 }
5021 }
5022 break;
5023
5024 case DB_IPCE_THREAD_DETACH:
5025 {
5026 STRESS_LOG2(LF_CORDB, LL_INFO100, "[%x] RCET::HRCE: thread detach : ID=%x \n",
5027 GetCurrentThreadId(), dwVolatileThreadId);
5028
5029 // If the runtime thread never entered managed code, there
5030 // won't be a CordbThread, and CreateThread was never
5031 // called, so don't bother calling ExitThread.
5032 if (pThread != NULL)
5033 {
5034 AddToNeuterOnContinueList(pThread);
5035
5036 RSSmartPtr<CordbThread> pRefThread(pThread);
5037
5038 _ASSERTE(pAppDomain != NULL);
5039
5040 // A thread is reported as dead before we get the exit event.
5041 // See code:IDacDbiInterface#IsThreadMarkedDead for the invariant being asserted here.
5042 TargetConsistencyCheck(pThread->IsThreadDead());
5043
5044 // Enforce the enumeration invariants (see code:IDacDbiInterface#Enumeration)that the thread is not discoverable.
5045 INDEBUG(pThread->DbgAssertThreadDeleted());
5046
5047 // Remove the thread from the hash. If we've removed it from the hash, we really should
5048 // neuter it ... but that causes test failures.
5049 // We'll neuter it in continue.
5050 m_userThreads.RemoveBase(VmPtrToCookie(pThread->m_vmThreadToken));
5051
5052
5053 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::HRCE: sending thread detach.\n", GetCurrentThreadId()));
5054
5055 {
5056 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5057 pCallback1->ExitThread(pAppDomain, pThread);
5058 }
5059
5060 // Implicit release on thread & pAppDomain
5061 }
5062 }
5063 break;
5064
5065 case DB_IPCE_METADATA_UPDATE:
5066 {
5067 CordbModule * pModule = pAppDomain->LookupOrCreateModule(pEvent->MetadataUpdateData.vmDomainFile);
5068 pModule->RefreshMetaData();
5069 }
5070 break;
5071
5072 case DB_IPCE_LOAD_MODULE:
5073 {
5074 _ASSERTE (pAppDomain != NULL);
5075 CordbModule * pModule = pAppDomain->LookupOrCreateModule(pEvent->LoadModuleData.vmDomainFile);
5076
5077 {
5078 pModule->SetLoadEventContinueMarker();
5079
5080 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5081 pCallback1->LoadModule(pAppDomain, pModule);
5082 }
5083
5084 }
5085 break;
5086
5087 case DB_IPCE_CREATE_CONNECTION:
5088 {
5089 STRESS_LOG1(LF_CORDB, LL_INFO100,
5090 "RCET::HRCE: Connection change %d \n",
5091 pEvent->CreateConnection.connectionId);
5092
5093 // pass back the connection id and the connection name.
5094 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5095 pCallback2->CreateConnection(
5096 this,
5097 pEvent->CreateConnection.connectionId,
5098 const_cast<WCHAR*> (pEvent->CreateConnection.wzConnectionName.GetString()));
5099 }
5100 break;
5101
5102 case DB_IPCE_DESTROY_CONNECTION:
5103 {
5104 STRESS_LOG1(LF_CORDB, LL_INFO100,
5105 "RCET::HRCE: Connection destroyed %d \n",
5106 pEvent->ConnectionChange.connectionId);
5107 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5108 pCallback2->DestroyConnection(this, pEvent->ConnectionChange.connectionId);
5109 }
5110 break;
5111
5112 case DB_IPCE_CHANGE_CONNECTION:
5113 {
5114 STRESS_LOG1(LF_CORDB, LL_INFO100,
5115 "RCET::HRCE: Connection changed %d \n",
5116 pEvent->ConnectionChange.connectionId);
5117
5118 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5119 pCallback2->ChangeConnection(this, pEvent->ConnectionChange.connectionId);
5120 }
5121 break;
5122
5123 case DB_IPCE_UNLOAD_MODULE:
5124 {
5125 STRESS_LOG3(LF_CORDB, LL_INFO100, "RCET::HRCE: unload module on thread %#x Mod:0x%x AD:0x%08x\n",
5126 dwVolatileThreadId,
5127 VmPtrToCookie(pEvent->UnloadModuleData.vmDomainFile),
5128 VmPtrToCookie(pEvent->vmAppDomain));
5129
5130 PREFIX_ASSUME (pAppDomain != NULL);
5131
5132 CordbModule *module = pAppDomain->LookupOrCreateModule(pEvent->UnloadModuleData.vmDomainFile);
5133
5134 if (module == NULL)
5135 {
5136 LOG((LF_CORDB, LL_INFO100, "Already unloaded Module - continue()ing!" ));
5137 break;
5138 }
5139 _ASSERTE(module != NULL);
5140 INDEBUG(module->DbgAssertModuleDeleted());
5141
5142 // The appdomain we're unloading in must be the appdomain we were loaded in. Otherwise, we've got mismatched
5143 // module and appdomain pointers. Bugs 65943 & 81728.
5144 _ASSERTE(pAppDomain == module->GetAppDomain());
5145
5146 // Ensure the module gets neutered once we call continue.
5147 AddToNeuterOnContinueList(module); // throws
5148 {
5149 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5150 pCallback1->UnloadModule(pAppDomain, module);
5151 }
5152
5153 pAppDomain->m_modules.RemoveBase(VmPtrToCookie(pEvent->UnloadModuleData.vmDomainFile));
5154 }
5155 break;
5156
5157 case DB_IPCE_LOAD_CLASS:
5158 {
5159 CordbClass *pClass = NULL;
5160
5161 LOG((LF_CORDB, LL_INFO10000,
5162 "RCET::HRCE: load class on thread %#x Tok:0x%08x Mod:0x%08x Asm:0x%08x AD:0x%08x\n",
5163 dwVolatileThreadId,
5164 pEvent->LoadClass.classMetadataToken,
5165 VmPtrToCookie(pEvent->LoadClass.vmDomainFile),
5166 LsPtrToCookie(pEvent->LoadClass.classDebuggerAssemblyToken),
5167 VmPtrToCookie(pEvent->vmAppDomain)));
5168
5169 _ASSERTE (pAppDomain != NULL);
5170
5171 CordbModule* pModule = pAppDomain->LookupOrCreateModule(pEvent->LoadClass.vmDomainFile);
5172 if (pModule == NULL)
5173 {
5174 LOG((LF_CORDB, LL_INFO100, "Load Class on not-loaded Module - continue()ing!" ));
5175 break;
5176 }
5177 _ASSERTE(pModule != NULL);
5178
5179 BOOL fDynamic = pModule->IsDynamic();
5180
5181 // If this is a class load in a dynamic module, the metadata has become invalid.
5182 if (fDynamic)
5183 {
5184 pModule->RefreshMetaData();
5185 }
5186
5187 hr = pModule->LookupOrCreateClass(pEvent->LoadClass.classMetadataToken, &pClass);
5188 _ASSERTE(SUCCEEDED(hr) == (pClass != NULL));
5189 IfFailThrow(hr);
5190
5191 // Prevent class load from being sent twice.
5192 // @dbgtodo - Microsoft, cordbclass: this is legacy. Can this really happen? Investigate as we dac-ize CordbClass.
5193 if (pClass->LoadEventSent())
5194 {
5195 // Dynamic modules are dynamic at the module level -
5196 // you can't add a new version of a class once the module
5197 // is baked.
5198 // EnC adds completely new classes.
5199 // There shouldn't be any other way to send multiple
5200 // ClassLoad events.
5201 // Except that there are race conditions between loading
5202 // an appdomain, and loading a class, so if we get the extra
5203 // class load, we should ignore it.
5204 break; //out of the switch statement
5205 }
5206 pClass->SetLoadEventSent(TRUE);
5207
5208
5209 if (pClass != NULL)
5210 {
5211 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5212 pCallback1->LoadClass(pAppDomain, pClass);
5213 }
5214 }
5215 break;
5216
5217 case DB_IPCE_UNLOAD_CLASS:
5218 {
5219 LOG((LF_CORDB, LL_INFO10000,
5220 "RCET::HRCE: unload class on thread %#x Tok:0x%08x Mod:0x%08x AD:0x%08x\n",
5221 dwVolatileThreadId,
5222 pEvent->UnloadClass.classMetadataToken,
5223 VmPtrToCookie(pEvent->UnloadClass.vmDomainFile),
5224 VmPtrToCookie(pEvent->vmAppDomain)));
5225
5226 // get the appdomain object
5227 _ASSERTE (pAppDomain != NULL);
5228
5229 CordbModule *pModule = pAppDomain->LookupOrCreateModule(pEvent->UnloadClass.vmDomainFile);
5230 if (pModule == NULL)
5231 {
5232 LOG((LF_CORDB, LL_INFO100, "Unload Class on not-loaded Module - continue()ing!" ));
5233 break;
5234 }
5235 _ASSERTE(pModule != NULL);
5236
5237 CordbClass *pClass = pModule->LookupClass(pEvent->UnloadClass.classMetadataToken);
5238
5239 if (pClass != NULL && !pClass->HasBeenUnloaded())
5240 {
5241 pClass->SetHasBeenUnloaded(true);
5242
5243 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5244 pCallback1->UnloadClass(pAppDomain, pClass);
5245 }
5246 }
5247 break;
5248
5249 case DB_IPCE_FIRST_LOG_MESSAGE:
5250 {
5251 _ASSERTE(pThread != NULL);
5252 _ASSERTE(pAppDomain != NULL);
5253
5254 const WCHAR * pszContent = pEvent->FirstLogMessage.szContent.GetString();
5255 {
5256 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5257 pCallback1->LogMessage(
5258 pAppDomain,
5259 pThread,
5260 pEvent->FirstLogMessage.iLevel,
5261 const_cast<WCHAR*> (pEvent->FirstLogMessage.szCategory.GetString()),
5262 const_cast<WCHAR*> (pszContent));
5263 }
5264 }
5265 break;
5266
5267 case DB_IPCE_LOGSWITCH_SET_MESSAGE:
5268 {
5269
5270 LOG((LF_CORDB, LL_INFO10000,
5271 "[%x] RCET::DRCE: Log Switch Setting Message.\n",
5272 GetCurrentThreadId()));
5273
5274 _ASSERTE(pThread != NULL);
5275
5276 const WCHAR *pstrLogSwitchName = pEvent->LogSwitchSettingMessage.szSwitchName.GetString();
5277 const WCHAR *pstrParentName = pEvent->LogSwitchSettingMessage.szParentSwitchName.GetString();
5278
5279 // from the thread object get the appdomain object
5280 _ASSERTE(pAppDomain == pThread->m_pAppDomain);
5281 _ASSERTE (pAppDomain != NULL);
5282
5283 {
5284 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5285 pCallback1->LogSwitch(
5286 pAppDomain,
5287 pThread,
5288 pEvent->LogSwitchSettingMessage.iLevel,
5289 pEvent->LogSwitchSettingMessage.iReason,
5290 const_cast<WCHAR*> (pstrLogSwitchName),
5291 const_cast<WCHAR*> (pstrParentName));
5292
5293 }
5294 }
5295
5296 break;
5297 case DB_IPCE_CUSTOM_NOTIFICATION:
5298 {
5299 _ASSERTE(pThread != NULL);
5300 _ASSERTE(pAppDomain != NULL);
5301
5302
5303 // determine first whether custom notifications for this type are enabled -- if not
5304 // we just return without doing anything.
5305 CordbClass * pNotificationClass = LookupClass(pAppDomain,
5306 pEvent->CustomNotification.vmDomainFile,
5307 pEvent->CustomNotification.classToken);
5308
5309 // if the class is NULL, that means the debugger never enabled notifications for it. Otherwise,
5310 // the CordbClass instance would already have been created when the notifications were
5311 // enabled.
5312 if ((pNotificationClass != NULL) && pNotificationClass->CustomNotificationsEnabled())
5313
5314 {
5315 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5316 pCallback3->CustomNotification(pThread, pAppDomain);
5317 }
5318 }
5319
5320 break;
5321
5322 case DB_IPCE_CREATE_APP_DOMAIN:
5323 {
5324 STRESS_LOG2(LF_CORDB, LL_INFO100,
5325 "RCET::HRCE: create appdomain on thread %#x AD:0x%08x \n",
5326 dwVolatileThreadId,
5327 VmPtrToCookie(pEvent->vmAppDomain));
5328
5329
5330 // Enumerate may have prepopulated the appdomain, so check if it already exists.
5331 // Either way, still send the CreateEvent. (We don't want to skip the Create event
5332 // just because the debugger did an enumerate)
5333 // We remove AppDomains from the hash as soon as they are exited.
5334 pAppDomain.Assign(LookupOrCreateAppDomain(pEvent->AppDomainData.vmAppDomain));
5335 _ASSERTE(pAppDomain != NULL); // throws on failure
5336
5337 {
5338 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5339 hr = pCallback1->CreateAppDomain(this, pAppDomain);
5340 }
5341 }
5342
5343
5344 break;
5345
5346 case DB_IPCE_EXIT_APP_DOMAIN:
5347 {
5348 STRESS_LOG2(LF_CORDB, LL_INFO100, "RCET::HRCE: exit appdomain on thread %#x AD:0x%08x \n",
5349 dwVolatileThreadId,
5350 VmPtrToCookie(pEvent->vmAppDomain));
5351
5352 // In debug-only builds, assert that the appdomain is indeed deleted and not discoverable.
5353 INDEBUG(DbgAssertAppDomainDeleted(pEvent->vmAppDomain));
5354
5355 // If we get an ExitAD message for which we have no AppDomain, then ignore it.
5356 // This can happen if an AD gets torn down very early (before the LS AD is to the
5357 // point that it can be published).
5358 // This could also happen if we attach a debugger right before the Exit event is sent.
5359 // In this case, the debuggee is no longer publishing the appdomain.
5360 if (pAppDomain == NULL)
5361 {
5362 break;
5363 }
5364 _ASSERTE (pAppDomain != NULL);
5365
5366 // See if this is the default AppDomain exiting. This should only happen very late in
5367 // the shutdown cycle, and so we shouldn't do anything significant with m_pDefaultDomain==NULL.
5368 // We should try and remove m_pDefaultDomain entirely since we can't count on it always existing.
5369 if (pAppDomain == m_pDefaultAppDomain)
5370 {
5371 m_pDefaultAppDomain = NULL;
5372 }
5373
5374 // Update any threads which were last seen in this AppDomain. We don't
5375 // get any notification when a thread leaves an AppDomain, so our idea
5376 // of what AppDomain the thread is in may be out of date.
5377 UpdateThreadsForAdUnload( pAppDomain );
5378
5379 // This will still maintain weak references so we could call Continue.
5380 AddToNeuterOnContinueList(pAppDomain);
5381
5382 {
5383 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5384 hr = pCallback1->ExitAppDomain(this, pAppDomain);
5385 }
5386
5387 // @dbgtodo appdomain: This should occur before the callback.
5388 // Even after ExitAppDomain, the outside world will want to continue calling
5389 // Continue (and thus they may need to call CordbAppDomain::GetProcess(), which Neutering
5390 // would clear). Thus we can't neuter yet.
5391
5392 // Remove this app domain. This means any attempt to lookup the AppDomain
5393 // will fail (which we do at the top of this method). Since any threads (incorrectly) referring
5394 // to this AppDomain have been moved to the default AppDomain, no one should be
5395 // interested in looking this AppDomain up anymore.
5396 m_appDomains.RemoveBase(VmPtrToCookie(pEvent->vmAppDomain));
5397 }
5398
5399 break;
5400
5401 case DB_IPCE_LOAD_ASSEMBLY:
5402 {
5403 LOG((LF_CORDB, LL_INFO100,
5404 "RCET::HRCE: load assembly on thread %#x Asm:0x%08x AD:0x%08x \n",
5405 dwVolatileThreadId,
5406 VmPtrToCookie(pEvent->AssemblyData.vmDomainAssembly),
5407 VmPtrToCookie(pEvent->vmAppDomain)));
5408
5409 _ASSERTE (pAppDomain != NULL);
5410
5411 // Determine if this Assembly is cached.
5412 CordbAssembly * pAssembly = pAppDomain->LookupOrCreateAssembly(pEvent->AssemblyData.vmDomainAssembly);
5413 _ASSERTE(pAssembly != NULL); // throws on error
5414
5415 // If created, or have, an Assembly, notify callback.
5416 {
5417 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5418 hr = pCallback1->LoadAssembly(pAppDomain, pAssembly);
5419 }
5420 }
5421
5422 break;
5423
5424 case DB_IPCE_UNLOAD_ASSEMBLY:
5425 {
5426 LOG((LF_CORDB, LL_INFO100, "RCET::DRCE: unload assembly on thread %#x Asm:0x%x AD:0x%x\n",
5427 dwVolatileThreadId,
5428 VmPtrToCookie(pEvent->AssemblyData.vmDomainAssembly),
5429 VmPtrToCookie(pEvent->vmAppDomain)));
5430
5431 _ASSERTE (pAppDomain != NULL);
5432
5433 CordbAssembly * pAssembly = pAppDomain->LookupOrCreateAssembly(pEvent->AssemblyData.vmDomainAssembly);
5434
5435 if (pAssembly == NULL)
5436 {
5437 // No assembly. This could happen if we attach right before an unload event is sent.
5438 return;
5439 }
5440 _ASSERTE(pAssembly != NULL);
5441 INDEBUG(pAssembly->DbgAssertAssemblyDeleted());
5442
5443 // Ensure the assembly gets neutered when we call continue.
5444 AddToNeuterOnContinueList(pAssembly); // throws
5445
5446 {
5447 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5448 hr = pCallback1->UnloadAssembly(pAppDomain, pAssembly);
5449 }
5450
5451 pAppDomain->RemoveAssemblyFromCache(pEvent->AssemblyData.vmDomainAssembly);
5452 }
5453
5454 break;
5455
5456 case DB_IPCE_FUNC_EVAL_COMPLETE:
5457 {
5458 LOG((LF_CORDB, LL_INFO1000, "RCET::DRCE: func eval complete.\n"));
5459
5460 CordbEval *pEval = NULL;
5461 {
5462 pEval = pEvent->FuncEvalComplete.funcEvalKey.UnWrapAndRemove(this);
5463 if (pEval == NULL)
5464 {
5465 _ASSERTE(!"Bogus FuncEval handle in IPC block.");
5466 // Bogus handle in IPC block.
5467 break;
5468 }
5469 }
5470 _ASSERTE(pEval != NULL);
5471
5472 _ASSERTE(pThread != NULL);
5473 _ASSERTE(pAppDomain != NULL);
5474
5475 CONSISTENCY_CHECK_MSGF(pEval->m_DbgAppDomainStarted == pAppDomain,
5476 ("AppDomain changed from Func-Eval. Eval=%p, Started=%p, Now=%p\n",
5477 pEval, pEval->m_DbgAppDomainStarted, (void*) pAppDomain));
5478
5479 // Hold the data about the result in the CordbEval for later.
5480 pEval->m_complete = true;
5481 pEval->m_successful = !!pEvent->FuncEvalComplete.successful;
5482 pEval->m_aborted = !!pEvent->FuncEvalComplete.aborted;
5483 pEval->m_resultAddr = pEvent->FuncEvalComplete.resultAddr;
5484 pEval->m_vmObjectHandle = pEvent->FuncEvalComplete.vmObjectHandle;
5485 pEval->m_resultType = pEvent->FuncEvalComplete.resultType;
5486 pEval->m_resultAppDomainToken = pEvent->FuncEvalComplete.vmAppDomain;
5487
5488 CordbAppDomain *pResultAppDomain = LookupOrCreateAppDomain(pEvent->FuncEvalComplete.vmAppDomain);
5489
5490 _ASSERTE(OutstandingEvalCount() > 0);
5491 DecrementOutstandingEvalCount();
5492
5493 CONSISTENCY_CHECK_MSGF(pEval->m_DbgAppDomainStarted == pAppDomain,
5494 ("AppDomain changed from Func-Eval. Eval=%p, Started=%p, Now=%p\n",
5495 pEval, pEval->m_DbgAppDomainStarted, (void*) pAppDomain));
5496
5497 // If we did this func eval with this thread stopped at an excpetion, then we need to pretend as if we
5498 // really didn't continue from the exception, since, of course, we really didn't on the Left Side.
5499 if (pEval->IsEvalDuringException())
5500 {
5501 pThread->SetExInfo(pEval->m_vmThreadOldExceptionHandle);
5502 }
5503
5504 bool fEvalCompleted = pEval->m_successful || pEval->m_aborted;
5505
5506 // If a CallFunction() is aborted, the LHS may not complete the abort
5507 // immediately and hence we cant do a SendCleanup() at that point. Also,
5508 // the debugger may (incorrectly) release the CordbEval before this
5509 // DB_IPCE_FUNC_EVAL_COMPLETE event is received. Hence, we maintain an
5510 // extra ref-count to determine when this can be done.
5511 // Note that this can cause a two-way DB_IPCE_FUNC_EVAL_CLEANUP event
5512 // to be sent. Hence, it has to be done before the Continue (see issue 102745).
5513
5514
5515 // Note that if the debugger has already (incorrectly) released the CordbEval,
5516 // pEval will be pointing to garbage and should not be used by the debugger.
5517 if (fEvalCompleted)
5518 {
5519 PUBLIC_CALLBACK_IN_THIS_SCOPE2(this, pLockHolder, pEvent, "thread=0x%p, eval=0x%p. (Complete)", pThread, pEval);
5520 pCallback1->EvalComplete(pResultAppDomain, pThread, pEval);
5521 }
5522 else
5523 {
5524 PUBLIC_CALLBACK_IN_THIS_SCOPE2(this, pLockHolder, pEvent, "pThread=0x%p, eval=0x%p. (Exception)", pThread, pEval);
5525 pCallback1->EvalException(pResultAppDomain, pThread, pEval);
5526 }
5527
5528 // This release may send an DB_IPCE_FUNC_EVAL_CLEANUP IPC event. That's ok b/c
5529 // we're still synced even if if Continue was called inside the callback.
5530 // That's because the StopContinueHolder bumped up the stopcount.
5531 // Corresponding AddRef() in CallFunction().
5532 // @todo - this is leaked if we don't get an EvalComplete event (eg, process exits with
5533 // in middle of func-eval).
5534 pEval->Release();
5535 }
5536 break;
5537
5538
5539 case DB_IPCE_NAME_CHANGE:
5540 {
5541 LOG((LF_CORDB, LL_INFO1000, "RCET::HRCE: Name Change %d 0x%p\n",
5542 dwVolatileThreadId,
5543 VmPtrToCookie(pEvent->NameChange.vmAppDomain)));
5544
5545 pThread = NULL;
5546 pAppDomain.Clear();
5547 if (pEvent->NameChange.eventType == THREAD_NAME_CHANGE)
5548 {
5549 // Lookup the CordbThread that matches this runtime thread.
5550 if (!pEvent->NameChange.vmThread.IsNull())
5551 {
5552 pThread = LookupOrCreateThread(pEvent->NameChange.vmThread);
5553 }
5554 }
5555 else
5556 {
5557 _ASSERTE (pEvent->NameChange.eventType == APP_DOMAIN_NAME_CHANGE);
5558 pAppDomain.Assign(LookupOrCreateAppDomain(pEvent->NameChange.vmAppDomain));
5559 if (pAppDomain)
5560 {
5561 pAppDomain->InvalidateName();
5562 }
5563 }
5564
5565 if (pThread || pAppDomain)
5566 {
5567 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5568 pCallback1->NameChange(pAppDomain, pThread);
5569 }
5570 }
5571
5572 break;
5573
5574 case DB_IPCE_UPDATE_MODULE_SYMS:
5575 {
5576 RSExtSmartPtr<IStream> pStream;
5577
5578 // Find the app domain the module lives in.
5579 _ASSERTE (pAppDomain != NULL);
5580
5581 // Find the Right Side module for this module.
5582 CordbModule * pModule = pAppDomain->LookupOrCreateModule(pEvent->UpdateModuleSymsData.vmDomainFile);
5583 _ASSERTE(pModule != NULL);
5584
5585 // This is a legacy event notification for updated PDBs.
5586 // Creates a new IStream object. Ownership is handed off via callback.
5587 IDacDbiInterface::SymbolFormat symFormat = pModule->GetInMemorySymbolStream(&pStream);
5588
5589 // We shouldn't get this event if there aren't PDB symbols waiting. Specifically we don't want
5590 // to incur the cost of copying over ILDB symbols here without the debugger asking for them.
5591 // Eventually we may remove this callback as well and always rely on explicit requests.
5592 _ASSERTE(symFormat == IDacDbiInterface::kSymbolFormatPDB);
5593
5594 if (symFormat == IDacDbiInterface::kSymbolFormatPDB)
5595 {
5596 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5597
5598 _ASSERTE(pStream != NULL); // Shouldn't send the event if we don't have a stream.
5599
5600 pCallback1->UpdateModuleSymbols(pAppDomain, pModule, pStream);
5601 }
5602
5603 }
5604 break;
5605
5606 case DB_IPCE_MDA_NOTIFICATION:
5607 {
5608 RSInitHolder<CordbMDA> pMDA(new CordbMDA(this, &pEvent->MDANotification)); // throws
5609
5610 // Ctor leaves both internal + ext Ref at 0, adding to neuter list bumps int-ref up to 1.
5611 // Neutering will dump it back down to zero.
5612 this->AddToNeuterOnExitList(pMDA);
5613
5614 // We bump up and down the external ref so that even if the callback doensn't touch the refs,
5615 // our Ext-Release here will still cause a 1->0 ext-ref transition, which will get it
5616 // swept on the neuter list.
5617 RSExtSmartPtr<ICorDebugMDA> pExternalMDARef;
5618 pMDA.TransferOwnershipExternal(&pExternalMDARef);
5619 {
5620 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5621
5622 pCallback2->MDANotification(
5623 this,
5624 pThread, // may be null
5625 pExternalMDARef);
5626
5627 // pExternalMDARef's dtor will do an external release,
5628 // which is very significant because it may be the one that does the 1->0 ext ref transition,
5629 // which may mean cause the "NeuterAtWill" bit to get flipped on this CordbMDA object.
5630 // Since this is an external release, do it in the PUBLIC_CALLBACK scope.
5631 pExternalMDARef.Clear();
5632 }
5633
5634 break;
5635 }
5636
5637 case DB_IPCE_CONTROL_C_EVENT:
5638 {
5639 hr = S_FALSE;
5640
5641 {
5642 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5643 hr = pCallback1->ControlCTrap((ICorDebugProcess*) this);
5644 }
5645
5646 {
5647 RSLockHolder ch(this->GetStopGoLock());
5648
5649 DebuggerIPCEvent eventControlCResult;
5650
5651 InitIPCEvent(&eventControlCResult,
5652 DB_IPCE_CONTROL_C_EVENT_RESULT,
5653 false,
5654 VMPTR_AppDomain::NullPtr());
5655
5656 // Indicate whether the debugger has handled the event.
5657 eventControlCResult.hr = hr;
5658
5659 // Send the reply to the LS.
5660 SendIPCEvent(&eventControlCResult, sizeof(eventControlCResult));
5661 } // release SG lock
5662
5663 }
5664 break;
5665
5666 // EnC Remap opportunity
5667 case DB_IPCE_ENC_REMAP:
5668 {
5669 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC Remap!.\n",
5670 GetCurrentThreadId()));
5671
5672 _ASSERTE(NULL != pAppDomain);
5673
5674 CordbModule * pModule = pAppDomain->LookupOrCreateModule(pEvent->EnCRemap.vmDomainFile);
5675 PREFIX_ASSUME(pModule != NULL);
5676
5677 CordbFunction * pCurFunction = NULL;
5678 CordbFunction * pResumeFunction = NULL;
5679
5680 // lookup the version of the function that we are mapping from
5681 // this is the one that is currently running
5682 pCurFunction = pModule->LookupOrCreateFunction(
5683 pEvent->EnCRemap.funcMetadataToken, pEvent->EnCRemap.currentVersionNumber);
5684
5685 // lookup the version of the function that we are mapping to
5686 // it will always be the most recent
5687 pResumeFunction = pModule->LookupOrCreateFunction(
5688 pEvent->EnCRemap.funcMetadataToken, pEvent->EnCRemap.resumeVersionNumber);
5689
5690 _ASSERTE(pCurFunction->GetEnCVersionNumber() < pResumeFunction->GetEnCVersionNumber());
5691
5692 RSSmartPtr<CordbFunction> pRefCurFunction(pCurFunction);
5693 RSSmartPtr<CordbFunction> pRefResumeFunction(pResumeFunction);
5694
5695 // Verify we're not about to overwrite an outstanding remap IP
5696 // This should only be set while a remap opportunity is being handled,
5697 // and cleared (by CordbThread::MarkStackFramesDirty) on Continue.
5698 // We want to be absolutely sure we don't accidentally keep a stale pointer
5699 // around because it would point to arbitrary stack space in the CLR potentially
5700 // leading to stack corruption.
5701 _ASSERTE( pThread->m_EnCRemapFunctionIP == NULL );
5702
5703 // Stash the address of the remap IP buffer. This indicates that calling
5704 // RemapFunction is valid and provides a communications channel between the RS
5705 // and LS for the remap IL offset.
5706 pThread->m_EnCRemapFunctionIP = pEvent->EnCRemap.resumeILOffset;
5707
5708 {
5709 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5710 pCallback2->FunctionRemapOpportunity(
5711 pAppDomain,
5712 pThread,
5713 pCurFunction,
5714 pResumeFunction,
5715 (ULONG32)pEvent->EnCRemap.currentILOffset);
5716 }
5717
5718 // Implicit release on pCurFunction and pResumeFunction.
5719 }
5720 break;
5721
5722 // EnC Remap complete
5723 case DB_IPCE_ENC_REMAP_COMPLETE:
5724 {
5725 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC Remap Complete!.\n",
5726 GetCurrentThreadId()));
5727
5728 _ASSERTE(NULL != pAppDomain);
5729
5730 CordbModule* pModule = pAppDomain->LookupOrCreateModule(pEvent->EnCRemap.vmDomainFile);
5731 PREFIX_ASSUME(pModule != NULL);
5732
5733 // Find the function we're remapping to, which must be the latest version
5734 CordbFunction *pRemapFunction=
5735 pModule->LookupFunctionLatestVersion(pEvent->EnCRemapComplete.funcMetadataToken);
5736 PREFIX_ASSUME(pRemapFunction != NULL);
5737
5738 // Dispatch the FunctionRemapComplete callback
5739 RSSmartPtr<CordbFunction> pRef(pRemapFunction);
5740 {
5741 PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
5742 pCallback2->FunctionRemapComplete(pAppDomain, pThread, pRemapFunction);
5743 }
5744 // Implicit release on pRemapFunction via holder
5745 }
5746 break;
5747
5748 case DB_IPCE_BREAKPOINT_SET_ERROR:
5749 {
5750 LOG((LF_CORDB, LL_INFO1000, "RCET::DRCE: breakpoint set error.\n"));
5751
5752 RSSmartPtr<CordbBreakpoint> pRef;
5753
5754 _ASSERTE(pThread != NULL);
5755 _ASSERTE(pAppDomain != NULL);
5756
5757 // Find the breakpoint object on this side.
5758 CordbBreakpoint * pBreakpoint = NULL;
5759
5760
5761 if (pThread == NULL)
5762 {
5763 // We've found cases out in the wild where we get this event on a thread we don't recognize.
5764 // We're not sure how this happens. Add a runtime check to protect ourselves to avoid the
5765 // an AV. We still assert because this should not be happening.
5766 // It likely means theres some issue where we failed to send a CreateThread notification.
5767 STRESS_LOG1(LF_CORDB, LL_INFO1000, "BreakpointSetError on unrecognized thread. %p\n", pBreakpoint);
5768
5769 _ASSERTE(!"Missing thread on bp set error");
5770 break;
5771 }
5772
5773 pBreakpoint = pAppDomain->m_breakpoints.GetBase(LsPtrToCookie(pEvent->BreakpointSetErrorData.breakpointToken));
5774
5775 if (pBreakpoint != NULL)
5776 {
5777 ICorDebugBreakpoint * pIBreakpoint = CordbBreakpointToInterface(pBreakpoint);
5778 _ASSERTE(pIBreakpoint != NULL);
5779 {
5780 PUBLIC_CALLBACK_IN_THIS_SCOPE2(this, pLockHolder, pEvent, "thread=0x%p, bp=0x%p", pThread, pBreakpoint);
5781 pCallback1->BreakpointSetError(pAppDomain, pThread, pIBreakpoint, 0);
5782 }
5783 }
5784 // Implicit release on pRef.
5785 }
5786 break;
5787
5788
5789 case DB_IPCE_EXCEPTION_CALLBACK2:
5790 {
5791 STRESS_LOG4(LF_CORDB, LL_INFO100,
5792 "RCET::DRCE: Exception2 0x%p 0x%X 0x%X 0x%X\n",
5793 pEvent->ExceptionCallback2.framePointer.GetSPValue(),
5794 pEvent->ExceptionCallback2.nOffset,
5795 pEvent->ExceptionCallback2.eventType,
5796 pEvent->ExceptionCallback2.dwFlags
5797 );
5798
5799 if (pThread == NULL)
5800 {
5801 // We've got an exception on a thread we don't know about. This could be a thread that
5802 // has never run any managed code, so let's just ignore the exception. We should have
5803 // already sent a log message about this situation for the EXCEPTION callback above.
5804 _ASSERTE( pEvent->ExceptionCallback2.eventType == DEBUG_EXCEPTION_UNHANDLED );
5805 break;
5806 }
5807
5808 pThread->SetExInfo(pEvent->ExceptionCallback2.vmExceptionHandle);
5809
5810 //
5811 // Send all the information back to the debugger.
5812 //
5813 RSSmartPtr<CordbFrame> pFrame;
5814
5815 FramePointer fp = pEvent->ExceptionCallback2.framePointer;
5816 if (fp != LEAF_MOST_FRAME)
5817 {
5818 // The interface forces us to to pass a FramePointer via an ICorDebugFrame.
5819 // However, we can't get a real ICDFrame without a stackwalk, and we don't
5820 // want to do a stackwalk now. so pass a netuered proxy frame. The shim
5821 // can map this to a real frame.
5822 // See comments at CordbPlaceHolderFrame class for details.
5823 pFrame.Assign(new CordbPlaceholderFrame(this, fp));
5824 }
5825
5826 CorDebugExceptionCallbackType type = pEvent->ExceptionCallback2.eventType;
5827 {
5828 PUBLIC_CALLBACK_IN_THIS_SCOPE3(this, pLockHolder, pEvent, "pThread=0x%p, frame=%p, type=%d", pThread, (ICorDebugFrame*) pFrame, type);
5829 hr = pCallback2->Exception(
5830 pThread->m_pAppDomain,
5831 pThread,
5832 pFrame,
5833 (ULONG32)(pEvent->ExceptionCallback2.nOffset),
5834 type,
5835 pEvent->ExceptionCallback2.dwFlags);
5836 }
5837 }
5838 break;
5839
5840 case DB_IPCE_EXCEPTION_UNWIND:
5841 {
5842 STRESS_LOG2(LF_CORDB, LL_INFO100,
5843 "RCET::DRCE: Exception Unwind 0x%X 0x%X\n",
5844 pEvent->ExceptionCallback2.eventType,
5845 pEvent->ExceptionCallback2.dwFlags
5846 );
5847
5848 if (pThread == NULL)
5849 {
5850 // We've got an exception on a thread we don't know about. This probably should never
5851 // happen (if it's unwinding, then we expect a managed frame on the stack, and so we should
5852 // know about the thread), but if it does fall back to ignoring the exception.
5853 _ASSERTE( !"Got unwind event for unknown exception" );
5854 break;
5855 }
5856
5857 //
5858 // Send all the information back to the debugger.
5859 //
5860 {
5861 PUBLIC_CALLBACK_IN_THIS_SCOPE1(this, pLockHolder, pEvent, "pThread=0x%p", pThread);
5862 hr = pCallback2->ExceptionUnwind(
5863 pThread->m_pAppDomain,
5864 pThread,
5865 pEvent->ExceptionUnwind.eventType,
5866 pEvent->ExceptionUnwind.dwFlags);
5867 }
5868 }
5869 break;
5870
5871
5872 case DB_IPCE_INTERCEPT_EXCEPTION_COMPLETE:
5873 {
5874 STRESS_LOG0(LF_CORDB, LL_INFO100, "RCET::DRCE: Exception Interception Complete.\n");
5875
5876 if (pThread == NULL)
5877 {
5878 // We've got an exception on a thread we don't know about. This probably should never
5879 // happen (if it's unwinding, then we expect a managed frame on the stack, and so we should
5880 // know about the thread), but if it does fall back to ignoring the exception.
5881 _ASSERTE( !"Got complete event for unknown exception" );
5882 break;
5883 }
5884
5885 //
5886 // Tell the debugger that the exception has been intercepted. This is similar to the
5887 // notification we give when we start unwinding for a non-intercepted exception, except that the
5888 // interception has been completed at this point, which means that we are conceptually at the end
5889 // of the second pass.
5890 //
5891 {
5892 PUBLIC_CALLBACK_IN_THIS_SCOPE1(this, pLockHolder, pEvent, "pThread=0x%p", pThread);
5893 hr = pCallback2->ExceptionUnwind(
5894 pThread->m_pAppDomain,
5895 pThread,
5896 DEBUG_EXCEPTION_INTERCEPTED,
5897 0);
5898 }
5899 }
5900 break;
5901#ifdef TEST_DATA_CONSISTENCY
5902 case DB_IPCE_TEST_CRST:
5903 {
5904 EX_TRY
5905 {
5906 // the left side has signaled that we should test whether pEvent->TestCrstData.vmCrst is held
5907 GetDAC()->TestCrst(pEvent->TestCrstData.vmCrst);
5908 }
5909 EX_CATCH_HRESULT(hr);
5910
5911 if (pEvent->TestCrstData.fOkToTake)
5912 {
5913 _ASSERTE(hr == S_OK);
5914 if (hr != S_OK)
5915 {
5916 // we want to catch this in retail builds too
5917 ThrowHR(E_FAIL);
5918 }
5919 }
5920 else // the lock was already held
5921 {
5922 // see if we threw because the lock was held
5923 _ASSERTE(hr == CORDBG_E_PROCESS_NOT_SYNCHRONIZED);
5924 if (hr != CORDBG_E_PROCESS_NOT_SYNCHRONIZED)
5925 {
5926 // we want to catch this in retail builds too
5927 ThrowHR(E_FAIL);
5928 }
5929 }
5930
5931 }
5932 break;
5933
5934 case DB_IPCE_TEST_RWLOCK:
5935 {
5936 EX_TRY
5937 {
5938 // the left side has signaled that we should test whether pEvent->TestRWLockData.vmRWLock is held
5939 GetDAC()->TestRWLock(pEvent->TestRWLockData.vmRWLock);
5940 }
5941 EX_CATCH_HRESULT(hr);
5942
5943 if (pEvent->TestRWLockData.fOkToTake)
5944 {
5945 _ASSERTE(hr == S_OK);
5946 if (hr != S_OK)
5947 {
5948 // we want to catch this in retail builds too
5949 ThrowHR(E_FAIL);
5950 }
5951 }
5952 else // the lock was already held
5953 {
5954 // see if we threw because the lock was held
5955 _ASSERTE(hr == CORDBG_E_PROCESS_NOT_SYNCHRONIZED);
5956 if (hr != CORDBG_E_PROCESS_NOT_SYNCHRONIZED)
5957 {
5958 // we want to catch this in retail builds too
5959 ThrowHR(E_FAIL);
5960 }
5961 }
5962 }
5963 break;
5964#endif
5965
5966 default:
5967 _ASSERTE(!"Unknown event");
5968 LOG((LF_CORDB, LL_INFO1000,
5969 "[%x] RCET::HRCE: Unknown event: 0x%08x\n",
5970 GetCurrentThreadId(), pEvent->type));
5971 }
5972
5973
5974 FinishEventDispatch();
5975}
5976#ifdef _PREFAST_
5977#pragma warning(pop)
5978#endif
5979
5980//---------------------------------------------------------------------------------------
5981// Callback for prepopulating threads.
5982//
5983// Arugments:
5984// vmThread - thread as part of the eunmeration.
5985// pUserData - data supplied with callback. It's a CordbProcess* object.
5986//
5987
5988// static
5989void CordbProcess::ThreadEnumerationCallback(VMPTR_Thread vmThread, void * pUserData)
5990{
5991 CordbProcess * pThis = reinterpret_cast<CordbProcess *> (pUserData);
5992 INTERNAL_DAC_CALLBACK(pThis);
5993
5994 STRESS_LOG0(LF_CORDB, LL_INFO1000, "ThreadEnumerationCallback()\n");
5995
5996 // Do lookup / lazy-create.
5997 pThis->LookupOrCreateThread(vmThread);
5998}
5999
6000//---------------------------------------------------------------------------------------
6001// Fully build up the CordbThread cache to match VM state.
6002void CordbProcess::PrepopulateThreadsOrThrow()
6003{
6004 RSLockHolder lockHolder(GetProcessLock());
6005 if (IsDacInitialized())
6006 {
6007 STRESS_LOG0(LF_CORDB, LL_INFO1000, "PrepopulateThreadsOrThrow()\n");
6008 GetDAC()->EnumerateThreads(ThreadEnumerationCallback, this);
6009 }
6010}
6011
6012//---------------------------------------------------------------------------------------
6013// Create a Thread enumerator
6014//
6015// Arguments:
6016// pOwnerObj - object (a CordbProcess or CordbThread) that will own the enumerator.
6017// pOwnerList - the neuter list that the enumerator will live on
6018// pHolder - an outparameter for the enumerator to be initialized.
6019//
6020void CordbProcess::BuildThreadEnum(CordbBase * pOwnerObj, NeuterList * pOwnerList, RSInitHolder<CordbHashTableEnum> * pHolder)
6021{
6022 CordbHashTableEnum::BuildOrThrow(
6023 pOwnerObj,
6024 pOwnerList,
6025 &m_userThreads,
6026 IID_ICorDebugThreadEnum,
6027 pHolder);
6028}
6029
6030// Public implementation of ICorDebugProcess::EnumerateThreads
6031HRESULT CordbProcess::EnumerateThreads(ICorDebugThreadEnum **ppThreads)
6032{
6033 HRESULT hr = S_OK;
6034 PUBLIC_API_BEGIN(this);
6035 {
6036 if (m_detached)
6037 {
6038 // #Detach_Check:
6039 //
6040 // FUTURE: Consider adding this IF block to the PUBLIC_API macros so that
6041 // typical public APIs fail quickly if we're trying to do a detach. For
6042 // now, I'm hand-adding this check only to the few problematic APIs that get
6043 // called while queuing the fake attach events. In these cases, it is not
6044 // enough to check if CordbProcess::IsNeutered(), as the detaching thread
6045 // may have begun the detaching and neutering process, but not be
6046 // finished--in which case m_detached is true, but
6047 // CordbProcess::IsNeutered() is still false.
6048 ThrowHR(CORDBG_E_PROCESS_DETACHED);
6049 }
6050
6051 ValidateOrThrow(ppThreads);
6052
6053 RSInitHolder<CordbHashTableEnum> pEnum;
6054 InternalEnumerateThreads(pEnum.GetAddr());
6055
6056 pEnum.TransferOwnershipExternal(ppThreads);
6057 }
6058 PUBLIC_API_END(hr);
6059 return hr;
6060}
6061
6062// Internal implementation of EnumerateThreads
6063VOID CordbProcess::InternalEnumerateThreads(RSInitHolder<CordbHashTableEnum> *ppThreads)
6064{
6065 INTERNAL_API_ENTRY(this);
6066 // Needs to prepopulate
6067 PrepopulateThreadsOrThrow();
6068 BuildThreadEnum(this, this->GetContinueNeuterList(), ppThreads);
6069}
6070
6071// Implementation of ICorDebugProcess::GetThread
6072HRESULT CordbProcess::GetThread(DWORD dwThreadId, ICorDebugThread **ppThread)
6073{
6074 PUBLIC_API_ENTRY(this);
6075 VALIDATE_POINTER_TO_OBJECT(ppThread, ICorDebugThread **);
6076
6077 // No good pre-existing ATT_* contract for this.
6078 // Because for legacy, we have to allow this on the win32 event thread.
6079 *ppThread = NULL;
6080
6081 HRESULT hr = S_OK;
6082 EX_TRY
6083 {
6084 RSLockHolder lockHolder(GetProcessLock());
6085 if (m_detached)
6086 {
6087 // See code:CordbProcess::EnumerateThreads#Detach_Check
6088 ThrowHR(CORDBG_E_PROCESS_DETACHED);
6089 }
6090 CordbThread * pThread = TryLookupOrCreateThreadByVolatileOSId(dwThreadId);
6091 if (pThread == NULL)
6092 {
6093 // This is a common case because we may be looking up an unmanaged thread.
6094 hr = E_INVALIDARG;
6095 }
6096 else
6097 {
6098 *ppThread = static_cast<ICorDebugThread*> (pThread);
6099 pThread->ExternalAddRef();
6100 }
6101 }
6102 EX_CATCH_HRESULT(hr);
6103
6104 LOG((LF_CORDB, LL_INFO10000, "CP::GT returns id=0x%x hr=0x%x ppThread=0x%p",
6105 dwThreadId, hr, *ppThread));
6106 return hr;
6107}
6108
6109HRESULT CordbProcess::ThreadForFiberCookie(DWORD fiberCookie,
6110 ICorDebugThread **ppThread)
6111{
6112 return E_NOTIMPL;
6113}
6114
6115HRESULT CordbProcess::GetHelperThreadID(DWORD *pThreadID)
6116{
6117 PUBLIC_API_ENTRY(this);
6118 FAIL_IF_NEUTERED(this);
6119
6120 _ASSERTE(m_pShim != NULL);
6121 if (pThreadID == NULL)
6122 {
6123 return (E_INVALIDARG);
6124 }
6125
6126 HRESULT hr = S_OK;
6127 // Return the ID of the current helper thread. There may be no thread in the process, or there may be a true helper
6128 // thread.
6129 if ((m_helperThreadId != 0) && !m_helperThreadDead)
6130 {
6131 *pThreadID = m_helperThreadId;
6132 }
6133 else if ((GetDCB() != NULL) && (GetDCB()->m_helperThreadId != 0))
6134 {
6135 EX_TRY
6136 {
6137 // be sure we have the latest information
6138 UpdateRightSideDCB();
6139 *pThreadID = GetDCB()->m_helperThreadId;
6140 }
6141 EX_CATCH_HRESULT(hr);
6142
6143 }
6144 else
6145 {
6146 *pThreadID = 0;
6147 }
6148
6149 return hr;
6150}
6151
6152//---------------------------------------------------------------------------------------
6153//
6154// Sends IPC event to set all the managed threads, except for the one given, to the given state
6155//
6156// Arguments:
6157// state - The state to set the threads to.
6158// pExceptThread - The thread to not set. This is usually the thread that is currently
6159// sending an IPC event to the RS, and should be excluded.
6160//
6161// Return Value:
6162// Typical HRESULT symantics, nothing abnormal.
6163//
6164HRESULT CordbProcess::SetAllThreadsDebugState(CorDebugThreadState state,
6165 ICorDebugThread * pExceptThread)
6166{
6167 PUBLIC_REENTRANT_API_ENTRY(this);
6168 FAIL_IF_NEUTERED(this);
6169 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pExceptThread, ICorDebugThread *);
6170 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
6171
6172 if (GetShim() == NULL)
6173 {
6174 return E_NOTIMPL;
6175 }
6176 CordbThread * pCordbExceptThread = static_cast<CordbThread *> (pExceptThread);
6177
6178 LOG((LF_CORDB, LL_INFO1000, "CP::SATDS: except thread=0x%08x 0x%x\n",
6179 pExceptThread,
6180 (pCordbExceptThread != NULL) ? pCordbExceptThread->m_id : 0));
6181
6182 // Send one event to the Left Side to twiddle each thread's state.
6183 DebuggerIPCEvent event;
6184
6185 InitIPCEvent(&event, DB_IPCE_SET_ALL_DEBUG_STATE, true, VMPTR_AppDomain::NullPtr());
6186
6187 event.SetAllDebugState.vmThreadToken = ((pCordbExceptThread != NULL) ?
6188 pCordbExceptThread->m_vmThreadToken : VMPTR_Thread::NullPtr());
6189
6190 event.SetAllDebugState.debugState = state;
6191
6192 HRESULT hr = SendIPCEvent(&event, sizeof(DebuggerIPCEvent));
6193
6194 hr = WORST_HR(hr, event.hr);
6195
6196 // If that worked, then loop over all the threads on this side and set their states.
6197 if (SUCCEEDED(hr))
6198 {
6199 RSLockHolder lockHolder(GetProcessLock());
6200 HASHFIND hashFind;
6201 CordbThread * pThread;
6202
6203 // We don't need to prepopulate here (to collect LS state) because we're just updating RS state.
6204 for (pThread = m_userThreads.FindFirst(&hashFind);
6205 pThread != NULL;
6206 pThread = m_userThreads.FindNext(&hashFind))
6207 {
6208 if (pThread != pCordbExceptThread)
6209 {
6210 pThread->m_debugState = state;
6211 }
6212 }
6213 }
6214
6215 return hr;
6216}
6217
6218
6219HRESULT CordbProcess::EnumerateObjects(ICorDebugObjectEnum **ppObjects)
6220{
6221 /* !!! */
6222 PUBLIC_API_ENTRY(this);
6223 FAIL_IF_NEUTERED(this);
6224 VALIDATE_POINTER_TO_OBJECT(ppObjects, ICorDebugObjectEnum **);
6225
6226 return E_NOTIMPL;
6227}
6228
6229//---------------------------------------------------------------------------------------
6230//
6231// Determines if the target address is a "CLR transition stub".
6232//
6233// Arguments:
6234// address - The address of an instruction to check in the target address space.
6235// pfTransitionStub - Space to store the result, TRUE if the address belongs to a
6236// transition stub, FALSE if not. Only valid if this method returns a success code.
6237//
6238// Return Value:
6239// Typical HRESULT symantics, nothing abnormal.
6240//
6241//---------------------------------------------------------------------------------------
6242HRESULT CordbProcess::IsTransitionStub(CORDB_ADDRESS address, BOOL *pfTransitionStub)
6243{
6244 PUBLIC_API_ENTRY(this);
6245 FAIL_IF_NEUTERED(this);
6246 VALIDATE_POINTER_TO_OBJECT(pfTransitionStub, BOOL *);
6247
6248 // Default to FALSE
6249 *pfTransitionStub = FALSE;
6250
6251 if (this->m_helperThreadDead)
6252 {
6253 return S_OK;
6254 }
6255
6256 // If we're not initialized, then it can't be a stub...
6257 if (!m_initialized)
6258 {
6259 return S_OK;
6260 }
6261
6262 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
6263
6264 HRESULT hr = S_OK;
6265 EX_TRY
6266 {
6267 DebuggerIPCEvent eventData;
6268
6269 InitIPCEvent(&eventData, DB_IPCE_IS_TRANSITION_STUB, true, VMPTR_AppDomain::NullPtr());
6270
6271 eventData.IsTransitionStub.address = CORDB_ADDRESS_TO_PTR(address);
6272
6273 hr = SendIPCEvent(&eventData, sizeof(eventData));
6274 hr = WORST_HR(hr, eventData.hr);
6275 IfFailThrow(hr);
6276
6277 _ASSERTE(eventData.type == DB_IPCE_IS_TRANSITION_STUB_RESULT);
6278
6279 *pfTransitionStub = eventData.IsTransitionStubResult.isStub;
6280 LOG((LF_CORDB, LL_INFO1000, "CP::ITS: addr=0x%p result=%d\n", address, *pfTransitionStub));
6281 // @todo - beware that IsTransitionStub has a very important sideeffect - it synchronizes the runtime!
6282 // This for example covers an OS bug where SetThreadContext may silently fail if we're not synchronized.
6283 // (See IMDArocess::SetThreadContext for details on that bug).
6284 // If we ever stop using IPC events here and only use DAC; we need to be aware of that.
6285
6286 // Check against DAC primitives
6287 {
6288 BOOL fIsStub2 = GetDAC()->IsTransitionStub(address);
6289 (void)fIsStub2; //prevent "unused variable" error from GCC
6290 CONSISTENCY_CHECK_MSGF(*pfTransitionStub == fIsStub2, ("IsStub2 failed, DAC2:%d, IPC:%d, addr:0x%p", (int) fIsStub2, (int) *pfTransitionStub, CORDB_ADDRESS_TO_PTR(address)));
6291
6292 }
6293 }
6294 EX_CATCH_HRESULT(hr);
6295 if(FAILED(hr))
6296 {
6297 LOG((LF_CORDB, LL_INFO1000, "CP::ITS: FAILED hr=0x%x\n", hr));
6298 }
6299 return hr;
6300}
6301
6302
6303HRESULT CordbProcess::SetStopState(DWORD threadID, CorDebugThreadState state)
6304{
6305 PUBLIC_API_ENTRY(this);
6306 FAIL_IF_NEUTERED(this);
6307 return E_NOTIMPL;
6308}
6309
6310HRESULT CordbProcess::IsOSSuspended(DWORD threadID, BOOL *pbSuspended)
6311{
6312 PUBLIC_API_ENTRY(this);
6313 // Gotta have a place for the result!
6314 if (!pbSuspended)
6315 return E_INVALIDARG;
6316
6317 FAIL_IF_NEUTERED(this);
6318
6319#ifdef FEATURE_INTEROP_DEBUGGING
6320 RSLockHolder lockHolder(GetProcessLock());
6321
6322 // Have we seen this thread?
6323 CordbUnmanagedThread *ut = GetUnmanagedThread(threadID);
6324
6325 // If we have, and if we've suspended it, then say so.
6326 if (ut && ut->IsSuspended())
6327 {
6328 *pbSuspended = TRUE;
6329 }
6330 else
6331 {
6332 *pbSuspended = FALSE;
6333 }
6334#else
6335 // Not interop-debugging, we never OS suspend.
6336 *pbSuspended = FALSE;
6337#endif
6338 return S_OK;
6339}
6340
6341//
6342// This routine reads a thread context from the process being debugged, taking into account the fact that the context
6343// record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate
6344// space for the extended registers. However, the CONTEXT struct that we compile with does have this space.
6345//
6346HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, DT_CONTEXT * pCtx)
6347{
6348 HRESULT hr = S_OK;
6349
6350 INTERNAL_API_ENTRY(this);
6351 FAIL_IF_NEUTERED(this);
6352
6353 EX_TRY
6354 {
6355
6356 void *pRemoteContext = pContext.UnsafeGet();
6357 TargetBuffer tbFull(pRemoteContext, sizeof(DT_CONTEXT));
6358
6359 // The context may have 2 parts:
6360 // 1. Base register, which are always present.
6361 // 2. Optional extended registers, which are only present if CONTEXT_EXTENDED_REGISTERS is set
6362 // in the flags.
6363
6364 // At a minimum we have room for a whole context up to the extended registers.
6365 #if defined(DT_CONTEXT_EXTENDED_REGISTERS)
6366 ULONG32 minContextSize = offsetof(DT_CONTEXT, ExtendedRegisters);
6367 #else
6368 ULONG32 minContextSize = sizeof(DT_CONTEXT);
6369 #endif
6370
6371 // Read the minimum part.
6372 TargetBuffer tbMin = tbFull.SubBuffer(0, minContextSize);
6373 SafeReadBuffer(tbMin, (BYTE*) pCtx);
6374
6375 #if defined(DT_CONTEXT_EXTENDED_REGISTERS)
6376 void *pCurExtReg = (void*)((UINT_PTR)pCtx + minContextSize);
6377 TargetBuffer tbExtended = tbFull.SubBuffer(minContextSize);
6378
6379 // Now, read the extended registers if the context contains them. If the context does not have extended registers,
6380 // just set them to zero.
6381 if (SUCCEEDED(hr) && (pCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
6382 {
6383 SafeReadBuffer(tbExtended, (BYTE*) pCurExtReg);
6384 }
6385 else
6386 {
6387 memset(pCurExtReg, 0, tbExtended.cbSize);
6388 }
6389 #endif
6390
6391 }
6392 EX_CATCH_HRESULT(hr);
6393 return hr;
6394}
6395
6396//
6397// This routine writes a thread context to the process being debugged, taking into account the fact that the context
6398// record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate
6399// space for the extended registers. However, the CONTEXT struct that we compile with does have this space.
6400//
6401HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const DT_CONTEXT * pCtx)
6402{
6403 INTERNAL_API_ENTRY(this);
6404 FAIL_IF_NEUTERED(this);
6405
6406 HRESULT hr = S_OK;
6407 DWORD sizeToWrite = sizeof(DT_CONTEXT);
6408
6409 BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet();
6410 BYTE * pCtxSource = (BYTE*) pCtx;
6411
6412
6413#if defined(DT_CONTEXT_EXTENDED_REGISTERS)
6414 // If our context has extended registers, then write the whole thing. Otherwise, just write the minimum part.
6415 if ((pCtx->ContextFlags & DT_CONTEXT_EXTENDED_REGISTERS) != DT_CONTEXT_EXTENDED_REGISTERS)
6416 {
6417 sizeToWrite = offsetof(DT_CONTEXT, ExtendedRegisters);
6418 }
6419#endif
6420
6421// 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that
6422// kernel to usermode transitions don't have to allocate a CONTEXT and do a seperate sub rsp
6423// to allocate stack spill space for the arguments. This means that writing to P1Home - P6Home
6424// will overwrite the arguments of some function higher on the stack, very bad. Conceptually you
6425// can think of these members as not being part of the context, ie they don't represent something
6426// which gets saved or restored on context switches. They are just space we shouldn't overwrite.
6427// See issue 630276 for more details.
6428#if defined DBG_TARGET_AMD64
6429 pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6
6430 pCtxSource += offsetof(CONTEXT, ContextFlags);
6431 sizeToWrite -= offsetof(CONTEXT, ContextFlags);
6432#endif
6433
6434 EX_TRY
6435 {
6436 // Write the context.
6437 TargetBuffer tb(pRemoteContext, sizeToWrite);
6438 SafeWriteBuffer(tb, (const BYTE*) pCtxSource);
6439 }
6440 EX_CATCH_HRESULT(hr);
6441
6442 return hr;
6443}
6444
6445
6446HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE context[])
6447{
6448 PUBLIC_REENTRANT_API_ENTRY(this);
6449 FAIL_IF_NEUTERED(this);
6450 LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x\n", threadID));
6451
6452 DT_CONTEXT * pContext;
6453
6454 if (contextSize != sizeof(DT_CONTEXT))
6455 {
6456 LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID));
6457 return E_INVALIDARG;
6458 }
6459
6460 pContext = reinterpret_cast<DT_CONTEXT *>(context);
6461
6462 VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true);
6463
6464 if (this->IsInteropDebugging())
6465 {
6466#ifdef FEATURE_INTEROP_DEBUGGING
6467 RSLockHolder lockHolder(GetProcessLock());
6468
6469 // Find the unmanaged thread
6470 CordbUnmanagedThread *ut = GetUnmanagedThread(threadID);
6471
6472 if (ut == NULL)
6473 {
6474 LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
6475
6476 return E_INVALIDARG;
6477 }
6478
6479 return ut->GetThreadContext((DT_CONTEXT*)context);
6480#else
6481 return E_NOTIMPL;
6482#endif
6483 }
6484 else
6485 {
6486 RSLockHolder ch(GetProcess()->GetStopGoLock());
6487 RSLockHolder lockHolder(GetProcessLock());
6488
6489 HRESULT hr = S_OK;
6490 EX_TRY
6491 {
6492 CordbThread* thread = this->TryLookupThreadByVolatileOSId(threadID);
6493 if (thread == NULL)
6494 {
6495 LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
6496
6497 hr = E_INVALIDARG;
6498 }
6499 else
6500 {
6501 DT_CONTEXT* managedContext;
6502 hr = thread->GetManagedContext(&managedContext);
6503 *pContext = *managedContext;
6504 }
6505 }
6506 EX_CATCH_HRESULT(hr)
6507 return hr;
6508 }
6509}
6510
6511// Public implementation of ICorDebugProcess::SetThreadContext.
6512// @dbgtodo interop-debugging: this should go away in V3. Use the data-target instead. This is
6513// interop-debugging aware (and cooperates with hijacks)
6514HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE context[])
6515{
6516 PUBLIC_REENTRANT_API_ENTRY(this);
6517
6518 HRESULT hr = S_OK;
6519
6520 // @todo - could we look at the context flags and return E_INVALIDARG if they're bad?
6521 FAIL_IF_NEUTERED(this);
6522 VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true);
6523
6524 if (contextSize != sizeof(DT_CONTEXT))
6525 {
6526 LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, context size is invalid.\n", threadID));
6527 return E_INVALIDARG;
6528 }
6529
6530 DT_CONTEXT* pContext = (DT_CONTEXT*)context;
6531
6532 if (this->IsInteropDebugging())
6533 {
6534#ifdef FEATURE_INTEROP_DEBUGGING
6535 RSLockHolder lockHolder(GetProcessLock());
6536
6537 CordbUnmanagedThread *ut = NULL;
6538
6539 // Find the unmanaged thread
6540 ut = GetUnmanagedThread(threadID);
6541
6542 if (ut == NULL)
6543 {
6544 LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, thread is invalid.\n", threadID));
6545 return E_INVALIDARG;
6546 }
6547
6548 hr = ut->SetThreadContext(pContext);
6549
6550 // Update the register set for the leaf-unmanaged chain so that it's consistent w/ the context.
6551 // We may not necessarily be synchronized, and so these frames may be stale. Even so, no harm done.
6552 if (SUCCEEDED(hr))
6553 {
6554 // @dbgtodo stackwalk: this should all disappear with V3 stackwalker and getting rid of SetThreadContext.
6555 EX_TRY
6556 {
6557 // Find the managed thread. Returns NULL if thread is not managed.
6558 // If we don't have a thread prveiously cached, then there's no state to update.
6559 CordbThread * pThread = TryLookupThreadByVolatileOSId(threadID);
6560
6561 if (pThread != NULL)
6562 {
6563 // In V2, we used to update the CONTEXT of the leaf chain if the chain is an unmanaged chain.
6564 // In Arrowhead, we just force a cleanup of the stackwalk cache. This is a more correct
6565 // thing to do anyway, since the CONTEXT being set could be anything.
6566 pThread->CleanupStack();
6567 }
6568 }
6569 EX_CATCH_HRESULT(hr);
6570 }
6571#else
6572 return E_NOTIMPL;
6573#endif
6574 }
6575 else
6576 {
6577 RSLockHolder ch(GetProcess()->GetStopGoLock());
6578 RSLockHolder lockHolder(GetProcessLock());
6579
6580 EX_TRY
6581 {
6582 CordbThread* thread = this->TryLookupThreadByVolatileOSId(threadID);
6583 if (thread == NULL)
6584 {
6585 LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
6586
6587 hr = E_INVALIDARG;
6588 }
6589
6590 hr = thread->SetManagedContext(pContext);
6591 }
6592 EX_CATCH
6593 {
6594 hr = E_FAIL;
6595 }
6596 EX_END_CATCH(SwallowAllExceptions)
6597
6598
6599 }
6600 return hr;
6601}
6602
6603
6604// @dbgtodo ICDProcess - When we DACize this function, we should use code:DacReplacePatches
6605HRESULT CordbProcess::ReadMemory(CORDB_ADDRESS address,
6606 DWORD size,
6607 BYTE buffer[],
6608 SIZE_T *read)
6609{
6610 PUBLIC_REENTRANT_API_ENTRY(this);
6611 FAIL_IF_NEUTERED(this);
6612
6613 // A read of 0 bytes is okay.
6614 if (size == 0)
6615 return S_OK;
6616
6617 VALIDATE_POINTER_TO_OBJECT_ARRAY(buffer, BYTE, size, true, true);
6618 VALIDATE_POINTER_TO_OBJECT(buffer, SIZE_T *);
6619
6620 if (address == NULL)
6621 return E_INVALIDARG;
6622
6623 // If no read parameter is supplied, we ignore it. This matches the semantics of kernel32!ReadProcessMemory.
6624 SIZE_T dummyRead;
6625 if (read == NULL)
6626 {
6627 read = &dummyRead;
6628 }
6629 *read = 0;
6630
6631 HRESULT hr = S_OK;
6632
6633 CORDBRequireProcessStateOK(this);
6634
6635 // Grab the memory we want to read
6636 // Note that this will return success on a partial read
6637 ULONG32 cbRead;
6638 hr = GetDataTarget()->ReadVirtual(address, buffer, size, &cbRead);
6639 if (FAILED(hr))
6640 {
6641 hr = CORDBG_E_READVIRTUAL_FAILURE;
6642 goto LExit;
6643 }
6644
6645 // Read at least one byte
6646 *read = (SIZE_T) cbRead;
6647
6648 // There seem to be strange cases where ReadProcessMemory will return a seemingly negative number into *read, which
6649 // is an unsigned value. So we check the sanity of *read by ensuring that its no bigger than the size we tried to
6650 // read.
6651 if ((*read > 0) && (*read <= size))
6652 {
6653 LOG((LF_CORDB, LL_INFO100000, "CP::RM: read %d bytes from 0x%08x, first byte is 0x%x\n",
6654 *read, (DWORD)address, buffer[0]));
6655
6656 if (m_initialized)
6657 {
6658 RSLockHolder ch(&this->m_processMutex);
6659
6660 // If m_pPatchTable is NULL, then it's been cleaned out b/c of a Continue for the left side. Get the table
6661 // again. Only do this, of course, if the managed state of the process is initialized.
6662 if (m_pPatchTable == NULL)
6663 {
6664 hr = RefreshPatchTable(address, *read, buffer);
6665 }
6666 else
6667 {
6668 // The previously fetched table is still good, so run through it & see if any patches are applicable
6669 hr = AdjustBuffer(address, *read, buffer, NULL, AB_READ);
6670 }
6671 }
6672 }
6673
6674LExit:
6675 if (FAILED(hr))
6676 {
6677 RSLockHolder ch(&this->m_processMutex);
6678 ClearPatchTable();
6679 }
6680 else if (*read < size)
6681 {
6682 // Unlike the DT api, our API is supposed to return an error on partial read
6683 hr = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
6684 }
6685 return hr;
6686}
6687
6688// Update patches & buffer to make the left-side's usage of patches transparent
6689// to our client. Behavior depends on AB_MODE:
6690// AB_READ:
6691// - use the RS patch table structure to replace patch opcodes in buffer.
6692// AB_WRITE:
6693// - update the RS patch table structure w/ new replace-opcode values
6694// if we've written over them. And put the int3 back in for write-memory.
6695//
6696// Note: If we're writing memory over top of a patch, then it must be JITted or stub code.
6697// Writing over JITed or Stub code can be dangerous since the CLR may not expect it
6698// (eg. JIT data structures about the code layout may be incorrect), but in certain
6699// narrow cases it may be safe (eg. replacing a constant). VS says they wouldn't expect
6700// this to work, but we'll keep the support in for legacy reasons.
6701//
6702// address, size - describe buffer in LS memory
6703// buffer - local copy of buffer that will be read/written from/to LS.
6704// bufferCopy - for writeprocessmemory, copy of original buffer (w/o injected patches)
6705// pbUpdatePatchTable - flag if patchtable got dirty and needs to be updated.
6706HRESULT CordbProcess::AdjustBuffer( CORDB_ADDRESS address,
6707 SIZE_T size,
6708 BYTE buffer[],
6709 BYTE **bufferCopy,
6710 AB_MODE mode,
6711 BOOL *pbUpdatePatchTable)
6712{
6713 INTERNAL_API_ENTRY(this);
6714
6715 _ASSERTE(m_initialized);
6716 _ASSERTE(this->ThreadHoldsProcessLock());
6717
6718 if ( address == NULL
6719 || size == NULL
6720 || buffer == NULL
6721 || (mode != AB_READ && mode != AB_WRITE) )
6722 return E_INVALIDARG;
6723
6724 if (pbUpdatePatchTable != NULL )
6725 *pbUpdatePatchTable = FALSE;
6726
6727 // If we don't have a patch table loaded, then return S_OK since there are no patches to adjust
6728 if (m_pPatchTable == NULL)
6729 return S_OK;
6730
6731 //is the requested memory completely out-of-range?
6732 if ((m_minPatchAddr > (address + (size - 1))) ||
6733 (m_maxPatchAddr < address))
6734 {
6735 return S_OK;
6736 }
6737
6738 // Without runtime offsets, we can't adjust - this should only ever happen on dumps, where there's
6739 // no W32ET to get the offsets, and so they stay zeroed
6740 if (!m_runtimeOffsetsInitialized)
6741 return S_OK;
6742
6743 LOG((LF_CORDB,LL_INFO10000, "CordbProcess::AdjustBuffer at addr 0x%p\n", address));
6744
6745 if (mode == AB_WRITE)
6746 {
6747 // We don't want to mess up the original copy of the buffer, so
6748 // for right now, just copy it wholesale.
6749 (*bufferCopy) = new (nothrow) BYTE[size];
6750 if (NULL == (*bufferCopy))
6751 return E_OUTOFMEMORY;
6752
6753 memmove((*bufferCopy), buffer, size);
6754 }
6755
6756 ULONG iNextFree = m_iFirstPatch;
6757 while( iNextFree != DPT_TERMINATING_INDEX )
6758 {
6759 BYTE *DebuggerControllerPatch = m_pPatchTable + m_runtimeOffsets.m_cbPatch*iNextFree;
6760 PRD_TYPE opcode = *(PRD_TYPE *)(DebuggerControllerPatch + m_runtimeOffsets.m_offOpcode);
6761 CORDB_ADDRESS patchAddress = PTR_TO_CORDB_ADDRESS(*(BYTE**)(DebuggerControllerPatch + m_runtimeOffsets.m_offAddr));
6762
6763 if (IsPatchInRequestedRange(address, size, patchAddress))
6764 {
6765 if (mode == AB_READ)
6766 {
6767 CORDbgSetInstructionEx(buffer, address, patchAddress, opcode, size);
6768 }
6769 else if (mode == AB_WRITE)
6770 {
6771 _ASSERTE( pbUpdatePatchTable != NULL );
6772 _ASSERTE( bufferCopy != NULL );
6773
6774 //There can be multiple patches at the same address: we don't want 2nd+ patches to get the
6775 // break opcode, so we read from the unmodified copy.
6776 m_rgUncommitedOpcode[iNextFree] =
6777 CORDbgGetInstructionEx(*bufferCopy, address, patchAddress, opcode, size);
6778
6779 //put the breakpoint into the memory itself
6780 CORDbgInsertBreakpointEx(buffer, address, patchAddress, opcode, size);
6781
6782 *pbUpdatePatchTable = TRUE;
6783 }
6784 else
6785 _ASSERTE( !"CordbProcess::AdjustBuffergiven non(Read|Write) mode!" );
6786 }
6787
6788 iNextFree = m_rgNextPatch[iNextFree];
6789 }
6790
6791 // If we created a copy of the buffer but didn't modify it, then free it now.
6792 if( ( mode == AB_WRITE ) && ( !*pbUpdatePatchTable ) )
6793 {
6794 delete [] *bufferCopy;
6795 *bufferCopy = NULL;
6796 }
6797
6798 return S_OK;
6799}
6800
6801
6802void CordbProcess::CommitBufferAdjustments( CORDB_ADDRESS start,
6803 CORDB_ADDRESS end )
6804{
6805 INTERNAL_API_ENTRY(this);
6806
6807 _ASSERTE(m_initialized);
6808 _ASSERTE(this->ThreadHoldsProcessLock());
6809 _ASSERTE(m_runtimeOffsetsInitialized);
6810
6811 ULONG iPatch = m_iFirstPatch;
6812 while( iPatch != DPT_TERMINATING_INDEX )
6813 {
6814 BYTE *DebuggerControllerPatch = m_pPatchTable +
6815 m_runtimeOffsets.m_cbPatch*iPatch;
6816
6817 BYTE *patchAddress = *(BYTE**)(DebuggerControllerPatch + m_runtimeOffsets.m_offAddr);
6818
6819 if (IsPatchInRequestedRange(start, (SIZE_T)(end - start), PTR_TO_CORDB_ADDRESS(patchAddress)) &&
6820 !PRDIsBreakInst(&(m_rgUncommitedOpcode[iPatch])))
6821 {
6822 //copy this back to the copy of the patch table
6823 *(PRD_TYPE *)(DebuggerControllerPatch + m_runtimeOffsets.m_offOpcode) =
6824 m_rgUncommitedOpcode[iPatch];
6825 }
6826
6827 iPatch = m_rgNextPatch[iPatch];
6828 }
6829}
6830
6831void CordbProcess::ClearBufferAdjustments( )
6832{
6833 INTERNAL_API_ENTRY(this);
6834 _ASSERTE(this->ThreadHoldsProcessLock());
6835
6836 ULONG iPatch = m_iFirstPatch;
6837 while( iPatch != DPT_TERMINATING_INDEX )
6838 {
6839 InitializePRDToBreakInst(&(m_rgUncommitedOpcode[iPatch]));
6840 iPatch = m_rgNextPatch[iPatch];
6841 }
6842}
6843
6844void CordbProcess::ClearPatchTable(void )
6845{
6846 INTERNAL_API_ENTRY(this);
6847 _ASSERTE(this->ThreadHoldsProcessLock());
6848
6849 if (m_pPatchTable != NULL )
6850 {
6851 delete [] m_pPatchTable;
6852 m_pPatchTable = NULL;
6853
6854 delete [] m_rgNextPatch;
6855 m_rgNextPatch = NULL;
6856
6857 delete [] m_rgUncommitedOpcode;
6858 m_rgUncommitedOpcode = NULL;
6859
6860 m_iFirstPatch = DPT_TERMINATING_INDEX;
6861 m_minPatchAddr = MAX_ADDRESS;
6862 m_maxPatchAddr = MIN_ADDRESS;
6863 m_rgData = NULL;
6864 m_cPatch = 0;
6865 }
6866}
6867
6868HRESULT CordbProcess::RefreshPatchTable(CORDB_ADDRESS address, SIZE_T size, BYTE buffer[])
6869{
6870 CONTRACTL
6871 {
6872 NOTHROW;
6873 }
6874 CONTRACTL_END;
6875
6876 INTERNAL_API_ENTRY(this);
6877 _ASSERTE(m_initialized);
6878 _ASSERTE(this->ThreadHoldsProcessLock());
6879
6880 HRESULT hr = S_OK;
6881 BYTE *rgb = NULL;
6882
6883 // All of m_runtimeOffsets will be zeroed out if there's been no call to code:CordbProcess::GetRuntimeOffsets.
6884 // Thus for things to work, we'd have to have a live target that went and got the real values.
6885 // For dumps, things are still all zeroed out because we don't have any events sent to the W32ET, don't
6886 // have a live process to investigate, etc.
6887 if (!m_runtimeOffsetsInitialized)
6888 return S_OK;
6889
6890 _ASSERTE( m_runtimeOffsets.m_cbOpcode == sizeof(PRD_TYPE) );
6891
6892 CORDBRequireProcessStateOK(this);
6893
6894 if (m_pPatchTable == NULL )
6895 {
6896 // First, check to be sure the patch table is valid on the Left Side. If its not, then we won't read it.
6897 BOOL fPatchTableValid = FALSE;
6898
6899 hr = SafeReadStruct(PTR_TO_CORDB_ADDRESS(m_runtimeOffsets.m_pPatchTableValid), &fPatchTableValid);
6900 if (FAILED(hr) || !fPatchTableValid)
6901 {
6902 LOG((LF_CORDB, LL_INFO10000, "Wont refresh patch table because its not valid now.\n"));
6903 return S_OK;
6904 }
6905
6906 SIZE_T offStart = 0;
6907 SIZE_T offEnd = 0;
6908 UINT cbTableSlice = 0;
6909
6910 // Grab the patch table info
6911 offStart = min(m_runtimeOffsets.m_offRgData, m_runtimeOffsets.m_offCData);
6912 offEnd = max(m_runtimeOffsets.m_offRgData, m_runtimeOffsets.m_offCData) + sizeof(SIZE_T);
6913 cbTableSlice = (UINT)(offEnd - offStart);
6914
6915 if (cbTableSlice == 0)
6916 {
6917 LOG((LF_CORDB, LL_INFO10000, "Wont refresh patch table because its not valid now.\n"));
6918 return S_OK;
6919 }
6920
6921 EX_TRY
6922 {
6923 rgb = new BYTE[cbTableSlice]; // throws
6924
6925 TargetBuffer tbSlice((BYTE*)m_runtimeOffsets.m_pPatches + offStart, cbTableSlice);
6926 this->SafeReadBuffer(tbSlice, rgb); // Throws;
6927
6928 // Note that rgData is a pointer in the left side address space
6929 m_rgData = *(BYTE**)(rgb + m_runtimeOffsets.m_offRgData - offStart);
6930 m_cPatch = *(ULONG*)(rgb + m_runtimeOffsets.m_offCData - offStart);
6931
6932 // Grab the patch table
6933 UINT cbPatchTable = (UINT)(m_cPatch * m_runtimeOffsets.m_cbPatch);
6934
6935 if (cbPatchTable == 0)
6936 {
6937 LOG((LF_CORDB, LL_INFO10000, "Wont refresh patch table because its not valid now.\n"));
6938 _ASSERTE(hr == S_OK);
6939 goto LExit; // can't return since we're in a Try/Catch
6940 }
6941
6942 // Throwing news
6943 m_pPatchTable = new BYTE[ cbPatchTable ];
6944 m_rgNextPatch = new ULONG[m_cPatch];
6945 m_rgUncommitedOpcode = new PRD_TYPE[m_cPatch];
6946
6947 TargetBuffer tb(m_rgData, cbPatchTable);
6948 this->SafeReadBuffer(tb, m_pPatchTable); // Throws
6949
6950 //As we go through the patch table we do a number of things:
6951 //
6952 // 1. collect min,max address seen for quick fail check
6953 //
6954 // 2. Link all valid entries into a linked list, the first entry of which is m_iFirstPatch
6955 //
6956 // 3. Initialize m_rgUncommitedOpcode, so that we can undo local patch table changes if WriteMemory can't write
6957 // atomically.
6958 //
6959 // 4. If the patch is in the memory we grabbed, unapply it.
6960
6961 ULONG iDebuggerControllerPatchPrev = DPT_TERMINATING_INDEX;
6962
6963 m_minPatchAddr = MAX_ADDRESS;
6964 m_maxPatchAddr = MIN_ADDRESS;
6965 m_iFirstPatch = DPT_TERMINATING_INDEX;
6966
6967 for (ULONG iPatch = 0; iPatch < m_cPatch;iPatch++)
6968 {
6969 // <REVISIT_TODO>@todo port: we're making assumptions about the size of opcodes,address pointers, etc</REVISIT_TODO>
6970 BYTE *DebuggerControllerPatch = m_pPatchTable + m_runtimeOffsets.m_cbPatch * iPatch;
6971 PRD_TYPE opcode = *(PRD_TYPE*)(DebuggerControllerPatch + m_runtimeOffsets.m_offOpcode);
6972 CORDB_ADDRESS patchAddress = PTR_TO_CORDB_ADDRESS(*(BYTE**)(DebuggerControllerPatch + m_runtimeOffsets.m_offAddr));
6973
6974 // A non-zero opcode indicates to us that this patch is valid.
6975 if (!PRDIsEmpty(opcode))
6976 {
6977 _ASSERTE( patchAddress != 0 );
6978
6979 // (1), above
6980 // Note that GetPatchEndAddr() returns the address immediately AFTER the patch,
6981 // so we have to subtract 1 from it below.
6982 if (m_minPatchAddr > patchAddress )
6983 m_minPatchAddr = patchAddress;
6984 if (m_maxPatchAddr < patchAddress )
6985 m_maxPatchAddr = GetPatchEndAddr(patchAddress) - 1;
6986
6987 // (2), above
6988 if ( m_iFirstPatch == DPT_TERMINATING_INDEX)
6989 {
6990 m_iFirstPatch = iPatch;
6991 _ASSERTE( iPatch != DPT_TERMINATING_INDEX);
6992 }
6993
6994 if (iDebuggerControllerPatchPrev != DPT_TERMINATING_INDEX)
6995 {
6996 m_rgNextPatch[iDebuggerControllerPatchPrev] = iPatch;
6997 }
6998
6999 iDebuggerControllerPatchPrev = iPatch;
7000
7001 // (3), above
7002 InitializePRDToBreakInst(&(m_rgUncommitedOpcode[iPatch]));
7003
7004 // (4), above
7005 if (IsPatchInRequestedRange(address, size, patchAddress))
7006 {
7007 _ASSERTE( buffer != NULL );
7008 _ASSERTE( size != NULL );
7009
7010
7011 //unapply the patch here.
7012 CORDbgSetInstructionEx(buffer, address, patchAddress, opcode, size);
7013 }
7014
7015 }
7016 }
7017
7018 if (iDebuggerControllerPatchPrev != DPT_TERMINATING_INDEX)
7019 {
7020 m_rgNextPatch[iDebuggerControllerPatchPrev] = DPT_TERMINATING_INDEX;
7021 }
7022 }
7023LExit:
7024 ;
7025 EX_CATCH_HRESULT(hr);
7026 }
7027
7028
7029 if (rgb != NULL )
7030 {
7031 delete [] rgb;
7032 }
7033
7034 if (FAILED( hr ) )
7035 {
7036 ClearPatchTable();
7037 }
7038
7039 return hr;
7040}
7041
7042//---------------------------------------------------------------------------------------
7043//
7044// Given an address, see if there is a patch in the patch table that matches it and return
7045// if its an unmanaged patch or not.
7046//
7047// Arguments:
7048// address - The address of an instruction to check in the target address space.
7049// pfPatchFound - Space to store the result, TRUE if the address belongs to a
7050// patch, FALSE if not. Only valid if this method returns a success code.
7051// pfPatchIsUnmanaged - Space to store the result, TRUE if the address is a patch
7052// and the patch is unmanaged, FALSE if not. Only valid if this method returns a
7053// success code.
7054//
7055// Return Value:
7056// Typical HRESULT symantics, nothing abnormal.
7057//
7058// Note: this method is pretty in-efficient. It refreshes the patch table, then scans it.
7059// Refreshing the patch table involves a scan, too, so this method could be folded
7060// with that.
7061//
7062//---------------------------------------------------------------------------------------
7063HRESULT CordbProcess::FindPatchByAddress(CORDB_ADDRESS address, bool *pfPatchFound, bool *pfPatchIsUnmanaged)
7064{
7065 INTERNAL_API_ENTRY(this);
7066 _ASSERTE(ThreadHoldsProcessLock());
7067 _ASSERTE((pfPatchFound != NULL) && (pfPatchIsUnmanaged != NULL));
7068 _ASSERTE(m_runtimeOffsetsInitialized);
7069 FAIL_IF_NEUTERED(this);
7070
7071 *pfPatchFound = false;
7072 *pfPatchIsUnmanaged = false;
7073
7074 // First things first. If the process isn't initialized, then there can be no patch table, so we know the breakpoint
7075 // doesn't belong to the Runtime.
7076 if (!m_initialized)
7077 {
7078 return S_OK;
7079 }
7080
7081 // This method is called from the main loop of the win32 event thread in response to a first chance breakpoint event
7082 // that we know is not a flare. The process has been runnning, and it may have invalidated the patch table, so we'll
7083 // flush it here before refreshing it to make sure we've got the right thing.
7084 //
7085 // Note: we really should have the Left Side mark the patch table dirty to help optimize this.
7086 ClearPatchTable();
7087
7088 // Refresh the patch table.
7089 HRESULT hr = RefreshPatchTable();
7090
7091 if (FAILED(hr))
7092 {
7093 LOG((LF_CORDB, LL_INFO1000, "CP::FPBA: failed to refresh the patch table\n"));
7094 return hr;
7095 }
7096
7097 // If there is no patch table yet, then we know there is no patch at the given address, so return S_OK with
7098 // *patchFound = false.
7099 if (m_pPatchTable == NULL)
7100 {
7101 LOG((LF_CORDB, LL_INFO1000, "CP::FPBA: no patch table\n"));
7102 return S_OK;
7103 }
7104
7105 // Scan the patch table for a matching patch.
7106 for (ULONG iNextPatch = m_iFirstPatch; iNextPatch != DPT_TERMINATING_INDEX; iNextPatch = m_rgNextPatch[iNextPatch])
7107 {
7108 BYTE *patch = m_pPatchTable + (m_runtimeOffsets.m_cbPatch * iNextPatch);
7109 BYTE *patchAddress = *(BYTE**)(patch + m_runtimeOffsets.m_offAddr);
7110 DWORD traceType = *(DWORD*)(patch + m_runtimeOffsets.m_offTraceType);
7111
7112 if (address == PTR_TO_CORDB_ADDRESS(patchAddress))
7113 {
7114 *pfPatchFound = true;
7115
7116 if (traceType == m_runtimeOffsets.m_traceTypeUnmanaged)
7117 {
7118 *pfPatchIsUnmanaged = true;
7119
7120#if defined(_DEBUG)
7121 HRESULT hrDac = S_OK;
7122 EX_TRY
7123 {
7124 // We should be able to double check w/ DAC that this really is outside of the runtime.
7125 IDacDbiInterface::AddressType addrType = GetDAC()->GetAddressType(address);
7126 CONSISTENCY_CHECK_MSGF(addrType == IDacDbiInterface::kAddressUnrecognized, ("Bad address type = %d", addrType));
7127 }
7128 EX_CATCH_HRESULT(hrDac);
7129 CONSISTENCY_CHECK_MSGF(SUCCEEDED(hrDac), ("DAC::GetAddressType failed, hr=0x%08x", hrDac));
7130#endif
7131 }
7132
7133 break;
7134 }
7135 }
7136
7137 // If we didn't find a patch, its actually still possible that this breakpoint exception belongs to us. There are
7138 // races with very large numbers of threads entering the Runtime through the same managed function. We will have
7139 // multiple threads adding and removing ref counts to an int 3 in the code stream. Sometimes, this count will go to
7140 // zero and the int 3 will be removed, then it will come back up and the int 3 will be replaced. The in-process
7141 // logic takes pains to ensure that such cases are handled properly, therefore we need to perform the same check
7142 // here to make the correct decision. Basically, the check is to see if there is indeed an int 3 at the exception
7143 // address. If there is _not_ an int 3 there, then we've hit this race. We will lie and say a managed patch was
7144 // found to cover this case. This is tracking the logic in DebuggerController::ScanForTriggers, where we call
7145 // IsPatched.
7146 if (*pfPatchFound == false)
7147 {
7148 // Read one instruction from the faulting address...
7149#if defined(DBG_TARGET_ARM) || defined(DBG_TARGET_ARM64)
7150 PRD_TYPE TrapCheck = 0;
7151#else
7152 BYTE TrapCheck = 0;
7153#endif
7154
7155 HRESULT hr2 = SafeReadStruct(address, &TrapCheck);
7156
7157 if (SUCCEEDED(hr2) && (TrapCheck != CORDbg_BREAK_INSTRUCTION))
7158 {
7159 LOG((LF_CORDB, LL_INFO1000, "CP::FPBA: patchFound=true based on odd missing int 3 case.\n"));
7160
7161 *pfPatchFound = true;
7162 }
7163 }
7164
7165 LOG((LF_CORDB, LL_INFO1000, "CP::FPBA: patchFound=%d, patchIsUnmanaged=%d\n", *pfPatchFound, *pfPatchIsUnmanaged));
7166
7167 return S_OK;
7168}
7169
7170HRESULT CordbProcess::WriteMemory(CORDB_ADDRESS address, DWORD size,
7171 BYTE buffer[], SIZE_T *written)
7172{
7173 PUBLIC_REENTRANT_API_ENTRY(this);
7174 FAIL_IF_NEUTERED(this);
7175 CORDBRequireProcessStateOK(this);
7176 _ASSERTE(m_runtimeOffsetsInitialized);
7177
7178
7179 if (size == 0 || address == NULL)
7180 return E_INVALIDARG;
7181
7182 VALIDATE_POINTER_TO_OBJECT_ARRAY(buffer, BYTE, size, true, true);
7183 VALIDATE_POINTER_TO_OBJECT(written, SIZE_T *);
7184
7185
7186#if defined(_DEBUG) && defined(FEATURE_INTEROP_DEBUGGING)
7187 // Shouldn't be using this to write int3. Use UM BP API instead.
7188 // This is technically legal (what if the '0xcc' is data or something), so we can't fail in retail.
7189 // But we can add this debug-only check to help VS migrate to the new API.
7190 static ConfigDWORD configCheckInt3;
7191 DWORD fCheckInt3 = configCheckInt3.val(CLRConfig::INTERNAL_DbgCheckInt3);
7192 if (fCheckInt3)
7193 {
7194#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
7195 if (size == 1 && buffer[0] == 0xCC)
7196 {
7197 CONSISTENCY_CHECK_MSGF(false,
7198 ("You're using ICorDebugProcess::WriteMemory() to write an 'int3' (1 byte 0xCC) at address 0x%p.\n"
7199 "If you're trying to set a breakpoint, you should be using ICorDebugProcess::SetUnmanagedBreakpoint() instead.\n"
7200 "(This assert is only enabled under the COM+ knob DbgCheckInt3.)\n",
7201 CORDB_ADDRESS_TO_PTR(address)));
7202 }
7203#endif // DBG_TARGET_X86 || DBG_TARGET_AMD64
7204
7205 // check if we're replaced an opcode.
7206 if (size == 1)
7207 {
7208 RSLockHolder ch(&this->m_processMutex);
7209
7210 NativePatch * p = GetNativePatch(CORDB_ADDRESS_TO_PTR(address));
7211 if (p != NULL)
7212 {
7213 CONSISTENCY_CHECK_MSGF(false,
7214 ("You're using ICorDebugProcess::WriteMemory() to write an 'opcode (0x%x)' at address 0x%p.\n"
7215 "There's already a native patch at that address from ICorDebugProcess::SetUnmanagedBreakpoint().\n"
7216 "If you're trying to remove the breakpoint, use ICDProcess::ClearUnmanagedBreakpoint() instead.\n"
7217 "(This assert is only enabled under the COM+ knob DbgCheckInt3.)\n",
7218 (DWORD) (buffer[0]), CORDB_ADDRESS_TO_PTR(address)));
7219 }
7220 }
7221 }
7222#endif // _DEBUG && FEATURE_INTEROP_DEBUGGING
7223
7224
7225 *written = 0;
7226
7227 HRESULT hr = S_OK;
7228 HRESULT hrSaved = hr; // this will hold the 'real' hresult in case of a
7229 // partially completed operation
7230 HRESULT hrPartialCopy = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
7231
7232 BOOL bUpdateOriginalPatchTable = FALSE;
7233 BYTE *bufferCopy = NULL;
7234
7235 // Only update the patch table if the managed state of the process
7236 // is initialized.
7237 if (m_initialized)
7238 {
7239 RSLockHolder ch(&this->m_processMutex);
7240
7241 if (m_pPatchTable == NULL )
7242 {
7243 if (!SUCCEEDED( hr = RefreshPatchTable() ) )
7244 {
7245 goto LExit;
7246 }
7247 }
7248
7249 if ( !SUCCEEDED( hr = AdjustBuffer( address,
7250 size,
7251 buffer,
7252 &bufferCopy,
7253 AB_WRITE,
7254 &bUpdateOriginalPatchTable)))
7255 {
7256 goto LExit;
7257 }
7258 }
7259
7260 //conveniently enough, SafeWriteBuffer will throw if it can't complete the entire operation
7261 EX_TRY
7262 {
7263 TargetBuffer tb(address, size);
7264 SafeWriteBuffer(tb, buffer); // throws
7265 *written = tb.cbSize; // DT's Write does everything or fails.
7266 }
7267 EX_CATCH_HRESULT(hr);
7268
7269 if (FAILED(hr))
7270 {
7271 if(hr != hrPartialCopy)
7272 goto LExit;
7273 else
7274 hrSaved = hr;
7275 }
7276
7277
7278 LOG((LF_CORDB, LL_INFO100000, "CP::WM: wrote %d bytes at 0x%08x, first byte is 0x%x\n",
7279 *written, (DWORD)address, buffer[0]));
7280
7281 if (bUpdateOriginalPatchTable == TRUE )
7282 {
7283 {
7284 RSLockHolder ch(&this->m_processMutex);
7285
7286 //don't tweak patch table for stuff that isn't written to LeftSide
7287 CommitBufferAdjustments(address, address + *written);
7288 }
7289
7290 // The only way this should be able to fail is if
7291 //someone else fiddles with the memory protections on the
7292 //left side while it's frozen
7293 EX_TRY
7294 {
7295 TargetBuffer tb(m_rgData, (ULONG) (m_cPatch*m_runtimeOffsets.m_cbPatch));
7296 SafeWriteBuffer(tb, m_pPatchTable);
7297 }
7298 EX_CATCH_HRESULT(hr);
7299 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
7300 }
7301
7302 // Since we may have
7303 // overwritten anything (objects, code, etc), we should mark
7304 // everything as needing to be re-cached.
7305 m_continueCounter++;
7306
7307 LExit:
7308 if (m_initialized)
7309 {
7310 RSLockHolder ch(&this->m_processMutex);
7311 ClearBufferAdjustments( );
7312 }
7313
7314 //we messed up our local copy, so get a clean copy the next time
7315 //we need it
7316 if (bUpdateOriginalPatchTable==TRUE)
7317 {
7318 if (bufferCopy != NULL)
7319 {
7320 memmove(buffer, bufferCopy, size);
7321 delete bufferCopy;
7322 }
7323 }
7324
7325 if (FAILED( hr ))
7326 {
7327 //we messed up our local copy, so get a clean copy the next time
7328 //we need it
7329 if (bUpdateOriginalPatchTable==TRUE)
7330 {
7331 RSLockHolder ch(&this->m_processMutex);
7332 ClearPatchTable();
7333 }
7334 }
7335 else if( FAILED(hrSaved) )
7336 {
7337 hr = hrSaved;
7338 }
7339
7340 return hr;
7341}
7342
7343HRESULT CordbProcess::ClearCurrentException(DWORD threadID)
7344{
7345#ifndef FEATURE_INTEROP_DEBUGGING
7346 return E_INVALIDARG;
7347#else
7348 PUBLIC_API_ENTRY(this);
7349
7350 RSLockHolder lockHolder(GetProcessLock());
7351
7352 // There's something wrong if you're calling this an there are no queued unmanaged events.
7353 if ((m_unmanagedEventQueue == NULL) && (m_outOfBandEventQueue == NULL))
7354 return E_INVALIDARG;
7355
7356 // Grab the unmanaged thread object.
7357 CordbUnmanagedThread *pUThread = GetUnmanagedThread(threadID);
7358
7359 if (pUThread == NULL)
7360 return E_INVALIDARG;
7361
7362 LOG((LF_CORDB, LL_INFO1000, "CP::CCE: tid=0x%x\n", threadID));
7363
7364 // We clear both the IB and OOB event.
7365 if (pUThread->HasIBEvent() && !pUThread->IBEvent()->IsEventUserContinued())
7366 {
7367 pUThread->IBEvent()->SetState(CUES_ExceptionCleared);
7368 }
7369
7370 if (pUThread->HasOOBEvent())
7371 {
7372 // must decide exception status _before_ we continue the event.
7373 _ASSERTE(!pUThread->OOBEvent()->IsEventContinuedUnhijacked());
7374 pUThread->OOBEvent()->SetState(CUES_ExceptionCleared);
7375 }
7376
7377 // If the thread is hijacked, then set the thread's debugger word to 0 to indicate to it that the
7378 // exception has been cleared.
7379 if (pUThread->IsGenericHijacked())
7380 {
7381 HRESULT hr = pUThread->SetEEDebuggerWord(0);
7382 _ASSERTE(SUCCEEDED(hr));
7383 }
7384
7385 return S_OK;
7386#endif // FEATURE_INTEROP_DEBUGGING
7387}
7388
7389#ifdef FEATURE_INTEROP_DEBUGGING
7390CordbUnmanagedThread *CordbProcess::HandleUnmanagedCreateThread(DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase)
7391{
7392 INTERNAL_API_ENTRY(this);
7393 CordbUnmanagedThread *ut = new (nothrow) CordbUnmanagedThread(this, dwThreadId, hThread, lpThreadLocalBase);
7394
7395 if (ut != NULL)
7396 {
7397 HRESULT hr = m_unmanagedThreads.AddBase(ut); // InternalAddRef, release on EXIT_THREAD events.
7398
7399 if (!SUCCEEDED(hr))
7400 {
7401 delete ut;
7402 ut = NULL;
7403
7404 LOG((LF_CORDB, LL_INFO10000, "Failed adding unmanaged thread to process!\n"));
7405 CORDBSetUnrecoverableError(this, hr, 0);
7406 }
7407 }
7408 else
7409 {
7410 LOG((LF_CORDB, LL_INFO10000, "New CordbThread failed!\n"));
7411 CORDBSetUnrecoverableError(this, E_OUTOFMEMORY, 0);
7412 }
7413
7414 return ut;
7415}
7416#endif // FEATURE_INTEROP_DEBUGGING
7417
7418
7419//-----------------------------------------------------------------------------
7420// Initializes the DAC
7421// Arguments: none--initializes the DAC for this CordbProcess instance
7422// Note: Throws on error
7423//-----------------------------------------------------------------------------
7424void CordbProcess::InitDac()
7425{
7426 // Go-Go DAC power!!
7427 HRESULT hr = S_OK;
7428 EX_TRY
7429 {
7430 InitializeDac();
7431 }
7432 EX_CATCH_HRESULT(hr);
7433
7434 // We Need DAC to debug for both Managed & Interop.
7435 if (FAILED(hr))
7436 {
7437 // We assert here b/c we're trying to be friendly. Most likely, the cause is either:
7438 // - a bad installation
7439 // - a CLR dev built mscorwks but didn't build DAC.
7440 SIMPLIFYING_ASSUMPTION_MSGF(false, ("Failed to load DAC while for debugging. hr=0x%08x", hr));
7441 ThrowHR(hr);
7442 }
7443} //CordbProcess::InitDac
7444
7445// Update the entire RS copy of the debugger control block by reading the LS copy. The RS copy is treated as
7446// a throw-away temporary buffer, rather than a true cache. That is, we make no assumptions about the
7447// validity of the information over time. Thus, before using any of the values, we need to update it. We
7448// update everything for simplicity; any perf hit we take by doing this instead of updating the individual
7449// fields we want at any given point isn't significant, particularly if we are updating multiple fields.
7450
7451// Arguments:
7452// none, but reads process memory from the LS debugger control block
7453// Return Value: none (copies from LS DCB to RS buffer GetDCB())
7454// Note: throws if SafeReadBuffer fails
7455void CordbProcess::UpdateRightSideDCB()
7456{
7457 IfFailThrow(m_pEventChannel->UpdateRightSideDCB());
7458} // CordbProcess::UpdateRightSideDCB
7459
7460// Update a single field with a value stored in the RS copy of the DCB. We can't update the entire LS DCB
7461// because in some cases, the LS and RS are simultaneously initializing the DCB. If we initialize a field on
7462// the RS and write back the whole thing, we may overwrite something the LS has initialized in the interim.
7463
7464// Arguments:
7465// input: rsFieldAddr - the address of the field in the RS copy of the DCB that we want to write back to
7466// the LS DCB. We use this to compute the offset of the field from the beginning of the
7467// DCB and then add this offset to the starting address of the LS DCB to get the LS
7468// address of the field we are updating
7469// size - the size of the field we're updating.
7470// Return value: none
7471// Note: throws if SafeWriteBuffer fails
7472void CordbProcess::UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size)
7473{
7474 IfFailThrow(m_pEventChannel->UpdateLeftSideDCBField(rsFieldAddr, size));
7475} // CordbProcess::UpdateRightSideDCB
7476
7477
7478//-----------------------------------------------------------------------------
7479// Gets the remote address of the event block for the Target and verifies that it's valid.
7480// We use this address when we need to read from or write to the debugger control block.
7481// Also allocates the RS buffer used for temporary storage for information from the DCB and
7482// copies the LS DCB into the RS buffer.
7483// Arguments:
7484// output: pfBlockExists - true iff the LS DCB has been successfully allocated. Note that
7485// we need this information even if the function throws, so we can't simply send it back
7486// as a return value.
7487// Return value:
7488// None, but allocates GetDCB() on success. If the LS DCB has not
7489// been successfully initialized or if this throws, GetDCB() will be NULL.
7490//
7491// Notes:
7492// Throws on error
7493//
7494//-----------------------------------------------------------------------------
7495void CordbProcess::GetEventBlock(BOOL * pfBlockExists)
7496{
7497 if (GetDCB() == NULL) // we only need to do this once
7498 {
7499 _ASSERTE(m_pShim != NULL);
7500 _ASSERTE(ThreadHoldsProcessLock());
7501
7502 // This will Initialize the DAC/DBI interface.
7503 BOOL fDacReady = TryInitializeDac();
7504
7505 if (fDacReady)
7506 {
7507 // Ensure that we have a DAC interface.
7508 _ASSERTE(m_pDacPrimitives != NULL);
7509
7510 // This is not technically necessary for Mac debugging. The event channel doesn't rely on
7511 // knowing the target address of the DCB on the LS.
7512 CORDB_ADDRESS pLeftSideDCB = NULL;
7513 pLeftSideDCB = (GetDAC()->GetDebuggerControlBlockAddress());
7514 if (pLeftSideDCB == NULL)
7515 {
7516 *pfBlockExists = false;
7517 ThrowHR(CORDBG_E_DEBUGGING_NOT_POSSIBLE);
7518 }
7519
7520 IfFailThrow(NewEventChannelForThisPlatform(pLeftSideDCB,
7521 m_pMutableDataTarget,
7522 GetProcessDescriptor(),
7523 m_pShim->GetMachineInfo(),
7524 &m_pEventChannel));
7525 _ASSERTE(m_pEventChannel != NULL);
7526
7527 // copy information from left side DCB
7528 UpdateRightSideDCB();
7529
7530 // Verify that the control block is valid.
7531 // This will throw on error.
7532 VerifyControlBlock();
7533
7534 *pfBlockExists = true;
7535 }
7536 else
7537 {
7538 // we can't initialize the DAC, so we can't get the block
7539 *pfBlockExists = false;
7540 }
7541 }
7542 else // we got the block before
7543 {
7544 *pfBlockExists = true;
7545 }
7546
7547} // CordbProcess::GetEventBlock()
7548
7549
7550//
7551// Verify that the version info in the control block matches what we expect. The minimum supported protocol from the
7552// Left Side must be greater or equal to the minimum required protocol of the Right Side. Note: its the Left Side's job
7553// to conform to whatever protocol the Right Side requires, so long as minimum is supported.
7554//
7555void CordbProcess::VerifyControlBlock()
7556{
7557 INTERNAL_API_ENTRY(this);
7558 _ASSERTE(m_pShim != NULL);
7559
7560 if (GetDCB()->m_DCBSize == 0)
7561 {
7562 // the LS is still initializing the DCB
7563 ThrowHR(CORDBG_E_DEBUGGING_NOT_POSSIBLE);
7564 }
7565
7566 // Fill in the protocol numbers for the Right Side and update the LS DCB.
7567 GetDCB()->m_rightSideProtocolCurrent = CorDB_RightSideProtocolCurrent;
7568 UpdateLeftSideDCBField(&(GetDCB()->m_rightSideProtocolCurrent), sizeof(GetDCB()->m_rightSideProtocolCurrent));
7569
7570 GetDCB()->m_rightSideProtocolMinSupported = CorDB_RightSideProtocolMinSupported;
7571 UpdateLeftSideDCBField(&(GetDCB()->m_rightSideProtocolMinSupported),
7572 sizeof(GetDCB()->m_rightSideProtocolMinSupported));
7573
7574 // For Telesto, Dbi and Wks have a more flexible versioning allowed, as described by the Debugger
7575 // Version Protocol String in DEBUGGER_PROTOCOL_STRING in DbgIpcEvents.h. This allows different build
7576 // numbers, but the other protocol numbers should still match.
7577
7578 // These assertions verify that the debug manager is behaving correctly.
7579 // An assertion failure here means that the runtime version of the debuggee is different from the runtime version of
7580 // the debugger is capable of debugging.
7581
7582 // The Debug Manager should properly match LS & RS, and thus guarantee that this assert should never fire.
7583 // But just in case the installation is corrupted, we'll check it.
7584 if (GetDCB()->m_DCBSize != sizeof(DebuggerIPCControlBlock))
7585 {
7586 CONSISTENCY_CHECK_MSGF(false, ("DCB in LS is %d bytes, in RS is %d bytes. Version mismatch!!\n",
7587 GetDCB()->m_DCBSize, sizeof(DebuggerIPCControlBlock)));
7588 ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL);
7589 }
7590
7591 // The Left Side has to support at least our minimum required protocol.
7592 if (GetDCB()->m_leftSideProtocolCurrent < GetDCB()->m_rightSideProtocolMinSupported)
7593 {
7594 _ASSERTE(GetDCB()->m_leftSideProtocolCurrent >= GetDCB()->m_rightSideProtocolMinSupported);
7595 ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL);
7596 }
7597
7598 // The Left Side has to be able to emulate at least our minimum required protocol.
7599 if (GetDCB()->m_leftSideProtocolMinSupported > GetDCB()->m_rightSideProtocolCurrent)
7600 {
7601 _ASSERTE(GetDCB()->m_leftSideProtocolMinSupported <= GetDCB()->m_rightSideProtocolCurrent);
7602 ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL);
7603 }
7604
7605#ifdef _DEBUG
7606 char buf[MAX_LONGPATH];
7607 DWORD len = GetEnvironmentVariableA("CORDBG_NotCompatibleTest", buf, sizeof(buf));
7608 _ASSERTE(len < sizeof(buf));
7609
7610 if (len > 0)
7611 ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL);
7612#endif
7613
7614 if (GetDCB()->m_bHostingInFiber)
7615 {
7616 ThrowHR(CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS);
7617 }
7618
7619 _ASSERTE(!GetDCB()->m_rightSideShouldCreateHelperThread);
7620} // CordbProcess::VerifyControlBlock
7621
7622//-----------------------------------------------------------------------------
7623// This is the CordbProcess objects chance to inspect the DCB and intialize stuff
7624//
7625// Return Value:
7626// Typical HRESULT return values, nothing abnormal.
7627// If succeeded, then the block exists and is valid.
7628//
7629//-----------------------------------------------------------------------------
7630HRESULT CordbProcess::GetRuntimeOffsets()
7631{
7632 INTERNAL_API_ENTRY(this);
7633
7634 _ASSERTE(m_pShim != NULL);
7635 UpdateRightSideDCB();
7636
7637 // Can't get a handle to the helper thread if the target is remote.
7638
7639 // If we got this far w/o failing, then we should be able to get the helper thread handle.
7640 // RS will handle not having the helper-thread handle, so we just make a best effort here.
7641 DWORD dwHelperTid = GetDCB()->m_realHelperThreadId;
7642 _ASSERTE(dwHelperTid != 0);
7643
7644
7645 {
7646#if !defined FEATURE_CORESYSTEM
7647 // kernel32!OpenThread does not exist on all platforms (missing on Win98).
7648 // So we need to delay load it.
7649 typedef HANDLE (WINAPI *FPOPENTHREAD)(DWORD dwDesiredAccess,
7650 BOOL bInheritHandle,
7651 DWORD dwThreadId);
7652
7653
7654
7655 HMODULE mod = WszGetModuleHandle(W("kernel32.dll"));
7656
7657 _ASSERTE(mod != NULL); // can't fail since Kernel32.dll is already loaded.
7658
7659 const FPOPENTHREAD pfnOpenThread = (FPOPENTHREAD)GetProcAddress(mod, "OpenThread");
7660
7661 if (pfnOpenThread != NULL)
7662 {
7663 m_hHelperThread = pfnOpenThread(SYNCHRONIZE, FALSE, dwHelperTid);
7664 CONSISTENCY_CHECK_MSGF(m_hHelperThread != NULL, ("Failed to get helper-thread handle. tid=0x%x\n", dwHelperTid));
7665 }
7666#elif FEATURE_PAL
7667 m_hHelperThread = NULL; //RS is supposed to be able to live without a helper thread handle.
7668#else
7669 m_hHelperThread = OpenThread(SYNCHRONIZE, FALSE, dwHelperTid);
7670 CONSISTENCY_CHECK_MSGF(m_hHelperThread != NULL, ("Failed to get helper-thread handle. tid=0x%x\n", dwHelperTid));
7671#endif
7672 }
7673
7674 // get the remote address of the runtime offsets structure and read the structure itself
7675 HRESULT hrRead = SafeReadStruct(PTR_TO_CORDB_ADDRESS(GetDCB()->m_pRuntimeOffsets), &m_runtimeOffsets);
7676
7677 if (FAILED(hrRead))
7678 {
7679 return hrRead;
7680 }
7681
7682 LOG((LF_CORDB, LL_INFO10000, "CP::GRO: got runtime offsets: \n"));
7683
7684#ifdef FEATURE_INTEROP_DEBUGGING
7685 LOG((LF_CORDB, LL_INFO10000, " m_genericHijackFuncAddr= 0x%p\n",
7686 m_runtimeOffsets.m_genericHijackFuncAddr));
7687 LOG((LF_CORDB, LL_INFO10000, " m_signalHijackStartedBPAddr= 0x%p\n",
7688 m_runtimeOffsets.m_signalHijackStartedBPAddr));
7689 LOG((LF_CORDB, LL_INFO10000, " m_excepNotForRuntimeBPAddr= 0x%p\n",
7690 m_runtimeOffsets.m_excepNotForRuntimeBPAddr));
7691 LOG((LF_CORDB, LL_INFO10000, " m_notifyRSOfSyncCompleteBPAddr= 0x%p\n",
7692 m_runtimeOffsets.m_notifyRSOfSyncCompleteBPAddr));
7693 LOG((LF_CORDB, LL_INFO10000, " m_raiseException= 0x%p\n",
7694 m_runtimeOffsets.m_raiseExceptionAddr));
7695 LOG((LF_CORDB, LL_INFO10000, " m_debuggerWordTLSIndex= 0x%08x\n",
7696 m_runtimeOffsets.m_debuggerWordTLSIndex));
7697#endif // FEATURE_INTEROP_DEBUGGING
7698
7699 LOG((LF_CORDB, LL_INFO10000, " m_TLSIndex= 0x%08x\n",
7700 m_runtimeOffsets.m_TLSIndex));
7701 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateOffset= 0x%08x\n",
7702 m_runtimeOffsets.m_EEThreadStateOffset));
7703 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateNCOffset= 0x%08x\n",
7704 m_runtimeOffsets.m_EEThreadStateNCOffset));
7705 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadPGCDisabledOffset= 0x%08x\n",
7706 m_runtimeOffsets.m_EEThreadPGCDisabledOffset));
7707 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadPGCDisabledValue= 0x%08x\n",
7708 m_runtimeOffsets.m_EEThreadPGCDisabledValue));
7709 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadFrameOffset= 0x%08x\n",
7710 m_runtimeOffsets.m_EEThreadFrameOffset));
7711 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadMaxNeededSize= 0x%08x\n",
7712 m_runtimeOffsets.m_EEThreadMaxNeededSize));
7713 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadSteppingStateMask= 0x%08x\n",
7714 m_runtimeOffsets.m_EEThreadSteppingStateMask));
7715 LOG((LF_CORDB, LL_INFO10000, " m_EEMaxFrameValue= 0x%08x\n",
7716 m_runtimeOffsets.m_EEMaxFrameValue));
7717 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadDebuggerFilterContextOffset= 0x%08x\n",
7718 m_runtimeOffsets.m_EEThreadDebuggerFilterContextOffset));
7719 LOG((LF_CORDB, LL_INFO10000, " m_EEThreadCantStopOffset= 0x%08x\n",
7720 m_runtimeOffsets.m_EEThreadCantStopOffset));
7721 LOG((LF_CORDB, LL_INFO10000, " m_EEFrameNextOffset= 0x%08x\n",
7722 m_runtimeOffsets.m_EEFrameNextOffset));
7723 LOG((LF_CORDB, LL_INFO10000, " m_EEIsManagedExceptionStateMask= 0x%08x\n",
7724 m_runtimeOffsets.m_EEIsManagedExceptionStateMask));
7725 LOG((LF_CORDB, LL_INFO10000, " m_pPatches= 0x%08x\n",
7726 m_runtimeOffsets.m_pPatches));
7727 LOG((LF_CORDB, LL_INFO10000, " m_offRgData= 0x%08x\n",
7728 m_runtimeOffsets.m_offRgData));
7729 LOG((LF_CORDB, LL_INFO10000, " m_offCData= 0x%08x\n",
7730 m_runtimeOffsets.m_offCData));
7731 LOG((LF_CORDB, LL_INFO10000, " m_cbPatch= 0x%08x\n",
7732 m_runtimeOffsets.m_cbPatch));
7733 LOG((LF_CORDB, LL_INFO10000, " m_offAddr= 0x%08x\n",
7734 m_runtimeOffsets.m_offAddr));
7735 LOG((LF_CORDB, LL_INFO10000, " m_offOpcode= 0x%08x\n",
7736 m_runtimeOffsets.m_offOpcode));
7737 LOG((LF_CORDB, LL_INFO10000, " m_cbOpcode= 0x%08x\n",
7738 m_runtimeOffsets.m_cbOpcode));
7739 LOG((LF_CORDB, LL_INFO10000, " m_offTraceType= 0x%08x\n",
7740 m_runtimeOffsets.m_offTraceType));
7741 LOG((LF_CORDB, LL_INFO10000, " m_traceTypeUnmanaged= 0x%08x\n",
7742 m_runtimeOffsets.m_traceTypeUnmanaged));
7743
7744#ifdef FEATURE_INTEROP_DEBUGGING
7745 // Flares are only used for interop debugging.
7746
7747 // Do check that the flares are all at unique offsets.
7748 // Since this is determined at link-time, we need a run-time check (an
7749 // assert isn't good enough, since this would only happen in a super
7750 // optimized / bbt run).
7751 {
7752 const void * flares[] = {
7753 m_runtimeOffsets.m_signalHijackStartedBPAddr,
7754 m_runtimeOffsets.m_excepForRuntimeHandoffStartBPAddr,
7755 m_runtimeOffsets.m_excepForRuntimeHandoffCompleteBPAddr,
7756 m_runtimeOffsets.m_signalHijackCompleteBPAddr,
7757 m_runtimeOffsets.m_excepNotForRuntimeBPAddr,
7758 m_runtimeOffsets.m_notifyRSOfSyncCompleteBPAddr,
7759 };
7760
7761 const int NumFlares = NumItems(flares);
7762
7763 // Ensure that all of the flares are unique.
7764 for(int i = 0; i < NumFlares; i++)
7765 {
7766 for(int j = i+1; j < NumFlares; j++)
7767 {
7768 if (flares[i] == flares[j])
7769 {
7770 // If we ever fail here, that means the LS build is busted.
7771
7772 // This assert is useful if we drop a checked RS onto a retail
7773 // LS (that's legal).
7774 _ASSERTE(!"LS has matching Flares.");
7775 LOG((LF_CORDB, LL_ALWAYS, "Failing because of matching flares.\n"));
7776 return CORDBG_E_INCOMPATIBLE_PROTOCOL;
7777 }
7778 }
7779 }
7780 }
7781
7782#endif // FEATURE_INTEROP_DEBUGGING
7783 m_runtimeOffsetsInitialized = true;
7784 return S_OK;
7785}
7786
7787#ifdef FEATURE_INTEROP_DEBUGGING
7788
7789//-----------------------------------------------------------------------------
7790// Resume hijacked threads.
7791//-----------------------------------------------------------------------------
7792void CordbProcess::ResumeHijackedThreads()
7793{
7794 INTERNAL_API_ENTRY(this);
7795 _ASSERTE(m_pShim != NULL);
7796 _ASSERTE(ThreadHoldsProcessLock());
7797
7798 LOG((LF_CORDB, LL_INFO10000, "CP::RHT: entered\n"));
7799 if (this->m_state & (CordbProcess::PS_SOME_THREADS_SUSPENDED | CordbProcess::PS_HIJACKS_IN_PLACE))
7800 {
7801 // On XP, This will also resume the threads suspended for Sync.
7802 this->ResumeUnmanagedThreads();
7803 }
7804
7805 // Hijacks send their ownership flares and then wait on this event. By setting this
7806 // we let the hijacks run free.
7807 if (this->m_leftSideUnmanagedWaitEvent != NULL)
7808 {
7809 SetEvent(this->m_leftSideUnmanagedWaitEvent);
7810 }
7811 else
7812 {
7813 // Only reason we expect to not have this event is if the CLR hasn't been loaded yet.
7814 // In that case, we won't hijack, so nobody's listening for this event either.
7815 _ASSERTE(!m_initialized);
7816 }
7817}
7818
7819//-----------------------------------------------------------------------------
7820// For debugging support, record the win32 events.
7821// Note that although this is for debugging, we want it in retail because we'll
7822// be debugging retail most of the time :(
7823// pEvent - the win32 debug event we just received
7824// pUThread - our unmanaged thread object for the event. We could look it up
7825// from pEvent->dwThreadId, but passed in for perf reasons.
7826//-----------------------------------------------------------------------------
7827void CordbProcess::DebugRecordWin32Event(const DEBUG_EVENT * pEvent, CordbUnmanagedThread * pUThread)
7828{
7829 _ASSERTE(ThreadHoldsProcessLock());
7830
7831 // Although we could look up the Unmanaged thread, it's faster to have it just passed in.
7832 // So here we do a consistency check.
7833 _ASSERTE(pUThread != NULL);
7834 _ASSERTE(pUThread->m_id == pEvent->dwThreadId);
7835
7836 m_DbgSupport.m_TotalNativeEvents++; // bump up the counter.
7837
7838 MiniDebugEvent * pMiniEvent = &m_DbgSupport.m_DebugEventQueue[m_DbgSupport.m_DebugEventQueueIdx];
7839 pMiniEvent->code = (BYTE) pEvent->dwDebugEventCode;
7840 pMiniEvent->pUThread = pUThread;
7841
7842 DWORD tid = pEvent->dwThreadId;
7843
7844 // Record debug-event specific data.
7845 switch(pEvent->dwDebugEventCode)
7846 {
7847 case LOAD_DLL_DEBUG_EVENT:
7848 pMiniEvent->u.ModuleData.pBaseAddress = pEvent->u.LoadDll.lpBaseOfDll;
7849 STRESS_LOG2(LF_CORDB, LL_INFO1000, "Win32 Debug Event received: tid=0x%8x, Load Dll. Addr=%p\n",
7850 tid,
7851 pEvent->u.LoadDll.lpBaseOfDll);
7852 break;
7853 case UNLOAD_DLL_DEBUG_EVENT:
7854 pMiniEvent->u.ModuleData.pBaseAddress = pEvent->u.UnloadDll.lpBaseOfDll;
7855 STRESS_LOG2(LF_CORDB, LL_INFO1000, "Win32 Debug Event received: tid=0x%8x, Unload Dll. Addr=%p\n",
7856 tid,
7857 pEvent->u.UnloadDll.lpBaseOfDll);
7858 break;
7859 case EXCEPTION_DEBUG_EVENT:
7860 pMiniEvent->u.ExceptionData.pAddress = pEvent->u.Exception.ExceptionRecord.ExceptionAddress;
7861 pMiniEvent->u.ExceptionData.dwCode = pEvent->u.Exception.ExceptionRecord.ExceptionCode;
7862
7863 STRESS_LOG3(LF_CORDB, LL_INFO1000, "Win32 Debug Event received: tid=%8x, (1) Exception. Code=0x%08x, Addr=%p\n",
7864 tid,
7865 pMiniEvent->u.ExceptionData.dwCode,
7866 pMiniEvent->u.ExceptionData.pAddress
7867 );
7868 break;
7869 default:
7870 STRESS_LOG2(LF_CORDB, LL_INFO1000, "Win32 Debug Event received tid=%8x, %d\n", tid, pEvent->dwDebugEventCode);
7871 break;
7872 }
7873
7874
7875 // Go to the next entry in the queue.
7876 m_DbgSupport.m_DebugEventQueueIdx = (m_DbgSupport.m_DebugEventQueueIdx + 1) % DEBUG_EVENTQUEUE_SIZE;
7877}
7878
7879void CordbProcess::QueueUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent)
7880{
7881 INTERNAL_API_ENTRY(this);
7882 _ASSERTE(ThreadHoldsProcessLock());
7883 _ASSERTE(m_pShim != NULL);
7884
7885 LOG((LF_CORDB, LL_INFO10000, "CP::QUE: queued unmanaged event %d for thread 0x%x\n",
7886 pEvent->dwDebugEventCode, pUThread->m_id));
7887
7888
7889 _ASSERTE(pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT);
7890
7891 // Copy the event into the given thread
7892 CordbUnmanagedEvent *ue;
7893
7894 // Use the primary IB event slot unless this is the special stack overflow event case.
7895 if (!pUThread->HasSpecialStackOverflowCase())
7896 ue = pUThread->IBEvent();
7897 else
7898 ue = pUThread->IBEvent2();
7899
7900 if(pUThread->HasIBEvent() && !pUThread->HasSpecialStackOverflowCase())
7901 {
7902 // Any event being replaced should at least have been continued outside of the hijack
7903 // We don't track whether or not we expect the exception to retrigger but if we are replacing
7904 // the event then it did not.
7905 _ASSERTE(ue->IsEventContinuedUnhijacked());
7906 LOG((LF_CORDB, LL_INFO10000, "CP::QUE: A previously seen event is being discarded 0x%x 0x%p\n",
7907 ue->m_currentDebugEvent.u.Exception.ExceptionRecord.ExceptionCode,
7908 ue->m_currentDebugEvent.u.Exception.ExceptionRecord.ExceptionAddress));
7909 DequeueUnmanagedEvent(ue->m_owner);
7910 }
7911
7912 memcpy(&(ue->m_currentDebugEvent), pEvent, sizeof(DEBUG_EVENT));
7913 ue->m_state = CUES_IsIBEvent;
7914 ue->m_next = NULL;
7915
7916 // Enqueue the event.
7917 pUThread->SetState(CUTS_HasIBEvent);
7918
7919 if (m_unmanagedEventQueue == NULL)
7920 m_unmanagedEventQueue = ue;
7921 else
7922 m_lastQueuedUnmanagedEvent->m_next = ue;
7923
7924 m_lastQueuedUnmanagedEvent = ue;
7925}
7926
7927void CordbProcess::DequeueUnmanagedEvent(CordbUnmanagedThread *ut)
7928{
7929 INTERNAL_API_ENTRY(this);
7930
7931 _ASSERTE(m_unmanagedEventQueue != NULL);
7932 _ASSERTE(ut->HasIBEvent() || ut->HasSpecialStackOverflowCase());
7933 _ASSERTE(ThreadHoldsProcessLock());
7934
7935
7936 CordbUnmanagedEvent *ue;
7937
7938 if (ut->HasIBEvent())
7939 ue = ut->IBEvent();
7940 else
7941 {
7942 ue = ut->IBEvent2();
7943
7944 // Since we're dequeuing the special stack overflow event, we're no longer in the special stack overflow case.
7945 ut->ClearState(CUTS_HasSpecialStackOverflowCase);
7946 }
7947
7948 DWORD ec = ue->m_currentDebugEvent.dwDebugEventCode;
7949 LOG((LF_CORDB, LL_INFO10000, "CP::DUE: dequeue unmanaged event %d for thread 0x%x\n", ec, ut->m_id));
7950
7951 _ASSERTE(ec == EXCEPTION_DEBUG_EVENT);
7952
7953 CordbUnmanagedEvent **tmp = &m_unmanagedEventQueue;
7954 CordbUnmanagedEvent **prev = NULL;
7955
7956 // Note: this supports out-of-order dequeing of unmanaged events. This is necessary because we queue events even if
7957 // we're not clear on the ownership question. When we get the answer, and if the event belongs to the Runtime, we go
7958 // ahead and yank the event out of the queue, wherever it may be.
7959 while (*tmp && *tmp != ue)
7960 {
7961 prev = tmp;
7962 tmp = &((*tmp)->m_next);
7963 }
7964
7965 _ASSERTE(*tmp == ue);
7966
7967 *tmp = (*tmp)->m_next;
7968
7969 if (m_unmanagedEventQueue == NULL)
7970 m_lastQueuedUnmanagedEvent = NULL;
7971 else if (m_lastQueuedUnmanagedEvent == ue)
7972 {
7973 _ASSERTE(prev != NULL);
7974 m_lastQueuedUnmanagedEvent = *prev;
7975 }
7976
7977 ut->ClearState(CUTS_HasIBEvent);
7978
7979}
7980
7981void CordbProcess::QueueOOBUnmanagedEvent(CordbUnmanagedThread *pUThread, const DEBUG_EVENT * pEvent)
7982{
7983 INTERNAL_API_ENTRY(this);
7984 _ASSERTE(ThreadHoldsProcessLock());
7985 _ASSERTE(!pUThread->HasOOBEvent());
7986 _ASSERTE(IsWin32EventThread());
7987 _ASSERTE(m_pShim != NULL);
7988
7989 LOG((LF_CORDB, LL_INFO10000, "CP::QUE: queued OOB unmanaged event %d for thread 0x%x\n",
7990 pEvent->dwDebugEventCode, pUThread->m_id));
7991
7992 // Copy the event into the given thread
7993 CordbUnmanagedEvent *ue = pUThread->OOBEvent();
7994 memcpy(&(ue->m_currentDebugEvent), pEvent, sizeof(DEBUG_EVENT));
7995 ue->m_state = CUES_None;
7996 ue->m_next = NULL;
7997
7998 // Enqueue the event.
7999 pUThread->SetState(CUTS_HasOOBEvent);
8000
8001 if (m_outOfBandEventQueue == NULL)
8002 m_outOfBandEventQueue = ue;
8003 else
8004 m_lastQueuedOOBEvent->m_next = ue;
8005
8006 m_lastQueuedOOBEvent = ue;
8007}
8008
8009void CordbProcess::DequeueOOBUnmanagedEvent(CordbUnmanagedThread *ut)
8010{
8011 INTERNAL_API_ENTRY(this);
8012 _ASSERTE(m_outOfBandEventQueue != NULL);
8013 _ASSERTE(ut->HasOOBEvent());
8014 _ASSERTE(ThreadHoldsProcessLock());
8015
8016 CordbUnmanagedEvent *ue = ut->OOBEvent();
8017 DWORD ec = ue->m_currentDebugEvent.dwDebugEventCode;
8018
8019 LOG((LF_CORDB, LL_INFO10000, "CP::DUE: dequeue OOB unmanaged event %d for thread 0x%x\n", ec, ut->m_id));
8020
8021 CordbUnmanagedEvent **tmp = &m_outOfBandEventQueue;
8022 CordbUnmanagedEvent **prev = NULL;
8023
8024 // Note: this supports out-of-order dequeing of unmanaged events. This is necessary because we queue events even if
8025 // we're not clear on the ownership question. When we get the answer, and if the event belongs to the Runtime, we go
8026 // ahead and yank the event out of the queue, wherever it may be.
8027 while (*tmp && *tmp != ue)
8028 {
8029 prev = tmp;
8030 tmp = &((*tmp)->m_next);
8031 }
8032
8033 _ASSERTE(*tmp == ue);
8034
8035 *tmp = (*tmp)->m_next;
8036
8037 if (m_outOfBandEventQueue == NULL)
8038 m_lastQueuedOOBEvent = NULL;
8039 else if (m_lastQueuedOOBEvent == ue)
8040 {
8041 _ASSERTE(prev != NULL);
8042 m_lastQueuedOOBEvent = *prev;
8043 }
8044
8045 ut->ClearState(CUTS_HasOOBEvent);
8046}
8047
8048HRESULT CordbProcess::SuspendUnmanagedThreads()
8049{
8050 INTERNAL_API_ENTRY(this);
8051
8052 _ASSERTE(ThreadHoldsProcessLock());
8053
8054 // Iterate over all unmanaged threads...
8055 CordbUnmanagedThread* ut;
8056 HASHFIND find;
8057
8058 for (ut = m_unmanagedThreads.FindFirst(&find); ut != NULL; ut = m_unmanagedThreads.FindNext(&find))
8059 {
8060
8061 // Don't suspend any thread in a can't stop region. This includes cooperative mode threads & preemptive
8062 // threads that haven't pushed a NativeTransitionFrame. The ultimate problem here is that a thread
8063 // in this state is effectively inside the runtime, and thus may take a lock that blocks the helper thread.
8064 // IsCan'tStop also includes the helper thread & hijacked threads - which we shouldn't suspend anyways.
8065
8066 // Only suspend those unmanaged threads that aren't already suspended by us and that aren't already hijacked by
8067 // us.
8068
8069 if (!ut->IsSuspended() &&
8070 !ut->IsDeleted() &&
8071 !ut->IsCantStop() &&
8072 !ut->IsBlockingForSync()
8073 )
8074 {
8075 LOG((LF_CORDB, LL_INFO1000, "CP::SUT: suspending unmanaged thread 0x%x, handle 0x%x\n", ut->m_id, ut->m_handle));
8076
8077 DWORD succ = SuspendThread(ut->m_handle);
8078
8079 if (succ == 0xFFFFFFFF)
8080 {
8081 // This is okay... the thread may be dying after an ExitThread event.
8082 LOG((LF_CORDB, LL_INFO1000, "CP::SUT: failed to suspend thread 0x%x\n", ut->m_id));
8083 }
8084 else
8085 {
8086 m_state |= PS_SOME_THREADS_SUSPENDED;
8087
8088 ut->SetState(CUTS_Suspended);
8089 }
8090 }
8091 }
8092
8093 return S_OK;
8094}
8095
8096HRESULT CordbProcess::ResumeUnmanagedThreads()
8097{
8098 INTERNAL_API_ENTRY(this);
8099 _ASSERTE(ThreadHoldsProcessLock());
8100 FAIL_IF_NEUTERED(this);
8101
8102 // Iterate over all unmanaged threads...
8103 CordbUnmanagedThread* ut;
8104 HASHFIND find;
8105
8106 for (ut = m_unmanagedThreads.FindFirst(&find); ut != NULL; ut = m_unmanagedThreads.FindNext(&find))
8107 {
8108 // Only resume those unmanaged threads that were suspended by us.
8109 if (ut->IsSuspended())
8110 {
8111 LOG((LF_CORDB, LL_INFO1000, "CP::RUT: resuming unmanaged thread 0x%x\n", ut->m_id));
8112
8113 DWORD succ = ResumeThread(ut->m_handle);
8114
8115 if (succ == 0xFFFFFFFF)
8116 {
8117 LOG((LF_CORDB, LL_INFO1000, "CP::RUT: failed to resume thread 0x%x\n", ut->m_id));
8118 }
8119 else
8120 ut->ClearState(CUTS_Suspended);
8121 }
8122 }
8123
8124 m_state &= ~PS_SOME_THREADS_SUSPENDED;
8125
8126 return S_OK;
8127}
8128
8129//-----------------------------------------------------------------------------
8130// DispatchUnmanagedInBandEvent
8131//
8132// Handler for Win32 events already known to be Unmanaged and in-band.
8133//-----------------------------------------------------------------------------
8134void CordbProcess::DispatchUnmanagedInBandEvent()
8135{
8136 INTERNAL_API_ENTRY(this);
8137 _ASSERTE(ThreadHoldsProcessLock());
8138
8139 // There should be no queued OOB events!!! If there are, then we have a breakdown in our protocol, since all OOB
8140 // events should be dispatched before attempting to really continue from any in-band event.
8141 _ASSERTE(m_outOfBandEventQueue == NULL);
8142 _ASSERTE(m_cordb != NULL);
8143 _ASSERTE(m_cordb->m_unmanagedCallback != NULL);
8144 _ASSERTE(!m_dispatchingUnmanagedEvent);
8145
8146 CordbUnmanagedThread * pUnmanagedThread = NULL;
8147 CordbUnmanagedEvent * pUnmanagedEvent = m_unmanagedEventQueue;
8148
8149 while (true)
8150 {
8151 // get the next queued event that isn't dispatched yet
8152 while(pUnmanagedEvent != NULL && pUnmanagedEvent->IsDispatched())
8153 {
8154 pUnmanagedEvent = pUnmanagedEvent->m_next;
8155 }
8156
8157 if(pUnmanagedEvent == NULL)
8158 break;
8159
8160 // Get the thread for this event
8161 _ASSERTE(pUnmanagedThread == NULL);
8162 pUnmanagedThread = pUnmanagedEvent->m_owner;
8163 _ASSERTE(pUnmanagedThread != NULL);
8164
8165 // We better not have dispatched it yet!
8166 _ASSERTE(!pUnmanagedEvent->IsDispatched());
8167
8168 // We shouldn't be dispatching IB events on a thread that has exited.
8169 // Though it's possible that the thread may exit *after* the IB event has been dispatched
8170 // if it gets hijacked.
8171 _ASSERTE(!pUnmanagedThread->IsDeleted());
8172
8173 // Make sure we keep the thread alive while we're playing with it.
8174 pUnmanagedThread->InternalAddRef();
8175
8176 LOG((LF_CORDB, LL_INFO10000, "CP::DUE: dispatching unmanaged event %d for thread 0x%x\n",
8177 pUnmanagedEvent->m_currentDebugEvent.dwDebugEventCode, pUnmanagedThread->m_id));
8178
8179 m_dispatchingUnmanagedEvent = true;
8180
8181 // Add/Remove a reference which is scoped to the time that m_lastDispatchedIBEvent
8182 // is set to pUnmanagedEvent (it is an interior pointer)
8183 // see DevDiv issue 818301 for more details
8184 if(m_lastDispatchedIBEvent != NULL)
8185 {
8186 m_lastDispatchedIBEvent->m_owner->InternalRelease();
8187 m_lastDispatchedIBEvent = NULL;
8188 }
8189 pUnmanagedThread->InternalAddRef();
8190 m_lastDispatchedIBEvent = pUnmanagedEvent;
8191 pUnmanagedEvent->SetState(CUES_Dispatched);
8192
8193 IncStopCount();
8194
8195 Unlock();
8196
8197 {
8198 // Interface is semantically const, but does not include const in signature.
8199 DEBUG_EVENT * pEvent = const_cast<DEBUG_EVENT *> (&(pUnmanagedEvent->m_currentDebugEvent));
8200 PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(this,pEvent, FALSE);
8201 m_cordb->m_unmanagedCallback->DebugEvent(pEvent, FALSE);
8202 }
8203
8204 Lock();
8205
8206 // Calling IMDA::Continue() will set m_dispatchingUnmanagedEvent = false.
8207 // So if Continue() was called && we have more events, we'll loop and dispatch more events.
8208 // Else we'll break out of the while loop.
8209 if(m_dispatchingUnmanagedEvent)
8210 break;
8211
8212 // Continue was called in the dispatch callback, but that continue path just
8213 // clears the dispatch flag and returns. The continue right here is the logical
8214 // completion of the user's continue request
8215 // Note it is sometimes the case that these events have already been continued because
8216 // they had defered dispatching. At the time of deferal they were immediately continued.
8217 // If the event is already continued then this continue becomes a no-op.
8218 m_pShim->GetWin32EventThread()->DoDbgContinue(this, pUnmanagedEvent);
8219
8220 // Release our reference to the unmanaged thread that we dispatched
8221 // This event should have been continued long ago...
8222 _ASSERTE(!pUnmanagedThread->IBEvent()->IsEventWaitingForContinue());
8223 pUnmanagedThread->InternalRelease();
8224 pUnmanagedThread = NULL;
8225 }
8226
8227 m_dispatchingUnmanagedEvent = false;
8228
8229 // Release our reference to the last thread that we dispatched now...
8230 if(pUnmanagedThread)
8231 {
8232 pUnmanagedThread->InternalRelease();
8233 pUnmanagedThread = NULL;
8234 }
8235}
8236
8237//-----------------------------------------------------------------------------
8238// DispatchUnmanagedOOBEvent
8239//
8240// Handler for Win32 events already known to be Unmanaged and out-of-band.
8241//-----------------------------------------------------------------------------
8242void CordbProcess::DispatchUnmanagedOOBEvent()
8243{
8244 INTERNAL_API_ENTRY(this);
8245 _ASSERTE(ThreadHoldsProcessLock());
8246 _ASSERTE(IsWin32EventThread());
8247
8248 // There should be OOB events queued...
8249 _ASSERTE(m_outOfBandEventQueue != NULL);
8250 _ASSERTE(m_cordb->m_unmanagedCallback != NULL);
8251
8252 do
8253 {
8254 // Get the first event in the OOB Queue...
8255 CordbUnmanagedEvent * pUnmanagedEvent = m_outOfBandEventQueue;
8256 CordbUnmanagedThread * pUnmanagedThread = pUnmanagedEvent->m_owner;
8257
8258 // Make sure we keep the thread alive while we're playing with it.
8259 RSSmartPtr<CordbUnmanagedThread> pRef(pUnmanagedThread);
8260
8261 LOG((LF_CORDB, LL_INFO10000, "[%x] CP::DUE: dispatching OOB unmanaged event %d for thread 0x%x\n",
8262 GetCurrentThreadId(), pUnmanagedEvent->m_currentDebugEvent.dwDebugEventCode, pUnmanagedThread->m_id));
8263
8264 m_dispatchingOOBEvent = true;
8265 pUnmanagedEvent->SetState(CUES_Dispatched);
8266 Unlock();
8267
8268 {
8269 // Interface is semantically const, but does not include const in signature.
8270 DEBUG_EVENT * pEvent = const_cast<DEBUG_EVENT *> (&(pUnmanagedEvent->m_currentDebugEvent));
8271 PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(this, pEvent, TRUE);
8272 m_cordb->m_unmanagedCallback->DebugEvent(pEvent, TRUE);
8273 }
8274
8275 Lock();
8276
8277 // If they called Continue from the callback, then continue the OOB event right now before dispatching the next
8278 // one.
8279 if (!m_dispatchingOOBEvent)
8280 {
8281 DequeueOOBUnmanagedEvent(pUnmanagedThread);
8282
8283 // Should not have continued from this debug event yet.
8284 _ASSERTE(pUnmanagedEvent->IsEventWaitingForContinue());
8285
8286 // Do a little extra work if that was an OOB exception event...
8287 HRESULT hr = pUnmanagedEvent->m_owner->FixupAfterOOBException(pUnmanagedEvent);
8288 _ASSERTE(SUCCEEDED(hr));
8289
8290 // Go ahead and continue now...
8291 this->m_pShim->GetWin32EventThread()->DoDbgContinue(this, pUnmanagedEvent);
8292 }
8293
8294 // Implicit release of pUnmanagedThread via pRef
8295 }
8296 while (!m_dispatchingOOBEvent && (m_outOfBandEventQueue != NULL));
8297
8298 m_dispatchingOOBEvent = false;
8299
8300 LOG((LF_CORDB, LL_INFO10000, "CP::DUE: done dispatching OOB events. Queue=0x%08x\n", m_outOfBandEventQueue));
8301}
8302#endif // FEATURE_INTEROP_DEBUGGING
8303
8304//-----------------------------------------------------------------------------
8305// StartSyncFromWin32Stop
8306//
8307// Get the process from a Fozen state or a Live state to a Synchronized State.
8308// Note that Process Exit is considered to be synchronized.
8309// This is a nop if we're not Interop Debugging.
8310// If this function succeeds, we're in a synchronized state.
8311//
8312// Arguments:
8313// pfAsyncBreakSent - returns if this method sent an async-break or not.
8314//
8315// Return value:
8316// typical HRESULT return values, nothing sinister here.
8317//-----------------------------------------------------------------------------
8318HRESULT CordbProcess::StartSyncFromWin32Stop(BOOL * pfAsyncBreakSent)
8319{
8320 INTERNAL_API_ENTRY(this);
8321 if (m_pShim == NULL) // This API is moved off to the shim
8322 {
8323 return E_NOTIMPL;
8324 }
8325
8326 HRESULT hr = S_OK;
8327
8328 // Caller should have taken the stop-go lock. This prevents us from racing w/ a continue.
8329 _ASSERTE(m_StopGoLock.HasLock());
8330
8331 // Process should be init before we try to sync it.
8332 _ASSERTE(this->m_initialized);
8333
8334 // If nobody's listening for an AsyncBreak, and we're not stopped, then our caller
8335 // doesn't know if we're sending an AsyncBreak or not; and thus we may not continue.
8336 // Failing this assert means that we're stopping but we don't think we're going to get a continue
8337 // down the road, and thus we're headed for a deadlock.
8338 _ASSERTE((pfAsyncBreakSent != NULL) || (m_stopCount > 0));
8339
8340 if (pfAsyncBreakSent)
8341 {
8342 *pfAsyncBreakSent = FALSE;
8343 }
8344
8345#ifdef FEATURE_INTEROP_DEBUGGING
8346
8347 // If we're win32 stopped (but not out-of-band win32 stopped), or if we're running free on the Left Side but we're
8348 // just not synchronized (and we're win32 attached), then go ahead and do an internal continue and send an async
8349 // break event to get the Left Side sync'd up.
8350 //
8351 // The process can be running free as far as Win32 events are concerned, but still not synchronized as far as the
8352 // Runtime is concerned. This can happen in a lot of cases where we end up with the Runtime not sync'd but with the
8353 // process running free due to hijacking, etc...
8354 if (((m_state & CordbProcess::PS_WIN32_STOPPED) && (m_outOfBandEventQueue == NULL)) ||
8355 (!GetSynchronized() && IsInteropDebugging()))
8356 {
8357 Lock();
8358
8359 if (((m_state & CordbProcess::PS_WIN32_STOPPED) && (m_outOfBandEventQueue == NULL)) ||
8360 (!GetSynchronized() && IsInteropDebugging()))
8361 {
8362 // This can't be the win32 ET b/c we need that thread to be alive and pumping win32 DE so that
8363 // our Async Break can get across.
8364 // So nobody should ever be calling this on the w32 ET. But they could, since we do trickle in from
8365 // outside APIs. So we need a retail check.
8366 if (IsWin32EventThread())
8367 {
8368 _ASSERTE(!"Don't call this API on the W32 Event Thread");
8369
8370 Unlock();
8371 return ErrWrapper(CORDBG_E_CANT_CALL_ON_THIS_THREAD);
8372 }
8373
8374 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[%x] CP::SSFW32S: sending internal continue\n", GetCurrentThreadId());
8375
8376 // Can't do this on the win32 event thread.
8377 _ASSERTE(!this->IsWin32EventThread());
8378
8379 // If the helper thread is already dead, then we just return as if we sync'd the process.
8380 if (m_helperThreadDead)
8381 {
8382 if (pfAsyncBreakSent)
8383 {
8384 *pfAsyncBreakSent = TRUE;
8385 }
8386
8387 // Mark the process as synchronized so no events will be dispatched until the thing is
8388 // continued. However, the marking here is not a usual marking for synchronized. It has special
8389 // semantics when we're interop debugging. We use m_oddSync to remember this so that we can take special
8390 // action in Continue().
8391 SetSynchronized(true);
8392 m_oddSync = true;
8393
8394 // Get the RC Event Thread to stop listening to the process.
8395 m_cordb->ProcessStateChanged();
8396
8397 Unlock();
8398
8399 return S_OK;
8400 }
8401
8402 m_stopRequested = true;
8403
8404 // See ::Stop for why we defer this. The delayed events will be dispatched when some one calls continue.
8405 // And we know they'll call continue b/c (stopCount > 0) || (our caller knows we're sending an AsyncBreak).
8406 m_specialDeferment = true;
8407
8408 Unlock();
8409
8410 // If the process gets synchronized between the Unlock() and here, then SendUnmanagedContinue() will end up
8411 // not doing anything at all since a) it holds the process lock when working and b) it gates everything on
8412 // if the process is sync'd or not. This is exactly what we want.
8413 hr = this->m_pShim->GetWin32EventThread()->SendUnmanagedContinue(this, cInternalUMContinue);
8414
8415 LOG((LF_CORDB, LL_INFO1000, "[%x] CP::SSFW32S: internal continue returned\n", GetCurrentThreadId()));
8416
8417 // Send an async break to the left side now that its running.
8418 DebuggerIPCEvent * pEvent = (DebuggerIPCEvent *) _alloca(CorDBIPC_BUFFER_SIZE);
8419 InitIPCEvent(pEvent, DB_IPCE_ASYNC_BREAK, false, VMPTR_AppDomain::NullPtr());
8420
8421 LOG((LF_CORDB, LL_INFO1000, "[%x] CP::SSFW32S: sending async stop\n", GetCurrentThreadId()));
8422
8423 // If the process gets synchronized between the Unlock() and here, then this message will do nothing (Left
8424 // Side catches it) and we'll never get a response, and it won't hurt anything.
8425 hr = m_cordb->SendIPCEvent(this, pEvent, CorDBIPC_BUFFER_SIZE);
8426 // @Todo- how do we handle a failure here?
8427
8428 // If the send returns with the helper thread being dead, then we know we don't need to wait for the process
8429 // to sync.
8430 if (!m_helperThreadDead)
8431 {
8432 STRESS_LOG1(LF_CORDB, LL_INFO1000, "[%x] CP::SSFW32S: sent async stop, waiting for event\n", GetCurrentThreadId());
8433
8434 // If we got synchronized between the Unlock() and here its okay since m_stopWaitEvent is still high
8435 // from the last sync.
8436 DWORD dwWaitResult = SafeWaitForSingleObject(this, m_stopWaitEvent, INFINITE);
8437
8438 STRESS_LOG2(LF_CORDB, LL_INFO1000, "[%x] CP::SSFW32S: got event, %d\n", GetCurrentThreadId(), dwWaitResult);
8439
8440 _ASSERTE(dwWaitResult == WAIT_OBJECT_0);
8441 }
8442
8443 Lock();
8444
8445 m_specialDeferment = false;
8446
8447 if (pfAsyncBreakSent)
8448 {
8449 *pfAsyncBreakSent = TRUE;
8450 }
8451
8452 // If the helper thread died while we were trying to send an event to it, then we just do the same odd sync
8453 // logic we do above.
8454 if (m_helperThreadDead)
8455 {
8456 SetSynchronized(true);
8457 m_oddSync = true;
8458 hr = S_OK;
8459 }
8460
8461 m_stopRequested = false;
8462 m_cordb->ProcessStateChanged();
8463 }
8464
8465 Unlock();
8466 }
8467#endif // FEATURE_INTEROP_DEBUGGING
8468
8469 return hr;
8470}
8471
8472// Check if the left side has exited. If so, get the right-side
8473// into shutdown mode. Only use this to avert us from going into
8474// an unrecoverable error.
8475bool CordbProcess::CheckIfLSExited()
8476{
8477// Check by waiting on the handle with no timeout.
8478 if (WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0)
8479 {
8480 Lock();
8481 m_terminated = true;
8482 m_exiting = true;
8483 Unlock();
8484 }
8485
8486 LOG((LF_CORDB, LL_INFO10, "CP::IsLSExited() returning '%s'\n",
8487 m_exiting ? "true" : "false"));
8488
8489 return m_exiting;
8490}
8491
8492// Call this if something really bad happened and we can't do
8493// anything meaningful with the CordbProcess.
8494void CordbProcess::UnrecoverableError(HRESULT errorHR,
8495 unsigned int errorCode,
8496 const char *errorFile,
8497 unsigned int errorLine)
8498{
8499 LOG((LF_CORDB, LL_INFO10, "[%x] CP::UE: unrecoverable error 0x%08x "
8500 "(%d) %s:%d\n",
8501 GetCurrentThreadId(),
8502 errorHR, errorCode, errorFile, errorLine));
8503
8504 // We definitely want to know about any of these.
8505 STRESS_LOG3(LF_CORDB, LL_EVERYTHING, "Unrecoverable Error:0x%08x, File=%s, line=%d\n", errorHR, errorFile, errorLine);
8506
8507 // It's possible for an unrecoverable error to occur if the user detaches the
8508 // debugger while inside CordbProcess::DispatchRCEvent() (as that function deliberately
8509 // calls Unlock() while calling into the Shim). Detect such cases here & bail before we
8510 // try to access invalid fields on this CordbProcess.
8511 //
8512 // Normally, we'd need to take the cordb process lock around the IsNeutered check
8513 // (and the code that follows). And perhaps this is a good thing to do in the
8514 // future. But for now we're not for two reasons:
8515 //
8516 // 1) It's scary. We're in UnrecoverableError() for gosh sake. I don't know all
8517 // the possible bad states we can be in to get here. Will taking the process lock
8518 // have ordering issues? Will the process lock even be valid to take here (or might
8519 // we AV)? Since this is error handling, we should probably be as light as we can
8520 // not to cause more errors.
8521 //
8522 // 2) It's unnecessary. For the Watson dump I investigated that caused this fix in
8523 // the first place, we already detached before entering UnrecoverableError()
8524 // (indeed, the only reason we're in UnrecoverableError is that we already detached
8525 // and that caused a prior API to fail). Thus, there's no timing issue (in that
8526 // case, anyway), wrt to entering UnrecoverableError() and detaching / neutering.
8527 if (IsNeutered())
8528 return;
8529
8530#ifdef _DEBUG
8531 // Ping our error trapping logic
8532 HRESULT hrDummy;
8533 hrDummy = ErrWrapper(errorHR);
8534#endif
8535
8536 if (m_pShim == NULL)
8537 {
8538 // @dbgtodo - , shim: Once everything is hoisted, we can remove
8539 // this code.
8540 // In the v3 case, we should never get an unrecoverable error. Instead, the HR should be propogated
8541 // and returned at the top-level public API.
8542 _ASSERTE(!"Unrecoverable error dispatched in V3 case.");
8543 }
8544
8545 CONSISTENCY_CHECK_MSGF(IsLegalFatalError(errorHR), ("Unrecoverable internal error: hr=0x%08x!", errorHR));
8546
8547 if (!IsLegalFatalError(errorHR) || (errorHR != CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS))
8548 {
8549 // This will throw everything into a Zombie state. The ATT_ macros will check this and fail immediately.
8550 m_unrecoverableError = true;
8551
8552 //
8553 // Mark the process as no longer synchronized.
8554 //
8555 Lock();
8556 SetSynchronized(false);
8557 IncStopCount();
8558 Unlock();
8559 }
8560
8561 // Set the error flags in the process so that if parts of it are
8562 // still alive, it will realize that its in this mode and do the
8563 // right thing.
8564 if (GetDCB() != NULL)
8565 {
8566 GetDCB()->m_errorHR = errorHR;
8567 GetDCB()->m_errorCode = errorCode;
8568 EX_TRY
8569 {
8570 UpdateLeftSideDCBField(&(GetDCB()->m_errorHR), sizeof(GetDCB()->m_errorHR));
8571 UpdateLeftSideDCBField(&(GetDCB()->m_errorCode), sizeof(GetDCB()->m_errorCode));
8572 }
8573 EX_CATCH
8574 {
8575 _ASSERTE(!"Writing process memory failed, perhaps due to an unexpected disconnection from the target.");
8576 }
8577 EX_END_CATCH(SwallowAllExceptions);
8578 }
8579
8580 //
8581 // Let the user know that we've hit an unrecoverable error.
8582 //
8583 if (m_cordb->m_managedCallback)
8584 {
8585 // We are about to send DebuggerError call back. The state of RS is undefined.
8586 // So we use the special Public Callback. We may be holding locks and stuff.
8587 // We may also be deeply nested within the RS.
8588 PUBLIC_CALLBACK_IN_THIS_SCOPE_DEBUGGERERROR(this);
8589 m_cordb->m_managedCallback->DebuggerError((ICorDebugProcess*) this,
8590 errorHR,
8591 errorCode);
8592 }
8593}
8594
8595
8596HRESULT CordbProcess::CheckForUnrecoverableError()
8597{
8598 HRESULT hr = S_OK;
8599
8600 if (GetDCB() != NULL)
8601 {
8602 // be sure we have the latest information
8603 UpdateRightSideDCB();
8604
8605 if (GetDCB()->m_errorHR != S_OK)
8606 {
8607 UnrecoverableError(GetDCB()->m_errorHR,
8608 GetDCB()->m_errorCode,
8609 __FILE__, __LINE__);
8610
8611 hr = GetDCB()->m_errorHR;
8612 }
8613 }
8614
8615 return hr;
8616}
8617
8618
8619/*
8620 * EnableLogMessages enables/disables sending of log messages to the
8621 * debugger for logging.
8622 */
8623HRESULT CordbProcess::EnableLogMessages(BOOL fOnOff)
8624{
8625 PUBLIC_API_ENTRY(this);
8626 FAIL_IF_NEUTERED(this);
8627 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
8628 HRESULT hr = S_OK;
8629
8630 DebuggerIPCEvent *event = (DebuggerIPCEvent*) _alloca(CorDBIPC_BUFFER_SIZE);
8631 InitIPCEvent(event, DB_IPCE_ENABLE_LOG_MESSAGES, false, VMPTR_AppDomain::NullPtr());
8632 event->LogSwitchSettingMessage.iLevel = (int)fOnOff;
8633
8634 hr = m_cordb->SendIPCEvent(this, event, CorDBIPC_BUFFER_SIZE);
8635 hr = WORST_HR(hr, event->hr);
8636
8637 LOG((LF_CORDB, LL_INFO10000, "[%x] CP::EnableLogMessages: EnableLogMessages=%d sent.\n",
8638 GetCurrentThreadId(), fOnOff));
8639
8640 return hr;
8641}
8642
8643/*
8644 * ModifyLogSwitch modifies the specified switch's severity level.
8645 */
8646COM_METHOD CordbProcess::ModifyLogSwitch(__in_z WCHAR *pLogSwitchName, LONG lLevel)
8647{
8648 PUBLIC_API_ENTRY(this);
8649 FAIL_IF_NEUTERED(this);
8650 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
8651
8652 HRESULT hr = S_OK;
8653
8654 _ASSERTE (pLogSwitchName != NULL);
8655
8656 DebuggerIPCEvent *event = (DebuggerIPCEvent*) _alloca(CorDBIPC_BUFFER_SIZE);
8657 InitIPCEvent(event, DB_IPCE_MODIFY_LOGSWITCH, false, VMPTR_AppDomain::NullPtr());
8658 event->LogSwitchSettingMessage.iLevel = lLevel;
8659 event->LogSwitchSettingMessage.szSwitchName.SetStringTruncate(pLogSwitchName);
8660
8661 hr = m_cordb->SendIPCEvent(this, event, CorDBIPC_BUFFER_SIZE);
8662 hr = WORST_HR(hr, event->hr);
8663
8664 LOG((LF_CORDB, LL_INFO10000, "[%x] CP::ModifyLogSwitch: ModifyLogSwitch sent.\n",
8665 GetCurrentThreadId()));
8666
8667 return hr;
8668}
8669
8670//-----------------------------------------------------------------------------
8671// Writes a buffer from the target and performs checks similar to SafeWriteStruct
8672//
8673// Arguments:
8674// tb - TargetBuffer which represents the target memory we want to write to
8675// pLocalBuffer - local pointer into source buffer
8676// cbSize - the size of local buffer
8677//
8678// Exceptions
8679// On error throws the result of WriteVirtual unless a short write is performed,
8680// in which case throws ERROR_PARTIAL_COPY
8681//
8682void CordbProcess::SafeWriteBuffer(TargetBuffer tb,
8683 const BYTE * pLocalBuffer)
8684{
8685 _ASSERTE(m_pMutableDataTarget != NULL);
8686 HRESULT hr = m_pMutableDataTarget->WriteVirtual(tb.pAddress,
8687 pLocalBuffer,
8688 tb.cbSize);
8689 IfFailThrow(hr);
8690}
8691
8692//-----------------------------------------------------------------------------
8693// Reads a buffer from the target and performs checks similar to SafeWriteStruct
8694//
8695// Arguments:
8696// tb - TargetBuffer which represents the target memory to read from
8697// pLocalBuffer - local pointer into source buffer
8698// cbSize - the size of the remote buffer
8699// throwOnError - determines whether the function throws exceptions or returns HRESULTs
8700// in failure cases
8701//
8702// Exceptions:
8703// If throwOnError is TRUE
8704// On error always throws the special CORDBG_E_READVIRTUAL_FAILURE, unless a short write is performed
8705// in which case throws ERROR_PARTIAL_COPY
8706// If throwOnError is FALSE
8707// No exceptions are thrown, and instead the same error codes are returned as HRESULTs
8708//
8709HRESULT CordbProcess::SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer, BOOL throwOnError)
8710{
8711 ULONG32 cbRead;
8712 HRESULT hr = m_pDACDataTarget->ReadVirtual(tb.pAddress,
8713 pLocalBuffer,
8714 tb.cbSize,
8715 &cbRead);
8716
8717 if (FAILED(hr))
8718 {
8719 if (throwOnError)
8720 ThrowHR(CORDBG_E_READVIRTUAL_FAILURE);
8721 else
8722 return CORDBG_E_READVIRTUAL_FAILURE;
8723 }
8724
8725 if (cbRead != tb.cbSize)
8726 {
8727 if (throwOnError)
8728 ThrowWin32(ERROR_PARTIAL_COPY);
8729 else
8730 return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
8731 }
8732 return S_OK;
8733}
8734
8735
8736//---------------------------------------------------------------------------------------
8737// Lookup or create an appdomain.
8738//
8739// Arguments:
8740// vmAppDomain - CLR appdomain to lookup
8741//
8742// Returns:
8743// Instance of CordbAppDomain for the given appdomain. This is a cached instance.
8744// If the CordbAppDomain does not yet exist, it will be created and added to the cache.
8745// Never returns NULL. Throw on error.
8746CordbAppDomain * CordbProcess::LookupOrCreateAppDomain(VMPTR_AppDomain vmAppDomain)
8747{
8748 CordbAppDomain * pAppDomain = m_appDomains.GetBase(VmPtrToCookie(vmAppDomain));
8749 if (pAppDomain != NULL)
8750 {
8751 return pAppDomain;
8752 }
8753 return CacheAppDomain(vmAppDomain);
8754}
8755
8756CordbAppDomain * CordbProcess::GetSharedAppDomain()
8757{
8758 if (m_sharedAppDomain == NULL)
8759 {
8760 CordbAppDomain *pAD = new CordbAppDomain(this, VMPTR_AppDomain::NullPtr());
8761 if (InterlockedCompareExchangeT<CordbAppDomain*>(&m_sharedAppDomain, pAD, NULL) != NULL)
8762 {
8763 delete pAD;
8764 }
8765 m_sharedAppDomain->InternalAddRef();
8766 }
8767
8768 return m_sharedAppDomain;
8769}
8770
8771//---------------------------------------------------------------------------------------
8772//
8773// Add a new appdomain to the cache.
8774//
8775// Arguments:
8776// vmAppDomain - appdomain to add.
8777//
8778// Return Value:
8779// Pointer to newly created appdomain, which should be the normal case.
8780// Throws on failure. Never returns null.
8781//
8782// Assumptions:
8783// Caller ensure the appdomain is not already cached.
8784// Caller should have stop-go lock, which provides thread-safety.
8785//
8786// Notes:
8787// This sets unrecoverable error on failure.
8788//
8789//---------------------------------------------------------------------------------------
8790CordbAppDomain * CordbProcess::CacheAppDomain(VMPTR_AppDomain vmAppDomain)
8791{
8792 INTERNAL_API_ENTRY(GetProcess());
8793
8794 _ASSERTE(GetProcessLock()->HasLock());
8795
8796 RSInitHolder<CordbAppDomain> pAppDomain;
8797 pAppDomain.Assign(new CordbAppDomain(this, vmAppDomain)); // throws
8798
8799 // Add to the hash. This will addref the pAppDomain.
8800 // Caller ensures we're not already cached.
8801 // The cache will take ownership.
8802 m_appDomains.AddBaseOrThrow(pAppDomain);
8803
8804 // see if this is the default AppDomain
8805 IDacDbiInterface * pDac = m_pProcess->GetDAC();
8806 BOOL fIsDefaultDomain = FALSE;
8807
8808 fIsDefaultDomain = pDac->IsDefaultDomain(vmAppDomain); // throws
8809
8810 if (fIsDefaultDomain)
8811 {
8812 // If this assert fires, then it likely means the target is corrupted.
8813 TargetConsistencyCheck(m_pDefaultAppDomain == NULL);
8814 m_pDefaultAppDomain = pAppDomain;
8815 }
8816
8817 CordbAppDomain * pReturn = pAppDomain;
8818 pAppDomain.ClearAndMarkDontNeuter();
8819
8820 _ASSERTE(pReturn != NULL);
8821 return pReturn;
8822}
8823
8824//---------------------------------------------------------------------------------------
8825//
8826// Callback for Appdomain enumeration.
8827//
8828// Arguments:
8829// vmAppDomain - new appdomain to add to enumeration
8830// pUserData - data passed with callback (a 'this' ptr for CordbProcess)
8831//
8832//
8833// Assumptions:
8834// Invoked as callback from code:CordbProcess::PrepopulateAppDomains
8835//
8836//
8837//---------------------------------------------------------------------------------------
8838
8839// static
8840void CordbProcess::AppDomainEnumerationCallback(VMPTR_AppDomain vmAppDomain, void * pUserData)
8841{
8842 CONTRACTL
8843 {
8844 THROWS;
8845 }
8846 CONTRACTL_END;
8847
8848 CordbProcess * pProcess = static_cast<CordbProcess *> (pUserData);
8849 INTERNAL_DAC_CALLBACK(pProcess);
8850
8851 pProcess->LookupOrCreateAppDomain(vmAppDomain);
8852}
8853
8854//---------------------------------------------------------------------------------------
8855//
8856// Traverse appdomains in the target and build up our list.
8857//
8858// Arguments:
8859//
8860// Return Value:
8861// returns on success.
8862// Throws on error. AppDomain cache may be partially populated.
8863//
8864// Assumptions:
8865// This is an non-invasive inspection operation called when the debuggee is stopped.
8866//
8867// Notes:
8868// This can be called multiple times. If the list is non-empty, it will nop.
8869//---------------------------------------------------------------------------------------
8870void CordbProcess::PrepopulateAppDomainsOrThrow()
8871{
8872 CONTRACTL
8873 {
8874 THROWS;
8875 }
8876 CONTRACTL_END;
8877
8878 INTERNAL_API_ENTRY(this);
8879
8880 if (!IsDacInitialized())
8881 {
8882 return;
8883 }
8884
8885 // DD-primitive that invokes a callback. This may throw.
8886 GetDAC()->EnumerateAppDomains(
8887 CordbProcess::AppDomainEnumerationCallback,
8888 this);
8889}
8890
8891//---------------------------------------------------------------------------------------
8892//
8893// EnumerateAppDomains enumerates all app domains in the process.
8894//
8895// Arguments:
8896// ppAppDomains - get appdomain enumerator
8897//
8898// Return Value:
8899// S_OK on success.
8900//
8901// Assumptions:
8902//
8903//
8904// Notes:
8905// This operation is non-invasive target.
8906//
8907//---------------------------------------------------------------------------------------
8908HRESULT CordbProcess::EnumerateAppDomains(ICorDebugAppDomainEnum **ppAppDomains)
8909{
8910 HRESULT hr = S_OK;
8911 PUBLIC_API_BEGIN(this);
8912 {
8913 ValidateOrThrow(ppAppDomains);
8914
8915 // Ensure list is populated.
8916 PrepopulateAppDomainsOrThrow();
8917
8918 RSInitHolder<CordbHashTableEnum> pEnum;
8919 CordbHashTableEnum::BuildOrThrow(
8920 this,
8921 GetContinueNeuterList(),
8922 &m_appDomains,
8923 IID_ICorDebugAppDomainEnum,
8924 pEnum.GetAddr());
8925
8926 *ppAppDomains = static_cast<ICorDebugAppDomainEnum*> (pEnum);
8927 pEnum->ExternalAddRef();
8928
8929 pEnum.ClearAndMarkDontNeuter();
8930 }
8931 PUBLIC_API_END(hr);
8932 return hr;
8933}
8934
8935/*
8936 * GetObject returns the runtime process object.
8937 * Note: This method is not yet implemented.
8938 */
8939HRESULT CordbProcess::GetObject(ICorDebugValue **ppObject)
8940{
8941 PUBLIC_API_ENTRY(this);
8942 FAIL_IF_NEUTERED(this);
8943 VALIDATE_POINTER_TO_OBJECT(ppObject, ICorDebugObjectValue **);
8944
8945 return E_NOTIMPL;
8946}
8947
8948
8949//---------------------------------------------------------------------------------------
8950//
8951// Given a taskid, finding the corresponding thread. The function can fail if we do not
8952// find any thread with the given taskid
8953//
8954// Arguments:
8955// taskId - The task ID to look for.
8956// ppThread - OUT: Space for storing the thread corresponding to the taskId given.
8957//
8958// Return Value:
8959// Typical HRESULT symantics, nothing abnormal.
8960//
8961HRESULT CordbProcess::GetThreadForTaskID(TASKID taskId, ICorDebugThread2 ** ppThread)
8962{
8963 PUBLIC_API_ENTRY(this);
8964 FAIL_IF_NEUTERED(this);
8965 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8966
8967 HRESULT hr = S_OK;
8968
8969 EX_TRY
8970 {
8971 RSLockHolder lockHolder(GetProcessLock());
8972
8973 if (ppThread == NULL)
8974 {
8975 ThrowHR(E_INVALIDARG);
8976 }
8977
8978 // On initialization, the task ID of every thread is INVALID_TASK_ID, unless a host is present and
8979 // the host calls IClrTask::SetTaskIdentifier(). So we need to explicitly check for INVALID_TASK_ID
8980 // here and return NULL if necessary. We return S_FALSE because that's the return value for the case
8981 // where we can't find a thread for the specified task ID.
8982 if (taskId == INVALID_TASK_ID)
8983 {
8984 *ppThread = NULL;
8985 hr = S_FALSE;
8986 }
8987 else
8988 {
8989 PrepopulateThreadsOrThrow();
8990
8991 // now find the ICorDebugThread corresponding to it
8992 CordbThread * pThread;
8993 HASHFIND hashFind;
8994
8995
8996 for (pThread = m_userThreads.FindFirst(&hashFind);
8997 pThread != NULL;
8998 pThread = m_userThreads.FindNext(&hashFind))
8999 {
9000 if (pThread->GetTaskID() == taskId)
9001 {
9002 break;
9003 }
9004 }
9005
9006 if (pThread == NULL)
9007 {
9008 *ppThread = NULL;
9009 hr = S_FALSE;
9010 }
9011 else
9012 {
9013 *ppThread = pThread;
9014 pThread->ExternalAddRef();
9015 }
9016 }
9017 }
9018 EX_CATCH_HRESULT(hr);
9019 return hr;
9020} // CordbProcess::GetThreadForTaskid
9021
9022HRESULT
9023CordbProcess::GetVersion(COR_VERSION* pVersion)
9024{
9025 if (NULL == pVersion)
9026 {
9027 return E_INVALIDARG;
9028 }
9029
9030 //
9031 // Because we require a matching version of mscordbi.dll to debug a certain version of the runtime,
9032 // we can just use constants found in this particular mscordbi.dll to determine the version of the left side.
9033 pVersion->dwMajor = CLR_MAJOR_VERSION;
9034 pVersion->dwMinor = CLR_MINOR_VERSION;
9035 pVersion->dwBuild = CLR_BUILD_VERSION;
9036 pVersion->dwSubBuild = CLR_BUILD_VERSION_QFE;
9037
9038 return S_OK;
9039}
9040
9041#ifdef FEATURE_INTEROP_DEBUGGING
9042//-----------------------------------------------------------------------------
9043// Search for a native patch given the address. Return null if not found.
9044// Since we return an address, this is only valid until the table is disturbed.
9045//-----------------------------------------------------------------------------
9046NativePatch * CordbProcess::GetNativePatch(const void * pAddress)
9047{
9048 _ASSERTE(ThreadHoldsProcessLock());
9049
9050 int cTotal = m_NativePatchList.Count();
9051 NativePatch * pTable = m_NativePatchList.Table();
9052 if (pTable == NULL)
9053 {
9054 return NULL;
9055 }
9056
9057 for(int i = 0; i < cTotal; i++)
9058 {
9059 if (pTable[i].pAddress == pAddress)
9060 {
9061 return &pTable[i];
9062 }
9063 }
9064 return NULL;
9065}
9066
9067//-----------------------------------------------------------------------------
9068// Is there an break-opcode (int3 on x86) at the address in the debuggee?
9069//-----------------------------------------------------------------------------
9070bool CordbProcess::IsBreakOpcodeAtAddress(const void * address)
9071{
9072 // There should have been an int3 there already. Since we already put it in there,
9073 // we should be able to safely read it out.
9074#if defined(DBG_TARGET_ARM) || defined(DBG_TARGET_ARM64)
9075 PRD_TYPE opcodeTest = 0;
9076#elif defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_X86)
9077 BYTE opcodeTest = 0;
9078#else
9079 PORTABILITY_ASSERT("NYI: Architecture specific opcode type to read");
9080#endif
9081
9082 HRESULT hr = SafeReadStruct(PTR_TO_CORDB_ADDRESS(address), &opcodeTest);
9083 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
9084
9085 return (opcodeTest == CORDbg_BREAK_INSTRUCTION);
9086}
9087#endif // FEATURE_INTEROP_DEBUGGING
9088
9089//-----------------------------------------------------------------------------
9090// CordbProcess::SetUnmanagedBreakpoint
9091// Called by a native debugger to add breakpoints during Interop.
9092// address - remote address into the debuggee
9093// bufsize, buffer[] - initial size & buffer for the opcode that we're replacing.
9094// buflen - size of the buffer that we write to.
9095//-----------------------------------------------------------------------------
9096HRESULT
9097CordbProcess::SetUnmanagedBreakpoint(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen)
9098{
9099 LOG((LF_CORDB, LL_INFO100, "CP::SetUnBP: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address)));
9100#ifndef FEATURE_INTEROP_DEBUGGING
9101 return E_NOTIMPL;
9102#else
9103 PUBLIC_API_ENTRY(this);
9104 FAIL_IF_NEUTERED(this);
9105 FAIL_IF_MANAGED_ONLY(this);
9106 _ASSERTE(!ThreadHoldsProcessLock());
9107 Lock();
9108 HRESULT hr = SetUnmanagedBreakpointInternal(address, bufsize, buffer, bufLen);
9109 Unlock();
9110 return hr;
9111#endif
9112}
9113
9114//-----------------------------------------------------------------------------
9115// CordbProcess::SetUnmanagedBreakpointInternal
9116// The worker behind SetUnmanagedBreakpoint, this function can set both public
9117// breakpoints used by the debugger and internal breakpoints used for utility
9118// purposes in interop debugging.
9119// address - remote address into the debuggee
9120// bufsize, buffer[] - initial size & buffer for the opcode that we're replacing.
9121// buflen - size of the buffer that we write to.
9122//-----------------------------------------------------------------------------
9123HRESULT
9124CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen)
9125{
9126 LOG((LF_CORDB, LL_INFO100, "CP::SetUnBPI: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address)));
9127#ifndef FEATURE_INTEROP_DEBUGGING
9128 return E_NOTIMPL;
9129#else
9130
9131 INTERNAL_API_ENTRY(this);
9132 FAIL_IF_NEUTERED(this);
9133 FAIL_IF_MANAGED_ONLY(this);
9134 _ASSERTE(ThreadHoldsProcessLock());
9135
9136 HRESULT hr = S_OK;
9137
9138 NativePatch * p = NULL;
9139#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
9140 const BYTE patch = CORDbg_BREAK_INSTRUCTION;
9141 BYTE opcode;
9142#elif defined(DBG_TARGET_ARM64)
9143 const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION;
9144 PRD_TYPE opcode;
9145#else
9146 PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform");
9147 hr = E_NOTIMPL;
9148 goto ErrExit;
9149#endif
9150
9151 // Make sure args are good
9152 if ((buffer == NULL) || (bufsize < sizeof(patch)) || (bufLen == NULL))
9153 {
9154 hr = E_INVALIDARG;
9155 goto ErrExit;
9156 }
9157
9158 // Fail if there's already a patch at this address.
9159 if (GetNativePatch(CORDB_ADDRESS_TO_PTR(address)) != NULL)
9160 {
9161 hr = CORDBG_E_NATIVE_PATCH_ALREADY_AT_ADDR;
9162 goto ErrExit;
9163 }
9164
9165 // Preallocate this now so that if are oom, we can fail before we get half-way through.
9166 p = m_NativePatchList.Append();
9167 if (p == NULL)
9168 {
9169 hr = E_OUTOFMEMORY;
9170 goto ErrExit;
9171 }
9172
9173
9174 // Read out opcode. 1 byte on x86
9175
9176 hr = ApplyRemotePatch(this, CORDB_ADDRESS_TO_PTR(address), &p->opcode);
9177 if (FAILED(hr))
9178 goto ErrExit;
9179
9180 // It's all successful, so now update our out-params & internal bookkeaping.
9181#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
9182 opcode = (BYTE)p->opcode;
9183 buffer[0] = opcode;
9184#elif defined(DBG_TARGET_ARM64)
9185 opcode = p->opcode;
9186 memcpy_s(buffer, bufsize, &opcode, sizeof(opcode));
9187#else
9188 PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform");
9189#endif
9190 *bufLen = sizeof(opcode);
9191
9192 p->pAddress = CORDB_ADDRESS_TO_PTR(address);
9193 p->opcode = opcode;
9194
9195 _ASSERTE(SUCCEEDED(hr));
9196
9197ErrExit:
9198 // If we failed, then free the patch
9199 if (FAILED(hr) && (p != NULL))
9200 {
9201 m_NativePatchList.Delete(*p);
9202 }
9203
9204 return hr;
9205
9206#endif // FEATURE_INTEROP_DEBUGGING
9207}
9208
9209
9210//-----------------------------------------------------------------------------
9211// CordbProcess::ClearUnmanagedBreakpoint
9212// Called by a native debugger to remove breakpoints during Interop.
9213// The patch is deleted even if the function fails.
9214//-----------------------------------------------------------------------------
9215HRESULT
9216CordbProcess::ClearUnmanagedBreakpoint(CORDB_ADDRESS address)
9217{
9218 LOG((LF_CORDB, LL_INFO100, "CP::ClearUnBP: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address)));
9219#ifndef FEATURE_INTEROP_DEBUGGING
9220 return E_NOTIMPL;
9221#else
9222 PUBLIC_API_ENTRY(this);
9223 FAIL_IF_NEUTERED(this);
9224 FAIL_IF_MANAGED_ONLY(this);
9225
9226 _ASSERTE(!ThreadHoldsProcessLock());
9227
9228 HRESULT hr = S_OK;
9229 PRD_TYPE opcode;
9230
9231 Lock();
9232
9233 // Make sure this is a valid patch.
9234 int cTotal = m_NativePatchList.Count();
9235 NativePatch * pTable = m_NativePatchList.Table();
9236 if (pTable == NULL)
9237 {
9238 hr = CORDBG_E_NO_NATIVE_PATCH_AT_ADDR;
9239 goto ErrExit;
9240 }
9241
9242 int i;
9243 for(i = 0; i < cTotal; i++)
9244 {
9245 if (pTable[i].pAddress == CORDB_ADDRESS_TO_PTR(address))
9246 break;
9247 }
9248
9249 if (i >= cTotal)
9250 {
9251 hr = CORDBG_E_NO_NATIVE_PATCH_AT_ADDR;
9252 goto ErrExit;
9253 }
9254
9255 // Found it! Remove it from our table. Note that this may shuffle table contents
9256 // around, so don't keep pointers into the table.
9257 opcode = pTable[i].opcode;
9258
9259 m_NativePatchList.Delete(pTable[i]);
9260 _ASSERTE(m_NativePatchList.Count() == cTotal - 1);
9261
9262 // Now remove the patch.
9263
9264
9265
9266 // Just call through to Write ProcessMemory
9267 hr = RemoveRemotePatch(this, CORDB_ADDRESS_TO_PTR(address), opcode);
9268 if (FAILED(hr))
9269 goto ErrExit;
9270
9271
9272 // Our internal bookeaping was already updated to remove the patch, so now we're done.
9273 // If we had a failure, we should have already bailed.
9274 _ASSERTE(SUCCEEDED(hr));
9275
9276ErrExit:
9277 Unlock();
9278 return hr;
9279#endif // FEATURE_INTEROP_DEBUGGING
9280}
9281
9282
9283//------------------------------------------------------------------------------------
9284// StopCount, Sync, SyncReceived form our stop-status. This status is super-critical
9285// to most hangs, so we stress log it.
9286//------------------------------------------------------------------------------------
9287void CordbProcess::SetSynchronized(bool fSynch)
9288{
9289 _ASSERTE(ThreadHoldsProcessLock() || !"Must have process lock to toggle SyncStatus");
9290 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP:: set sync=%d\n", fSynch);
9291 m_synchronized = fSynch;
9292}
9293
9294bool CordbProcess::GetSynchronized()
9295{
9296 // This can be accessed whether we're Locked or not. This means that the result
9297 // may change underneath us.
9298 return m_synchronized;
9299}
9300
9301void CordbProcess::IncStopCount()
9302{
9303 _ASSERTE(ThreadHoldsProcessLock());
9304 m_stopCount++;
9305 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP:: Inc StopCount=%d\n", m_stopCount);
9306}
9307void CordbProcess::DecStopCount()
9308{
9309 // We can inc w/ just the process lock (b/c we can dispatch events from the W32ET)
9310 // But decrementing (eg, Continue), requires the stop-go lock.
9311 // This if an operation takes the SG lock, it ensures we don't continue from underneath it.
9312 ASSERT_SINGLE_THREAD_ONLY(HoldsLock(&m_StopGoLock));
9313 _ASSERTE(ThreadHoldsProcessLock());
9314
9315 m_stopCount--;
9316 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP:: Dec StopCount=%d\n", m_stopCount);
9317}
9318
9319// Just gets whether we're stopped or not (m_stopped > 0).
9320// You only need the StopGo lock for this.
9321bool CordbProcess::IsStopped()
9322{
9323 // We don't require the process-lock, just the SG-lock.
9324 // Holding the SG lock prevents another thread from continuing underneath you.
9325 // (see DecStopCount()).
9326 // But you could still be running free, and have another thread stop-underneath you.
9327 // Thus IsStopped() leans towards returning false.
9328 ASSERT_SINGLE_THREAD_ONLY(HoldsLock(&m_StopGoLock));
9329
9330 return (m_stopCount > 0);
9331}
9332
9333int CordbProcess::GetStopCount()
9334{
9335 _ASSERTE(ThreadHoldsProcessLock());
9336 return m_stopCount;
9337}
9338
9339bool CordbProcess::GetSyncCompleteRecv()
9340{
9341 _ASSERTE(ThreadHoldsProcessLock());
9342 return m_syncCompleteReceived;
9343}
9344
9345void CordbProcess::SetSyncCompleteRecv(bool fSyncRecv)
9346{
9347 _ASSERTE(ThreadHoldsProcessLock());
9348 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP:: set syncRecv=%d\n", fSyncRecv);
9349 m_syncCompleteReceived = fSyncRecv;
9350}
9351
9352// This can be used if we ever need the RS to emulate old behavior of previous versions.
9353// This can not be used in QIs to deny queries for new interfaces.
9354// QIs must be consistent across the lifetime of an object. Say CordbThread used this in a QI
9355// do deny returning a ICorDebugThread2 interface when emulating v1.1. Once that Thread is neutered,
9356// it no longer has a pointer to the process, and it no longer knows if it should be denying
9357// the v2.0 query. An object's QI can't start returning new interfaces onces its neutered.
9358bool CordbProcess::SupportsVersion(CorDebugInterfaceVersion featureVersion)
9359{
9360 _ASSERTE(featureVersion == CorDebugVersion_2_0);
9361 return true;
9362}
9363
9364
9365//---------------------------------------------------------------------------------------
9366// Add an object to the process's Left-Side resource cleanup list
9367//
9368// Arguments:
9369// pObject - non-null object to be added
9370//
9371// Notes:
9372// This list tracks objects with process-scope that hold left-side
9373// resources (like func-eval).
9374// See code:CordbAppDomain::GetSweepableExitNeuterList for per-appdomain
9375// objects with left-side resources.
9376void CordbProcess::AddToLeftSideResourceCleanupList(CordbBase * pObject)
9377{
9378 INTERNAL_API_ENTRY(this);
9379 _ASSERTE(pObject != NULL);
9380
9381 m_LeftSideResourceCleanupList.Add(this, pObject);
9382}
9383
9384// This list will get actively swept (looking for objects w/ external ref = 0) between continues.
9385void CordbProcess::AddToNeuterOnExitList(CordbBase *pObject)
9386{
9387 INTERNAL_API_ENTRY(this);
9388 _ASSERTE(pObject != NULL);
9389
9390 HRESULT hr = S_OK;
9391 EX_TRY
9392 {
9393 this->m_ExitNeuterList.Add(this, pObject);
9394 }
9395 EX_CATCH_HRESULT(hr);
9396 SetUnrecoverableIfFailed(GetProcess(), hr);
9397}
9398
9399// Mark that this object should be neutered the next time we Continue the process.
9400void CordbProcess::AddToNeuterOnContinueList(CordbBase *pObject)
9401{
9402 INTERNAL_API_ENTRY(this);
9403 _ASSERTE(pObject != NULL);
9404
9405 m_ContinueNeuterList.Add(this, pObject); // throws
9406}
9407
9408
9409/* ------------------------------------------------------------------------- *
9410 * Runtime Controller Event Thread class
9411 * ------------------------------------------------------------------------- */
9412
9413//
9414// Constructor
9415//
9416CordbRCEventThread::CordbRCEventThread(Cordb* cordb)
9417{
9418 _ASSERTE(cordb != NULL);
9419
9420 m_cordb.Assign(cordb);
9421 m_thread = NULL;
9422 m_threadId = 0;
9423 m_run = TRUE;
9424 m_threadControlEvent = NULL;
9425 m_processStateChanged = FALSE;
9426
9427 g_pRSDebuggingInfo->m_RCET = this;
9428}
9429
9430
9431//
9432// Destructor. Cleans up all of the open handles and such.
9433// This expects that the thread has been stopped and has terminated
9434// before being called.
9435//
9436CordbRCEventThread::~CordbRCEventThread()
9437{
9438 if (m_threadControlEvent != NULL)
9439 CloseHandle(m_threadControlEvent);
9440
9441 if (m_thread != NULL)
9442 CloseHandle(m_thread);
9443
9444 g_pRSDebuggingInfo->m_RCET = NULL;
9445}
9446
9447//
9448// Init sets up all the objects that the thread will need to run.
9449//
9450HRESULT CordbRCEventThread::Init()
9451{
9452 if (m_cordb == NULL)
9453 return E_INVALIDARG;
9454
9455 m_threadControlEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL);
9456
9457 if (m_threadControlEvent == NULL)
9458 return HRESULT_FROM_GetLastError();
9459
9460 return S_OK;
9461}
9462
9463
9464#if defined(FEATURE_INTEROP_DEBUGGING)
9465//
9466// Helper to duplicate a handle or thorw
9467//
9468// Arguments:
9469// pLocalHandle - handle to duplicate into the remote process
9470// pRemoteHandle - RemoteHandle structure in IPC block to hold the remote handle.
9471// Return value:
9472// None. Throws on error.
9473//
9474void CordbProcess::DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle)
9475{
9476 _ASSERTE(m_pShim != NULL);
9477
9478 // Dup RSEA and RSER into this process if we don't already have them.
9479 // On Launch, we don't have them yet, but on attach we do.
9480 if (*pLocalHandle == NULL)
9481 {
9482 BOOL fSuccess = pRemoteHandle->DuplicateToLocalProcess(m_handle, pLocalHandle);
9483 if (!fSuccess)
9484 {
9485 ThrowLastError();
9486 }
9487 }
9488
9489}
9490#endif // FEATURE_INTEROP_DEBUGGING
9491
9492// Public entry wrapper for code:CordbProcess::FinishInitializeIPCChannelWorker
9493void CordbProcess::FinishInitializeIPCChannel()
9494{
9495 // This is called directly from a shim callback.
9496 PUBLIC_API_ENTRY_FOR_SHIM(this);
9497 FinishInitializeIPCChannelWorker();
9498}
9499
9500//
9501// Initialize the IPC channel. After this, IPC events can flow in both ways.
9502//
9503// Return value:
9504// Returns S_OK on success.
9505//
9506// Notes:
9507// This will dispatch an UnrecoverableError callback if it fails.
9508// This will also initialize key state in the CordbProcess object.
9509//
9510// @dbgtodo remove helper-thread: this should eventually go away once we get rid of IPC events.
9511//
9512void CordbProcess::FinishInitializeIPCChannelWorker()
9513{
9514 CONTRACTL
9515 {
9516 THROWS;
9517 }
9518 CONTRACTL_END;
9519
9520 HRESULT hr = S_OK;
9521 _ASSERTE(m_pShim != NULL);
9522
9523 RSLockHolder lockHolder(&this->m_processMutex);
9524
9525 // If it's already initialized, then nothing left to do.
9526 // this protects us if this function is called multiple times.
9527 if (m_initialized)
9528 {
9529 _ASSERTE(GetDCB() != NULL);
9530 return;
9531 }
9532
9533 EX_TRY
9534 {
9535 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::HFRCE: first event..., process %p\n", GetCurrentThreadId(), this));
9536
9537 BOOL fBlockExists;
9538 GetEventBlock(&fBlockExists); // throws on error
9539
9540 LOG((LF_CORDB, LL_EVERYTHING, "Size of CdbP is %d\n", sizeof(CordbProcess)));
9541
9542 m_pEventChannel->Init(m_handle);
9543
9544#if defined(FEATURE_INTEROP_DEBUGGING)
9545 DuplicateHandleToLocalProcess(&m_leftSideUnmanagedWaitEvent, &GetDCB()->m_leftSideUnmanagedWaitEvent);
9546#endif // FEATURE_INTEROP_DEBUGGING
9547
9548 // Read the Runtime Offsets struct out of the debuggee.
9549 hr = GetRuntimeOffsets();
9550 IfFailThrow(hr);
9551
9552 // we need to be careful here. The LS will have a thread running free that may be initializing
9553 // fields of the DCB (specifically it may be setting up the helper thread), so we need to make sure
9554 // we don't overwrite any fields that the LS is writing. We need to be sure we only write to RS
9555 // status fields.
9556 m_initialized = true;
9557 GetDCB()->m_rightSideIsWin32Debugger = IsInteropDebugging();
9558 UpdateLeftSideDCBField(&(GetDCB()->m_rightSideIsWin32Debugger), sizeof(GetDCB()->m_rightSideIsWin32Debugger));
9559
9560 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::HFRCE: ...went fine\n", GetCurrentThreadId()));
9561 _ASSERTE(SUCCEEDED(hr));
9562
9563 } EX_CATCH_HRESULT(hr);
9564 if (SUCCEEDED(hr))
9565 {
9566 return;
9567 }
9568
9569 // We only land here on failure cases.
9570 // We must have jumped to this label. Maybe we didn't set HR, so check now.
9571 STRESS_LOG1(LF_CORDB, LL_INFO1000, "HFCR: FAILED hr=0x%08x\n", hr);
9572
9573 CloseIPCHandles();
9574
9575 // Rethrow
9576 ThrowHR(hr);
9577}
9578
9579
9580//---------------------------------------------------------------------------------------
9581// Marshals over a string buffer in a managed event
9582//
9583// Arguments:
9584// pTarget - data-target for read the buffer from the LeftSide.
9585//
9586// Throws on error
9587void Ls_Rs_BaseBuffer::CopyLSDataToRSWorker(ICorDebugDataTarget * pTarget)
9588{
9589 //
9590 const DWORD cbCacheSize = m_cbSize;
9591
9592 // SHOULD not happen for more than once in well-behaved case.
9593 if (m_pbRS != NULL)
9594 {
9595 SIMPLIFYING_ASSUMPTION(!"m_pbRS is non-null; is this a corrupted event?");
9596 ThrowHR(E_INVALIDARG);
9597 }
9598
9599 NewHolder<BYTE> pData(new BYTE[cbCacheSize]);
9600
9601 ULONG32 cbRead;
9602 HRESULT hrRead = pTarget->ReadVirtual(PTR_TO_CORDB_ADDRESS(m_pbLS), pData, cbCacheSize , &cbRead);
9603
9604 if(FAILED(hrRead))
9605 {
9606 hrRead = CORDBG_E_READVIRTUAL_FAILURE;
9607 }
9608
9609 if (SUCCEEDED(hrRead) && (cbCacheSize != cbRead))
9610 {
9611 hrRead = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
9612 }
9613 IfFailThrow(hrRead);
9614
9615 // Now do Transfer
9616 m_pbRS = pData;
9617 pData.SuppressRelease();
9618}
9619
9620//---------------------------------------------------------------------------------------
9621// Marshals over a Byte buffer in a managed event
9622//
9623// Arguments:
9624// pTarget - data-target for read the buffer from the LeftSide.
9625//
9626// Throws on error
9627void Ls_Rs_ByteBuffer::CopyLSDataToRS(ICorDebugDataTarget * pTarget)
9628{
9629 CopyLSDataToRSWorker(pTarget);
9630}
9631
9632//---------------------------------------------------------------------------------------
9633// Marshals over a string buffer in a managed event
9634//
9635// Arguments:
9636// pTarget - data-target for read the buffer from the LeftSide.
9637//
9638// Throws on error
9639void Ls_Rs_StringBuffer::CopyLSDataToRS(ICorDebugDataTarget * pTarget)
9640{
9641 CopyLSDataToRSWorker(pTarget);
9642
9643 // Ensure we're a valid, well-formed string.
9644 // @dbgtodo - this should only happen in corrupted scenarios. Perhaps a better HR here?
9645 // - null terminated.
9646 // - no embedded nulls.
9647
9648 const WCHAR * pString = GetString();
9649 SIZE_T dwExpectedLenWithNull = m_cbSize / sizeof(WCHAR);
9650
9651 // Should at least have 1 character for the null-terminator.
9652 if (dwExpectedLenWithNull == 0)
9653 {
9654 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
9655 }
9656
9657 // Ensure that there's a null where we expect it to be.
9658 if (pString[dwExpectedLenWithNull-1] != 0)
9659 {
9660 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
9661 }
9662
9663 // Now we know it's safe to call wcslen. The buffer is local, so we know the pages are there.
9664 // And we know there's a null capping the max length of the string.
9665 SIZE_T dwActualLenWithNull = wcslen(pString) + 1;
9666 if (dwActualLenWithNull != dwExpectedLenWithNull)
9667 {
9668 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
9669 }
9670}
9671
9672//---------------------------------------------------------------------------------------
9673// Marshals the arguments in a managed-debug event.
9674//
9675// Arguments:
9676// pManagedEvent - (IN/OUT) debug event to marshal. Events are not usable in the host process
9677// until they are marshalled. This will marshal the event in-place, and may convert
9678// some target addresses to host addresses.
9679//
9680// Return Value:
9681// S_OK on success. Else Error.
9682//
9683// Assumptions:
9684// Target is currently stopped and inspectable.
9685// After the event is marshalled, it has resources that must be cleaned up
9686// by calling code:DeleteIPCEventHelper.
9687//
9688// Notes:
9689// Call a Copy function (CopyManagedEventFromTarget, CopyRCEventFromIPCBlock)to
9690// get the event to marshal.
9691// This will marshal args from the target into the host.
9692// The debug event is fixed size. But since the debuggee is stopped, this can copy
9693// arbitrary-length buffers out of of the debuggee.
9694//
9695// This could be rolled into code:CordbProcess::RawDispatchEvent
9696//---------------------------------------------------------------------------------------
9697void CordbProcess::MarshalManagedEvent(DebuggerIPCEvent * pManagedEvent)
9698{
9699 CONTRACTL
9700 {
9701 THROWS;
9702
9703 // Event has already been copied, now we do some quick Marshalling.
9704 // Thsi should be a private local copy, and not the one in the IPC block or Target.
9705 PRECONDITION(CheckPointer(pManagedEvent));
9706 }
9707 CONTRACTL_END;
9708
9709 IfFailThrow(pManagedEvent->hr);
9710
9711 // This may throw part way through marshalling. But that's ok because
9712 // code:DeleteIPCEventHelper can cleanup a partially-marshalled event.
9713
9714 // Do a pre-processing on the event
9715 switch (pManagedEvent->type & DB_IPCE_TYPE_MASK)
9716 {
9717 case DB_IPCE_MDA_NOTIFICATION:
9718 {
9719 pManagedEvent->MDANotification.szName.CopyLSDataToRS(this->m_pDACDataTarget);
9720 pManagedEvent->MDANotification.szDescription.CopyLSDataToRS(this->m_pDACDataTarget);
9721 pManagedEvent->MDANotification.szXml.CopyLSDataToRS(this->m_pDACDataTarget);
9722 break;
9723 }
9724
9725 case DB_IPCE_FIRST_LOG_MESSAGE:
9726 {
9727 pManagedEvent->FirstLogMessage.szContent.CopyLSDataToRS(this->m_pDACDataTarget);
9728 break;
9729 }
9730
9731 default:
9732 break;
9733 }
9734
9735
9736}
9737
9738
9739//---------------------------------------------------------------------------------------
9740// Copy a managed debug event from the target process into this local process
9741//
9742// Arguments:
9743// pRecord - native-debug event serving as the envelope for the managed event.
9744// pLocalManagedEvent - (dst) required local buffer to hold managed event.
9745//
9746// Return Value:
9747// * True if the event belongs to this runtime. This is very useful when multiple CLRs are
9748// loaded into the target and all sending events wit the same exception code.
9749// * False if this does not belong to this instance of ICorDebug. (perhaps it's an event
9750// intended for another instance of the CLR in the target, or some rogue user code happening
9751// to use our exception code).
9752// In either case, the event can still be cleaned up via code:DeleteIPCEventHelper.
9753//
9754// Throws on error. In the error case, the contents of pLocalManagedEvent are undefined.
9755// They may have been partially copied from the target. The local managed event does not own
9756// any resources until it's marshalled, so the buffer can be ignored if this function fails.
9757//
9758// Assumptions:
9759//
9760// Notes:
9761// The events are sent form the target via code:Debugger::SendRawEvent
9762// This just does a raw Byte copy, but does not do any Marshalling.
9763// This should always succeed in the well-behaved case. However, A bad debuggee can
9764// always send a poor-formed debug event.
9765// We don't distinguish between a badly formed event and an event that's not ours.
9766// The event still needs to be Marshaled before being used. (see code:CordbProcess::MarshalManagedEvent)
9767//
9768//---------------------------------------------------------------------------------------
9769#if defined(_MSC_VER) && defined(_TARGET_ARM_)
9770// This is a temporary workaround for an ARM specific MS C++ compiler bug (internal LKG build 18.1).
9771// Branch < if (ptrRemoteManagedEvent == NULL) > was always taken and the function always returned false.
9772// TODO: It should be removed once the bug is fixed.
9773#pragma optimize("", off)
9774#endif
9775bool CordbProcess::CopyManagedEventFromTarget(
9776 const EXCEPTION_RECORD * pRecord,
9777 DebuggerIPCEvent * pLocalManagedEvent)
9778{
9779 _ASSERTE(pRecord != NULL);
9780 _ASSERTE(pLocalManagedEvent != NULL);
9781
9782 // Initialize the event enough such backout code can call code:DeleteIPCEventHelper.
9783 pLocalManagedEvent->type = DB_IPCE_DEBUGGER_INVALID;
9784
9785 // Ensure we have a CLR instance ID by now. Either we had one already, or we're in
9786 // V2 mode and this is the startup event, and so we'll set it now.
9787 HRESULT hr = EnsureClrInstanceIdSet();
9788 IfFailThrow(hr);
9789 _ASSERTE(m_clrInstanceId != 0);
9790
9791 // Determine if the event is really a debug event, and for our instance.
9792 CORDB_ADDRESS ptrRemoteManagedEvent = IsEventDebuggerNotification(pRecord, m_clrInstanceId);
9793
9794 if (ptrRemoteManagedEvent == NULL)
9795 {
9796 return false;
9797 }
9798
9799 // What we are doing on Windows here is dangerous. Any buffer for IPC events must be at least
9800 // CorDBIPC_BUFFER_SIZE big, but here we are only copying sizeof(DebuggerIPCEvent). Fortunately, the
9801 // only case where an IPC event is bigger than sizeof(DebuggerIPCEvent) is for the second category
9802 // described in the comment for code:IEventChannel. In this case, we are just transferring the IPC
9803 // event from the native pipeline to the event channel, and the event channel will read it directly from
9804 // the send buffer on the LS. See code:CordbRCEventThread::WaitForIPCEventFromProcess.
9805#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
9806 hr = SafeReadStruct(ptrRemoteManagedEvent, pLocalManagedEvent);
9807#else
9808 // For Mac remote debugging the address returned above is actually a local address.
9809 // Also, we need to copy the entire buffer because once a debug event is read from the debugger
9810 // transport, it won't be available afterwards.
9811 memcpy(reinterpret_cast<BYTE *>(pLocalManagedEvent),
9812 CORDB_ADDRESS_TO_PTR(ptrRemoteManagedEvent),
9813 CorDBIPC_BUFFER_SIZE);
9814 hr = S_OK;
9815#endif
9816 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
9817 IfFailThrow(hr);
9818
9819 return true;
9820}
9821#if defined(_MSC_VER) && defined(_TARGET_ARM_)
9822#pragma optimize("", on)
9823#endif
9824
9825//---------------------------------------------------------------------------------------
9826// EnsureClrInstanceIdSet - Ensure we have a CLR Instance ID to debug
9827//
9828// In Arrowhead scenarios, the debugger is required to pass a valid CLR instance ID
9829// to us in OpenVirtualProcess. In V2 scenarios, for compatibility, we'll allow a
9830// CordbProcess object to exist for a process that doesn't yet have the CLR loaded.
9831// In this case the CLR instance ID will start off as 0, but be filled in when we see the
9832// startup exception indicating the CLR has been loaded.
9833//
9834// If we don't already have an instance ID, this function sets it to the only CLR in the
9835// target process. This requires that a CLR be loaded in the target process.
9836//
9837// Return Value:
9838// S_OK - if m_clrInstanceId was already set, or is now set to a valid CLR instance ID
9839// an error HRESULT - if m_clrInstanceId was 0, and cannot be set to a valid value
9840// (i.e. because we cannot find a CLR in the target process).
9841//
9842// Note that we need to probe for this on attach, and it's common to attach before the
9843// CLR has been loaded, so we avoid using exceptions for this common case.
9844//
9845HRESULT CordbProcess::EnsureClrInstanceIdSet()
9846{
9847 // If we didn't expect a specific CLR, then attempt to attach to any.
9848 if (m_clrInstanceId == 0)
9849 {
9850
9851#ifdef FEATURE_CORESYSTEM
9852 if(m_cordb->GetTargetCLR() != 0)
9853 {
9854 m_clrInstanceId = PTR_TO_CORDB_ADDRESS(m_cordb->GetTargetCLR());
9855 return S_OK;
9856 }
9857#endif
9858
9859 // The only case in which we're allowed to request the "default" CLR instance
9860 // ID is when we're running in V2 mode. In V3, the client is required to pass
9861 // a non-zero value to OpenVirtualProcess.
9862 _ASSERTE(m_pShim != NULL);
9863
9864 HRESULT hr = m_pShim->FindLoadedCLR(&m_clrInstanceId);
9865 if (FAILED(hr))
9866 {
9867 // Couldn't find a loaded clr - no CLR instance ID yet
9868 _ASSERTE(m_clrInstanceId == 0);
9869 return hr;
9870 }
9871 }
9872
9873 // We've (now) got a valid CLR instance id
9874 return S_OK;
9875}
9876
9877//---------------------------------------------------------------------------------------
9878// // Copy event from IPC block into local.
9879//
9880// Arguments:
9881// pLocalManagedEvent - required local buffer to hold managed event.
9882//
9883// Return Value:
9884// None. Always succeeds.
9885//
9886// Assumptions:
9887// The IPC block has already been opened and filled in with an event.
9888//
9889// Notes:
9890// This is copying from a shared-memory block, which is treated as local memory.
9891// This just does a raw Byte copy, but does not do any Marshalling.
9892// This does no validation on the event.
9893// The event still needs to be Marshaled before being used. (see code:CordbProcess::MarshalManagedEvent)
9894//
9895//---------------------------------------------------------------------------------------
9896void inline CordbProcess::CopyRCEventFromIPCBlock(DebuggerIPCEvent * pLocalManagedEvent)
9897{
9898 _ASSERTE(pLocalManagedEvent != NULL);
9899
9900 IfFailThrow(m_pEventChannel->GetEventFromLeftSide(pLocalManagedEvent));
9901}
9902
9903// Return true if this is the RCEvent thread, else false.
9904bool CordbRCEventThread::IsRCEventThread()
9905{
9906 return (m_threadId == GetCurrentThreadId());
9907}
9908
9909//---------------------------------------------------------------------------------------
9910// Runtime assert, throws CORDBG_E_TARGET_INCONSISTENT if the expression is not true.
9911//
9912// Arguments:
9913// fExpression - assert parameter. If true, this function is a nop. If false,
9914// this will throw a CORDBG_E_TARGET_INCONSISTENT error.
9915//
9916// Notes:
9917// Use this for runtime checks to validate assumptions about the data-target.
9918// IcorDebug can't trust that data from the debugee is consistent (perhaps it's
9919// corrupted).
9920void CordbProcess::TargetConsistencyCheck(bool fExpression)
9921{
9922 if (!fExpression)
9923 {
9924 STRESS_LOG0(LF_CORDB, LL_INFO10000, "Target consistency check failed");
9925
9926 // When debugging possibly corrupt targets, this failure may be expected. For debugging purposes,
9927 // assert if we're not expecting any target inconsistencies.
9928 CONSISTENCY_CHECK_MSG( !m_fAssertOnTargetInconsistency, "Target consistency check failed unexpectedly");
9929
9930 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
9931 }
9932}
9933
9934//
9935// SendIPCEvent -- send an IPC event to the runtime controller. All this
9936// really does is copy the event into the process's send buffer and sets
9937// the RSEA then waits on RSER.
9938//
9939// Note: when sending a two-way event (replyRequired = true), the
9940// eventSize must be large enough for both the event sent and the
9941// result event.
9942//
9943// Returns whether the event was sent successfully. This is different than event->eventHr.
9944//
9945HRESULT CordbRCEventThread::SendIPCEvent(CordbProcess* process,
9946 DebuggerIPCEvent* event,
9947 SIZE_T eventSize)
9948{
9949
9950 _ASSERTE(process != NULL);
9951 _ASSERTE(event != NULL);
9952 _ASSERTE(process->GetShim() != NULL);
9953
9954#ifdef _DEBUG
9955 // We need to be synchronized whenever we're sending an IPC Event.
9956 // This may require our callers' using a Stop-Continue holder.
9957 // Attach + AsyncBreak are the only (obvious) exceptions.
9958 // For continue, we set Sync-Status to false before sending, so we exclude that too.
9959 // Everybody else should only be sending events when synced. We should never ever ever
9960 // send an event from a CorbXYZ dtor (b/c that would be called at any random time). Instead,
9961 // use a NeuterList.
9962 switch (event->type)
9963 {
9964 case DB_IPCE_ATTACHING:
9965 case DB_IPCE_ASYNC_BREAK:
9966 case DB_IPCE_CONTINUE:
9967 break;
9968
9969 default:
9970 CONSISTENCY_CHECK_MSGF(process->GetSynchronized(), ("Must by synced while sending IPC event: %s (0x%x)",
9971 IPCENames::GetName(event->type), event->type));
9972 }
9973#endif
9974
9975
9976 LOG((LF_CORDB, LL_EVERYTHING, "SendIPCEvent in CordbRCEventThread called\n"));
9977
9978 // For simplicity sake, we have the following conservative invariants when sending IPC events:
9979 // - Always hold the Stop-Go lock.
9980 // - never on the W32ET.
9981 // - Never hold the Process-lock (this allows the w32et to take that lock to pump)
9982
9983 // Must have the stop-go lock to send an IPC event.
9984 CONSISTENCY_CHECK_MSGF(process->GetStopGoLock()->HasLock(), ("Must have stop-go lock to send event. proc=%p, event=%s",
9985 process, IPCENames::GetName(event->type)));
9986
9987 // The w32 ET will need to take the process lock. So if we're holding it here, then we'll
9988 // deadlock (since W32 ET is blocked on lock, which we would hold; and we're blocked on W32 ET
9989 // to keep pumping.
9990 _ASSERTE(!process->ThreadHoldsProcessLock() || !"Can't hold P-lock while sending blocking IPC event");
9991
9992
9993 // Can't be on the w32 ET, or we can't be pumping.
9994 // Although we can trickle in here from public APIs, our caller should have validated
9995 // that we weren't on the w32et, so the assert here is justified. But just in case there's something we missed,
9996 // we have a runtime check (as a final backstop against a deadlock).
9997 _ASSERTE(!process->IsWin32EventThread());
9998 CORDBFailIfOnWin32EventThread(process);
9999
10000
10001 // If this is an async event, then we expect it to be sent while the process is locked.
10002 if (event->asyncSend)
10003 {
10004 // This may be on the w32et, so we can't hold the stop-go lock.
10005 _ASSERTE(event->type == DB_IPCE_ATTACHING); // only async event should be attaching.
10006 }
10007
10008
10009 // This will catch us if we've detached or exited.
10010 // Note if we exited, then we should have been neutered and so shouldn't even be sending an IPC event,
10011 // but just in case, we'll check.
10012 CORDBRequireProcessStateOK(process);
10013
10014
10015#ifdef _DEBUG
10016 // We should never send an Async Break on the RCET. This will deadlock.
10017 // - if we're on the RCET, we should be stopped, and thus Stop() should just bump up a stop count,
10018 // and not actually send an AsyncBreak.
10019 // - Delayed-Continues help enforce this.
10020 // This is a special case of the deadlock check below.
10021 if (IsRCEventThread())
10022 {
10023 _ASSERTE(event->type != DB_IPCE_ASYNC_BREAK);
10024 }
10025#endif
10026
10027#ifdef _DEBUG
10028 // This assert protects us against a deadlock.
10029 // 1) (RCET) blocked on (This function): If we're on the RCET, then the RCET is blocked until we return (duh).
10030 // 2) (LS) blocked on (RCET): If the LS is not synchronized, then it may be sending an event to the RCET, and thus blocked on the RCET.
10031 // 3) (Helper thread) blocked on (LS): That LS thread may be holding a lock that the helper thread needs, thus blocking the helper thread.
10032 // 4) (This function) blocked on (Helper Thread): We block until the helper thread can process our IPC event.
10033 // #4 is not true for async events.
10034 //
10035 // If we hit this assert, it means we may get the deadlock above and we're calling SendIPCEvent at a time we shouldn't.
10036 // Note this race is as old as dirt.
10037 if (IsRCEventThread() && !event->asyncSend)
10038 {
10039 // Note that w/ Continue & Attach, GetSynchronized() has a different meaning and the race above won't happen.
10040 BOOL fPossibleDeadlock = process->GetSynchronized() || (event->type == DB_IPCE_CONTINUE) || (event->type == DB_IPCE_ATTACHING);
10041 CONSISTENCY_CHECK_MSGF(fPossibleDeadlock, ("Possible deadlock while sending: '%s'\n", IPCENames::GetName(event->type)));
10042 }
10043#endif
10044
10045
10046
10047 // Cache this process into the MRU so that we can find it if we're debugging in retail.
10048 g_pRSDebuggingInfo->m_MRUprocess = process;
10049
10050 HRESULT hr = S_OK;
10051 HRESULT hrEvent = S_OK;
10052 _ASSERTE(event != NULL);
10053
10054 // NOTE: the eventSize parameter is only so you can specify an event size that is SMALLER than the process send
10055 // buffer size!!
10056 if (eventSize > CorDBIPC_BUFFER_SIZE)
10057 return E_INVALIDARG;
10058
10059 STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: sending %s to AD 0x%x, proc 0x%x(%d)\n",
10060 IPCENames::GetName(event->type), VmPtrToCookie(event->vmAppDomain), process->m_id, process->m_id);
10061
10062 // For 2-way events, this check is unnecessary (since we already check for LS exit)
10063 // But for async events, we need this.
10064 // So just check it up here and make everyone's life easier.
10065 if (process->m_terminated)
10066 {
10067 STRESS_LOG0(LF_CORDB, LL_INFO10000, "CRCET::SIPCE: LS already terminated, shortcut exiting\n");
10068 return CORDBG_E_PROCESS_TERMINATED;
10069 }
10070
10071 // If the helper thread has died, we can't send an IPC event (and it's never coming back either).
10072 // Although we do wait on the thread's handle, there are strange windows where the thread's handle
10073 // is not yet signaled even though we've continued from the exit-thread event for the helper.
10074 if (process->m_helperThreadDead)
10075 {
10076 STRESS_LOG0(LF_CORDB, LL_INFO10000, "CRCET::SIPCE: Helper-thread dead, shortcut exiting\n");
10077 return CORDBG_E_PROCESS_TERMINATED;
10078 }
10079
10080 BOOL fUnrecoverableError = TRUE;
10081 EX_TRY
10082 {
10083 hr = process->GetEventChannel()->SendEventToLeftSide(event, eventSize);
10084 fUnrecoverableError = FALSE;
10085 }
10086 EX_CATCH_HRESULT(hr);
10087
10088
10089 // If we're sending a Continue() event, then after this, the LS may run free.
10090 // If this is the last managed event before the LS exits, (which is the case
10091 // if we're responding to either an Exit-Thread or if we respond to a Detach)
10092 // the LS may exit at anytime from here on, so we need to be careful.
10093
10094
10095 if (fUnrecoverableError)
10096 {
10097 _ASSERTE(FAILED(hr));
10098 CORDBSetUnrecoverableError(process, hr, 0);
10099 }
10100 else
10101 {
10102 // Get a handle to the target process - this call always succeeds
10103 HANDLE hLSProcess = NULL;
10104 process->GetHandle(&hLSProcess);
10105
10106 // We take locks to ensure that the CordbProcess object is still alive,
10107 // even if the OS process exited.
10108 _ASSERTE(hLSProcess != NULL);
10109
10110 // Check if Sending the IPC event failed
10111 if (FAILED(hr))
10112 {
10113 // The failure to send an event may be due to the target process terminating
10114 // (especially, but not exclusively, in the case of async events).
10115 // There is a race here - we can't rely on any check above SendEventToLeftSide
10116 // to tell us whether the process has exited yet.
10117 // Check for that case and return an accurate hresult.
10118 DWORD ret = WaitForSingleObject(hLSProcess, 0);
10119 if (ret == WAIT_OBJECT_0)
10120 {
10121 return CORDBG_E_PROCESS_TERMINATED;
10122 }
10123
10124 // Some other failure sending the IPC event - just return it.
10125 return hr;
10126 }
10127
10128 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: sent...\n");
10129
10130 // If this is an async send, then don't wait for the left side to acknowledge that its read the event.
10131 _ASSERTE(!event->asyncSend || !event->replyRequired);
10132
10133 if (process->GetEventChannel()->NeedToWaitForAck(event))
10134 {
10135 STRESS_LOG0(LF_CORDB, LL_INFO1000,"CRCET::SIPCE: waiting for left side to read event. (on RSER)\n");
10136
10137 DWORD ret;
10138
10139 // Wait for either a reply (common case) or the left side to go away.
10140 // We can't detach while waiting for a reply (because detach needs to send events).
10141 // All of the outcomes from this wait are completely disjoint.
10142 // It's possible for the LS to reply and then exit normally (Thread_Detach, Process_Detach)
10143 // and so ExitProcess may have been called, but it doesn't matter.
10144
10145 enum {
10146 ID_RSER = WAIT_OBJECT_0,
10147 ID_LSPROCESS,
10148 ID_HELPERTHREAD,
10149 };
10150
10151 // Only wait on the helper thread for cases where the process is stopped (and thus we don't expect it do exit on us).
10152 // If the process is running and we lose our helper thread, it ought to be during shutdown and we ough to
10153 // follow up with an exit.
10154 // This includes when we've dispatch Native events, and it includes the AsyncBreak sent to get us from a
10155 // win32 frozen state to a synchronized state).
10156 HANDLE hHelperThread = NULL;
10157 if (process->IsStopped())
10158 {
10159 hHelperThread = process->GetHelperThreadHandle();
10160 }
10161
10162
10163 // Note that in case of a tie (multiple handles signaled), WaitForMultipleObjects gives
10164 // priority to the handle earlier in the array.
10165 HANDLE waitSet[] = { process->GetEventChannel()->GetRightSideEventAckHandle(), hLSProcess, hHelperThread};
10166 DWORD cWaitSet = NumItems(waitSet);
10167 if (hHelperThread == NULL)
10168 {
10169 cWaitSet--;
10170 }
10171
10172 do
10173 {
10174 ret = WaitForMultipleObjectsEx(cWaitSet, waitSet, FALSE, CordbGetWaitTimeout(), FALSE);
10175 // If we timeout because we're waiting for an uncontinued OOB event, we need to just keep waiting.
10176 } while ((ret == WAIT_TIMEOUT) && process->IsWaitingForOOBEvent());
10177
10178 switch(ret)
10179 {
10180 case ID_RSER:
10181 // Normal reply from LS.
10182 // This is set iff the LS replied to our event. The LS may have exited since it replied
10183 // but we don't care. We still have the reply and we'll pass it on.
10184 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: left side read the event.\n");
10185
10186 // If this was a two-way event, then the result is already ready for us. Simply copy the result back
10187 // over the original event that was sent. Otherwise, the left side has simply read the event and is
10188 // processing it...
10189 if (event->replyRequired)
10190 {
10191 process->GetEventChannel()->GetReplyFromLeftSide(event, eventSize);
10192 hrEvent = event->hr;
10193 }
10194 break;
10195
10196 case ID_LSPROCESS:
10197 // Left side exited on us.
10198 // ExitProcess may or may not have been called here (since it's on a different thread).
10199 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: left side exiting while RS was waiting for reply.\n");
10200 hr = CORDBG_E_PROCESS_TERMINATED;
10201 break;
10202
10203 case ID_HELPERTHREAD:
10204 // We can only send most IPC events while the LS is synchronized. We shouldn't lose our helper thread
10205 // when synced under any sort of normal conditions.
10206 // This won't fire if the process already exited, because LSPROCESS gets higher priority in the wait
10207 // (since it was placed earlier).
10208 // Thus the only "legitimate" window where this could happen would be in a shutdown scenario after
10209 // the helper is dead but before the process has died. We shouldn't be synced in that scenario,
10210 // so we shouldn't be sending IPC events during it.
10211 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: lost helper thread.\n");
10212
10213
10214 // Assert because we want to know if we ever actually hit this in any detectable scenario.
10215 // However, shutdown can occur in preemptive mode. Thus if the RS does an AsyncBreak late
10216 // enough, then the LS will appear to be stopped but may still shutdown.
10217 // Since the debuggee can exit asynchronously at any time (eg, suppose somebody forcefully
10218 // kills it with taskman), this doesn't introduce a new case.
10219 // That aside, it would be great to be able to assert this:
10220 //_ASSERTE(!"Potential deadlock - Randomly Lost helper thread");
10221
10222 // We'll piggy back this on the terminated case.
10223 hr = CORDBG_E_PROCESS_TERMINATED;
10224 break;
10225
10226 default:
10227 {
10228 // If we timed out/failed, check the left side to see if it is in the unrecoverable error mode. If it is,
10229 // return the HR from the left side that caused the error. Otherwise, return that we timed out and that
10230 // we don't really know why.
10231 HRESULT realHR = (ret == WAIT_FAILED) ? HRESULT_FROM_GetLastError() : ErrWrapper(CORDBG_E_TIMEOUT);
10232
10233 hr = process->CheckForUnrecoverableError();
10234
10235 if (hr == S_OK)
10236 {
10237 CORDBSetUnrecoverableError(process, realHR, 0);
10238 hr = realHR;
10239 }
10240
10241 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: left side timeout/fail while RS waiting for reply. hr = 0x%08x\n", hr);
10242 }
10243 break;
10244 }
10245
10246 // If the LS picked up RSEA, it will be reset (since it's an auto event).
10247 // But in the case that the wait failed or that the LS exited, we need to explicitly reset RSEA
10248 if (hr != S_OK)
10249 {
10250 process->GetEventChannel()->ClearEventForLeftSide();
10251 }
10252
10253 // Done waiting for reply.
10254
10255 }
10256 }
10257
10258 process->ForceDacFlush();
10259
10260 // The hr and hrEvent are 2 very different things.
10261 // hr tells us whether the event was sent successfully.
10262 // hrEvent tells us how the LS responded to it.
10263 // if FAILED(hr), then hrEvent is useless b/c the LS never got it.
10264 // But if SUCCEEDED(hr), then hrEvent may still have failed and that could be
10265 // valuable information.
10266
10267 return hr;
10268}
10269
10270//---------------------------------------------------------------------------------------
10271// FlushQueuedEvents flushes a process's event queue.
10272//
10273// Arguments:
10274// pProcess - non-null process object whose queue will be drained
10275//
10276// Notes:
10277// @dbgtodo shim: this should be part of the shim.
10278// This dispatches events that are queued up. The queue is populated by
10279// the shim's proxy callback (see code:ShimProxyCallback). This will dispatch events
10280// to the 'real' callback supplied by the debugger. This will dispatch events
10281// as long as the debugger keeps calling continue.
10282//
10283// This requires that the process lock be held, although it will toggle the lock.
10284void CordbRCEventThread::FlushQueuedEvents(CordbProcess* process)
10285{
10286 CONTRACTL
10287 {
10288 NOTHROW; // This is happening on the RCET thread, so there's no place to propogate an error back up.
10289 }
10290 CONTRACTL_END;
10291
10292 STRESS_LOG0(LF_CORDB,LL_INFO10000, "CRCET::FQE: Beginning to flush queue\n");
10293
10294 _ASSERTE(process->GetShim() != NULL);
10295
10296 // We should only call this is we already have queued events
10297 _ASSERTE(!process->GetShim()->GetManagedEventQueue()->IsEmpty());
10298
10299 //
10300 // Dispatch queued events so long as they keep calling Continue()
10301 // before returning from their callback. If they call Continue(),
10302 // process->m_synchronized will be false again and we know to
10303 // loop around and dispatch the next event.
10304 //
10305 _ASSERTE(process->ThreadHoldsProcessLock());
10306
10307
10308 // Give shim a chance to queue any faked attach events. Grab a pointer to the
10309 // ShimProcess now, while we still hold the process lock. Once we release the lock,
10310 // GetShim() may not work.
10311 RSExtSmartPtr<ShimProcess> pShim(process->GetShim());
10312
10313 // Release lock before we call out to shim to Queue fake events.
10314 {
10315 RSInverseLockHolder inverseLockHolder(process->GetProcessLock());
10316 {
10317 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(pProcess);
10318
10319 // Because we've released the lock, at any point from here forward the
10320 // CorDbProcess may suddenly get neutered if the user detaches the debugger.
10321
10322 pShim->QueueFakeAttachEventsIfNeeded(false);
10323 }
10324 }
10325
10326 // Now that we're holding the process lock again, we can safely check whether
10327 // process has become neutered
10328 if (process->IsNeutered())
10329 {
10330 return;
10331 }
10332
10333 {
10334
10335 // Main dispatch loop here. DispatchRCEvent will take events out of the
10336 // queue and invoke callbacks
10337 do
10338 {
10339 // DispatchRCEvent will mark the process as stopped before dispatching.
10340 process->DispatchRCEvent();
10341
10342 LOG((LF_CORDB,LL_INFO10000, "CRCET::FQE: Finished w/ "
10343 "DispatchRCEvent\n"));
10344 }
10345 while (process->GetSyncCompleteRecv() &&
10346 (process->GetSynchronized() == false) &&
10347 (process->GetShim() != NULL) && // may have lost Shim if we detached while dispatch
10348 (!process->GetShim()->GetManagedEventQueue()->IsEmpty()) &&
10349 (process->m_unrecoverableError == false));
10350 }
10351
10352 //
10353 // If they returned from a callback without calling Continue() then
10354 // the process is still synchronized, so let the rc event thread
10355 // know that it need to update its process list and remove the
10356 // process's event.
10357 //
10358 if (process->GetSynchronized())
10359 {
10360 ProcessStateChanged();
10361 }
10362
10363 LOG((LF_CORDB,LL_INFO10000, "CRCET::FQE: finished\n"));
10364}
10365
10366//---------------------------------------------------------------------------------------
10367// Preliminary Handle an Notification event from the target. This may queue the event,
10368// but does not actually dispatch the event.
10369//
10370// Arguments:
10371// pManagedEvent - local managed-event. On success, this function assumes ownership of the
10372// event and will delete its memory. Assumed that caller allocated via 'new'.
10373// pCallback - callback obecjt to dispatch events on.
10374//
10375// Return Value:
10376// None. Throws on error. On error, caller still owns the pManagedEvent and must free it.
10377//
10378// Assumptions:
10379// This should be called once a notification event is received from the target.
10380//
10381// Notes:
10382// HandleRCEvent -- handle an IPC event received from the runtime controller.
10383// This will update ICorDebug state and immediately dispatch the event.
10384//
10385//---------------------------------------------------------------------------------------
10386void CordbProcess::HandleRCEvent(
10387 DebuggerIPCEvent * pManagedEvent,
10388 RSLockHolder * pLockHolder,
10389 ICorDebugManagedCallback * pCallback)
10390{
10391 CONTRACTL
10392 {
10393 THROWS;
10394 PRECONDITION(CheckPointer(pManagedEvent));
10395 PRECONDITION(CheckPointer(pCallback));
10396 PRECONDITION(ThreadHoldsProcessLock());
10397 }
10398 CONTRACTL_END;
10399
10400 if (!this->IsSafeToSendEvents() || this->m_exiting)
10401 {
10402 return;
10403 }
10404
10405 // Marshals over some standard data from event.
10406 MarshalManagedEvent(pManagedEvent);
10407
10408 STRESS_LOG4(LF_CORDB, LL_INFO1000, "RCET::TP: Got %s for AD 0x%x, proc 0x%x(%d)\n",
10409 IPCENames::GetName(pManagedEvent->type), VmPtrToCookie(pManagedEvent->vmAppDomain), this->m_id, this->m_id);
10410
10411 RSExtSmartPtr<ICorDebugManagedCallback2> pCallback2;
10412 pCallback->QueryInterface(IID_ICorDebugManagedCallback2, reinterpret_cast<void **> (&pCallback2));
10413
10414 RSExtSmartPtr<ICorDebugManagedCallback3> pCallback3;
10415 pCallback->QueryInterface(IID_ICorDebugManagedCallback3, reinterpret_cast<void **> (&pCallback3));
10416
10417 RSExtSmartPtr<ICorDebugManagedCallback4> pCallback4;
10418 pCallback->QueryInterface(IID_ICorDebugManagedCallback4, reinterpret_cast<void **> (&pCallback4));
10419
10420 // Dispatch directly. May not necessarily dispatch an event.
10421 // Toggles the lock to dispatch callbacks.
10422 RawDispatchEvent(pManagedEvent, pLockHolder, pCallback, pCallback2, pCallback3, pCallback4);
10423}
10424
10425//
10426// ProcessStateChanged -- tell the rc event thread that the ICorDebug's
10427// process list has changed by setting its flag and thread control event.
10428// This will cause the rc event thread to update its set of handles to wait
10429// on.
10430//
10431void CordbRCEventThread::ProcessStateChanged()
10432{
10433 m_cordb->LockProcessList();
10434 STRESS_LOG0(LF_CORDB, LL_INFO100000, "CRCET::ProcessStateChanged\n");
10435 m_processStateChanged = TRUE;
10436 SetEvent(m_threadControlEvent);
10437 m_cordb->UnlockProcessList();
10438}
10439
10440
10441//---------------------------------------------------------------------------------------
10442// Primary loop of the Runtime Controller event thread. This routine loops during the
10443// debug session taking IPC events from the IPC block and calling out to process them.
10444//
10445// Arguments:
10446// None.
10447//
10448// Return Value:
10449// None.
10450//
10451// Notes:
10452// @dbgtodo shim: eventually hoist the entire RCET into the shim.
10453//---------------------------------------------------------------------------------------
10454void CordbRCEventThread::ThreadProc()
10455{
10456 HANDLE waitSet[MAXIMUM_WAIT_OBJECTS];
10457 CordbProcess * rgProcessSet[MAXIMUM_WAIT_OBJECTS];
10458 unsigned int waitCount;
10459
10460#ifdef _DEBUG
10461 memset(&rgProcessSet, NULL, MAXIMUM_WAIT_OBJECTS * sizeof(CordbProcess *));
10462 memset(&waitSet, NULL, MAXIMUM_WAIT_OBJECTS * sizeof(HANDLE));
10463#endif
10464
10465
10466 // First event to wait on is always the thread control event.
10467 waitSet[0] = m_threadControlEvent;
10468 rgProcessSet[0] = NULL;
10469 waitCount = 1;
10470
10471 while (m_run)
10472 {
10473 DWORD dwStatus = WaitForMultipleObjectsEx(waitCount, waitSet, FALSE, 2000, FALSE);
10474
10475 if (dwStatus == WAIT_FAILED)
10476 {
10477 STRESS_LOG1(LF_CORDB, LL_INFO10000, "CordbRCEventThread::ThreadProc WaitFor"
10478 "MultipleObjects failed: 0x%x\n", GetLastError());
10479 }
10480#ifdef _DEBUG
10481 else if ((dwStatus >= WAIT_OBJECT_0) && (dwStatus < WAIT_OBJECT_0 + waitCount) && m_run)
10482 {
10483 // Got an event. Figure out which process it came from.
10484 unsigned int procNumber = dwStatus - WAIT_OBJECT_0;
10485
10486 if (procNumber != 0)
10487 {
10488 // @dbgtodo shim: rip all of this out. Leave the assert in for now to verify that we're not accidentally
10489 // going down this codepath. Once we rip this out, we can also simplify some of the code below.
10490 // Notification events (including Sync-complete) should be coming from Win32 event thread via
10491 // V3 pipeline.
10492 _ASSERTE(!"Shouldn't be here");
10493
10494 }
10495 }
10496#endif
10497
10498 // Empty any queued work items.
10499 DrainWorkerQueue();
10500
10501 // Check a flag to see if we need to update our list of processes to wait on.
10502 if (m_processStateChanged)
10503 {
10504 STRESS_LOG0(LF_CORDB, LL_INFO1000, "RCET::TP: refreshing process list.\n");
10505
10506 unsigned int i;
10507
10508 //
10509 // free the old wait list
10510 //
10511 for (i = 1; i < waitCount; i++)
10512 {
10513 rgProcessSet[i]->InternalRelease();
10514 }
10515
10516 // Pass 1: iterate the hash of all processes and collect the unsynchronized ones into the wait list.
10517 // Note that Stop / Continue can still be called on a different thread while we're doing this.
10518 m_cordb->LockProcessList();
10519 m_processStateChanged = FALSE;
10520
10521 waitCount = 1;
10522
10523 CordbSafeHashTable<CordbProcess> * pHashTable = m_cordb->GetProcessList();
10524 HASHFIND hashFind;
10525 CordbProcess * pProcess;
10526
10527 for (pProcess = pHashTable->FindFirst(&hashFind); pProcess != NULL; pProcess = pHashTable->FindNext(&hashFind))
10528 {
10529 _ASSERTE(waitCount < MAXIMUM_WAIT_OBJECTS);
10530
10531 if( waitCount >= MAXIMUM_WAIT_OBJECTS )
10532 {
10533 break;
10534 }
10535
10536 // Only listen to unsynchronized processes. Processes that are synchronized will not send events without
10537 // being asked by us first, so there is no need to async listen to them.
10538 //
10539 // Note: if a process is not synchronized then there is no way for it to transition to the syncrhonized
10540 // state without this thread receiving an event and taking action. So there is no need to lock the
10541 // per-process mutex when checking the process's synchronized flag here.
10542 if (!pProcess->GetSynchronized() && pProcess->IsSafeToSendEvents())
10543 {
10544 STRESS_LOG2(LF_CORDB, LL_INFO1000, "RCET::TP: listening to process 0x%x(%d)\n",
10545 pProcess->m_id, pProcess->m_id);
10546
10547 waitSet[waitCount] = pProcess->m_leftSideEventAvailable;
10548 rgProcessSet[waitCount] = pProcess;
10549 rgProcessSet[waitCount]->InternalAddRef();
10550 waitCount++;
10551 }
10552 }
10553
10554 m_cordb->UnlockProcessList();
10555
10556 // Pass 2: for each process that we placed in the wait list, determine if there are any existing queued
10557 // events that need to be flushed.
10558
10559 // Start i at 1 to skip the control event...
10560 i = 1;
10561
10562 while(i < waitCount)
10563 {
10564 pProcess = rgProcessSet[i];
10565
10566 // Take the process lock so we can check the queue safely
10567 pProcess->Lock();
10568
10569 // Now that we've just locked the processes, we can safely inspect it and dispatch events.
10570 // The process may have changed since when we first added it to the process list in Pass 1,
10571 // so we can't make any assumptions about whether it's sync, live, or exiting.
10572
10573 // Flush the queue if necessary. Note, we only do this if we've actually received a SyncComplete message
10574 // from this process. If we haven't received a SyncComplete yet, then we don't attempt to drain any
10575 // queued events yet. They'll be drained when the SyncComplete event is actually received.
10576 if (pProcess->GetSyncCompleteRecv() &&
10577 (pProcess->GetShim() != NULL) &&
10578 !pProcess->GetSynchronized())
10579 {
10580 if (pProcess->GetShim()->GetManagedEventQueue()->IsEmpty())
10581 {
10582 // Effectively what we are doing here is to continue everything without actually
10583 // handling an event. We can get here if the event raised by the LS is a duplicate
10584 // creation event, which the shim discards without adding it to the event queue.
10585 // See code:ShimProcess::IsDuplicateCreationEvent.
10586 //
10587 // To continue, we need to increment the stop count first. Also, we can't call
10588 // Continue() while holding the process lock.
10589 pProcess->SetSynchronized(true);
10590 pProcess->IncStopCount();
10591 pProcess->Unlock();
10592 pProcess->ContinueInternal(FALSE);
10593 pProcess->Lock();
10594 }
10595 else
10596 {
10597 // This may toggle the process-lock
10598 FlushQueuedEvents(pProcess);
10599 }
10600 }
10601
10602 // Flushing could have left the process synchronized...
10603 // Common case is if the callback didn't call Continue().
10604 if (pProcess->GetSynchronized())
10605 {
10606 // remove the process from the wait list by moving all the other processes down one.
10607 if ((i + 1) < waitCount)
10608 {
10609 memcpy(&rgProcessSet[i], &(rgProcessSet[i+1]), sizeof(rgProcessSet[0]) * (waitCount - i - 1));
10610 memcpy(&waitSet[i], &waitSet[i+1], sizeof(waitSet[0]) * (waitCount - i - 1));
10611 }
10612
10613 // drop the count of processes to wait on
10614 waitCount--;
10615
10616 pProcess->Unlock();
10617
10618 // make sure to release the reference we added when the process was added to the wait list.
10619 pProcess->InternalRelease();
10620
10621 // We don't have to increment i because we've copied the next element into
10622 // the current value at i.
10623 }
10624 else
10625 {
10626 // Even after flushing, its still not syncd, so leave it in the wait list.
10627 pProcess->Unlock();
10628
10629 // Increment i normally.
10630 i++;
10631 }
10632 }
10633 } // end ProcessStateChanged
10634 } // while (m_run)
10635
10636#ifdef _DEBUG_IMPL
10637 // We intentionally return while leaking some CordbProcess objects inside
10638 // rgProcessSet, in some cases (e.g., I've seen this happen when detaching from a
10639 // debuggee almost immediately after attaching to it). In the future, we should
10640 // really consider not leaking these anymore. However, I'm unsure how safe it is to just
10641 // go and InternalRelease() those guys, as above we intentionally DON'T release them when
10642 // they're not synchronized. So for now, to make debug builds happy, exclude those
10643 // references when we run CheckMemLeaks() later on. In our next side-by-side release,
10644 // consider actually doing InternalRelease() on the remaining CordbProcesses on
10645 // retail, and then we can remove the following loop.
10646 for (UINT i=1; i < waitCount; i++)
10647 {
10648 InterlockedDecrement(&Cordb::s_DbgMemTotalOutstandingInternalRefs);
10649 }
10650#endif //_DEBUG_IMPL
10651}
10652
10653
10654//
10655// This is the thread's real thread proc. It simply calls to the
10656// thread proc on the given object.
10657//
10658/*static*/
10659DWORD WINAPI CordbRCEventThread::ThreadProc(LPVOID parameter)
10660{
10661 CordbRCEventThread * pThread = (CordbRCEventThread *) parameter;
10662
10663 INTERNAL_THREAD_ENTRY(pThread);
10664 pThread->ThreadProc();
10665 return 0;
10666}
10667
10668template<typename T>
10669InterlockedStack<T>::InterlockedStack()
10670{
10671 m_pHead = NULL;
10672}
10673
10674template<typename T>
10675InterlockedStack<T>::~InterlockedStack()
10676{
10677 // This is an arbitrary choice. We expect the stacks be drained.
10678 _ASSERTE(m_pHead == NULL);
10679}
10680
10681// Thread safe pushes + pops.
10682// Many threads can push simultaneously.
10683// Only 1 thread can pop.
10684template<typename T>
10685void InterlockedStack<T>::Push(T * pItem)
10686{
10687 // InterlockedCompareExchangePointer(&dest, ex, comp).
10688 // Really behaves like:
10689 // val = *dest;
10690 // if (*dest == comp) { *dest = ex; }
10691 // return val;
10692 //
10693 // We can do a thread-safe assign { comp = dest; dest = ex } via:
10694 // do { comp = dest } while (ICExPtr(&dest, ex, comp) != comp));
10695
10696
10697 do
10698 {
10699 pItem->m_next = m_pHead;
10700 }
10701 while(InterlockedCompareExchangeT(&m_pHead, pItem, pItem->m_next) != pItem->m_next);
10702}
10703
10704// Returns NULL on empty,
10705// else returns the head of the list.
10706template<typename T>
10707T * InterlockedStack<T>::Pop()
10708{
10709 if (m_pHead == NULL)
10710 {
10711 return NULL;
10712 }
10713
10714 // This allows 1 thread to Pop() and race against N threads doing a Push().
10715 T * pItem = NULL;
10716 do
10717 {
10718 pItem = m_pHead;
10719 } while(InterlockedCompareExchangeT(&m_pHead, pItem->m_next, pItem) != pItem);
10720
10721 return pItem;
10722}
10723
10724
10725// RCET will take ownership of this item and delete it.
10726// This can be done w/o taking any locks (thus it can be called from any lock context)
10727// This may race w/ the RCET draining the queue.
10728void CordbRCEventThread::QueueAsyncWorkItem(RCETWorkItem * pItem)
10729{
10730 // @todo -
10731 // Non-blocking insert into queue.
10732
10733 _ASSERTE(pItem != NULL);
10734
10735 m_WorkerStack.Push(pItem);
10736
10737 // Ping the RCET so that it drains the queue.
10738 SetEvent(m_threadControlEvent);
10739}
10740
10741// Execute & delete all workitems in the queue.
10742// This can be done w/o taking any locks. (though individual items may take locks).
10743void CordbRCEventThread::DrainWorkerQueue()
10744{
10745 _ASSERTE(IsRCEventThread());
10746
10747 while(true)
10748 {
10749 RCETWorkItem* pCur = m_WorkerStack.Pop();
10750 if (pCur == NULL)
10751 {
10752 break;
10753 }
10754
10755 pCur->Do();
10756 delete pCur;
10757 }
10758}
10759
10760
10761//---------------------------------------------------------------------------------------
10762// Wait for an reply from the debuggee.
10763//
10764// Arguments:
10765// pProcess - process for debuggee.
10766// pAppDomain - not used.
10767// pEvent - caller-allocated event to be filled out.
10768// This is expected to be at least as big as CorDBIPC_BUFFER_SIZE.
10769//
10770// Return Value:
10771// S_OK on success. else failure.
10772//
10773// Assumptions:
10774// Caller allocates
10775//
10776// Notes:
10777// WaitForIPCEventFromProcess waits for an event from just the specified
10778// process. This should only be called when the process is in a synchronized
10779// state, which ensures that the RCEventThread isn't listening to the
10780// process's event, too, which would get confusing.
10781//
10782// @dbgtodo - this function should eventually be obsolete once everything
10783// is using DAC calls instead of helper-thread.
10784//
10785//---------------------------------------------------------------------------------------
10786HRESULT CordbRCEventThread::WaitForIPCEventFromProcess(CordbProcess * pProcess,
10787 CordbAppDomain * pAppDomain,
10788 DebuggerIPCEvent * pEvent)
10789{
10790 CORDBRequireProcessStateOKAndSync(pProcess, pAppDomain);
10791
10792 DWORD dwStatus;
10793 HRESULT hr = S_OK;
10794
10795 do
10796 {
10797 dwStatus = SafeWaitForSingleObject(pProcess,
10798 pProcess->m_leftSideEventAvailable,
10799 CordbGetWaitTimeout());
10800
10801 if (pProcess->m_terminated)
10802 {
10803 return CORDBG_E_PROCESS_TERMINATED;
10804 }
10805 // If we timeout because we're waiting for an uncontinued OOB event, we need to just keep waiting.
10806 } while ((dwStatus == WAIT_TIMEOUT) && pProcess->IsWaitingForOOBEvent());
10807
10808
10809
10810
10811 if (dwStatus == WAIT_OBJECT_0)
10812 {
10813 pProcess->CopyRCEventFromIPCBlock(pEvent);
10814
10815 EX_TRY
10816 {
10817 pProcess->MarshalManagedEvent(pEvent);
10818
10819 STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: Got %s for AD 0x%x, proc 0x%x(%d)\n",
10820 IPCENames::GetName(pEvent->type),
10821 VmPtrToCookie(pEvent->vmAppDomain),
10822 pProcess->m_id,
10823 pProcess->m_id);
10824
10825 }
10826 EX_CATCH_HRESULT(hr)
10827
10828 SetEvent(pProcess->m_leftSideEventRead);
10829
10830 return hr;
10831 }
10832 else if (dwStatus == WAIT_TIMEOUT)
10833 {
10834 //
10835 // If we timed out, check the left side to see if it is in the
10836 // unrecoverable error mode. If it is, return the HR from the
10837 // left side that caused the error. Otherwise, return that we timed
10838 // out and that we don't really know why.
10839 //
10840 HRESULT realHR = ErrWrapper(CORDBG_E_TIMEOUT);
10841
10842 hr = pProcess->CheckForUnrecoverableError();
10843
10844 if (hr == S_OK)
10845 {
10846 CORDBSetUnrecoverableError(pProcess, realHR, 0);
10847 return realHR;
10848 }
10849 else
10850 return hr;
10851 }
10852 else
10853 {
10854 _ASSERTE(dwStatus == WAIT_FAILED);
10855
10856 hr = HRESULT_FROM_GetLastError();
10857
10858 CORDBSetUnrecoverableError(pProcess, hr, 0);
10859
10860 return hr;
10861 }
10862}
10863
10864
10865//
10866// Start actually creates and starts the thread.
10867//
10868HRESULT CordbRCEventThread::Start()
10869{
10870 if (m_threadControlEvent == NULL)
10871 {
10872 return E_INVALIDARG;
10873 }
10874
10875 m_thread = CreateThread(NULL,
10876 0,
10877 &CordbRCEventThread::ThreadProc,
10878 (LPVOID) this,
10879 0,
10880 &m_threadId);
10881
10882 if (m_thread == NULL)
10883 {
10884 return HRESULT_FROM_GetLastError();
10885 }
10886
10887 return S_OK;
10888}
10889
10890
10891//
10892// Stop causes the thread to stop receiving events and exit. It
10893// waits for it to exit before returning.
10894//
10895HRESULT CordbRCEventThread::Stop()
10896{
10897 if (m_thread != NULL)
10898 {
10899 LOG((LF_CORDB, LL_INFO100000, "CRCET::Stop\n"));
10900
10901 m_run = FALSE;
10902
10903 SetEvent(m_threadControlEvent);
10904
10905 DWORD ret = WaitForSingleObject(m_thread, INFINITE);
10906
10907 if (ret != WAIT_OBJECT_0)
10908 {
10909 return HRESULT_FROM_GetLastError();
10910 }
10911 }
10912
10913 m_cordb.Clear();
10914
10915 return S_OK;
10916}
10917
10918
10919/* ------------------------------------------------------------------------- *
10920 * Win32 Event Thread class
10921 * ------------------------------------------------------------------------- */
10922
10923enum
10924{
10925 W32ETA_NONE = 0,
10926 W32ETA_CREATE_PROCESS = 1,
10927 W32ETA_ATTACH_PROCESS = 2,
10928 W32ETA_CONTINUE = 3,
10929 W32ETA_DETACH = 4
10930};
10931
10932
10933
10934//---------------------------------------------------------------------------------------
10935// Constructor
10936//
10937// Arguments:
10938// pCordb - Pointer to the owning cordb object for this event thread.
10939// pShim - Pointer to the shim for supporting V2 debuggers on V3 architecture.
10940//
10941//---------------------------------------------------------------------------------------
10942CordbWin32EventThread::CordbWin32EventThread(
10943 Cordb * pCordb,
10944 ShimProcess * pShim
10945 ) :
10946 m_thread(NULL), m_threadControlEvent(NULL),
10947 m_actionTakenEvent(NULL), m_run(TRUE),
10948 m_action(W32ETA_NONE)
10949{
10950 m_cordb.Assign(pCordb);
10951 _ASSERTE(pCordb != NULL);
10952
10953 m_pShim = pShim;
10954
10955 m_pNativePipeline = NULL;
10956}
10957
10958
10959//
10960// Destructor. Cleans up all of the open handles and such.
10961// This expects that the thread has been stopped and has terminated
10962// before being called.
10963//
10964CordbWin32EventThread::~CordbWin32EventThread()
10965{
10966 if (m_thread != NULL)
10967 CloseHandle(m_thread);
10968
10969 if (m_threadControlEvent != NULL)
10970 CloseHandle(m_threadControlEvent);
10971
10972 if (m_actionTakenEvent != NULL)
10973 CloseHandle(m_actionTakenEvent);
10974
10975 if (m_pNativePipeline != NULL)
10976 {
10977 m_pNativePipeline->Delete();
10978 m_pNativePipeline = NULL;
10979 }
10980
10981 m_sendToWin32EventThreadMutex.Destroy();
10982}
10983
10984
10985//
10986// Init sets up all the objects that the thread will need to run.
10987//
10988HRESULT CordbWin32EventThread::Init()
10989{
10990 if (m_cordb == NULL)
10991 return E_INVALIDARG;
10992
10993 m_sendToWin32EventThreadMutex.Init("Win32-Send lock", RSLock::cLockFlat, RSLock::LL_WIN32_SEND_LOCK);
10994
10995 m_threadControlEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL);
10996 if (m_threadControlEvent == NULL)
10997 return HRESULT_FROM_GetLastError();
10998
10999 m_actionTakenEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL);
11000 if (m_actionTakenEvent == NULL)
11001 return HRESULT_FROM_GetLastError();
11002
11003 m_pNativePipeline = NewPipelineWithDebugChecks();
11004 if (m_pNativePipeline == NULL)
11005 {
11006 return E_OUTOFMEMORY;
11007 }
11008
11009 return S_OK;
11010}
11011
11012//
11013// Main function of the Win32 Event Thread
11014//
11015void CordbWin32EventThread::ThreadProc()
11016{
11017#if defined(RSCONTRACTS)
11018 DbgRSThread::GetThread()->SetThreadType(DbgRSThread::cW32ET);
11019
11020 // The win32 ET conceptually holds a lock (all threads do).
11021 DbgRSThread::GetThread()->TakeVirtualLock(RSLock::LL_WIN32_EVENT_THREAD);
11022#endif
11023
11024 // In V2, the debuggee decides what to do if the debugger rudely exits / detaches. (This is
11025 // handled by host policy). With the OS native-debuggging pipeline, the debugger by default
11026 // kills the debuggee if it exits. To emulate V2 behavior, we need to override that default.
11027 BOOL fOk = m_pNativePipeline->DebugSetProcessKillOnExit(FALSE);
11028 (void)fOk; //prevent "unused variable" error from GCC
11029 _ASSERTE(fOk);
11030
11031
11032 // Run the top-level event loop.
11033 Win32EventLoop();
11034
11035#if defined(RSCONTRACTS)
11036 // The win32 ET conceptually holds a lock (all threads do).
11037 DbgRSThread::GetThread()->ReleaseVirtualLock(RSLock::LL_WIN32_EVENT_THREAD);
11038#endif
11039}
11040
11041// Define a holder that calls code:DeleteIPCEventHelper
11042NEW_WRAPPER_TEMPLATE1(DeleteIPCEventHolderHelper, DeleteIPCEventHelper);
11043typedef DeleteIPCEventHolderHelper<DebuggerIPCEvent> DeleteIPCEventHolder;
11044
11045//---------------------------------------------------------------------------------------
11046//
11047// Helper to clean up IPCEvent before deleting it.
11048// This must be called after an event is marshalled via code:CordbProcess::MarshalManagedEvent
11049//
11050// Arguments:
11051// pManagedEvent - managed event to delete.
11052//
11053// Notes:
11054// This can delete a partially marshalled event.
11055//
11056void DeleteIPCEventHelper(DebuggerIPCEvent *pManagedEvent)
11057{
11058 CONTRACTL
11059 {
11060 // This is backout code that shouldn't need to throw.
11061 NOTHROW;
11062 }
11063 CONTRACTL_END;
11064 if (pManagedEvent == NULL)
11065 {
11066 return;
11067 }
11068 switch (pManagedEvent->type & DB_IPCE_TYPE_MASK)
11069 {
11070 // so far only this event need to cleanup.
11071 case DB_IPCE_MDA_NOTIFICATION:
11072 pManagedEvent->MDANotification.szName.CleanUp();
11073 pManagedEvent->MDANotification.szDescription.CleanUp();
11074 pManagedEvent->MDANotification.szXml.CleanUp();
11075 break;
11076
11077 case DB_IPCE_FIRST_LOG_MESSAGE:
11078 pManagedEvent->FirstLogMessage.szContent.CleanUp();
11079 break;
11080
11081 default:
11082 break;
11083 }
11084 delete [] (BYTE *)pManagedEvent;
11085}
11086
11087//---------------------------------------------------------------------------------------
11088// Handle a CLR specific notification event.
11089//
11090// Arguments:
11091// pManagedEvent - non-null pointer to a managed event.
11092// pLockHolder - hold to process lock that gets toggled if this dispatches an event.
11093// pCallback - callback to dispatch potential managed events.
11094//
11095// Return Value:
11096// Throws on error.
11097//
11098// Assumptions:
11099// Target is stopped. Record was already determined to be a CLR event.
11100//
11101// Notes:
11102// This is called after caller does WaitForDebugEvent.
11103// Any exception this Filter does not recognize is treated as kNotClr.
11104// Currently, this includes both managed-exceptions and unmanaged ones.
11105// For interop-debugging, the interop logic will handle all kNotClr and triage if
11106// it's really a non-CLR exception.
11107//
11108//---------------------------------------------------------------------------------------
11109void CordbProcess::FilterClrNotification(
11110 DebuggerIPCEvent * pManagedEvent,
11111 RSLockHolder * pLockHolder,
11112 ICorDebugManagedCallback * pCallback)
11113{
11114 CONTRACTL
11115 {
11116 THROWS;
11117 PRECONDITION(CheckPointer(pManagedEvent));
11118 PRECONDITION(CheckPointer(pCallback));
11119 PRECONDITION(ThreadHoldsProcessLock());
11120 }
11121 CONTRACTL_END;
11122
11123 // There are 3 types of events from the LS:
11124 // 1) Replies (eg, corresponding to WaitForIPCEvent)
11125 // we need to set LSEA/wait on LSER.
11126 // 2) Sync-Complete (kind of like a special notification)
11127 // Ping the helper
11128 // 3) Notifications (eg, Module-load):
11129 // these are dispatched immediately.
11130 // 4) Left-side Startup event
11131
11132
11133 // IF we're synced, then we must be getting a "Reply".
11134 bool fReply = this->GetSynchronized();
11135
11136 LOG((LF_CORDB, LL_INFO10000, "CP::FCN - Received event %s; fReply: %d\n",
11137 IPCENames::GetName(pManagedEvent->type),
11138 fReply));
11139
11140 if (fReply)
11141 {
11142 //
11143 _ASSERTE(m_pShim != NULL);
11144 //
11145 // Case 1: Reply
11146 //
11147
11148 pLockHolder->Release();
11149 _ASSERTE(!ThreadHoldsProcessLock());
11150
11151 // Save the IPC event and wake up the thread which is waiting for it from the LS.
11152 GetEventChannel()->SaveEventFromLeftSide(pManagedEvent);
11153 SetEvent(this->m_leftSideEventAvailable);
11154
11155 // Some other thread called code:CordbRCEventThread::WaitForIPCEventFromProcess, and
11156 // that will respond here and set the event.
11157
11158 DWORD dwResult = WaitForSingleObject(this->m_leftSideEventRead, CordbGetWaitTimeout());
11159 pLockHolder->Acquire();
11160 if (dwResult != WAIT_OBJECT_0)
11161 {
11162 // The wait failed. This is probably WAIT_TIMEOUT which suggests a deadlock/assert on
11163 // the RCEventThread.
11164 CONSISTENCY_CHECK_MSGF(false, ("WaitForSingleObject failed: %d", dwResult));
11165 ThrowHR(CORDBG_E_TIMEOUT);
11166 }
11167 }
11168 else
11169 {
11170 if (pManagedEvent->type == DB_IPCE_LEFTSIDE_STARTUP)
11171 {
11172 //
11173 // Case 4: Left-side startup event. We'll mark that we're attached from oop.
11174 //
11175
11176 // Now that LS is started, we should definitely be able to instantiate DAC.
11177 InitializeDac();
11178
11179 // @dbgtodo 'attach-bit': we don't want the debugger automatically invading the process.
11180 GetDAC()->MarkDebuggerAttached(TRUE);
11181 }
11182 else if (pManagedEvent->type == DB_IPCE_SYNC_COMPLETE)
11183 {
11184 // Since V3 doesn't request syncs, it shouldn't get sync-complete.
11185 // @dbgtodo sync: this changes when V3 can explicitly request an AsyncBreak.
11186 _ASSERTE(m_pShim != NULL);
11187
11188 //
11189 // Case 2: Sync Complete
11190 //
11191
11192 HandleSyncCompleteRecieved();
11193 }
11194 else
11195 {
11196 //
11197 // Case 3: Notification. This will dispatch the event immediately.
11198 //
11199
11200 // Toggles the process-lock if it dispatches callbacks.
11201 HandleRCEvent(pManagedEvent, pLockHolder, pCallback);
11202
11203 } // end Notification
11204 }
11205}
11206
11207
11208
11209//
11210// If the thread has an unhandled managed exception, hijack it.
11211//
11212// Arguments:
11213// dwThreadId - OS Thread id.
11214//
11215// Returns:
11216// True if hijacked; false if not.
11217//
11218// Notes:
11219// This is called from shim to emulate being synchronized at an unhandled
11220// exception.
11221// Other ICorDebug operations could calls this (eg, func-eval at 2nd chance).
11222BOOL CordbProcess::HijackThreadForUnhandledExceptionIfNeeded(DWORD dwThreadId)
11223{
11224 PUBLIC_API_ENTRY(this); // from Shim
11225
11226 BOOL fHijacked = FALSE;
11227 HRESULT hr = S_OK;
11228 EX_TRY
11229 {
11230 RSLockHolder lockHolder(GetProcessLock());
11231
11232 // OS will not execute the Unhandled Exception Filter under native debugger, so
11233 // we need to hijack the thread to get it to execute the UEF, which will then do
11234 // work for unhandled managed exceptions.
11235 CordbThread * pThread = TryLookupOrCreateThreadByVolatileOSId(dwThreadId);
11236 if (pThread != NULL)
11237 {
11238 // If the thread has a managed exception, then we should have a pThread object.
11239
11240 if (pThread->HasUnhandledNativeException())
11241 {
11242 _ASSERTE(pThread->IsThreadExceptionManaged()); // should have been marked earlier
11243
11244 pThread->HijackForUnhandledException();
11245 fHijacked = TRUE;
11246 }
11247 }
11248 }
11249 EX_CATCH_HRESULT(hr);
11250 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
11251
11252 return fHijacked;
11253}
11254
11255//---------------------------------------------------------------------------------------
11256// Validate the given exception record or throw.
11257//
11258// Arguments:
11259// pRawRecord - non-null raw bytes of the exception
11260// countBytes - number of bytes in pRawRecord buffer.
11261// format - format of pRawRecord
11262//
11263// Returns:
11264// A type-safe exception record from the raw buffer.
11265//
11266// Notes:
11267// This is a helper for code:CordbProcess::Filter.
11268// This can do consistency checks on the incoming parameters such as:
11269// * verify countBytes matches the expected size for the given format.
11270// * verify the format is supported.
11271//
11272// If we let a given ICD understand multiple formats (eg, have x86 understand both Exr32 and
11273// Exr64), this would be the spot to allow the conversion.
11274//
11275const EXCEPTION_RECORD * CordbProcess::ValidateExceptionRecord(
11276 const BYTE pRawRecord[],
11277 DWORD countBytes,
11278 CorDebugRecordFormat format)
11279{
11280 ValidateOrThrow(pRawRecord);
11281
11282 //
11283 // Check format against expected platform.
11284 //
11285
11286 // @dbgtodo - , cross-plat: Once we do cross-plat, these should be based off target-architecture not host's.
11287#if defined(_WIN64)
11288 if (format != FORMAT_WINDOWS_EXCEPTIONRECORD64)
11289 {
11290 ThrowHR(E_INVALIDARG);
11291 }
11292#else
11293 if (format != FORMAT_WINDOWS_EXCEPTIONRECORD32)
11294 {
11295 ThrowHR(E_INVALIDARG);
11296 }
11297#endif
11298
11299 // @dbgtodo cross-plat: once we do cross-plat, need to use correct EXCEPTION_RECORD variant.
11300 if (countBytes != sizeof(EXCEPTION_RECORD))
11301 {
11302 ThrowHR(E_INVALIDARG);
11303 }
11304
11305
11306 const EXCEPTION_RECORD * pRecord = reinterpret_cast<const EXCEPTION_RECORD *> (pRawRecord);
11307
11308 return pRecord;
11309};
11310
11311// Return value: S_OK or indication that no more room exists for enabled types
11312HRESULT CordbProcess::SetEnableCustomNotification(ICorDebugClass * pClass, BOOL fEnable)
11313{
11314 HRESULT hr = S_OK;
11315 PUBLIC_API_BEGIN(this); // takes the lock
11316
11317 ValidateOrThrow(pClass);
11318
11319 ((CordbClass *)pClass)->SetCustomNotifications(fEnable);
11320
11321 PUBLIC_API_END(hr);
11322 return hr;
11323} // CordbProcess::SetEnableCustomNotification
11324
11325//---------------------------------------------------------------------------------------
11326// Public implementation of ICDProcess4::Filter
11327//
11328// Arguments:
11329// pRawRecord - non-null raw bytes of the exception
11330// countBytes - number of bytes in pRawRecord buffer.
11331// format - format of pRawRecord
11332// dwFlags - flags providing auxillary info for exception record.
11333// dwThreadId - thread that exception occurred on.
11334// pCallback - callback to dispatch potential managed events on.
11335// pContinueStatus - Continuation status for exception. This dictates what
11336// to pass to kernel32!ContinueDebugEvent().
11337//
11338// Return Value:
11339// S_OK on success.
11340//
11341// Assumptions:
11342// Target is stopped.
11343//
11344// Notes:
11345// The exception could be anything, including:
11346// - a CLR notification,
11347// - a random managed exception (both from managed code or the runtime),
11348// - a non-CLR exception
11349//
11350// This is cross-platform. The {pRawRecord, countBytes, format} describe events
11351// on an arbitrary target architecture. On windows, this will be an EXCEPTION_RECORD.
11352//
11353HRESULT CordbProcess::Filter(
11354 const BYTE pRawRecord[],
11355 DWORD countBytes,
11356 CorDebugRecordFormat format,
11357 DWORD dwFlags,
11358 DWORD dwThreadId,
11359 ICorDebugManagedCallback * pCallback,
11360 DWORD * pContinueStatus
11361)
11362{
11363 HRESULT hr = S_OK;
11364 PUBLIC_API_BEGIN(this); // takes the lock
11365 {
11366 //
11367 // Validate parameters
11368 //
11369
11370 // If we don't care about the continue status, we leave it untouched.
11371 ValidateOrThrow(pContinueStatus);
11372 ValidateOrThrow(pCallback);
11373
11374 const EXCEPTION_RECORD * pRecord = ValidateExceptionRecord(pRawRecord, countBytes, format);
11375
11376 DWORD dwFirstChance = (dwFlags & IS_FIRST_CHANCE);
11377
11378 //
11379 // Deal with 2nd-chance exceptions. Don't actually hijack now (that's too invasive),
11380 // but mark that we have the exception in case a future operation (eg, func-eval) needs to hijack.
11381 //
11382 if (!dwFirstChance)
11383 {
11384 CordbThread * pThread = TryLookupOrCreateThreadByVolatileOSId(dwThreadId);
11385
11386 // If we don't have a managed-thread object, then it certainly can't have a throwable.
11387 // It's possible this is still an exception from the native portion of the runtime,
11388 // but that's ok, we'll just treat it as a native exception.
11389 // This could be expensive, don't want to do it often... (definitely not on every Filter).
11390
11391
11392 // OS will not execute the Unhandled Exception Filter under native debugger, so
11393 // we need to hijack the thread to get it to execute the UEF, which will then do
11394 // work for unhandled managed exceptions.
11395 if ((pThread != NULL) && pThread->IsThreadExceptionManaged())
11396 {
11397 // Copy exception record for future use in case we decide to hijack.
11398 pThread->SetUnhandledNativeException(pRecord);
11399 }
11400 // we don't care about 2nd-chance exceptions, unless we decide to hijack it later.
11401 }
11402
11403 //
11404 // Deal with CLR notifications
11405 //
11406 else if (pRecord->ExceptionCode == CLRDBG_NOTIFICATION_EXCEPTION_CODE) // Special event code
11407 {
11408 //
11409 // This may not be for us, or we may not have a managed thread object:
11410 // 1. Anybody can raise an exception with this exception code, so can't assume this belongs to us yet.
11411 // 2. Notifications may come on unmanaged threads if they're coming from MDAs or CLR internal events
11412 // fired before the thread is created.
11413 //
11414 BYTE * pManagedEventBuffer = new BYTE[CorDBIPC_BUFFER_SIZE];
11415 DeleteIPCEventHolder pManagedEvent(reinterpret_cast<DebuggerIPCEvent *>(pManagedEventBuffer));
11416
11417 bool fOwner = CopyManagedEventFromTarget(pRecord, pManagedEvent);
11418 if (fOwner)
11419 {
11420 // This toggles the lock if it dispatches callbacks
11421 FilterClrNotification(pManagedEvent, GET_PUBLIC_LOCK_HOLDER(), pCallback);
11422
11423 // Cancel any notification events from target. These are just supposed to notify ICD and not
11424 // actually be real exceptions in the target.
11425 // Canceling here also prevents a VectoredExceptionHandler in the target from picking
11426 // up exceptions for the CLR.
11427 *pContinueStatus = DBG_CONTINUE;
11428 }
11429
11430 // holder will invoke DeleteIPCEventHelper(pManagedEvent).
11431 }
11432
11433 }
11434 PUBLIC_API_END(hr);
11435 // we may not find the correct mscordacwks so fail gracefully
11436 _ASSERTE(SUCCEEDED(hr) || (hr != HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)));
11437
11438 return hr;
11439}
11440
11441//---------------------------------------------------------------------------------------
11442// Wrapper to invoke ICorDebugMutableDataTarget::ContinueStatusChanged
11443//
11444// Arguments:
11445// dwContinueStatus - new continue status
11446//
11447// Returns:
11448// None. Throw on error.
11449//
11450// Notes:
11451// Initial continue status is returned from code:CordbProcess::Filter.
11452// Some operations (mainly hijacking on a 2nd-chance exception), may need to
11453// override that continue status.
11454// ICorDebug operations invoke a callback on the data-target to notify the debugger
11455// of a change in status. Debugger may fail the request.
11456//
11457void CordbProcess::ContinueStatusChanged(DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus)
11458{
11459 HRESULT hr = m_pMutableDataTarget->ContinueStatusChanged(dwThreadId, dwContinueStatus);
11460 IfFailThrow(hr);
11461}
11462
11463//---------------------------------------------------------------------------------------
11464// Request a synchronization to occur after a debug event is dispatched.
11465//
11466// Note:
11467// This is called in response to a managed debug event, and so we know that we have
11468// a worker thread in the process (the one that just sent the event!)
11469// This can not be called asynchronously.
11470//---------------------------------------------------------------------------------------
11471void CordbProcess::RequestSyncAtEvent()
11472{
11473 GetDAC()->RequestSyncAtEvent();
11474}
11475
11476//---------------------------------------------------------------------------------------
11477//
11478// Primary loop of the Win32 debug event thread.
11479//
11480//
11481// Arguments:
11482// None.
11483//
11484// Return Value:
11485// None.
11486//
11487// Notes:
11488// This is it, you've found it, the main guy. This function loops as long as the
11489// debugger is around calling the OS WaitForDebugEvent() API. It takes the OS Debug
11490// Event and filters it thru the right-side, continuing the process if not recognized.
11491//
11492// @dbgtodo shim: this will become part of the shim.
11493//---------------------------------------------------------------------------------------
11494void CordbWin32EventThread::Win32EventLoop()
11495{
11496 // This must be called from the win32 event thread.
11497 _ASSERTE(IsWin32EventThread());
11498
11499 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: entered win32 event loop\n"));
11500
11501
11502 DEBUG_EVENT event;
11503
11504 // Allow the timeout for WFDE to be adjustable. Default to 25 ms based off perf numbers (see issue VSWhidbey 132368).
11505 DWORD dwWFDETimeout = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_DbgWFDETimeout);
11506
11507 while (m_run)
11508 {
11509 BOOL fEventAvailable = FALSE;
11510
11511 // We should not have any locks right now.
11512
11513
11514 // Have to wait on 2 sources:
11515 // WaitForMultipleObjects - ping for messages (create, attach, Continue, detach) and also
11516 // process exits in the managed-only case.
11517 // Native Debug Events - This is a huge perf hit so we want to avoid it whenever we can.
11518 // Only wait on these if we're interop debugging and if the process is not frozen.
11519 // A frozen process can't send any debug events, so don't bother looking for them.
11520
11521
11522 unsigned int cWaitCount = 1;
11523
11524 HANDLE rghWaitSet[2];
11525
11526 rghWaitSet[0] = m_threadControlEvent;
11527
11528 DWORD dwWaitTimeout = INFINITE;
11529
11530 if (m_pProcess != NULL)
11531 {
11532 // Process is always built on Native debugging pipeline, so it needs to always be prepared to call WFDE
11533 // As an optimization, if the target is stopped, then we can avoid calling WFDE.
11534 {
11535#ifndef FEATURE_INTEROP_DEBUGGING
11536 // Managed-only, never win32 stopped, so always check for an event.
11537 dwWaitTimeout = 0;
11538 fEventAvailable = m_pNativePipeline->WaitForDebugEvent(&event, dwWFDETimeout, m_pProcess);
11539#else
11540 // Wait for a Win32 debug event from any processes that we may be attached to as the Win32 debugger.
11541 const bool fIsWin32Stopped = (m_pProcess->m_state & CordbProcess::PS_WIN32_STOPPED) != 0;
11542 const bool fSkipWFDE = fIsWin32Stopped;
11543
11544
11545 const bool fIsInteropDebugging = m_pProcess->IsInteropDebugging();
11546 (void)fIsInteropDebugging; //prevent "unused variable" error from GCC
11547
11548 // Assert checks
11549 _ASSERTE(fIsInteropDebugging == m_pShim->IsInteropDebugging());
11550
11551 if (!fSkipWFDE)
11552 {
11553 dwWaitTimeout = 0;
11554 fEventAvailable = m_pNativePipeline->WaitForDebugEvent(&event, dwWFDETimeout, m_pProcess);
11555 }
11556 else
11557 {
11558 // If we're managed-only debugging, then the process should always be running,
11559 // which means we always need to be calling WFDE to pump potential debug events.
11560 // If we're interop-debugging, then the process can be stopped at a native-debug event,
11561 // in which case we don't have to call WFDE until we resume it again.
11562 // So we can only skip the WFDE when we're interop-debugging.
11563 _ASSERTE(fIsInteropDebugging);
11564 }
11565#endif // FEATURE_INTEROP_DEBUGGING
11566 }
11567
11568
11569 } // end m_pProcess != NULL
11570
11571#if defined(FEATURE_INTEROP_DEBUGGING)
11572 // While interop-debugging, the process may get killed rudely underneath us, even if we haven't
11573 // continued the last debug event. In such cases, The process object will get signalled normally.
11574 // If we didn't just get a native-exitProcess event, then listen on the process handle for exit.
11575 // (this includes all managed-only debugging)
11576 // It's very important to establish this before we go into the WaitForMutlipleObjects below
11577 // because the debuggee may exit while we're sitting in that loop (waiting for the debugger to call Continue).
11578 bool fDidNotJustGetExitProcessEvent = !fEventAvailable || (event.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
11579#else
11580 // In non-interop scenarios, we'll never get any native debug events, let alone an ExitProcess native event.
11581 bool fDidNotJustGetExitProcessEvent = true;
11582#endif // FEATURE_INTEROP_DEBUGGING
11583
11584
11585 // The m_pProcess handle will get nulled out after we process the ExitProcess event, and
11586 // that will ensure that we only wait for an Exit event once.
11587 if ((m_pProcess != NULL) && fDidNotJustGetExitProcessEvent)
11588 {
11589 rghWaitSet[1] = m_pProcess->UnsafeGetProcessHandle();
11590 cWaitCount = 2;
11591 }
11592
11593 // See if any process that we aren't attached to as the Win32 debugger have exited. (Note: this is a
11594 // polling action if we are also waiting for Win32 debugger events. We're also looking at the thread
11595 // control event here, too, to see if we're supposed to do something, like attach.
11596 DWORD dwStatus = WaitForMultipleObjectsEx(cWaitCount, rghWaitSet, FALSE, dwWaitTimeout, FALSE);
11597
11598 _ASSERTE((dwStatus == WAIT_TIMEOUT) || (dwStatus < cWaitCount));
11599
11600 if (!m_run)
11601 {
11602 _ASSERTE(m_action == W32ETA_NONE);
11603 break;
11604 }
11605
11606 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL - got event , ret=%d, has w32 dbg event=%d\n",
11607 dwStatus, fEventAvailable));
11608
11609 // If we haven't timed out, or if it wasn't the thread control event
11610 // that was set, then a process has
11611 // exited...
11612 if ((dwStatus != WAIT_TIMEOUT) && (dwStatus != WAIT_OBJECT_0))
11613 {
11614 // Grab the process that exited.
11615 _ASSERTE((dwStatus - WAIT_OBJECT_0) == 1);
11616 ExitProcess(false); // not detach
11617 fEventAvailable = false;
11618 }
11619 // Should we create a process?
11620 else if (m_action == W32ETA_CREATE_PROCESS)
11621 {
11622 CreateProcess();
11623 }
11624 // Should we attach to a process?
11625 else if (m_action == W32ETA_ATTACH_PROCESS)
11626 {
11627 AttachProcess();
11628 }
11629 // Should we detach from a process?
11630 else if (m_action == W32ETA_DETACH)
11631 {
11632 ExitProcess(true); // detach case
11633
11634 // Once we detach, we don't need to continue any outstanding event.
11635 // So act like we never got the event.
11636 fEventAvailable = false;
11637 PREFIX_ASSUME(m_pProcess == NULL); // W32 cleared process pointer
11638 }
11639
11640#ifdef FEATURE_INTEROP_DEBUGGING
11641 // Should we continue the process?
11642 else if (m_action == W32ETA_CONTINUE)
11643 {
11644 HandleUnmanagedContinue();
11645 }
11646#endif // FEATURE_INTEROP_DEBUGGING
11647
11648 // We don't need to sweep the FCH threads since we never hijack a thread in cooperative mode.
11649
11650
11651 // Only process an event if one is available.
11652 if (!fEventAvailable)
11653 {
11654 continue;
11655 }
11656
11657 // The only ref we have is the one in the ProcessList hash;
11658 // If we dispatch an ExitProcess event, we may even lose that.
11659 // But since the CordbProcess is our parent object, we know it won't go away until
11660 // it neuters us, so we can safely proceed.
11661 // Find the process this event is for.
11662 PREFIX_ASSUME(m_pProcess != NULL);
11663 _ASSERTE(m_pProcess->m_id == GetProcessId(&event)); // should only get events for our proc
11664 g_pRSDebuggingInfo->m_MRUprocess = m_pProcess;
11665
11666 // Must flush the dac cache since we were just running.
11667 m_pProcess->ForceDacFlush();
11668
11669 // So we've filtered out CLR events.
11670 // Let the shim handle the remaining events. This will call back into Filter() if appropriate.
11671 // This will also ensure the debug event gets continued.
11672 HRESULT hrShim = S_OK;
11673 {
11674 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(NULL);
11675 hrShim = m_pShim->HandleWin32DebugEvent(&event);
11676 }
11677 // Any errors from the shim (eg. failure to load DAC) are unrecoverable
11678 SetUnrecoverableIfFailed(m_pProcess, hrShim);
11679
11680 } // loop
11681
11682 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: exiting event loop\n"));
11683
11684 return;
11685}
11686
11687//---------------------------------------------------------------------------------------
11688//
11689// Returns if the current thread is the win32 thread.
11690//
11691// Return Value:
11692// true iff this is the win32 event thread.
11693//
11694//---------------------------------------------------------------------------------------
11695bool CordbProcess::IsWin32EventThread()
11696{
11697 _ASSERTE((m_pShim != NULL) || !"Don't check win32 event thread in V3 cases");
11698 return m_pShim->IsWin32EventThread();
11699}
11700
11701//---------------------------------------------------------------------------------------
11702// Call when the sync complete event is received and can be processed.
11703//
11704// Notes:
11705// This is called when the RS gets the sync-complete from the LS and can process it.
11706//
11707// This has a somewhat elaborate contract to fill between Interop-debugging, Async-Break, draining the
11708// managed event-queue, and coordinating with the dispatch thread (RCET).
11709//
11710// @dbgtodo - this should eventually get hoisted into the shim.
11711void CordbProcess::HandleSyncCompleteRecieved()
11712{
11713 _ASSERTE(ThreadHoldsProcessLock());
11714
11715 this->SetSyncCompleteRecv(true);
11716
11717 // If some thread is waiting for the process to sync, notify that it can go now.
11718 if (this->m_stopRequested)
11719 {
11720 this->SetSynchronized(true);
11721 SetEvent(this->m_stopWaitEvent);
11722 }
11723 else
11724 {
11725 // Note: we set the m_stopWaitEvent all the time and leave it high while we're stopped. This
11726 // must be done after we've checked m_stopRequested.
11727 SetEvent(this->m_stopWaitEvent);
11728
11729 // Otherwise, simply mark that the state of the process has changed and let the
11730 // managed event dispatch logic take over.
11731 //
11732 // Note: process->m_synchronized remains false, which indicates to the RC event
11733 // thread that it can dispatch the next managed event.
11734 m_cordb->ProcessStateChanged();
11735 }
11736}
11737
11738
11739#ifdef FEATURE_INTEROP_DEBUGGING
11740
11741//---------------------------------------------------------------------------------------
11742//
11743// Get (create if needed) the unmanaged thread for an unmanaged debug event.
11744//
11745// Arguments:
11746// event - native debug event.
11747//
11748// Return Value:
11749// Unmanaged thread corresponding to the native debug event.
11750//
11751//
11752// Notes:
11753// Thread may be newly allocated, or may be existing. CordbProcess holds
11754// list of all CordbUnmanagedThreads, and will handle freeing memory.
11755//
11756//---------------------------------------------------------------------------------------
11757CordbUnmanagedThread * CordbProcess::GetUnmanagedThreadFromEvent(const DEBUG_EVENT * pEvent)
11758{
11759 _ASSERTE(ThreadHoldsProcessLock());
11760 HRESULT hr;
11761
11762 CordbUnmanagedThread * pUnmanagedThread = NULL;
11763
11764 // Remember newly created threads.
11765 if (pEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
11766 {
11767 // We absolutely should have an unmanaged callback by this point.
11768 // That means that the client debugger should have called ICorDebug::SetUnmanagedHandler by now.
11769 // However, we can't actually enforce that (see comment in ICorDebug::SetUnmanagedHandler for details),
11770 // so we do a runtime check to check this.
11771 // This is an extremely gross API misuse and an issue in the client if the callback is not set yet.
11772 // Without the unmanaged callback, we absolutely can't do interop-debugging. We assert (checked builds) and
11773 // dispatch unrecoverable error (retail builds) to avoid an AV.
11774
11775
11776 if (this->m_cordb->m_unmanagedCallback == NULL)
11777 {
11778 CONSISTENCY_CHECK_MSGF((this->m_cordb->m_unmanagedCallback != NULL),
11779 ("GROSS API misuse!!\nNo unmanaged callback set by the time we've received CreateProcess debug event for proces 0x%x.\n",
11780 pEvent->dwProcessId));
11781
11782 CORDBSetUnrecoverableError(this, CORDBG_E_INTEROP_NOT_SUPPORTED, 0);
11783
11784 // Returning NULL will tell caller not to dispatch event to client. We have no callback object to dispatch upon.
11785 return NULL;
11786 }
11787
11788 pUnmanagedThread = this->HandleUnmanagedCreateThread(pEvent->dwThreadId,
11789 pEvent->u.CreateProcessInfo.hThread,
11790 pEvent->u.CreateProcessInfo.lpThreadLocalBase);
11791
11792 // Managed-attach won't start until after Cordbg continues from the loader-bp.
11793 }
11794 else if (pEvent->dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
11795 {
11796 pUnmanagedThread = this->HandleUnmanagedCreateThread(pEvent->dwThreadId,
11797 pEvent->u.CreateThread.hThread,
11798 pEvent->u.CreateThread.lpThreadLocalBase);
11799
11800 BOOL fBlockExists = FALSE;
11801 hr = S_OK;
11802 EX_TRY
11803 {
11804 // See if we have the debugger control block yet...
11805
11806 this->GetEventBlock(&fBlockExists);
11807
11808 // If we have the debugger control block, and if that control block has the address of the thread proc for
11809 // the helper thread, then we're initialized enough on the Left Side to recgonize the helper thread based on
11810 // its thread proc's address.
11811 if (this->GetDCB() != NULL)
11812 {
11813 // get the latest LS DCB information
11814 UpdateRightSideDCB();
11815 if ((this->GetDCB()->m_helperThreadStartAddr != NULL) && (pUnmanagedThread != NULL))
11816 {
11817 void * pStartAddr = pEvent->u.CreateThread.lpStartAddress;
11818
11819 if (pStartAddr == this->GetDCB()->m_helperThreadStartAddr)
11820 {
11821 // Remember the ID of the helper thread.
11822 this->m_helperThreadId = pEvent->dwThreadId;
11823
11824 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: Left Side Helper Thread is 0x%x\n", pEvent->dwThreadId));
11825 }
11826 }
11827 }
11828 }
11829 EX_CATCH_HRESULT(hr)
11830 {
11831 if (fBlockExists && FAILED(hr))
11832 {
11833 _ASSERTE(IsLegalFatalError(hr));
11834 // Send up the DebuggerError event
11835 this->UnrecoverableError(hr, 0, NULL, 0);
11836
11837 // Kill the process.
11838 // RS will pump events until we LS process exits.
11839 TerminateProcess(this->m_handle, hr);
11840
11841 return pUnmanagedThread;
11842 }
11843 }
11844 }
11845 else
11846 {
11847 // Find the unmanaged thread that this event is for.
11848 pUnmanagedThread = this->GetUnmanagedThread(pEvent->dwThreadId);
11849 }
11850
11851 return pUnmanagedThread;
11852}
11853
11854//---------------------------------------------------------------------------------------
11855//
11856// Handle a native-debug event representing a managed sync-complete event.
11857//
11858//
11859// Return Value:
11860// Reaction telling caller how to respond to the native-debug event.
11861//
11862// Assumptions:
11863// Called within the Triage process after receiving a native-debug event.
11864//
11865//---------------------------------------------------------------------------------------
11866Reaction CordbProcess::TriageSyncComplete()
11867{
11868 _ASSERTE(ThreadHoldsProcessLock());
11869
11870 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TSC: received 'sync complete' flare.\n");
11871
11872 _ASSERTE(IsInteropDebugging());
11873
11874 // Note: we really don't need to be suspending Runtime threads that we know have tripped
11875 // here. If we ever end up with a nice, quick way to know that about each unmanaged thread, then
11876 // we should put that to good use here.
11877 this->SuspendUnmanagedThreads();
11878
11879 this->HandleSyncCompleteRecieved();
11880
11881 // Let the process run free.
11882 return REACTION(cIgnore);
11883
11884 // At this point, all managed threads are stopped at safe places and all unmanaged
11885 // threads are either suspended or hijacked. All stopped managed threads are also hard
11886 // suspended (due to the call to SuspendUnmanagedThreads above) except for the thread
11887 // that sent the sync complete flare.
11888
11889 // We've handled this exception, so skip all further processing.
11890 UNREACHABLE();
11891}
11892
11893//-----------------------------------------------------------------------------
11894// Triage a breakpoint (non-flare) on a "normal" thread.
11895//-----------------------------------------------------------------------------
11896Reaction CordbProcess::TriageBreakpoint(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent)
11897{
11898 _ASSERTE(ThreadHoldsProcessLock());
11899
11900 HRESULT hr = S_OK;
11901
11902 DWORD dwExCode = pEvent->u.Exception.ExceptionRecord.ExceptionCode;
11903 const void * pExAddress = pEvent->u.Exception.ExceptionRecord.ExceptionAddress;
11904
11905 _ASSERTE(dwExCode == STATUS_BREAKPOINT);
11906
11907 // There are three cases here:
11908 //
11909 // 1. The breakpoint definetly belongs to the Runtime. (I.e., a BP in our patch table that
11910 // is in managed code.) In this case, we continue the process with
11911 // DBG_EXCEPTION_NOT_HANDLED, which lets the in-process exception logic kick in as if we
11912 // weren't here.
11913 //
11914 // 2. The breakpoint is definetly not ours. (I.e., a BP that is not in our patch table.) We
11915 // pass these up as regular exception events, doing the can't stop check as usual.
11916 //
11917 // 3. We're not sure. (I.e., a BP in our patch table, but set in unmangaed code.) In this
11918 // case, we hijack as usual, also with can't stop check as usual.
11919
11920 bool fPatchFound = false;
11921 bool fPatchIsUnmanaged = false;
11922
11923 hr = this->FindPatchByAddress(PTR_TO_CORDB_ADDRESS(pExAddress),
11924 &fPatchFound,
11925 &fPatchIsUnmanaged);
11926
11927 if (SUCCEEDED(hr))
11928 {
11929 if (fPatchFound)
11930 {
11931#ifdef _DEBUG
11932 // What if managed & native patch the same address? That could happen on a step out M --> U.
11933 {
11934 NativePatch * pNativePatch = GetNativePatch(pExAddress);
11935 SIMPLIFYING_ASSUMPTION_MSGF(pNativePatch == NULL, ("Have Managed & native patch at 0x%p", pExAddress));
11936 }
11937#endif
11938
11939 // BP could be ours... if its unmanaged, then we still need to hijack, so fall
11940 // through to that logic. Otherwise, its ours.
11941 if (!fPatchIsUnmanaged)
11942 {
11943 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: breakpoint exception "
11944 "belongs to runtime due to patch table match.\n"));
11945
11946 return REACTION(cCLR);
11947 }
11948 else
11949 {
11950 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: breakpoint exception "
11951 "matched in patch table, but its unmanaged so might hijack anyway.\n"));
11952
11953 // If we're in cooperative mode, then we must have a inproc handler, and don't need to hijack
11954 // One way this can happen is the patch placed for a func-eval complete is hit in coop-mode.
11955 if (pUnmanagedThread->GetEEPGCDisabled())
11956 {
11957 LOG((LF_CORDB, LL_INFO10000, "Already in coop-mode, don't need to hijack\n"));
11958 return REACTION(cCLR);
11959 }
11960 else
11961 {
11962 return REACTION(cBreakpointRequiringHijack);
11963 }
11964 }
11965
11966 UNREACHABLE();
11967 }
11968 else // Patch not found
11969 {
11970 // If we're here, then we have a BP that's not in the managed patch table, and not
11971 // in the native patch list. This should be rare. Perhaps an int3 / DebugBreak() / Assert in
11972 // the native code stream.
11973 // Anyway, we don't know about this patch so we can't skip it. The only thing we can do
11974 // is chuck it up to Cordbg and hope they can help us. Note that this is the same case
11975 // we were in w. V1.
11976
11977 // BP doesn't belong to CLR ... so dispatch it to Cordbg as either make it IB or OOB.
11978 // @todo - make the runtime 1 giant Can't stop region.
11979 bool fCantStop = pUnmanagedThread->IsCantStop();
11980
11981#ifdef _DEBUG
11982 // We rarely expect a raw int3 here. Add a debug check that will assert.
11983 // Tests that know they don't have raw int3 can enable this regkey to get
11984 // extra coverage.
11985 static DWORD s_fBreakOnRawInt3 = -1;
11986
11987 if (s_fBreakOnRawInt3 == -1)
11988 s_fBreakOnRawInt3 = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgBreakOnRawInt3);
11989
11990 if (s_fBreakOnRawInt3)
11991 {
11992 CONSISTENCY_CHECK_MSGF(false, ("Unexpected Raw int3 at:%p on tid 0x%x (%d). CantStop=%d."
11993 "This assert is used by specific tests to get extra checks."
11994 "For normal cases it's ignorable and is enabled by setting DbgBreakOnRawInt3==1.",
11995 pExAddress, pEvent->dwThreadId, pEvent->dwThreadId, fCantStop));
11996 }
11997#endif
11998
11999 if (fCantStop)
12000 {
12001 // If we're in a can't stop region, then its OOB no matter what at this point.
12002 return REACTION(cOOB);
12003 }
12004 else
12005 {
12006 // PGC must be enabled if we're going to stop for an IB event.
12007 bool PGCDisabled = pUnmanagedThread->GetEEPGCDisabled();
12008 _ASSERTE(!PGCDisabled);
12009
12010 // Bp is definitely not ours, and PGC is not disabled, so in-band exception.
12011 LOG((LF_CORDB, LL_INFO1000, "W32ET::W32EL: breakpoint exception "
12012 "does not belong to the runtime due to failed patch table match.\n"));
12013
12014 return REACTION(cInband);
12015 }
12016
12017 UNREACHABLE();
12018 }
12019
12020 UNREACHABLE();
12021 }
12022 else
12023 {
12024 // Patch table lookup failed? Only on OOM or if ReadProcessMemory fails...
12025 _ASSERTE(!"Patch table lookup failed!");
12026 CORDBSetUnrecoverableError(this, hr, 0);
12027 return REACTION(cOOB);
12028 }
12029
12030 UNREACHABLE();
12031}
12032
12033//---------------------------------------------------------------------------------------
12034//
12035// Triage a "normal" 1st chance exception on a "normal" thread.
12036// Not hijacked, not the helper thread, not a flare, etc.. This is the common
12037// case for a native exception from native code.
12038//
12039// Arguments:
12040// pUnmanagedThread - Pointer to the CordbUnmanagedThread object that we want to hijack.
12041// pEvent - Pointer to the debug event which contains the exception code and address.
12042//
12043// Return Value:
12044// The Reaction tells if the event is in-band, out-of-band, CLR specific or ignorable.
12045//
12046//---------------------------------------------------------------------------------------
12047Reaction CordbProcess::Triage1stChanceNonSpecial(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent)
12048{
12049 _ASSERTE(ThreadHoldsProcessLock());
12050 CONTRACTL
12051 {
12052 THROWS;
12053 }
12054 CONTRACTL_END;
12055
12056 HRESULT hr = S_OK;
12057
12058 DWORD dwExCode = pEvent->u.Exception.ExceptionRecord.ExceptionCode;
12059 const void * pExAddress = pEvent->u.Exception.ExceptionRecord.ExceptionAddress;
12060
12061 // This had better not be a flare. If it is, that means we have some race that unmarked
12062 // the hijacks.
12063 _ASSERTE(!ExceptionIsFlare(dwExCode, pExAddress));
12064
12065 // Any first chance exception could belong to the Runtime, so long as the Runtime has actually been
12066 // initialized. Here we'll setup a first-chance hijack for this thread so that it can give us the
12067 // true answer that we need.
12068
12069 // But none of those exceptions could possibly be ours unless we have a managed thread to go with
12070 // this unmanaged thread. A non-NULL EEThreadPtr tells us that there is indeed a managed thread for
12071 // this unmanaged thread, even if the Right Side hasn't received a managed ThreadCreate message yet.
12072 REMOTE_PTR pEEThread;
12073 hr = pUnmanagedThread->GetEEThreadPtr(&pEEThread);
12074 _ASSERTE(SUCCEEDED(hr));
12075
12076 if (pEEThread == NULL)
12077 {
12078 // No managed thread, so it can't possibly belong to the runtime!
12079 // But it may still be in a can't-stop region (think some goofy shutdown case).
12080 if (pUnmanagedThread->IsCantStop())
12081 {
12082 return REACTION(cOOB);
12083 }
12084 else
12085 {
12086 return REACTION(cInband);
12087 }
12088 }
12089
12090
12091
12092 // We have to be careful here. A Runtime thread may be in a place where we cannot let an
12093 // unmanaged exception stop it. For instance, an unmanaged user breakpoint set on
12094 // WaitForSingleObject will prevent Runtime threads from sending events to the Right Side. So at
12095 // various points below, we check to see if this Runtime thread is in a place were we can't let
12096 // it stop, and if so then we jump over to the out-of-band dispatch logic and treat this
12097 // exception as out-of-band. The debugger is supposed to continue from the out-of-band event
12098 // properly and help us avoid this problem altogether.
12099
12100 // Grab a few flags from the thread's state...
12101 bool fThreadStepping = false;
12102 bool fSpecialManagedException = false;
12103
12104 pUnmanagedThread->GetEEState(&fThreadStepping, &fSpecialManagedException);
12105
12106 // If we've got a single step exception, and if the Left Side has indicated that it was
12107 // stepping the thread, then the exception is ours.
12108 if (dwExCode == STATUS_SINGLE_STEP)
12109 {
12110 if (fThreadStepping)
12111 {
12112 // Yup, its the Left Side that was stepping the thread...
12113 STRESS_LOG0(LF_CORDB, LL_INFO1000, "W32ET::W32EL: single step exception belongs to the runtime.\n");
12114
12115 return REACTION(cCLR);
12116 }
12117
12118 // Any single step that is triggered when the thread's state doesn't indicate that
12119 // we were stepping the thread automatically gets passed out as an unmanged event.
12120 STRESS_LOG0(LF_CORDB, LL_INFO1000, "W32ET::W32EL: single step exception "
12121 "does not belong to the runtime.\n");
12122
12123 if (pUnmanagedThread->IsCantStop())
12124 {
12125 return REACTION(cOOB);
12126 }
12127 else
12128 {
12129 return REACTION(cInband);
12130 }
12131
12132 UNREACHABLE();
12133 }
12134
12135#ifdef CorDB_Short_Circuit_First_Chance_Ownership
12136 // If the runtime indicates that this is a special exception being thrown within the runtime,
12137 // then its ours no matter what.
12138 else if (fSpecialManagedException)
12139 {
12140 STRESS_LOG0(LF_CORDB, LL_INFO1000, "W32ET::W32EL: exception belongs to the runtime due to "
12141 "special managed exception marking.\n");
12142
12143 return REACTION(cCLR);
12144 }
12145 else if ((dwExCode == EXCEPTION_COMPLUS) || (dwExCode == EXCEPTION_HIJACK))
12146 {
12147 STRESS_LOG0(LF_CORDB, LL_INFO1000,
12148 "W32ET::W32EL: exception belongs to Runtime due to match on built in exception code\n");
12149
12150 return REACTION(cCLR);
12151 }
12152 else if (dwExCode == EXCEPTION_MSVC)
12153 {
12154 // The runtime may use C++ exceptions internally. We can still report these
12155 // to the debugger as long as we're outside of a can't-stop region.
12156 if (pUnmanagedThread->IsCantStop())
12157 {
12158 return REACTION(cCLR);
12159 }
12160 else
12161 {
12162 return REACTION(cInband);
12163 }
12164 }
12165 else if (dwExCode == STATUS_BREAKPOINT)
12166 {
12167 return TriageBreakpoint(pUnmanagedThread, pEvent);
12168 }// end BP case
12169#endif
12170
12171 // It's not a breakpoint or single-step. Now it just comes down to the address from where
12172 // the exception is coming from. If it's managed, we give it back to the CLR. If it's
12173 // from native, then we dispatch to Cordbg.
12174 // We can use DAC to figure this out from Out-of-process.
12175 _ASSERTE(dwExCode != STATUS_BREAKPOINT); // BP were already handled.
12176
12177
12178 // Use DAC to decide if it's ours or not w/o going inproc.
12179 CORDB_ADDRESS address = PTR_TO_CORDB_ADDRESS(pExAddress);
12180
12181 IDacDbiInterface::AddressType addrType;
12182
12183 addrType = GetDAC()->GetAddressType(address);
12184 bool fIsCorCode =((addrType == IDacDbiInterface::kAddressManagedMethod) ||
12185 (addrType == IDacDbiInterface::kAddressRuntimeManagedCode) ||
12186 (addrType == IDacDbiInterface::kAddressRuntimeUnmanagedCode));
12187
12188 STRESS_LOG2(LF_CORDB, LL_INFO1000, "W32ET::W32EL: IsCorCode(0x%I64p)=%d\n", address, fIsCorCode);
12189
12190
12191 if (fIsCorCode)
12192 {
12193 return REACTION(cCLR);
12194 }
12195 else
12196 {
12197 if (pUnmanagedThread->IsCantStop())
12198 {
12199 return REACTION(cOOB);
12200 }
12201 else
12202 {
12203 return REACTION(cInband);
12204 }
12205 }
12206
12207 UNREACHABLE();
12208}
12209
12210//---------------------------------------------------------------------------------------
12211//
12212// Triage a 1st-chance exception when the CLR is initialized.
12213//
12214// Arguments:
12215// pUnmanagedThread - thread that the event has occurred on.
12216// pEvent - native debug event for the exception that occurred that this is triaging.
12217//
12218// Return Value:
12219// Reaction for how to handle this event.
12220//
12221// Assumptions:
12222// Called when receiving a debug event when the process is stopped.
12223//
12224// Notes:
12225// A 1st-chance event has a wide spectrum of possibility including:
12226// - It may be unmanaged or managed.
12227// - Or it may be an execution control exception for managed-exceution
12228// - thread skipping an OOB event.
12229//
12230//---------------------------------------------------------------------------------------
12231Reaction CordbProcess::TriageExcep1stChanceAndInit(CordbUnmanagedThread * pUnmanagedThread,
12232 const DEBUG_EVENT * pEvent)
12233{
12234 _ASSERTE(ThreadHoldsProcessLock());
12235 _ASSERTE(m_runtimeOffsetsInitialized);
12236
12237 NativePatch * pNativePatch = NULL;
12238 DebuggerIPCRuntimeOffsets * pIPCRuntimeOffsets = &(this->m_runtimeOffsets);
12239
12240 DWORD dwExCode = pEvent->u.Exception.ExceptionRecord.ExceptionCode;
12241 const void * pExAddress = pEvent->u.Exception.ExceptionRecord.ExceptionAddress;
12242
12243 LOG((LF_CORDB, LL_INFO1000, "CP::TE1stCAI: Enter\n"));
12244
12245#ifdef _DEBUG
12246 // Some Interop bugs involve threads that land at a crazy IP. Since we're interop-debugging, we can't
12247 // attach a debugger to the LS. So we have some debug mode where we enable the SS flag and thus
12248 // produce a trace of where a thread is going.
12249 if (pUnmanagedThread->IsDEBUGTrace() && (dwExCode == STATUS_SINGLE_STEP))
12250 {
12251 pUnmanagedThread->ClearState(CUTS_DEBUG_SingleStep);
12252 LOG((LF_CORDB, LL_INFO10000, "DEBUG TRACE, thread %4x at IP: 0x%p\n", pUnmanagedThread->m_id, pExAddress));
12253
12254 // Clear the exception and pretend this never happened.
12255 return REACTION(cIgnore);
12256 }
12257#endif
12258
12259 // If we were stepping for exception retrigger and got the single step and it should be hidden then just ignore it.
12260 // Anything that isn't cInbandExceptionRetrigger will cause the debug event to be dequeued, stepping turned off, and
12261 // it will count as not retriggering
12262 // TODO: I don't think the IsSSFlagNeeded() check is needed here though it doesn't break anything
12263 if (pUnmanagedThread->IsSSFlagNeeded() && pUnmanagedThread->IsSSFlagHidden() && (dwExCode == STATUS_SINGLE_STEP))
12264 {
12265 LOG((LF_CORDB, LL_INFO10000, "CP::TE1stCAI: ignoring hidden single step\n"));
12266 return REACTION(cIgnore);
12267 }
12268
12269 // Is this a breakpoint indicating that the Left Side is now synchronized?
12270 if ((dwExCode == STATUS_BREAKPOINT) &&
12271 (pExAddress == pIPCRuntimeOffsets->m_notifyRSOfSyncCompleteBPAddr))
12272 {
12273 return TriageSyncComplete();
12274 }
12275 else if ((dwExCode == STATUS_BREAKPOINT) &&
12276 (pExAddress == pIPCRuntimeOffsets->m_excepForRuntimeHandoffCompleteBPAddr))
12277 {
12278 _ASSERTE(!"This should be unused now");
12279
12280 // This notification means that a thread that had been first-chance hijacked is now
12281 // finally leaving the hijack.
12282 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: received 'first chance hijack handoff complete' flare.\n");
12283
12284 // Let the process run.
12285 return REACTION(cIgnore);
12286 }
12287 else if ((dwExCode == STATUS_BREAKPOINT) &&
12288 (pExAddress == pIPCRuntimeOffsets->m_signalHijackCompleteBPAddr))
12289 {
12290 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: received 'hijack complete' flare.\n");
12291 return REACTION(cInbandHijackComplete);
12292 }
12293 else if ((dwExCode == STATUS_BREAKPOINT) &&
12294 (pExAddress == m_runtimeOffsets.m_signalHijackStartedBPAddr))
12295 {
12296 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: received 'hijack started' flare.\n");
12297 return REACTION(cFirstChanceHijackStarted);
12298 }
12299 else if ((dwExCode == STATUS_BREAKPOINT) && ((pNativePatch = GetNativePatch(pExAddress)) != NULL) )
12300 {
12301 // We hit a native BP placed by Cordbg. This could happen on any thread (including helper)
12302 bool fCantStop = pUnmanagedThread->IsCantStop();
12303
12304 // REVISIT_TODO: if the user also set a breakpoint here then we should dispatch to the debugger
12305 // and rely on the debugger to get us past this. Should be a rare case though.
12306 if (fCantStop)
12307 {
12308 // Need to skip it completely; never dispatch.
12309 pUnmanagedThread->SetupForSkipBreakpoint(pNativePatch);
12310
12311 // Debuggee will single step over the patch, and fire a SS exception.
12312 // We'll then call FixupForSkipBreakpoint, and continue the process.
12313 return REACTION(cIgnore);
12314 }
12315 else
12316 {
12317 // Native patch in native code. A very common scenario.
12318 // Dispatch as an IB event to Cordbg.
12319 STRESS_LOG1(LF_CORDB, LL_INFO10000, "Native patch in native code (at %p), dispatching as IB event.\n", pExAddress);
12320 return REACTION(cInband);
12321 }
12322
12323 UNREACHABLE();
12324 }
12325
12326 else if ((dwExCode == STATUS_BREAKPOINT) && !IsBreakOpcodeAtAddress(pExAddress))
12327 {
12328 // If we got an int3 exception, but there's not actually an int3 at the address, then just reset the IP
12329 // to the address. This can happen if the int 3 is cleared after the thread has dispatched it (in which case
12330 // WFDE will pick it up) but before we realize it's one of ours.
12331 STRESS_LOG2(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: Phantom Int3: Tid=0x%x, addr=%p\n", pEvent->dwThreadId, pExAddress);
12332
12333 DT_CONTEXT context;
12334
12335 context.ContextFlags = DT_CONTEXT_FULL;
12336
12337 BOOL fSuccess = DbiGetThreadContext(pUnmanagedThread->m_handle, &context);
12338
12339 _ASSERTE(fSuccess);
12340
12341 if (fSuccess)
12342 {
12343 // Backup IP to point to the instruction we need to execute. Continuing from a breakpoint exception
12344 // continues execution at the instruction after the breakpoint, but we need to continue where the
12345 // breakpoint was.
12346 CORDbgSetIP(&context, (LPVOID) pExAddress);
12347
12348 fSuccess = DbiSetThreadContext(pUnmanagedThread->m_handle, &context);
12349 _ASSERTE(fSuccess);
12350 }
12351
12352 return REACTION(cIgnore);
12353 }
12354 else if (pUnmanagedThread->IsSkippingNativePatch())
12355 {
12356 // If we Single-Step over an exception, then the OS never gives us the single-step event.
12357 // Thus if we're skipping a native patch, we don't care what exception event we got.
12358 LOG((LF_CORDB, LL_INFO100000, "Done skipping native patch. Ex=0x%x\n, IsSS=%d",
12359 dwExCode,
12360 (dwExCode == STATUS_SINGLE_STEP)));
12361
12362 // This is the 2nd half of skipping a native patch.
12363 // This could happen on any thread (including helper)
12364 // We've already removed the opcode and now we just finished a single-step over it.
12365 // So put the patch back in, and continue the process.
12366 pUnmanagedThread->FixupForSkipBreakpoint();
12367
12368 return REACTION(cIgnore);
12369 }
12370 else if (this->IsHelperThreadWorked(pUnmanagedThread->GetOSTid()))
12371 {
12372 // We should never ever get a single-step event from the helper thread.
12373 CONSISTENCY_CHECK_MSGF(dwExCode != STATUS_SINGLE_STEP, (
12374 "Single-Step exception on helper thread (tid=0x%x/%d) in debuggee process (pid=0x%x/%d).\n"
12375 "For more information, attach a debuggee non-invasively to the LS to get the callstack.\n",
12376 pUnmanagedThread->m_id,
12377 pUnmanagedThread->m_id,
12378 this->m_id,
12379 this->m_id));
12380
12381 // We ignore any first chance exceptions from the helper thread. There are lots of places
12382 // on the left side where we attempt to dereference bad object refs and such that will be
12383 // handled by exception handlers already in place.
12384 //
12385 // Note: we check this after checking for the sync complete notification, since that can
12386 // come from the helper thread.
12387 //
12388 // Note: we do let single step and breakpoint exceptions go through to the debugger for processing.
12389 if ((dwExCode != STATUS_BREAKPOINT) && (dwExCode != STATUS_SINGLE_STEP))
12390 {
12391 return REACTION(cCLR);
12392 }
12393 else
12394 {
12395 // Since the helper thread is part of the "can't stop" region, we should have already
12396 // skipped any BPs on it.
12397 // However, any Assert on the helper thread will hit this case.
12398 CONSISTENCY_CHECK_MSGF((dwExCode != STATUS_BREAKPOINT), (
12399 "Assert on helper thread (tid=0x%x/%d) in debuggee process (pid=0x%x/%d).\n"
12400 "For more information, attach a debuggee non-invasively to the LS to get the callstack.\n",
12401 pUnmanagedThread->m_id,
12402 pUnmanagedThread->m_id,
12403 this->m_id,
12404 this->m_id));
12405
12406 // These breakpoint and single step exceptions have to be dispatched to the debugger as
12407 // out-of-band events. This tells the debugger that they must continue from these events
12408 // immediatly, and that no interaction with the Left Side is allowed until they do so. This
12409 // makes sense, since these events are on the helper thread.
12410 return REACTION(cOOB);
12411 }
12412 UNREACHABLE();
12413 }
12414 else if (pUnmanagedThread->IsFirstChanceHijacked() && this->ExceptionIsFlare(dwExCode, pExAddress))
12415 {
12416 _ASSERTE(!"This should be unused now");
12417 }
12418 else if (pUnmanagedThread->IsGenericHijacked())
12419 {
12420 if (this->ExceptionIsFlare(dwExCode, pExAddress))
12421 {
12422 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: fixing up from generic hijack.\n");
12423
12424 _ASSERTE(dwExCode == STATUS_BREAKPOINT);
12425
12426 // Fixup the thread from the generic hijack.
12427 pUnmanagedThread->FixupFromGenericHijack();
12428
12429 // We force continue from this flare, since its only purpose was to notify us that we had to
12430 // fixup the thread from a generic hijack.
12431 return REACTION(cIgnore);
12432 }
12433 else
12434 {
12435 // We might reach here due to the stack overflow issue, due to target
12436 // memory corruption, or even due to an exception thrown during hijacking
12437
12438 BOOL bStackOverflow = FALSE;
12439
12440 if (dwExCode == STATUS_ACCESS_VIOLATION || dwExCode == STATUS_STACK_OVERFLOW)
12441 {
12442 CORDB_ADDRESS stackLimit;
12443 CORDB_ADDRESS stackBase;
12444 if (pUnmanagedThread->GetStackRange(&stackBase, &stackLimit))
12445 {
12446 TADDR addr = pEvent->u.Exception.ExceptionRecord.ExceptionInformation[1];
12447 if (stackLimit <= addr && addr < stackBase)
12448 bStackOverflow = TRUE;
12449 }
12450 else
12451 {
12452 // to limit the impact of the change we'll consider failure to retrieve the stack
12453 // bounds as stack overflow as well
12454 bStackOverflow = TRUE;
12455 }
12456 }
12457
12458 if (!bStackOverflow)
12459 {
12460 // generic hijack means we're in CantStop, so return cOOB
12461 return REACTION(cOOB);
12462 }
12463
12464 // If generichijacked and its not a flare, and the address referenced is on the stack then we've
12465 // got our special stack overflow case. Take off generic hijacked, mark that the helper thread
12466 // is dead, throw this event on the floor, and pop anyone in SendIPCEvent out of their wait.
12467 pUnmanagedThread->ClearState(CUTS_GenericHijacked);
12468
12469 this->m_helperThreadDead = true;
12470
12471 // This only works on Windows, not on Mac. We don't support interop-debugging on Mac anyway.
12472 SetEvent(m_pEventChannel->GetRightSideEventAckHandle());
12473
12474 // Note: we remember that this was a second chance event from one of the special stack overflow
12475 // cases with CUES_ExceptionUnclearable. This tells us to force the process to terminate when we
12476 // continue from the event. Since for some odd reason the OS decides to re-raise this exception
12477 // (first chance then second chance) infinitely.
12478
12479 _ASSERTE(pUnmanagedThread->HasIBEvent());
12480
12481 pUnmanagedThread->IBEvent()->SetState(CUES_ExceptionUnclearable);
12482
12483 //newEvent = false;
12484 return REACTION(cInband_NotNewEvent);
12485 }
12486 }
12487 else
12488 {
12489 LOG((LF_CORDB, LL_INFO1000, "CP::TE1stCAI: Triage1stChanceNonSpecial\n"));
12490
12491 Reaction r(REACTION(cOOB));
12492 HRESULT hrCheck = S_OK;;
12493 EX_TRY
12494 {
12495 r = Triage1stChanceNonSpecial(pUnmanagedThread, pEvent);
12496 }
12497 EX_CATCH_HRESULT(hrCheck);
12498 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hrCheck));
12499 SetUnrecoverableIfFailed(this, hrCheck);
12500
12501 return r;
12502
12503 }
12504
12505 // At this point, any first-chance exceptions that could be special have been handled. Any
12506 // first-chance exception that we're still processing at this point is destined to be
12507 // dispatched as an unmanaged event.
12508 UNREACHABLE();
12509}
12510
12511
12512//---------------------------------------------------------------------------------------
12513//
12514// Triage a 2nd-chance exception when the CLR is initialized.
12515//
12516// Arguments:
12517// pUnmanagedThread - thread that the event has occurred on.
12518// pEvent - native debug event for the exception that occurred that this is triaging.
12519//
12520// Return Value:
12521// Reaction for how to handle this event.
12522//
12523// Assumptions:
12524// Called when receiving a debug event when the process is stopped.
12525//
12526// Notes:
12527// We already hijacked 2nd-chance managed exceptions, so this is just handling
12528// some V2 Interop corner cases.
12529// @dbgtodo interop: this should eventually completely go away with the V3 design.
12530//
12531//---------------------------------------------------------------------------------------
12532Reaction CordbProcess::TriageExcep2ndChanceAndInit(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent)
12533{
12534 _ASSERTE(ThreadHoldsProcessLock());
12535
12536 DWORD dwExCode = pEvent->u.Exception.ExceptionRecord.ExceptionCode;
12537
12538#ifdef _DEBUG
12539 // For debugging, add an extra knob that let us break on any 2nd chance exceptions.
12540 // Most tests don't throw 2nd-chance, so we could have this enabled most of the time and
12541 // catch bogus 2nd chance exceptions
12542 static DWORD dwNo2ndChance = -1;
12543
12544 if (dwNo2ndChance == -1)
12545 {
12546 dwNo2ndChance = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgNo2ndChance);
12547 }
12548
12549 if (dwNo2ndChance)
12550 {
12551 CONSISTENCY_CHECK_MSGF(false, ("2nd chance exception occurred on LS thread=0x%x, code=0x%08x, address=0x%p\n"
12552 "This assert is firing b/c you explicitly requested it by having the 'DbgNo2ndChance' knob enabled.\n"
12553 "Disable it to avoid asserts on 2nd chance.",
12554 pUnmanagedThread->m_id,
12555 dwExCode,
12556 pEvent->u.Exception.ExceptionRecord.ExceptionAddress));
12557 }
12558#endif
12559
12560
12561 // Second chance exception, Runtime initialized. It could belong to the Runtime, so we'll check. If it
12562 // does, then we'll hijack the thread. Otherwise, well just fall through and let it get
12563 // dispatched. Note: we do this so that the CLR's unhandled exception logic gets a chance to run even
12564 // though we've got a win32 debugger attached. But the unhandled exception logic never touches
12565 // breakpoint or single step exceptions, so we ignore those here, too.
12566
12567 // There are strange cases with stack overflow exceptions. If a nieve application catches a stack
12568 // overflow exception and handles it, without resetting the guard page, then the app will get an AV when
12569 // it overflows the stack a second time. We will get the first chance AV, but when we continue from it the
12570 // OS won't run any SEH handlers, so our FCH won't actually work. Instead, we'll get the AV back on
12571 // second chance right away, and we'll end up right here.
12572 if (this->IsSpecialStackOverflowCase(pUnmanagedThread, pEvent))
12573 {
12574 // IsSpecialStackOverflowCase will queue the event for us, so its no longer a "new event". Setting
12575 // newEvent = false here basically prevents us from playing with the event anymore and we fall down
12576 // to the dispatch logic below, which will get our already queued first chance AV dispatched for
12577 // this thread.
12578 //newEvent = false;
12579 return REACTION(cInband_NotNewEvent);
12580 }
12581 else if (this->IsHelperThreadWorked(pUnmanagedThread->GetOSTid()))
12582 {
12583 // A second chance exception from the helper thread. This is pretty bad... we just force continue
12584 // from them and hope for the best.
12585 return REACTION(cCLR);
12586 }
12587
12588 if(pUnmanagedThread->IsCantStop())
12589 {
12590 return REACTION(cOOB);
12591 }
12592 else
12593 {
12594 return REACTION(cInband);
12595 }
12596}
12597
12598
12599//---------------------------------------------------------------------------------------
12600//
12601// Triage a win32 Debug event to get a reaction
12602//
12603// Arguments:
12604// pUnmanagedThread - thread that the event has occurred on.
12605// pEvent - native debug event for the exception that occurred that this is triaging.
12606//
12607// Return Value:
12608// Reaction for how to handle this event.
12609//
12610// Assumptions:
12611// Called when receiving a debug event when the process is stopped.
12612//
12613// Notes:
12614// This is the main triage routine for Win32 debug events, this delegates to the
12615// 1st and 2nd chance routines above appropriately.
12616//
12617//---------------------------------------------------------------------------------------
12618Reaction CordbProcess::TriageWin32DebugEvent(CordbUnmanagedThread * pUnmanagedThread, const DEBUG_EVENT * pEvent)
12619{
12620 _ASSERTE(ThreadHoldsProcessLock());
12621
12622 // Lots of special cases for exception events. The vast majority of hybrid debugging work that takes
12623 // place is in response to exception events. The work below will consider certian exception events
12624 // special cases and rather than letting them be queued and dispatched, they will be handled right
12625 // here.
12626 if (pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
12627 {
12628 STRESS_LOG4(LF_CORDB, LL_INFO1000, "CP::TW32DE: unmanaged exception on "
12629 "tid 0x%x, code 0x%08x, addr 0x%08x, chance %d\n",
12630 pEvent->dwThreadId,
12631 pEvent->u.Exception.ExceptionRecord.ExceptionCode,
12632 pEvent->u.Exception.ExceptionRecord.ExceptionAddress,
12633 2-pEvent->u.Exception.dwFirstChance);
12634
12635#ifdef LOGGING
12636 if (pEvent->u.Exception.ExceptionRecord.ExceptionCode == STATUS_ACCESS_VIOLATION)
12637 {
12638 LOG((LF_CORDB, LL_INFO1000, "\t<%s> address 0x%08x\n",
12639 pEvent->u.Exception.ExceptionRecord.ExceptionInformation[0] ? "write to" : "read from",
12640 pEvent->u.Exception.ExceptionRecord.ExceptionInformation[1]));
12641 }
12642#endif
12643
12644 // Mark the loader bp for kicks. We won't start managed attach until native attach is finished.
12645 if (!this->m_loaderBPReceived)
12646 {
12647 // If its a first chance breakpoint, and its the first one, then its the loader breakpoint.
12648 if (pEvent->u.Exception.dwFirstChance &&
12649 (pEvent->u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT))
12650 {
12651 LOG((LF_CORDB, LL_INFO1000, "CP::TW32DE: loader breakpoint received.\n"));
12652
12653 // Remember that we've received the loader BP event.
12654 this->m_loaderBPReceived = true;
12655
12656 // We never hijack the loader BP anymore (CLR 2.0+).
12657 // This is b/c w/ interop-attach, we don't start the managed-attach until _after_ Cordbg
12658 // continues from the loader-bp.
12659 }
12660 } // end of loader bp.
12661
12662 // This event might be the retriggering of an event we already saw but previously had to hijack
12663 if(pUnmanagedThread->HasIBEvent())
12664 {
12665 const EXCEPTION_RECORD* pRecord1 = &(pEvent->u.Exception.ExceptionRecord);
12666 const EXCEPTION_RECORD* pRecord2 = &(pUnmanagedThread->IBEvent()->m_currentDebugEvent.u.Exception.ExceptionRecord);
12667 if(pRecord1->ExceptionCode == pRecord2->ExceptionCode &&
12668 pRecord1->ExceptionFlags == pRecord2->ExceptionFlags &&
12669 pRecord1->ExceptionAddress == pRecord2->ExceptionAddress)
12670 {
12671 STRESS_LOG0(LF_CORDB, LL_INFO1000, "CP::TW32DE: event is continuation of previously hijacked event.\n");
12672 // if we continued from the hijack then we should have already dispatched this event
12673 _ASSERTE(pUnmanagedThread->IBEvent()->IsDispatched());
12674 return REACTION(cInbandExceptionRetrigger);
12675 }
12676 }
12677
12678 // We only care about exception events if they are first chance events and if the Runtime is
12679 // initialized within the process. Otherwise, we don't do anything special with them.
12680 if (pEvent->u.Exception.dwFirstChance && this->m_initialized)
12681 {
12682 return TriageExcep1stChanceAndInit(pUnmanagedThread, pEvent);
12683 }
12684 else if (!pEvent->u.Exception.dwFirstChance && this->m_initialized)
12685 {
12686 return TriageExcep2ndChanceAndInit(pUnmanagedThread, pEvent);
12687 }
12688 else
12689 {
12690 // An exception event, but the Runtime hasn't been initialize. I.e., its an exception event
12691 // that we will never try to hijack.
12692 return REACTION(cInband);
12693 }
12694
12695 UNREACHABLE();
12696 }
12697 else
12698 // OOB
12699 {
12700 return REACTION(cOOB);
12701 }
12702
12703}
12704
12705//---------------------------------------------------------------------------------------
12706//
12707// Top-level handler for a win32 debug event during Interop-debugging.
12708//
12709// Arguments:
12710// event - native debug event to handle.
12711//
12712// Assumptions:
12713// The process just got a native debug event via WaitForDebugEvent
12714//
12715// Notes:
12716// The function will Triage the excpetion and then handle it based on the
12717// appropriate reaction (see: code:Reaction).
12718//
12719// @dbgtodo interop: this should all go into the shim.
12720//---------------------------------------------------------------------------------------
12721void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEvent)
12722{
12723 PUBLIC_API_ENTRY_FOR_SHIM(this);
12724 _ASSERTE(IsInteropDebugging() || !"Only do this in real interop handling path");
12725
12726
12727 STRESS_LOG3(LF_CORDB, LL_INFO1000, "W32ET::W32EL: got unmanaged event %d on thread 0x%x, proc 0x%x\n",
12728 pEvent->dwDebugEventCode, pEvent->dwThreadId, pEvent->dwProcessId);
12729
12730 // Get the Lock.
12731 _ASSERTE(!this->ThreadHoldsProcessLock());
12732
12733 RSSmartPtr<CordbProcess> pRef(this); // make sure we're alive...
12734
12735 RSLockHolder processLockHolder(&this->m_processMutex);
12736
12737 // If we get a new Win32 Debug event, then we need to flush any cached oop data structures.
12738 // This includes refreshing DAC and our patch table.
12739 ForceDacFlush();
12740 ClearPatchTable();
12741
12742#ifdef _DEBUG
12743 // We want to detect if we've deadlocked. Unfortunately, w/ interop debugging, there can be a lot of
12744 // deadtime since we need to wait for a debug event. Thus the CPU usage may appear to be at 0%, but
12745 // we're not deadlocked b/c we're still receiving debug events.
12746 // So ping every X debug events.
12747 static int s_cCount = 0;
12748 static int s_iPingLevel = -1;
12749 if (s_iPingLevel == -1)
12750 {
12751 s_iPingLevel = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgPingInterop);
12752 }
12753 if (s_iPingLevel != 0)
12754 {
12755 s_cCount++;
12756 if (s_cCount >= s_iPingLevel)
12757 {
12758 s_cCount = 0;
12759 ::Beep(1000,100);
12760
12761 // Refresh so we can adjust ping level midstream.
12762 s_iPingLevel = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgPingInterop);
12763 }
12764 }
12765#endif
12766
12767 bool fNewEvent = true;
12768
12769 // Mark the process as stopped.
12770 this->m_state |= CordbProcess::PS_WIN32_STOPPED;
12771
12772 CordbUnmanagedThread * pUnmanagedThread = GetUnmanagedThreadFromEvent(pEvent);
12773
12774 // In retail, if there is no unmanaged thread then we just continue and loop back around. UnrecoverableError has
12775 // already been set in this case. Note: there is an issue in the Win32 debugging API that can cause duplicate
12776 // ExitThread events. We therefore must handle not finding an unmanaged thread gracefully.
12777
12778 _ASSERTE((pUnmanagedThread != NULL) || (pEvent->dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT));
12779
12780 if (pUnmanagedThread == NULL)
12781 {
12782 // Note: we use ContinueDebugEvent directly here since our continue is very simple and all of our other
12783 // continue mechanisms rely on having an UnmanagedThread object to play with ;)
12784 STRESS_LOG2(LF_CORDB, LL_INFO1000, "W32ET::W32EL: Continuing without thread on tid 0x%x, code=0x%x\n",
12785 pEvent->dwThreadId,
12786 pEvent->dwDebugEventCode);
12787
12788 this->m_state &= ~CordbProcess::PS_WIN32_STOPPED;
12789
12790 BOOL fOk = ContinueDebugEvent(pEvent->dwProcessId, pEvent->dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
12791
12792 _ASSERTE(fOk || !"ContinueDebugEvent failed when he have no thread. Debuggee is likely hung");
12793
12794 return;
12795 }
12796
12797 // There's an innate race such that we can get a Debug Event even after we've suspended a thread.
12798 // This can happen if the thread has already dispatched the debug event but we haven't called WFDE to pick it up
12799 // yet. This is sufficiently goofy that we want to stress log it.
12800 if (pUnmanagedThread->IsSuspended())
12801 {
12802 STRESS_LOG1(LF_CORDB, LL_INFO1000, "W32ET::W32EL: Thread 0x%x is suspended\n", pEvent->dwThreadId);
12803 }
12804
12805 // For debugging crazy races in retail, we'll keep a rolling queue of win32 debug events.
12806 this->DebugRecordWin32Event(pEvent, pUnmanagedThread);
12807
12808
12809 // Check to see if shutdown of the in-proc debugging services has begun. If it has, then we know we'll no longer
12810 // be running any managed code, and we know that we can stop hijacking threads. We remember this by setting
12811 // m_initialized to false, thus preventing most things from happening elsewhere.
12812 // Don't even bother checking the DCB fields until it's been verified (m_initialized == true)
12813 if (this->m_initialized && (this->GetDCB() != NULL))
12814 {
12815 UpdateRightSideDCB();
12816 if (this->GetDCB()->m_shutdownBegun)
12817 {
12818 STRESS_LOG0(LF_CORDB, LL_INFO1000, "W32ET::W32EL: shutdown begun...\n");
12819 this->m_initialized = false;
12820 }
12821 }
12822
12823#ifdef _DEBUG
12824 //Verify that GetThreadContext agrees with the exception address
12825 if (pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
12826 {
12827 DT_CONTEXT tempDebugContext;
12828 tempDebugContext.ContextFlags = DT_CONTEXT_FULL;
12829 DbiGetThreadContext(pUnmanagedThread->m_handle, &tempDebugContext);
12830 CordbUnmanagedThread::LogContext(&tempDebugContext);
12831#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
12832 const ULONG_PTR breakpointOpcodeSize = 1;
12833#elif defined(DBG_TARGET_ARM64)
12834 const ULONG_PTR breakpointOpcodeSize = 4;
12835#else
12836 const ULONG_PTR breakpointOpcodeSize = 1;
12837 PORTABILITY_ASSERT("NYI: Breakpoint size offset for this platform");
12838#endif
12839 _ASSERTE(CORDbgGetIP(&tempDebugContext) == pEvent->u.Exception.ExceptionRecord.ExceptionAddress ||
12840 (DWORD)CORDbgGetIP(&tempDebugContext) == ((DWORD)pEvent->u.Exception.ExceptionRecord.ExceptionAddress)+breakpointOpcodeSize);
12841 }
12842#endif
12843
12844 // This call will decide what to do w/ the the win32 event we just got. It does a lot of work.
12845 Reaction reaction = TriageWin32DebugEvent(pUnmanagedThread, pEvent);
12846
12847
12848 // Stress-log the reaction.
12849#ifdef _DEBUG
12850 STRESS_LOG3(LF_CORDB, LL_INFO1000, "Reaction: %d (%s), line=%d\n",
12851 reaction.GetType(),
12852 reaction.GetReactionName(),
12853 reaction.GetLine());
12854#else
12855 STRESS_LOG1(LF_CORDB, LL_INFO1000, "Reaction: %d\n", reaction.GetType());
12856#endif
12857
12858 // Make sure the lock wasn't accidentally released.
12859 _ASSERTE(ThreadHoldsProcessLock());
12860 CordbWin32EventThread * pW32EventThread = this->m_pShim->GetWin32EventThread();
12861 _ASSERTE(pW32EventThread != NULL);
12862
12863 // if we were waiting for a retriggered exception but recieved any other event then turn
12864 // off the single stepping and dequeue the IB event. Right now we only use the SS flag internally
12865 // for stepping during possible retrigger.
12866 if(reaction.GetType() != Reaction::cInbandExceptionRetrigger && pUnmanagedThread->IsSSFlagNeeded())
12867 {
12868 _ASSERTE(pUnmanagedThread->HasIBEvent());
12869 CordbUnmanagedEvent* pUnmanagedEvent = pUnmanagedThread->IBEvent();
12870 _ASSERTE(pUnmanagedEvent->IsIBEvent());
12871 _ASSERTE(pUnmanagedEvent->IsEventContinuedUnhijacked());
12872 _ASSERTE(pUnmanagedEvent->IsDispatched());
12873 LOG((LF_CORDB, LL_INFO100000, "CP::HDEFID: IB event did not retrigger ue=0x%p\n", pUnmanagedEvent));
12874
12875 DequeueUnmanagedEvent(pUnmanagedThread);
12876 pUnmanagedThread->EndStepping();
12877 }
12878
12879 switch(reaction.GetType())
12880 {
12881 // Common for flares.
12882 case Reaction::cIgnore:
12883
12884 // Shouldn't be suspending in the first place with outstanding flares.
12885 _ASSERTE(!pUnmanagedThread->IsSuspended());
12886
12887 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread, DBG_CONTINUE, false);
12888 goto LDone;
12889
12890 case Reaction::cCLR:
12891 // Don't care if thread is suspended here. We'll just let the thread continue whatever it's doing.
12892
12893 this->m_DbgSupport.m_TotalCLR++;
12894
12895 // If this is for the CLR, then we just continue unhandled and know that the CLR has
12896 // a handler inplace to deal w/ this exception.
12897 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread, DBG_EXCEPTION_NOT_HANDLED, false);
12898 goto LDone;
12899
12900
12901 case Reaction::cInband_NotNewEvent:
12902 fNewEvent = false;
12903
12904 // fall through to Inband case...
12905
12906 case Reaction::cInband:
12907 {
12908 this->m_DbgSupport.m_TotalIB++;
12909
12910 // Hijack in-band events (exception events, exit threads) if there is already an event at the head
12911 // of the queue or if the process is currently synchronized. Of course, we only do this if the
12912 // process is initialized.
12913 //
12914 // Note: we also hijack these left over in-band events if we're actively trying to send the
12915 // managed continue message to the Left Side. This is controlled by m_specialDeferment below.
12916
12917 // Only exceptions can be IB events - everything else is OOB.
12918 _ASSERTE(pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT);
12919
12920 // CLR internal exceptions should be sent back to the CLR and never treated as inband events.
12921 // If this assert fires, the event was triaged wrong.
12922 CONSISTENCY_CHECK_MSGF((pEvent->u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_COMPLUS),
12923 ("Attempting to dispatch a CLR internal exception as an Inband event. Reaction line=%d\n",
12924 reaction.GetLine()));
12925
12926
12927 _ASSERTE(!pUnmanagedThread->IsCantStop());
12928
12929 // We need to decide whether or not to dispatch this event immediately
12930 // We defer it to enforce that we only dispatch 1 IB event at a time (managed events are
12931 // considered IB here).
12932 // This means if:
12933 // 1) there's already an outstanding unmanaged inband event (an event the user has not continued from)
12934 // 2) If the process is synchronized (since that means we've already dispatched a managed event).
12935 // 3) If we've received a SyncComplete event, but aren't yet Sync. This will almost always be the same as
12936 // whether we're synced, but has a distict quality. It's always set by the w32 event thread in Interop,
12937 // and so it's guaranteed to be serialized against this check here (also on the w32et).
12938 // 4) Special deferment - This covers the region where we're sending a Stop/Continue IPC event across.
12939 // We defer it here to keep the Helper thread alive so that it can handle these IPC events.
12940 // Queued events will be dispatched when continue is called.
12941 BOOL fHasUserUncontinuedNativeEvents = HasUserUncontinuedNativeEvents();
12942 bool fDeferInbandEvent = (fHasUserUncontinuedNativeEvents ||
12943 GetSynchronized() ||
12944 GetSyncCompleteRecv() ||
12945 m_specialDeferment);
12946
12947 // If we've got a new event, queue it.
12948 if (fNewEvent)
12949 {
12950 this->QueueUnmanagedEvent(pUnmanagedThread, pEvent);
12951 }
12952
12953 if (fNewEvent && this->m_initialized && fDeferInbandEvent)
12954 {
12955 STRESS_LOG4(LF_CORDB, LL_INFO1000, "W32ET::W32EL: Needed to defer dispatching event: %d %d %d %d\n",
12956 fHasUserUncontinuedNativeEvents,
12957 GetSynchronized(),
12958 GetSyncCompleteRecv(),
12959 m_specialDeferment);
12960
12961 // this continues the IB debug event into the hijack
12962 // the process is now running again
12963 pW32EventThread->DoDbgContinue(this, pUnmanagedThread->IBEvent());
12964
12965 // Since we've hijacked this event, we don't need to do any further processing.
12966 goto LDone;
12967 }
12968 else
12969 {
12970 // No need to defer the dispatch, do it now
12971 this->DispatchUnmanagedInBandEvent();
12972
12973 goto LDone;
12974 }
12975 UNREACHABLE();
12976 }
12977
12978 case Reaction::cFirstChanceHijackStarted:
12979 {
12980 // determine the logical event we are handling, if any
12981 CordbUnmanagedEvent* pUnmanagedEvent = NULL;
12982 if(pUnmanagedThread->HasIBEvent())
12983 {
12984 pUnmanagedEvent = pUnmanagedThread->IBEvent();
12985 }
12986 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: IB hijack starting, ue=0x%p\n", pUnmanagedEvent));
12987
12988 // fetch the LS memory set up for this hijack
12989 REMOTE_PTR pDebuggerWord = NULL;
12990 DebuggerIPCFirstChanceData fcd;
12991 pUnmanagedThread->GetEEDebuggerWord(&pDebuggerWord);
12992 SafeReadStruct(PTR_TO_CORDB_ADDRESS(pDebuggerWord), &fcd);
12993
12994 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: old fcd DebugCounter=0x%x\n", fcd.debugCounter));
12995
12996 // determine what action the LS should take
12997 if(pUnmanagedThread->IsBlockingForSync())
12998 {
12999 // there should be an event we hijacked in this case
13000 _ASSERTE(pUnmanagedEvent != NULL);
13001
13002 // block that event
13003 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: blocking\n"));
13004 fcd.action = HIJACK_ACTION_WAIT;
13005 fcd.debugCounter = 0x2;
13006 SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pDebuggerWord), &fcd);
13007 }
13008 else
13009 {
13010 // we don't need to block. We want the vectored handler to just exit
13011 // as if it wasn't there
13012 _ASSERTE(fcd.action == HIJACK_ACTION_EXIT_UNHANDLED);
13013 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: not blocking\n"));
13014 }
13015
13016 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: continuing from flare\n"));
13017 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread, DBG_CONTINUE, false);
13018 goto LDone;
13019 }
13020
13021 case Reaction::cInbandHijackComplete:
13022 {
13023 // We now execute the hijack worker even when not actually hijacked
13024 // so can't assert this
13025 //_ASSERTE(pUnmanagedThread->IsFirstChanceHijacked());
13026
13027 // we should not be stepping at the end of hijacks
13028 _ASSERTE(!pUnmanagedThread->IsSSFlagHidden());
13029 _ASSERTE(!pUnmanagedThread->IsSSFlagNeeded());
13030
13031 // if we were hijacked then clean up
13032 if(pUnmanagedThread->IsFirstChanceHijacked())
13033 {
13034 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: hijack complete will restore context...\n"));
13035 DT_CONTEXT tempContext = { 0 };
13036 tempContext.ContextFlags = DT_CONTEXT_FULL;
13037 HRESULT hr = pUnmanagedThread->GetThreadContext(&tempContext);
13038 _ASSERTE(SUCCEEDED(hr));
13039
13040 // The sync hijack returns normally but the m2uHandoff hijack needs to have the IP
13041 // deliberately restored
13042 if(!pUnmanagedThread->IsBlockingForSync())
13043 {
13044 // restore the context to the current un-hijacked context
13045 BOOL succ = DbiSetThreadContext(pUnmanagedThread->m_handle, &tempContext);
13046 _ASSERTE(succ);
13047
13048 // Because hijacks don't return normally they might have pushed handlers without poping them
13049 // back off. To take care of that we explicitly restore the old SEH chain.
13050 #ifdef DBG_TARGET_X86
13051 hr = pUnmanagedThread->RestoreLeafSeh();
13052 _ASSERTE(SUCCEEDED(hr));
13053 #endif
13054 }
13055 else
13056 {
13057 _ASSERTE(pUnmanagedThread->HasIBEvent());
13058 CordbUnmanagedEvent* pUnmanagedEvent = pUnmanagedThread->IBEvent();
13059 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: IB hijack completing, continuing unhijacked ue=0x%p\n", pUnmanagedEvent));
13060 _ASSERTE(pUnmanagedEvent->IsEventContinuedHijacked());
13061 _ASSERTE(pUnmanagedEvent->IsDispatched());
13062 _ASSERTE(pUnmanagedEvent->IsEventUserContinued());
13063 _ASSERTE(!pUnmanagedEvent->IsEventContinuedUnhijacked());
13064 pUnmanagedEvent->SetState(CUES_EventContinuedUnhijacked);
13065
13066 // fetch the LS memory set up for this hijack
13067 REMOTE_PTR pDebuggerWord = NULL;
13068 DebuggerIPCFirstChanceData fcd;
13069 pUnmanagedThread->GetEEDebuggerWord(&pDebuggerWord);
13070 SafeReadStruct(PTR_TO_CORDB_ADDRESS(pDebuggerWord), &fcd);
13071
13072 LOG((LF_CORDB, LL_INFO10000, "W32ET::W32EL: pDebuggerWord is 0x%p\n", pDebuggerWord));
13073
13074 //set the correct continuation action based upon the user's selection
13075 if(pUnmanagedEvent->IsExceptionCleared())
13076 {
13077 LOG((LF_CORDB, LL_INFO10000, "W32ET::W32EL: exception cleared\n"));
13078 fcd.action = HIJACK_ACTION_EXIT_HANDLED;
13079 }
13080 else
13081 {
13082 LOG((LF_CORDB, LL_INFO10000, "W32ET::W32EL: exception not cleared\n"));
13083 fcd.action = HIJACK_ACTION_EXIT_UNHANDLED;
13084 }
13085
13086 //
13087 // LS context is restored here so that execution continues from next instruction that caused the hijack.
13088 // We shouldn't always restore the LS context though.
13089 // Consider the following case where this can cause issues:
13090 // Debuggee process hits an exception and calls KERNELBASE!RaiseException, debugger gets the notification and
13091 // prepares for first-chance hijack. Debugger(DBI) saves the current thread context (see SetupFirstChanceHijackForSync) which is restored
13092 // later below (see SafeWriteThreadContext call) when the process is in VEH (CLRVectoredExceptionHandlerShim->FirstChanceSuspendHijackWorker).
13093 // The thread context that got saved(by SetupFirstChanceHijackForSync) was for when the thread was executing RaiseException and when
13094 // this context gets restored in VEH, the thread resumes after the exception handler with a context that is not same as one with which
13095 // it entered. This inconsistency can lead to bad execution code-paths or even a debuggee crash.
13096 //
13097 // Example case where we should definitely update the LS context:
13098 // After a DbgBreakPoint call, IP gets updated to point to the instruction after int 3 and this is the context saved by debugger.
13099 // The IP in context passed to VEH still points to int 3 though and if we don't update the LS context in VEH, the breakpoint
13100 // instruction will get executed again.
13101 //
13102 // Here's a list of cases when we update the LS context:
13103 // * we know that context was explicitly updated during this hijack, OR
13104 // * if single-stepping flag was set on it originally, OR
13105 // * if this was a breakpoint event
13106 // Note that above list is a heuristic and it is possible that we need to add more such cases in future.
13107 //
13108 BOOL isBreakPointEvent = (pUnmanagedEvent->m_currentDebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
13109 pUnmanagedEvent->m_currentDebugEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT);
13110 if (pUnmanagedThread->IsContextSet() || IsSSFlagEnabled(&tempContext) || isBreakPointEvent)
13111 {
13112 _ASSERTE(fcd.pLeftSideContext != NULL);
13113 LOG((LF_CORDB, LL_INFO10000, "W32ET::W32EL: updating LS context at 0x%p\n", fcd.pLeftSideContext));
13114 // write the new context over the old one on the LS
13115 SafeWriteThreadContext(fcd.pLeftSideContext, &tempContext);
13116 }
13117
13118 // Write the new Fcd data to the LS
13119 fcd.debugCounter = 0x1;
13120 SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pDebuggerWord), &fcd);
13121
13122 fcd.debugCounter = 0;
13123 SafeReadStruct(PTR_TO_CORDB_ADDRESS(pDebuggerWord), &fcd);
13124 _ASSERTE(fcd.debugCounter == 1);
13125
13126 DequeueUnmanagedEvent(pUnmanagedThread);
13127 }
13128
13129 _ASSERTE(m_cFirstChanceHijackedThreads > 0);
13130 m_cFirstChanceHijackedThreads--;
13131 if(m_cFirstChanceHijackedThreads == 0)
13132 {
13133 m_state &= ~PS_HIJACKS_IN_PLACE;
13134 }
13135
13136 pUnmanagedThread->ClearState(CUTS_FirstChanceHijacked);
13137 pUnmanagedThread->ClearState(CUTS_BlockingForSync);
13138
13139 // if the user set the context it either was already applied (m2uHandoff hijack)
13140 // or is about to be applied when the hijack returns (sync hijack).
13141 // There may still a small window where it won't appear accurate that
13142 // we just have to live with
13143 pUnmanagedThread->ClearState(CUTS_HasContextSet);
13144 }
13145
13146 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread, DBG_CONTINUE, false);
13147
13148 // We've handled this event. Skip further processing.
13149 goto LDone;
13150 }
13151
13152 case Reaction::cBreakpointRequiringHijack:
13153 {
13154 HRESULT hr = pUnmanagedThread->SetupFirstChanceHijack(EHijackReason::kM2UHandoff, &(pEvent->u.Exception.ExceptionRecord));
13155 _ASSERTE(SUCCEEDED(hr));
13156 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread, DBG_CONTINUE, false);
13157 goto LDone;
13158 }
13159
13160 case Reaction::cInbandExceptionRetrigger:
13161 {
13162 // this should be unused now
13163 _ASSERTE(FALSE);
13164 _ASSERTE(pUnmanagedThread->HasIBEvent());
13165 CordbUnmanagedEvent* pUnmanagedEvent = pUnmanagedThread->IBEvent();
13166 _ASSERTE(pUnmanagedEvent->IsIBEvent());
13167 _ASSERTE(pUnmanagedEvent->IsEventContinuedUnhijacked());
13168 _ASSERTE(pUnmanagedEvent->IsDispatched());
13169 LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: IB event completing, continuing ue=0x%p\n", pUnmanagedEvent));
13170
13171 DequeueUnmanagedEvent(pUnmanagedThread);
13172 // If this event came from RaiseException then flush the context to ensure we won't use it until we re-enter
13173 if(pUnmanagedEvent->m_owner->IsRaiseExceptionHijacked())
13174 {
13175 pUnmanagedEvent->m_owner->RestoreFromRaiseExceptionHijack();
13176 pUnmanagedEvent->m_owner->ClearRaiseExceptionEntryContext();
13177 }
13178 else // otherwise we should have been stepping
13179 {
13180 pUnmanagedThread->EndStepping();
13181 }
13182 pW32EventThread->ForceDbgContinue(this, pUnmanagedThread,
13183 pUnmanagedEvent->IsExceptionCleared() ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED, false);
13184
13185 // We've handled this event. Skip further processing.
13186 goto LDone;
13187 }
13188
13189 case Reaction::cOOB:
13190 {
13191 // Don't care if this thread claimed to be suspended or not. Dispatch event anyways. After all,
13192 // OOB events can come at *any* time.
13193
13194 // This thread may be suspended. We don't care.
13195 this->m_DbgSupport.m_TotalOOB++;
13196
13197 // Not an inband event. This includes ALL non-exception events (including EXIT_THREAD) as
13198 // well as any exception that can't be hijacked (ex, an exception on the helper thread).
13199
13200 // If this is an exit thread or exit process event, then we need to mark the unmanaged thread as
13201 // exited for later.
13202 if ((pEvent->dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) ||
13203 (pEvent->dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT))
13204 {
13205 pUnmanagedThread->SetState(CUTS_Deleted);
13206 }
13207
13208 // If we get an exit process or exit thread event on the helper thread, then we know we're loosing
13209 // the Left Side, so go ahead and remember that the helper thread has died.
13210 if (this->IsHelperThreadWorked(pUnmanagedThread->GetOSTid()))
13211 {
13212 if ((pEvent->dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) ||
13213 (pEvent->dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT))
13214 {
13215 this->m_helperThreadDead = true;
13216 }
13217 }
13218
13219 // Queue the current out-of-band event.
13220 this->QueueOOBUnmanagedEvent(pUnmanagedThread, pEvent);
13221
13222 // Go ahead and dispatch the event if its the first one.
13223 if (this->m_outOfBandEventQueue == pUnmanagedThread->OOBEvent())
13224 {
13225 // Set this to true to indicate to Continue() that we're in the unamnaged callback.
13226 CordbUnmanagedEvent * pUnmanagedEvent = pUnmanagedThread->OOBEvent();
13227
13228 this->m_dispatchingOOBEvent = true;
13229
13230 pUnmanagedEvent->SetState(CUES_Dispatched);
13231
13232 this->Unlock();
13233
13234 // Handler should have been registered by now.
13235 _ASSERTE(this->m_cordb->m_unmanagedCallback != NULL);
13236
13237 // Call the callback with fIsOutOfBand = TRUE.
13238 {
13239 PUBLIC_WIN32_CALLBACK_IN_THIS_SCOPE(this, pEvent, TRUE);
13240 this->m_cordb->m_unmanagedCallback->DebugEvent(const_cast<DEBUG_EVENT*> (pEvent), TRUE);
13241 }
13242
13243 this->Lock();
13244
13245 // If m_dispatchingOOBEvent is false, that means that the user called Continue() from within
13246 // the callback. We know that we can go ahead and continue the process now.
13247 if (this->m_dispatchingOOBEvent == false)
13248 {
13249 // Note: this call will dispatch more OOB events if necessary.
13250 pW32EventThread->UnmanagedContinue(this, cOobUMContinue);
13251 }
13252 else
13253 {
13254 // We're not dispatching anymore, so set this back to false.
13255 this->m_dispatchingOOBEvent = false;
13256 }
13257 }
13258
13259 // We've handled this event. Skip further processing.
13260 goto LDone;
13261 }
13262 } // end Switch on Reaction
13263
13264 UNREACHABLE();
13265
13266LDone:
13267 // Process Lock implicitly released by holder.
13268
13269 STRESS_LOG0(LF_CORDB, LL_INFO1000, "W32ET::W32EL: done processing event.\n");
13270
13271 return;
13272}
13273
13274//
13275// Returns true if the exception is a flare from the left side, false otherwise.
13276//
13277bool CordbProcess::ExceptionIsFlare(DWORD exceptionCode, const void *exceptionAddress)
13278{
13279 _ASSERTE(m_runtimeOffsetsInitialized);
13280
13281 // Can't have a flare if the left side isn't initialized
13282 if (m_initialized)
13283 {
13284 DebuggerIPCRuntimeOffsets *pRO = &m_runtimeOffsets;
13285
13286 // All flares are breakpoints...
13287 if (exceptionCode == STATUS_BREAKPOINT)
13288 {
13289 // Does the breakpoint address match a flare address?
13290 if ((exceptionAddress == pRO->m_signalHijackStartedBPAddr) ||
13291 (exceptionAddress == pRO->m_excepForRuntimeHandoffStartBPAddr) ||
13292 (exceptionAddress == pRO->m_excepForRuntimeHandoffCompleteBPAddr) ||
13293 (exceptionAddress == pRO->m_signalHijackCompleteBPAddr) ||
13294 (exceptionAddress == pRO->m_excepNotForRuntimeBPAddr) ||
13295 (exceptionAddress == pRO->m_notifyRSOfSyncCompleteBPAddr))
13296 return true;
13297 }
13298 }
13299
13300 return false;
13301}
13302#endif // FEATURE_INTEROP_DEBUGGING
13303
13304// Allocate a buffer in the target and copy data into it.
13305//
13306// Arguments:
13307// pDomain - an appdomain associated with the allocation request.
13308// bufferSize - size of the buffer in bytes
13309// bufferFrom - local buffer of data (bufferSize bytes) to copy data from.
13310// ppRes - address into target of allocated buffer
13311//
13312// Returns:
13313// S_OK on success, else error.
13314HRESULT CordbProcess::GetAndWriteRemoteBuffer(CordbAppDomain *pDomain, unsigned int bufferSize, const void *bufferFrom, void **ppRes)
13315{
13316 _ASSERTE(ppRes != NULL);
13317 *ppRes = NULL;
13318
13319 HRESULT hr = S_OK;
13320
13321 EX_TRY
13322 {
13323 TargetBuffer tbTarget = GetRemoteBuffer(bufferSize); // throws
13324 SafeWriteBuffer(tbTarget, (const BYTE*) bufferFrom); // throws
13325
13326 // Succeeded.
13327 *ppRes = CORDB_ADDRESS_TO_PTR(tbTarget.pAddress);
13328 }
13329 EX_CATCH_HRESULT(hr);
13330 return hr;
13331}
13332
13333#ifdef FEATURE_INTEROP_DEBUGGING
13334
13335//
13336// Checks to see if the given second chance exception event actually signifies the death of the process due to a second
13337// stack overflow special case.
13338//
13339// There are strange cases with stack overflow exceptions. If a nieve application catches a stack overflow exception and
13340// handles it, without resetting the guard page, then the app will get an AV when it overflows the stack a second time. We
13341// will get the first chance AV, but when we continue from it the OS won't run any SEH handlers, so our FCH won't
13342// actually work. Instead, we'll get the AV back on second chance right away.
13343//
13344bool CordbProcess::IsSpecialStackOverflowCase(CordbUnmanagedThread *pUThread, const DEBUG_EVENT *pEvent)
13345{
13346 _ASSERTE(pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT);
13347 _ASSERTE(pEvent->u.Exception.dwFirstChance == 0);
13348
13349 // If this is not an AV, it can't be our special case.
13350 if (pEvent->u.Exception.ExceptionRecord.ExceptionCode != STATUS_ACCESS_VIOLATION)
13351 return false;
13352
13353 // If the thread isn't already first chance hijacked, it can't be our special case.
13354 if (!pUThread->IsFirstChanceHijacked())
13355 return false;
13356
13357 // The first chance hijack didn't take, so we're not FCH anymore and we're not waiting for an answer
13358 // anymore... Note: by leaving this thread completely unhijacked, we'll report its true context, which is correct.
13359 pUThread->ClearState(CUTS_FirstChanceHijacked);
13360
13361 // The process is techincally dead as a door nail here, so we'll mark that the helper thread is dead so our managed
13362 // API bails nicely.
13363 m_helperThreadDead = true;
13364
13365 // Remember we're in our special case.
13366 pUThread->SetState(CUTS_HasSpecialStackOverflowCase);
13367
13368 // Now, remember the second chance AV event in the second IB event slot for this thread and add it to the end of the
13369 // IB event queue.
13370 QueueUnmanagedEvent(pUThread, pEvent);
13371
13372 // Note: returning true will ensure that the queued first chance AV for this thread is dispatched.
13373 return true;
13374}
13375
13376//-----------------------------------------------------------------------------
13377// Longhorn broke ContinueDebugEvent.
13378// In previous OS releases, DBG_CONTINUE would continue a non-continuable exception.
13379// In longhorn, we need to pass the DBG_FORCE_CONTINUE flag to do that.
13380// Note that all CLR exceptions are non-continuable.
13381// Now instead of DBG_CONTINUE, we need to pass DBG_FORCE_CONTINUE.
13382//-----------------------------------------------------------------------------
13383
13384// Currently we don't have headers for the longhorn winnt.h. So we need to privately declare
13385// this here. We have a check such that if we do get headers, the value won't change underneath us.
13386#define MY_DBG_FORCE_CONTINUE ((DWORD )0x00010003L)
13387#ifndef DBG_FORCE_CONTINUE
13388#define DBG_FORCE_CONTINUE MY_DBG_FORCE_CONTINUE
13389#else
13390static_assert_no_msg(DBG_FORCE_CONTINUE == MY_DBG_FORCE_CONTINUE);
13391#endif
13392
13393DWORD GetDbgContinueFlag()
13394{
13395 // Currently, default to not using the new DBG_FORCE_CONTINUE flag.
13396 static ConfigDWORD fNoFlagKey;
13397 bool fNoFlag = fNoFlagKey.val(CLRConfig::UNSUPPORTED_DbgNoForceContinue) != 0;
13398
13399
13400 if (!fNoFlag)
13401 {
13402 return DBG_FORCE_CONTINUE;
13403 }
13404 else
13405 {
13406 return DBG_CONTINUE;
13407 }
13408}
13409
13410
13411// Some Interop bugs involve threads that land at a crazy IP. Since we're interop-debugging, we can't
13412// attach a debugger to the LS. So we have some debug mode where we enable the SS flag and thus
13413// produce a trace of where a thread is going.
13414#ifdef _DEBUG
13415void EnableDebugTrace(CordbUnmanagedThread *ut)
13416{
13417 // To enable, attach w/ a debugger and either set fTrace==true, or setip.
13418 static bool fTrace = false;
13419 if (!fTrace)
13420 return;
13421
13422 // Give us a nop so that we can setip in the optimized case.
13423#ifdef _TARGET_X86_
13424 __asm {
13425 nop
13426 }
13427#endif
13428
13429 fTrace = true;
13430 CordbProcess *pProcess = ut->GetProcess();
13431
13432 // Get the context
13433 HRESULT hr = S_OK;
13434 DT_CONTEXT context;
13435 context.ContextFlags = DT_CONTEXT_FULL;
13436
13437
13438 hr = pProcess->GetThreadContext((DWORD) ut->m_id, sizeof(context), (BYTE*)&context);
13439 if (FAILED(hr))
13440 return;
13441
13442 // If the flag is already set, then don't set it again - that will just get confusing.
13443 if (IsSSFlagEnabled(&context))
13444 {
13445 return;
13446 }
13447 _ASSERTE(CORDbgGetIP(&context) != 0);
13448 SetSSFlag(&context);
13449
13450 // If SS flag not set, enable it. And remeber that it's us so we know how to handle
13451 // it when we get the debug event.
13452 hr = pProcess->SetThreadContext((DWORD)ut->m_id, sizeof(context), (BYTE*)&context);
13453 ut->SetState(CUTS_DEBUG_SingleStep);
13454}
13455#endif // _DEBUG
13456
13457//-----------------------------------------------------------------------------
13458// DoDbgContinue
13459//
13460// Continues from a specific Win32 DEBUG_EVENT.
13461//
13462// Arguments:
13463// pProcess - The process to continue.
13464// pUnmanagedEvent - The event to continue.
13465//
13466//-----------------------------------------------------------------------------
13467void CordbWin32EventThread::DoDbgContinue(CordbProcess *pProcess,
13468 CordbUnmanagedEvent *pUnmanagedEvent)
13469{
13470 _ASSERTE(pProcess->ThreadHoldsProcessLock());
13471 _ASSERTE(IsWin32EventThread());
13472 _ASSERTE(pUnmanagedEvent != NULL);
13473 _ASSERTE(!pUnmanagedEvent->IsEventContinuedUnhijacked());
13474
13475 STRESS_LOG3(LF_CORDB, LL_INFO1000,
13476 "W32ET::DDC: continue with ue=0x%p, thread=0x%p, tid=0x%x\n",
13477 pUnmanagedEvent,
13478 pUnmanagedEvent->m_owner,
13479 pUnmanagedEvent->m_owner->m_id);
13480
13481#ifdef _DEBUG
13482 EnableDebugTrace(pUnmanagedEvent->m_owner);
13483#endif
13484
13485
13486 if (pUnmanagedEvent->IsEventContinuedHijacked())
13487 {
13488 LOG((LF_CORDB, LL_INFO100000, "W32ET::DDC: Skiping DoDbgContinue because event was already"
13489 " continued hijacked, ue=0x%p\n", pUnmanagedEvent));
13490 return;
13491 }
13492
13493 BOOL threadIsHijacked = (pUnmanagedEvent->m_owner->IsFirstChanceHijacked() ||
13494 pUnmanagedEvent->m_owner->IsGenericHijacked());
13495
13496 BOOL eventIsIB = (pUnmanagedEvent->m_owner->HasIBEvent() &&
13497 pUnmanagedEvent->m_owner->IBEvent() == pUnmanagedEvent);
13498
13499 _ASSERTE((DWORD) pProcess->m_id == pUnmanagedEvent->m_currentDebugEvent.dwProcessId);
13500 _ASSERTE(pProcess->m_state & CordbProcess::PS_WIN32_STOPPED);
13501
13502 DWORD dwContType;
13503 if(eventIsIB)
13504 {
13505 // 3 cases here...
13506 // event was already hijacked
13507 if(threadIsHijacked)
13508 {
13509 LOG((LF_CORDB, LL_INFO100000, "W32ET::DDC: Continuing IB, already hijacked, ue=0x%p\n", pUnmanagedEvent));
13510 pUnmanagedEvent->SetState(CUES_EventContinuedHijacked);
13511 dwContType = !pUnmanagedEvent->m_owner->IsBlockingForSync() ? GetDbgContinueFlag() : DBG_EXCEPTION_NOT_HANDLED;
13512 }
13513 // event was not hijacked but has been dispatched
13514 else if(!threadIsHijacked && pUnmanagedEvent->IsDispatched())
13515 {
13516 LOG((LF_CORDB, LL_INFO100000, "W32ET::DDC: Continuing IB, not hijacked, ue=0x%p\n", pUnmanagedEvent));
13517 _ASSERTE(pUnmanagedEvent->IsDispatched());
13518 _ASSERTE(pUnmanagedEvent->IsEventUserContinued());
13519 _ASSERTE(!pUnmanagedEvent->IsEventContinuedUnhijacked());
13520 pUnmanagedEvent->SetState(CUES_EventContinuedUnhijacked);
13521 dwContType = pUnmanagedEvent->IsExceptionCleared() ? GetDbgContinueFlag() : DBG_EXCEPTION_NOT_HANDLED;
13522
13523 // The event was never hijacked and so will never need to retrigger, get rid
13524 // of it right now. If it had been hijacked then we would dequeue it either after the
13525 // hijack complete flare or one instruction after that when it has had a chance to retrigger
13526 pProcess->DequeueUnmanagedEvent(pUnmanagedEvent->m_owner);
13527 }
13528 // event was not hijacked nor dispatched
13529 else // if(!threadIsHijacked && !pUnmanagedEvent->IsDispatched())
13530 {
13531 LOG((LF_CORDB, LL_INFO100000, "W32ET::DDC: Continuing IB, now hijacked, ue=0x%p\n", pUnmanagedEvent));
13532 HRESULT hr = pProcess->HijackIBEvent(pUnmanagedEvent);
13533 _ASSERTE(SUCCEEDED(hr));
13534 pUnmanagedEvent->SetState(CUES_EventContinuedHijacked);
13535 dwContType = !pUnmanagedEvent->m_owner->IsBlockingForSync() ? GetDbgContinueFlag() : DBG_EXCEPTION_NOT_HANDLED;
13536 }
13537 }
13538 else
13539 {
13540 LOG((LF_CORDB, LL_INFO100000, "W32ET::DDC: Continuing OB, ue=0x%p\n", pUnmanagedEvent));
13541 // we might actually be hijacked here, but if we are it should be for a previous IB event
13542 // we just mark all OB events as continued unhijacked
13543 pUnmanagedEvent->SetState(CUES_EventContinuedUnhijacked);
13544 dwContType = pUnmanagedEvent->IsExceptionCleared() ? GetDbgContinueFlag() : DBG_EXCEPTION_NOT_HANDLED;
13545 }
13546
13547 // If the exception is marked as unclearable, then make sure the continue type is correct and force the process
13548 // to terminate.
13549 if (pUnmanagedEvent->IsExceptionUnclearable())
13550 {
13551 TerminateProcess(pProcess->UnsafeGetProcessHandle(), pUnmanagedEvent->m_currentDebugEvent.u.Exception.ExceptionRecord.ExceptionCode);
13552 dwContType = DBG_EXCEPTION_NOT_HANDLED;
13553 }
13554
13555 // If we're continuing from the loader-bp, then send the managed attach here.
13556 // (Note this will only be set if the runtime was loaded when we first tried to attach).
13557 // We assume that the loader-bp is the 1st BP exception. This is naive,
13558 // since it's not 100% accurate (someone could CreateThread w/ a threadproc of DebugBreak).
13559 // But it's the best we can do.
13560 // Note that it's critical we do this BEFORE continuing the process. If this is mixed-mode, we've already
13561 // told VS about this breakpoint, and so it's set the attach-complete event. As soon as we continue this debug
13562 // event the process can start moving again, so the CLR needs to know to wait for a managed attach.
13563 DWORD dwEventCode = pUnmanagedEvent->m_currentDebugEvent.dwDebugEventCode;
13564 if (dwEventCode == EXCEPTION_DEBUG_EVENT)
13565 {
13566 EXCEPTION_DEBUG_INFO * pDebugInfo = &pUnmanagedEvent->m_currentDebugEvent.u.Exception;
13567 if (pDebugInfo->dwFirstChance && pDebugInfo->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
13568 {
13569 HRESULT hrIgnore = S_OK;
13570 EX_TRY
13571 {
13572 LOG((LF_CORDB, LL_INFO1000, "W32ET::DDC: Continuing from LdrBp, doing managed attach.\n"));
13573 pProcess->QueueManagedAttachIfNeededWorker();
13574 }
13575 EX_CATCH_HRESULT(hrIgnore);
13576 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hrIgnore));
13577 }
13578 }
13579
13580 STRESS_LOG4(LF_CORDB, LL_INFO1000,
13581 "W32ET::DDC: calling ContinueDebugEvent(0x%x, 0x%x, 0x%x), process state=0x%x\n",
13582 pProcess->m_id, pUnmanagedEvent->m_owner->m_id, dwContType, pProcess->m_state);
13583
13584 // Actually continue the debug event
13585 pProcess->m_state &= ~CordbProcess::PS_WIN32_STOPPED;
13586 BOOL fSuccess = m_pNativePipeline->ContinueDebugEvent((DWORD)pProcess->m_id, (DWORD)pUnmanagedEvent->m_owner->m_id, dwContType);
13587
13588 // ContinueDebugEvent may 'fail' if we force kill the debuggee while stopped at the exit-process event.
13589 if (!fSuccess && (dwEventCode != EXIT_PROCESS_DEBUG_EVENT))
13590 {
13591 _ASSERTE(!"ContinueDebugEvent failed!");
13592 CORDBSetUnrecoverableError(pProcess, HRESULT_FROM_GetLastError(), 0);
13593 STRESS_LOG1(LF_CORDB, LL_INFO1000, "W32ET::DDC: Last error after ContinueDebugEvent is %d\n", GetLastError());
13594 }
13595
13596 // If this thread is marked for deletion (exit thread or exit process event on it), then we need to delete the
13597 // unmanaged thread object.
13598 if ((dwEventCode == EXIT_PROCESS_DEBUG_EVENT) || (dwEventCode == EXIT_THREAD_DEBUG_EVENT))
13599 {
13600 CordbUnmanagedThread * pUnmanagedThread = pUnmanagedEvent->m_owner;
13601 _ASSERTE(pUnmanagedThread->IsDeleted());
13602
13603
13604 // Thread may have a hijacked inband event on it. Thus it's actually running free from the OS perspective,
13605 // and fair game to be terminated. In that case, we need to auto-dequeue the event.
13606 // This will just prevent the RS from making the underlying call to ContinueDebugEvent on this thread
13607 // for the inband event. Since we've already lost the thread, that's actually exactly what we want.
13608 if (pUnmanagedThread->HasIBEvent())
13609 {
13610 pProcess->DequeueUnmanagedEvent(pUnmanagedThread);
13611 }
13612
13613 STRESS_LOG1(LF_CORDB, LL_INFO1000, "Removing thread 0x%x (%d) from process list\n", pUnmanagedThread->m_id);
13614 pProcess->m_unmanagedThreads.RemoveBase((ULONG_PTR)pUnmanagedThread->m_id);
13615 }
13616
13617
13618 // If we just continued from an exit process event, then its time to do the exit processing.
13619 if (dwEventCode == EXIT_PROCESS_DEBUG_EVENT)
13620 {
13621 pProcess->Unlock();
13622 ExitProcess(false); // not detach case
13623 pProcess->Lock();
13624 }
13625
13626}
13627
13628//---------------------------------------------------------------------------------------
13629//
13630// ForceDbgContinue continues from the last Win32 DEBUG_EVENT on the given thread, no matter what it was.
13631//
13632// Arguments:
13633// pProcess - process object to continue
13634// pUnmanagedThread - unmanaged thread object (maybe null if we're doing a raw cotninue)
13635// contType - continuation status (DBG_CONTINUE or DBG_EXCEPTION_NOT_HANDLED)
13636// fContinueProcess - do we resume hijacks?
13637//
13638void CordbWin32EventThread::ForceDbgContinue(CordbProcess *pProcess, CordbUnmanagedThread *pUnmanagedThread, DWORD contType,
13639 bool fContinueProcess)
13640{
13641 _ASSERTE(pProcess->ThreadHoldsProcessLock());
13642 _ASSERTE(pUnmanagedThread != NULL);
13643 STRESS_LOG4(LF_CORDB, LL_INFO1000,
13644 "W32ET::FDC: force continue with 0x%x (%s), contProcess=%d, tid=0x%x\n",
13645 contType,
13646 (contType == DBG_CONTINUE) ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED",
13647 fContinueProcess,
13648 pUnmanagedThread->m_id);
13649
13650 if (fContinueProcess)
13651 {
13652 pProcess->ResumeHijackedThreads();
13653 }
13654
13655 if (contType == DBG_CONTINUE)
13656 {
13657 contType = GetDbgContinueFlag();
13658 }
13659
13660 _ASSERTE(pProcess->m_state & CordbProcess::PS_WIN32_STOPPED);
13661
13662 // Remove the Win32 stopped flag so long as the OOB event queue is empty. We're forcing a continue here, so by
13663 // definition this should be the case...
13664 _ASSERTE(pProcess->m_outOfBandEventQueue == NULL);
13665
13666 pProcess->m_state &= ~CordbProcess::PS_WIN32_STOPPED;
13667
13668 STRESS_LOG4(LF_CORDB, LL_INFO1000, "W32ET::FDC: calling ContinueDebugEvent(0x%x, 0x%x, 0x%x), process state=0x%x\n",
13669 pProcess->m_id, pUnmanagedThread->m_id, contType, pProcess->m_state);
13670
13671
13672 #ifdef _DEBUG
13673 EnableDebugTrace(pUnmanagedThread);
13674 #endif
13675 BOOL ret = m_pNativePipeline->ContinueDebugEvent((DWORD)pProcess->m_id, (DWORD)pUnmanagedThread->m_id, contType);
13676
13677 if (!ret)
13678 {
13679 // This could in theory fail from Process exit, but that really would only be on the DoDbgContinue path.
13680 _ASSERTE(!"ContinueDebugEvent failed #2!");
13681 STRESS_LOG1(LF_CORDB, LL_INFO1000, "W32ET::DDC: Last error after ContinueDebugEvent is %d\n", GetLastError());
13682 }
13683}
13684#endif // FEATURE_INTEROP_DEBUGGING
13685
13686//
13687// This is the thread's real thread proc. It simply calls to the
13688// thread proc on the given object.
13689//
13690/*static*/ DWORD WINAPI CordbWin32EventThread::ThreadProc(LPVOID parameter)
13691{
13692 CordbWin32EventThread* t = (CordbWin32EventThread*) parameter;
13693 INTERNAL_THREAD_ENTRY(t);
13694 t->ThreadProc();
13695 return 0;
13696}
13697
13698
13699//
13700// Send a CreateProcess event to the Win32 thread to have it create us
13701// a new process.
13702//
13703HRESULT CordbWin32EventThread::SendCreateProcessEvent(
13704 MachineInfo machineInfo,
13705 LPCWSTR programName,
13706 __in_z LPWSTR programArgs,
13707 LPSECURITY_ATTRIBUTES lpProcessAttributes,
13708 LPSECURITY_ATTRIBUTES lpThreadAttributes,
13709 BOOL bInheritHandles,
13710 DWORD dwCreationFlags,
13711 PVOID lpEnvironment,
13712 LPCWSTR lpCurrentDirectory,
13713 LPSTARTUPINFOW lpStartupInfo,
13714 LPPROCESS_INFORMATION lpProcessInformation,
13715 CorDebugCreateProcessFlags corDebugFlags)
13716{
13717 HRESULT hr = S_OK;
13718
13719 LockSendToWin32EventThreadMutex();
13720 LOG((LF_CORDB, LL_EVERYTHING, "CordbWin32EventThread::SCPE Called\n"));
13721 m_actionData.createData.machineInfo = machineInfo;
13722 m_actionData.createData.programName = programName;
13723 m_actionData.createData.programArgs = programArgs;
13724 m_actionData.createData.lpProcessAttributes = lpProcessAttributes;
13725 m_actionData.createData.lpThreadAttributes = lpThreadAttributes;
13726 m_actionData.createData.bInheritHandles = bInheritHandles;
13727 m_actionData.createData.dwCreationFlags = dwCreationFlags;
13728 m_actionData.createData.lpEnvironment = lpEnvironment;
13729 m_actionData.createData.lpCurrentDirectory = lpCurrentDirectory;
13730 m_actionData.createData.lpStartupInfo = lpStartupInfo;
13731 m_actionData.createData.lpProcessInformation = lpProcessInformation;
13732 m_actionData.createData.corDebugFlags = corDebugFlags;
13733
13734 // m_action is set last so that the win32 event thread can inspect
13735 // it and take action without actually having to take any
13736 // locks. The lock around this here is simply to prevent multiple
13737 // threads from making requests at the same time.
13738 m_action = W32ETA_CREATE_PROCESS;
13739
13740 BOOL succ = SetEvent(m_threadControlEvent);
13741
13742 if (succ)
13743 {
13744 DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE);
13745
13746 LOG((LF_CORDB, LL_EVERYTHING, "Process Handle is: %x, m_threadControlEvent is %x\n",
13747 (UINT_PTR)m_actionData.createData.lpProcessInformation->hProcess, (UINT_PTR)m_threadControlEvent));
13748
13749 if (ret == WAIT_OBJECT_0)
13750 hr = m_actionResult;
13751 else
13752 hr = HRESULT_FROM_GetLastError();
13753 }
13754 else
13755 hr = HRESULT_FROM_GetLastError();
13756
13757 UnlockSendToWin32EventThreadMutex();
13758
13759 return hr;
13760}
13761
13762
13763//---------------------------------------------------------------------------------------
13764//
13765// Create a process
13766//
13767// Assumptions:
13768// This occurs on the win32 event thread. It is invokved via
13769// a message sent from code:CordbWin32EventThread::SendCreateProcessEvent
13770//
13771// Notes:
13772// Create a new process. This is called in the context of the Win32
13773// event thread to ensure that if we're Win32 debugging the process
13774// that the same thread that waits for debugging events will be the
13775// thread that creates the process.
13776//
13777//---------------------------------------------------------------------------------------
13778void CordbWin32EventThread::CreateProcess()
13779{
13780 m_action = W32ETA_NONE;
13781 HRESULT hr = S_OK;
13782
13783 DWORD dwCreationFlags = m_actionData.createData.dwCreationFlags;
13784
13785 // If the creation flags has DEBUG_PROCESS in them, then we're
13786 // Win32 debugging this process. Otherwise, we have to create
13787 // suspended to give us time to setup up our side of the IPC
13788 // channel.
13789 BOOL fInteropDebugging =
13790#if defined(FEATURE_INTEROP_DEBUGGING)
13791 (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
13792#else
13793 false; // Interop not supported.
13794#endif
13795
13796 // Have Win32 create the process...
13797 hr = m_pNativePipeline->CreateProcessUnderDebugger(
13798 m_actionData.createData.machineInfo,
13799 m_actionData.createData.programName,
13800 m_actionData.createData.programArgs,
13801 m_actionData.createData.lpProcessAttributes,
13802 m_actionData.createData.lpThreadAttributes,
13803 m_actionData.createData.bInheritHandles,
13804 dwCreationFlags,
13805 m_actionData.createData.lpEnvironment,
13806 m_actionData.createData.lpCurrentDirectory,
13807 m_actionData.createData.lpStartupInfo,
13808 m_actionData.createData.lpProcessInformation);
13809
13810 if (SUCCEEDED(hr))
13811 {
13812 // Process ID is filled in after process is succesfully created.
13813 DWORD dwProcessId = m_actionData.createData.lpProcessInformation->dwProcessId;
13814 ProcessDescriptor pd = ProcessDescriptor::FromPid(dwProcessId);
13815
13816 RSUnsafeExternalSmartPtr<CordbProcess> pProcess;
13817 hr = m_pShim->InitializeDataTarget(&pd);
13818
13819 if (SUCCEEDED(hr))
13820 {
13821 // To emulate V2 semantics, we pass 0 for the clrInstanceID into
13822 // OpenVirtualProcess. This will then connect to the first CLR
13823 // loaded.
13824 const ULONG64 cFirstClrLoaded = 0;
13825 hr = CordbProcess::OpenVirtualProcess(cFirstClrLoaded, m_pShim->GetDataTarget(), NULL, m_cordb, &pd, m_pShim, &pProcess);
13826 }
13827
13828 // Shouldn't happen on a create, only an attach
13829 _ASSERTE(hr != CORDBG_E_DEBUGGER_ALREADY_ATTACHED);
13830
13831 // Remember the process in the global list of processes.
13832 if (SUCCEEDED(hr))
13833 {
13834 EX_TRY
13835 {
13836 // Mark if we're interop-debugging
13837 if (fInteropDebugging)
13838 {
13839 pProcess->EnableInteropDebugging();
13840 }
13841
13842 m_cordb->AddProcess(pProcess); // will take ref if it succeeds
13843 }
13844 EX_CATCH_HRESULT(hr);
13845 }
13846
13847 // If we're Win32 attached to this process, then increment the
13848 // proper count, otherwise add this process to the wait set
13849 // and resume the process's main thread.
13850 if (SUCCEEDED(hr))
13851 {
13852 _ASSERTE(m_pProcess == NULL);
13853 m_pProcess.Assign(pProcess);
13854 }
13855 }
13856
13857
13858 //
13859 // Signal the hr to the caller.
13860 //
13861 m_actionResult = hr;
13862 SetEvent(m_actionTakenEvent);
13863}
13864
13865
13866//
13867// Send a DebugActiveProcess event to the Win32 thread to have it attach to
13868// a new process.
13869//
13870HRESULT CordbWin32EventThread::SendDebugActiveProcessEvent(
13871 MachineInfo machineInfo,
13872 const ProcessDescriptor *pProcessDescriptor,
13873 bool fWin32Attach,
13874 CordbProcess *pProcess)
13875{
13876 HRESULT hr = S_OK;
13877
13878 LockSendToWin32EventThreadMutex();
13879
13880 m_actionData.attachData.machineInfo = machineInfo;
13881 m_actionData.attachData.processDescriptor = *pProcessDescriptor;
13882#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
13883 m_actionData.attachData.fWin32Attach = fWin32Attach;
13884#endif
13885 m_actionData.attachData.pProcess = pProcess;
13886
13887 // m_action is set last so that the win32 event thread can inspect
13888 // it and take action without actually having to take any
13889 // locks. The lock around this here is simply to prevent multiple
13890 // threads from making requests at the same time.
13891 m_action = W32ETA_ATTACH_PROCESS;
13892
13893 BOOL succ = SetEvent(m_threadControlEvent);
13894
13895 if (succ)
13896 {
13897 DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE);
13898
13899 if (ret == WAIT_OBJECT_0)
13900 hr = m_actionResult;
13901 else
13902 hr = HRESULT_FROM_GetLastError();
13903 }
13904 else
13905 hr = HRESULT_FROM_GetLastError();
13906
13907 UnlockSendToWin32EventThreadMutex();
13908
13909 return hr;
13910}
13911
13912//-----------------------------------------------------------------------------
13913// Is the given thread id a helper thread (real or worker?)
13914//-----------------------------------------------------------------------------
13915bool CordbProcess::IsHelperThreadWorked(DWORD tid)
13916{
13917 // Check against the id gained by sniffing Thread-Create events.
13918 if (tid == this->m_helperThreadId)
13919 {
13920 return true;
13921 }
13922
13923 // Now check for potential datate in the IPC block. If not there,
13924 // then we know it can't be the helper.
13925 DebuggerIPCControlBlock * pDCB = this->GetDCB();
13926
13927 if (pDCB == NULL)
13928 {
13929 return false;
13930 }
13931
13932 // get the latest information from the LS DCB
13933 UpdateRightSideDCB();
13934 return
13935 (tid == pDCB->m_realHelperThreadId) ||
13936 (tid == pDCB->m_temporaryHelperThreadId);
13937
13938}
13939
13940//---------------------------------------------------------------------------------------
13941//
13942// Cleans up the Left Side's DCB after a failed attach attempt.
13943//
13944// Assumptions:
13945// Called when the left-site failed initialization
13946//
13947// Notes:
13948// This can be called multiple times.
13949//---------------------------------------------------------------------------------------
13950void CordbProcess::CleanupHalfBakedLeftSide()
13951{
13952 if (GetDCB() != NULL)
13953 {
13954 EX_TRY
13955 {
13956 GetDCB()->m_rightSideIsWin32Debugger = false;
13957 UpdateLeftSideDCBField(&(GetDCB()->m_rightSideIsWin32Debugger), sizeof(GetDCB()->m_rightSideIsWin32Debugger));
13958
13959 if (m_pEventChannel != NULL)
13960 {
13961 m_pEventChannel->Delete();
13962 m_pEventChannel = NULL;
13963 }
13964 }
13965 EX_CATCH
13966 {
13967 _ASSERTE(!"Writing process memory failed, perhaps due to an unexpected disconnection from the target.");
13968 }
13969 EX_END_CATCH(SwallowAllExceptions);
13970 }
13971
13972 // Close and null out the various handles and events, including our process handle m_handle.
13973 CloseIPCHandles();
13974
13975 m_cordb.Clear();
13976
13977 // This process object is Dead-On-Arrival, so it doesn't really have anything to neuter.
13978 // But for safekeeping, we'll mark it as neutered.
13979 UnsafeNeuterDeadObject();
13980}
13981
13982
13983//---------------------------------------------------------------------------------------
13984//
13985// Attach to an existing process.
13986//
13987//
13988// Assumptions:
13989// Called on W32Event Thread, in response to event sent by
13990// code:CordbWin32EventThread::SendDebugActiveProcessEvent
13991//
13992// Notes:
13993// Attach to a process. This is called in the context of the Win32
13994// event thread to ensure that if we're Win32 debugging the process
13995// that the same thread that waits for debugging events will be the
13996// thread that attaches the process.
13997//
13998// @dbgtodo shim: this will be part of the shim
13999//---------------------------------------------------------------------------------------
14000void CordbWin32EventThread::AttachProcess()
14001{
14002 _ASSERTE(IsWin32EventThread());
14003
14004 RSUnsafeExternalSmartPtr<CordbProcess> pProcess;
14005
14006 m_action = W32ETA_NONE;
14007
14008 HRESULT hr = S_OK;
14009
14010 ProcessDescriptor processDescriptor = m_actionData.attachData.processDescriptor;
14011 bool fNativeAttachSucceeded = false;
14012
14013 // Always do OS attach to the target.
14014 // By this point, the pid should be valid (because OpenProcess above), pending some race where the process just exited.
14015 // The OS will enforce that only 1 debugger is attached.
14016 // Common failure paths here would be: access denied, double-attach
14017 {
14018 hr = m_pNativePipeline->DebugActiveProcess(m_actionData.attachData.machineInfo,
14019 processDescriptor);
14020 if (FAILED(hr))
14021 {
14022 goto LExit;
14023 }
14024 fNativeAttachSucceeded = true;
14025 }
14026
14027
14028 hr = m_pShim->InitializeDataTarget(&processDescriptor);
14029 if (FAILED(hr))
14030 {
14031 goto LExit;
14032 }
14033
14034 // To emulate V2 semantics, we pass 0 for the clrInstanceID into
14035 // OpenVirtualProcess. This will then connect to the first CLR
14036 // loaded.
14037 {
14038 const ULONG64 cFirstClrLoaded = 0;
14039 hr = CordbProcess::OpenVirtualProcess(cFirstClrLoaded, m_pShim->GetDataTarget(), NULL, m_cordb, &processDescriptor, m_pShim, &pProcess);
14040 if (FAILED(hr))
14041 {
14042 goto LExit;
14043 }
14044 }
14045
14046 // Remember the process in the global list of processes.
14047 // The caller back in code:Cordb::DebugActiveProcess will then get this by fetching it from the list.
14048
14049 EX_TRY
14050 {
14051 // Mark interop-debugging
14052 if (m_actionData.attachData.IsInteropDebugging())
14053 {
14054 pProcess->EnableInteropDebugging(); // Throwing
14055 }
14056
14057 m_cordb->AddProcess(pProcess); // will take ref if it succeeds
14058
14059
14060 // Queue fake Attach event for CreateProcess
14061 {
14062 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(pProcess);
14063 m_pShim->BeginQueueFakeAttachEvents();
14064 }
14065 }
14066 EX_CATCH_HRESULT(hr);
14067 if (FAILED(hr))
14068 {
14069 goto LExit;
14070 }
14071
14072 _ASSERTE(m_pProcess == NULL);
14073 m_pProcess.Assign(pProcess);
14074 pProcess.Clear(); // ownership transfered to m_pProcess
14075
14076 // Should have succeeded if we got to this point.
14077 _ASSERTE(SUCCEEDED(hr));
14078
14079
14080LExit:
14081 if (FAILED(hr))
14082 {
14083 // If we succeed to do a native-attach, but then failed elsewhere, try to native-detach.
14084 if (fNativeAttachSucceeded)
14085 {
14086 m_pNativePipeline->DebugActiveProcessStop(processDescriptor.m_Pid);
14087 }
14088
14089 if (pProcess != NULL)
14090 {
14091 // Safe to call this even if the process wasn't added.
14092 m_cordb->RemoveProcess(pProcess);
14093 pProcess->CleanupHalfBakedLeftSide();
14094 pProcess.Clear();
14095 }
14096 m_pProcess.Clear();
14097 }
14098
14099 //
14100 // Signal the hr to the caller.
14101 //
14102 m_actionResult = hr;
14103 SetEvent(m_actionTakenEvent);
14104}
14105
14106
14107// Note that the actual 'DetachProcess' method is really ExitProcess with CW32ET_UNKNOWN_PROCESS_SLOT ==
14108// processSlot
14109HRESULT CordbWin32EventThread::SendDetachProcessEvent(CordbProcess *pProcess)
14110{
14111 LOG((LF_CORDB, LL_INFO1000, "W32ET::SDPE\n"));
14112 HRESULT hr = S_OK;
14113
14114 LockSendToWin32EventThreadMutex();
14115
14116 m_actionData.detachData.pProcess = pProcess;
14117
14118 // m_action is set last so that the win32 event thread can inspect it and take action without actually
14119 // having to take any locks. The lock around this here is simply to prevent multiple threads from making
14120 // requests at the same time.
14121 m_action = W32ETA_DETACH;
14122
14123 BOOL succ = SetEvent(m_threadControlEvent);
14124
14125 if (succ)
14126 {
14127 DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE);
14128
14129 if (ret == WAIT_OBJECT_0)
14130 hr = m_actionResult;
14131 else
14132 hr = HRESULT_FROM_GetLastError();
14133 }
14134 else
14135 hr = HRESULT_FROM_GetLastError();
14136
14137 UnlockSendToWin32EventThreadMutex();
14138
14139 return hr;
14140}
14141
14142#ifdef FEATURE_INTEROP_DEBUGGING
14143//
14144// Send a UnmanagedContinue event to the Win32 thread to have it
14145// continue from an unmanged debug event.
14146//
14147HRESULT CordbWin32EventThread::SendUnmanagedContinue(CordbProcess *pProcess,
14148 EUMContinueType eContType)
14149{
14150 HRESULT hr = S_OK;
14151
14152 // If this were being called on the win32 EventThread, we'd deadlock.
14153 _ASSERTE(!IsWin32EventThread());
14154
14155 // This can't hold the process lock, b/c we're making a cross-thread call,
14156 // and our target will need the process lock.
14157 _ASSERTE(!pProcess->ThreadHoldsProcessLock());
14158
14159 LockSendToWin32EventThreadMutex();
14160
14161 m_actionData.continueData.process = pProcess;
14162 m_actionData.continueData.eContType = eContType;
14163
14164 // m_action is set last so that the win32 event thread can inspect
14165 // it and take action without actually having to take any
14166 // locks. The lock around this here is simply to prevent multiple
14167 // threads from making requests at the same time.
14168 m_action = W32ETA_CONTINUE;
14169
14170 BOOL succ = SetEvent(m_threadControlEvent);
14171
14172 if (succ)
14173 {
14174 DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE);
14175
14176 if (ret == WAIT_OBJECT_0)
14177 hr = m_actionResult;
14178 else
14179 hr = HRESULT_FROM_GetLastError();
14180 }
14181 else
14182 hr = HRESULT_FROM_GetLastError();
14183
14184 UnlockSendToWin32EventThreadMutex();
14185
14186 return hr;
14187}
14188
14189
14190//
14191// Handle unmanaged continue. Continue an unmanaged debug
14192// event. Deferes to UnmanagedContinue. This is called in the context
14193// of the Win32 event thread to ensure that if we're Win32 debugging
14194// the process that the same thread that waits for debugging events
14195// will be the thread that continues the process.
14196//
14197void CordbWin32EventThread::HandleUnmanagedContinue()
14198{
14199 _ASSERTE(IsWin32EventThread());
14200
14201 m_action = W32ETA_NONE;
14202 HRESULT hr = S_OK;
14203
14204 // Continue the process
14205 CordbProcess *pProcess = m_actionData.continueData.process;
14206
14207 // If we lost the process object, we must have exited.
14208 if (m_pProcess != NULL)
14209 {
14210 _ASSERTE(m_pProcess != NULL);
14211 _ASSERTE(pProcess == m_pProcess);
14212
14213 _ASSERTE(!pProcess->ThreadHoldsProcessLock());
14214
14215 RSSmartPtr<CordbProcess> proc(pProcess);
14216 RSLockHolder ch(&pProcess->m_processMutex);
14217
14218 hr = UnmanagedContinue(pProcess, m_actionData.continueData.eContType);
14219 }
14220
14221 // Signal the hr to the caller.
14222 m_actionResult = hr;
14223 SetEvent(m_actionTakenEvent);
14224}
14225
14226//
14227// Continue an unmanaged debug event. This is called in the context of the Win32 Event thread to ensure that the same
14228// thread that waits for debug events will be the thread that continues the process.
14229//
14230HRESULT CordbWin32EventThread::UnmanagedContinue(CordbProcess *pProcess,
14231 EUMContinueType eContType)
14232{
14233 _ASSERTE(pProcess->ThreadHoldsProcessLock());
14234 _ASSERTE(IsWin32EventThread());
14235 _ASSERTE(m_pShim != NULL);
14236
14237 HRESULT hr = S_OK;
14238
14239 STRESS_LOG1(LF_CORDB, LL_INFO1000, "UM Continue. type=%d\n", eContType);
14240
14241 if (eContType == cOobUMContinue)
14242 {
14243 _ASSERTE(pProcess->m_outOfBandEventQueue != NULL);
14244
14245 // Dequeue the OOB event.
14246 CordbUnmanagedEvent *ue = pProcess->m_outOfBandEventQueue;
14247 CordbUnmanagedThread *ut = ue->m_owner;
14248 pProcess->DequeueOOBUnmanagedEvent(ut);
14249
14250 // Do a little extra work if that was an OOB exception event...
14251 hr = ue->m_owner->FixupAfterOOBException(ue);
14252 _ASSERTE(SUCCEEDED(hr));
14253
14254 // Continue from the event.
14255 DoDbgContinue(pProcess, ue);
14256
14257 // If there are more queued OOB events, dispatch them now.
14258 if (pProcess->m_outOfBandEventQueue != NULL)
14259 pProcess->DispatchUnmanagedOOBEvent();
14260
14261 // Note: if we previously skipped letting the entire process go on an IB continue due to a blocking OOB event,
14262 // and if the OOB event queue is now empty, then go ahead and let the process continue now...
14263 if ((pProcess->m_doRealContinueAfterOOBBlock == true) &&
14264 (pProcess->m_outOfBandEventQueue == NULL))
14265 goto doRealContinue;
14266 }
14267 else if (eContType == cInternalUMContinue)
14268 {
14269 // We're trying to get into a synced state which means we need the process running (potentially
14270 // with some threads hijacked) in order to have the helper thread do the sync.
14271 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: internal continue.\n"));
14272
14273 if (!pProcess->GetSynchronized())
14274 {
14275 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: internal continue, !sync'd.\n"));
14276 pProcess->ResumeUnmanagedThreads();
14277
14278 // the event we may need to hijack and continue;
14279 CordbUnmanagedEvent* pEvent = pProcess->m_lastQueuedUnmanagedEvent;
14280
14281 // It is possible to be stopped at either an IB or an OOB event here. We only want to
14282 // continue from an IB event here though
14283 if(pProcess->m_state & CordbProcess::PS_WIN32_STOPPED && pEvent != NULL &&
14284 pEvent->IsEventWaitingForContinue())
14285 {
14286 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: internal continue, frozen on IB event.\n"));
14287
14288 // There should be a uncontinued IB event at the head of the queue
14289 _ASSERTE(pEvent->IsIBEvent());
14290 _ASSERTE(!pEvent->IsEventContinuedUnhijacked());
14291 _ASSERTE(!pEvent->IsEventContinuedHijacked());
14292
14293 // Ensure that the event is hijacked now (it may not have been before) so that the
14294 // thread does not slip forward during the sync process. After that we can safely continue
14295 // it.
14296 pProcess->HijackIBEvent(pEvent);
14297 m_pShim->GetWin32EventThread()->DoDbgContinue(pProcess, pEvent);
14298 }
14299 }
14300
14301 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: internal continue, done.\n"));
14302 }
14303 else
14304 {
14305 // If we're here, then we know 100% for sure that we've successfully gotten the managed continue event to the
14306 // Left Side, so we can stop force hijacking left over in-band events now. Note: if we had hijacked any such
14307 // events, they'll be dispatched below since they're properly queued.
14308 pProcess->m_specialDeferment = false;
14309
14310 // We don't actually do any work if there is an outstanding out-of-band event. When we do continue from the
14311 // out-of-band event, we'll do this work, too.
14312 if (pProcess->m_outOfBandEventQueue != NULL)
14313 {
14314 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: ignoring real continue due to block by out-of-band event(s).\n"));
14315
14316 _ASSERTE(pProcess->m_doRealContinueAfterOOBBlock == false);
14317 pProcess->m_doRealContinueAfterOOBBlock = true;
14318 }
14319 else
14320 {
14321doRealContinue:
14322 // This is either the Frozen -> Running transition or a
14323 // Synced -> Running transition
14324 _ASSERTE(pProcess->m_outOfBandEventQueue == NULL);
14325
14326
14327 pProcess->m_doRealContinueAfterOOBBlock = false;
14328
14329 LOG((LF_CORDB, LL_INFO1000, "W32ET::UC: continuing the process.\n"));
14330 // Dispatch any more queued in-band events, or if there are none then just continue the process.
14331 //
14332 // Note: don't dispatch more events if we've already sent up the ExitProcess event... those events are just
14333 // lost.
14334 if ((pProcess->HasUndispatchedNativeEvents()) && (pProcess->m_exiting == false))
14335 {
14336 pProcess->DispatchUnmanagedInBandEvent();
14337 }
14338 else
14339 {
14340 // If the unmanaged event queue is empty now, and the process is synchronized, and there are queued
14341 // managed events, then go ahead and get more managed events dispatched.
14342 //
14343 // Note: don't dispatch more events if we've already sent up the ExitProcess event... those events are
14344 // just lost.
14345 if (pProcess->GetSynchronized() && (!m_pShim->GetManagedEventQueue()->IsEmpty()) && (pProcess->m_exiting == false))
14346 {
14347 if(pProcess->m_state & CordbProcess::PS_WIN32_STOPPED)
14348 {
14349 DoDbgContinue(pProcess, pProcess->m_lastDispatchedIBEvent);
14350
14351 // This if should not be necessary, I am just being extra careful because this
14352 // fix is going in late - see issue 818301
14353 _ASSERTE(pProcess->m_lastDispatchedIBEvent != NULL);
14354 if(pProcess->m_lastDispatchedIBEvent != NULL)
14355 {
14356 pProcess->m_lastDispatchedIBEvent->m_owner->InternalRelease();
14357 pProcess->m_lastDispatchedIBEvent = NULL;
14358 }
14359 }
14360
14361 // Now, get more managed events dispatched.
14362 pProcess->SetSynchronized(false);
14363 pProcess->MarkAllThreadsDirty();
14364 m_cordb->ProcessStateChanged();
14365 }
14366 else
14367 {
14368 // free all the hijacked threads that hit native debug events
14369 pProcess->ResumeHijackedThreads();
14370
14371 // after continuing the here the process should be running completely
14372 // free... no hijacks, no suspended threads, and of course not frozen
14373 if(pProcess->m_state & CordbProcess::PS_WIN32_STOPPED)
14374 {
14375 DoDbgContinue(pProcess, pProcess->m_lastDispatchedIBEvent);
14376 // This if should not be necessary, I am just being extra careful because this
14377 // fix is going in late - see issue 818301
14378 _ASSERTE(pProcess->m_lastDispatchedIBEvent != NULL);
14379 if(pProcess->m_lastDispatchedIBEvent != NULL)
14380 {
14381 pProcess->m_lastDispatchedIBEvent->m_owner->InternalRelease();
14382 pProcess->m_lastDispatchedIBEvent = NULL;
14383 }
14384 }
14385 }
14386 }
14387
14388 // Implicit Release on UT
14389 }
14390 }
14391
14392 return hr;
14393}
14394#endif // FEATURE_INTEROP_DEBUGGING
14395
14396void ExitProcessWorkItem::Do()
14397{
14398 STRESS_LOG1(LF_CORDB, LL_INFO1000, "ExitProcessWorkItem proc=%p\n", GetProcess());
14399
14400 // This is being called on the RCET.
14401 // That's the thread that dispatches managed events. Since it's calling us now, we know
14402 // it can't be dispatching a managed event, and so we don't need to both waiting for it
14403
14404 {
14405 // Get the SG lock here to coordinate against any other continues.
14406 RSLockHolder ch(GetProcess()->GetStopGoLock());
14407 RSLockHolder ch2(&(GetProcess()->m_processMutex));
14408
14409 LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: ExitProcess callback\n"));
14410
14411 // We're synchronized now, so mark the process as such.
14412 GetProcess()->SetSynchronized(true);
14413 GetProcess()->IncStopCount();
14414
14415 // By the time we release the SG + Process locks here, the process object has been
14416 // marked as exiting + terminated (by the w32et which queued us). Future attemps to
14417 // continue should fail, and thus we should remain synchronized.
14418 }
14419
14420
14421 // Just to be safe, neuter any children before the exit process callback.
14422 {
14423 RSLockHolder ch(GetProcess()->GetProcessLock());
14424
14425 // Release the process.
14426 GetProcess()->NeuterChildren();
14427 }
14428
14429 RSSmartPtr<Cordb> pCordb(NULL);
14430
14431 // There is a race condition here where the debuggee process is killed while we are processing a process
14432 // detach. We queue the process exit event for the Win32 event thread before queueing the process detach
14433 // event. By the time this function is executed, we may have neutered the CordbProcess already as a
14434 // result of code:CordbProcess::Detach. Detect that case here under the SG lock.
14435 {
14436 RSLockHolder ch(GetProcess()->GetStopGoLock());
14437 if (!GetProcess()->IsNeutered())
14438 {
14439 _ASSERTE(GetProcess()->m_cordb != NULL);
14440 pCordb.Assign(GetProcess()->m_cordb);
14441 }
14442 }
14443
14444 // Move this into Shim?
14445
14446 // Invoke the ExitProcess callback. This is very important since the a shell
14447 // may rely on it for proper shutdown and may hang if they don't get it.
14448 // We don't expect Cordbg to continue from this (we're certainly not going to wait for it).
14449 if ((pCordb != NULL) && (pCordb->m_managedCallback != NULL))
14450 {
14451 PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(GetProcess());
14452 pCordb->m_managedCallback->ExitProcess(GetProcess());
14453 }
14454
14455 // This CordbProcess object now has no reservations against a client calling ICorDebug::Terminate.
14456 // That call may race against the CordbProcess::Neuter below, but since we already neutered the children,
14457 // that neuter call will not do anything interesting that will conflict with Terminate.
14458
14459 LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: returned from ExitProcess callback\n"));
14460
14461 {
14462 RSLockHolder ch(GetProcess()->GetStopGoLock());
14463
14464 // Release the process.
14465 GetProcess()->Neuter();
14466 }
14467
14468 // Our dtor will release the Process object.
14469 // This may be the final release on the process.
14470}
14471
14472
14473//---------------------------------------------------------------------------------------
14474//
14475// Handles process exiting and detach cases
14476//
14477// Arguments:
14478// fDetach - true if detaching, false if process is exiting.
14479//
14480// Return Value:
14481// The type of the next argument in the signature,
14482// normalized.
14483//
14484// Assumptions:
14485// On exit, the process has already exited and we detected this by either an EXIT_PROCESS
14486// native debug event, or by waiting on the process handle.
14487// On detach, the process is stil live.
14488//
14489// Notes:
14490// ExitProcess is called when a process exits or detaches.
14491// This does our final cleanup and removes the process from our wait sets.
14492// We're either here because we're detaching (fDetach == TRUE), or because the process has really exited,
14493// and we're doing shutdown logic.
14494//
14495//---------------------------------------------------------------------------------------
14496void CordbWin32EventThread::ExitProcess(bool fDetach)
14497{
14498 INTERNAL_API_ENTRY(this);
14499
14500 // Consider the following when you're modifying this function:
14501 // - The OS can kill the debuggee at any time.
14502 // - ExitProcess can race with detach.
14503
14504 LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: begin ExitProcess, detach=%d\n", fDetach));
14505
14506
14507 // For the Mac remote debugging transport, DebugActiveProcessStop() is a nop. The transport will be
14508 // shut down later when we neuter the CordbProcess.
14509#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
14510 // @dbgtodo shim: this is a primitive workaround for interop-detach
14511 // Eventually, the Debugger owns the detach pipeline, so this won't be necessary.
14512 if (fDetach && (m_pProcess != NULL))
14513 {
14514 HRESULT hr = m_pNativePipeline->DebugActiveProcessStop(m_pProcess->GetProcessDescriptor()->m_Pid);
14515
14516 // We don't expect detach to fail (we check earlier for common conditions that
14517 // may cause it to fail)
14518 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
14519 if( FAILED(hr) )
14520 {
14521 m_actionResult = hr;
14522 SetEvent(m_actionTakenEvent);
14523 return;
14524 }
14525 }
14526#endif // !FEATURE_DBGIPC_TRANSPORT_DI
14527
14528
14529 // We don't really care if we're on the Win32 thread or not here. We just want to be sure that
14530 // the LS Exit case and the Detach case both occur on the same thread. This makes it much easier
14531 // to assert that if we exit while detaching, EP is only called once.
14532 // If we ever decide to make the RCET listen on the LS process handle for EP(exit), then we should also
14533 // make the EP(detach) handled on the RCET (via DoFavor() ).
14534 _ASSERTE(IsWin32EventThread());
14535
14536 // So either the Exit case or Detach case must happen first.
14537 // 1) If Detach first, then LS process is removed from wait set and so EP(Exit) will never happen
14538 // because we check wait set after returning from EP(Detach).
14539 // 2) If Exit is first, m_pProcess gets set=NULL. EP(detach) will still get called, so explicitly check that.
14540 if (fDetach && ((m_pProcess == NULL) || m_pProcess->m_terminated))
14541 {
14542 // m_terminated is only set after the LS exits.
14543 // So the only way (fDetach && m_terminated) is true is if the LS exited while detaching. In that case
14544 // we already called EP(exit) and we don't want to call it again for EP(detach). So return here.
14545 LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: In EP(detach), but EP(exit) already called. Early failure\n"));
14546
14547 m_actionResult = CORDBG_E_PROCESS_TERMINATED;
14548 SetEvent(m_actionTakenEvent);
14549
14550 return;
14551 }
14552
14553 // We null m_pProcess at the end here, so
14554 // Only way we could get here w/ null process is if we're called twice. We can only be called
14555 // by detach or exit. Can't detach twice, can't exit twice, so must have been one of each.
14556 // If exit is first, we got removed from the wait set, so 2nd call must be detach and we'd catch
14557 // that above. If detach is first, we'd get removed from the wait set and so exit would never happen.
14558 _ASSERTE(m_pProcess != NULL);
14559 _ASSERTE(!m_pProcess->ThreadHoldsProcessLock());
14560
14561
14562
14563 // Mark the process teminated. After this, the RCET will never call FlushQueuedEvents. It will
14564 // ignore all events it receives (including a SyncComplete) and the RCET also does not listen
14565 // to terminated processes (so ProcessStateChange() won't cause a FQE either).
14566 m_pProcess->Terminating(fDetach);
14567
14568 // Take care of the race where the process exits right after the user calls Continue() from the last
14569 // managed event but before the handler has actually returned.
14570 //
14571 // Also, To get through this lock means that either:
14572 // 1. FlushQueuedEvents is not currently executing and no one will call FQE.
14573 // 2. FQE is exiting but is in the middle of a callback (so AreDispatchingEvent = true)
14574 //
14575 m_pProcess->Lock();
14576
14577 m_pProcess->m_exiting = true;
14578
14579 if (fDetach)
14580 {
14581 m_pProcess->SetSynchronized(false);
14582 }
14583
14584 // If we are exiting, we *must* dispatch the ExitProcess callback, but we will delete all the events
14585 // in the queue and not bother dispatching anything else. If (and only if) we are currently dispatching
14586 // an event, then we will wait while that event is finished before invoking ExitProcess.
14587 // (Note that a dispatched event has already been removed from the queue)
14588
14589 // Remove the process from the global list of processes.
14590 m_cordb->RemoveProcess(m_pProcess);
14591
14592 if (fDetach)
14593 {
14594 // Signal the hr to the caller.
14595 LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: Detach: send result back!\n"));
14596
14597 m_actionResult = S_OK;
14598 SetEvent(m_actionTakenEvent);
14599 }
14600
14601 m_pProcess->Unlock();
14602
14603 // Delete all queued events
14604 m_pProcess->DeleteQueuedEvents();
14605
14606
14607 // If we're detaching, then the Detach already neutered everybody, so nothing here.
14608 // If we're exiting, then we still need to neuter things, but we can't do that on this thread,
14609 // so we queue it. We also need to dispatch an exit process callback. We'll queue that onto the RCET
14610 // and dispatch it inband w/the other callbacks.
14611 if (!fDetach)
14612 {
14613#ifdef FEATURE_PAL
14614 // Cleanup the transport pipe and semaphore files that might be left by the target (LS) process.
14615 m_pNativePipeline->CleanupTargetProcess();
14616#endif
14617 ExitProcessWorkItem * pItem = new (nothrow) ExitProcessWorkItem(m_pProcess);
14618 if (pItem != NULL)
14619 {
14620 m_cordb->m_rcEventThread->QueueAsyncWorkItem(pItem);
14621 }
14622 }
14623
14624 // This will remove the process from our wait lists (so that we don't send multiple ExitProcess events).
14625 m_pProcess.Clear();
14626}
14627
14628
14629//
14630// Start actually creates and starts the thread.
14631//
14632HRESULT CordbWin32EventThread::Start()
14633{
14634 HRESULT hr = S_OK;
14635 if (m_threadControlEvent == NULL)
14636 return E_INVALIDARG;
14637
14638 // Create the thread suspended to make sure that m_threadId is set
14639 // before CordbWin32EventThread::ThreadProc runs
14640 // Stack size = 0x80000 = 512KB
14641 m_thread = CreateThread(NULL, 0x80000, &CordbWin32EventThread::ThreadProc,
14642 (LPVOID) this, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &m_threadId);
14643
14644 if (m_thread == NULL)
14645 return HRESULT_FROM_GetLastError();
14646
14647 DWORD succ = ResumeThread(m_thread);
14648 if (succ == (DWORD)-1)
14649 return HRESULT_FROM_GetLastError();
14650 return hr;
14651}
14652
14653
14654//
14655// Stop causes the thread to stop receiving events and exit. It
14656// waits for it to exit before returning.
14657//
14658HRESULT CordbWin32EventThread::Stop()
14659{
14660 HRESULT hr = S_OK;
14661
14662 // m_pProcess may be NULL from CordbWin32EventThread::ExitProcess
14663
14664 // Can't block on W32ET while holding the process-lock since the W32ET may need that to exit.
14665 // But since m_pProcess may be null, we can't enforce that.
14666
14667 if (m_thread != NULL)
14668 {
14669 LockSendToWin32EventThreadMutex();
14670 m_action = W32ETA_NONE;
14671 m_run = FALSE;
14672
14673 SetEvent(m_threadControlEvent);
14674 UnlockSendToWin32EventThreadMutex();
14675
14676 DWORD ret = WaitForSingleObject(m_thread, INFINITE);
14677
14678 if (ret != WAIT_OBJECT_0)
14679 hr = HRESULT_FROM_GetLastError();
14680 }
14681
14682 m_pProcess.Clear();
14683 m_cordb.Clear();
14684
14685 return hr;
14686}
14687
14688
14689
14690
14691
14692
14693
14694
14695// Allocate a buffer of cbBuffer bytes in the target.
14696//
14697// Arguments:
14698// cbBuffer - count of bytes for the buffer.
14699//
14700// Returns:
14701// a TargetBuffer describing the new memory region in the target.
14702// Throws on error.
14703TargetBuffer CordbProcess::GetRemoteBuffer(ULONG cbBuffer)
14704{
14705 INTERNAL_SYNC_API_ENTRY(this); //
14706
14707 // Create and initialize the event as synchronous
14708 DebuggerIPCEvent event;
14709 InitIPCEvent(&event,
14710 DB_IPCE_GET_BUFFER,
14711 true,
14712 VMPTR_AppDomain::NullPtr());
14713
14714 // Indicate the buffer size wanted
14715 event.GetBuffer.bufSize = cbBuffer;
14716
14717 // Make the request, which is synchronous
14718 HRESULT hr = SendIPCEvent(&event, sizeof(event));
14719 IfFailThrow(hr);
14720 _ASSERTE(event.type == DB_IPCE_GET_BUFFER_RESULT);
14721
14722 IfFailThrow(event.GetBufferResult.hr);
14723
14724 // The request succeeded. Return the newly allocated range.
14725 return TargetBuffer(event.GetBufferResult.pBuffer, cbBuffer);
14726}
14727
14728/*
14729 * This will release a previously allocated left side buffer.
14730 */
14731HRESULT CordbProcess::ReleaseRemoteBuffer(void **ppBuffer)
14732{
14733 INTERNAL_SYNC_API_ENTRY(this); //
14734
14735 _ASSERTE(m_pShim != NULL);
14736
14737 // Create and initialize the event as synchronous
14738 DebuggerIPCEvent event;
14739 InitIPCEvent(&event,
14740 DB_IPCE_RELEASE_BUFFER,
14741 true,
14742 VMPTR_AppDomain::NullPtr());
14743
14744 // Indicate the buffer to release
14745 event.ReleaseBuffer.pBuffer = (*ppBuffer);
14746
14747 // Make the request, which is synchronous
14748 HRESULT hr = SendIPCEvent(&event, sizeof(event));
14749 TESTANDRETURNHR(hr);
14750
14751 (*ppBuffer) = NULL;
14752
14753 // Indicate success
14754 return event.ReleaseBufferResult.hr;
14755}
14756
14757HRESULT CordbProcess::SetDesiredNGENCompilerFlags(DWORD dwFlags)
14758{
14759 PUBLIC_API_ENTRY(this);
14760 FAIL_IF_NEUTERED(this);
14761
14762#if defined(FEATURE_PREJIT)
14763 if ((dwFlags != CORDEBUG_JIT_DEFAULT) && (dwFlags != CORDEBUG_JIT_DISABLE_OPTIMIZATION))
14764 {
14765 return E_INVALIDARG;
14766 }
14767
14768 CordbProcess *pProcess = GetProcess();
14769 ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess);
14770 HRESULT hr = S_OK;
14771 EX_TRY
14772 {
14773 // Left-side checks that this is a valid time to set the Ngen flags.
14774 hr = pProcess->GetDAC()->SetNGENCompilerFlags(dwFlags);
14775 if (!SUCCEEDED(hr) && GetShim() != NULL)
14776 {
14777 // Emulate V2 error semantics.
14778 hr = GetShim()->FilterSetNgenHresult(hr);
14779 }
14780 }
14781 EX_CATCH_HRESULT(hr);
14782 return hr;
14783
14784#else // !FEATURE_PREJIT
14785 return CORDBG_E_NGEN_NOT_SUPPORTED;
14786
14787#endif // FEATURE_PREJIT
14788}
14789
14790HRESULT CordbProcess::GetDesiredNGENCompilerFlags(DWORD *pdwFlags )
14791{
14792 PUBLIC_API_ENTRY(this);
14793 FAIL_IF_NEUTERED(this);
14794 VALIDATE_POINTER_TO_OBJECT(pdwFlags, DWORD*);
14795 *pdwFlags = 0;
14796
14797 CordbProcess *pProcess = GetProcess();
14798 ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess);
14799 HRESULT hr = S_OK;
14800 EX_TRY
14801 {
14802 hr = pProcess->GetDAC()->GetNGENCompilerFlags(pdwFlags);
14803 }
14804 EX_CATCH_HRESULT(hr);
14805 return hr;
14806}
14807
14808//-----------------------------------------------------------------------------
14809// Get an ICorDebugReference Value for the GC handle.
14810// handle - raw bits for the GC handle.
14811// pOutHandle
14812//-----------------------------------------------------------------------------
14813HRESULT CordbProcess::GetReferenceValueFromGCHandle(
14814 UINT_PTR gcHandle,
14815 ICorDebugReferenceValue **pOutValue)
14816{
14817 PUBLIC_API_ENTRY(this);
14818 FAIL_IF_NEUTERED(this);
14819 ATT_REQUIRE_STOPPED_MAY_FAIL(this);
14820 VALIDATE_POINTER_TO_OBJECT(pOutValue, ICorDebugReferenceValue*);
14821
14822 *pOutValue = NULL;
14823 HRESULT hr = S_OK;
14824
14825 EX_TRY
14826 {
14827 if (gcHandle == NULL)
14828 {
14829 ThrowHR(CORDBG_E_BAD_REFERENCE_VALUE);
14830 }
14831
14832 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
14833 VMPTR_OBJECTHANDLE vmObjHandle = pDAC->GetVmObjectHandle(gcHandle);
14834 if(!pDAC->IsVmObjectHandleValid(vmObjHandle))
14835 {
14836 ThrowHR(CORDBG_E_BAD_REFERENCE_VALUE);
14837 }
14838 ULONG appDomainId = pDAC->GetAppDomainIdFromVmObjectHandle(vmObjHandle);
14839 VMPTR_AppDomain vmAppDomain = pDAC->GetAppDomainFromId(appDomainId);
14840
14841 RSLockHolder lockHolder(GetProcessLock());
14842 CordbAppDomain * pAppDomain = LookupOrCreateAppDomain(vmAppDomain);
14843 lockHolder.Release();
14844
14845 // Now that we finally have the AppDomain, we can go ahead and get a ReferenceValue
14846 // from the ObjectHandle.
14847 hr = CordbReferenceValue::BuildFromGCHandle(pAppDomain, vmObjHandle, pOutValue);
14848 _ASSERTE(SUCCEEDED(hr) == (*pOutValue != NULL));
14849 IfFailThrow(hr);
14850 }
14851 EX_CATCH_HRESULT(hr);
14852 return hr;
14853}
14854
14855//-----------------------------------------------------------------------------
14856// Return count of outstanding GC handles held by CordbHandleValue objects
14857LONG CordbProcess::OutstandingHandles()
14858{
14859 return m_cOutstandingHandles;
14860}
14861
14862//-----------------------------------------------------------------------------
14863// Increment the outstanding handle count for code:CordbProces::OutstandingHandles
14864// This is the inverse of code:CordbProces::DecrementOutstandingHandles
14865void CordbProcess::IncrementOutstandingHandles()
14866{
14867 _ASSERTE(ThreadHoldsProcessLock());
14868 m_cOutstandingHandles++;
14869}
14870
14871//-----------------------------------------------------------------------------
14872// Decrement the outstanding handle count for code:CordbProces::OutstandingHandles
14873// This is the inverse of code:CordbProces::IncrementOutstandingHandles
14874void CordbProcess::DecrementOutstandingHandles()
14875{
14876 _ASSERTE(ThreadHoldsProcessLock());
14877 m_cOutstandingHandles--;
14878}
14879
14880
14881/*
14882 * IsReadyForDetach
14883 *
14884 * This method encapsulates all logic for deciding if it is ok for a debugger to
14885 * detach from the process at this time.
14886 *
14887 * Parameters: None.
14888 *
14889 * Returns: S_OK if it is ok to detach, else a specific HRESULT describing why it
14890 * is not ok to detach.
14891 *
14892 */
14893HRESULT CordbProcess::IsReadyForDetach()
14894{
14895 INTERNAL_API_ENTRY(this);
14896
14897 // Always safe to detach in V3 case.
14898 if (m_pShim == NULL)
14899 {
14900 return S_OK;
14901 }
14902
14903 // If not initialized yet, then there are no detach liabilities.
14904 if (!m_initialized)
14905 {
14906 return S_OK;
14907 }
14908
14909 RSLockHolder lockHolder(&this->m_processMutex);
14910
14911 //
14912 // If there are any outstanding func-evals then fail the detach.
14913 //
14914 if (OutstandingEvalCount() != 0)
14915 {
14916 return CORDBG_E_DETACH_FAILED_OUTSTANDING_EVALS;
14917 }
14918
14919 // V2 didn't check outstanding handles (code:CordbProcess::OutstandingHandles)
14920 // because it could automatically clean those up on detach.
14921
14922 //
14923 // If there are any outstanding steppers then fail the detach.
14924 //
14925 if (m_steppers.IsInitialized() && (m_steppers.GetCount() > 0))
14926 {
14927 return CORDBG_E_DETACH_FAILED_OUTSTANDING_STEPPERS;
14928 }
14929
14930 //
14931 // If there are any outstanding breakpoints then fail the detach.
14932 //
14933 HASHFIND foundAppDomain;
14934 CordbAppDomain *pAppDomain = m_appDomains.FindFirst(&foundAppDomain);
14935
14936 while (pAppDomain != NULL)
14937 {
14938 if (pAppDomain->m_breakpoints.IsInitialized() && (pAppDomain->m_breakpoints.GetCount() > 0))
14939 {
14940 return CORDBG_E_DETACH_FAILED_OUTSTANDING_BREAKPOINTS;
14941 }
14942
14943 // Check for any outstanding EnC modules.
14944 HASHFIND foundModule;
14945 CordbModule * pModule = pAppDomain->m_modules.FindFirst(&foundModule);
14946 while (pModule != NULL)
14947 {
14948 if (pModule->m_EnCCount > 0)
14949 {
14950 return CORDBG_E_DETACH_FAILED_ON_ENC;
14951 }
14952 pModule = pAppDomain->m_modules.FindNext(&foundModule);
14953 }
14954
14955
14956 pAppDomain = m_appDomains.FindNext(&foundAppDomain);
14957 }
14958
14959 // If we're using the shim, give a chance to early-out if the OS doesn't support detach
14960 // so that the user can continue to debug in that case.
14961 // Ideally we'd just rely on the failure from DebugActiveProcessStop, but by then it's too late
14962 // to recover. This function is our only chance to distinguish between graceful detach failures
14963 // and hard detach failures (after which the process object is neutered).
14964 if (m_pShim != NULL)
14965 {
14966#if !defined(FEATURE_CORESYSTEM) // CORESYSTEM TODO
14967 HModuleHolder hKernel32;
14968 hKernel32 = WszLoadLibrary(W("kernel32"));
14969 if (hKernel32 == NULL)
14970 return HRESULT_FROM_GetLastError();
14971 typedef BOOL (*DebugActiveProcessStopSig) (DWORD);
14972 DebugActiveProcessStopSig pDebugActiveProcessStop =
14973 reinterpret_cast<DebugActiveProcessStopSig>(GetProcAddress(hKernel32, "DebugActiveProcessStop"));
14974 if (pDebugActiveProcessStop == NULL)
14975 return COR_E_PLATFORMNOTSUPPORTED;
14976#endif
14977 }
14978
14979 return S_OK;
14980}
14981
14982
14983/*
14984 * Look for any thread which was last seen in the specified AppDomain.
14985 * The CordbAppDomain object is about to be neutered due to an AD Unload
14986 * So the thread must no longer be considered to be in that domain.
14987 * Note that this is a workaround due to the existance of the (possibly incorrect)
14988 * cached AppDomain value. Ideally we would remove the cached value entirely
14989 * and there would be no need for this.
14990 *
14991 * @dbgtodo: , appdomain: We should remove CordbThread::m_pAppDomain in the V3 architecture.
14992 * If we need the thread's current domain, we should get it accurately with DAC.
14993 */
14994void CordbProcess::UpdateThreadsForAdUnload(CordbAppDomain * pAppDomain)
14995{
14996 INTERNAL_API_ENTRY(this);
14997
14998 // If we're doing an AD unload then we should have already seen the ATTACH
14999 // notification for the default domain.
15000 //_ASSERTE( m_pDefaultAppDomain != NULL );
15001 // @dbgtodo appdomain: fix Default domain invariants with DAC-izing Appdomain work.
15002
15003 RSLockHolder lockHolder(GetProcessLock());
15004
15005 CordbThread* t;
15006 HASHFIND find;
15007
15008 // We don't need to prepopulate here (to collect LS state) because we're just updating RS state.
15009 for (t = m_userThreads.FindFirst(&find);
15010 t != NULL;
15011 t = m_userThreads.FindNext(&find))
15012 {
15013 if( t->GetAppDomain() == pAppDomain )
15014 {
15015 // This thread cannot actually be in this AppDomain anymore (since it's being
15016 // unloaded). Reset it to point to the default AppDomain
15017 t->m_pAppDomain = m_pDefaultAppDomain;
15018 }
15019 }
15020}
15021
15022// CordbProcess::LookupClass
15023// Looks up a previously constructed CordbClass instance without creating. May return NULL if the
15024// CordbClass instance doesn't exist.
15025// Argument: (in) vmDomainFile - pointer to the domainfile for the module
15026// (in) mdTypeDef - metadata token for the class
15027// Return value: pointer to a previously created CordbClass instance or NULL in none exists
15028CordbClass * CordbProcess::LookupClass(ICorDebugAppDomain * pAppDomain, VMPTR_DomainFile vmDomainFile, mdTypeDef classToken)
15029{
15030 _ASSERTE(ThreadHoldsProcessLock());
15031
15032 if (pAppDomain != NULL)
15033 {
15034 CordbModule * pModule = ((CordbAppDomain *)pAppDomain)->m_modules.GetBase(VmPtrToCookie(vmDomainFile));
15035 if (pModule != NULL)
15036 {
15037 return pModule->LookupClass(classToken);
15038 }
15039 }
15040 return NULL;
15041} // CordbProcess::LookupClass
15042
15043//---------------------------------------------------------------------------------------
15044// Look for a specific module in the process.
15045//
15046// Arguments:
15047// vmDomainFile - non-null module to lookup
15048//
15049// Returns:
15050// a CordbModule object for the given cookie. Object may be from the cache, or created
15051// lazily.
15052// Never returns null. Throws on error.
15053//
15054// Notes:
15055// A VMPTR_DomainFile has appdomain affinity, but is ultimately scoped to a process.
15056// So if we get a raw VMPTR_DomainFile (eg, from the stackwalker or from some other
15057// lookup function), then we need to do a process wide lookup since we don't know which
15058// appdomain it's in. If you know the appdomain, you can use code:CordbAppDomain::LookupOrCreateModule.
15059//
15060CordbModule * CordbProcess::LookupOrCreateModule(VMPTR_DomainFile vmDomainFile)
15061{
15062 INTERNAL_API_ENTRY(this);
15063
15064 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
15065 _ASSERTE(!vmDomainFile.IsNull());
15066
15067 DomainFileInfo data;
15068 GetDAC()->GetDomainFileData(vmDomainFile, &data); // throws
15069
15070 CordbAppDomain * pAppDomain = LookupOrCreateAppDomain(data.vmAppDomain);
15071 return pAppDomain->LookupOrCreateModule(vmDomainFile);
15072}
15073
15074//---------------------------------------------------------------------------------------
15075// Determine if the process has any in-band queued events which have not been dispatched
15076//
15077// Returns:
15078// TRUE iff there are undispatched IB events
15079//
15080#ifdef FEATURE_INTEROP_DEBUGGING
15081BOOL CordbProcess::HasUndispatchedNativeEvents()
15082{
15083 INTERNAL_API_ENTRY(this);
15084
15085 CordbUnmanagedEvent* pEvent = m_unmanagedEventQueue;
15086 while(pEvent != NULL && pEvent->IsDispatched())
15087 {
15088 pEvent = pEvent->m_next;
15089 }
15090
15091 return pEvent != NULL;
15092}
15093#endif
15094
15095//---------------------------------------------------------------------------------------
15096// Determine if the process has any in-band queued events which have not been user continued
15097//
15098// Returns:
15099// TRUE iff there are user uncontinued IB events
15100//
15101#ifdef FEATURE_INTEROP_DEBUGGING
15102BOOL CordbProcess::HasUserUncontinuedNativeEvents()
15103{
15104 INTERNAL_API_ENTRY(this);
15105
15106 CordbUnmanagedEvent* pEvent = m_unmanagedEventQueue;
15107 while(pEvent != NULL && pEvent->IsEventUserContinued())
15108 {
15109 pEvent = pEvent->m_next;
15110 }
15111
15112 return pEvent != NULL;
15113}
15114#endif
15115
15116//---------------------------------------------------------------------------------------
15117// Hijack the thread which had this event. If the thread is already hijacked this method
15118// has no effect.
15119//
15120// Arguments:
15121// pUnmanagedEvent - the debug event which requires us to hijack
15122//
15123// Returns:
15124// S_OK on success, failing HRESULT if the hijack could not be set up
15125//
15126#ifdef FEATURE_INTEROP_DEBUGGING
15127HRESULT CordbProcess::HijackIBEvent(CordbUnmanagedEvent * pUnmanagedEvent)
15128{
15129 // Can't hijack after the event has already been continued hijacked
15130 _ASSERTE(!pUnmanagedEvent->IsEventContinuedHijacked());
15131 // Can only hijack IB events
15132 _ASSERTE(pUnmanagedEvent->IsIBEvent());
15133
15134 // If we already hijacked the event then there is nothing left to do
15135 if(pUnmanagedEvent->m_owner->IsFirstChanceHijacked() ||
15136 pUnmanagedEvent->m_owner->IsGenericHijacked())
15137 {
15138 return S_OK;
15139 }
15140
15141 ResetEvent(this->m_leftSideUnmanagedWaitEvent);
15142 if (pUnmanagedEvent->m_currentDebugEvent.u.Exception.dwFirstChance)
15143 {
15144 HRESULT hr = pUnmanagedEvent->m_owner->SetupFirstChanceHijackForSync();
15145 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
15146 return hr;
15147 }
15148 else // Second chance exceptions must be generic hijacked.
15149 {
15150 HRESULT hr = pUnmanagedEvent->m_owner->SetupGenericHijack(pUnmanagedEvent->m_currentDebugEvent.dwDebugEventCode, &pUnmanagedEvent->m_currentDebugEvent.u.Exception.ExceptionRecord);
15151 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
15152 return hr;
15153 }
15154}
15155#endif
15156
15157// Sets a bitfield reflecting the managed debugging state at the time of
15158// the jit attach.
15159HRESULT CordbProcess::GetAttachStateFlags(CLR_DEBUGGING_PROCESS_FLAGS *pFlags)
15160{
15161 HRESULT hr = S_OK;
15162 PUBLIC_REENTRANT_API_BEGIN(this)
15163 {
15164 if(pFlags == NULL)
15165 hr = E_POINTER;
15166 else
15167 *pFlags = GetDAC()->GetAttachStateFlags();
15168 }
15169 PUBLIC_API_END(hr);
15170
15171 return hr;
15172}
15173
15174// Determine if this version of ICorDebug is compatibile with the ICorDebug in the specified major CLR version
15175bool CordbProcess::IsCompatibleWith(DWORD clrMajorVersion)
15176{
15177 // The debugger versioning policy is that debuggers generally need to opt-in to supporting major new
15178 // versions of the CLR. Often new versions of the CLR violate some invariant that previous debuggers assume
15179 // (eg. hot/cold splitting in Whidbey, multiple CLRs in a process in CLR v4), and neither VS or the CLR
15180 // teams generally want the support burden of forward compatibility.
15181
15182 //
15183 // If this assert is firing for you, its probably because the major version
15184 // number of the clr.dll has changed. This assert is here to remind you to do a bit of other
15185 // work you may not have realized you needed to do so that our versioning works smoothly
15186 // for debugging. You probably want to contact the CLR DST team if you are a
15187 // non-debugger person hitting this. DON'T JUST DELETE THIS ASSERT!!!
15188 //
15189 // 1) You should ensure new versions of all ICorDebug users in DevDiv (VS Debugger, MDbg, etc.)
15190 // are using a creation path that explicitly specifies that they support this new major
15191 // version of the CLR.
15192 // 2) You should file an issue to track blocking earlier debuggers from targetting this
15193 // version of the CLR (i.e. update requiredVersion to the new CLR major
15194 // version). To enable a smooth internal transition, this often isn't done until absolutely
15195 // necessary (sometimes as late as Beta2).
15196 // 3) You can consider updating the CLR_ID guid used by the shim to recognize a CLR, but only
15197 // if it's important to completely hide newer CLRs from the shim. The expectation now
15198 // is that we won't need to do this (i.e. we'd like VS to give a nice error message about
15199 // needed a newer version of the debugger, rather than just acting as if a process has no CLR).
15200 // 4) Update this assert so that it no longer fires for your new CLR version or any of
15201 // the previous versions, but don't delete the assert...
15202 // the next CLR version after yours will probably need the same reminder
15203
15204 _ASSERTE_MSG(clrMajorVersion <= 4,
15205 "Found major CLR version greater than 4 in mscordbi.dll from CLRv4 - contact CLRDST");
15206
15207 // This knob lets us enable forward compatibility for internal scenarios, and also simulate new
15208 // versions of the runtime for testing the failure user-experience in a version of the debugger
15209 // before it is shipped.
15210 // We don't want to risk customers getting this, so for RTM builds this must be CHK-only.
15211 // To aid in internal transition, we may temporarily enable this in RET builds, but when
15212 // doing so must file a bug to track making it CHK only again before RTM.
15213 // For example, Dev10 Beta2 shipped with this knob, but it was made CHK-only at the start of RC.
15214 // In theory we might have a point release someday where we break debugger compat, but
15215 // it seems unlikely and since this knob is unsupported anyway we can always extend it
15216 // then (support reading a string value, etc.). So for now we just map the number
15217 // to the major CLR version number.
15218 DWORD requiredVersion = 0;
15219#ifdef _DEBUG
15220 requiredVersion = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_Debugging_RequiredVersion);
15221#endif
15222
15223 // If unset (the only supported configuration), then we require a debugger designed for CLRv4
15224 // for desktop, where we do not allow forward compat.
15225 // For SL, we allow forward compat. Right now, that means SLv2+ debugger requests can be
15226 // honored for SLv4.
15227 if (requiredVersion <= 0)
15228 {
15229 requiredVersion = 2;
15230 }
15231
15232 // Compare the version we were created for against the minimum required
15233 return (clrMajorVersion >= requiredVersion);
15234}
15235
15236bool CordbProcess::IsThreadSuspendedOrHijacked(ICorDebugThread * pICorDebugThread)
15237{
15238 // An RS lock can be held while this is called. Specifically,
15239 // CordbThread::EnumerateChains may be on the stack, and it uses
15240 // ATT_REQUIRE_STOPPED_MAY_FAIL, which holds the CordbProcess::m_StopGoLock lock for
15241 // its entire duration. As a result, this needs to be considered a reentrant API. See
15242 // comments above code:PrivateShimCallbackHolder for more info.
15243 PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(this);
15244
15245 CordbThread * pCordbThread = static_cast<CordbThread *> (pICorDebugThread);
15246 return GetDAC()->IsThreadSuspendedOrHijacked(pCordbThread->m_vmThreadToken);
15247}
15248