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: DacDbiImpl.cpp
6//
7
8//
9// Implement DAC/DBI interface
10//
11//*****************************************************************************
12
13
14#include "stdafx.h"
15
16#include "dacdbiinterface.h"
17
18#include "typestring.h"
19#include "holder.h"
20#include "debuginfostore.h"
21#include "peimagelayout.inl"
22#include "encee.h"
23#include "switches.h"
24#include "generics.h"
25#include "stackwalk.h"
26
27#include "dacdbiimpl.h"
28
29#ifdef FEATURE_COMINTEROP
30#include "runtimecallablewrapper.h"
31#include "comcallablewrapper.h"
32#endif // FEATURE_COMINTEROP
33
34#include "request_common.h"
35
36//-----------------------------------------------------------------------------
37// Have standard enter and leave macros at the DacDbi boundary to enforce
38// standard behavior.
39// 1. catch exceptions and convert them at the boundary.
40// 2. provide a space to hook logging and transitions.
41// 3. provide a hook to verify return values.
42//
43// Usage notes:
44// - use this at the DacDbi boundary; but not at internal functions
45// - it's ok to Return from the middle.
46//
47// Expected usage is:
48// Foo()
49// {
50// DD_ENTER_MAY_THROW
51// ...
52// if (...) { ThrowHr(E_SOME_FAILURE); }
53// ...
54// if (...) { return; } // early success case
55// ...
56// }
57//-----------------------------------------------------------------------------
58
59
60
61
62// Global allocator for DD. Access is protected under the g_dacCritSec lock.
63IDacDbiInterface::IAllocator * g_pAllocator = NULL;
64
65//---------------------------------------------------------------------------------------
66//
67// Extra sugar for wrapping IAllocator under friendly New/Delete operators.
68//
69// Sample usage:
70// void Foo(TestClass ** ppOut)
71// {
72// *ppOut = NULL;
73// TestClass * p = new (forDbi) TestClass();
74// ...
75// if (ok)
76// {
77// *ppOut = p;
78// return; // DBI will then free this memory.
79// }
80// ...
81// DeleteDbiMemory(p);
82// }
83//
84// Be very careful when using this on classes since Dbi and DAC may be in
85// separate dlls. This is best used when operating on blittable data-structures.
86// (no ctor/dtor, plain data fields) to guarantee the proper DLL isolation.
87// You don't want to call the ctor in DAC's context and the dtor in DBI's context
88// unless you really know what you're doing and that it's safe.
89//
90
91// Need a class to serve as a tag that we can use to overload New/Delete.
92forDbiWorker forDbi;
93
94void * operator new(size_t lenBytes, const forDbiWorker &)
95{
96 _ASSERTE(g_pAllocator != NULL);
97 void *result = g_pAllocator->Alloc(lenBytes);
98 if (result == NULL)
99 {
100 ThrowOutOfMemory();
101 }
102 return result;
103}
104
105void * operator new[](size_t lenBytes, const forDbiWorker &)
106{
107 _ASSERTE(g_pAllocator != NULL);
108 void *result = g_pAllocator->Alloc(lenBytes);
109 if (result == NULL)
110 {
111 ThrowOutOfMemory();
112 }
113 return result;
114}
115
116// Note: there is no C++ syntax for manually invoking this, but if a constructor throws an exception I understand that
117// this delete operator will be invoked automatically to destroy the object.
118void operator delete(void *p, const forDbiWorker &)
119{
120 if (p == NULL)
121 {
122 return;
123 }
124
125 _ASSERTE(g_pAllocator != NULL);
126 g_pAllocator->Free((BYTE*) p);
127
128}
129
130// Note: there is no C++ syntax for manually invoking this, but if a constructor throws an exception I understand that
131// this delete operator will be invoked automatically to destroy the object.
132void operator delete[](void *p, const forDbiWorker &)
133{
134 if (p == NULL)
135 {
136 return;
137 }
138
139 _ASSERTE(g_pAllocator != NULL);
140 g_pAllocator->Free((BYTE*) p);
141}
142
143// @dbgtodo dac support: determine how to handle an array of class instances to ensure the dtors get
144// called correctly or document that they won't
145// Delete memory and invoke dtor for memory allocated with 'operator (forDbi) new'
146template<class T> void DeleteDbiMemory(T *p)
147{
148 if (p == NULL)
149 {
150 return;
151 }
152 p->~T();
153
154 _ASSERTE(g_pAllocator != NULL);
155 g_pAllocator->Free((BYTE*) p);
156}
157
158
159//---------------------------------------------------------------------------------------
160// Creates the DacDbiInterface object, used by Dbi.
161//
162// Arguments:
163// pTarget - pointer to a Data-Target
164// baseAddress - non-zero base address of mscorwks in target to debug.
165// pAllocator - pointer to client allocator object. This lets DD allocate objects and
166// pass them out back to the client, which can then delete them.
167// DD takes a weak ref to this, so client must keep it alive until it
168// calls Destroy.
169// pMetadataLookup - callback interface to do internal metadata lookup. This is because
170// metadata is not dac-ized.
171// ppInterface - mandatory out-parameter
172//
173// Return Value:
174// S_OK on success.
175//
176//
177// Notes:
178// On Windows, this is public function that can be retrieved by GetProcAddress.
179
180// On Mac, this is used internally by DacDbiMarshalStubInstance below
181// This will yield an IDacDbiInterface to provide structured access to the
182// data-target.
183//
184// Must call Destroy to on interface to free its resources.
185//
186//---------------------------------------------------------------------------------------
187STDAPI
188DacDbiInterfaceInstance(
189 ICorDebugDataTarget * pTarget,
190 CORDB_ADDRESS baseAddress,
191 IDacDbiInterface::IAllocator * pAllocator,
192 IDacDbiInterface::IMetaDataLookup * pMetaDataLookup,
193 IDacDbiInterface ** ppInterface)
194{
195 // No marshalling is done by the instantiationf function - we just need to setup the infrastructure.
196 // We don't want to warn if this involves creating and accessing undacized data structures,
197 // because it's for the infrastructure, not DACized code itself.
198 SUPPORTS_DAC_HOST_ONLY;
199
200 // Since this is public, verify it.
201 if ((ppInterface == NULL) || (pTarget == NULL) || (baseAddress == 0))
202 {
203 return E_INVALIDARG;
204 }
205
206 *ppInterface = NULL;
207
208 //
209 // Actually allocate the real object and initialize it.
210 //
211 DacDbiInterfaceImpl * pDac = new (nothrow) DacDbiInterfaceImpl(pTarget, baseAddress, pAllocator, pMetaDataLookup);
212 if (!pDac)
213 {
214 return E_OUTOFMEMORY;
215 }
216
217 HRESULT hrStatus = pDac->Initialize();
218
219 if (SUCCEEDED(hrStatus))
220 {
221 *ppInterface = pDac;
222 }
223 else
224 {
225 delete pDac;
226 }
227 return hrStatus;
228}
229
230
231//---------------------------------------------------------------------------------------
232// Constructor. Instantiates a DAC/DBI interface around a DataTarget.
233//
234// Arguments:
235// pTarget - pointer to a Data-Target
236// baseAddress - non-zero base address of mscorwks in target to debug.
237// pAllocator - pointer to client allocator object. This lets DD allocate objects and
238// pass them out back to the client, which can then delete them.
239// DD takes a weak ref to this, so client must keep it alive until it
240// calls Destroy.
241// pMetadataLookup - callback interface to do internal metadata lookup. This is because
242// metadata is not dac-ized.
243//
244// Notes:
245// pAllocator is a weak reference.
246//---------------------------------------------------------------------------------------
247DacDbiInterfaceImpl::DacDbiInterfaceImpl(
248 ICorDebugDataTarget* pTarget,
249 CORDB_ADDRESS baseAddress,
250 IAllocator * pAllocator,
251 IMetaDataLookup * pMetaDataLookup
252) : ClrDataAccess(pTarget),
253 m_pAllocator(pAllocator),
254 m_pMetaDataLookup(pMetaDataLookup),
255 m_pCachedPEFile(VMPTR_PEFile::NullPtr()),
256 m_pCachedImporter(NULL),
257 m_isCachedHijackFunctionValid(FALSE)
258{
259 _ASSERTE(baseAddress != NULL);
260 m_globalBase = CORDB_ADDRESS_TO_TADDR(baseAddress);
261
262 _ASSERTE(pMetaDataLookup != NULL);
263 _ASSERTE(pAllocator != NULL);
264 _ASSERTE(pTarget != NULL);
265
266#ifdef _DEBUG
267 // Enable verification asserts in ICorDebug scenarios. ICorDebug never guesses at the DAC path, so any
268 // mismatch should be fatal, and so always of interest to the user.
269 // This overrides the assignment in the base class ctor (which runs first).
270 m_fEnableDllVerificationAsserts = true;
271#endif
272}
273
274//-----------------------------------------------------------------------------
275// Destructor.
276//
277// Notes:
278// This gets invoked after Destroy().
279//-----------------------------------------------------------------------------
280DacDbiInterfaceImpl::~DacDbiInterfaceImpl()
281{
282 SUPPORTS_DAC_HOST_ONLY;
283 // This will automatically chain to the base class dtor
284}
285
286//-----------------------------------------------------------------------------
287// Called from DAC-ized code to get a IMDInternalImport
288//
289// Arguments:
290// pPEFile - PE file for which to get importer for
291// fThrowEx - if true, throw instead of returning NULL.
292//
293// Returns:
294// an Internal importer object for this file.
295// May return NULL or throw (depending on fThrowEx).
296// May throw in exceptional circumstances (eg, corrupt debuggee).
297//
298// Assumptions:
299// This is called from DAC-ized code within the VM, which
300// was in turn called from some DD primitive. The returned importer will
301// be used by the DAC-ized code in the callstack, but it won't be cached.
302//
303// Notes:
304// This is an Internal importer, not a public Metadata importer.
305//
306interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
307 const PEFile* pPEFile,
308 const ReflectionModule * pReflectionModule,
309 bool fThrowEx)
310{
311 // Since this is called from an existing DAC-primitive, we already hold the g_dacCritSec lock.
312 // The lock conveniently protects our cache.
313 SUPPORTS_DAC;
314
315 IDacDbiInterface::IMetaDataLookup * pLookup = m_pMetaDataLookup;
316 _ASSERTE(pLookup != NULL);
317
318 VMPTR_PEFile vmPEFile = VMPTR_PEFile::NullPtr();
319
320 if (pPEFile != NULL)
321 {
322 vmPEFile.SetHostPtr(pPEFile);
323 }
324 else if (pReflectionModule != NULL)
325 {
326 // SOS and ClrDataAccess rely on special logic to find the metadata for methods in dynamic modules.
327 // We don't need to. The RS has already taken care of the special logic for us.
328 // So here we just grab the PEFile off of the ReflectionModule and continue down the normal
329 // code path. See code:ClrDataAccess::GetMDImport for comparison.
330 vmPEFile.SetHostPtr(pReflectionModule->GetFile());
331 }
332
333 // Optimize for the case where the VM queries the same Importer many times in a row.
334 if (m_pCachedPEFile == vmPEFile)
335 {
336 return m_pCachedImporter;
337 }
338
339 // Go to DBI to find the metadata.
340 IMDInternalImport * pInternal = NULL;
341 bool isILMetaDataForNI = false;
342 EX_TRY
343 {
344 // If test needs it in the future, prop isILMetaDataForNI back up to
345 // ClrDataAccess.m_mdImports.Add() call.
346 // example in code:ClrDataAccess::GetMDImport
347 // CordbModule::GetMetaDataInterface also looks up MetaData and would need attention.
348
349 // This is the new codepath that uses ICorDebugMetaDataLookup.
350 // To get the old codepath that uses the v2 metadata lookup methods,
351 // you'd have to load DAC only and then you'll get ClrDataAccess's implementation
352 // of this function.
353 pInternal = pLookup->LookupMetaData(vmPEFile, isILMetaDataForNI);
354 }
355 EX_CATCH
356 {
357 // Any expected error we should ignore.
358 if ((GET_EXCEPTION()->GetHR() != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) &&
359 (GET_EXCEPTION()->GetHR() != CORDBG_E_READVIRTUAL_FAILURE) &&
360 (GET_EXCEPTION()->GetHR() != CORDBG_E_SYMBOLS_NOT_AVAILABLE) &&
361 (GET_EXCEPTION()->GetHR() != CORDBG_E_MODULE_LOADED_FROM_DISK))
362 {
363 EX_RETHROW;
364 }
365 }
366 EX_END_CATCH(SwallowAllExceptions)
367
368 if (pInternal == NULL)
369 {
370 SIMPLIFYING_ASSUMPTION(!"MD lookup failed");
371 if (fThrowEx)
372 {
373 ThrowHR(E_FAIL);
374 }
375 return NULL;
376 }
377 else
378 {
379 // Cache it such that it we look for the exact same Importer again, we'll return it.
380 m_pCachedPEFile = vmPEFile;
381 m_pCachedImporter = pInternal;
382 }
383
384 return pInternal;
385}
386
387//-----------------------------------------------------------------------------
388// Implementation of IDacDbiInterface
389// See DacDbiInterface.h for full descriptions of all of these functions
390//-----------------------------------------------------------------------------
391
392// Destroy the connection, freeing up any resources.
393void DacDbiInterfaceImpl::Destroy()
394{
395 m_pAllocator = NULL;
396
397 this->Release();
398 // Memory is deleted, don't access this object any more
399}
400
401// Check whether the version of the DBI matches the version of the runtime.
402// See code:CordbProcess::CordbProcess#DBIVersionChecking for more information regarding version checking.
403HRESULT DacDbiInterfaceImpl::CheckDbiVersion(const DbiVersion * pVersion)
404{
405 DD_ENTER_MAY_THROW;
406
407 if (pVersion->m_dwFormat != kCurrentDbiVersionFormat)
408 {
409 return CORDBG_E_INCOMPATIBLE_PROTOCOL;
410 }
411
412 if ((pVersion->m_dwProtocolBreakingChangeCounter != kCurrentDacDbiProtocolBreakingChangeCounter) ||
413 (pVersion->m_dwReservedMustBeZero1 != 0))
414 {
415 return CORDBG_E_INCOMPATIBLE_PROTOCOL;
416 }
417
418 return S_OK;
419}
420
421// Flush the DAC cache. This should be called when target memory changes.
422HRESULT DacDbiInterfaceImpl::FlushCache()
423{
424 // Non-reentrant. We don't want to flush cached instances from a callback.
425 // That would remove host DAC instances while they're being used.
426 DD_NON_REENTRANT_MAY_THROW;
427
428 m_pCachedPEFile = VMPTR_PEFile::NullPtr();
429 m_pCachedImporter = NULL;
430 m_isCachedHijackFunctionValid = FALSE;
431
432 HRESULT hr = ClrDataAccess::Flush();
433
434 // Current impl of Flush() should always succeed. If it ever fails, we want to know.
435 _ASSERTE(SUCCEEDED(hr));
436 return hr;
437}
438
439// enable or disable DAC target consistency checks
440void DacDbiInterfaceImpl::DacSetTargetConsistencyChecks(bool fEnableAsserts)
441{
442 // forward on to our ClrDataAccess base class
443 ClrDataAccess::SetTargetConsistencyChecks(fEnableAsserts);
444}
445
446// Query if Left-side is started up?
447BOOL DacDbiInterfaceImpl::IsLeftSideInitialized()
448{
449 DD_ENTER_MAY_THROW;
450
451 if (g_pDebugger != NULL)
452 {
453 // This check is "safe".
454 // The initialize order in the left-side is:
455 // 1) g_pDebugger is an RVA based global initialized to NULL when the module is loaded.
456 // 2) Allocate a "Debugger" object.
457 // 3) run the ctor, which will set m_fLeftSideInitialized = FALSE.
458 // 4) assign the object to g_pDebugger.
459 // 5) later, LS initialization code will assign g_pDebugger->m_fLeftSideInitialized = TRUE.
460 //
461 // The memory write in #5 is atomic. There is no window where we're reading unitialized data.
462
463 return (g_pDebugger->m_fLeftSideInitialized != 0);
464 }
465
466 return FALSE;
467}
468
469
470// Determines if a given adddress is a CLR stub.
471BOOL DacDbiInterfaceImpl::IsTransitionStub(CORDB_ADDRESS address)
472{
473 DD_ENTER_MAY_THROW;
474
475 BOOL fIsStub = FALSE;
476
477#if defined(FEATURE_PAL)
478 // Currently IsIPInModule() is not implemented in the PAL. Rather than skipping the check, we should
479 // either E_NOTIMPL this API or implement IsIPInModule() in the PAL. Since ICDProcess::IsTransitionStub()
480 // is only called by VS in mixed-mode debugging scenarios, and mixed-mode debugging is not supported on
481 // POSIX systems, there is really no incentive to implement this API at this point.
482 ThrowHR(E_NOTIMPL);
483
484#else // !FEATURE_PAL
485
486 TADDR ip = (TADDR)address;
487
488 if (ip == NULL)
489 {
490 fIsStub = FALSE;
491 }
492 else
493 {
494 fIsStub = StubManager::IsStub(ip);
495 }
496
497 // If it's in Mscorwks, count that as a stub too.
498 if (fIsStub == FALSE)
499 {
500 fIsStub = IsIPInModule(m_globalBase, ip);
501 }
502
503#endif // FEATURE_PAL
504
505 return fIsStub;
506}
507
508// Gets the type of 'address'.
509IDacDbiInterface::AddressType DacDbiInterfaceImpl::GetAddressType(CORDB_ADDRESS address)
510{
511 DD_ENTER_MAY_THROW;
512 TADDR taAddr = CORDB_ADDRESS_TO_TADDR(address);
513
514 if (IsPossibleCodeAddress(taAddr) == S_OK)
515 {
516 if (ExecutionManager::IsManagedCode(taAddr))
517 {
518 return kAddressManagedMethod;
519 }
520
521 if (StubManager::IsStub(taAddr))
522 {
523 return kAddressRuntimeUnmanagedStub;
524 }
525 }
526
527 return kAddressUnrecognized;
528}
529
530
531// Get a VM appdomain pointer that matches the appdomain ID
532VMPTR_AppDomain DacDbiInterfaceImpl::GetAppDomainFromId(ULONG appdomainId)
533{
534 DD_ENTER_MAY_THROW;
535
536 VMPTR_AppDomain vmAppDomain;
537
538 // @dbgtodo dac support - We would like to wean ourselves off the IXClrData interfaces.
539 IXCLRDataProcess * pDAC = this;
540 ReleaseHolder<IXCLRDataAppDomain> pDacAppDomain;
541
542 HRESULT hrStatus = pDAC->GetAppDomainByUniqueID(appdomainId, &pDacAppDomain);
543 IfFailThrow(hrStatus);
544
545 IXCLRDataAppDomain * pIAppDomain = pDacAppDomain;
546 AppDomain * pAppDomain = (static_cast<ClrDataAppDomain *> (pIAppDomain))->GetAppDomain();
547 SIMPLIFYING_ASSUMPTION(pAppDomain != NULL);
548 if (pAppDomain == NULL)
549 {
550 ThrowHR(E_FAIL); // corrupted left-side?
551 }
552
553 TADDR addrAppDomain = PTR_HOST_TO_TADDR(pAppDomain);
554 vmAppDomain.SetDacTargetPtr(addrAppDomain);
555
556 return vmAppDomain;
557}
558
559
560// Get the AppDomain ID for an AppDomain.
561ULONG DacDbiInterfaceImpl::GetAppDomainId(VMPTR_AppDomain vmAppDomain)
562{
563 DD_ENTER_MAY_THROW;
564
565 if (vmAppDomain.IsNull())
566 {
567 return 0;
568 }
569 else
570 {
571 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
572 return pAppDomain->GetId().m_dwId;
573 }
574}
575
576// Get the managed AppDomain object for an AppDomain.
577VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetAppDomainObject(VMPTR_AppDomain vmAppDomain)
578{
579 DD_ENTER_MAY_THROW;
580
581 AppDomain* pAppDomain = vmAppDomain.GetDacPtr();
582 OBJECTHANDLE hAppDomainManagedObject = pAppDomain->GetRawExposedObjectHandleForDebugger();
583 VMPTR_OBJECTHANDLE vmObj = VMPTR_OBJECTHANDLE::NullPtr();
584 vmObj.SetDacTargetPtr(hAppDomainManagedObject);
585 return vmObj;
586
587}
588
589// Determine if the specified AppDomain is the default domain
590BOOL DacDbiInterfaceImpl::IsDefaultDomain(VMPTR_AppDomain vmAppDomain)
591{
592 DD_ENTER_MAY_THROW;
593
594 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
595 BOOL fDefaultDomain = pAppDomain->IsDefaultDomain();
596
597 return fDefaultDomain;
598}
599
600
601// Get the full AD friendly name for the given EE AppDomain.
602void DacDbiInterfaceImpl::GetAppDomainFullName(
603 VMPTR_AppDomain vmAppDomain,
604 IStringHolder * pStrName )
605{
606 DD_ENTER_MAY_THROW;
607 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
608
609 // Get the AppDomain name from the VM without changing anything
610 // We might be able to simplify this, eg. by returning an SString.
611 bool fIsUtf8;
612 PVOID pRawName = pAppDomain->GetFriendlyNameNoSet(&fIsUtf8);
613
614 if (!pRawName)
615 {
616 ThrowHR(E_NOINTERFACE);
617 }
618
619 HRESULT hrStatus = S_OK;
620 if (fIsUtf8)
621 {
622 // we have to allocate a temporary string
623 // we could avoid this by adding a version of IStringHolder::AssignCopy that takes a UTF8 string
624 // We should also probably check to see when fIsUtf8 is ever true (it looks like it should normally be false).
625 ULONG32 dwNameLen = 0;
626 hrStatus = ConvertUtf8((LPCUTF8)pRawName, 0, &dwNameLen, NULL);
627 if (SUCCEEDED( hrStatus ))
628 {
629 NewArrayHolder<WCHAR> pwszName(new WCHAR[dwNameLen]);
630 hrStatus = ConvertUtf8((LPCUTF8)pRawName, dwNameLen, &dwNameLen, pwszName );
631 IfFailThrow(hrStatus);
632
633 hrStatus = pStrName->AssignCopy(pwszName);
634 }
635 }
636 else
637 {
638 hrStatus = pStrName->AssignCopy(static_cast<PCWSTR>(pRawName));
639 }
640
641 // Very important that this either sets pStrName or Throws.
642 // Don't set it and then then throw.
643 IfFailThrow(hrStatus);
644}
645
646//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
647// JIT Compiler Flags
648//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
649
650// Get the values of the JIT Optimization and EnC flags.
651void DacDbiInterfaceImpl::GetCompilerFlags (
652 VMPTR_DomainFile vmDomainFile,
653 BOOL *pfAllowJITOpts,
654 BOOL *pfEnableEnC)
655{
656 DD_ENTER_MAY_THROW;
657
658 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
659
660 if (pDomainFile == NULL)
661 {
662 ThrowHR(E_FAIL);
663 }
664
665 // Get the underlying module - none of this is AppDomain specific
666 Module * pModule = pDomainFile->GetModule();
667 DWORD dwBits = pModule->GetDebuggerInfoBits();
668 *pfAllowJITOpts = !CORDisableJITOptimizations(dwBits);
669 *pfEnableEnC = pModule->IsEditAndContinueEnabled();
670
671
672} //GetCompilerFlags
673
674//-----------------------------------------------------------------------------
675// Helper function for SetCompilerFlags to set EnC status.
676// Arguments:
677// Input:
678// pModule - The runtime module for which flags are being set.
679//
680// Return value:
681// true if the Enc bits can be set on this module
682//-----------------------------------------------------------------------------
683
684bool DacDbiInterfaceImpl::CanSetEnCBits(Module * pModule)
685{
686 _ASSERTE(pModule != NULL);
687#ifdef EnC_SUPPORTED
688 // If we're using explicit sequence points (from the PDB), then we can't do EnC
689 // because EnC won't get updated pdbs and so the sequence points will be wrong.
690 bool fIgnorePdbs = ((pModule->GetDebuggerInfoBits() & DACF_IGNORE_PDBS) != 0);
691
692 bool fAllowEnc = pModule->IsEditAndContinueCapable() &&
693
694#ifdef PROFILING_SUPPORTED_DATA
695 !CORProfilerPresent() && // this queries target
696#endif
697 fIgnorePdbs;
698#else // ! EnC_SUPPORTED
699 // Enc not supported on any other platforms.
700 bool fAllowEnc = false;
701#endif
702
703 return fAllowEnc;
704} // DacDbiInterfaceImpl::SetEnCBits
705
706// Set the values of the JIT optimization and EnC flags.
707HRESULT DacDbiInterfaceImpl::SetCompilerFlags(VMPTR_DomainFile vmDomainFile,
708 BOOL fAllowJitOpts,
709 BOOL fEnableEnC)
710{
711 DD_ENTER_MAY_THROW;
712
713 DWORD dwBits = 0;
714 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
715 Module * pModule = pDomainFile->GetCurrentModule();
716 HRESULT hr = S_OK;
717
718
719#ifdef FEATURE_PREJIT
720 if (pModule->HasNativeImage())
721 {
722 ThrowHR(CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE);
723 }
724#endif
725 _ASSERTE(pModule != NULL);
726
727 // Initialize dwBits.
728 dwBits = (pModule->GetDebuggerInfoBits() & ~(DACF_ALLOW_JIT_OPTS | DACF_ENC_ENABLED));
729 dwBits &= DACF_CONTROL_FLAGS_MASK;
730
731 if (fAllowJitOpts)
732 {
733 dwBits |= DACF_ALLOW_JIT_OPTS;
734 }
735 if (fEnableEnC)
736 {
737 if (CanSetEnCBits(pModule))
738 {
739 dwBits |= DACF_ENC_ENABLED;
740 }
741 else
742 {
743 hr = CORDBG_S_NOT_ALL_BITS_SET;
744 }
745 }
746 // Settings from the debugger take precedence over all other settings.
747 dwBits |= DACF_USER_OVERRIDE;
748
749 // set flags. This will write back to the target
750 pModule->SetDebuggerInfoBits((DebuggerAssemblyControlFlags)dwBits);
751
752
753 LOG((LF_CORDB, LL_INFO100, "D::HIPCE, Changed Jit-Debug-Info: fOpt=%d, fEnableEnC=%d, new bits=0x%08x\n",
754 (dwBits & DACF_ALLOW_JIT_OPTS) != 0,
755 (dwBits & DACF_ENC_ENABLED) != 0,
756 dwBits));
757
758 _ASSERTE(SUCCEEDED(hr));
759 return hr;
760
761} // DacDbiInterfaceImpl::SetCompilerFlags
762
763
764//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
765// sequence points and var info
766//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
767
768// Initialize the native/IL sequence points and native var info for a function.
769void DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc,
770 CORDB_ADDRESS startAddr,
771 BOOL fCodeAvailable,
772 NativeVarData * pNativeVarData,
773 SequencePoints * pSequencePoints)
774{
775 DD_ENTER_MAY_THROW;
776
777 _ASSERTE(!vmMethodDesc.IsNull());
778
779 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
780
781 _ASSERTE(fCodeAvailable != 0);
782
783 // get information about the locations of arguments and local variables
784 GetNativeVarData(pMD, startAddr, GetArgCount(pMD), pNativeVarData);
785
786 // get the sequence points
787 GetSequencePoints(pMD, startAddr, pSequencePoints);
788
789} // GetNativeCodeSequencePointsAndVarInfo
790
791//-----------------------------------------------------------------------------
792// Get the number of fixed arguments to a function, i.e., the explicit args and the "this" pointer.
793// This does not include other implicit arguments or varargs. This is used to compute a variable ID
794// (see comment in CordbJITILFrame::ILVariableToNative for more detail)
795// Arguments:
796// input: pMD pointer to the method desc for the function
797// output: none
798// Return value:
799// the number of fixed arguments to the function
800//-----------------------------------------------------------------------------
801SIZE_T DacDbiInterfaceImpl::GetArgCount(MethodDesc * pMD)
802{
803
804 // Create a MetaSig for the given method's sig. (Easier than
805 // picking the sig apart ourselves.)
806 PCCOR_SIGNATURE pCallSig;
807 DWORD cbCallSigSize;
808
809 pMD->GetSig(&pCallSig, &cbCallSigSize);
810
811 if (pCallSig == NULL)
812 {
813 // Sig should only be null if the image is corrupted. (Even for lightweight-codegen)
814 // We expect the jit+verifier to catch this, so that we never land here.
815 // But just in case ...
816 CONSISTENCY_CHECK_MSGF(false, ("Corrupted image, null sig.(%s::%s)",
817 pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
818 return 0;
819 }
820
821 MetaSig msig(pCallSig, cbCallSigSize, pMD->GetModule(), NULL, MetaSig::sigMember);
822
823 // Get the arg count.
824 UINT32 NumArguments = msig.NumFixedArgs();
825
826 // Account for the 'this' argument.
827 if (!pMD->IsStatic())
828 {
829 NumArguments++;
830 }
831/*
832 SigParser sigParser(pCallSig, cbCallSigSize);
833 sigParser.SkipMethodHeaderSignature(&m_allArgsCount);
834*/
835 return NumArguments;
836} //GetArgCount
837
838// Allocator to pass to DebugInfoStores, allocating forDBI
839BYTE* InfoStoreForDbiNew(void * pData, size_t cBytes)
840{
841 return new(forDbi) BYTE[cBytes];
842}
843
844// Allocator to pass to the debug-info-stores...
845BYTE* InfoStoreNew(void * pData, size_t cBytes)
846{
847 return new BYTE[cBytes];
848}
849
850//-----------------------------------------------------------------------------
851// Get locations and code offsets for local variables and arguments in a function
852// This information is used to find the location of a value at a given IP.
853// Arguments:
854// input:
855// pMethodDesc pointer to the method desc for the function
856// startAddr starting address of the function--used to differentiate
857// EnC versions
858// fixedArgCount number of fixed arguments to the function
859// output:
860// pVarInfo data structure containing a list of variable and
861// argument locations by range of IP offsets
862// Note: this function may throw
863//-----------------------------------------------------------------------------
864void DacDbiInterfaceImpl::GetNativeVarData(MethodDesc * pMethodDesc,
865 CORDB_ADDRESS startAddr,
866 SIZE_T fixedArgCount,
867 NativeVarData * pVarInfo)
868{
869 // make sure we haven't done this already
870 if (pVarInfo->IsInitialized())
871 {
872 return;
873 }
874
875 NewHolder<ICorDebugInfo::NativeVarInfo> nativeVars(NULL);
876
877 DebugInfoRequest request;
878 request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));
879
880 ULONG32 entryCount;
881
882 BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
883 InfoStoreNew, NULL, // allocator
884 NULL, NULL,
885 &entryCount, &nativeVars);
886
887 if (!success)
888 ThrowHR(E_FAIL);
889
890 // set key fields of pVarInfo
891 pVarInfo->InitVarDataList(nativeVars, (int)fixedArgCount, (int)entryCount);
892} // GetNativeVarData
893
894
895//-----------------------------------------------------------------------------
896// Given a instrumented IL map from the profiler that maps:
897// Original offset IL_A -> Instrumentend offset IL_B
898// And a native mapping from the JIT that maps:
899// Instrumented offset IL_B -> native offset Native_C
900// This function merges the two maps and stores the result back into the nativeMap.
901// The nativeMap now maps:
902// Original offset IL_A -> native offset Native_C
903// pEntryCount is the number of valid entries in nativeMap, and it may be adjusted downwards
904// as part of the composition.
905//-----------------------------------------------------------------------------
906void DacDbiInterfaceImpl::ComposeMapping(const InstrumentedILOffsetMapping * pProfilerILMap, ICorDebugInfo::OffsetMapping nativeMap[], ULONG32* pEntryCount)
907{
908 // Translate the IL offset if the profiler has provided us with a mapping.
909 // The ICD public API should always expose the original IL offsets, but GetBoundaries()
910 // directly accesses the debug info, which stores the instrumented IL offsets.
911
912 ULONG32 entryCount = *pEntryCount;
913 // The map pointer could be NULL or there could be no entries in the map, in either case no work to do
914 if (pProfilerILMap && !pProfilerILMap->IsNull())
915 {
916 // If we did instrument, then we can't have any sequence points that
917 // are "in-between" the old-->new map that the profiler gave us.
918 // Ex, if map is:
919 // (6 old -> 36 new)
920 // (8 old -> 50 new)
921 // And the jit gives us an entry for 44 new, that will map back to 6 old.
922 // Since the map can only have one entry for 6 old, we remove 44 new.
923
924 // First Pass: invalidate all the duplicate entries by setting their IL offset to MAX_ILNUM
925 ULONG32 cDuplicate = 0;
926 ULONG32 prevILOffset = (ULONG32)(ICorDebugInfo::MAX_ILNUM);
927 for (ULONG32 i = 0; i < entryCount; i++)
928 {
929 ULONG32 origILOffset = TranslateInstrumentedILOffsetToOriginal(nativeMap[i].ilOffset, pProfilerILMap);
930
931 if (origILOffset == prevILOffset)
932 {
933 // mark this sequence point as invalid; refer to the comment above
934 nativeMap[i].ilOffset = (ULONG32)(ICorDebugInfo::MAX_ILNUM);
935 cDuplicate += 1;
936 }
937 else
938 {
939 // overwrite the instrumented IL offset with the original IL offset
940 nativeMap[i].ilOffset = origILOffset;
941 prevILOffset = origILOffset;
942 }
943 }
944
945 // Second Pass: move all the valid entries up front
946 ULONG32 realIndex = 0;
947 for (ULONG32 curIndex = 0; curIndex < entryCount; curIndex++)
948 {
949 if (nativeMap[curIndex].ilOffset != (ULONG32)(ICorDebugInfo::MAX_ILNUM))
950 {
951 // This is a valid entry. Move it up front.
952 nativeMap[realIndex] = nativeMap[curIndex];
953 realIndex += 1;
954 }
955 }
956
957 // make sure we have done the bookkeeping correctly
958 _ASSERTE((realIndex + cDuplicate) == entryCount);
959
960 // Final Pass: derecement entryCount
961 entryCount -= cDuplicate;
962 *pEntryCount = entryCount;
963 }
964}
965
966
967//-----------------------------------------------------------------------------
968// Get the native/IL sequence points for a function
969// Arguments:
970// input:
971// pMethodDesc pointer to the method desc for the function
972// startAddr starting address of the function--used to differentiate
973// output:
974// pNativeMap data structure containing a list of sequence points
975// Note: this function may throw
976//-----------------------------------------------------------------------------
977void DacDbiInterfaceImpl::GetSequencePoints(MethodDesc * pMethodDesc,
978 CORDB_ADDRESS startAddr,
979 SequencePoints * pSeqPoints)
980{
981
982 // make sure we haven't done this already
983 if (pSeqPoints->IsInitialized())
984 {
985 return;
986 }
987
988 // Use the DebugInfoStore to get IL->Native maps.
989 // It doesn't matter whether we're jitted, ngenned etc.
990 DebugInfoRequest request;
991 request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));
992
993
994 // Bounds info.
995 NewArrayHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
996
997 ULONG32 entryCount;
998 BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
999 InfoStoreNew, NULL, // allocator
1000 &entryCount, &mapCopy,
1001 NULL, NULL);
1002 if (!success)
1003 ThrowHR(E_FAIL);
1004
1005 // if there is a rejit IL map for this function, apply that in preference to load-time mapping
1006#ifdef FEATURE_REJIT
1007 CodeVersionManager * pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
1008 NativeCodeVersion nativeCodeVersion = pCodeVersionManager->GetNativeCodeVersion(dac_cast<PTR_MethodDesc>(pMethodDesc), (PCODE)startAddr);
1009 if (!nativeCodeVersion.IsNull())
1010 {
1011 const InstrumentedILOffsetMapping * pRejitMapping = nativeCodeVersion.GetILCodeVersion().GetInstrumentedILMap();
1012 ComposeMapping(pRejitMapping, mapCopy, &entryCount);
1013 }
1014 else
1015 {
1016#endif
1017 // if there is a profiler load-time mapping and not a rejit mapping, apply that instead
1018 InstrumentedILOffsetMapping loadTimeMapping =
1019 pMethodDesc->GetModule()->GetInstrumentedILOffsetMapping(pMethodDesc->GetMemberDef());
1020 ComposeMapping(&loadTimeMapping, mapCopy, &entryCount);
1021#ifdef FEATURE_REJIT
1022 }
1023#endif
1024
1025 pSeqPoints->InitSequencePoints(entryCount);
1026
1027 // mapCopy and pSeqPoints have elements of different types. Thus, we
1028 // need to copy the individual members from the elements of mapCopy to the
1029 // elements of pSeqPoints. Once we're done, we can release mapCopy
1030 pSeqPoints->CopyAndSortSequencePoints(mapCopy);
1031
1032} // GetSequencePoints
1033
1034// ----------------------------------------------------------------------------
1035// DacDbiInterfaceImpl::TranslateInstrumentedILOffsetToOriginal
1036//
1037// Description:
1038// Helper function to convert an instrumented IL offset to the corresponding original IL offset.
1039//
1040// Arguments:
1041// * ilOffset - offset to be translated
1042// * pMapping - the profiler-provided mapping between original IL offsets and instrumented IL offsets
1043//
1044// Return Value:
1045// Return the translated offset.
1046//
1047
1048ULONG DacDbiInterfaceImpl::TranslateInstrumentedILOffsetToOriginal(ULONG ilOffset,
1049 const InstrumentedILOffsetMapping * pMapping)
1050{
1051 SIZE_T cMap = pMapping->GetCount();
1052 ARRAY_PTR_COR_IL_MAP rgMap = pMapping->GetOffsets();
1053
1054 _ASSERTE((cMap == 0) == (rgMap == NULL));
1055
1056 // Early out if there is no mapping, or if we are dealing with a special IL offset such as
1057 // prolog, epilog, etc.
1058 if ((cMap == 0) || ((int)ilOffset < 0))
1059 {
1060 return ilOffset;
1061 }
1062
1063 SIZE_T i = 0;
1064 for (i = 1; i < cMap; i++)
1065 {
1066 if (ilOffset < rgMap[i].newOffset)
1067 {
1068 return rgMap[i - 1].oldOffset;
1069 }
1070 }
1071 return rgMap[i - 1].oldOffset;
1072}
1073
1074//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1075// Function Data
1076//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1077
1078
1079// GetILCodeAndSig returns the function's ILCode and SigToken given
1080// a module and a token. The info will come from a MethodDesc, if
1081// one exists or from metadata.
1082//
1083void DacDbiInterfaceImpl::GetILCodeAndSig(VMPTR_DomainFile vmDomainFile,
1084 mdToken functionToken,
1085 TargetBuffer * pCodeInfo,
1086 mdToken * pLocalSigToken)
1087{
1088 DD_ENTER_MAY_THROW;
1089
1090 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1091 Module * pModule = pDomainFile->GetCurrentModule();
1092 RVA methodRVA = 0;
1093 DWORD implFlags;
1094
1095 // preinitialize out params
1096 pCodeInfo->Clear();
1097 *pLocalSigToken = mdSignatureNil;
1098
1099 // Get the RVA and impl flags for this method.
1100 IfFailThrow(pModule->GetMDImport()->GetMethodImplProps(functionToken,
1101 &methodRVA,
1102 &implFlags));
1103
1104 MethodDesc* pMethodDesc =
1105 FindLoadedMethodRefOrDef(pModule, functionToken);
1106
1107 // If the RVA is 0 or it's native, then the method is not IL
1108 if (methodRVA == 0)
1109 {
1110 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Function is not IL - methodRVA == NULL!\n"));
1111 // return (CORDBG_E_FUNCTION_NOT_IL);
1112 // Sanity check this....
1113
1114 if(!pMethodDesc || !pMethodDesc->IsIL())
1115 {
1116 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: And the MD agrees..\n"));
1117 ThrowHR(CORDBG_E_FUNCTION_NOT_IL);
1118 }
1119 else
1120 {
1121 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: But the MD says it's IL..\n"));
1122 }
1123
1124 if (pMethodDesc != NULL && pMethodDesc->GetRVA() == 0)
1125 {
1126 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Actually, MD says RVA is 0 too - keep going...!\n"));
1127 }
1128 }
1129 if (IsMiNative(implFlags))
1130 {
1131 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Function is not IL - IsMiNative!\n"));
1132 ThrowHR(CORDBG_E_FUNCTION_NOT_IL);
1133 }
1134
1135 *pLocalSigToken = GetILCodeAndSigHelper(pModule, pMethodDesc, functionToken, methodRVA, pCodeInfo);
1136
1137#ifdef LOGGING
1138 else
1139 {
1140 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: GetMethodImplProps failed!\n"));
1141 }
1142#endif
1143} // GetILCodeAndSig
1144
1145//---------------------------------------------------------------------------------------
1146//
1147// This is just a worker function for GetILCodeAndSig. It returns the function's ILCode and SigToken
1148// given a module, a token, and the RVA. If a MethodDesc is provided, it has to be consistent with
1149// the token and the RVA.
1150//
1151// Arguments:
1152// pModule - the Module containing the specified method
1153// pMD - the specified method; can be NULL
1154// mdMethodToken - the MethodDef token of the specified method
1155// methodRVA - the RVA of the IL for the specified method
1156// pIL - out parameter; return the target address and size of the IL of the specified method
1157//
1158// Return Value:
1159// Return the local variable signature token of the specified method. Can be mdSignatureNil.
1160//
1161
1162mdSignature DacDbiInterfaceImpl::GetILCodeAndSigHelper(Module * pModule,
1163 MethodDesc * pMD,
1164 mdMethodDef mdMethodToken,
1165 RVA methodRVA,
1166 TargetBuffer * pIL)
1167{
1168 _ASSERTE(pModule != NULL);
1169
1170 // If a MethodDesc is provided, it has to be consistent with the MethodDef token and the RVA.
1171 _ASSERTE((pMD == NULL) || ((pMD->GetMemberDef() == mdMethodToken) && (pMD->GetRVA() == methodRVA)));
1172
1173 TADDR pTargetIL; // target address of start of IL blob
1174
1175 // This works for methods in dynamic modules, and methods overriden by a profiler.
1176 pTargetIL = pModule->GetDynamicIL(mdMethodToken, TRUE);
1177
1178 // Method not overriden - get the original copy of the IL by going to the PE file/RVA
1179 // If this is in a dynamic module then don't even attempt this since ReflectionModule::GetIL isn't
1180 // implemend for DAC.
1181 if (pTargetIL == 0 && !pModule->IsReflection())
1182 {
1183 pTargetIL = (TADDR)pModule->GetIL(methodRVA);
1184 }
1185
1186 mdSignature mdSig = mdSignatureNil;
1187 if (pTargetIL == 0)
1188 {
1189 // Currently this should only happen for LCG methods (including IL stubs).
1190 // LCG methods have a 0 RVA, and so we don't currently have any way to get the IL here.
1191 _ASSERTE(pMD->IsDynamicMethod());
1192 _ASSERTE(pMD->AsDynamicMethodDesc()->IsLCGMethod()||
1193 pMD->AsDynamicMethodDesc()->IsILStub());
1194
1195 // Clear the buffer.
1196 pIL->Clear();
1197 }
1198 else
1199 {
1200 // Now we have the target address of the IL blob, we need to bring it over to the host.
1201 // DacGetILMethod will copy the COR_ILMETHOD information that we need
1202 COR_ILMETHOD * pHostIL = DacGetIlMethod(pTargetIL); // host address of start of IL blob
1203 COR_ILMETHOD_DECODER header(pHostIL); // host address of header
1204
1205
1206 // Get the IL code info. We need the address of the IL itself, which will be beyond the header
1207 // at the beginning of the blob. We ultimately need the target address. To get this, we take
1208 // target address of the target IL blob and add the offset from the beginning of the host IL blob
1209 // (the header) to the beginning of the IL itself (we get this information from the header).
1210 pIL->pAddress = pTargetIL + ((SIZE_T)(header.Code) - (SIZE_T)pHostIL);
1211 pIL->cbSize = header.GetCodeSize();
1212
1213 // Now we get the signature token
1214 if (header.LocalVarSigTok != NULL)
1215 {
1216 mdSig = header.GetLocalVarSigTok();
1217 }
1218 else
1219 {
1220 mdSig = mdSignatureNil;
1221 }
1222 }
1223
1224 return mdSig;
1225}
1226
1227
1228bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
1229 DWORD &dwTimeStamp,
1230 DWORD &dwSize,
1231 bool &isNGEN,
1232 IStringHolder* pStrFilename)
1233{
1234#if !defined(FEATURE_PREJIT)
1235
1236 return false;
1237
1238#else // defined(FEATURE_PREJIT)
1239
1240 DD_ENTER_MAY_THROW;
1241
1242 DWORD dwDataSize;
1243 DWORD dwRvaHint;
1244 PEFile * pPEFile = vmPEFile.GetDacPtr();
1245 _ASSERTE(pPEFile != NULL);
1246 if (pPEFile == NULL)
1247 return false;
1248
1249 WCHAR wszFilePath[MAX_LONGPATH] = {0};
1250 DWORD cchFilePath = MAX_LONGPATH;
1251 bool ret = ClrDataAccess::GetMetaDataFileInfoFromPEFile(pPEFile,
1252 dwTimeStamp,
1253 dwSize,
1254 dwDataSize,
1255 dwRvaHint,
1256 isNGEN,
1257 wszFilePath,
1258 cchFilePath);
1259
1260 pStrFilename->AssignCopy(wszFilePath);
1261 return ret;
1262#endif // !defined(FEATURE_PREJIT)
1263}
1264
1265
1266bool DacDbiInterfaceImpl::GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
1267 DWORD &dwTimeStamp,
1268 DWORD &dwSize,
1269 IStringHolder* pStrFilename)
1270{
1271#if !defined(FEATURE_PREJIT)
1272
1273 return false;
1274
1275#else // defined(FEATURE_PREJIT)
1276
1277 DD_ENTER_MAY_THROW;
1278
1279 PEFile * pPEFile = vmPEFile.GetDacPtr();
1280 _ASSERTE(pPEFile != NULL);
1281 if (pPEFile == NULL)
1282 {
1283 return false;
1284 }
1285
1286 WCHAR wszFilePath[MAX_LONGPATH] = {0};
1287 DWORD cchFilePath = MAX_LONGPATH;
1288 bool ret = ClrDataAccess::GetILImageInfoFromNgenPEFile(pPEFile,
1289 dwTimeStamp,
1290 dwSize,
1291 wszFilePath,
1292 cchFilePath);
1293
1294 pStrFilename->AssignCopy(wszFilePath);
1295 return ret;
1296#endif // !defined(FEATURE_PREJIT)
1297}
1298
1299// Get start addresses and sizes for hot and cold regions for a native code blob.
1300// Arguments:
1301// Input:
1302// pMethodDesc - method desc for the function we are inspecting
1303// Output (required):
1304// pCodeInfo - initializes the m_rgCodeRegions field of this structure
1305// if the native code is available. Otherwise,
1306// pCodeInfo->IsValid() is false.
1307
1308void DacDbiInterfaceImpl::GetMethodRegionInfo(MethodDesc * pMethodDesc,
1309 NativeCodeFunctionData * pCodeInfo)
1310{
1311 CONTRACTL
1312 {
1313 SO_INTOLERANT;
1314 GC_NOTRIGGER;
1315 PRECONDITION(CheckPointer(pCodeInfo));
1316 }
1317 CONTRACTL_END;
1318
1319 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
1320 PCODE functionAddress = pMethodDesc->GetNativeCode();
1321
1322 // get the start address of the hot region and initialize the jit manager
1323 pCodeInfo->m_rgCodeRegions[kHot].pAddress = CORDB_ADDRESS(PCODEToPINSTR(functionAddress));
1324
1325 // if the start address is NULL, the code isn't available yet, so just return
1326 if (functionAddress != NULL)
1327 {
1328 EECodeInfo codeInfo(functionAddress);
1329 _ASSERTE(codeInfo.IsValid());
1330
1331 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
1332
1333 // now get the rest of the region information
1334 pCodeInfo->m_rgCodeRegions[kHot].cbSize = (ULONG)methodRegionInfo.hotSize;
1335 pCodeInfo->m_rgCodeRegions[kCold].Init(PCODEToPINSTR(methodRegionInfo.coldStartAddress),
1336 (ULONG)methodRegionInfo.coldSize);
1337 _ASSERTE(pCodeInfo->IsValid());
1338 }
1339 else
1340 {
1341 _ASSERTE(!pCodeInfo->IsValid());
1342 }
1343} // GetMethodRegionInfo
1344
1345
1346// Gets the following information about a native code blob:
1347// - its method desc
1348// - whether it's an instantiated generic
1349// - its EnC version number
1350// - hot and cold region information.
1351// If the hot region start address is NULL at the end, it means the native code
1352// isn't currently available. In this case, all values in pCodeInfo will be
1353// cleared.
1354
1355void DacDbiInterfaceImpl::GetNativeCodeInfo(VMPTR_DomainFile vmDomainFile,
1356 mdToken functionToken,
1357 NativeCodeFunctionData * pCodeInfo)
1358{
1359 DD_ENTER_MAY_THROW;
1360
1361 _ASSERTE(pCodeInfo != NULL);
1362
1363 // pre-initialize:
1364 pCodeInfo->Clear();
1365
1366 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1367 Module * pModule = pDomainFile->GetCurrentModule();
1368
1369 MethodDesc* pMethodDesc = FindLoadedMethodRefOrDef(pModule, functionToken);
1370 pCodeInfo->vmNativeCodeMethodDescToken.SetHostPtr(pMethodDesc);
1371
1372 // if we are loading a module and trying to bind a previously set breakpoint, we may not have
1373 // a method desc yet, so check for that situation
1374 if(pMethodDesc != NULL)
1375 {
1376 GetMethodRegionInfo(pMethodDesc, pCodeInfo);
1377 if (pCodeInfo->m_rgCodeRegions[kHot].pAddress != NULL)
1378 {
1379 pCodeInfo->isInstantiatedGeneric = pMethodDesc->HasClassOrMethodInstantiation();
1380 LookupEnCVersions(pModule,
1381 pCodeInfo->vmNativeCodeMethodDescToken,
1382 functionToken,
1383 pCodeInfo->m_rgCodeRegions[kHot].pAddress,
1384 &(pCodeInfo->encVersion));
1385 }
1386 }
1387} // GetNativeCodeInfo
1388
1389// Gets the following information about a native code blob:
1390// - its method desc
1391// - whether it's an instantiated generic
1392// - its EnC version number
1393// - hot and cold region information.
1394void DacDbiInterfaceImpl::GetNativeCodeInfoForAddr(VMPTR_MethodDesc vmMethodDesc,
1395 CORDB_ADDRESS hotCodeStartAddr,
1396 NativeCodeFunctionData * pCodeInfo)
1397{
1398 DD_ENTER_MAY_THROW;
1399
1400 _ASSERTE(pCodeInfo != NULL);
1401
1402 if (hotCodeStartAddr == NULL)
1403 {
1404 // if the start address is NULL, the code isn't available yet, so just return
1405 _ASSERTE(!pCodeInfo->IsValid());
1406 return;
1407 }
1408
1409 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
1410 TADDR codeAddr = CORDB_ADDRESS_TO_TADDR(hotCodeStartAddr);
1411
1412#ifdef _TARGET_ARM_
1413 // TADDR should not have the thumb code bit set.
1414 _ASSERTE((codeAddr & THUMB_CODE) == 0);
1415 codeAddr &= ~THUMB_CODE;
1416#endif
1417
1418 EECodeInfo codeInfo(codeAddr);
1419 _ASSERTE(codeInfo.IsValid());
1420
1421 // We may not have the memory for the cold code region in a minidump.
1422 // Do not fail stackwalking because of this.
1423 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
1424 {
1425 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
1426 }
1427 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
1428
1429 // Even if GetMethodRegionInfo() fails to retrieve the cold code region info,
1430 // we should still be able to get the hot code region info. We are counting on this for
1431 // stackwalking to work in dump debugging scenarios.
1432 _ASSERTE(methodRegionInfo.hotStartAddress == codeAddr);
1433
1434 // now get the rest of the region information
1435 pCodeInfo->m_rgCodeRegions[kHot].Init(PCODEToPINSTR(methodRegionInfo.hotStartAddress),
1436 (ULONG)methodRegionInfo.hotSize);
1437 pCodeInfo->m_rgCodeRegions[kCold].Init(PCODEToPINSTR(methodRegionInfo.coldStartAddress),
1438 (ULONG)methodRegionInfo.coldSize);
1439 _ASSERTE(pCodeInfo->IsValid());
1440
1441 MethodDesc* pMethodDesc = vmMethodDesc.GetDacPtr();
1442 pCodeInfo->isInstantiatedGeneric = pMethodDesc->HasClassOrMethodInstantiation();
1443 pCodeInfo->vmNativeCodeMethodDescToken = vmMethodDesc;
1444
1445 SIZE_T unusedLatestEncVersion;
1446 Module * pModule = pMethodDesc->GetModule();
1447 _ASSERTE(pModule != NULL);
1448 LookupEnCVersions(pModule,
1449 vmMethodDesc,
1450 pMethodDesc->GetMemberDef(),
1451 codeAddr,
1452 &unusedLatestEncVersion, //unused by caller
1453 &(pCodeInfo->encVersion));
1454
1455} // GetNativeCodeInfo
1456
1457
1458//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1459//
1460// Functions to get Type and Class information
1461//
1462//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1463//-----------------------------------------------------------------------------
1464//DacDbiInterfaceImpl::GetTypeHandles
1465// Get the approximate and exact type handles for a type
1466// Arguments:
1467// input:
1468// vmThExact - VMPTR of the exact type handle. If this method is called
1469// to get information for a new generic instantiation, this will already
1470// be initialized. If it's called to get type information for an arbitrary
1471// type (i.e., called to initialize an instance of CordbClass), it will be NULL
1472// vmThApprox - VMPTR of the approximate type handle. If this method is called
1473// to get information for a new generic instantiation, this will already
1474// be initialized. If it's called to get type information for an arbitrary
1475// type (i.e., called to initialize an instance of CordbClass), it will be NULL
1476// output:
1477// pThExact - handle for exact type information for a generic instantiation
1478// pThApprox - handle for type information
1479// Notes:
1480// pThExact and pTHApprox must be pointers to existing memory.
1481//-----------------------------------------------------------------------------
1482void DacDbiInterfaceImpl::GetTypeHandles(VMPTR_TypeHandle vmThExact,
1483 VMPTR_TypeHandle vmThApprox,
1484 TypeHandle * pThExact,
1485 TypeHandle * pThApprox)
1486 {
1487 _ASSERTE((pThExact != NULL) && (pThApprox != NULL));
1488
1489 *pThExact = TypeHandle::FromPtr(vmThExact.GetDacPtr());
1490 *pThApprox = TypeHandle::FromPtr(vmThApprox.GetDacPtr());
1491
1492 // If we can't find the class, return the proper HR to the right side. Note: if the class is not a value class and
1493 // the class is also not restored, then we must pretend that the class is still not loaded. We are gonna let
1494 // unrestored value classes slide, though, and special case access to the class's parent below.
1495 if ((pThApprox->IsNull()) || ((!pThApprox->IsValueType()) && (!pThApprox->IsRestored())))
1496 {
1497 LOG((LF_CORDB, LL_INFO10000, "D::GASCI: class isn't loaded.\n"));
1498 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
1499 }
1500 // If the exact type handle is not restored ignore it.
1501 if (!pThExact->IsNull() && !pThExact->IsRestored())
1502 {
1503 *pThExact = TypeHandle();
1504 }
1505 } // DacDbiInterfaceImpl::GetTypeHandles
1506
1507//-----------------------------------------------------------------------------
1508// DacDbiInterfaceImpl::GetTotalFieldCount
1509// Gets the total number of fields for a type.
1510// Input Argument: thApprox - type handle used to determine the number of fields
1511// Return Value: count of the total fields of the type.
1512//-----------------------------------------------------------------------------
1513unsigned int DacDbiInterfaceImpl::GetTotalFieldCount(TypeHandle thApprox)
1514{
1515 MethodTable *pMT = thApprox.GetMethodTable();
1516
1517 // Count the instance and static fields for this class (not including parent).
1518 // This will not include any newly added EnC fields.
1519 unsigned int IFCount = pMT->GetNumIntroducedInstanceFields();
1520 unsigned int SFCount = pMT->GetNumStaticFields();
1521
1522#ifdef EnC_SUPPORTED
1523 PTR_Module pModule = pMT->GetModule();
1524
1525 // Stats above don't include EnC fields. So add them now.
1526 if (pModule->IsEditAndContinueEnabled())
1527 {
1528 PTR_EnCEEClassData pEncData =
1529 (dac_cast<PTR_EditAndContinueModule>(pModule))->GetEnCEEClassData(pMT, TRUE);
1530
1531 if (pEncData != NULL)
1532 {
1533 _ASSERTE(pEncData->GetMethodTable() == pMT);
1534
1535 // EnC only adds fields, never removes them.
1536 IFCount += pEncData->GetAddedInstanceFields();
1537 SFCount += pEncData->GetAddedStaticFields();
1538 }
1539 }
1540#endif
1541 return IFCount + SFCount;
1542} // DacDbiInterfaceImpl::GetTotalFieldCount
1543
1544//-----------------------------------------------------------------------------
1545// DacDbiInterfaceImpl::InitClassData
1546// initializes various values of the ClassInfo data structure, including the
1547// field count, generic args count, size and value class flag
1548// Arguments:
1549// input: thApprox - used to get access to all the necessary values
1550// fIsInstantiatedType - used to determine how to compute the size
1551// output: pData - contains fields to be initialized
1552//-----------------------------------------------------------------------------
1553void DacDbiInterfaceImpl::InitClassData(TypeHandle thApprox,
1554 BOOL fIsInstantiatedType,
1555 ClassInfo * pData)
1556{
1557 pData->m_fieldList.Alloc(GetTotalFieldCount(thApprox));
1558
1559 // For Generic classes you must get the object size via the type handle, which
1560 // will get you to the right information for the particular instantiation
1561 // you're working with...
1562 pData->m_objectSize = 0;
1563 if ((!thApprox.GetNumGenericArgs()) || fIsInstantiatedType)
1564 {
1565 pData->m_objectSize = thApprox.GetMethodTable()->GetNumInstanceFieldBytes();
1566 }
1567
1568} // DacDbiInterfaceImpl::InitClassData
1569
1570//-----------------------------------------------------------------------------
1571// DacDbiInterfaceImpl::GetStaticsBases
1572// Gets the base table addresses for both GC and non-GC statics
1573// Arguments:
1574// input: thExact - exact type handle for the class
1575// pAppDomain - AppDomain in which the class is loaded
1576// output: ppGCStaticsBase - base pointer for GC statics
1577// ppNonGCStaticsBase - base pointer for non GC statics
1578// Notes:
1579// If this is a non-generic type, or an instantiated type, then we'll be able to get the static var bases
1580// If the typeHandle represents a generic type constructor (i.e. an uninstantiated generic class), then
1581// the static bases will be null (since statics are per-instantiation).
1582//-----------------------------------------------------------------------------
1583void DacDbiInterfaceImpl::GetStaticsBases(TypeHandle thExact,
1584 AppDomain * pAppDomain,
1585 PTR_BYTE * ppGCStaticsBase,
1586 PTR_BYTE * ppNonGCStaticsBase)
1587 {
1588 MethodTable * pMT = thExact.GetMethodTable();
1589 Module * pModuleForStatics = pMT->GetModuleForStatics();
1590 if (pModuleForStatics != NULL)
1591 {
1592 PTR_DomainLocalModule pLocalModule = pModuleForStatics->GetDomainLocalModule(pAppDomain);
1593 if (pLocalModule != NULL)
1594 {
1595 *ppGCStaticsBase = pLocalModule->GetGCStaticsBasePointer(pMT);
1596 *ppNonGCStaticsBase = pLocalModule->GetNonGCStaticsBasePointer(pMT);
1597 }
1598 }
1599} // DacDbiInterfaceImpl::GetStaticsBases
1600
1601//-----------------------------------------------------------------------------
1602// DacDbiInterfaceImpl::ComputeFieldData
1603// Computes the field info for pFD and stores it in pcurrentFieldData
1604// Arguments:
1605// input: pFD - FieldDesc used to get necessary information
1606// pGCStaticsBase - base table address for GC statics
1607// pNonGCStaticsBase - base table address for non-GC statics
1608// output: pCurrentFieldData - contains fields to be initialized
1609//-----------------------------------------------------------------------------
1610void DacDbiInterfaceImpl::ComputeFieldData(PTR_FieldDesc pFD,
1611 PTR_BYTE pGCStaticsBase,
1612 PTR_BYTE pNonGCStaticsBase,
1613 FieldData * pCurrentFieldData)
1614{
1615 pCurrentFieldData->Initialize(pFD->IsStatic(), pFD->IsPrimitive(), pFD->GetMemberDef());
1616
1617#ifdef EnC_SUPPORTED
1618 // If the field was newly introduced via EnC, and hasn't yet
1619 // been fixed up, then we'll send back a marker indicating
1620 // that it isn't yet available.
1621 if (pFD->IsEnCNew())
1622 {
1623 // @dbgtodo Microsoft inspection: eliminate the debugger token when ICDClass and ICDType are
1624 // completely DACized
1625 pCurrentFieldData->m_vmFieldDesc.SetHostPtr(pFD);
1626 pCurrentFieldData->m_fFldStorageAvailable = FALSE;
1627 pCurrentFieldData->m_fFldIsTLS = FALSE;
1628 pCurrentFieldData->m_fFldIsRVA = FALSE;
1629 pCurrentFieldData->m_fFldIsCollectibleStatic = FALSE;
1630 }
1631 else
1632#endif // EnC_SUPPORTED
1633 {
1634 // Otherwise, we'll compute the info & send it back.
1635 pCurrentFieldData->m_fFldStorageAvailable = TRUE;
1636 // @dbgtodo Microsoft inspection: eliminate the debugger token when ICDClass and ICDType are
1637 // completely DACized
1638 pCurrentFieldData->m_vmFieldDesc.SetHostPtr(pFD);
1639 pCurrentFieldData->m_fFldIsTLS = (pFD->IsThreadStatic() == TRUE);
1640 pCurrentFieldData->m_fFldIsRVA = (pFD->IsRVA() == TRUE);
1641 pCurrentFieldData->m_fFldIsCollectibleStatic = (pFD->IsStatic() == TRUE &&
1642 pFD->GetEnclosingMethodTable()->Collectible());
1643
1644 // Compute the address of the field
1645 if (pFD->IsStatic())
1646 {
1647 // statics are addressed using an absolute address.
1648 if (pFD->IsRVA())
1649 {
1650 // RVA statics are relative to a base module address
1651 DWORD offset = pFD->GetOffset();
1652 PTR_VOID addr = pFD->GetModule()->GetRvaField(offset, pFD->IsZapped());
1653 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1654 {
1655 pCurrentFieldData->SetStaticAddress(PTR_TO_TADDR(addr));
1656 }
1657 }
1658 else if (pFD->IsThreadStatic() ||
1659 pCurrentFieldData->m_fFldIsCollectibleStatic)
1660 {
1661 // this is a special type of static that must be queried using DB_IPCE_GET_SPECIAL_STATIC
1662 }
1663 else
1664 {
1665 // This is a normal static variable in the GC or Non-GC static base table
1666 PTR_BYTE base = pFD->IsPrimitive() ? pNonGCStaticsBase : pGCStaticsBase;
1667 if (base == NULL)
1668 {
1669 // static var not available. This may be an open generic class (not an instantiated type),
1670 // or we might only have approximate type information because the type hasn't been
1671 // initialized yet.
1672
1673 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1674 {
1675 pCurrentFieldData->SetStaticAddress(NULL);
1676 }
1677 }
1678 else
1679 {
1680 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1681 {
1682 // calculate the absolute address using the base and the offset from the base
1683 pCurrentFieldData->SetStaticAddress(PTR_TO_TADDR(base) + pFD->GetOffset());
1684 }
1685 }
1686 }
1687 }
1688 else
1689 {
1690 // instance variables are addressed using an offset within the instance
1691 if (pCurrentFieldData->OkToGetOrSetInstanceOffset())
1692 {
1693 pCurrentFieldData->SetInstanceOffset(pFD->GetOffset());
1694 }
1695 }
1696 }
1697
1698} // DacDbiInterfaceImpl::ComputeFieldData
1699
1700//-----------------------------------------------------------------------------
1701// DacDbiInterfaceImpl::CollectFields
1702// Gets information for all the fields for a given type
1703// Arguments:
1704// input: thExact - used to determine whether we need to get statics base tables
1705// thApprox - used to get the field desc iterator
1706// pAppDomain - used to get statics base tables
1707// output:
1708// pFieldList - contains fields to be initialized
1709// Note: the caller must ensure that *ppFields is NULL (i.e., any previously allocated memory
1710// must have been deallocated.
1711//-----------------------------------------------------------------------------
1712void DacDbiInterfaceImpl::CollectFields(TypeHandle thExact,
1713 TypeHandle thApprox,
1714 AppDomain * pAppDomain,
1715 DacDbiArrayList<FieldData> * pFieldList)
1716{
1717 PTR_BYTE pGCStaticsBase = NULL;
1718 PTR_BYTE pNonGCStaticsBase = NULL;
1719 if (!thExact.IsNull() && !thExact.GetMethodTable()->Collectible())
1720 {
1721 // get base tables for static fields
1722 GetStaticsBases(thExact, pAppDomain, &pGCStaticsBase, &pNonGCStaticsBase);
1723 }
1724
1725 unsigned int fieldCount = 0;
1726
1727 // <TODO> we are losing exact type information for static fields in generic types. We have
1728 // field desc iterators only for approximate types, but statics are per instantiation, so we
1729 // need an exact type to be able to handle these correctly. We need to use
1730 // FieldDesc::GetExactDeclaringType to get at the correct field. This requires the exact
1731 // TypeHandle. </TODO>
1732 EncApproxFieldDescIterator fdIterator(thApprox.GetMethodTable(),
1733 ApproxFieldDescIterator::ALL_FIELDS,
1734 FALSE); // don't fixup EnC (we can't, we're stopped)
1735
1736 PTR_FieldDesc pCurrentFD;
1737 int index = 0;
1738 while (((pCurrentFD = fdIterator.Next()) != NULL) && (index < pFieldList->Count()))
1739 {
1740 // fill in the pCurrentEntry structure
1741 ComputeFieldData(pCurrentFD, pGCStaticsBase, pNonGCStaticsBase, &((*pFieldList)[index]));
1742
1743 // Bump our counts and pointers.
1744 fieldCount++;
1745 index++;
1746 }
1747 _ASSERTE(fieldCount == (unsigned int)pFieldList->Count());
1748
1749} // DacDbiInterfaceImpl::CollectFields
1750
1751
1752// Determine if a type is a ValueType
1753BOOL DacDbiInterfaceImpl::IsValueType (VMPTR_TypeHandle vmTypeHandle)
1754{
1755 DD_ENTER_MAY_THROW;
1756
1757 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
1758 return th.IsValueType();
1759}
1760
1761// Determine if a type has generic parameters
1762BOOL DacDbiInterfaceImpl::HasTypeParams (VMPTR_TypeHandle vmTypeHandle)
1763{
1764 DD_ENTER_MAY_THROW;
1765
1766 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
1767 return th.ContainsGenericVariables();
1768}
1769
1770// DacDbi API: Get type information for a class
1771void DacDbiInterfaceImpl::GetClassInfo(VMPTR_AppDomain vmAppDomain,
1772 VMPTR_TypeHandle vmThExact,
1773 ClassInfo * pData)
1774{
1775 DD_ENTER_MAY_THROW;
1776
1777 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
1778
1779 TypeHandle thExact;
1780 TypeHandle thApprox;
1781
1782 GetTypeHandles(vmThExact, vmThExact, &thExact, &thApprox);
1783
1784 // initialize field count, generic args count, size and value class flag
1785 InitClassData(thApprox, false, pData);
1786
1787 if (pAppDomain != NULL)
1788 CollectFields(thExact, thApprox, pAppDomain, &(pData->m_fieldList));
1789} // DacDbiInterfaceImpl::GetClassInfo
1790
1791// DacDbi API: Get field information and object size for an instantiated generic type
1792void DacDbiInterfaceImpl::GetInstantiationFieldInfo (VMPTR_DomainFile vmDomainFile,
1793 VMPTR_TypeHandle vmThExact,
1794 VMPTR_TypeHandle vmThApprox,
1795 DacDbiArrayList<FieldData> * pFieldList,
1796 SIZE_T * pObjectSize)
1797{
1798 DD_ENTER_MAY_THROW;
1799
1800 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1801 _ASSERTE(pDomainFile != NULL);
1802 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
1803 TypeHandle thExact;
1804 TypeHandle thApprox;
1805
1806 GetTypeHandles(vmThExact, vmThApprox, &thExact, &thApprox);
1807
1808 *pObjectSize = thApprox.GetMethodTable()->GetNumInstanceFieldBytes();
1809
1810 pFieldList->Alloc(GetTotalFieldCount(thApprox));
1811
1812 CollectFields(thExact, thApprox, pAppDomain, pFieldList);
1813
1814} // DacDbiInterfaceImpl::GetInstantiationFieldInfo
1815
1816//-----------------------------------------------------------------------------------
1817// DacDbiInterfaceImpl::TypeDataWalk member functions
1818//-----------------------------------------------------------------------------------
1819
1820//-----------------------------------------------------------------------------
1821// TypeDataWalk constructor--initialize the buffer and number of remaining items from input data
1822// Arguments: pData - pointer to a list of records containing information about type parameters for an
1823// instantiated type
1824// nData - number of entries in pData
1825//-----------------------------------------------------------------------------
1826DacDbiInterfaceImpl::TypeDataWalk::TypeDataWalk(DebuggerIPCE_TypeArgData * pData, unsigned int nData)
1827{
1828 m_pCurrentData = pData;
1829 m_nRemaining = nData;
1830} // DacDbiInterfaceImpl::TypeDataWalk::TypeDataWalk
1831
1832//-----------------------------------------------------------------------------
1833// DacDbiInterfaceImpl::TypeDataWalk::ReadOne
1834// read and return a single node from the list of type parameters
1835// Arguments: none (uses internal state)
1836// Return value: information about the next type parameter in m_pCurrentData
1837//-----------------------------------------------------------------------------
1838DebuggerIPCE_TypeArgData * DacDbiInterfaceImpl::TypeDataWalk::ReadOne()
1839{
1840 LIMITED_METHOD_CONTRACT;
1841 if (m_nRemaining)
1842 {
1843 m_nRemaining--;
1844 return m_pCurrentData++;
1845 }
1846 else
1847 {
1848 return NULL;
1849 }
1850} // DacDbiInterfaceImpl::TypeDataWalk::ReadOne
1851
1852//-----------------------------------------------------------------------------
1853// DacDbiInterfaceImpl::TypeDataWalk::Skip
1854// Skip a single node from the list of type handles along with any children it might have
1855// Arguments: none (uses internal state)
1856// Return value: none (updates internal state)
1857//-----------------------------------------------------------------------------
1858void DacDbiInterfaceImpl::TypeDataWalk::Skip()
1859{
1860 LIMITED_METHOD_CONTRACT;
1861
1862 DebuggerIPCE_TypeArgData * pData = ReadOne();
1863 if (pData)
1864 {
1865 for (unsigned int i = 0; i < pData->numTypeArgs; i++)
1866 {
1867 Skip();
1868 }
1869 }
1870} // DacDbiInterfaceImpl::TypeDataWalk::Skip
1871
1872//-----------------------------------------------------------------------------
1873// DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg
1874// Read a type handle when it is used in the position of a generic argument or
1875// argument of an array or address type. Take into account generic code sharing if we
1876// have been requested to find the canonical representation amongst a set of shared-
1877// code generic types. That is, if generics code sharing is enabled then return "Object"
1878// for all reference types, and canonicalize underneath value types, e.g. V<string> --> V<object>.
1879// Return TypeHandle() if any of the type handles are not loaded.
1880//
1881// Arguments: retrieveWhich - indicates whether to retrieve a canonical representation or
1882// an exact representation
1883// Return value: the type handle for the type parameter
1884//-----------------------------------------------------------------------------
1885TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg(TypeHandleReadType retrieveWhich)
1886{
1887 CONTRACTL
1888 {
1889 NOTHROW;
1890 GC_NOTRIGGER;
1891 }
1892 CONTRACTL_END;
1893
1894#if !defined(FEATURE_SHARE_GENERIC_CODE)
1895 return ReadLoadedTypeHandle(kGetExact);
1896#else
1897
1898 if (retrieveWhich == kGetExact)
1899 return ReadLoadedTypeHandle(kGetExact);
1900
1901 // This nasty bit of code works out what the "canonicalization" of a
1902 // parameter to a generic is once we take into account generics code sharing.
1903 //
1904 // This logic is somewhat a duplication of logic in vm\typehandle.cpp, though
1905 // that logic operates on a TypeHandle format, i.e. assumes we're finding the
1906 // canonical form of a type that has already been loaded. Here we are finding
1907 // the canonical form of a type that may not have been loaded (but where we expect
1908 // its canonical form to have been loaded).
1909 //
1910 // Ideally this logic would not be duplicated in this way, but it is difficult
1911 // to arrange for that.
1912 DebuggerIPCE_TypeArgData * pData = ReadOne();
1913 if (!pData)
1914 return TypeHandle();
1915
1916 // If we have code sharing then the process of canonicalizing is trickier.
1917 // unfortunately we have to include the exact specification of compatibility at
1918 // this point.
1919 CorElementType elementType = pData->data.elementType;
1920
1921 switch (elementType)
1922 {
1923 case ELEMENT_TYPE_PTR:
1924 _ASSERTE(pData->numTypeArgs == 1);
1925 return PtrOrByRefTypeArg(pData, retrieveWhich);
1926 break;
1927
1928 case ELEMENT_TYPE_CLASS:
1929 case ELEMENT_TYPE_VALUETYPE:
1930 return ClassTypeArg(pData, retrieveWhich);
1931 break;
1932
1933 case ELEMENT_TYPE_FNPTR:
1934 return FnPtrTypeArg(pData, retrieveWhich);
1935 break;
1936
1937 default:
1938 return ObjRefOrPrimitiveTypeArg(pData, elementType);
1939 break;
1940 }
1941
1942#endif // FEATURE_SHARE_GENERIC_CODE
1943} // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg
1944
1945//-----------------------------------------------------------------------------
1946// DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles
1947// Iterate through the type argument data, creating type handles as we go.
1948//
1949// Arguments:
1950// input: retrieveWhich - indicates whether we can return a canonical type handle
1951// or we must return an exact type handle
1952// nTypeArgs - number of type arguments to be read
1953// output: ppResults - pointer to a list of TypeHandles that will hold the type handles
1954// for each type parameter
1955//
1956// Return Value: FALSE iff any of the type handles are not loaded.
1957//-----------------------------------------------------------------------------
1958BOOL DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles(TypeHandleReadType retrieveWhich,
1959 unsigned int nTypeArgs,
1960 TypeHandle * ppResults)
1961{
1962 WRAPPER_NO_CONTRACT;
1963
1964 BOOL allOK = true;
1965 for (unsigned int i = 0; i < nTypeArgs; i++)
1966 {
1967 ppResults[i] = ReadLoadedTypeArg(retrieveWhich);
1968 allOK &= !ppResults[i].IsNull();
1969 }
1970 return allOK;
1971} // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles
1972
1973//-----------------------------------------------------------------------------
1974// DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation
1975// Read an instantiation of a generic type if it has already been created.
1976//
1977// Arguments:
1978// input: retrieveWhich - indicates whether we can return a canonical type handle
1979// or we must return an exact type handle
1980// pModule - module in which the instantiated type is loaded
1981// mdToken - metadata token for the type
1982// nTypeArgs - number of type arguments to be read
1983// Return value: the type handle for the instantiated type
1984//-----------------------------------------------------------------------------
1985TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation(TypeHandleReadType retrieveWhich,
1986 Module * pModule,
1987 mdTypeDef mdToken,
1988 unsigned int nTypeArgs)
1989{
1990 WRAPPER_NO_CONTRACT;
1991
1992 NewHolder<TypeHandle> pInst(new TypeHandle[nTypeArgs]);
1993
1994 // get the type handle for each of the type parameters
1995 if (!ReadLoadedTypeHandles(retrieveWhich, nTypeArgs, pInst))
1996 {
1997 return TypeHandle();
1998 }
1999
2000 // get the type handle for the particular instantiation that corresponds to
2001 // the given type parameters
2002 return FindLoadedInstantiation(pModule, mdToken, nTypeArgs, pInst);
2003
2004} // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation
2005
2006
2007//-----------------------------------------------------------------------------
2008// DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle
2009//
2010// Compute the type handle for a given type.
2011// This is the top-level function that will return the type handle for an
2012// arbitrary type. It uses mutual recursion with ReadLoadedTypeArg to get
2013// the type handle for a (possibly parameterized) type. Note that the referent of
2014// address types or the element type of an array type are viewed as type parameters.
2015//
2016// For example, assume that we are retrieving only exact types, and we have as our
2017// top level type an array defined as int [][].
2018// We start by noting that the type is an array type, so we call ReadLoadedTypeArg to
2019// get the element type. We find that the element type is also an array:int [].
2020// ReadLoadedTypeArg will call ReadLoadedTypeHandle with this type information.
2021// Again, we determine that the top-level type is an array, so we call ReadLoadedTypeArg
2022// to get the element type, int. ReadLoadedTypeArg will again call ReadLoadedTypeHandle
2023// which will find that this time, the top-level type is a primitive type. It will request
2024// the loaded type handle from the loader and return it. On return, we get the type handle
2025// for an array of int from the loader. We return again and request the type handle for an
2026// array of arrays of int. This is the type handle we will return.
2027//
2028// Arguments:
2029// input: retrieveWhich - determines whether we can return the type handle for
2030// a canonical type or only for an exact type
2031// we use the list of type data stored in the TypeDataWalk data members
2032// for other input information
2033// Return value: type handle for the current type.
2034//-----------------------------------------------------------------------------
2035TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle(TypeHandleReadType retrieveWhich)
2036{
2037 CONTRACTL
2038 {
2039 NOTHROW;
2040 GC_NOTRIGGER;
2041 }
2042 CONTRACTL_END;
2043
2044 // get the type information at the head of the list m_pCurrentData
2045 DebuggerIPCE_TypeArgData * pData = ReadOne();
2046 if (!pData)
2047 return TypeHandle();
2048
2049 // get the type handle that corresponds to its elementType
2050 TypeHandle typeHandle;
2051 switch (pData->data.elementType)
2052 {
2053 case ELEMENT_TYPE_ARRAY:
2054 case ELEMENT_TYPE_SZARRAY:
2055 typeHandle = ArrayTypeArg(pData, retrieveWhich);
2056 break;
2057
2058 case ELEMENT_TYPE_PTR:
2059 case ELEMENT_TYPE_BYREF:
2060 typeHandle = PtrOrByRefTypeArg(pData, retrieveWhich);
2061 break;
2062 case ELEMENT_TYPE_CLASS:
2063 case ELEMENT_TYPE_VALUETYPE:
2064 {
2065 Module * pModule = pData->data.ClassTypeData.vmModule.GetDacPtr();
2066 typeHandle = ReadLoadedInstantiation(retrieveWhich,
2067 pModule,
2068 pData->data.ClassTypeData.metadataToken,
2069 pData->numTypeArgs);
2070 }
2071 break;
2072
2073 case ELEMENT_TYPE_FNPTR:
2074 {
2075 typeHandle = FnPtrTypeArg(pData, retrieveWhich);
2076 }
2077 break;
2078
2079 default:
2080 typeHandle = FindLoadedElementType(pData->data.elementType);
2081 break;
2082 }
2083 return typeHandle;
2084} // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle
2085
2086//-----------------------------------------------------------------------------
2087// DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg
2088// get a loaded type handle for an array type (E_T_ARRAY or E_T_SZARRAY)
2089//
2090// Arguments:
2091// input: pArrayTypeInfo - type information for an array type
2092// Although this is in fact a pointer (in)to a list, we treat it here
2093// simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2094// which holds type information for an array.
2095// This is the most recent type node (for an array type) retrieved
2096// by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeArg will
2097// result in call(s) to ReadOne to retrieve one or more type nodes
2098// that are needed to compute the type handle for the
2099// element type of the array. When we return from that call, we pass
2100// pArrayTypeInfo along with arrayElementTypeArg to FindLoadedArrayType
2101// to get the type handle for this particular array type.
2102// Note:
2103// On entry, we know that pArrayTypeInfo is the same as m_pCurrentData - 1,
2104// but by the time we need to use it, this is no longer true. Because
2105// we can't predict how many nodes will be consumed by the call to
2106// ReadLoadedTypeArg, we can't compute this value from the member fields
2107// of TypeDataWalk and therefore pass it as a parameter.
2108// retrieveWhich - determines whether we can return the type handle for
2109// a canonical type or only for an exact type
2110// Return value: the type handle corresponding to the array type
2111//-----------------------------------------------------------------------------
2112
2113TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg(DebuggerIPCE_TypeArgData * pArrayTypeInfo,
2114 TypeHandleReadType retrieveWhich)
2115{
2116 TypeHandle arrayElementTypeArg = ReadLoadedTypeArg(retrieveWhich);
2117 if (!arrayElementTypeArg.IsNull())
2118 {
2119 return FindLoadedArrayType(pArrayTypeInfo->data.elementType,
2120 arrayElementTypeArg,
2121 pArrayTypeInfo->data.ArrayTypeData.arrayRank);
2122 }
2123 return TypeHandle();
2124} // DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg
2125
2126
2127//-----------------------------------------------------------------------------
2128// DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg
2129// get a loaded type handle for an address type (E_T_PTR or E_T_BYREF)
2130//
2131// Arguments:
2132// input: pPtrOrByRefTypeInfo - type information for a pointer or byref type
2133// Although this is in fact a pointer (in)to a list, we treat it here
2134// simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2135// which holds type information for a pointer or byref type.
2136// This is the most recent type node (for a pointer or byref type) retrieved
2137// by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeArg will
2138// result in call(s) to ReadOne to retrieve one or more type nodes
2139// that are needed to compute the type handle for the
2140// referent type of the pointer. When we return from that call, we pass
2141// pPtrOrByRefTypeInfo along with referentTypeArg to FindLoadedPointerOrByrefType
2142// to get the type handle for this particular pointer or byref type.
2143// Note:
2144// On entry, we know that pPtrOrByRefTypeInfo is the same as m_pCurrentData - 1,
2145// but by the time we need to use it, this is no longer true. Because
2146// we can't predict how many nodes will be consumed by the call to
2147// ReadLoadedTypeArg, we can't compute this value from the member fields
2148// of TypeDataWalk and therefore pass it as a parameter.
2149// retrieveWhich - determines whether we can return the type handle for
2150// a canonical type or only for an exact type
2151// Return value: the type handle corresponding to the address type
2152//-----------------------------------------------------------------------------
2153TypeHandle DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg(DebuggerIPCE_TypeArgData * pPtrOrByRefTypeInfo,
2154 TypeHandleReadType retrieveWhich)
2155{
2156 TypeHandle referentTypeArg = ReadLoadedTypeArg(retrieveWhich);
2157 if (!referentTypeArg.IsNull())
2158 {
2159 return FindLoadedPointerOrByrefType(pPtrOrByRefTypeInfo->data.elementType, referentTypeArg);
2160 }
2161
2162 return TypeHandle();
2163
2164} // DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg
2165
2166//-----------------------------------------------------------------------------
2167// DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg
2168// get a loaded type handle for a class type (E_T_CLASS or E_T_VALUETYPE)
2169//
2170// Arguments:
2171// input: pClassTypeInfo - type information for a class type
2172// Although this is in fact a pointer (in)to a list, we treat it here
2173// simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2174// which holds type information for a pointer or byref type.
2175// This is the most recent type node (for a pointer or byref type) retrieved
2176// by TypeDataWalk::ReadOne(). The call to ReadLoadedInstantiation will
2177// result in call(s) to ReadOne to retrieve one or more type nodes
2178// that are needed to compute the type handle for the type parameters
2179// for the class. If we can't find an exact loaded type for the class, we will
2180// instead return a canonical method table. In this case, we need to skip
2181// the type parameter information for each actual parameter to the class.
2182// This is necessary because we may be getting a type handle for a class which is
2183// in turn an argument to a parent type. If the parent type has more arguments, we
2184// need to be at the right place in the list when we return. We use
2185// pClassTypeInfo to get the number of type arguments that we need to skip.
2186// retrieveWhich - determines whether we can return the type handle for
2187// a canonical type or only for an exact type
2188// Return value: the type handle corresponding to the class type
2189//-----------------------------------------------------------------------------
2190TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg(DebuggerIPCE_TypeArgData * pClassTypeInfo,
2191 TypeHandleReadType retrieveWhich)
2192{
2193 Module * pModule = pClassTypeInfo->data.ClassTypeData.vmModule.GetDacPtr();
2194 TypeHandle typeDef = ClassLoader::LookupTypeDefOrRefInModule(pModule,
2195 pClassTypeInfo->data.ClassTypeData.metadataToken);
2196
2197 if ((!typeDef.IsNull() && typeDef.IsValueType()) || (pClassTypeInfo->data.elementType == ELEMENT_TYPE_VALUETYPE))
2198 {
2199 return ReadLoadedInstantiation(retrieveWhich,
2200 pModule,
2201 pClassTypeInfo->data.ClassTypeData.metadataToken,
2202 pClassTypeInfo->numTypeArgs);
2203 }
2204 else
2205 {
2206 _ASSERTE(retrieveWhich == kGetCanonical);
2207 // skip the instantiation - no need to look at it since the type canonicalizes to "Object"
2208 for (unsigned int i = 0; i < pClassTypeInfo->numTypeArgs; i++)
2209 {
2210 Skip();
2211 }
2212 return TypeHandle(g_pCanonMethodTableClass);
2213 }
2214}// DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg
2215
2216//-----------------------------------------------------------------------------
2217// DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg
2218// get a loaded type handle for a function pointer type (E_T_FNPTR)
2219//
2220// Arguments:
2221// input: pFnPtrTypeInfo - type information for a pointer or byref type
2222// Although this is in fact a pointer (in)to a list, we treat it here
2223// simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2224// which holds type information for a function pointer type.
2225// This is the most recent type node (for a function pointer type) retrieved
2226// by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeHandles will
2227// result in call(s) to ReadOne to retrieve one or more type nodes
2228// that are needed to compute the type handle for the return type and
2229// parameter types of the function. When we return from that call, we pass
2230// pFnPtrTypeInfo along with pInst to FindLoadedFnptrType
2231// to get the type handle for this particular function pointer type.
2232// retrieveWhich - determines whether we can return the type handle for
2233// a canonical type or only for an exact type
2234// Return value: the type handle corresponding to the function pointer type
2235//-----------------------------------------------------------------------------
2236TypeHandle DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg(DebuggerIPCE_TypeArgData * pFnPtrTypeInfo,
2237 TypeHandleReadType retrieveWhich)
2238{
2239 // allocate space to store a list of type handles, one for the return type and one for each
2240 // of the parameter types of the function to which the FnPtr type refers.
2241 NewHolder<TypeHandle> pInst(new TypeHandle[sizeof(TypeHandle) * pFnPtrTypeInfo->numTypeArgs]);
2242
2243 if (ReadLoadedTypeHandles(retrieveWhich, pFnPtrTypeInfo->numTypeArgs, pInst))
2244 {
2245 return FindLoadedFnptrType(pFnPtrTypeInfo->numTypeArgs, pInst);
2246 }
2247
2248 return TypeHandle();
2249
2250} // DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg
2251
2252//-----------------------------------------------------------------------------
2253// DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg
2254// get a loaded type handle for a primitive type or ObjRef
2255//
2256// Arguments:
2257// input: pArgInfo - type information for an objref or primitive type.
2258// This is called only when the objref or primitive type
2259// is a type argument for a parent type. In this case,
2260// we treat all objrefs the same, that is, we don't care
2261// about type parameters for the referent. Instead, we will
2262// simply return the canonical object type handle as the type
2263// of the referent. <@dbgtodo Microsoft: why is this?>
2264// If this is a primitive type, we'll simply get the
2265// type handle for that type.
2266// elementType - type of the argument
2267// Return value: the type handle corresponding to the elementType
2268//-----------------------------------------------------------------------------
2269TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg(DebuggerIPCE_TypeArgData * pArgInfo,
2270 CorElementType elementType)
2271{
2272 // If there are any type args (e.g. for arrays) they can be skipped. The thing
2273 // is a reference type anyway.
2274 for (unsigned int i = 0; i < pArgInfo->numTypeArgs; i++)
2275 {
2276 Skip();
2277 }
2278
2279 // for an ObjRef, just return the CLASS____CANON type handle
2280 if (CorTypeInfo::IsObjRef_NoThrow(elementType))
2281 {
2282 return TypeHandle(g_pCanonMethodTableClass);
2283 }
2284 else
2285 {
2286 return FindLoadedElementType(elementType);
2287 }
2288} // DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg
2289
2290
2291//-------------------------------------------------------------------------
2292// end of TypeDataWalk implementations
2293//-------------------------------------------------------------------------
2294//-------------------------------------------------------------------------
2295// functions to use loader to get type handles
2296// ------------------------------------------------------------------------
2297
2298// Note, in these functions, the use of ClassLoader::DontLoadTypes was chosen
2299// instead of FailIfNotLoaded because, although we may want to debug unrestored
2300// VCs, we can't do it because the debug API is not set up to handle them.
2301//
2302//-----------------------------------------------------------------------------
2303// DacDbiInterfaceImpl::FindLoadedArrayType
2304// Use ClassLoader to find a loaded type handle for an array type (E_T_ARRAY or E_T_SZARRAY)
2305// Arguments:
2306// input: arrayType - type of the array
2307// TypeArg - type handle for the base type
2308// rank - array rank
2309// Return Value: type handle for the array type
2310//-----------------------------------------------------------------------------
2311// static
2312TypeHandle DacDbiInterfaceImpl::FindLoadedArrayType(CorElementType arrayType,
2313 TypeHandle typeArg,
2314 unsigned rank)
2315{
2316 // Lookup operations run the class loader in non-load mode.
2317 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2318
2319 if (typeArg.IsNull())
2320 {
2321 return TypeHandle();
2322 }
2323 else
2324 {
2325 return ClassLoader::LoadArrayTypeThrowing(typeArg,
2326 arrayType,
2327 rank,
2328 ClassLoader::DontLoadTypes );
2329 }
2330} // DacDbiInterfaceImpl::FindLoadedArrayType;
2331
2332//-----------------------------------------------------------------------------
2333// DacDbiInterfaceImpl::FindLoadedPointerOrByrefType
2334// Use ClassLoader to find a loaded type handle for an address type (E_T_PTR or E_T_BYREF)
2335// Arguments:
2336// input: addressType - type of the address type
2337// TypeArg - type handle for the base type
2338// Return Value: type handle for the address type
2339//-----------------------------------------------------------------------------
2340// static
2341TypeHandle DacDbiInterfaceImpl::FindLoadedPointerOrByrefType(CorElementType addressType, TypeHandle typeArg)
2342{
2343 // Lookup operations run the class loader in non-load mode.
2344 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2345
2346 return ClassLoader::LoadPointerOrByrefTypeThrowing(addressType,
2347 typeArg,
2348 ClassLoader::DontLoadTypes);
2349} // DacDbiInterfaceImpl::FindLoadedPointerOrByrefType
2350
2351//-----------------------------------------------------------------------------
2352// DacDbiInterfaceImpl::FindLoadedFnptrType
2353// Use ClassLoader to find a loaded type handle for a function pointer type (E_T_FNPTR)
2354// Arguments:
2355// input: pInst - type handles of the function's return value and arguments
2356// numTypeArgs - number of type handles in pInst
2357// Return Value: type handle for the function pointer type
2358//-----------------------------------------------------------------------------
2359// static
2360TypeHandle DacDbiInterfaceImpl::FindLoadedFnptrType(DWORD numTypeArgs, TypeHandle * pInst)
2361{
2362 // Lookup operations run the class loader in non-load mode.
2363 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2364
2365 // @dbgtodo : Do we need to worry about calling convention here?
2366 // LoadFnptrTypeThrowing expects the count of arguments, not
2367 // including return value, so we subtract 1 from numTypeArgs.
2368 return ClassLoader::LoadFnptrTypeThrowing(0,
2369 numTypeArgs - 1,
2370 pInst,
2371 ClassLoader::DontLoadTypes);
2372} // DacDbiInterfaceImpl::FindLoadedFnptrType
2373
2374//-----------------------------------------------------------------------------
2375// DacDbiInterfaceImpl::FindLoadedInstantiation
2376// Use ClassLoader to find a loaded type handle for a particular instantiation of a
2377// class type (E_T_CLASS or E_T_VALUECLASS)
2378//
2379// Arguments:
2380// input: pModule - module in which the type is loaded
2381// mdToken - metadata token for the type
2382// nTypeArgs - number of type arguments in pInst
2383// pInst - list of type handles for the type parameters
2384// Return value: type handle for the instantiated class type
2385//-----------------------------------------------------------------------------
2386// static
2387TypeHandle DacDbiInterfaceImpl::FindLoadedInstantiation(Module * pModule,
2388 mdTypeDef mdToken,
2389 DWORD nTypeArgs,
2390 TypeHandle * pInst)
2391{
2392 // Lookup operations run the class loader in non-load mode.
2393 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2394
2395 return ClassLoader::LoadGenericInstantiationThrowing(pModule,
2396 mdToken,
2397 Instantiation(pInst,nTypeArgs),
2398 ClassLoader::DontLoadTypes);
2399
2400} // DacDbiInterfaceImpl::FindLoadedInstantiation
2401
2402//-----------------------------------------------------------------------------
2403// DacDbiInterfaceImpl::FindLoadedElementType
2404// Get the type handle for a primitive type
2405// Arguments:
2406// input: elementType - type of the primitive type
2407// Return Value: Type handle for the primitive type
2408//-----------------------------------------------------------------------------
2409// static
2410TypeHandle DacDbiInterfaceImpl::FindLoadedElementType(CorElementType elementType)
2411{
2412 // Lookup operations run the class loader in non-load mode.
2413 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2414
2415 MethodTable * pMethodTable = (&g_Mscorlib)->GetElementType(elementType);
2416
2417 return TypeHandle(pMethodTable);
2418} // DacDbiInterfaceImpl::FindLoadedElementType
2419
2420
2421//-----------------------------------------------------------------------------
2422// DacDbiInterfaceImpl::GetArrayTypeInfo
2423// Gets additional information to convert a type handle to an instance of CordbType if the type is E_T_ARRAY.
2424// Specifically, we get the rank and the type of the array elements
2425//
2426// Arguments:
2427// input: typeHandle - type handle for the array type
2428// pAppDomain - AppDomain into which the type is loaded
2429// output: pTypeInfo - information for the array rank and element type
2430//
2431//-----------------------------------------------------------------------------
2432void DacDbiInterfaceImpl::GetArrayTypeInfo(TypeHandle typeHandle,
2433 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2434 AppDomain * pAppDomain)
2435{
2436 _ASSERTE(typeHandle.IsArray());
2437 pTypeInfo->ArrayTypeData.arrayRank = typeHandle.AsArray()->GetRank();
2438 TypeHandleToBasicTypeInfo(typeHandle.AsArray()->GetArrayElementTypeHandle(),
2439 &(pTypeInfo->ArrayTypeData.arrayTypeArg),
2440 pAppDomain);
2441} // DacDbiInterfaceImpl::GetArrayTypeInfo
2442
2443//-----------------------------------------------------------------------------
2444// DacDbiInterfaceImpl::GetPtrTypeInfo
2445// Gets additional information to convert a type handle to an instance of CordbType if the type is
2446// E_T_PTR or E_T_BYREF. Specifically, we get the type for the referent of the address type
2447//
2448// Arguments:
2449// input: boxed - indicates what, if anything, is boxed (see code:AreValueTypesBoxed for
2450// more specific information)
2451// typeHandle - type handle for the address type
2452// pAppDomain - AppDomain into which the type is loaded
2453// output: pTypeInfo - information for the referent type
2454//
2455//-----------------------------------------------------------------------------
2456void DacDbiInterfaceImpl::GetPtrTypeInfo(AreValueTypesBoxed boxed,
2457 TypeHandle typeHandle,
2458 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2459 AppDomain * pAppDomain)
2460{
2461 if (boxed == AllBoxed)
2462 {
2463 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2464 }
2465 else
2466 {
2467 _ASSERTE(typeHandle.IsTypeDesc());
2468 TypeHandleToBasicTypeInfo(typeHandle.AsTypeDesc()->GetTypeParam(),
2469 &(pTypeInfo->UnaryTypeData.unaryTypeArg),
2470 pAppDomain);
2471 }
2472} // DacDbiInterfaceImpl::GetPtrTypeInfo
2473
2474//-----------------------------------------------------------------------------
2475// DacDbiInterfaceImpl::GetFnPtrTypeInfo
2476// Gets additional information to convert a type handle to an instance of CordbType if the type is
2477// E_T_FNPTR, specifically the typehandle for the referent.
2478//
2479// Arguments
2480// input: boxed - indicates what, if anything, is boxed (see code:AreValueTypesBoxed for
2481// more specific information)
2482// typeHandle - type handle for the address type
2483// pAppDomain - AppDomain into which the type is loaded
2484// output: pTypeInfo - information for the referent type
2485//
2486//-----------------------------------------------------------------------------
2487void DacDbiInterfaceImpl::GetFnPtrTypeInfo(AreValueTypesBoxed boxed,
2488 TypeHandle typeHandle,
2489 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2490 AppDomain * pAppDomain)
2491{
2492 if (boxed == AllBoxed)
2493 {
2494 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2495 }
2496 else
2497 {
2498 pTypeInfo->NaryTypeData.typeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2499 }
2500} // DacDbiInterfaceImpl::GetFnPtrTypeInfo
2501
2502
2503//-----------------------------------------------------------------------------
2504// DacDbiInterfaceImpl::GetClassTypeInfo
2505// Gets additional information to convert a type handle to an instance of CordbType if the type is
2506// E_T_CLASS or E_T_VALUETYPE
2507//
2508// Arguments
2509// input: typeHandle - type handle for the address type
2510// pAppDomain - AppDomain into which the type is loaded
2511// output: pTypeInfo - information for the referent type
2512//
2513//-----------------------------------------------------------------------------
2514void DacDbiInterfaceImpl::GetClassTypeInfo(TypeHandle typeHandle,
2515 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2516 AppDomain * pAppDomain)
2517{
2518 Module * pModule = typeHandle.GetModule();
2519
2520 if (typeHandle.HasInstantiation()) // the type handle represents a generic instantiation
2521 {
2522 pTypeInfo->ClassTypeData.typeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2523 }
2524 else // non-generic
2525 {
2526 pTypeInfo->ClassTypeData.typeHandle = VMPTR_TypeHandle::NullPtr();
2527 }
2528
2529 pTypeInfo->ClassTypeData.metadataToken = typeHandle.GetCl();
2530
2531 _ASSERTE(pModule);
2532 pTypeInfo->ClassTypeData.vmModule.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule));
2533 if (pAppDomain)
2534 {
2535 pTypeInfo->ClassTypeData.vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule->GetDomainFile(pAppDomain)));
2536 }
2537 else
2538 {
2539 pTypeInfo->ClassTypeData.vmDomainFile = VMPTR_DomainFile::NullPtr();
2540 }
2541} // DacDbiInterfaceImpl::GetClassTypeInfo
2542
2543//-----------------------------------------------------------------------------
2544// DacDbiInterfaceImpl::GetElementType
2545// Gets the correct CorElementType value from a type handle
2546//
2547// Arguments
2548// input: typeHandle - type handle for the address type
2549// Return Value: the CorElementType enum value for the type handle
2550//-----------------------------------------------------------------------------
2551CorElementType DacDbiInterfaceImpl::GetElementType (TypeHandle typeHandle)
2552{
2553 if (typeHandle.IsNull())
2554 {
2555 return ELEMENT_TYPE_VOID;
2556 }
2557 else if (typeHandle.GetMethodTable() == g_pObjectClass)
2558 {
2559 return ELEMENT_TYPE_OBJECT;
2560 }
2561 else if (typeHandle.GetMethodTable() == g_pStringClass)
2562 {
2563 return ELEMENT_TYPE_STRING;
2564 }
2565 else
2566 {
2567 // GetSignatureCorElementType returns E_T_CLASS for E_T_STRING... :-(
2568 return typeHandle.GetSignatureCorElementType();
2569 }
2570
2571} // DacDbiInterfaceImpl::GetElementType
2572
2573//-----------------------------------------------------------------------------
2574// DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo
2575// Gets additional information to convert a type handle to an instance of CordbType for the referent of an
2576// E_T_BYREF or E_T_PTR or for the element type of an E_T_ARRAY or E_T_SZARRAY
2577//
2578// Arguments:
2579// input: typeHandle - type handle for the address type
2580// pAppDomain - AppDomain into which the type is loaded
2581// output: pTypeInfo - information for the referent type
2582//
2583//-----------------------------------------------------------------------------
2584void DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo(TypeHandle typeHandle,
2585 DebuggerIPCE_BasicTypeData * pTypeInfo,
2586 AppDomain * pAppDomain)
2587{
2588 pTypeInfo->elementType = GetElementType(typeHandle);
2589
2590 switch (pTypeInfo->elementType)
2591 {
2592 case ELEMENT_TYPE_ARRAY:
2593 case ELEMENT_TYPE_SZARRAY:
2594 case ELEMENT_TYPE_FNPTR:
2595 case ELEMENT_TYPE_PTR:
2596 case ELEMENT_TYPE_BYREF:
2597 pTypeInfo->vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2598 pTypeInfo->metadataToken = mdTokenNil;
2599 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2600 break;
2601
2602 case ELEMENT_TYPE_CLASS:
2603 case ELEMENT_TYPE_VALUETYPE:
2604 {
2605 Module * pModule = typeHandle.GetModule();
2606
2607 if (typeHandle.HasInstantiation()) // only set if instantiated
2608 {
2609 pTypeInfo->vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2610 }
2611 else
2612 {
2613 pTypeInfo->vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2614 }
2615
2616 pTypeInfo->metadataToken = typeHandle.GetCl();
2617 _ASSERTE(pModule);
2618
2619 pTypeInfo->vmModule.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule));
2620 if (pAppDomain)
2621 {
2622 pTypeInfo->vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule->GetDomainFile(pAppDomain)));
2623 }
2624 else
2625 {
2626 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2627 }
2628 break;
2629 }
2630
2631 default:
2632 pTypeInfo->vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2633 pTypeInfo->metadataToken = mdTokenNil;
2634 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2635 break;
2636 }
2637 return;
2638} // DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo
2639
2640
2641void DacDbiInterfaceImpl::GetObjectExpandedTypeInfoFromID(AreValueTypesBoxed boxed,
2642 VMPTR_AppDomain vmAppDomain,
2643 COR_TYPEID id,
2644 DebuggerIPCE_ExpandedTypeData *pTypeInfo)
2645{
2646 DD_ENTER_MAY_THROW;
2647
2648 PTR_MethodTable pMT(TO_TADDR(id.token1));
2649
2650 if (pMT->IsArray())
2651 {
2652 // ArrayBase::GetTypeHandle() may return a NULL handle in corner case scenarios. This check prevents
2653 // us from an AV but doesn't actually fix the problem. See DevDiv 653441 for more info.
2654 TypeHandle arrayHandle = ArrayBase::GetTypeHandle(pMT);
2655 if (arrayHandle.IsNull())
2656 {
2657 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2658 }
2659
2660 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, arrayHandle, pTypeInfo);
2661 }
2662 else
2663 {
2664 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, TypeHandle::FromPtr(TO_TADDR(id.token1)), pTypeInfo);
2665 }
2666}
2667
2668void DacDbiInterfaceImpl::GetObjectExpandedTypeInfo(AreValueTypesBoxed boxed,
2669 VMPTR_AppDomain vmAppDomain,
2670 CORDB_ADDRESS addr,
2671 DebuggerIPCE_ExpandedTypeData *pTypeInfo)
2672{
2673 DD_ENTER_MAY_THROW;
2674
2675 PTR_Object obj(TO_TADDR(addr));
2676 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, obj->GetGCSafeTypeHandle(), pTypeInfo);
2677}
2678
2679// DacDbi API: use a type handle to get the information needed to create the corresponding RS CordbType instance
2680void DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed,
2681 VMPTR_AppDomain vmAppDomain,
2682 VMPTR_TypeHandle vmTypeHandle,
2683 DebuggerIPCE_ExpandedTypeData * pTypeInfo)
2684{
2685 DD_ENTER_MAY_THROW;
2686
2687
2688 TypeHandle typeHandle = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
2689 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, typeHandle, pTypeInfo);
2690}
2691
2692
2693void DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed,
2694 VMPTR_AppDomain vmAppDomain,
2695 TypeHandle typeHandle,
2696 DebuggerIPCE_ExpandedTypeData * pTypeInfo)
2697{
2698 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
2699 pTypeInfo->elementType = GetElementType(typeHandle);
2700
2701 switch (pTypeInfo->elementType)
2702 {
2703 case ELEMENT_TYPE_ARRAY:
2704 case ELEMENT_TYPE_SZARRAY:
2705 GetArrayTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2706 break;
2707
2708 case ELEMENT_TYPE_PTR:
2709 case ELEMENT_TYPE_BYREF:
2710 GetPtrTypeInfo(boxed, typeHandle, pTypeInfo, pAppDomain);
2711 break;
2712
2713 case ELEMENT_TYPE_VALUETYPE:
2714 if (boxed == OnlyPrimitivesUnboxed || boxed == AllBoxed)
2715 {
2716 pTypeInfo->elementType = ELEMENT_TYPE_CLASS;
2717 }
2718 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2719 break;
2720
2721 case ELEMENT_TYPE_CLASS:
2722 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2723 break;
2724
2725 case ELEMENT_TYPE_FNPTR:
2726 GetFnPtrTypeInfo(boxed, typeHandle, pTypeInfo, pAppDomain);
2727 break;
2728 default:
2729 if (boxed == AllBoxed)
2730 {
2731 pTypeInfo->elementType = ELEMENT_TYPE_CLASS;
2732 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2733 }
2734 // else the element type is sufficient
2735 break;
2736 }
2737 LOG((LF_CORDB, LL_INFO10000, "D::THTETI: converted left-side type handle to expanded right-side type info, pTypeInfo->ClassTypeData.typeHandle = 0x%08x.\n", pTypeInfo->ClassTypeData.typeHandle.GetRawPtr()));
2738 return;
2739} // DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfo
2740
2741// Get type handle for a TypeDef token, if one exists. For generics this returns the open type.
2742VMPTR_TypeHandle DacDbiInterfaceImpl::GetTypeHandle(VMPTR_Module vmModule,
2743 mdTypeDef metadataToken)
2744{
2745 DD_ENTER_MAY_THROW;
2746 Module* pModule = vmModule.GetDacPtr();
2747 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2748
2749 TypeHandle th = ClassLoader::LookupTypeDefOrRefInModule(pModule, metadataToken);
2750 if (th.IsNull())
2751 {
2752 LOG((LF_CORDB, LL_INFO10000, "D::GTH: class isn't loaded.\n"));
2753 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2754 }
2755
2756 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
2757 return vmTypeHandle;
2758}
2759
2760// DacDbi API: GetAndSendApproxTypeHandle finds the type handle for the layout of the instance fields of an
2761// instantiated type if it is available.
2762VMPTR_TypeHandle DacDbiInterfaceImpl::GetApproxTypeHandle(TypeInfoList * pTypeData)
2763{
2764 DD_ENTER_MAY_THROW;
2765
2766 LOG((LF_CORDB, LL_INFO10000, "D::GATH: getting info.\n"));
2767
2768
2769 TypeDataWalk walk(&((*pTypeData)[0]), pTypeData->Count());
2770 TypeHandle typeHandle = walk.ReadLoadedTypeHandle(TypeDataWalk::kGetCanonical);
2771 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2772
2773 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2774 if (!typeHandle.IsNull())
2775 {
2776 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2777 }
2778 else
2779 {
2780 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2781 }
2782
2783 LOG((LF_CORDB, LL_INFO10000,
2784 "D::GATH: sending result, result = 0x%0x8\n",
2785 typeHandle));
2786 return vmTypeHandle;
2787} // DacDbiInterfaceImpl::GetApproxTypeHandle
2788
2789// DacDbiInterface API: Get the exact type handle from type data
2790HRESULT DacDbiInterfaceImpl::GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData,
2791 ArgInfoList * pArgInfo,
2792 VMPTR_TypeHandle& vmTypeHandle)
2793{
2794 DD_ENTER_MAY_THROW;
2795
2796 LOG((LF_CORDB, LL_INFO10000, "D::GETH: getting info.\n"));
2797
2798 HRESULT hr = S_OK;
2799
2800 EX_TRY
2801 {
2802 vmTypeHandle = vmTypeHandle.NullPtr();
2803
2804 // convert the type information to a type handle
2805 TypeHandle typeHandle = ExpandedTypeInfoToTypeHandle(pTypeData, pArgInfo);
2806 _ASSERTE(!typeHandle.IsNull());
2807 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2808 }
2809 EX_CATCH_HRESULT(hr);
2810
2811 return hr;
2812} // DacDbiInterfaceImpl::GetExactTypeHandle
2813
2814// Retrieve the generic type params for a given MethodDesc. This function is specifically
2815// for stackwalking because it requires the generic type token on the stack.
2816void DacDbiInterfaceImpl::GetMethodDescParams(
2817 VMPTR_AppDomain vmAppDomain,
2818 VMPTR_MethodDesc vmMethodDesc,
2819 GENERICS_TYPE_TOKEN genericsToken,
2820 UINT32 * pcGenericClassTypeParams,
2821 TypeParamsList * pGenericTypeParams)
2822{
2823 DD_ENTER_MAY_THROW;
2824
2825 if (vmAppDomain.IsNull() || vmMethodDesc.IsNull())
2826 {
2827 ThrowHR(E_INVALIDARG);
2828 }
2829
2830 _ASSERTE((pcGenericClassTypeParams != NULL) && (pGenericTypeParams != NULL));
2831
2832 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
2833
2834 // Retrieve the number of type parameters for the class and
2835 // the number of type parameters for the method itself.
2836 // For example, the method Foo<T, U>::Bar<V>() has 2 class type parameters and 1 method type parameters.
2837 UINT32 cGenericClassTypeParams = pMD->GetNumGenericClassArgs();
2838 UINT32 cGenericMethodTypeParams = pMD->GetNumGenericMethodArgs();
2839 UINT32 cTotalGenericTypeParams = cGenericClassTypeParams + cGenericMethodTypeParams;
2840
2841 // Set the out parameter.
2842 *pcGenericClassTypeParams = cGenericClassTypeParams;
2843
2844 TypeHandle thSpecificClass;
2845 MethodDesc * pSpecificMethod;
2846
2847 // Try to retrieve a more specific MethodDesc and TypeHandle via the generics type token.
2848 // The generics token is not always guaranteed to be available.
2849 // For example, it may be unavailable in prologs and epilogs.
2850 // In dumps, not available can also mean a thrown exception for missing memory.
2851 BOOL fExact = FALSE;
2852 ALLOW_DATATARGET_MISSING_MEMORY(
2853 fExact = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
2854 pMD,
2855 PTR_VOID((TADDR)genericsToken),
2856 &thSpecificClass,
2857 &pSpecificMethod);
2858 );
2859 if (!fExact ||
2860 !thSpecificClass.GetMethodTable()->SanityCheck() ||
2861 !pSpecificMethod->GetMethodTable()->SanityCheck())
2862 {
2863 // Use the canonical MethodTable and MethodDesc if the exact generics token is not available.
2864 thSpecificClass = TypeHandle(pMD->GetMethodTable());
2865 pSpecificMethod = pMD;
2866 }
2867
2868 // Retrieve the array of class type parameters and the array of method type parameters.
2869 Instantiation classInst = pSpecificMethod->GetExactClassInstantiation(thSpecificClass);
2870 Instantiation methodInst = pSpecificMethod->GetMethodInstantiation();
2871
2872 _ASSERTE((classInst.IsEmpty()) == (cGenericClassTypeParams == 0));
2873 _ASSERTE((methodInst.IsEmpty()) == (cGenericMethodTypeParams == 0));
2874
2875 // allocate memory for the return array
2876 pGenericTypeParams->Alloc(cTotalGenericTypeParams);
2877
2878 for (UINT32 i = 0; i < cTotalGenericTypeParams; i++)
2879 {
2880 // Retrieve the current type parameter depending on the index.
2881 TypeHandle thCurrent;
2882 if (i < cGenericClassTypeParams)
2883 {
2884 thCurrent = classInst[i];
2885 }
2886 else
2887 {
2888 thCurrent = methodInst[i - cGenericClassTypeParams];
2889 }
2890
2891 // There is the possiblity that we'll get this far with a dump and not fail, but still
2892 // not be able to get full info for a particular param.
2893 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2894 {
2895 // Fill in the struct using the TypeHandle of the current type parameter if we can.
2896 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2897 vmTypeHandle.SetDacTargetPtr(thCurrent.AsTAddr());
2898 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
2899 vmAppDomain,
2900 vmTypeHandle,
2901 &((*pGenericTypeParams)[i]));
2902 }
2903 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2904 {
2905 // On failure for a particular type, default it back to System.__Canon.
2906 VMPTR_TypeHandle vmTHCanon = VMPTR_TypeHandle::NullPtr();
2907 TypeHandle thCanon = TypeHandle(g_pCanonMethodTableClass);
2908 vmTHCanon.SetDacTargetPtr(thCanon.AsTAddr());
2909 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
2910 vmAppDomain,
2911 vmTHCanon,
2912 &((*pGenericTypeParams)[i]));
2913 }
2914 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2915 }
2916}
2917
2918//-----------------------------------------------------------------------------
2919// DacDbiInterfaceImpl::GetClassOrValueTypeHandle
2920// get a typehandle for a class or valuetype from basic type data (metadata token
2921// and domain file).
2922// Arguments:
2923// input: pData - contains the metadata token and domain file
2924// Return value: the type handle for the corresponding type
2925//-----------------------------------------------------------------------------
2926TypeHandle DacDbiInterfaceImpl::GetClassOrValueTypeHandle(DebuggerIPCE_BasicTypeData * pData)
2927{
2928 TypeHandle typeHandle;
2929
2930 // if we already have a type handle, just return it
2931 if (!pData->vmTypeHandle.IsNull())
2932 {
2933 typeHandle = TypeHandle::FromPtr(pData->vmTypeHandle.GetDacPtr());
2934 }
2935 // otherwise, have the loader look it up using the metadata token and domain file
2936 else
2937 {
2938 DomainFile * pDomainFile = pData->vmDomainFile.GetDacPtr();
2939 Module * pModule = pDomainFile->GetModule();
2940
2941 typeHandle = ClassLoader::LookupTypeDefOrRefInModule(pModule, pData->metadataToken);
2942 if (typeHandle.IsNull())
2943 {
2944 LOG((LF_CORDB, LL_INFO10000, "D::BTITTH: class isn't loaded.\n"));
2945 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2946 }
2947
2948 _ASSERTE(typeHandle.GetNumGenericArgs() == 0);
2949 }
2950
2951 return typeHandle;
2952
2953} // DacDbiInterfaceImpl::GetClassOrValueTypeHandle
2954
2955//-----------------------------------------------------------------------------
2956// DacDbiInterfaceImpl::GetExactArrayTypeHandle
2957// get an exact type handle for an array type
2958// Arguments:
2959// input: pTopLevelTypeData - type information for a top-level array type
2960// pArgInfo - contains the following information:
2961// m_genericArgsCount - number of generic parameters for the element type--this should be 1
2962// m_pGenericArgs - pointer to the generic parameter for the element type--this is
2963// effectively a one-element list. These are the actual parameters
2964// Return Value: the exact type handle for the type
2965//-----------------------------------------------------------------------------
2966TypeHandle DacDbiInterfaceImpl::GetExactArrayTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
2967 ArgInfoList * pArgInfo)
2968{
2969 TypeHandle typeArg;
2970
2971 _ASSERTE(pArgInfo->Count() == 1);
2972
2973 // get the type handle for the element type
2974 typeArg = BasicTypeInfoToTypeHandle(&((*pArgInfo)[0]));
2975
2976 // get the exact type handle for the array type
2977 return FindLoadedArrayType(pTopLevelTypeData->elementType,
2978 typeArg,
2979 pTopLevelTypeData->ArrayTypeData.arrayRank);
2980
2981} // DacDbiInterfaceImpl::GetExactArrayTypeHandle
2982
2983//-----------------------------------------------------------------------------
2984// DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle
2985// get an exact type handle for a PTR or BYREF type
2986// Arguments:
2987// input: pTopLevelTypeData - type information for the PTR or BYREF type
2988// pArgInfo - contains the following information:
2989// m_genericArgsCount - number of generic parameters for the element type--this should be 1
2990// m_pGenericArgs - pointer to the generic parameter for the element type--this is
2991// effectively a one-element list. These are the actual parameters
2992// Return Value: the exact type handle for the type
2993//-----------------------------------------------------------------------------
2994TypeHandle DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
2995 ArgInfoList * pArgInfo)
2996{
2997 TypeHandle typeArg;
2998 _ASSERTE(pArgInfo->Count() == 1);
2999
3000 // get the type handle for the referent
3001 typeArg = BasicTypeInfoToTypeHandle(&((*pArgInfo)[0]));
3002
3003 // get the exact type handle for the PTR or BYREF type
3004 return FindLoadedPointerOrByrefType(pTopLevelTypeData->elementType, typeArg);
3005
3006} // DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle
3007
3008//-----------------------------------------------------------------------------
3009// DacDbiInterfaceImpl::GetExactClassTypeHandle
3010// get an exact type handle for a CLASS or VALUETYPE type
3011// Arguments:
3012// input: pTopLevelTypeData - type information for the CLASS or VALUETYPE type
3013// pArgInfo - contains the following information:
3014// m_genericArgsCount - number of generic parameters for the class
3015// m_pGenericArgs - list of generic parameters for the class--these
3016// are the actual parameters
3017// Return Value: the exact type handle for the type
3018//-----------------------------------------------------------------------------
3019TypeHandle DacDbiInterfaceImpl::GetExactClassTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
3020 ArgInfoList * pArgInfo)
3021{
3022 Module * pModule = pTopLevelTypeData->ClassTypeData.vmModule.GetDacPtr();
3023 int argCount = pArgInfo->Count();
3024
3025 TypeHandle typeConstructor =
3026 ClassLoader::LookupTypeDefOrRefInModule(pModule, pTopLevelTypeData->ClassTypeData.metadataToken);
3027
3028 // If we can't find the class, throw the appropriate HR. Note: if the class is not a value class and
3029 // the class is also not restored, then we must pretend that the class is still not loaded. We are gonna let
3030 // unrestored value classes slide, though, and special case access to the class's parent below.
3031 if (typeConstructor.IsNull())
3032 {
3033 LOG((LF_CORDB, LL_INFO10000, "D::ETITTH: class isn't loaded.\n"));
3034 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3035 }
3036
3037 // if there are no generic parameters, we already have the correct type handle
3038 if (argCount == 0)
3039 {
3040 return typeConstructor;
3041 }
3042
3043 // we have generic parameters--first validate we have a number consistent with the list
3044 // of parameters we received
3045 if ((unsigned int)argCount != typeConstructor.GetNumGenericArgs())
3046 {
3047 LOG((LF_CORDB, LL_INFO10000,
3048 "D::ETITTH: wrong number of type parameters, %d given, %d expected\n",
3049 argCount, typeConstructor.GetNumGenericArgs()));
3050 _ASSERTE((unsigned int)argCount == typeConstructor.GetNumGenericArgs());
3051 ThrowHR(E_FAIL);
3052 }
3053
3054 // now we allocate a list to store the type handles for each parameter
3055 S_UINT32 allocSize = S_UINT32(argCount) * S_UINT32(sizeof(TypeHandle));
3056 if (allocSize.IsOverflow())
3057 {
3058 ThrowHR(E_OUTOFMEMORY);
3059 }
3060
3061 NewHolder<TypeHandle> pInst(new TypeHandle[allocSize.Value()]);
3062
3063 // convert the type information for each parameter to its corresponding type handle
3064 // and store it in the list
3065 for (unsigned int i = 0; i < (unsigned int)argCount; i++)
3066 {
3067 pInst[i] = BasicTypeInfoToTypeHandle(&((*pArgInfo)[i]));
3068 }
3069
3070 // Finally, we find the type handle corresponding to this particular instantiation
3071 return FindLoadedInstantiation(typeConstructor.GetModule(),
3072 typeConstructor.GetCl(),
3073 argCount,
3074 pInst);
3075
3076} // DacDbiInterfaceImpl::GetExactClassTypeHandle
3077
3078//-----------------------------------------------------------------------------
3079// DacDbiInterfaceImpl::GetExactFnPtrTypeHandle
3080// get an exact type handle for a FNPTR type
3081// Arguments:
3082// input: pArgInfo - Contains the following information:
3083// m_genericArgsCount - number of generic parameters for the referent
3084// m_pGenericArgs - list of generic parameters for the referent--these
3085// are the actual parameters for the function signature
3086// Return Value: the exact type handle for the type
3087//-----------------------------------------------------------------------------
3088TypeHandle DacDbiInterfaceImpl::GetExactFnPtrTypeHandle(ArgInfoList * pArgInfo)
3089{
3090 // allocate a list to store the type handles for each parameter
3091 S_UINT32 allocSize = S_UINT32(pArgInfo->Count()) * S_UINT32(sizeof(TypeHandle));
3092 if( allocSize.IsOverflow() )
3093 {
3094 ThrowHR(E_OUTOFMEMORY);
3095 }
3096 NewHolder<TypeHandle> pInst(new TypeHandle[allocSize.Value()]);
3097
3098 // convert the type information for each parameter to its corresponding type handle
3099 // and store it in the list
3100 for (int i = 0; i < pArgInfo->Count(); i++)
3101 {
3102 pInst[i] = BasicTypeInfoToTypeHandle(&((*pArgInfo)[i]));
3103 }
3104
3105 // find the type handle corresponding to this particular FNPTR
3106 return FindLoadedFnptrType(pArgInfo->Count(), pInst);
3107} // DacDbiInterfaceImpl::GetExactFnPtrTypeHandle
3108
3109//-----------------------------------------------------------------------------
3110// DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle
3111// Convert basic type info for a type parameter that came from a top-level type to
3112// the corresponding type handle. If the type parameter is an array or pointer
3113// type, we simply extract the LS type handle from the VMPTR_TypeHandle that is
3114// part of the type information. If the type parameter is a class or value type,
3115// we use the metadata token and domain file in the type info to look up the
3116// appropriate type handle. If the type parameter is any other types, we get the
3117// type handle by having the loader look up the type handle for the element type.
3118// Arguments:
3119// input: pArgTypeData - basic type information for the type.
3120// Return Value: the type handle for the type.
3121//-----------------------------------------------------------------------------
3122TypeHandle DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle(DebuggerIPCE_BasicTypeData * pArgTypeData)
3123{
3124 LOG((LF_CORDB, LL_INFO10000,
3125 "D::BTITTH: expanding basic right-side type to left-side type, ELEMENT_TYPE: %d.\n",
3126 pArgTypeData->elementType));
3127 TypeHandle typeHandle = TypeHandle();
3128
3129 switch (pArgTypeData->elementType)
3130 {
3131 case ELEMENT_TYPE_ARRAY:
3132 case ELEMENT_TYPE_SZARRAY:
3133 case ELEMENT_TYPE_PTR:
3134 case ELEMENT_TYPE_BYREF:
3135 case ELEMENT_TYPE_FNPTR:
3136 _ASSERTE(!pArgTypeData->vmTypeHandle.IsNull());
3137 typeHandle = TypeHandle::FromPtr(pArgTypeData->vmTypeHandle.GetDacPtr());
3138 break;
3139
3140 case ELEMENT_TYPE_CLASS:
3141 case ELEMENT_TYPE_VALUETYPE:
3142 typeHandle = GetClassOrValueTypeHandle(pArgTypeData);
3143 break;
3144
3145 default:
3146 typeHandle = FindLoadedElementType(pArgTypeData->elementType);
3147 break;
3148 }
3149 if (typeHandle.IsNull())
3150 {
3151 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3152 }
3153 return typeHandle;
3154} // DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle
3155
3156
3157//-----------------------------------------------------------------------------
3158// DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle
3159// Convert type information for a top-level type to an exact type handle. This
3160// information includes information about the element type if the top-level type is
3161// an array type, the referent if the top-level type is a pointer type, or actual
3162// parameters if the top-level type is a generic class or value type.
3163// Arguments:
3164// input: pTopLevelTypeData - type information for the top-level type
3165// pArgInfo - contains the following information:
3166// m_genericArtsCount - number of parameters
3167// m_pGenericArgs - list of actual parameters
3168// Return Value: the exact type handle corresponding to the type represented by
3169// pTopLevelTypeData
3170//-----------------------------------------------------------------------------
3171TypeHandle DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
3172 ArgInfoList * pArgInfo)
3173{
3174 WRAPPER_NO_CONTRACT;
3175
3176 LOG((LF_CORDB, LL_INFO10000,
3177 "D::ETITTH: expanding right-side type to left-side type, ELEMENT_TYPE: %d.\n",
3178 pData->elementType));
3179
3180 TypeHandle typeHandle = TypeHandle();
3181 // depending on the top-level type, get the type handle incorporating information about any type arguments
3182 switch (pTopLevelTypeData->elementType)
3183 {
3184 case ELEMENT_TYPE_ARRAY:
3185 case ELEMENT_TYPE_SZARRAY:
3186 typeHandle = GetExactArrayTypeHandle(pTopLevelTypeData, pArgInfo);
3187 break;
3188
3189 case ELEMENT_TYPE_PTR:
3190 case ELEMENT_TYPE_BYREF:
3191 typeHandle = GetExactPtrOrByRefTypeHandle(pTopLevelTypeData, pArgInfo);
3192 break;
3193
3194 case ELEMENT_TYPE_CLASS:
3195 case ELEMENT_TYPE_VALUETYPE:
3196 typeHandle = GetExactClassTypeHandle(pTopLevelTypeData, pArgInfo);
3197 break;
3198 case ELEMENT_TYPE_FNPTR:
3199 typeHandle = GetExactFnPtrTypeHandle(pArgInfo);
3200 break;
3201 default:
3202 typeHandle = FindLoadedElementType(pTopLevelTypeData->elementType);
3203 break;
3204 } // end switch (pData->elementType)
3205
3206 if (typeHandle.IsNull())
3207 {
3208 // This may fail because there are cases when a type can be used (and so visible to the
3209 // debugger), but not yet loaded to the point of being available in the EETypeHashTable.
3210 // For example, generic value types (without explicit constructors) may not need their
3211 // exact instantiation type to be loaded in order to be used as a field of an object
3212 // created on the heap
3213 LOG((LF_CORDB, LL_INFO10000, "D::ETITTH: type isn't loaded.\n"));
3214 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3215 }
3216 return typeHandle;
3217} // DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle
3218
3219// ----------------------------------------------------------------------------
3220// DacDbi API: GetThreadStaticAddress
3221// Get the target field address of a thread local static.
3222//
3223// Notes:
3224// The address is constant and could be cached.
3225//
3226// This can commonly fail, in which case, it will return NULL.
3227// ----------------------------------------------------------------------------
3228CORDB_ADDRESS DacDbiInterfaceImpl::GetThreadStaticAddress(VMPTR_FieldDesc vmField,
3229 VMPTR_Thread vmRuntimeThread)
3230{
3231 DD_ENTER_MAY_THROW;
3232
3233 Thread * pRuntimeThread = vmRuntimeThread.GetDacPtr();
3234 PTR_FieldDesc pFieldDesc = vmField.GetDacPtr();
3235 TADDR fieldAddress = NULL;
3236
3237 _ASSERTE(pRuntimeThread != NULL);
3238
3239 // Find out whether the field is thread local and get its address.
3240 if (pFieldDesc->IsThreadStatic())
3241 {
3242 fieldAddress = pRuntimeThread->GetStaticFieldAddrNoCreate(pFieldDesc);
3243 }
3244 else
3245 {
3246 // In case we have more special cases added later, this will allow us to notice the need to
3247 // update this function.
3248 ThrowHR(E_NOTIMPL);
3249 }
3250 return fieldAddress;
3251
3252} // DacDbiInterfaceImpl::GetThreadStaticAddress
3253
3254 // Get the target field address of a collectible types static.
3255CORDB_ADDRESS DacDbiInterfaceImpl::GetCollectibleTypeStaticAddress(VMPTR_FieldDesc vmField,
3256 VMPTR_AppDomain vmAppDomain)
3257{
3258 DD_ENTER_MAY_THROW;
3259
3260 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3261 PTR_FieldDesc pFieldDesc = vmField.GetDacPtr();
3262 _ASSERTE(pAppDomain != NULL);
3263
3264 //
3265 // Verify this field is of the right type
3266 //
3267 if(!pFieldDesc->IsStatic() ||
3268 pFieldDesc->IsSpecialStatic())
3269 {
3270 _ASSERTE(!"BUG: Unsupported static field type for collectible types");
3271 }
3272
3273 //
3274 // Check that the data is available
3275 //
3276 /* TODO: Ideally we should be checking if the class is allocated first, however
3277 we don't appear to be doing this even for non-collectible statics and
3278 we have never seen an issue.
3279 */
3280
3281 //
3282 // Get the address
3283 //
3284 PTR_VOID base = pFieldDesc->GetBaseInDomain(pAppDomain);
3285 if (base == PTR_NULL)
3286 {
3287 return PTR_HOST_TO_TADDR(NULL);
3288 }
3289
3290 //
3291 // Store the result and return
3292 //
3293 PTR_VOID addr = pFieldDesc->GetStaticAddressHandle(base);
3294 return PTR_TO_TADDR(addr);
3295
3296} // DacDbiInterfaceImpl::GetCollectibleTypeStaticAddress
3297
3298// DacDbi API: GetTypeHandleParams
3299// - gets the necessary data for a type handle, i.e. its type parameters, e.g. "String" and "List<int>" from the type handle
3300// for "Dict<String,List<int>>", and sends it back to the right side.
3301// - pParams is allocated and initialized by this function
3302// - This should not fail except for OOM
3303void DacDbiInterfaceImpl::GetTypeHandleParams(VMPTR_AppDomain vmAppDomain,
3304 VMPTR_TypeHandle vmTypeHandle,
3305 TypeParamsList * pParams)
3306{
3307 DD_ENTER_MAY_THROW
3308
3309 TypeHandle typeHandle = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
3310 LOG((LF_CORDB, LL_INFO10000, "D::GTHP: getting type parameters for 0x%08x 0x%0x8.\n",
3311 vmAppDomain.GetDacPtr(), typeHandle.AsPtr()));
3312
3313
3314 // Find the class given its type handle.
3315 _ASSERTE(pParams->IsEmpty());
3316 pParams->Alloc(typeHandle.GetNumGenericArgs());
3317
3318 // collect type information for each type parameter
3319 for (int i = 0; i < pParams->Count(); ++i)
3320 {
3321 VMPTR_TypeHandle thInst = VMPTR_TypeHandle::NullPtr();
3322 thInst.SetDacTargetPtr(typeHandle.GetInstantiation()[i].AsTAddr());
3323
3324 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3325 vmAppDomain,
3326 thInst,
3327 &((*pParams)[i]));
3328 }
3329
3330 LOG((LF_CORDB, LL_INFO10000, "D::GTHP: sending result"));
3331} // DacDbiInterfaceImpl::GetTypeHandleParams
3332
3333//-----------------------------------------------------------------------------
3334// DacDbi API: GetSimpleType
3335// gets the metadata token and domain file corresponding to a simple type
3336//-----------------------------------------------------------------------------
3337void DacDbiInterfaceImpl::GetSimpleType(VMPTR_AppDomain vmAppDomain,
3338 CorElementType simpleType,
3339 mdTypeDef *pMetadataToken,
3340 VMPTR_Module *pVmModule,
3341 VMPTR_DomainFile *pVmDomainFile)
3342{
3343 DD_ENTER_MAY_THROW;
3344
3345 AppDomain *pAppDomain = vmAppDomain.GetDacPtr();
3346
3347 // if we fail to get either a valid type handle or module, we will want to send back
3348 // a NULL domain file too, so we'll to preinitialize this here.
3349 _ASSERTE(pVmDomainFile != NULL);
3350 *pVmDomainFile = VMPTR_DomainFile::NullPtr();
3351 // FindLoadedElementType will return NULL if the type hasn't been loaded yet.
3352 TypeHandle typeHandle = FindLoadedElementType(simpleType);
3353
3354 if (typeHandle.IsNull())
3355 {
3356 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3357 }
3358 else
3359 {
3360 _ASSERTE(pMetadataToken != NULL);
3361 *pMetadataToken = typeHandle.GetCl();
3362
3363 Module * pModule = typeHandle.GetModule();
3364 if (pModule == NULL)
3365 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
3366
3367 pVmModule->SetHostPtr(pModule);
3368
3369 if (pAppDomain)
3370 {
3371 pVmDomainFile->SetHostPtr(pModule->GetDomainFile(pAppDomain));
3372 if (pVmDomainFile->IsNull())
3373 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
3374 }
3375 }
3376
3377 LOG((LF_CORDB, LL_INFO10000, "D::STI: sending result.\n"));
3378} // DacDbiInterfaceImpl::GetSimpleType
3379
3380BOOL DacDbiInterfaceImpl::IsExceptionObject(VMPTR_Object vmObject)
3381{
3382 DD_ENTER_MAY_THROW;
3383
3384 Object* objPtr = vmObject.GetDacPtr();
3385 MethodTable* pMT = objPtr->GetMethodTable();
3386
3387 return IsExceptionObject(pMT);
3388}
3389
3390BOOL DacDbiInterfaceImpl::IsExceptionObject(MethodTable* pMT)
3391{
3392 PTR_MethodTable pExMT = g_pExceptionClass;
3393
3394 TADDR targetMT = dac_cast<TADDR>(pMT);
3395 TADDR exceptionMT = dac_cast<TADDR>(pExMT);
3396
3397 do
3398 {
3399 if (targetMT == exceptionMT)
3400 return TRUE;
3401
3402 pMT = pMT->GetParentMethodTable();
3403 targetMT = dac_cast<TADDR>(pMT);
3404 } while (pMT);
3405
3406 return FALSE;
3407}
3408
3409void DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList<DacExceptionCallStackData>& dacStackFrames)
3410{
3411 DD_ENTER_MAY_THROW;
3412
3413 PTR_Object objPtr = vmObject.GetDacPtr();
3414
3415#ifdef _DEBUG
3416 // ensure we have an Exception object
3417 MethodTable* pMT = objPtr->GetMethodTable();
3418 _ASSERTE(IsExceptionObject(pMT));
3419#endif
3420
3421 OBJECTREF objRef = ObjectToOBJECTREF(objPtr);
3422
3423 DebugStackTrace::GetStackFramesData stackFramesData;
3424
3425 stackFramesData.pDomain = NULL;
3426 stackFramesData.skip = 0;
3427 stackFramesData.NumFramesRequested = 0;
3428
3429 DebugStackTrace::GetStackFramesFromException(&objRef, &stackFramesData);
3430
3431 INT32 dacStackFramesLength = stackFramesData.cElements;
3432
3433 if (dacStackFramesLength > 0)
3434 {
3435 dacStackFrames.Alloc(dacStackFramesLength);
3436
3437 for (INT32 index = 0; index < dacStackFramesLength; ++index)
3438 {
3439 DebugStackTrace::DebugStackTraceElement const& currentElement = stackFramesData.pElements[index];
3440 DacExceptionCallStackData& currentFrame = dacStackFrames[index];
3441
3442 Module* pModule = currentElement.pFunc->GetModule();
3443 BaseDomain* pBaseDomain = currentElement.pFunc->GetAssembly()->GetDomain();
3444
3445 AppDomain* pDomain = NULL;
3446 DomainFile* pDomainFile = NULL;
3447
3448 pDomain = pBaseDomain->AsAppDomain();
3449
3450 _ASSERTE(pDomain != NULL);
3451
3452 pDomainFile = pModule->FindDomainFile(pDomain);
3453 _ASSERTE(pDomainFile != NULL);
3454
3455 currentFrame.vmAppDomain.SetHostPtr(pDomain);
3456 currentFrame.vmDomainFile.SetHostPtr(pDomainFile);
3457 currentFrame.ip = currentElement.ip;
3458 currentFrame.methodDef = currentElement.pFunc->GetMemberDef();
3459 currentFrame.isLastForeignExceptionFrame = currentElement.fIsLastFrameFromForeignStackTrace;
3460 }
3461 }
3462}
3463
3464#ifdef FEATURE_COMINTEROP
3465
3466PTR_RCW GetRcwFromVmptrObject(VMPTR_Object vmObject)
3467{
3468 PTR_RCW pRCW = NULL;
3469
3470 Object* objPtr = vmObject.GetDacPtr();
3471
3472 PTR_SyncBlock pSyncBlock = NULL;
3473 pSyncBlock = objPtr->PassiveGetSyncBlock();
3474 if (pSyncBlock == NULL)
3475 return pRCW;
3476
3477 PTR_InteropSyncBlockInfo pInfo = NULL;
3478 pInfo = pSyncBlock->GetInteropInfoNoCreate();
3479 if (pInfo == NULL)
3480 return pRCW;
3481
3482 pRCW = dac_cast<PTR_RCW>(pInfo->DacGetRawRCW());
3483
3484 return pRCW;
3485}
3486
3487#endif
3488
3489BOOL DacDbiInterfaceImpl::IsRcw(VMPTR_Object vmObject)
3490{
3491#ifdef FEATURE_COMINTEROP
3492 DD_ENTER_MAY_THROW;
3493 return GetRcwFromVmptrObject(vmObject) != NULL;
3494#else
3495 return FALSE;
3496#endif // FEATURE_COMINTEROP
3497
3498}
3499
3500void DacDbiInterfaceImpl::GetRcwCachedInterfaceTypes(
3501 VMPTR_Object vmObject,
3502 VMPTR_AppDomain vmAppDomain,
3503 BOOL bIInspectableOnly,
3504 DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pDacInterfaces)
3505{
3506#ifdef FEATURE_COMINTEROP
3507
3508 DD_ENTER_MAY_THROW;
3509
3510 Object* objPtr = vmObject.GetDacPtr();
3511
3512 InlineSArray<PTR_MethodTable, INTERFACE_ENTRY_CACHE_SIZE> rgMT;
3513
3514 PTR_RCW pRCW = GetRcwFromVmptrObject(vmObject);
3515 if (pRCW != NULL)
3516 {
3517 pRCW->GetCachedInterfaceTypes(bIInspectableOnly, &rgMT);
3518
3519 pDacInterfaces->Alloc(rgMT.GetCount());
3520
3521 for (COUNT_T i = 0; i < rgMT.GetCount(); ++i)
3522 {
3523 // There is the possiblity that we'll get this far with a dump and not fail, but still
3524 // not be able to get full info for a particular param.
3525 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3526 {
3527 // Fill in the struct using the current TypeHandle
3528 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3529 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(rgMT[i]));
3530 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3531 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3532 vmAppDomain,
3533 vmTypeHandle,
3534 &((*pDacInterfaces)[i]));
3535 }
3536 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3537 {
3538 // On failure for a particular type, default it to NULL.
3539 (*pDacInterfaces)[i].elementType = ELEMENT_TYPE_END;
3540 }
3541 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3542
3543 }
3544
3545 }
3546 else
3547#endif // FEATURE_COMINTEROP
3548 {
3549 pDacInterfaces->Alloc(0);
3550 }
3551}
3552
3553void DacDbiInterfaceImpl::GetRcwCachedInterfacePointers(
3554 VMPTR_Object vmObject,
3555 BOOL bIInspectableOnly,
3556 DacDbiArrayList<CORDB_ADDRESS> * pDacItfPtrs)
3557{
3558#ifdef FEATURE_COMINTEROP
3559
3560 DD_ENTER_MAY_THROW;
3561
3562 Object* objPtr = vmObject.GetDacPtr();
3563
3564 InlineSArray<TADDR, INTERFACE_ENTRY_CACHE_SIZE> rgUnks;
3565
3566 PTR_RCW pRCW = GetRcwFromVmptrObject(vmObject);
3567 if (pRCW != NULL)
3568 {
3569 pRCW->GetCachedInterfacePointers(bIInspectableOnly, &rgUnks);
3570
3571 pDacItfPtrs->Alloc(rgUnks.GetCount());
3572
3573 for (COUNT_T i = 0; i < rgUnks.GetCount(); ++i)
3574 {
3575 (*pDacItfPtrs)[i] = (CORDB_ADDRESS)(rgUnks[i]);
3576 }
3577
3578 }
3579 else
3580#endif // FEATURE_COMINTEROP
3581 {
3582 pDacItfPtrs->Alloc(0);
3583 }
3584}
3585
3586void DacDbiInterfaceImpl::GetCachedWinRTTypesForIIDs(
3587 VMPTR_AppDomain vmAppDomain,
3588 DacDbiArrayList<GUID> & iids,
3589 OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes)
3590{
3591#ifdef FEATURE_COMINTEROP
3592
3593 DD_ENTER_MAY_THROW;
3594
3595 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3596
3597 {
3598 pTypes->Alloc(iids.Count());
3599
3600 for (int i = 0; i < iids.Count(); ++i)
3601 {
3602 // There is the possiblity that we'll get this far with a dump and not fail, but still
3603 // not be able to get full info for a particular param.
3604 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3605 {
3606 PTR_MethodTable pMT = pAppDomain->LookupTypeByGuid(iids[i]);
3607
3608 // Fill in the struct using the current TypeHandle
3609 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3610 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(pMT));
3611 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3612 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3613 vmAppDomain,
3614 vmTypeHandle,
3615 &((*pTypes)[i]));
3616 }
3617 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3618 {
3619 // On failure for a particular type, default it to NULL.
3620 (*pTypes)[i].elementType = ELEMENT_TYPE_END;
3621 }
3622 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3623 }
3624 }
3625#else // FEATURE_COMINTEROP
3626 {
3627 pTypes->Alloc(0);
3628 }
3629#endif // FEATURE_COMINTEROP
3630}
3631
3632void DacDbiInterfaceImpl::GetCachedWinRTTypes(
3633 VMPTR_AppDomain vmAppDomain,
3634 OUT DacDbiArrayList<GUID> * pGuids,
3635 OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes)
3636{
3637#ifdef FEATURE_COMINTEROP
3638
3639 DD_ENTER_MAY_THROW;
3640
3641 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3642
3643 InlineSArray<PTR_MethodTable, 32> rgMT;
3644 InlineSArray<GUID, 32> rgGuid;
3645
3646 {
3647 pAppDomain->GetCachedWinRTTypes(&rgMT, &rgGuid, 0, NULL);
3648
3649 pTypes->Alloc(rgMT.GetCount());
3650 pGuids->Alloc(rgGuid.GetCount());
3651
3652 for (COUNT_T i = 0; i < rgMT.GetCount(); ++i)
3653 {
3654 // There is the possiblity that we'll get this far with a dump and not fail, but still
3655 // not be able to get full info for a particular param.
3656 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3657 {
3658 // Fill in the struct using the current TypeHandle
3659 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3660 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(rgMT[i]));
3661 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3662 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3663 vmAppDomain,
3664 vmTypeHandle,
3665 &((*pTypes)[i]));
3666 }
3667 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3668 {
3669 // On failure for a particular type, default it to NULL.
3670 (*pTypes)[i].elementType = ELEMENT_TYPE_END;
3671 }
3672 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3673 (*pGuids)[i] = rgGuid[i];
3674
3675 }
3676
3677 }
3678#else // FEATURE_COMINTEROP
3679 {
3680 pTypes->Alloc(0);
3681 }
3682#endif // FEATURE_COMINTEROP
3683}
3684
3685//-----------------------------------------------------------------------------
3686// DacDbiInterfaceImpl::FindField
3687// Finds information for a particular class field
3688// Arguments:
3689// input: thApprox - type handle for the type to which the field belongs
3690// fldToken - metadata token for the field
3691// Return Value: FieldDesc containing information for the field if found or NULL otherwise
3692//-----------------------------------------------------------------------------
3693PTR_FieldDesc DacDbiInterfaceImpl::FindField(TypeHandle thApprox, mdFieldDef fldToken)
3694{
3695 EncApproxFieldDescIterator fdIterator(thApprox.GetMethodTable(),
3696 ApproxFieldDescIterator::ALL_FIELDS,
3697 FALSE); // don't fixup EnC (we can't, we're stopped)
3698
3699 PTR_FieldDesc pCurrentFD;
3700
3701 while ((pCurrentFD = fdIterator.Next()) != NULL)
3702 {
3703 // We're looking for a specific fieldDesc, see if we got it.
3704 if (pCurrentFD->GetMemberDef() == fldToken)
3705 {
3706 return pCurrentFD;
3707 }
3708 }
3709
3710 // we never found it...
3711 return NULL;
3712} // DacDbiInterfaceImpl::FindField
3713
3714//-----------------------------------------------------------------------------
3715// DacDbiInterfaceImpl::GetEnCFieldDesc
3716// Get the FieldDesc corresponding to a particular EnC field token
3717// Arguments:
3718// input: pEnCFieldInfo
3719// Return Value: pointer to the FieldDesc that corresponds to the EnC field
3720// Note: this function may throw
3721//-----------------------------------------------------------------------------
3722FieldDesc * DacDbiInterfaceImpl::GetEnCFieldDesc(const EnCHangingFieldInfo * pEnCFieldInfo)
3723{
3724 FieldDesc * pFD = NULL;
3725
3726 DomainFile * pDomainFile = pEnCFieldInfo->GetObjectTypeData().vmDomainFile.GetDacPtr();
3727 Module * pModule = pDomainFile->GetModule();
3728
3729 // get the type handle for the object
3730 TypeHandle typeHandle = ClassLoader::LookupTypeDefOrRefInModule(pModule,
3731 pEnCFieldInfo->GetObjectTypeData().metadataToken);
3732 if (typeHandle == NULL)
3733 {
3734 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3735 }
3736 // and find the field desc
3737 pFD = FindField(typeHandle, pEnCFieldInfo->GetFieldToken());
3738 if (pFD == NULL)
3739 {
3740 // FieldDesc is not yet available, so can't get EnC field info
3741 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3742 }
3743 return pFD;
3744
3745} // DacDbiInterfaceImpl::GetEnCFieldDesc
3746
3747//-----------------------------------------------------------------------------
3748// DacDbiInterfaceImpl::GetPtrToEnCField
3749// Get the address of a field added with EnC.
3750// Arguments:
3751// input: pFD - field desc for the added field
3752// pEnCFieldInfo - information about the new field
3753// Return Value: The field address if the field is available (i.e., it has been accessed)
3754// or NULL otherwise
3755// Note: this function may throw
3756//-----------------------------------------------------------------------------
3757PTR_CBYTE DacDbiInterfaceImpl::GetPtrToEnCField(FieldDesc * pFD, const EnCHangingFieldInfo * pEnCFieldInfo)
3758{
3759#ifndef EnC_SUPPORTED
3760 _ASSERTE(!"Trying to get the address of an EnC field where EnC is not supported! ");
3761 return NULL;
3762#else
3763
3764 PTR_EditAndContinueModule pEnCModule;
3765 DomainFile * pDomainFile = pEnCFieldInfo->GetObjectTypeData().vmDomainFile.GetDacPtr();
3766 Module * pModule = pDomainFile->GetModule();
3767
3768 // make sure we actually have an EditAndContinueModule
3769 _ASSERTE(pModule->IsEditAndContinueCapable());
3770 pEnCModule = dac_cast<PTR_EditAndContinueModule>(pModule);
3771
3772 // we should also have an EnCFieldDesc
3773 _ASSERTE(pFD->IsEnCNew());
3774 EnCFieldDesc * pEnCFieldDesc;
3775 pEnCFieldDesc = dac_cast<PTR_EnCFieldDesc>(pFD);
3776
3777 // If it hasn't been fixed up yet, then we can't return the pointer.
3778 if (pEnCFieldDesc->NeedsFixup())
3779 {
3780 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3781 }
3782 // Get a pointer to the field
3783 PTR_CBYTE pORField = NULL;
3784
3785 PTR_Object pObject = pEnCFieldInfo->GetVmObject().GetDacPtr();
3786 pORField = pEnCModule->ResolveField(ObjectToOBJECTREF(pObject),
3787 pEnCFieldDesc);
3788
3789 // The field could be absent because the code hasn't accessed it yet. If so, we're not going to add it
3790 // since we can't allocate anyway.
3791 if (pORField == NULL)
3792 {
3793 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3794 }
3795 return pORField;
3796#endif // EnC_SUPPORTED
3797} // DacDbiInterfaceImpl::GetPtrToEnCField
3798
3799//-----------------------------------------------------------------------------
3800// DacDbiInterfaceImpl::InitFieldData
3801// Initialize information about a field added with EnC
3802// Arguments :
3803// input:
3804// pFD - provides information about whether the field is static,
3805// the metadata token, etc.
3806// pORField - provides the field address or offset
3807// pEnCFieldData - provides the offset to the fields of the object
3808// output: pFieldData - initialized in accordance with the input information
3809//-----------------------------------------------------------------------------
3810void DacDbiInterfaceImpl::InitFieldData(const FieldDesc * pFD,
3811 const PTR_CBYTE pORField,
3812 const EnCHangingFieldInfo * pEnCFieldData,
3813 FieldData * pFieldData)
3814{
3815
3816 pFieldData->ClearFields();
3817
3818 pFieldData->m_fFldIsStatic = (pFD->IsStatic() != 0);
3819 pFieldData->m_vmFieldDesc.SetHostPtr(pFD);
3820 pFieldData->m_fFldIsTLS = (pFD->IsThreadStatic() == TRUE);
3821 pFieldData->m_fldMetadataToken = pFD->GetMemberDef();
3822 pFieldData->m_fFldIsRVA = (pFD->IsRVA() == TRUE);
3823 pFieldData->m_fFldIsCollectibleStatic = FALSE;
3824 pFieldData->m_fFldStorageAvailable = true;
3825
3826 if (pFieldData->m_fFldIsStatic)
3827 {
3828 //EnC is only supported on regular static fields
3829 _ASSERTE(!pFieldData->m_fFldIsTLS);
3830 _ASSERTE(!pFieldData->m_fFldIsRVA);
3831
3832 // pORField contains the absolute address
3833 pFieldData->SetStaticAddress(PTR_TO_TADDR(pORField));
3834 }
3835 else
3836 {
3837 // fldInstanceOffset is computed to work correctly with GetFieldValue
3838 // which computes:
3839 // addr of pORField = object + pEnCFieldInfo->m_offsetToVars + offsetToFld
3840 pFieldData->SetInstanceOffset(PTR_TO_TADDR(pORField) -
3841 (PTR_TO_TADDR(pEnCFieldData->GetVmObject().GetDacPtr()) +
3842 pEnCFieldData->GetOffsetToVars()));
3843 }
3844} // DacDbiInterfaceImpl::InitFieldData
3845
3846
3847// ----------------------------------------------------------------------------
3848// DacDbi API: GetEnCHangingFieldInfo
3849// After a class has been loaded, if a field has been added via EnC we'll have to jump through
3850// some hoops to get at it (it hangs off the sync block or FieldDesc).
3851//
3852// GENERICS: TODO: this method will need to be modified if we ever support EnC on
3853// generic classes.
3854//-----------------------------------------------------------------------------
3855void DacDbiInterfaceImpl::GetEnCHangingFieldInfo(const EnCHangingFieldInfo * pEnCFieldInfo,
3856 FieldData * pFieldData,
3857 BOOL * pfStatic)
3858{
3859 DD_ENTER_MAY_THROW;
3860
3861 LOG((LF_CORDB, LL_INFO100000, "DDI::IEnCHFI: Obj:0x%x, objType"
3862 ":0x%x, offset:0x%x\n", pEnCFieldInfo->m_pObject, pEnCFieldInfo->m_objectTypeData.elementType,
3863 pEnCFieldInfo->m_offsetToVars));
3864
3865 FieldDesc * pFD = NULL;
3866 PTR_CBYTE pORField = NULL;
3867
3868 pFD = GetEnCFieldDesc(pEnCFieldInfo);
3869 _ASSERTE(pFD->IsEnCNew()); // We shouldn't be here if it wasn't added to an
3870 // already loaded class.
3871
3872#ifdef EnC_SUPPORTED
3873 pORField = GetPtrToEnCField(pFD, pEnCFieldInfo);
3874#else
3875 _ASSERTE(!"We shouldn't be here: EnC not supported");
3876#endif // EnC_SUPPORTED
3877
3878 InitFieldData(pFD, pORField, pEnCFieldInfo, pFieldData);
3879 *pfStatic = (pFD->IsStatic() != 0);
3880
3881} // DacDbiInterfaceImpl::GetEnCHangingFieldInfo
3882
3883//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3884
3885
3886void DacDbiInterfaceImpl::GetAssemblyFromDomainAssembly(VMPTR_DomainAssembly vmDomainAssembly, VMPTR_Assembly *vmAssembly)
3887{
3888 DD_ENTER_MAY_THROW;
3889
3890 _ASSERTE(vmAssembly != NULL);
3891
3892 DomainAssembly * pDomainAssembly = vmDomainAssembly.GetDacPtr();
3893 vmAssembly->SetHostPtr(pDomainAssembly->GetAssembly());
3894}
3895
3896// Determines whether the runtime security system has assigned full-trust to this assembly.
3897BOOL DacDbiInterfaceImpl::IsAssemblyFullyTrusted(VMPTR_DomainAssembly vmDomainAssembly)
3898{
3899 DD_ENTER_MAY_THROW;
3900
3901 return TRUE;
3902}
3903
3904// Get the full path and file name to the assembly's manifest module.
3905BOOL DacDbiInterfaceImpl::GetAssemblyPath(
3906 VMPTR_Assembly vmAssembly,
3907 IStringHolder * pStrFilename)
3908{
3909 DD_ENTER_MAY_THROW;
3910
3911 // Get the manifest module for this assembly
3912 Assembly * pAssembly = vmAssembly.GetDacPtr();
3913 Module * pManifestModule = pAssembly->GetManifestModule();
3914
3915 // Get the path for the manifest module.
3916 // since we no longer support Win9x, we assume all paths will be in unicode format already
3917 const WCHAR * szPath = pManifestModule->GetPath().DacGetRawUnicode();
3918 HRESULT hrStatus = pStrFilename->AssignCopy(szPath);
3919 IfFailThrow(hrStatus);
3920
3921 if(szPath == NULL || *szPath=='\0')
3922 {
3923 // The asembly has no (and will never have a) file name, but we didn't really fail
3924 return FALSE;
3925 }
3926
3927 return TRUE;
3928}
3929
3930// DAC/DBI API
3931// Get a resolved type def from a type ref. The type ref may come from a module other than the
3932// referencing module.
3933void DacDbiInterfaceImpl::ResolveTypeReference(const TypeRefData * pTypeRefInfo,
3934 TypeRefData * pTargetRefInfo)
3935{
3936 DD_ENTER_MAY_THROW;
3937 DomainFile * pDomainFile = pTypeRefInfo->vmDomainFile.GetDacPtr();
3938 Module * pReferencingModule = pDomainFile->GetCurrentModule();
3939 BOOL fSuccess = FALSE;
3940
3941 // Resolve the type ref
3942 // g_pEEInterface->FindLoadedClass is almost what we want, but it isn't guaranteed to work if
3943 // the typeRef was originally loaded from a different assembly. Also, we need to ensure that
3944 // we can resolve even unloaded types in fully loaded assemblies, so APIs such as
3945 // LoadTypeDefOrRefThrowing aren't acceptable.
3946
3947 Module * pTargetModule = NULL;
3948 mdTypeDef targetTypeDef = mdTokenNil;
3949
3950 // The loader won't need to trigger a GC or throw because we've told it not to load anything
3951 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
3952
3953 fSuccess = ClassLoader::ResolveTokenToTypeDefThrowing(pReferencingModule,
3954 pTypeRefInfo->typeToken,
3955 &pTargetModule,
3956 &targetTypeDef,
3957 Loader::SafeLookup //don't load, no locks/allocations
3958 );
3959 if (fSuccess)
3960 {
3961 _ASSERTE(pTargetModule != NULL);
3962 _ASSERTE( TypeFromToken(targetTypeDef) == mdtTypeDef );
3963
3964 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
3965
3966 pTargetRefInfo->vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pTargetModule->GetDomainFile(pAppDomain)));
3967 pTargetRefInfo->typeToken = targetTypeDef;
3968 }
3969 else
3970 {
3971 // failed - presumably because the target assembly isn't loaded
3972 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3973 }
3974} // DacDbiInterfaceImpl::ResolveTypeReference
3975
3976
3977// Get the full path and file name to the module (if any).
3978BOOL DacDbiInterfaceImpl::GetModulePath(VMPTR_Module vmModule,
3979 IStringHolder * pStrFilename)
3980{
3981 DD_ENTER_MAY_THROW;
3982
3983 Module * pModule = vmModule.GetDacPtr();
3984 PEFile * pFile = pModule->GetFile();
3985 if (pFile != NULL)
3986 {
3987 if( !pFile->GetPath().IsEmpty() )
3988 {
3989 // Module has an on-disk path
3990 const WCHAR * szPath = pFile->GetPath().DacGetRawUnicode();
3991 if (szPath == NULL)
3992 {
3993 szPath = pFile->GetModuleFileNameHint().DacGetRawUnicode();
3994 if (szPath == NULL)
3995 {
3996 goto NoFileName;
3997 }
3998 }
3999 IfFailThrow(pStrFilename->AssignCopy(szPath));
4000 return TRUE;
4001 }
4002 }
4003
4004NoFileName:
4005 // no filename
4006 IfFailThrow(pStrFilename->AssignCopy(W("")));
4007 return FALSE;
4008}
4009
4010// Get the full path and file name to the ngen image for the module (if any).
4011BOOL DacDbiInterfaceImpl::GetModuleNGenPath(VMPTR_Module vmModule,
4012 IStringHolder * pStrFilename)
4013{
4014 DD_ENTER_MAY_THROW;
4015#ifdef FEATURE_PREJIT
4016 Module * pModule = vmModule.GetDacPtr();
4017 PEFile * pFile = pModule->GetFile();
4018 if (pFile != NULL && pFile->HasNativeImage())
4019 {
4020 PEImage * pImage = pFile->GetPersistentNativeImage();
4021 if (pImage != NULL && pImage->IsFile())
4022 {
4023 // We have an on-disk ngen image. Return the path.
4024 // since we no longer support Win9x, we assume all paths will be in unicode format already
4025 const WCHAR * szPath = pImage->GetPath().DacGetRawUnicode();
4026 if (szPath == NULL)
4027 {
4028 szPath = pFile->GetModuleFileNameHint().DacGetRawUnicode();
4029 if (szPath == NULL)
4030 {
4031 goto NoFileName;
4032 }
4033 }
4034 IfFailThrow(pStrFilename->AssignCopy(szPath));
4035 return TRUE;
4036 }
4037 }
4038NoFileName:
4039#endif // FEATURE_PREJIT
4040
4041 // no ngen filename
4042 IfFailThrow(pStrFilename->AssignCopy(W("")));
4043 return FALSE;
4044}
4045
4046// Implementation of IDacDbiInterface::GetModuleSimpleName
4047void DacDbiInterfaceImpl::GetModuleSimpleName(VMPTR_Module vmModule, IStringHolder * pStrFilename)
4048{
4049 DD_ENTER_MAY_THROW;
4050
4051 _ASSERTE(pStrFilename != NULL);
4052
4053 Module * pModule = vmModule.GetDacPtr();
4054 LPCUTF8 szNameUtf8 = pModule->GetSimpleName();
4055
4056 SString convert(SString::Utf8, szNameUtf8);
4057 IfFailThrow(pStrFilename->AssignCopy(convert.GetUnicode()));
4058}
4059
4060// Helper to intialize a TargetBuffer from a MemoryRange
4061//
4062// Arguments:
4063// memoryRange - memory range.
4064// pTargetBuffer - required out parameter to be initialized to value of memory range.
4065//
4066// Notes:
4067// MemoryRange and TargetBuffer both conceptually describe a single contiguous buffer of memory in the
4068// target. MemoryRange is a VM structure, which can't bleed across the DacDbi boundary. TargetBuffer is
4069// a DacDbi structure, which can cross the DacDbi boundary.
4070void InitTargetBufferFromMemoryRange(const MemoryRange memoryRange, TargetBuffer * pTargetBuffer)
4071{
4072 SUPPORTS_DAC;
4073
4074 _ASSERTE(pTargetBuffer != NULL);
4075 PTR_CVOID p = memoryRange.StartAddress();
4076 CORDB_ADDRESS addr = PTR_TO_CORDB_ADDRESS(PTR_TO_TADDR(p));
4077
4078 _ASSERTE(memoryRange.Size() <= 0xffffffff);
4079 pTargetBuffer->Init(addr, (ULONG)memoryRange.Size());
4080}
4081
4082// Helper to intialize a TargetBuffer (host representation of target) from an SBuffer (target)
4083//
4084// Arguments:
4085// pBuffer - target pointer to a SBuffer structure. If pBuffer is NULL, then target buffer will be empty.
4086// pTargetBuffer - required out pointer to hold buffer description.
4087//
4088// Notes:
4089// PTR_SBuffer and TargetBuffer are both semantically equivalent structures. They both are a pointer and length
4090// describing a buffer in the target address space. (SBufer also has ownership semantics, but for DAC's
4091// read-only nature, that doesn't matter).
4092// Neither of these will actually copy the target buffer into the host without explicit action.
4093// The important difference is that TargetBuffer is a host datastructure and so easier to manipulate.
4094//
4095void InitTargetBufferFromTargetSBuffer(PTR_SBuffer pBuffer, TargetBuffer * pTargetBuffer)
4096{
4097 SUPPORTS_DAC;
4098
4099 _ASSERTE(pTargetBuffer != NULL);
4100
4101 SBuffer * pBufferHost = pBuffer;
4102 if (pBufferHost == NULL)
4103 {
4104 pTargetBuffer->Clear();
4105 return;
4106 }
4107
4108 MemoryRange m = pBufferHost->DacGetRawBuffer();
4109 InitTargetBufferFromMemoryRange(m, pTargetBuffer);
4110}
4111
4112
4113// Implementation of IDacDbiInterface::GetMetadata
4114void DacDbiInterfaceImpl::GetMetadata(VMPTR_Module vmModule, TargetBuffer * pTargetBuffer)
4115{
4116 DD_ENTER_MAY_THROW;
4117
4118 pTargetBuffer->Clear();
4119
4120 Module * pModule = vmModule.GetDacPtr();
4121
4122 // Target should only be asking about modules that are visible to debugger.
4123 _ASSERTE(pModule->IsVisibleToDebugger());
4124
4125 // For dynamic modules, metadata is stored as an eagerly-serialized buffer hanging off the Reflection Module.
4126 if (pModule->IsReflection())
4127 {
4128 // Here is the fetch.
4129 ReflectionModule * pReflectionModule = pModule->GetReflectionModule();
4130 InitTargetBufferFromTargetSBuffer(pReflectionModule->GetDynamicMetadataBuffer(), pTargetBuffer);
4131 }
4132 else
4133 {
4134 PEFile * pFile = pModule->GetFile();
4135
4136 // For non-dynamic modules, metadata is in the pe-image.
4137 COUNT_T size;
4138 CORDB_ADDRESS address = PTR_TO_CORDB_ADDRESS(dac_cast<TADDR>(pFile->GetLoadedMetadata(&size)));
4139
4140 pTargetBuffer->Init(address, (ULONG) size);
4141 }
4142
4143 if (pTargetBuffer->IsEmpty())
4144 {
4145 // We never expect this to happen in a well-behaved scenario. But just in case.
4146 ThrowHR(CORDBG_E_MISSING_METADATA);
4147 }
4148
4149}
4150
4151// Implementation of IDacDbiInterface::GetSymbolsBuffer
4152void DacDbiInterfaceImpl::GetSymbolsBuffer(VMPTR_Module vmModule, TargetBuffer * pTargetBuffer, SymbolFormat * pSymbolFormat)
4153{
4154 DD_ENTER_MAY_THROW;
4155
4156 pTargetBuffer->Clear();
4157 *pSymbolFormat = kSymbolFormatNone;
4158
4159 Module * pModule = vmModule.GetDacPtr();
4160
4161 // Target should only be asking about modules that are visible to debugger.
4162 _ASSERTE(pModule->IsVisibleToDebugger());
4163
4164 PTR_CGrowableStream pStream = pModule->GetInMemorySymbolStream();
4165 if (pStream == NULL)
4166 {
4167 // Common case is to not have PDBs in-memory.
4168 return;
4169 }
4170
4171 const MemoryRange m = pStream->GetRawBuffer();
4172 if (m.Size() == 0)
4173 {
4174 // We may be prepared to store symbols (in some particular format) but none are there yet.
4175 // We treat this the same as not having any symbols above.
4176 return;
4177 }
4178 InitTargetBufferFromMemoryRange(m, pTargetBuffer);
4179
4180 // Set the symbol format appropriately
4181 ESymbolFormat symFormat = pModule->GetInMemorySymbolStreamFormat();
4182 switch (symFormat)
4183 {
4184 case eSymbolFormatPDB:
4185 *pSymbolFormat = kSymbolFormatPDB;
4186 break;
4187
4188 case eSymbolFormatILDB:
4189 *pSymbolFormat = kSymbolFormatILDB;
4190 break;
4191
4192 default:
4193 CONSISTENCY_CHECK_MSGF(false, "Unexpected symbol format");
4194 pTargetBuffer->Clear();
4195 ThrowHR(E_UNEXPECTED);
4196 }
4197}
4198
4199
4200
4201void DacDbiInterfaceImpl::GetModuleForDomainFile(VMPTR_DomainFile vmDomainFile, OUT VMPTR_Module * pModule)
4202{
4203 DD_ENTER_MAY_THROW;
4204
4205 _ASSERTE(pModule != NULL);
4206
4207 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
4208 pModule->SetHostPtr(pDomainFile->GetModule());
4209}
4210
4211
4212// Implement IDacDbiInterface::GetDomainFileData
4213void DacDbiInterfaceImpl::GetDomainFileData(VMPTR_DomainFile vmDomainFile, DomainFileInfo * pData)
4214{
4215 DD_ENTER_MAY_THROW;
4216
4217 _ASSERTE(pData != NULL);
4218
4219 ZeroMemory(pData, sizeof(*pData));
4220
4221 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
4222 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
4223
4224 // @dbgtodo - is this efficient DAC usage (perhaps a dac-cop rule)? Are we round-tripping the pointer?
4225 // Should we have a GetDomainAssembly() that returns a PTR_DomainAssembly?
4226 pData->vmDomainAssembly.SetHostPtr(pDomainFile->GetDomainAssembly());
4227 pData->vmAppDomain.SetHostPtr(pAppDomain);
4228}
4229
4230// Implement IDacDbiInterface::GetModuleData
4231void DacDbiInterfaceImpl::GetModuleData(VMPTR_Module vmModule, ModuleInfo * pData)
4232{
4233 DD_ENTER_MAY_THROW;
4234
4235 _ASSERTE(pData != NULL);
4236
4237 ZeroMemory(pData, sizeof(*pData));
4238
4239 Module * pModule = vmModule.GetDacPtr();
4240 PEFile * pFile = pModule->GetFile();
4241
4242 pData->vmPEFile.SetHostPtr(pFile);
4243 pData->vmAssembly.SetHostPtr(pModule->GetAssembly());
4244
4245 // Is it dynamic?
4246 BOOL fIsDynamic = pModule->IsReflection();
4247 pData->fIsDynamic = fIsDynamic;
4248
4249 // Get PE BaseAddress and Size
4250 // For dynamic modules, these are 0. Else,
4251 pData->pPEBaseAddress = NULL;
4252 pData->nPESize = 0;
4253
4254 if (!fIsDynamic)
4255 {
4256 COUNT_T size = 0;
4257 pData->pPEBaseAddress = PTR_TO_TADDR(pFile->GetDebuggerContents(&size));
4258 pData->nPESize = (ULONG) size;
4259 }
4260
4261 // In-memory is determined by whether the module has a filename.
4262 pData->fInMemory = FALSE;
4263 if (pFile != NULL)
4264 {
4265 pData->fInMemory = pFile->GetPath().IsEmpty();
4266 }
4267}
4268
4269
4270// Enumerate all AppDomains in the process.
4271void DacDbiInterfaceImpl::EnumerateAppDomains(
4272 FP_APPDOMAIN_ENUMERATION_CALLBACK fpCallback,
4273 void * pUserData)
4274{
4275 DD_ENTER_MAY_THROW;
4276
4277 _ASSERTE(fpCallback != NULL);
4278
4279 // Only include active appdomains in the enumeration.
4280 // This includes appdomains sent before the AD load event,
4281 // and does not include appdomains that are in shutdown after the AD exit event.
4282 const BOOL bOnlyActive = TRUE;
4283 AppDomainIterator iterator(bOnlyActive);
4284
4285 while(iterator.Next())
4286 {
4287 // It's critical that we don't yield appdomains after the unload event has been sent.
4288 // See code:IDacDbiInterface#Enumeration for details.
4289 AppDomain * pAppDomain = iterator.GetDomain();
4290
4291 VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
4292 vmAppDomain.SetHostPtr(pAppDomain);
4293
4294 fpCallback(vmAppDomain, pUserData);
4295 }
4296}
4297
4298// Enumerate all Assemblies in an appdomain.
4299void DacDbiInterfaceImpl::EnumerateAssembliesInAppDomain(
4300 VMPTR_AppDomain vmAppDomain,
4301 FP_ASSEMBLY_ENUMERATION_CALLBACK fpCallback,
4302 void * pUserData
4303)
4304{
4305 DD_ENTER_MAY_THROW;
4306
4307 _ASSERTE(fpCallback != NULL);
4308
4309 // Iterate through all Assemblies (including shared) in the appdomain.
4310 AppDomain::AssemblyIterator iterator;
4311
4312 // If the containing appdomain is unloading, then don't enumerate any assemblies
4313 // in the domain. This is to enforce rules at code:IDacDbiInterface#Enumeration.
4314 // See comment in code:DacDbiInterfaceImpl::EnumerateModulesInAssembly code for details.
4315 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
4316
4317 // Pass the magical flags to the loader enumerator to get all Execution-only assemblies.
4318 iterator = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution));
4319 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4320
4321 while (iterator.Next(pDomainAssembly.This()))
4322 {
4323 if (!pDomainAssembly->IsVisibleToDebugger())
4324 {
4325 continue;
4326 }
4327
4328 VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr();
4329 vmDomainAssembly.SetHostPtr(pDomainAssembly);
4330
4331 fpCallback(vmDomainAssembly, pUserData);
4332 }
4333}
4334
4335// Implementation of IDacDbiInterface::EnumerateModulesInAssembly,
4336// Enumerate all the modules (non-resource) in an assembly.
4337void DacDbiInterfaceImpl::EnumerateModulesInAssembly(
4338 VMPTR_DomainAssembly vmAssembly,
4339 FP_MODULE_ENUMERATION_CALLBACK fpCallback,
4340 void * pUserData)
4341{
4342 DD_ENTER_MAY_THROW;
4343
4344 _ASSERTE(fpCallback != NULL);
4345
4346 DomainAssembly * pDomainAssembly = vmAssembly.GetDacPtr();
4347
4348 // If the domain is not yet fully-loaded, don't advertise it yet.
4349 // It's not ready to be inspected.
4350 DomainModuleIterator iterator = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
4351
4352 while (iterator.Next())
4353 {
4354 DomainFile * pDomainFile = iterator.GetDomainFile();
4355
4356 // Debugger isn't notified of Resource / Inspection-only modules.
4357 if (!pDomainFile->GetModule()->IsVisibleToDebugger())
4358 {
4359 continue;
4360 }
4361
4362 _ASSERTE(pDomainFile->IsLoaded());
4363
4364 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
4365 vmDomainFile.SetHostPtr(pDomainFile);
4366
4367 fpCallback(vmDomainFile, pUserData);
4368 }
4369}
4370
4371// Implementation of IDacDbiInterface::ResolveAssembly
4372// Returns NULL if not found.
4373VMPTR_DomainAssembly DacDbiInterfaceImpl::ResolveAssembly(
4374 VMPTR_DomainFile vmScope,
4375 mdToken tkAssemblyRef)
4376{
4377 DD_ENTER_MAY_THROW;
4378
4379
4380 DomainFile * pDomainFile = vmScope.GetDacPtr();
4381 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
4382 Module * pModule = pDomainFile->GetCurrentModule();
4383
4384 VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr();
4385
4386 Assembly * pAssembly = pModule->LookupAssemblyRef(tkAssemblyRef);
4387 if (pAssembly != NULL)
4388 {
4389 DomainAssembly * pDomainAssembly = pAssembly->FindDomainAssembly(pAppDomain);
4390 vmDomainAssembly.SetHostPtr(pDomainAssembly);
4391 }
4392 return vmDomainAssembly;
4393}
4394
4395// When stopped at an event, request a synchronization.
4396// See DacDbiInterface.h for full comments
4397void DacDbiInterfaceImpl::RequestSyncAtEvent()
4398{
4399 DD_ENTER_MAY_THROW;
4400
4401 // To request a sync, we just need to set g_pDebugger->m_RSRequestedSync high.
4402 if (g_pDebugger != NULL)
4403 {
4404 TADDR addr = PTR_HOST_MEMBER_TADDR(Debugger, g_pDebugger, m_RSRequestedSync);
4405
4406 BOOL fTrue = TRUE;
4407 SafeWriteStructOrThrow<BOOL>(addr, &fTrue);
4408
4409 }
4410}
4411
4412HRESULT DacDbiInterfaceImpl::SetSendExceptionsOutsideOfJMC(BOOL sendExceptionsOutsideOfJMC)
4413{
4414 DD_ENTER_MAY_THROW
4415
4416 HRESULT hr = S_OK;
4417 EX_TRY
4418 {
4419 if (g_pDebugger != NULL)
4420 {
4421 TADDR addr = PTR_HOST_MEMBER_TADDR(Debugger, g_pDebugger, m_sendExceptionsOutsideOfJMC);
4422 SafeWriteStructOrThrow<BOOL>(addr, &sendExceptionsOutsideOfJMC);
4423 }
4424 }
4425 EX_CATCH_HRESULT(hr);
4426 return hr;
4427}
4428
4429// Notify the debuggee that a debugger attach is pending.
4430// See DacDbiInterface.h for full comments
4431void DacDbiInterfaceImpl::MarkDebuggerAttachPending()
4432{
4433 DD_ENTER_MAY_THROW;
4434
4435 if (g_pDebugger != NULL)
4436 {
4437 DWORD flags = g_CORDebuggerControlFlags;
4438 flags |= DBCF_PENDING_ATTACH;
4439
4440 // Uses special DAC writing. PTR_TO_TADDR doesn't fetch for globals.
4441 // @dbgtodo dac support - the exact mechanism of writing to the target needs to be flushed out,
4442 // especially as it relates to DAC cop and enforcing undac-ized writes.
4443 g_CORDebuggerControlFlags = flags;
4444 }
4445 else
4446 {
4447 // Caller should have guaranteed that the LS is loaded.
4448 // If we're detaching, then don't throw because we don't care.
4449 ThrowHR(CORDBG_E_NOTREADY);
4450 }
4451}
4452
4453
4454// Notify the debuggee that a debugger is attached.
4455// See DacDbiInterface.h for full comments
4456void DacDbiInterfaceImpl::MarkDebuggerAttached(BOOL fAttached)
4457{
4458 DD_ENTER_MAY_THROW;
4459
4460 if (g_pDebugger != NULL)
4461 {
4462 // To be attached, we need to set the following
4463 // g_CORDebuggerControlFlags |= DBCF_ATTACHED;
4464 // To detach (if !fAttached), we need to do the opposite.
4465
4466 DWORD flags = g_CORDebuggerControlFlags;
4467 if (fAttached)
4468 {
4469 flags |= DBCF_ATTACHED;
4470 }
4471 else
4472 {
4473 flags &= ~ (DBCF_ATTACHED | DBCF_PENDING_ATTACH);
4474 }
4475
4476 // Uses special DAC writing. PTR_TO_TADDR doesn't fetch for globals.
4477 // @dbgtodo dac support - the exact mechanism of writing to the target needs to be flushed out,
4478 // especially as it relates to DAC cop and enforcing undac-ized writes.
4479 g_CORDebuggerControlFlags = flags;
4480 }
4481 else if (fAttached)
4482 {
4483 // Caller should have guaranteed that the LS is loaded.
4484 // If we're detaching, then don't throw because we don't care.
4485 ThrowHR(CORDBG_E_NOTREADY);
4486 }
4487
4488}
4489
4490
4491
4492// Enumerate all threads in the process.
4493void DacDbiInterfaceImpl::EnumerateThreads(FP_THREAD_ENUMERATION_CALLBACK fpCallback, void * pUserData)
4494{
4495 DD_ENTER_MAY_THROW;
4496
4497 if (ThreadStore::s_pThreadStore == NULL)
4498 {
4499 return;
4500 }
4501
4502 Thread *pThread = ThreadStore::GetThreadList(NULL);
4503
4504 while (pThread != NULL)
4505 {
4506
4507 // Don't want to publish threads via enumeration before they're ready to be inspected.
4508 // Use the same window that we used in whidbey.
4509 Thread::ThreadState threadState = pThread->GetSnapshotState();
4510 if (!((IsThreadMarkedDeadWorker(pThread)) || (threadState & Thread::TS_Unstarted)))
4511 {
4512 VMPTR_Thread vmThread = VMPTR_Thread::NullPtr();
4513 vmThread.SetHostPtr(pThread);
4514 fpCallback(vmThread, pUserData);
4515 }
4516
4517 pThread = ThreadStore::GetThreadList(pThread);
4518 }
4519}
4520
4521// public implementation of IsThreadMarkedDead
4522bool DacDbiInterfaceImpl::IsThreadMarkedDead(VMPTR_Thread vmThread)
4523{
4524 DD_ENTER_MAY_THROW;
4525 Thread * pThread = vmThread.GetDacPtr();
4526 return IsThreadMarkedDeadWorker(pThread);
4527}
4528
4529// Private worker for IsThreadMarkedDead
4530//
4531// Arguments:
4532// pThread - valid thread to check if dead
4533//
4534// Returns:
4535// true iff thread is marked as dead.
4536//
4537// Notes:
4538// This is an internal method that skips public validation.
4539// See code:IDacDbiInterface::#IsThreadMarkedDead for purpose.
4540bool DacDbiInterfaceImpl::IsThreadMarkedDeadWorker(Thread * pThread)
4541{
4542 _ASSERTE(pThread != NULL);
4543
4544 Thread::ThreadState threadState = pThread->GetSnapshotState();
4545
4546 bool fIsDead = (threadState & Thread::TS_Dead) != 0;
4547
4548 return fIsDead;
4549}
4550
4551
4552// Return the handle of the specified thread.
4553HANDLE DacDbiInterfaceImpl::GetThreadHandle(VMPTR_Thread vmThread)
4554{
4555 DD_ENTER_MAY_THROW;
4556
4557 Thread * pThread = vmThread.GetDacPtr();
4558 return pThread->GetThreadHandle();
4559}
4560
4561// Return the object handle for the managed Thread object corresponding to the specified thread.
4562VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetThreadObject(VMPTR_Thread vmThread)
4563{
4564 DD_ENTER_MAY_THROW;
4565
4566 Thread * pThread = vmThread.GetDacPtr();
4567 Thread::ThreadState threadState = pThread->GetSnapshotState();
4568
4569 if ( (threadState & Thread::TS_Dead) ||
4570 (threadState & Thread::TS_Unstarted) ||
4571 (threadState & Thread::TS_Detached) ||
4572 g_fProcessDetach )
4573 {
4574 ThrowHR(CORDBG_E_BAD_THREAD_STATE);
4575 }
4576 else
4577 {
4578 VMPTR_OBJECTHANDLE vmObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
4579 vmObjHandle.SetDacTargetPtr(pThread->GetExposedObjectHandleForDebugger());
4580 return vmObjHandle;
4581 }
4582}
4583
4584// Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
4585// according to the CorDebugThreadState.
4586void DacDbiInterfaceImpl::SetDebugState(VMPTR_Thread vmThread,
4587 CorDebugThreadState debugState)
4588{
4589 DD_ENTER_MAY_THROW;
4590
4591 Thread * pThread = vmThread.GetDacPtr();
4592
4593 // update the field on the host copy
4594 if (debugState == THREAD_SUSPEND)
4595 {
4596 pThread->SetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
4597 }
4598 else if (debugState == THREAD_RUN)
4599 {
4600 pThread->ResetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
4601 }
4602 else
4603 {
4604 ThrowHR(E_INVALIDARG);
4605 }
4606
4607 // update the field on the target copy
4608 TADDR taThreadState = PTR_HOST_MEMBER_TADDR(Thread, pThread, m_StateNC);
4609 SafeWriteStructOrThrow<Thread::ThreadStateNoConcurrency>(taThreadState, &(pThread->m_StateNC));
4610}
4611
4612// Gets the debugger unhandled exception threadstate flag
4613BOOL DacDbiInterfaceImpl::HasUnhandledException(VMPTR_Thread vmThread)
4614{
4615 DD_ENTER_MAY_THROW;
4616
4617 Thread * pThread = vmThread.GetDacPtr();
4618
4619 // some managed exceptions don't have any underlying
4620 // native exception processing going on. They just consist
4621 // of a managed throwable that we have stashed away followed
4622 // by a debugger notification and some form of failfast.
4623 // Everything that comes through EEFatalError is in this category
4624 if(pThread->IsLastThrownObjectUnhandled())
4625 {
4626 return TRUE;
4627 }
4628
4629 // most managed exceptions are just a throwable bound to a
4630 // native exception. In that case this handle will be non-null
4631 OBJECTHANDLE ohException = pThread->GetThrowableAsHandle();
4632 if (ohException != NULL)
4633 {
4634 // during the UEF we set the unhandled bit, if it is set the exception
4635 // was unhandled
4636 // however if the exception has intercept info then we consider it handled
4637 // again
4638 return pThread->GetExceptionState()->GetFlags()->IsUnhandled() &&
4639 !(pThread->GetExceptionState()->GetFlags()->DebuggerInterceptInfo());
4640 }
4641
4642 return FALSE;
4643}
4644
4645// Return the user state of the specified thread.
4646CorDebugUserState DacDbiInterfaceImpl::GetUserState(VMPTR_Thread vmThread)
4647{
4648 DD_ENTER_MAY_THROW;
4649
4650 UINT result = 0;
4651 result = GetPartialUserState(vmThread);
4652
4653 if (!IsThreadAtGCSafePlace(vmThread))
4654 {
4655 result |= USER_UNSAFE_POINT;
4656 }
4657
4658 return (CorDebugUserState)result;
4659}
4660
4661
4662// Return the connection ID of the specified thread.
4663CONNID DacDbiInterfaceImpl::GetConnectionID(VMPTR_Thread vmThread)
4664{
4665 DD_ENTER_MAY_THROW;
4666
4667 return INVALID_CONNECTION_ID;
4668}
4669
4670// Return the task ID of the specified thread.
4671TASKID DacDbiInterfaceImpl::GetTaskID(VMPTR_Thread vmThread)
4672{
4673 DD_ENTER_MAY_THROW;
4674
4675 return INVALID_TASK_ID;
4676}
4677
4678// Return the OS thread ID of the specified thread
4679DWORD DacDbiInterfaceImpl::TryGetVolatileOSThreadID(VMPTR_Thread vmThread)
4680{
4681 DD_ENTER_MAY_THROW;
4682
4683 Thread * pThread = vmThread.GetDacPtr();
4684 _ASSERTE(pThread != NULL);
4685
4686 DWORD dwThreadId = pThread->GetOSThreadIdForDebugger();
4687
4688 // If the thread ID is a the magical cookie value, then this is really
4689 // a switched out thread and doesn't have an OS tid. In that case, the
4690 // DD contract is to return 0 (a much more sane value)
4691 const DWORD dwSwitchedOutThreadId = SWITCHED_OUT_FIBER_OSID;
4692 if (dwThreadId == dwSwitchedOutThreadId)
4693 {
4694 return 0;
4695 }
4696 return dwThreadId;
4697}
4698
4699// Return the unique thread ID of the specified thread.
4700DWORD DacDbiInterfaceImpl::GetUniqueThreadID(VMPTR_Thread vmThread)
4701{
4702 DD_ENTER_MAY_THROW;
4703
4704 Thread * pThread = vmThread.GetDacPtr();
4705 _ASSERTE(pThread != NULL);
4706
4707 return pThread->GetOSThreadId();
4708}
4709
4710// Return the object handle to the managed Exception object of the current exception
4711// on the specified thread. The return value could be NULL if there is no current exception.
4712VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetCurrentException(VMPTR_Thread vmThread)
4713{
4714 DD_ENTER_MAY_THROW;
4715
4716 Thread * pThread = vmThread.GetDacPtr();
4717
4718 // OBJECTHANDLEs are really just TADDRs.
4719 OBJECTHANDLE ohException = pThread->GetThrowableAsHandle(); // ohException can be NULL
4720
4721 if (ohException == NULL)
4722 {
4723 if (pThread->IsLastThrownObjectUnhandled())
4724 {
4725 ohException = pThread->LastThrownObjectHandle();
4726 }
4727 }
4728
4729 VMPTR_OBJECTHANDLE vmObjHandle;
4730 vmObjHandle.SetDacTargetPtr(ohException);
4731 return vmObjHandle;
4732}
4733
4734// Return the object handle to the managed object for a given CCW pointer.
4735VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetObjectForCCW(CORDB_ADDRESS ccwPtr)
4736{
4737 DD_ENTER_MAY_THROW;
4738
4739 OBJECTHANDLE ohCCW = NULL;
4740
4741#ifdef FEATURE_COMINTEROP
4742 ComCallWrapper *pCCW = DACGetCCWFromAddress(ccwPtr);
4743 if (pCCW)
4744 {
4745 ohCCW = pCCW->GetObjectHandle();
4746 }
4747#endif
4748
4749 VMPTR_OBJECTHANDLE vmObjHandle;
4750 vmObjHandle.SetDacTargetPtr(ohCCW);
4751 return vmObjHandle;
4752}
4753
4754// Return the object handle to the managed CustomNotification object of the current notification
4755// on the specified thread. The return value could be NULL if there is no current notification.
4756// Arguments:
4757// input: vmThread - the thread on which the notification occurred
4758// Return value: object handle for the current notification (if any) on the thread. This will return non-null
4759// if and only if we are currently inside a CustomNotification Callback (or a dump was generated while in this
4760// callback)
4761//
4762VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetCurrentCustomDebuggerNotification(VMPTR_Thread vmThread)
4763{
4764 DD_ENTER_MAY_THROW;
4765
4766 Thread * pThread = vmThread.GetDacPtr();
4767
4768 // OBJECTHANDLEs are really just TADDRs.
4769 OBJECTHANDLE ohNotification = pThread->GetThreadCurrNotification(); // ohNotification can be NULL
4770
4771 VMPTR_OBJECTHANDLE vmObjHandle;
4772 vmObjHandle.SetDacTargetPtr(ohNotification);
4773 return vmObjHandle;
4774}
4775
4776// Return the current appdomain the specified thread is in.
4777VMPTR_AppDomain DacDbiInterfaceImpl::GetCurrentAppDomain(VMPTR_Thread vmThread)
4778{
4779 DD_ENTER_MAY_THROW;
4780
4781 Thread * pThread = vmThread.GetDacPtr();
4782 AppDomain * pAppDomain = pThread->GetDomain();
4783
4784 if (pAppDomain == NULL)
4785 {
4786 ThrowHR(E_FAIL);
4787 }
4788
4789 VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
4790 vmAppDomain.SetDacTargetPtr(PTR_HOST_TO_TADDR(pAppDomain));
4791 return vmAppDomain;
4792}
4793
4794
4795// Returns a bitfield reflecting the managed debugging state at the time of
4796// the jit attach.
4797CLR_DEBUGGING_PROCESS_FLAGS DacDbiInterfaceImpl::GetAttachStateFlags()
4798{
4799 DD_ENTER_MAY_THROW;
4800
4801 CLR_DEBUGGING_PROCESS_FLAGS res = (CLR_DEBUGGING_PROCESS_FLAGS)0;
4802 if (g_pDebugger != NULL)
4803 {
4804 res = g_pDebugger->GetAttachStateFlags();
4805 }
4806 else
4807 {
4808 // When launching the process under a managed debugger we
4809 // request these flags when CLR is loaded (before g_pDebugger
4810 // had a chance to be initialized). In these cases simply
4811 // return 0
4812 }
4813 return res;
4814}
4815
4816//---------------------------------------------------------------------------------------
4817// Helper to get the address of the 2nd-chance hijack function Or throw
4818//
4819// Returns:
4820// Non-null Target Address of hijack function.
4821TADDR DacDbiInterfaceImpl::GetHijackAddress()
4822{
4823 TADDR addr = NULL;
4824 if (g_pDebugger != NULL)
4825 {
4826 // Get the start address of the redirect function for unhandled exceptions.
4827 addr = dac_cast<TADDR>(g_pDebugger->m_rgHijackFunction[Debugger::kUnhandledException].StartAddress());
4828 }
4829 if (addr == NULL)
4830 {
4831 ThrowHR(CORDBG_E_NOTREADY);
4832 }
4833 return addr;
4834}
4835
4836//---------------------------------------------------------------------------------------
4837// Helper to determine whether a control PC is in any native stub which the runtime knows how to unwind.
4838//
4839// Arguments:
4840// taControlPC - control PC to be checked
4841//
4842// Returns:
4843// Returns true if the control PC is in a runtime unwindable stub.
4844//
4845// Notes:
4846// Currently this function only recognizes the ExceptionHijack() stub,
4847// which is used for unhandled exceptions.
4848//
4849
4850bool DacDbiInterfaceImpl::IsRuntimeUnwindableStub(PCODE targetControlPC)
4851{
4852
4853 TADDR controlPC = PCODEToPINSTR(targetControlPC);
4854 // we call this function a lot while walking the stack and the values here will never change
4855 // Getting the g_pDebugger and each entry in the m_rgHijackFunction is potentially ~7 DAC
4856 // accesses per frame. Caching the data into a single local array is much faster. This optimization
4857 // recovered a few % of DAC stackwalking time
4858 if(!m_isCachedHijackFunctionValid)
4859 {
4860 Debugger* pDebugger = g_pDebugger;
4861 if ((pDebugger == NULL) || (pDebugger->m_rgHijackFunction == NULL))
4862 {
4863 // The in-process debugging infrastructure hasn't been fully initialized, which means that we could
4864 // NOT have hijacked anything yet.
4865 return false;
4866 }
4867
4868 // PERF NOTE: if needed this array copy could probably be made more efficient
4869 // hitting the DAC only once for a single memory block, or even better
4870 // put the array inline in the Debugger object so that we only do 1 DAC
4871 // access for this entire thing
4872 for (int i = 0; i < Debugger::kMaxHijackFunctions; i++)
4873 {
4874 InitTargetBufferFromMemoryRange(pDebugger->m_rgHijackFunction[i], &m_pCachedHijackFunction[i] );
4875 }
4876 m_isCachedHijackFunctionValid = TRUE;
4877 }
4878
4879 // Check whether the control PC is in any of the thread redirection functions.
4880 for (int i = 0; i < Debugger::kMaxHijackFunctions; i++)
4881 {
4882 CORDB_ADDRESS start = m_pCachedHijackFunction[i].pAddress;
4883 CORDB_ADDRESS end = start + m_pCachedHijackFunction[i].cbSize;
4884 if ((start <= controlPC) && (controlPC < end))
4885 {
4886 return true;
4887 }
4888 }
4889 return false;
4890}
4891
4892//---------------------------------------------------------------------------------------
4893// Align a stack pointer for the given architecture
4894//
4895// Arguments:
4896// pEsp - in/out: pointer to stack pointer.
4897//
4898void DacDbiInterfaceImpl::AlignStackPointer(CORDB_ADDRESS * pEsp)
4899{
4900 SUPPORTS_DAC;
4901
4902 // Nop on x86.
4903#if defined(_WIN64)
4904 // on 64-bit, stack pointer must be 16-byte aligned.
4905 // Stacks grown down, so round down to nearest 0xF bits.
4906 *pEsp &= ~((CORDB_ADDRESS) 0xF);
4907#endif
4908}
4909
4910//---------------------------------------------------------------------------------------
4911// Emulate pushing something on a thread's stack.
4912//
4913// Arguments:
4914// pEsp - in/out: pointer to stack pointer to push object at. On output,
4915// updated stack pointer.
4916// pData - object to push on the stack.
4917// fAlignStack - whether to align the stack pointer before and after the push.
4918// Callers which specify FALSE must be very careful and know exactly
4919// what they are doing.
4920//
4921// Return:
4922// address of pushed object. Throws on error.
4923template <class T>
4924CORDB_ADDRESS DacDbiInterfaceImpl::PushHelper(CORDB_ADDRESS * pEsp,
4925 const T * pData,
4926 BOOL fAlignStack)
4927{
4928 SUPPORTS_DAC;
4929
4930 if (fAlignStack == TRUE)
4931 {
4932 AlignStackPointer(pEsp);
4933 }
4934 *pEsp -= sizeof(T);
4935 if (fAlignStack == TRUE)
4936 {
4937 AlignStackPointer(pEsp);
4938 }
4939 SafeWriteStructOrThrow(*pEsp, pData);
4940 return *pEsp;
4941}
4942
4943//---------------------------------------------------------------------------------------
4944// Write an EXCEPTION_RECORD structure to the remote target at the specified address while taking
4945// into account the number of exception parameters. On 64-bit OS and on the WOW64, the OS always
4946// pushes the entire EXCEPTION_RECORD onto the stack. However, on native x86 OS, the OS only pushes
4947// enough of the EXCEPTION_RECORD to cover the specified number of exception parameters. Thus we
4948// need to be extra careful when we overwrite an EXCEPTION_RECORD on the stack.
4949//
4950// Arguments:
4951// pRemotePtr - address of the EXCEPTION_RECORD in the remote target
4952// pExcepRecord - EXCEPTION_RECORD to be written
4953//
4954// Notes:
4955// This function is only used by the code which hijacks a therad when there's an unhandled exception.
4956// It only works when we are actually debugging a live process, not a dump.
4957//
4958
4959void DacDbiInterfaceImpl::WriteExceptionRecordHelper(CORDB_ADDRESS pRemotePtr,
4960 const EXCEPTION_RECORD * pExcepRecord)
4961{
4962 // Calculate the correct size to push onto the stack.
4963 ULONG32 cbSize = offsetof(EXCEPTION_RECORD, ExceptionInformation);
4964 cbSize += pExcepRecord->NumberParameters * sizeof(pExcepRecord->ExceptionInformation[0]);
4965
4966 // Use the data target to write to the remote target. Here we are assuming that we are debugging a
4967 // live process, since this function is only called by the hijacking code for unhandled exceptions.
4968 HRESULT hr = m_pMutableTarget->WriteVirtual(pRemotePtr,
4969 reinterpret_cast<const BYTE *>(pExcepRecord),
4970 cbSize);
4971
4972 if (FAILED(hr))
4973 {
4974 ThrowHR(hr);
4975 }
4976}
4977
4978// Implement IDacDbiInterface::Hijack
4979void DacDbiInterfaceImpl::Hijack(
4980 VMPTR_Thread vmThread,
4981 ULONG32 dwThreadId,
4982 const EXCEPTION_RECORD * pRecord,
4983 T_CONTEXT * pOriginalContext,
4984 ULONG32 cbSizeContext,
4985 EHijackReason::EHijackReason reason,
4986 void * pUserData,
4987 CORDB_ADDRESS * pRemoteContextAddr)
4988{
4989 DD_ENTER_MAY_THROW;
4990
4991 //
4992 // Validate parameters
4993 //
4994
4995 // pRecord may be NULL if we're not hijacking at an exception
4996 // pOriginalContext may be NULL if caller doesn't want a copy of the context.
4997 // (The hijack function already has the context)
4998 _ASSERTE((pOriginalContext == NULL) == (cbSizeContext == 0));
4999 _ASSERTE(EHijackReason::IsValid(reason));
5000#ifdef PLATFORM_UNIX
5001 _ASSERTE(!"Not supported on this platform");
5002#endif
5003
5004 //
5005 // If we hijack a thread which might not be managed we can set vmThread = NULL
5006 // The only side-effect in this case is that we can't reuse CONTEXT and
5007 // EXCEPTION_RECORD space on the stack by an already underway in-process exception
5008 // filter. If you depend on those being used and updated you must provide the vmThread
5009 //
5010 Thread* pThread = NULL;
5011 if(!vmThread.IsNull())
5012 {
5013 pThread = vmThread.GetDacPtr();
5014 _ASSERTE(pThread->GetOSThreadIdForDebugger() == dwThreadId);
5015 }
5016
5017 TADDR pfnHijackFunction = GetHijackAddress();
5018
5019 //
5020 // Setup context for hijack
5021 //
5022 T_CONTEXT ctx;
5023 HRESULT hr = m_pTarget->GetThreadContext(
5024 dwThreadId,
5025 CONTEXT_FULL,
5026 sizeof(ctx),
5027 (BYTE*) &ctx);
5028 IfFailThrow(hr);
5029
5030 // If caller requested, copy back the original context that we're hijacking from.
5031 if (pOriginalContext != NULL)
5032 {
5033 // Since Dac + DBI are tightly coupled, context sizes should be the same.
5034 if (cbSizeContext != sizeof(T_CONTEXT))
5035 {
5036 ThrowHR(E_INVALIDARG);
5037 }
5038
5039 memcpy(pOriginalContext, &ctx, cbSizeContext);
5040 }
5041
5042 // Make sure the trace flag isn't on. This can happen if we were single stepping the thread when we faulted. This
5043 // will ensure that we don't try to single step through the OS's exception logic, which greatly confuses our second
5044 // chance hijack logic. This also mimics what the OS does for us automaically when single stepping in process, i.e.,
5045 // when you turn the trace flag on in-process and go, if there is a fault, the fault is reported and the trace flag
5046 // is automatically turned off.
5047 //
5048 // The debugger could always re-enable the single-step flag if it wants to.
5049#ifndef _TARGET_ARM_
5050 UnsetSSFlag(reinterpret_cast<DT_CONTEXT *>(&ctx));
5051#endif
5052
5053 // Push pointers
5054 void* espContext = NULL;
5055 void* espRecord = NULL;
5056 const void* pData = pUserData;
5057
5058 // @dbgtodo cross-plat - this is not cross plat
5059 CORDB_ADDRESS esp = GetSP(&ctx);
5060
5061 //
5062 // Find out where the OS exception dispatcher has pushed the EXCEPTION_RECORD and CONTEXT. The ExInfo and
5063 // ExceptionTracker have pointers to these data structures, but when we get the unhandled exception
5064 // notification, the OS exception dispatcher is no longer on the stack, so these pointers are no longer
5065 // valid. We need to either update these pointers in the ExInfo/ExcepionTracker, or reuse the stack
5066 // space used by the OS exception dispatcher. We are using the latter approach here.
5067 //
5068
5069 CORDB_ADDRESS espOSContext = NULL;
5070 CORDB_ADDRESS espOSRecord = NULL;
5071 if (pThread != NULL && pThread->IsExceptionInProgress())
5072 {
5073 espOSContext = (CORDB_ADDRESS)PTR_TO_TADDR(pThread->GetExceptionState()->GetContextRecord());
5074 espOSRecord = (CORDB_ADDRESS)PTR_TO_TADDR(pThread->GetExceptionState()->GetExceptionRecord());
5075
5076 // The managed exception may not be related to the unhandled exception for which we are trying to
5077 // hijack. An example would be when a thread hits a managed exception, VS tries to do func eval on
5078 // the thread, but the func eval causes an unhandled exception (e.g. AV in mscorwks.dll). In this
5079 // case, the pointers stored on the ExInfo/ExceptionTracker are closer to the root than the current
5080 // SP of the thread. The check below makes sure we don't reuse the pointers in this case.
5081 if (espOSContext < esp)
5082 {
5083 SafeWriteStructOrThrow(espOSContext, &ctx);
5084 espContext = CORDB_ADDRESS_TO_PTR(espOSContext);
5085
5086 // We should have an EXCEPTION_RECORD if we are hijacked at an exception.
5087 // We need to be careful when we overwrite the exception record. On x86, the OS doesn't
5088 // always push the full record onto the stack, and so we can't blindly use sizeof(EXCEPTION_RECORD).
5089 // Instead, we have to look at the number of exception parameters and calculate the size.
5090 _ASSERTE(pRecord != NULL);
5091 WriteExceptionRecordHelper(espOSRecord, pRecord);
5092 espRecord = CORDB_ADDRESS_TO_PTR(espOSRecord);
5093
5094 esp = min(espOSContext, espOSRecord);
5095 }
5096 }
5097
5098 // If we haven't reused the pointers, then push everything at the leaf of the stack.
5099 if (espContext == NULL)
5100 {
5101 _ASSERTE(espRecord == NULL);
5102
5103 // Push on full Context and ExceptionRecord structures. We'll then push pointers to these,
5104 // and those pointers will serve as the actual args to the function.
5105 espContext = CORDB_ADDRESS_TO_PTR(PushHelper(&esp, &ctx, TRUE));
5106
5107 // If caller didn't pass an exception-record, then we're not being hijacked at an exception.
5108 // We'll just pass NULL for the exception-record to the Hijack function.
5109 if (pRecord != NULL)
5110 {
5111 espRecord = CORDB_ADDRESS_TO_PTR(PushHelper(&esp, pRecord, TRUE));
5112 }
5113 }
5114
5115 if(pRemoteContextAddr != NULL)
5116 {
5117 *pRemoteContextAddr = PTR_TO_CORDB_ADDRESS(espContext);
5118 }
5119
5120 //
5121 // Push args onto the stack to be able to call the hijack function
5122 //
5123
5124 // Prototype of hijack is:
5125 // void __stdcall ExceptionHijackWorker(CONTEXT * pContext, EXCEPTION_RECORD * pRecord, EHijackReason, void * pData)
5126 // Set up everything so that the hijack stub can just do a "call" instruction.
5127 //
5128 // Regarding stack overflow: We could do an explicit check against the thread's stack base limit.
5129 // However, we don't need an explicit overflow check because if the stack does overflow,
5130 // the hijack will just hit a regular stack-overflow exception.
5131#if defined(_TARGET_X86_) // TARGET
5132 // X86 calling convention is to push args on the stack in reverse order.
5133 // If we fail here, the stack is written, but esp hasn't been committed yet so it shouldn't matter.
5134 PushHelper(&esp, &pData, TRUE);
5135 PushHelper(&esp, &reason, TRUE);
5136 PushHelper(&esp, &espRecord, TRUE);
5137 PushHelper(&esp, &espContext, TRUE);
5138#elif defined (_TARGET_AMD64_) // TARGET
5139 // AMD64 calling convention is to place first 4 parameters in: rcx, rdx, r8 and r9
5140 ctx.Rcx = (DWORD64) espContext;
5141 ctx.Rdx = (DWORD64) espRecord;
5142 ctx.R8 = (DWORD64) reason;
5143 ctx.R9 = (DWORD64) pData;
5144
5145 // Caller must allocate stack space to spill for args.
5146 // Push the arguments onto the outgoing argument homes.
5147 // Make sure we push pointer-sized values to keep the stack aligned.
5148 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.R9)), FALSE);
5149 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.R8)), FALSE);
5150 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.Rdx)), FALSE);
5151 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.Rcx)), FALSE);
5152#elif defined(_TARGET_ARM_)
5153 ctx.R0 = (DWORD)espContext;
5154 ctx.R1 = (DWORD)espRecord;
5155 ctx.R2 = (DWORD)reason;
5156 ctx.R3 = (DWORD)pData;
5157#elif defined(_TARGET_ARM64_)
5158 ctx.X0 = (DWORD64)espContext;
5159 ctx.X1 = (DWORD64)espRecord;
5160 ctx.X2 = (DWORD64)reason;
5161 ctx.X3 = (DWORD64)pData;
5162#else
5163 PORTABILITY_ASSERT("CordbThread::HijackForUnhandledException is not implemented on this platform.");
5164#endif
5165 SetSP(&ctx, CORDB_ADDRESS_TO_TADDR(esp));
5166
5167 // @dbgtodo cross-plat - not cross-platform safe
5168 SetIP(&ctx, pfnHijackFunction);
5169
5170 //
5171 // Commit the context.
5172 //
5173 hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(ctx), reinterpret_cast<BYTE*> (&ctx));
5174 IfFailThrow(hr);
5175}
5176
5177// Return the filter CONTEXT on the LS.
5178VMPTR_CONTEXT DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Thread vmThread)
5179{
5180 DD_ENTER_MAY_THROW;
5181
5182 VMPTR_CONTEXT vmContext = VMPTR_CONTEXT::NullPtr();
5183
5184 Thread * pThread = vmThread.GetDacPtr();
5185 if (pThread->GetInteropDebuggingHijacked())
5186 {
5187 _ASSERTE(!ISREDIRECTEDTHREAD(pThread));
5188 vmContext = VMPTR_CONTEXT::NullPtr();
5189 }
5190 else
5191 {
5192 DT_CONTEXT * pLSContext = reinterpret_cast<DT_CONTEXT *>(pThread->GetFilterContext());
5193 if (pLSContext != NULL)
5194 {
5195 _ASSERTE(!ISREDIRECTEDTHREAD(pThread));
5196 vmContext.SetHostPtr(pLSContext);
5197 }
5198 else if (ISREDIRECTEDTHREAD(pThread))
5199 {
5200 pLSContext = reinterpret_cast<DT_CONTEXT *>(GETREDIRECTEDCONTEXT(pThread));
5201 _ASSERTE(pLSContext != NULL);
5202
5203 if (pLSContext != NULL)
5204 {
5205 vmContext.SetHostPtr(pLSContext);
5206 }
5207 }
5208 }
5209
5210 return vmContext;
5211}
5212
5213// Return a TargetBuffer for the raw vararg signature.
5214TargetBuffer DacDbiInterfaceImpl::GetVarArgSig(CORDB_ADDRESS VASigCookieAddr,
5215 CORDB_ADDRESS * pArgBase)
5216{
5217 DD_ENTER_MAY_THROW;
5218
5219 _ASSERTE(pArgBase != NULL);
5220 *pArgBase = NULL;
5221
5222 // First, read the VASigCookie pointer.
5223 TADDR taVASigCookie = NULL;
5224 SafeReadStructOrThrow(VASigCookieAddr, &taVASigCookie);
5225
5226 // Now create a DAC copy of VASigCookie.
5227 VASigCookie * pVACookie = PTR_VASigCookie(taVASigCookie);
5228
5229 // Figure out where the first argument is.
5230#if defined(_TARGET_X86_) // (STACK_GROWS_DOWN_ON_ARGS_WALK)
5231 *pArgBase = VASigCookieAddr + pVACookie->sizeOfArgs;
5232#else // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
5233 *pArgBase = VASigCookieAddr + sizeof(VASigCookie *);
5234#endif // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
5235
5236 return TargetBuffer(PTR_TO_CORDB_ADDRESS(pVACookie->signature.GetRawSig()),
5237 pVACookie->signature.GetRawSigLen());
5238}
5239
5240// returns TRUE if the type requires 8-byte alignment
5241BOOL DacDbiInterfaceImpl::RequiresAlign8(VMPTR_TypeHandle thExact)
5242{
5243 DD_ENTER_MAY_THROW;
5244
5245#ifdef FEATURE_64BIT_ALIGNMENT
5246 TypeHandle th = TypeHandle::FromPtr(thExact.GetDacPtr());
5247 PTR_MethodTable mt = th.AsMethodTable();
5248
5249 return mt->RequiresAlign8();
5250#else
5251 ThrowHR(E_NOTIMPL);
5252#endif
5253}
5254
5255// Resolve the raw generics token to the real generics type token. The resolution is based on the
5256// given index.
5257GENERICS_TYPE_TOKEN DacDbiInterfaceImpl::ResolveExactGenericArgsToken(DWORD dwExactGenericArgsTokenIndex,
5258 GENERICS_TYPE_TOKEN rawToken)
5259{
5260 DD_ENTER_MAY_THROW;
5261
5262 if (dwExactGenericArgsTokenIndex == 0)
5263 {
5264 // In this case the real generics type token is the MethodTable of the "this" object.
5265 // Note that we want the target address here.
5266
5267 // Incoming rawToken is actually a PTR_Object for the 'this' pointer.
5268 // Need to do some casting to convert GENERICS_TYPE_TOKEN --> PTR_Object
5269 TADDR addrObjThis = CORDB_ADDRESS_TO_TADDR(rawToken);
5270 PTR_Object pObjThis = dac_cast<PTR_Object>(addrObjThis);
5271
5272
5273 PTR_MethodTable pMT = pObjThis->GetMethodTable();
5274
5275 // Now package up the PTR_MethodTable back into a GENERICS_TYPE_TOKEN
5276 TADDR addrMT = dac_cast<TADDR>(pMT);
5277 GENERICS_TYPE_TOKEN realToken = (GENERICS_TYPE_TOKEN) addrMT;
5278 return realToken;
5279 }
5280 else if (dwExactGenericArgsTokenIndex == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
5281 {
5282 // rawToken is already initialized correctly. Nothing to do here.
5283 return rawToken;
5284 }
5285
5286 // The index of the generics type token should not be anything else.
5287 // This is indeed an error condition, and so we throw here.
5288 _ASSERTE(!"DDII::REGAT - Unexpected generics type token index.");
5289 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
5290}
5291
5292// Check if the given method is an IL stub or an LCD method.
5293IDacDbiInterface::DynamicMethodType DacDbiInterfaceImpl::IsILStubOrLCGMethod(VMPTR_MethodDesc vmMethodDesc)
5294{
5295 DD_ENTER_MAY_THROW;
5296
5297 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
5298
5299 if (pMD->IsILStub())
5300 {
5301 return kILStub;
5302 }
5303 else if (pMD->IsLCGMethod())
5304 {
5305 return kLCGMethod;
5306 }
5307 else
5308 {
5309 return kNone;
5310 }
5311}
5312
5313//---------------------------------------------------------------------------------------
5314//
5315// Determine whether the specified thread is at a GC safe place.
5316//
5317// Arguments:
5318// vmThread - the thread to be examined
5319//
5320// Return Value:
5321// Return TRUE if the thread is at a GC safe place.
5322// and under what conditions
5323//
5324// Notes:
5325// This function basically does a one-frame stackwalk.
5326// The logic is adopted from Debugger::IsThreadAtSafePlace().
5327//
5328
5329BOOL DacDbiInterfaceImpl::IsThreadAtGCSafePlace(VMPTR_Thread vmThread)
5330{
5331 DD_ENTER_MAY_THROW;
5332
5333 BOOL fIsGCSafe = FALSE;
5334 Thread * pThread = vmThread.GetDacPtr();
5335
5336 // Check if the runtime has entered "Shutdown for Finalizer" mode.
5337 if ((g_fEEShutDown & ShutDown_Finalize2) != 0)
5338 {
5339 fIsGCSafe = TRUE;
5340 }
5341 else
5342 {
5343 T_CONTEXT ctx;
5344 REGDISPLAY rd;
5345 SetUpRegdisplayForStackWalk(pThread, &ctx, &rd);
5346
5347 ULONG32 flags = (QUICKUNWIND | HANDLESKIPPEDFRAMES | DISABLE_MISSING_FRAME_DETECTION);
5348
5349 StackFrameIterator iter;
5350 iter.Init(pThread, pThread->GetFrame(), &rd, flags);
5351
5352 CrawlFrame * pCF = &(iter.m_crawl);
5353 if (pCF->IsFrameless() && pCF->IsActiveFunc())
5354 {
5355 if (pCF->IsGcSafe())
5356 {
5357 fIsGCSafe = TRUE;
5358 }
5359 }
5360 }
5361
5362 return fIsGCSafe;
5363}
5364
5365//---------------------------------------------------------------------------------------
5366//
5367// Return a partial user state of the specified thread. The returned user state doesn't contain
5368// information about USER_UNSAFE_POINT. The caller needs to call IsThreadAtGCSafePlace() to get
5369// the full user state.
5370//
5371// Arguments:
5372// vmThread - the specified thread
5373//
5374// Return Value:
5375// Return the partial user state except for USER_UNSAFE_POINT
5376//
5377
5378CorDebugUserState DacDbiInterfaceImpl::GetPartialUserState(VMPTR_Thread vmThread)
5379{
5380 DD_ENTER_MAY_THROW;
5381
5382 Thread * pThread = vmThread.GetDacPtr();
5383 Thread::ThreadState ts = pThread->GetSnapshotState();
5384
5385 UINT result = 0;
5386 if (ts & Thread::TS_Background)
5387 {
5388 result |= USER_BACKGROUND;
5389 }
5390
5391 if (ts & Thread::TS_Unstarted)
5392 {
5393 result |= USER_UNSTARTED;
5394 }
5395
5396 // Don't report a StopRequested if the thread has actually stopped.
5397 if (ts & Thread::TS_Dead)
5398 {
5399 result |= USER_STOPPED;
5400 }
5401
5402 // The interruptible flag is unreliable (see issue 699245)
5403 // The Debugger_SleepWaitJoin is always accurate when it is present, but it is still
5404 // just a band-aid fix to cover some of the race conditions interruptible has.
5405
5406 if (ts & Thread::TS_Interruptible || pThread->HasThreadStateNC(Thread::TSNC_DebuggerSleepWaitJoin))
5407 {
5408 result |= USER_WAIT_SLEEP_JOIN;
5409 }
5410
5411 // CoreCLR does not support user-requested thread suspension
5412 _ASSERTE(!(ts & Thread::TS_UserSuspendPending));
5413
5414 if (pThread->IsThreadPoolThread())
5415 {
5416 result |= USER_THREADPOOL;
5417 }
5418
5419 return (CorDebugUserState)result;
5420}
5421
5422//---------------------------------------------------------------------------------------
5423//
5424// Look up the EnC version number of a particular jitted instance of a managed method.
5425//
5426// Arguments:
5427// pModule - the module containing the managed method
5428// vmMethodDesc - the MethodDesc of the managed method
5429// mdMethod - the MethodDef metadata token of the managed method
5430// pNativeStartAddress - the native start address of the jitted code
5431// pJittedInstanceEnCVersion - out parameter; the version number of the version
5432// corresponding to the specified native start address
5433// pLatestEnCVersion - out parameter; the version number of the latest version
5434//
5435// Assumptions:
5436// vmMethodDesc and mdMethod must match (see below).
5437//
5438// Notes:
5439// mdMethod is not strictly necessary, since we can always get that from vmMethodDesc.
5440// It is just a perf optimization since the caller has the metadata token around already.
5441//
5442// Today, there is no way to retrieve the EnC version number from the RS data structures.
5443// This primitive uses DAC to retrieve it from the LS data structures. This function may
5444// very well be ripped out in the future if we DACize this information, but the current
5445// thinking is that some of the RS data structures will remain, most likely in a reduced form.
5446//
5447
5448void DacDbiInterfaceImpl::LookupEnCVersions(Module* pModule,
5449 VMPTR_MethodDesc vmMethodDesc,
5450 mdMethodDef mdMethod,
5451 CORDB_ADDRESS pNativeStartAddress,
5452 SIZE_T * pLatestEnCVersion,
5453 SIZE_T * pJittedInstanceEnCVersion /* = NULL */)
5454{
5455 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
5456
5457 // make sure the vmMethodDesc and mdMethod match
5458 _ASSERTE(pMD->GetMemberDef() == mdMethod);
5459
5460 _ASSERTE(pLatestEnCVersion != NULL);
5461
5462 // @dbgtodo inspection - once we do EnC, stop using DMIs.
5463 // If the method wasn't EnCed, DMIs may not exist. And since this is DAC, we can't create them.
5464
5465 // We may not have the memory for the DebuggerMethodInfos in a minidump.
5466 // When dump debugging EnC information isn't very useful so just fallback
5467 // to default version.
5468 DebuggerMethodInfo * pDMI = NULL;
5469 DebuggerJitInfo * pDJI = NULL;
5470 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
5471 {
5472 pDMI = g_pDebugger->GetOrCreateMethodInfo(pModule, mdMethod);
5473 if (pDMI != NULL)
5474 {
5475 pDJI = pDMI->FindJitInfo(pMD, CORDB_ADDRESS_TO_TADDR(pNativeStartAddress));
5476 }
5477 }
5478 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
5479 if (pDJI != NULL)
5480 {
5481 if (pJittedInstanceEnCVersion != NULL)
5482 {
5483 *pJittedInstanceEnCVersion = pDJI->m_encVersion;
5484 }
5485 *pLatestEnCVersion = pDMI->GetCurrentEnCVersion();
5486 }
5487 else
5488 {
5489 // If we have no DMI/DJI, then we must never have EnCed. So we can use default EnC info
5490 // Several cases where we don't have a DMI/DJI:
5491 // - LCG methods
5492 // - method was never "touched" by debugger. (DJIs are created lazily).
5493 if (pJittedInstanceEnCVersion != NULL)
5494 {
5495 *pJittedInstanceEnCVersion = CorDB_DEFAULT_ENC_FUNCTION_VERSION;
5496 }
5497 *pLatestEnCVersion = CorDB_DEFAULT_ENC_FUNCTION_VERSION;
5498 }
5499}
5500
5501// Get the address of the Debugger control block on the helper thread
5502// Arguments: none
5503// Return Value: The remote address of the Debugger control block allocated on the helper thread
5504// if it has been successfully allocated or NULL otherwise.
5505CORDB_ADDRESS DacDbiInterfaceImpl::GetDebuggerControlBlockAddress()
5506{
5507 DD_ENTER_MAY_THROW;
5508
5509 if ((g_pDebugger != NULL) &&
5510 (g_pDebugger->m_pRCThread != NULL))
5511 {
5512 return CORDB_ADDRESS(dac_cast<TADDR>(g_pDebugger->m_pRCThread->GetDCB()));
5513 }
5514
5515 return NULL;
5516}
5517
5518// DacDbi API: Get the context for a particular thread of the target process
5519void DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer)
5520{
5521 DD_ENTER_MAY_THROW
5522
5523 _ASSERTE(pContextBuffer != NULL);
5524
5525 Thread * pThread = vmThread.GetDacPtr();
5526
5527 // @dbgtodo Once the filter context is removed, then we should always
5528 // start with the leaf CONTEXT.
5529 DT_CONTEXT * pFilterContext = reinterpret_cast<DT_CONTEXT *>(pThread->GetFilterContext());
5530
5531 if (pFilterContext == NULL)
5532 {
5533 // If the filter context is NULL, then we use the true context of the thread.
5534 pContextBuffer->ContextFlags = CONTEXT_ALL;
5535 HRESULT hr = m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
5536 pContextBuffer->ContextFlags,
5537 sizeof(*pContextBuffer),
5538 reinterpret_cast<BYTE *>(pContextBuffer));
5539 if (hr == E_NOTIMPL)
5540 {
5541 // GetThreadContext is not implemented on this data target.
5542 // That's why we have to make do with context we can obtain from Frames explicitly stored in Thread object.
5543 // It suffices for managed debugging stackwalk.
5544 REGDISPLAY tmpRd = {};
5545 T_CONTEXT tmpContext = {};
5546 FillRegDisplay(&tmpRd, &tmpContext);
5547
5548 // Going through thread Frames and looking for first (deepest one) one that
5549 // that has context available for stackwalking (SP and PC)
5550 // For example: RedirectedThreadFrame, InlinedCallFrame, HelperMethodFrame, ComPlusMethodFrame
5551 Frame *frame = pThread->GetFrame();
5552 while (frame != NULL && frame != FRAME_TOP)
5553 {
5554 frame->UpdateRegDisplay(&tmpRd);
5555 if (GetRegdisplaySP(&tmpRd) != 0 && GetControlPC(&tmpRd) != 0)
5556 {
5557 UpdateContextFromRegDisp(&tmpRd, &tmpContext);
5558 CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer));
5559 pContextBuffer->ContextFlags = DT_CONTEXT_CONTROL;
5560 return;
5561 }
5562 frame = frame->Next();
5563 }
5564
5565 // It looks like this thread is not running managed code.
5566 ZeroMemory(pContextBuffer, sizeof(*pContextBuffer));
5567 }
5568 else
5569 {
5570 IfFailThrow(hr);
5571 }
5572 }
5573 else
5574 {
5575 *pContextBuffer = *pFilterContext;
5576 }
5577
5578} // DacDbiInterfaceImpl::GetContext
5579
5580// Create a VMPTR_Object from a target object address
5581// @dbgtodo validate the VMPTR_Object is in fact a object, possibly by DACizing
5582// Object::Validate
5583VMPTR_Object DacDbiInterfaceImpl::GetObject(CORDB_ADDRESS ptr)
5584{
5585 DD_ENTER_MAY_THROW;
5586
5587 VMPTR_Object vmObj = VMPTR_Object::NullPtr();
5588 vmObj.SetDacTargetPtr(CORDB_ADDRESS_TO_TADDR(ptr));
5589 return vmObj;
5590}
5591
5592HRESULT DacDbiInterfaceImpl::EnableNGENPolicy(CorDebugNGENPolicy ePolicy)
5593{
5594 return E_NOTIMPL;
5595}
5596
5597HRESULT DacDbiInterfaceImpl::SetNGENCompilerFlags(DWORD dwFlags)
5598{
5599 DD_ENTER_MAY_THROW;
5600
5601#ifndef FEATURE_PREJIT
5602 return CORDBG_E_NGEN_NOT_SUPPORTED;
5603#else
5604 // verify that we are still early enough in runtime lifecycle to mutate these
5605 // flags. Typically this is done in the CreateProcess event though it is possible
5606 // to do it even earlier
5607 if(!Debugger::s_fCanChangeNgenFlags)
5608 return CORDBG_E_MUST_BE_IN_CREATE_PROCESS;
5609
5610 BOOL fAllowOpt =
5611 ((dwFlags & CORDEBUG_JIT_DISABLE_OPTIMIZATION) != CORDEBUG_JIT_DISABLE_OPTIMIZATION);
5612 PEFile::SetNGENDebugFlags(fAllowOpt);
5613 return S_OK;
5614#endif
5615}
5616
5617HRESULT DacDbiInterfaceImpl::GetNGENCompilerFlags(DWORD *pdwFlags)
5618{
5619 DD_ENTER_MAY_THROW;
5620
5621#ifndef FEATURE_PREJIT
5622 return CORDBG_E_NGEN_NOT_SUPPORTED;
5623#else
5624 BOOL fAllowOpt = TRUE;
5625 PEFile::GetNGENDebugFlags(&fAllowOpt);
5626 if(!fAllowOpt)
5627 {
5628 *pdwFlags = CORDEBUG_JIT_DISABLE_OPTIMIZATION;
5629 }
5630 else
5631 {
5632 *pdwFlags = CORDEBUG_JIT_DEFAULT;
5633 }
5634
5635 return S_OK;
5636#endif
5637}
5638
5639typedef DPTR(OBJECTREF) PTR_ObjectRef;
5640
5641// Create a VMPTR_Object from an address which points to a reference to an object
5642// @dbgtodo validate the VMPTR_Object is in fact a object, possibly by DACizing
5643// Object::Validate
5644VMPTR_Object DacDbiInterfaceImpl::GetObjectFromRefPtr(CORDB_ADDRESS ptr)
5645{
5646 DD_ENTER_MAY_THROW;
5647
5648 VMPTR_Object vmObj = VMPTR_Object::NullPtr();
5649 PTR_ObjectRef objRef = PTR_ObjectRef(CORDB_ADDRESS_TO_TADDR(ptr));
5650 vmObj.SetDacTargetPtr(PTR_TO_TADDR(*objRef));
5651
5652 return vmObj;
5653}
5654
5655// Create a VMPTR_OBJECTHANDLE from a handle
5656VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetVmObjectHandle(CORDB_ADDRESS handleAddress)
5657{
5658 DD_ENTER_MAY_THROW;
5659
5660 VMPTR_OBJECTHANDLE vmObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
5661 vmObjHandle.SetDacTargetPtr(CORDB_ADDRESS_TO_TADDR(handleAddress));
5662
5663 return vmObjHandle;
5664}
5665
5666
5667// Validate that the VMPTR_OBJECTHANDLE refers to a legitimate managed object
5668BOOL DacDbiInterfaceImpl::IsVmObjectHandleValid(VMPTR_OBJECTHANDLE vmHandle)
5669{
5670 DD_ENTER_MAY_THROW;
5671
5672 BOOL ret = FALSE;
5673 // this may cause unallocated debuggee memory to be read
5674 // SEH exceptions will be caught
5675 EX_TRY
5676 {
5677 OBJECTREF objRef = ObjectFromHandle((OBJECTHANDLE)vmHandle.GetDacPtr());
5678
5679 // NULL is certainly valid...
5680 if (objRef != NULL)
5681 {
5682 if (objRef->ValidateObjectWithPossibleAV())
5683 {
5684 ret = TRUE;
5685 }
5686 }
5687 }
5688 EX_CATCH
5689 {
5690 }
5691 EX_END_CATCH(SwallowAllExceptions);
5692
5693 return ret;
5694}
5695
5696// determines if the specified module is a WinRT module
5697HRESULT DacDbiInterfaceImpl::IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT)
5698{
5699 DD_ENTER_MAY_THROW;
5700
5701 HRESULT hr = S_OK;
5702 isWinRT = FALSE;
5703
5704 EX_TRY
5705 {
5706 Module* pModule = vmModule.GetDacPtr();
5707 isWinRT = pModule->GetFile()->GetAssembly()->IsWindowsRuntime();
5708 }
5709 EX_CATCH_HRESULT(hr);
5710
5711 return hr;
5712}
5713
5714// Determines the app domain id for the object refered to by a given VMPTR_OBJECTHANDLE
5715ULONG DacDbiInterfaceImpl::GetAppDomainIdFromVmObjectHandle(VMPTR_OBJECTHANDLE vmHandle)
5716{
5717 DD_ENTER_MAY_THROW;
5718
5719 OBJECTHANDLE handle = (OBJECTHANDLE) vmHandle.GetDacPtr();
5720 return HndGetHandleADIndex(handle).m_dwIndex;
5721}
5722
5723// Get the target address from a VMPTR_OBJECTHANDLE, i.e., the handle address
5724CORDB_ADDRESS DacDbiInterfaceImpl::GetHandleAddressFromVmHandle(VMPTR_OBJECTHANDLE vmHandle)
5725{
5726 DD_ENTER_MAY_THROW;
5727
5728 CORDB_ADDRESS handle = vmHandle.GetDacPtr();
5729
5730 return handle;
5731}
5732
5733// Create a TargetBuffer which describes the location of the object
5734TargetBuffer DacDbiInterfaceImpl::GetObjectContents(VMPTR_Object vmObj)
5735{
5736 DD_ENTER_MAY_THROW;
5737 PTR_Object objPtr = vmObj.GetDacPtr();
5738
5739 _ASSERTE(objPtr->GetSize() <= 0xffffffff);
5740 return TargetBuffer(PTR_TO_TADDR(objPtr), (ULONG)objPtr->GetSize());
5741}
5742
5743// ============================================================================
5744// functions to get information about objects referenced via an instance of CordbReferenceValue or
5745// CordbHandleValue
5746// ============================================================================
5747
5748// DacDbiInterfaceImpl::FastSanityCheckObject
5749// Helper function for CheckRef. Sanity check an object.
5750// We use a fast and easy check to improve confidence that objPtr points to a valid object.
5751// We can't tell cheaply if this is really a valid object (that would require walking the GC heap), but at
5752// least we can check if we get an EEClass from the supposed method table and then get the method table from
5753// the class. If we can, we have improved the probability that the object is valid.
5754// Arguments:
5755// input: objPtr - address of the object we are checking
5756// Return Value: E_INVALIDARG or S_OK.
5757HRESULT DacDbiInterfaceImpl::FastSanityCheckObject(PTR_Object objPtr)
5758{
5759 CONTRACTL
5760 {
5761 SO_NOT_MAINLINE;
5762 NOTHROW;
5763 GC_NOTRIGGER;
5764 }
5765 CONTRACTL_END;
5766
5767 HRESULT hr = S_OK;
5768
5769 EX_TRY
5770 {
5771 // NULL is certainly valid...
5772 if (objPtr != NULL)
5773 {
5774 if (!objPtr->ValidateObjectWithPossibleAV())
5775 {
5776 LOG((LF_CORDB, LL_INFO10000, "GOI: object methodtable-class invariant doesn't hold.\n"));
5777 hr = E_INVALIDARG;
5778 }
5779 }
5780 }
5781 EX_CATCH
5782 {
5783 LOG((LF_CORDB, LL_INFO10000, "GOI: exception indicated ref is bad.\n"));
5784 hr = E_INVALIDARG;
5785 }
5786 EX_END_CATCH(SwallowAllExceptions);
5787
5788 return hr;
5789} // DacDbiInterfaceImpl::FastSanityCheckObject
5790
5791// Perform a sanity check on an object address to determine if this _could be_ a valid object.
5792// We can't tell this for certain without walking the GC heap, but we do some fast tests to rule
5793// out clearly invalid object addresses. See code:DacDbiInterfaceImpl::FastSanityCheckObject for more
5794// details.
5795// Arguments:
5796// input: objPtr - address of the object we are checking
5797// Return Value:
5798// objRefBad - true iff we have determined the address cannot be pointing to a valid object.
5799// Note that a value of false doesn't necessarily guarantee the object is really
5800// valid
5801bool DacDbiInterfaceImpl::CheckRef(PTR_Object objPtr)
5802{
5803 bool objRefBad = false;
5804
5805 // Shortcut null references now...
5806 if (objPtr == NULL)
5807 {
5808 LOG((LF_CORDB, LL_INFO10000, "D::GOI: ref is NULL.\n"));
5809
5810 objRefBad = true;
5811 }
5812 else
5813 {
5814 // Try to verify the integrity of the object. This is not fool proof.
5815 // @todo - this whole idea of expecting AVs is broken, but it does rule
5816 // out a fair bit of rubbish. Find another
5817 // way to test if the object is valid?
5818 if (FAILED(FastSanityCheckObject(objPtr)))
5819 {
5820 LOG((LF_CORDB, LL_INFO10000, "D::GOI: address is not a valid object.\n"));
5821
5822 objRefBad = true;
5823 }
5824 }
5825
5826 return objRefBad;
5827} // DacDbiInterfaceImpl::CheckRef
5828
5829// DacDbiInterfaceImpl::InitObjectData
5830// Initialize basic object information: type handle, object size, offset to fields and expanded type
5831// information.
5832// Arguments:
5833// input: objPtr - address of object of interest
5834// vmAppDomain - AppDomain for the type f the object
5835// output: pObjectData - object information
5836// Note: It is assumed that pObjectData is non-null.
5837void DacDbiInterfaceImpl::InitObjectData(PTR_Object objPtr,
5838 VMPTR_AppDomain vmAppDomain,
5839 DebuggerIPCE_ObjectData * pObjectData)
5840{
5841 _ASSERTE(pObjectData != NULL);
5842 // @todo - this is still dangerous because the object may still be invalid.
5843 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
5844 vmTypeHandle.SetDacTargetPtr(objPtr->GetGCSafeTypeHandle().AsTAddr());
5845
5846 // Save basic object info.
5847 pObjectData->objSize = objPtr->GetSize();
5848 pObjectData->objOffsetToVars = dac_cast<TADDR>((objPtr)->GetData()) - dac_cast<TADDR>(objPtr);
5849
5850 TypeHandleToExpandedTypeInfo(AllBoxed, vmAppDomain, vmTypeHandle, &(pObjectData->objTypeData));
5851
5852 // If this is a string object, set the type to ELEMENT_TYPE_STRING.
5853 if (objPtr->GetGCSafeMethodTable() == g_pStringClass)
5854 {
5855 pObjectData->objTypeData.elementType = ELEMENT_TYPE_STRING;
5856 if(pObjectData->objSize < MIN_OBJECT_SIZE)
5857 {
5858 pObjectData->objSize = PtrAlign(pObjectData->objSize);
5859 }
5860 }
5861} // DacDbiInterfaceImpl::InitObjectData
5862
5863// DAC/DBI API
5864
5865// Get object information for a TypedByRef object (System.TypedReference).
5866
5867// These are objects that contain a managed pointer to a location and the type of the value at that location.
5868// They are most commonly used for varargs but also may be used for parameters and locals. They are
5869// stack-allocated. They provide a means for adding dynamic type information to a value type, whereas boxing
5870// provides only static type information. This means they can be passed as reference parameters to
5871// polymorphic methods that don't statically restrict the type of arguments they can receive.
5872
5873// Although they are represented simply as an address, unlike other object references, they don't point
5874// directly to the object. Instead, there is an extra level of indirection. The reference points to a struct
5875// that contains the address of the object, so we need to treat them differently. They have their own
5876// CorElementType (ELEMENT_TYPE_TYPEDBYREF) which makes it possible to identify this special case.
5877
5878// Example:
5879// static int AddABunchOfInts (__arglist)
5880// {
5881// int result = 0;
5882//
5883// System.ArgIterator iter = new System.ArgIterator (__arglist);
5884// int argCount = iter.GetRemainingCount();
5885//
5886// for (int i = 0; i < argCount; i++)
5887// {
5888// System.TypedReference typedRef = iter.GetNextArg();
5889// result += (int)TypedReference.ToObject(typedRef);
5890// }
5891//
5892// return result;
5893// }
5894//
5895// static int Main (string[] args)
5896// {
5897// int result = AddABunchOfInts (__arglist (2, 3, 4));
5898// Console.WriteLine ("Answer: {0}", result);
5899//
5900// if (result != 9)
5901// return 1;
5902//
5903// return 0;
5904// }
5905
5906// Initializes the objRef and typedByRefType fields of pObjectData (type info for the referent).
5907void DacDbiInterfaceImpl::GetTypedByRefInfo(CORDB_ADDRESS pTypedByRef,
5908 VMPTR_AppDomain vmAppDomain,
5909 DebuggerIPCE_ObjectData * pObjectData)
5910{
5911 DD_ENTER_MAY_THROW;
5912
5913 // pTypedByRef is really the address of a TypedByRef struct rather than of a normal object.
5914 // The data field of the TypedByRef struct is the actual object ref.
5915 PTR_TypedByRef refAddr = PTR_TypedByRef(TADDR(pTypedByRef));
5916
5917 _ASSERTE(refAddr != NULL);
5918 _ASSERTE(pObjectData != NULL);
5919
5920 // The type of the referent is in the type field of the TypedByRef. We need to initialize the object
5921 // data type information.
5922 TypeHandleToBasicTypeInfo(refAddr->type,
5923 &(pObjectData->typedByrefInfo.typedByrefType),
5924 vmAppDomain.GetDacPtr());
5925
5926 // The reference to the object is in the data field of the TypedByRef.
5927 CORDB_ADDRESS tempRef = dac_cast<TADDR>(refAddr->data);
5928 pObjectData->objRef = CORDB_ADDRESS_TO_PTR(tempRef);
5929
5930 LOG((LF_CORDB, LL_INFO10000, "D::GASOI: sending REFANY result: "
5931 "ref=0x%08x, cls=0x%08x, mod=0x%p\n",
5932 pObjectData->objRef,
5933 pObjectData->typedByrefType.metadataToken,
5934 pObjectData->typedByrefType.vmDomainFile.GetDacPtr()));
5935} // DacDbiInterfaceImpl::GetTypedByRefInfo
5936
5937// Get the string data associated withn obj and put it into the pointers
5938// DAC/DBI API
5939// Get the string length and offset to string base for a string object
5940void DacDbiInterfaceImpl::GetStringData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData)
5941{
5942 DD_ENTER_MAY_THROW;
5943
5944 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
5945 LOG((LF_CORDB, LL_INFO10000, "D::GOI: The referent is a string.\n"));
5946
5947 if (objPtr->GetGCSafeMethodTable() != g_pStringClass)
5948 {
5949 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
5950 }
5951
5952 PTR_StringObject pStrObj = dac_cast<PTR_StringObject>(objPtr);
5953
5954 _ASSERTE(pStrObj != NULL);
5955 pObjectData->stringInfo.length = pStrObj->GetStringLength();
5956 pObjectData->stringInfo.offsetToStringBase = (UINT_PTR) pStrObj->GetBufferOffset();
5957
5958} // DacDbiInterfaceImpl::GetStringData
5959
5960
5961// DAC/DBI API
5962// Get information for an array type referent of an objRef, including rank, upper and lower
5963// bounds, element size and type, and the number of elements.
5964void DacDbiInterfaceImpl::GetArrayData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData)
5965{
5966 DD_ENTER_MAY_THROW;
5967
5968 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
5969 PTR_MethodTable pMT = objPtr->GetGCSafeMethodTable();
5970
5971 if (!objPtr->GetGCSafeTypeHandle().IsArray())
5972 {
5973 LOG((LF_CORDB, LL_INFO10000,
5974 "D::GASOI: object should be an array.\n"));
5975
5976 pObjectData->objRefBad = true;
5977 }
5978 else
5979 {
5980 PTR_ArrayBase arrPtr = dac_cast<PTR_ArrayBase>(objPtr);
5981
5982 // this is also returned in the type information for the array - we return both for sanity checking...
5983 pObjectData->arrayInfo.rank = arrPtr->GetRank();
5984 pObjectData->arrayInfo.componentCount = arrPtr->GetNumComponents();
5985 pObjectData->arrayInfo.offsetToArrayBase = arrPtr->GetDataPtrOffset(pMT);
5986
5987 if (arrPtr->IsMultiDimArray())
5988 {
5989 pObjectData->arrayInfo.offsetToUpperBounds = SIZE_T(arrPtr->GetBoundsOffset(pMT));
5990
5991 pObjectData->arrayInfo.offsetToLowerBounds = SIZE_T(arrPtr->GetLowerBoundsOffset(pMT));
5992 }
5993 else
5994 {
5995 pObjectData->arrayInfo.offsetToUpperBounds = 0;
5996 pObjectData->arrayInfo.offsetToLowerBounds = 0;
5997 }
5998
5999 pObjectData->arrayInfo.elementSize = arrPtr->GetComponentSize();
6000
6001 LOG((LF_CORDB, LL_INFO10000, "D::GOI: array info: "
6002 "baseOff=%d, lowerOff=%d, upperOff=%d, cnt=%d, rank=%d, rank (2) = %d,"
6003 "eleSize=%d, eleType=0x%02x\n",
6004 pObjectData->arrayInfo.offsetToArrayBase,
6005 pObjectData->arrayInfo.offsetToLowerBounds,
6006 pObjectData->arrayInfo.offsetToUpperBounds,
6007 pObjectData->arrayInfo.componentCount,
6008 pObjectData->arrayInfo.rank,
6009 pObjectData->objTypeData.ArrayTypeData.arrayRank,
6010 pObjectData->arrayInfo.elementSize,
6011 pObjectData->objTypeData.ArrayTypeData.arrayTypeArg.elementType));
6012 }
6013} // DacDbiInterfaceImpl::GetArrayData
6014
6015// DAC/DBI API: Get information about an object for which we have a reference, including the object size and
6016// type information.
6017void DacDbiInterfaceImpl::GetBasicObjectInfo(CORDB_ADDRESS objectAddress,
6018 CorElementType type,
6019 VMPTR_AppDomain vmAppDomain,
6020 DebuggerIPCE_ObjectData * pObjectData)
6021{
6022 DD_ENTER_MAY_THROW;
6023
6024 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
6025 pObjectData->objRefBad = CheckRef(objPtr);
6026 if (pObjectData->objRefBad != true)
6027 {
6028 // initialize object type, size, offset information. Note: We may have a different element type
6029 // after this. For example, we may start with E_T_CLASS but return with something more specific.
6030 InitObjectData (objPtr, vmAppDomain, pObjectData);
6031 }
6032} // DacDbiInterfaceImpl::GetBasicObjectInfo
6033
6034// This is the data passed to EnumerateBlockingObjectsCallback below
6035struct BlockingObjectUserDataWrapper
6036{
6037 CALLBACK_DATA pUserData;
6038 IDacDbiInterface::FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK fpCallback;
6039};
6040
6041// The callback helper used by EnumerateBlockingObjects below, this
6042// callback in turn invokes the user's callback with the right arguments
6043void EnumerateBlockingObjectsCallback(PTR_DebugBlockingItem obj, VOID* pUserData)
6044{
6045 BlockingObjectUserDataWrapper* wrapper = (BlockingObjectUserDataWrapper*)pUserData;
6046 DacBlockingObject dacObj;
6047
6048 // init to an arbitrary value to avoid mac compiler error about unintialized use
6049 // it will be correctly set in the switch and is never used with only this init here
6050 dacObj.blockingReason = DacBlockReason_MonitorCriticalSection;
6051
6052 dacObj.vmBlockingObject.SetDacTargetPtr(dac_cast<TADDR>(OBJECTREFToObject(obj->pMonitor->GetOwningObject())));
6053 dacObj.dwTimeout = obj->dwTimeout;
6054 dacObj.vmAppDomain.SetDacTargetPtr(dac_cast<TADDR>(obj->pAppDomain));
6055 switch(obj->type)
6056 {
6057 case DebugBlock_MonitorCriticalSection:
6058 dacObj.blockingReason = DacBlockReason_MonitorCriticalSection;
6059 break;
6060 case DebugBlock_MonitorEvent:
6061 dacObj.blockingReason = DacBlockReason_MonitorEvent;
6062 break;
6063 default:
6064 _ASSERTE(!"obj->type has an invalid value");
6065 return;
6066 }
6067
6068 wrapper->fpCallback(dacObj, wrapper->pUserData);
6069}
6070
6071// DAC/DBI API:
6072// Enumerate all monitors blocking a thread
6073void DacDbiInterfaceImpl::EnumerateBlockingObjects(VMPTR_Thread vmThread,
6074 FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK fpCallback,
6075 CALLBACK_DATA pUserData)
6076{
6077 DD_ENTER_MAY_THROW;
6078
6079 Thread * pThread = vmThread.GetDacPtr();
6080 _ASSERTE(pThread != NULL);
6081
6082 BlockingObjectUserDataWrapper wrapper;
6083 wrapper.fpCallback = fpCallback;
6084 wrapper.pUserData = pUserData;
6085
6086 pThread->DebugBlockingInfo.VisitBlockingItems((DebugBlockingItemVisitor)EnumerateBlockingObjectsCallback,
6087 (VOID*)&wrapper);
6088}
6089
6090// DAC/DBI API:
6091// Returns the thread which owns the monitor lock on an object and the acquisition count
6092MonitorLockInfo DacDbiInterfaceImpl::GetThreadOwningMonitorLock(VMPTR_Object vmObject)
6093{
6094 DD_ENTER_MAY_THROW;
6095 MonitorLockInfo info;
6096 info.lockOwner = VMPTR_Thread::NullPtr();
6097 info.acquisitionCount = 0;
6098
6099 Object* pObj = vmObject.GetDacPtr();
6100 DWORD threadId;
6101 DWORD acquisitionCount;
6102 if(!pObj->GetHeader()->GetThreadOwningMonitorLock(&threadId, &acquisitionCount))
6103 {
6104 return info;
6105 }
6106
6107 Thread *pThread = ThreadStore::GetThreadList(NULL);
6108 while (pThread != NULL)
6109 {
6110 if(pThread->GetThreadId() == threadId)
6111 {
6112 info.lockOwner.SetDacTargetPtr(PTR_HOST_TO_TADDR(pThread));
6113 info.acquisitionCount = acquisitionCount;
6114 return info;
6115 }
6116 pThread = ThreadStore::GetThreadList(pThread);
6117 }
6118 _ASSERTE(!"A thread should have been found");
6119 return info;
6120}
6121
6122// The data passed to EnumerateThreadsCallback below
6123struct ThreadUserDataWrapper
6124{
6125 CALLBACK_DATA pUserData;
6126 IDacDbiInterface::FP_THREAD_ENUMERATION_CALLBACK fpCallback;
6127};
6128
6129// The callback helper used for EnumerateMonitorEventWaitList below. This callback
6130// invokes the user's callback with the correct arguments.
6131void EnumerateThreadsCallback(PTR_Thread pThread, VOID* pUserData)
6132{
6133 ThreadUserDataWrapper* wrapper = (ThreadUserDataWrapper*)pUserData;
6134 VMPTR_Thread vmThread = VMPTR_Thread::NullPtr();
6135 vmThread.SetDacTargetPtr(dac_cast<TADDR>(pThread));
6136 wrapper->fpCallback(vmThread, wrapper->pUserData);
6137}
6138
6139// DAC/DBI API:
6140// Enumerate all threads waiting on the monitor event for an object
6141void DacDbiInterfaceImpl::EnumerateMonitorEventWaitList(VMPTR_Object vmObject,
6142 FP_THREAD_ENUMERATION_CALLBACK fpCallback,
6143 CALLBACK_DATA pUserData)
6144{
6145 DD_ENTER_MAY_THROW;
6146
6147 Object* pObj = vmObject.GetDacPtr();
6148 SyncBlock* psb = pObj->PassiveGetSyncBlock();
6149
6150 // no sync block means no wait list
6151 if(psb == NULL)
6152 return;
6153
6154 ThreadUserDataWrapper wrapper;
6155 wrapper.fpCallback = fpCallback;
6156 wrapper.pUserData = pUserData;
6157 ThreadQueue::EnumerateThreads(psb, (FP_TQ_THREAD_ENUMERATION_CALLBACK)EnumerateThreadsCallback, (VOID*) &wrapper);
6158}
6159
6160
6161bool DacDbiInterfaceImpl::AreGCStructuresValid()
6162{
6163 return true;
6164}
6165
6166HeapData::HeapData()
6167 : YoungestGenPtr(0), YoungestGenLimit(0), Gen0Start(0), Gen0End(0), SegmentCount(0), Segments(0)
6168{
6169}
6170
6171HeapData::~HeapData()
6172{
6173 if (Segments)
6174 delete [] Segments;
6175}
6176
6177LinearReadCache::LinearReadCache()
6178 : mCurrPageStart(0), mPageSize(0), mCurrPageSize(0), mPage(0)
6179{
6180 SYSTEM_INFO si;
6181 GetSystemInfo(&si);
6182
6183 mPageSize = si.dwPageSize;
6184 mPage = new (nothrow) BYTE[mPageSize];
6185}
6186
6187LinearReadCache::~LinearReadCache()
6188{
6189 if (mPage)
6190 delete [] mPage;
6191}
6192
6193bool LinearReadCache::MoveToPage(CORDB_ADDRESS addr)
6194{
6195 mCurrPageStart = addr - (addr % mPageSize);
6196 HRESULT hr = g_dacImpl->m_pTarget->ReadVirtual(mCurrPageStart, mPage, mPageSize, &mCurrPageSize);
6197
6198 if (hr != S_OK)
6199 {
6200 mCurrPageStart = 0;
6201 mCurrPageSize = 0;
6202 return false;
6203 }
6204
6205 return true;
6206}
6207
6208
6209CORDB_ADDRESS DacHeapWalker::HeapStart = 0;
6210CORDB_ADDRESS DacHeapWalker::HeapEnd = ~0;
6211
6212DacHeapWalker::DacHeapWalker()
6213 : mThreadCount(0), mAllocInfo(0), mHeapCount(0), mHeaps(0),
6214 mCurrObj(0), mCurrSize(0), mCurrMT(0),
6215 mCurrHeap(0), mCurrSeg(0), mStart((TADDR)HeapStart), mEnd((TADDR)HeapEnd)
6216{
6217}
6218
6219DacHeapWalker::~DacHeapWalker()
6220{
6221 if (mAllocInfo)
6222 delete [] mAllocInfo;
6223
6224 if (mHeaps)
6225 delete [] mHeaps;
6226}
6227
6228SegmentData *DacHeapWalker::FindSegment(CORDB_ADDRESS obj)
6229{
6230 for (size_t i = 0; i < mHeapCount; ++i)
6231 for (size_t j = 0; j < mHeaps[i].SegmentCount; ++j)
6232 if (mHeaps[i].Segments[j].Start <= obj && obj <= mHeaps[i].Segments[j].End)
6233 return &mHeaps[i].Segments[j];
6234
6235 return NULL;
6236}
6237
6238HRESULT DacHeapWalker::Next(CORDB_ADDRESS *pValue, CORDB_ADDRESS *pMT, ULONG64 *pSize)
6239{
6240 if (!HasMoreObjects())
6241 return E_FAIL;
6242
6243 if (pValue)
6244 *pValue = mCurrObj;
6245
6246 if (pMT)
6247 *pMT = (CORDB_ADDRESS)mCurrMT;
6248
6249 if (pSize)
6250 *pSize = (ULONG64)mCurrSize;
6251
6252 HRESULT hr = MoveToNextObject();
6253 return FAILED(hr) ? hr : S_OK;
6254}
6255
6256
6257
6258HRESULT DacHeapWalker::MoveToNextObject()
6259{
6260 do
6261 {
6262 // Move to the next object
6263 mCurrObj += mCurrSize;
6264
6265 // Check to see if we are in the correct bounds.
6266 if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
6267 CheckAllocAndSegmentRange();
6268
6269 // Check to see if we've moved off the end of a segment
6270 if (mCurrObj >= mHeaps[mCurrHeap].Segments[mCurrSeg].End || mCurrObj > mEnd)
6271 {
6272 HRESULT hr = NextSegment();
6273 if (FAILED(hr) || hr == S_FALSE)
6274 return hr;
6275 }
6276
6277 // Get the method table pointer
6278 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6279 return E_FAIL;
6280
6281 if (!GetSize(mCurrMT, mCurrSize))
6282 return E_FAIL;
6283 } while (mCurrObj < mStart);
6284
6285 _ASSERTE(mStart <= mCurrObj && mCurrObj <= mEnd);
6286 return S_OK;
6287}
6288
6289bool DacHeapWalker::GetSize(TADDR tMT, size_t &size)
6290{
6291 // With heap corruption, it's entierly possible that the MethodTable
6292 // we get is bad. This could cause exceptions, which we will catch
6293 // and return false. This causes the heapwalker to move to the next
6294 // segment.
6295 bool ret = true;
6296 EX_TRY
6297 {
6298 MethodTable *mt = PTR_MethodTable(tMT);
6299 size_t cs = mt->GetComponentSize();
6300
6301 if (cs)
6302 {
6303 DWORD tmp = 0;
6304 if (mCache.Read(mCurrObj+sizeof(TADDR), &tmp))
6305 cs *= tmp;
6306 else
6307 ret = false;
6308 }
6309
6310 size = mt->GetBaseSize() + cs;
6311
6312 // The size is not guaranteed to be aligned, we have to
6313 // do that ourself.
6314 if (mHeaps[mCurrHeap].Segments[mCurrSeg].Generation == 3)
6315 size = AlignLarge(size);
6316 else
6317 size = Align(size);
6318 }
6319 EX_CATCH
6320 {
6321 ret = false;
6322 }
6323 EX_END_CATCH(SwallowAllExceptions)
6324
6325 return ret;
6326}
6327
6328
6329HRESULT DacHeapWalker::NextSegment()
6330{
6331 mCurrObj = 0;
6332 mCurrMT = 0;
6333 mCurrSize = 0;
6334
6335 do
6336 {
6337 mCurrSeg++;
6338 while (mCurrSeg >= mHeaps[mCurrHeap].SegmentCount)
6339 {
6340 mCurrSeg = 0;
6341 mCurrHeap++;
6342
6343 if (mCurrHeap >= mHeapCount)
6344 {
6345 return S_FALSE;
6346 }
6347 }
6348
6349 mCurrObj = mHeaps[mCurrHeap].Segments[mCurrSeg].Start;
6350
6351 if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
6352 CheckAllocAndSegmentRange();
6353
6354 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6355 {
6356 return E_FAIL;
6357 }
6358
6359 if (!GetSize(mCurrMT, mCurrSize))
6360 {
6361 return E_FAIL;
6362 }
6363 } while((mHeaps[mCurrHeap].Segments[mCurrSeg].Start > mEnd) || (mHeaps[mCurrHeap].Segments[mCurrSeg].End < mStart));
6364
6365 return S_OK;
6366}
6367
6368void DacHeapWalker::CheckAllocAndSegmentRange()
6369{
6370 const size_t MinObjSize = sizeof(TADDR)*3;
6371
6372 for (int i = 0; i < mThreadCount; ++i)
6373 if (mCurrObj == mAllocInfo[i].Ptr)
6374 {
6375 mCurrObj = mAllocInfo[i].Limit + Align(MinObjSize);
6376 break;
6377 }
6378
6379 if (mCurrObj == mHeaps[mCurrHeap].YoungestGenPtr)
6380 {
6381 mCurrObj = mHeaps[mCurrHeap].YoungestGenLimit + Align(MinObjSize);
6382 }
6383}
6384
6385HRESULT DacHeapWalker::Init(CORDB_ADDRESS start, CORDB_ADDRESS end)
6386{
6387 // Collect information about the allocation contexts in the process.
6388 ThreadStore* threadStore = ThreadStore::s_pThreadStore;
6389 if (threadStore != NULL)
6390 {
6391 int count = (int)threadStore->ThreadCountInEE();
6392 mAllocInfo = new (nothrow) AllocInfo[count];
6393 if (mAllocInfo == NULL)
6394 return E_OUTOFMEMORY;
6395
6396 Thread *thread = NULL;
6397 int j = 0;
6398 for (int i = 0; i < count; ++i)
6399 {
6400 // The thread or allocation context being null is troubling, but not fatal.
6401 // We may have stopped the process where the thread list or thread's alloc
6402 // context was in an inconsistent state. We will simply skip over affected
6403 // segments during the heap walk if we encounter problems due to this.
6404 thread = ThreadStore::GetThreadList(thread);
6405 if (thread == NULL)
6406 continue;
6407
6408 gc_alloc_context *ctx = thread->GetAllocContext();
6409 if (ctx == NULL)
6410 continue;
6411
6412 if ((CORDB_ADDRESS)ctx->alloc_ptr != NULL)
6413 {
6414 mAllocInfo[j].Ptr = (CORDB_ADDRESS)ctx->alloc_ptr;
6415 mAllocInfo[j].Limit = (CORDB_ADDRESS)ctx->alloc_limit;
6416 j++;
6417 }
6418 }
6419
6420 mThreadCount = j;
6421 }
6422
6423#ifdef FEATURE_SVR_GC
6424 HRESULT hr = GCHeapUtilities::IsServerHeap() ? InitHeapDataSvr(mHeaps, mHeapCount) : InitHeapDataWks(mHeaps, mHeapCount);
6425#else
6426 HRESULT hr = InitHeapDataWks(mHeaps, mHeapCount);
6427#endif
6428
6429 // Set up mCurrObj/mCurrMT.
6430 if (SUCCEEDED(hr))
6431 hr = Reset(start, end);
6432
6433 // Collect information about GC heaps
6434 return hr;
6435}
6436
6437HRESULT DacHeapWalker::Reset(CORDB_ADDRESS start, CORDB_ADDRESS end)
6438{
6439 _ASSERTE(mHeaps);
6440 _ASSERTE(mHeapCount > 0);
6441 _ASSERTE(mHeaps[0].Segments);
6442 _ASSERTE(mHeaps[0].SegmentCount > 0);
6443
6444 mStart = start;
6445 mEnd = end;
6446
6447 // Set up first object
6448 mCurrObj = mHeaps[0].Segments[0].Start;
6449 mCurrMT = 0;
6450 mCurrSize = 0;
6451 mCurrHeap = 0;
6452 mCurrSeg = 0;
6453
6454 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6455 return E_FAIL;
6456
6457 if (!GetSize(mCurrMT, mCurrSize))
6458 return E_FAIL;
6459
6460 if (mCurrObj < mStart || mCurrObj > mEnd)
6461 MoveToNextObject();
6462
6463 return S_OK;
6464}
6465
6466HRESULT DacHeapWalker::ListNearObjects(CORDB_ADDRESS obj, CORDB_ADDRESS *pPrev, CORDB_ADDRESS *pContaining, CORDB_ADDRESS *pNext)
6467{
6468 SegmentData *seg = FindSegment(obj);
6469
6470 if (seg == NULL)
6471 return E_FAIL;
6472
6473 HRESULT hr = Reset(seg->Start, seg->End);
6474 if (SUCCEEDED(hr))
6475 {
6476 CORDB_ADDRESS prev = 0;
6477 CORDB_ADDRESS curr = 0;
6478 ULONG64 size = 0;
6479 bool found = false;
6480
6481 while (!found && HasMoreObjects())
6482 {
6483 prev = curr;
6484 hr = Next(&curr, NULL, &size);
6485 if (FAILED(hr))
6486 break;
6487
6488 if (obj >= curr && obj < curr + size)
6489 found = true;
6490 }
6491
6492 if (found)
6493 {
6494 if (pPrev)
6495 *pPrev = prev;
6496
6497 if (pContaining)
6498 *pContaining = curr;
6499
6500 if (pNext)
6501 {
6502 if (HasMoreObjects())
6503 {
6504 hr = Next(&curr, NULL, NULL);
6505 if (SUCCEEDED(hr))
6506 *pNext = curr;
6507 }
6508 else
6509 {
6510 *pNext = 0;
6511 }
6512 }
6513
6514 hr = S_OK;
6515 }
6516 else if (SUCCEEDED(hr))
6517 {
6518 hr = E_FAIL;
6519 }
6520 }
6521
6522 return hr;
6523}
6524
6525HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
6526{
6527 // Scrape basic heap details
6528 pCount = 1;
6529 pHeaps = new (nothrow) HeapData[1];
6530 if (pHeaps == NULL)
6531 return E_OUTOFMEMORY;
6532
6533 dac_generation gen0 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 0);
6534 dac_generation gen1 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 1);
6535 dac_generation gen2 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 2);
6536 dac_generation loh = *GenerationTableIndex(g_gcDacGlobals->generation_table, 3);
6537 pHeaps[0].YoungestGenPtr = (CORDB_ADDRESS)gen0.allocation_context.alloc_ptr;
6538 pHeaps[0].YoungestGenLimit = (CORDB_ADDRESS)gen0.allocation_context.alloc_limit;
6539
6540 pHeaps[0].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
6541 pHeaps[0].Gen0End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
6542 pHeaps[0].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
6543
6544 // Segments
6545 int count = GetSegmentCount(loh.start_segment);
6546 count += GetSegmentCount(gen2.start_segment);
6547
6548 pHeaps[0].SegmentCount = count;
6549 pHeaps[0].Segments = new (nothrow) SegmentData[count];
6550 if (pHeaps[0].Segments == NULL)
6551 return E_OUTOFMEMORY;
6552
6553 // Small object heap segments
6554 DPTR(dac_heap_segment) seg = gen2.start_segment;
6555 int i = 0;
6556 for (; seg && (i < count); ++i)
6557 {
6558 pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
6559 if (seg.GetAddr() == (TADDR)*g_gcDacGlobals->ephemeral_heap_segment)
6560 {
6561 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
6562 pHeaps[0].Segments[i].Generation = 1;
6563 pHeaps[0].EphemeralSegment = i;
6564 }
6565 else
6566 {
6567 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
6568 pHeaps[0].Segments[i].Generation = 2;
6569 }
6570
6571 seg = seg->next;
6572 }
6573
6574 // Large object heap segments
6575 seg = loh.start_segment;
6576 for (; seg && (i < count); ++i)
6577 {
6578 pHeaps[0].Segments[i].Generation = 3;
6579 pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
6580 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
6581
6582 seg = seg->next;
6583 }
6584
6585 return S_OK;
6586}
6587
6588 HRESULT DacDbiInterfaceImpl::CreateHeapWalk(IDacDbiInterface::HeapWalkHandle *pHandle)
6589{
6590 DD_ENTER_MAY_THROW;
6591
6592 DacHeapWalker *data = new (nothrow) DacHeapWalker;
6593 if (data == NULL)
6594 return E_OUTOFMEMORY;
6595
6596 HRESULT hr = data->Init();
6597 if (SUCCEEDED(hr))
6598 *pHandle = reinterpret_cast<HeapWalkHandle>(data);
6599 else
6600 delete data;
6601
6602 return hr;
6603}
6604
6605void DacDbiInterfaceImpl::DeleteHeapWalk(HeapWalkHandle handle)
6606{
6607 DD_ENTER_MAY_THROW;
6608
6609 DacHeapWalker *data = reinterpret_cast<DacHeapWalker*>(handle);
6610 if (data)
6611 delete data;
6612}
6613
6614HRESULT DacDbiInterfaceImpl::WalkHeap(HeapWalkHandle handle,
6615 ULONG count,
6616 OUT COR_HEAPOBJECT * objects,
6617 OUT ULONG *fetched)
6618{
6619 DD_ENTER_MAY_THROW;
6620 if (fetched == NULL)
6621 return E_INVALIDARG;
6622
6623 DacHeapWalker *walk = reinterpret_cast<DacHeapWalker*>(handle);
6624 *fetched = 0;
6625
6626 if (!walk->HasMoreObjects())
6627 return S_FALSE;
6628
6629 CORDB_ADDRESS freeMT = (CORDB_ADDRESS)g_pFreeObjectMethodTable.GetAddr();
6630
6631 HRESULT hr = S_OK;
6632 CORDB_ADDRESS addr, mt;
6633 ULONG64 size;
6634
6635 ULONG i = 0;
6636 while (i < count && walk->HasMoreObjects())
6637 {
6638 hr = walk->Next(&addr, &mt, &size);
6639
6640 if (FAILED(hr))
6641 break;
6642
6643 if (mt != freeMT)
6644 {
6645 objects[i].address = addr;
6646 objects[i].type.token1 = mt;
6647 objects[i].type.token2 = NULL;
6648 objects[i].size = size;
6649 i++;
6650 }
6651 }
6652
6653 if (SUCCEEDED(hr))
6654 hr = (i < count) ? S_FALSE : S_OK;
6655
6656 *fetched = i;
6657 return hr;
6658}
6659
6660
6661
6662HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *pSegments)
6663{
6664 DD_ENTER_MAY_THROW;
6665
6666
6667 size_t heapCount = 0;
6668 HeapData *heaps = 0;
6669
6670#ifdef FEATURE_SVR_GC
6671 HRESULT hr = GCHeapUtilities::IsServerHeap() ? DacHeapWalker::InitHeapDataSvr(heaps, heapCount) : DacHeapWalker::InitHeapDataWks(heaps, heapCount);
6672#else
6673 HRESULT hr = DacHeapWalker::InitHeapDataWks(heaps, heapCount);
6674#endif
6675
6676 NewArrayHolder<HeapData> _heapHolder = heaps;
6677
6678 // Count the number of segments to know how much to allocate.
6679 int total = 0;
6680 for (size_t i = 0; i < heapCount; ++i)
6681 {
6682 // SegmentCount is +1 due to the ephemeral segment containing more than one
6683 // generation (Gen1 + Gen0, and sometimes part of Gen2).
6684 total += (int)heaps[i].SegmentCount + 1;
6685
6686 // It's possible that part of Gen2 lives on the ephemeral segment. If so,
6687 // we need to add one more to the output.
6688 const size_t eph = heaps[i].EphemeralSegment;
6689 _ASSERTE(eph < heaps[i].SegmentCount);
6690 if (heaps[i].Segments[eph].Start != heaps[i].Gen1Start)
6691 total++;
6692 }
6693
6694 pSegments->Alloc(total);
6695
6696 // Now walk all segments and write them to the array.
6697 int curr = 0;
6698 for (size_t i = 0; i < heapCount; ++i)
6699 {
6700 // Generation 0 is not in the segment list.
6701 _ASSERTE(curr < total);
6702 {
6703 COR_SEGMENT &seg = (*pSegments)[curr++];
6704 seg.start = heaps[i].Gen0Start;
6705 seg.end = heaps[i].Gen0End;
6706 seg.type = CorDebug_Gen0;
6707 seg.heap = (ULONG)i;
6708 }
6709
6710 for (size_t j = 0; j < heaps[i].SegmentCount; ++j)
6711 {
6712 if (heaps[i].Segments[j].Generation == 1)
6713 {
6714 // This is the ephemeral segment. We have already written Gen0,
6715 // now write Gen1.
6716 _ASSERTE(heaps[i].Segments[j].Start <= heaps[i].Gen1Start);
6717 _ASSERTE(heaps[i].Segments[j].End > heaps[i].Gen1Start);
6718
6719 {
6720 _ASSERTE(curr < total);
6721 COR_SEGMENT &seg = (*pSegments)[curr++];
6722 seg.start = heaps[i].Gen1Start;
6723 seg.end = heaps[i].Gen0Start;
6724 seg.type = CorDebug_Gen1;
6725 seg.heap = (ULONG)i;
6726 }
6727
6728 // It's possible for Gen2 to take up a portion of the ephemeral segment.
6729 // We test for that here.
6730 if (heaps[i].Segments[j].Start != heaps[i].Gen1Start)
6731 {
6732 _ASSERTE(curr < total);
6733 COR_SEGMENT &seg = (*pSegments)[curr++];
6734 seg.start = heaps[i].Segments[j].Start;
6735 seg.end = heaps[i].Gen1Start;
6736 seg.type = CorDebug_Gen2;
6737 seg.heap = (ULONG)i;
6738 }
6739 }
6740 else
6741 {
6742 // Otherwise, we have a gen2 or gen3 (LOH) segment
6743 _ASSERTE(curr < total);
6744 COR_SEGMENT &seg = (*pSegments)[curr++];
6745 seg.start = heaps[i].Segments[j].Start;
6746 seg.end = heaps[i].Segments[j].End;
6747
6748 _ASSERTE(heaps[i].Segments[j].Generation <= CorDebug_LOH);
6749 seg.type = (CorDebugGenerationTypes)heaps[i].Segments[j].Generation;
6750 seg.heap = (ULONG)i;
6751 }
6752 }
6753 }
6754
6755 _ASSERTE(total == curr);
6756 return hr;
6757}
6758
6759bool DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS addr)
6760{
6761 DD_ENTER_MAY_THROW;
6762
6763 bool isValid = false;
6764
6765 if (addr != 0 && addr != (CORDB_ADDRESS)-1)
6766 {
6767 EX_TRY
6768 {
6769 PTR_Object obj(TO_TADDR(addr));
6770
6771 PTR_MethodTable mt = obj->GetMethodTable();
6772 PTR_EEClass cls = mt->GetClass();
6773
6774 if (mt == cls->GetMethodTable())
6775 isValid = true;
6776 else if (!mt->IsCanonicalMethodTable())
6777 isValid = cls->GetMethodTable()->GetClass() == cls;
6778 }
6779 EX_CATCH
6780 {
6781 isValid = false;
6782 }
6783 EX_END_CATCH(SwallowAllExceptions)
6784 }
6785
6786 return isValid;
6787}
6788
6789bool DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS addr, OUT VMPTR_AppDomain * pAppDomain,
6790 OUT VMPTR_Module *pModule, OUT VMPTR_DomainFile *pDomainFile)
6791{
6792 DD_ENTER_MAY_THROW;
6793
6794 if (addr == 0 || addr == (CORDB_ADDRESS)-1)
6795 {
6796 return false;
6797 }
6798
6799 PTR_Object obj(TO_TADDR(addr));
6800 MethodTable *mt = obj->GetMethodTable();
6801
6802 PTR_Module module = mt->GetModule();
6803 PTR_Assembly assembly = module->GetAssembly();
6804 BaseDomain *baseDomain = assembly->GetDomain();
6805
6806 if (baseDomain->IsAppDomain())
6807 {
6808 pAppDomain->SetDacTargetPtr(PTR_HOST_TO_TADDR(baseDomain->AsAppDomain()));
6809 pModule->SetDacTargetPtr(PTR_HOST_TO_TADDR(module));
6810 pDomainFile->SetDacTargetPtr(PTR_HOST_TO_TADDR(module->GetDomainFile(baseDomain->AsAppDomain())));
6811 }
6812 else
6813 {
6814 return false;
6815 }
6816
6817 return true;
6818}
6819
6820HRESULT DacDbiInterfaceImpl::CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask)
6821{
6822 DD_ENTER_MAY_THROW;
6823
6824 DacRefWalker *walker = new (nothrow) DacRefWalker(this, walkStacks, walkFQ, handleWalkMask);
6825
6826 if (walker == NULL)
6827 return E_OUTOFMEMORY;
6828
6829 HRESULT hr = walker->Init();
6830 if (FAILED(hr))
6831 {
6832 delete walker;
6833 }
6834 else
6835 {
6836 *pHandle = reinterpret_cast<RefWalkHandle>(walker);
6837 }
6838
6839 return hr;
6840}
6841
6842
6843void DacDbiInterfaceImpl::DeleteRefWalk(IN RefWalkHandle handle)
6844{
6845 DD_ENTER_MAY_THROW;
6846
6847 DacRefWalker *walker = reinterpret_cast<DacRefWalker*>(handle);
6848
6849 if (walker)
6850 delete walker;
6851}
6852
6853
6854HRESULT DacDbiInterfaceImpl::WalkRefs(RefWalkHandle handle, ULONG count, OUT DacGcReference * objects, OUT ULONG *pFetched)
6855{
6856 if (objects == NULL || pFetched == NULL)
6857 return E_POINTER;
6858
6859 DD_ENTER_MAY_THROW;
6860
6861 DacRefWalker *walker = reinterpret_cast<DacRefWalker*>(handle);
6862 if (!walker)
6863 return E_INVALIDARG;
6864
6865 return walker->Next(count, objects, pFetched);
6866}
6867
6868HRESULT DacDbiInterfaceImpl::GetTypeID(CORDB_ADDRESS dbgObj, COR_TYPEID *pID)
6869{
6870 DD_ENTER_MAY_THROW;
6871
6872 TADDR obj[3];
6873 ULONG32 read = 0;
6874 HRESULT hr = g_dacImpl->m_pTarget->ReadVirtual(dbgObj, (BYTE*)obj, sizeof(obj), &read);
6875 if (FAILED(hr))
6876 return hr;
6877
6878 pID->token1 = (UINT64)(obj[0] & ~1);
6879 pID->token2 = 0;
6880
6881 return hr;
6882}
6883
6884HRESULT DacDbiInterfaceImpl::GetTypeIDForType(VMPTR_TypeHandle vmTypeHandle, COR_TYPEID *pID)
6885{
6886 DD_ENTER_MAY_THROW;
6887
6888 _ASSERTE(pID != NULL);
6889 _ASSERTE(!vmTypeHandle.IsNull());
6890
6891 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
6892 PTR_MethodTable pMT = th.GetMethodTable();
6893 pID->token1 = pMT.GetAddr();
6894 _ASSERTE(pID->token1 != 0);
6895 pID->token2 = 0;
6896 return S_OK;
6897}
6898
6899HRESULT DacDbiInterfaceImpl::GetObjectFields(COR_TYPEID id, ULONG32 celt, COR_FIELD *layout, ULONG32 *pceltFetched)
6900{
6901 if (layout == NULL || pceltFetched == NULL)
6902 return E_POINTER;
6903
6904 if (id.token1 == 0)
6905 return CORDBG_E_CLASS_NOT_LOADED;
6906
6907 DD_ENTER_MAY_THROW;
6908
6909 HRESULT hr = S_OK;
6910
6911 TypeHandle typeHandle = TypeHandle::FromPtr(TO_TADDR(id.token1));
6912
6913 if (typeHandle.IsTypeDesc())
6914 return E_INVALIDARG;
6915
6916 ApproxFieldDescIterator fieldDescIterator(typeHandle.AsMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
6917
6918 ULONG32 cFields = fieldDescIterator.Count();
6919
6920 // Handle case where user only wanted to know the number of fields.
6921 if (layout == NULL)
6922 {
6923 *pceltFetched = cFields;
6924 return S_FALSE;
6925 }
6926
6927 if (celt < cFields)
6928 {
6929 cFields = celt;
6930
6931 // we are returning less than the total
6932 hr = S_FALSE;
6933 }
6934
6935 // This must be non-null due to check at beginning of function.
6936 *pceltFetched = celt;
6937
6938 CorElementType componentType = typeHandle.AsMethodTable()->GetInternalCorElementType();
6939 BOOL fReferenceType = CorTypeInfo::IsObjRef_NoThrow(componentType);
6940 for (ULONG32 i = 0; i < cFields; ++i)
6941 {
6942 FieldDesc *pField = fieldDescIterator.Next();
6943 layout[i].token = pField->GetMemberDef();
6944 layout[i].offset = (ULONG32)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
6945
6946 TypeHandle fieldHandle = pField->LookupFieldTypeHandle();
6947
6948 if (fieldHandle.IsNull())
6949 {
6950 layout[i].id.token1 = 0;
6951 layout[i].id.token2 = 0;
6952 layout[i].fieldType = (CorElementType)0;
6953 }
6954 else
6955 {
6956 PTR_MethodTable mt = fieldHandle.GetMethodTable();
6957 layout[i].fieldType = mt->GetInternalCorElementType();
6958 layout[i].id.token1 = (ULONG64)mt.GetAddr();
6959
6960 if (!mt->IsArray())
6961 {
6962 layout[i].id.token2 = 0;
6963 }
6964 else
6965 {
6966 TypeHandle hnd = mt->GetApproxArrayElementTypeHandle();
6967 PTR_MethodTable cmt = hnd.GetMethodTable();
6968 layout[i].id.token2 = (ULONG64)cmt.GetAddr();
6969 }
6970 }
6971 }
6972
6973 return hr;
6974}
6975
6976
6977HRESULT DacDbiInterfaceImpl::GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout)
6978{
6979 if (pLayout == NULL)
6980 return E_POINTER;
6981
6982 if (id.token1 == 0)
6983 return CORDBG_E_CLASS_NOT_LOADED;
6984
6985 DD_ENTER_MAY_THROW;
6986
6987 PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
6988 PTR_MethodTable parentMT = mt->GetParentMethodTable();
6989
6990 COR_TYPEID parent = {parentMT.GetAddr(), 0};
6991 pLayout->parentID = parent;
6992
6993 DWORD size = mt->GetBaseSize();
6994 ApproxFieldDescIterator fieldDescIterator(mt, ApproxFieldDescIterator::INSTANCE_FIELDS);
6995
6996 pLayout->objectSize = size;
6997 pLayout->numFields = fieldDescIterator.Count();
6998
6999 // Get type
7000 CorElementType componentType = mt->IsString() ? ELEMENT_TYPE_STRING : mt->GetInternalCorElementType();
7001 pLayout->type = componentType;
7002 pLayout->boxOffset = CorTypeInfo::IsObjRef_NoThrow(componentType) ? 0 : sizeof(TADDR);
7003
7004 return S_OK;
7005}
7006
7007HRESULT DacDbiInterfaceImpl::GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout)
7008{
7009 if (pLayout == NULL)
7010 return E_POINTER;
7011
7012 if (id.token1 == 0)
7013 return CORDBG_E_CLASS_NOT_LOADED;
7014
7015 DD_ENTER_MAY_THROW;
7016
7017 PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
7018
7019 if (!mt->IsStringOrArray())
7020 return E_INVALIDARG;
7021
7022 if (mt->IsString())
7023 {
7024 COR_TYPEID token;
7025 token.token1 = MscorlibBinder::GetElementType(ELEMENT_TYPE_CHAR).GetAddr();
7026 token.token2 = 0;
7027
7028 pLayout->componentID = token;
7029
7030 pLayout->rankSize = 4;
7031 pLayout->numRanks = 1;
7032 pLayout->rankOffset = sizeof(TADDR);
7033 pLayout->firstElementOffset = sizeof(TADDR) + 4;
7034 pLayout->countOffset = sizeof(TADDR);
7035 pLayout->componentType = ELEMENT_TYPE_CHAR;
7036 pLayout->elementSize = 2;
7037 }
7038 else
7039 {
7040 DWORD ranks = mt->GetRank();
7041 pLayout->rankSize = 4;
7042 pLayout->numRanks = ranks;
7043 bool multiDim = (ranks > 1);
7044
7045 pLayout->rankOffset = multiDim ? sizeof(TADDR)*2 : sizeof(TADDR);
7046 pLayout->countOffset = sizeof(TADDR);
7047 pLayout->firstElementOffset = ArrayBase::GetDataPtrOffset(mt);
7048
7049
7050 TypeHandle hnd = mt->GetApproxArrayElementTypeHandle();
7051 PTR_MethodTable cmt = hnd.GetMethodTable();
7052
7053 CorElementType componentType = cmt->GetInternalCorElementType();
7054 if ((UINT64)cmt.GetAddr() == (UINT64)g_pStringClass.GetAddr())
7055 componentType = ELEMENT_TYPE_STRING;
7056
7057 COR_TYPEID token;
7058 token.token1 = cmt.GetAddr(); // This could be type handle
7059 token.token2 = 0;
7060 pLayout->componentID = token;
7061 pLayout->componentType = componentType;
7062
7063 if (CorTypeInfo::IsObjRef_NoThrow(componentType))
7064 pLayout->elementSize = sizeof(TADDR);
7065 else if (CorIsPrimitiveType(componentType))
7066 pLayout->elementSize = gElementTypeInfo[componentType].m_cbSize;
7067 else
7068 pLayout->elementSize = cmt->GetNumInstanceFieldBytes();
7069 }
7070
7071 return S_OK;
7072}
7073
7074
7075void DacDbiInterfaceImpl::GetGCHeapInformation(COR_HEAPINFO * pHeapInfo)
7076{
7077 DD_ENTER_MAY_THROW;
7078
7079 size_t heapCount = 0;
7080 pHeapInfo->areGCStructuresValid = *g_gcDacGlobals->gc_structures_invalid_cnt == 0;
7081
7082#ifdef FEATURE_SVR_GC
7083 if (GCHeapUtilities::IsServerHeap())
7084 {
7085 pHeapInfo->gcType = CorDebugServerGC;
7086 pHeapInfo->numHeaps = DacGetNumHeaps();
7087 }
7088 else
7089#endif
7090 {
7091 pHeapInfo->gcType = CorDebugWorkstationGC;
7092 pHeapInfo->numHeaps = 1;
7093 }
7094
7095 pHeapInfo->pointerSize = sizeof(TADDR);
7096 pHeapInfo->concurrent = g_pConfig->GetGCconcurrent() ? TRUE : FALSE;
7097}
7098
7099
7100HRESULT DacDbiInterfaceImpl::GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW)
7101{
7102 DD_ENTER_MAY_THROW;
7103 if (pAddrMDInternalRW == NULL)
7104 return E_INVALIDARG;
7105 PEFile * pPEFile = vmPEFile.GetDacPtr();
7106 *pAddrMDInternalRW = pPEFile->GetMDInternalRWAddress();
7107 return S_OK;
7108}
7109
7110HRESULT DacDbiInterfaceImpl::GetReJitInfo(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ReJitInfo* pvmReJitInfo)
7111{
7112 DD_ENTER_MAY_THROW;
7113 _ASSERTE(!"You shouldn't be calling this - use GetActiveRejitILCodeVersionNode instead");
7114 return S_OK;
7115}
7116
7117HRESULT DacDbiInterfaceImpl::GetActiveRejitILCodeVersionNode(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ILCodeVersionNode* pVmILCodeVersionNode)
7118{
7119 DD_ENTER_MAY_THROW;
7120 if (pVmILCodeVersionNode == NULL)
7121 return E_INVALIDARG;
7122#ifdef FEATURE_REJIT
7123 PTR_Module pModule = vmModule.GetDacPtr();
7124 CodeVersionManager * pCodeVersionManager = pModule->GetCodeVersionManager();
7125 // Be careful, there are two different definitions of 'active' being used here
7126 // For the CodeVersionManager, the active IL version is whatever one should be used in the next invocation of the method
7127 // 'rejit active' narrows that to only include rejit IL bodies where the profiler has already provided the definition
7128 // for the new IL (ilCodeVersion.GetRejitState()==ILCodeVersion::kStateActive). It is possible that the code version
7129 // manager's active IL version hasn't yet asked the profiler for the IL body to use, in which case we want to filter it
7130 // out from the return in this method.
7131 ILCodeVersion activeILVersion = pCodeVersionManager->GetActiveILCodeVersion(pModule, methodTk);
7132 if (activeILVersion.IsNull() || activeILVersion.IsDefaultVersion() || activeILVersion.GetRejitState() != ILCodeVersion::kStateActive)
7133 {
7134 pVmILCodeVersionNode->SetDacTargetPtr(0);
7135 }
7136 else
7137 {
7138 pVmILCodeVersionNode->SetDacTargetPtr(PTR_TO_TADDR(activeILVersion.AsNode()));
7139 }
7140#else
7141 _ASSERTE(!"You shouldn't be calling this - rejit is not supported in this build");
7142 pVmILCodeVersionNode->SetDacTargetPtr(0);
7143#endif
7144 return S_OK;
7145}
7146
7147HRESULT DacDbiInterfaceImpl::GetReJitInfo(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeStartAddress, OUT VMPTR_ReJitInfo* pvmReJitInfo)
7148{
7149 DD_ENTER_MAY_THROW;
7150 _ASSERTE(!"You shouldn't be calling this - use GetNativeCodeVersionNode instead");
7151 return S_OK;
7152}
7153
7154HRESULT DacDbiInterfaceImpl::GetNativeCodeVersionNode(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeStartAddress, OUT VMPTR_NativeCodeVersionNode* pVmNativeCodeVersionNode)
7155{
7156 DD_ENTER_MAY_THROW;
7157 if (pVmNativeCodeVersionNode == NULL)
7158 return E_INVALIDARG;
7159#ifdef FEATURE_REJIT
7160 PTR_MethodDesc pMD = vmMethod.GetDacPtr();
7161 CodeVersionManager * pCodeVersionManager = pMD->GetCodeVersionManager();
7162 NativeCodeVersion codeVersion = pCodeVersionManager->GetNativeCodeVersion(pMD, (PCODE)codeStartAddress);
7163 pVmNativeCodeVersionNode->SetDacTargetPtr(PTR_TO_TADDR(codeVersion.AsNode()));
7164#else
7165 pVmNativeCodeVersionNode->SetDacTargetPtr(0);
7166#endif
7167 return S_OK;
7168}
7169
7170HRESULT DacDbiInterfaceImpl::GetSharedReJitInfo(VMPTR_ReJitInfo vmReJitInfo, OUT VMPTR_SharedReJitInfo* pvmSharedReJitInfo)
7171{
7172 DD_ENTER_MAY_THROW;
7173 _ASSERTE(!"You shouldn't be calling this - use GetLCodeVersionNode instead");
7174 return S_OK;
7175}
7176
7177HRESULT DacDbiInterfaceImpl::GetILCodeVersionNode(VMPTR_NativeCodeVersionNode vmNativeCodeVersionNode, VMPTR_ILCodeVersionNode* pVmILCodeVersionNode)
7178{
7179 DD_ENTER_MAY_THROW;
7180 if (pVmILCodeVersionNode == NULL)
7181 return E_INVALIDARG;
7182#ifdef FEATURE_REJIT
7183 NativeCodeVersionNode* pNativeCodeVersionNode = vmNativeCodeVersionNode.GetDacPtr();
7184 ILCodeVersion ilCodeVersion = pNativeCodeVersionNode->GetILCodeVersion();
7185 if (ilCodeVersion.IsDefaultVersion())
7186 {
7187 pVmILCodeVersionNode->SetDacTargetPtr(0);
7188 }
7189 else
7190 {
7191 pVmILCodeVersionNode->SetDacTargetPtr(PTR_TO_TADDR(ilCodeVersion.AsNode()));
7192 }
7193
7194#else
7195 _ASSERTE(!"You shouldn't be calling this - rejit is not supported in this build");
7196 pVmILCodeVersionNode->SetDacTargetPtr(0);
7197#endif
7198 return S_OK;
7199}
7200
7201HRESULT DacDbiInterfaceImpl::GetSharedReJitInfoData(VMPTR_SharedReJitInfo vmSharedReJitInfo, DacSharedReJitInfo* pData)
7202{
7203 DD_ENTER_MAY_THROW;
7204 _ASSERTE(!"You shouldn't be calling this - use GetILCodeVersionNodeData instead");
7205 return S_OK;
7206}
7207
7208HRESULT DacDbiInterfaceImpl::GetILCodeVersionNodeData(VMPTR_ILCodeVersionNode vmILCodeVersionNode, DacSharedReJitInfo* pData)
7209{
7210 DD_ENTER_MAY_THROW;
7211#ifdef FEATURE_REJIT
7212 ILCodeVersion ilCode(vmILCodeVersionNode.GetDacPtr());
7213 pData->m_state = ilCode.GetRejitState();
7214 pData->m_pbIL = PTR_TO_CORDB_ADDRESS(dac_cast<ULONG_PTR>(ilCode.GetIL()));
7215 pData->m_dwCodegenFlags = ilCode.GetJitFlags();
7216 const InstrumentedILOffsetMapping* pMapping = ilCode.GetInstrumentedILMap();
7217 if (pMapping)
7218 {
7219 pData->m_cInstrumentedMapEntries = (ULONG)pMapping->GetCount();
7220 pData->m_rgInstrumentedMapEntries = PTR_TO_CORDB_ADDRESS(dac_cast<ULONG_PTR>(pMapping->GetOffsets()));
7221 }
7222 else
7223 {
7224 pData->m_cInstrumentedMapEntries = 0;
7225 pData->m_rgInstrumentedMapEntries = 0;
7226 }
7227#else
7228 _ASSERTE(!"You shouldn't be calling this - rejit isn't supported in this build");
7229#endif
7230 return S_OK;
7231}
7232
7233HRESULT DacDbiInterfaceImpl::GetDefinesBitField(ULONG32 *pDefines)
7234{
7235 DD_ENTER_MAY_THROW;
7236 if (pDefines == NULL)
7237 return E_INVALIDARG;
7238 *pDefines = g_pDebugger->m_defines;
7239 return S_OK;
7240}
7241
7242HRESULT DacDbiInterfaceImpl::GetMDStructuresVersion(ULONG32* pMDStructuresVersion)
7243{
7244 DD_ENTER_MAY_THROW;
7245 if (pMDStructuresVersion == NULL)
7246 return E_INVALIDARG;
7247 *pMDStructuresVersion = g_pDebugger->m_mdDataStructureVersion;
7248 return S_OK;
7249}
7250
7251HRESULT DacDbiInterfaceImpl::EnableGCNotificationEvents(BOOL fEnable)
7252{
7253 DD_ENTER_MAY_THROW
7254
7255 HRESULT hr = S_OK;
7256 EX_TRY
7257 {
7258 if (g_pDebugger != NULL)
7259 {
7260 TADDR addr = PTR_HOST_MEMBER_TADDR(Debugger, g_pDebugger, m_isGarbageCollectionEventsEnabled);
7261 SafeWriteStructOrThrow<BOOL>(addr, &fEnable);
7262 }
7263 }
7264 EX_CATCH_HRESULT(hr);
7265 return hr;
7266}
7267
7268DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, BOOL walkFQ, UINT32 handleMask)
7269 : mDac(dac), mWalkStacks(walkStacks), mWalkFQ(walkFQ), mHandleMask(handleMask), mStackWalker(NULL),
7270 mHandleWalker(NULL), mFQStart(PTR_NULL), mFQEnd(PTR_NULL), mFQCurr(PTR_NULL)
7271{
7272}
7273
7274DacRefWalker::~DacRefWalker()
7275{
7276 Clear();
7277}
7278
7279HRESULT DacRefWalker::Init()
7280{
7281 HRESULT hr = S_OK;
7282 if (mHandleMask)
7283 {
7284 // Will throw on OOM, which is fine.
7285 mHandleWalker = new DacHandleWalker();
7286
7287 hr = mHandleWalker->Init(GetHandleWalkerMask());
7288 }
7289
7290 if (mWalkStacks && SUCCEEDED(hr))
7291 {
7292 hr = NextThread();
7293 }
7294
7295 return hr;
7296}
7297
7298void DacRefWalker::Clear()
7299{
7300 if (mHandleWalker)
7301 {
7302 delete mHandleWalker;
7303 mHandleWalker = NULL;
7304 }
7305
7306 if (mStackWalker)
7307 {
7308 delete mStackWalker;
7309 mStackWalker = NULL;
7310 }
7311}
7312
7313
7314
7315UINT32 DacRefWalker::GetHandleWalkerMask()
7316{
7317 UINT32 result = 0;
7318 if (mHandleMask & CorHandleStrong)
7319 result |= (1 << HNDTYPE_STRONG);
7320
7321 if (mHandleMask & CorHandleStrongPinning)
7322 result |= (1 << HNDTYPE_PINNED);
7323
7324 if (mHandleMask & CorHandleWeakShort)
7325 result |= (1 << HNDTYPE_WEAK_SHORT);
7326
7327 if (mHandleMask & CorHandleWeakLong)
7328 result |= (1 << HNDTYPE_WEAK_LONG);
7329
7330#ifdef FEATURE_COMINTEROP
7331 if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount))
7332 result |= (1 << HNDTYPE_REFCOUNTED);
7333
7334 if (mHandleMask & CorHandleWeakWinRT)
7335 result |= (1 << HNDTYPE_WEAK_WINRT);
7336#endif // FEATURE_COMINTEROP
7337
7338 if (mHandleMask & CorHandleStrongDependent)
7339 result |= (1 << HNDTYPE_DEPENDENT);
7340
7341 if (mHandleMask & CorHandleStrongAsyncPinned)
7342 result |= (1 << HNDTYPE_ASYNCPINNED);
7343
7344 if (mHandleMask & CorHandleStrongSizedByref)
7345 result |= (1 << HNDTYPE_SIZEDREF);
7346
7347 return result;
7348}
7349
7350
7351
7352HRESULT DacRefWalker::Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched)
7353{
7354 if (roots == NULL || pceltFetched == NULL)
7355 return E_POINTER;
7356
7357 ULONG total = 0;
7358 HRESULT hr = S_OK;
7359
7360 if (mHandleWalker)
7361 {
7362 hr = mHandleWalker->Next(celt, roots, &total);
7363
7364 if (hr == S_FALSE || FAILED(hr))
7365 {
7366 delete mHandleWalker;
7367 mHandleWalker = NULL;
7368
7369 if (FAILED(hr))
7370 return hr;
7371 }
7372 }
7373
7374 if (total < celt)
7375 {
7376 while (total < celt && mFQCurr < mFQEnd)
7377 {
7378 DacGcReference &ref = roots[total++];
7379
7380 ref.vmDomain = VMPTR_AppDomain::NullPtr();
7381 ref.objHnd.SetDacTargetPtr(mFQCurr.GetAddr());
7382 ref.dwType = (DWORD)CorReferenceFinalizer;
7383 ref.i64ExtraData = 0;
7384
7385 mFQCurr++;
7386 }
7387 }
7388
7389 while (total < celt && mStackWalker)
7390 {
7391 ULONG fetched = 0;
7392 hr = mStackWalker->Next(celt-total, roots+total, &fetched);
7393
7394 if (FAILED(hr))
7395 return hr;
7396
7397 if (hr == S_FALSE)
7398 {
7399 hr = NextThread();
7400
7401 if (FAILED(hr))
7402 return hr;
7403 }
7404
7405 total += fetched;
7406 }
7407
7408 *pceltFetched = total;
7409
7410 return total < celt ? S_FALSE : S_OK;
7411}
7412
7413HRESULT DacRefWalker::NextThread()
7414{
7415 Thread *pThread = NULL;
7416 if (mStackWalker)
7417 {
7418 pThread = mStackWalker->GetThread();
7419 delete mStackWalker;
7420 mStackWalker = NULL;
7421 }
7422
7423 pThread = ThreadStore::GetThreadList(pThread);
7424
7425 if (!pThread)
7426 return S_FALSE;
7427
7428 mStackWalker = new DacStackReferenceWalker(mDac, pThread->GetOSThreadId());
7429 return mStackWalker->Init();
7430}
7431
7432HRESULT DacHandleWalker::Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched)
7433{
7434 SUPPORTS_DAC;
7435
7436 if (roots == NULL || pceltFetched == NULL)
7437 return E_POINTER;
7438
7439 return DoHandleWalk<DacGcReference, ULONG, DacHandleWalker::EnumCallbackDac>(celt, roots, pceltFetched);
7440}
7441
7442
7443void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, uintptr_t *pExtraInfo, uintptr_t param1, uintptr_t param2)
7444{
7445 SUPPORTS_DAC;
7446
7447 DacHandleWalkerParam *param = (DacHandleWalkerParam *)param1;
7448 HandleChunkHead *curr = param->Curr;
7449
7450 // If we failed on a previous call (OOM) don't keep trying to allocate, it's not going to work.
7451 if (FAILED(param->Result))
7452 return;
7453
7454 // We've moved past the size of the current chunk. We'll allocate a new chunk
7455 // and stuff the handles there. These are cleaned up by the destructor
7456 if (curr->Count >= (curr->Size/sizeof(DacGcReference)))
7457 {
7458 if (curr->Next == NULL)
7459 {
7460 HandleChunk *next = new (nothrow) HandleChunk;
7461 if (next != NULL)
7462 {
7463 curr->Next = next;
7464 }
7465 else
7466 {
7467 param->Result = E_OUTOFMEMORY;
7468 return;
7469 }
7470 }
7471
7472 curr = param->Curr = param->Curr->Next;
7473 }
7474
7475 // Fill the current handle.
7476 DacGcReference *dataArray = (DacGcReference*)curr->pData;
7477 DacGcReference &data = dataArray[curr->Count++];
7478
7479 data.objHnd.SetDacTargetPtr(handle.GetAddr());
7480 data.vmDomain.SetDacTargetPtr(TO_TADDR(param->AppDomain));
7481
7482 data.i64ExtraData = 0;
7483 unsigned int refCnt = 0;
7484
7485 switch (param->Type)
7486 {
7487 case HNDTYPE_STRONG:
7488 data.dwType = (DWORD)CorHandleStrong;
7489 break;
7490
7491 case HNDTYPE_PINNED:
7492 data.dwType = (DWORD)CorHandleStrongPinning;
7493 break;
7494
7495 case HNDTYPE_WEAK_SHORT:
7496 data.dwType = (DWORD)CorHandleWeakShort;
7497 break;
7498
7499 case HNDTYPE_WEAK_LONG:
7500 data.dwType = (DWORD)CorHandleWeakLong;
7501 break;
7502
7503#ifdef FEATURE_COMINTEROP
7504 case HNDTYPE_REFCOUNTED:
7505 data.dwType = (DWORD)(data.i64ExtraData ? CorHandleStrongRefCount : CorHandleWeakRefCount);
7506 GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &refCnt, NULL, NULL, NULL);
7507 data.i64ExtraData = refCnt;
7508 break;
7509
7510 case HNDTYPE_WEAK_WINRT:
7511 data.dwType = (DWORD)CorHandleWeakWinRT;
7512 break;
7513#endif
7514
7515 case HNDTYPE_DEPENDENT:
7516 data.dwType = (DWORD)CorHandleStrongDependent;
7517 data.i64ExtraData = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
7518 break;
7519
7520 case HNDTYPE_ASYNCPINNED:
7521 data.dwType = (DWORD)CorHandleStrongAsyncPinned;
7522 break;
7523
7524 case HNDTYPE_SIZEDREF:
7525 data.dwType = (DWORD)CorHandleStrongSizedByref;
7526 break;
7527 }
7528}
7529
7530
7531void DacStackReferenceWalker::GCEnumCallbackDac(LPVOID hCallback, OBJECTREF *pObject, uint32_t flags, DacSlotLocation loc)
7532{
7533 GCCONTEXT *gcctx = (GCCONTEXT *)hCallback;
7534 DacScanContext *dsc = (DacScanContext*)gcctx->sc;
7535
7536 CORDB_ADDRESS obj = 0;
7537
7538 if (flags & GC_CALL_INTERIOR)
7539 {
7540 if (loc.targetPtr)
7541 obj = (CORDB_ADDRESS)(*PTR_PTR_Object((TADDR)pObject)).GetAddr();
7542 else
7543 obj = (CORDB_ADDRESS)TO_TADDR(pObject);
7544
7545 HRESULT hr = dsc->pWalker->mHeap.ListNearObjects(obj, NULL, &obj, NULL);
7546
7547 // If we failed don't add this instance to the list. ICorDebug doesn't handle invalid pointers
7548 // very well, and the only way the heap walker's ListNearObjects will fail is if we have heap
7549 // corruption...which ICorDebug doesn't deal with anyway.
7550 if (FAILED(hr))
7551 return;
7552 }
7553
7554 DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
7555 if (data != NULL)
7556 {
7557 data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
7558 if (obj)
7559 data->pObject = obj | 1;
7560 else if (loc.targetPtr)
7561 data->objHnd.SetDacTargetPtr(TO_TADDR(pObject));
7562 else
7563 data->pObject = pObject->GetAddr() | 1;
7564
7565 data->dwType = CorReferenceStack;
7566 data->i64ExtraData = 0;
7567 }
7568}
7569
7570
7571void DacStackReferenceWalker::GCReportCallbackDac(PTR_PTR_Object ppObj, ScanContext *sc, uint32_t flags)
7572{
7573 DacScanContext *dsc = (DacScanContext*)sc;
7574
7575 TADDR obj = ppObj.GetAddr();
7576 if (flags & GC_CALL_INTERIOR)
7577 {
7578 CORDB_ADDRESS fixed_addr = 0;
7579 HRESULT hr = dsc->pWalker->mHeap.ListNearObjects((CORDB_ADDRESS)obj, NULL, &fixed_addr, NULL);
7580
7581 // If we failed don't add this instance to the list. ICorDebug doesn't handle invalid pointers
7582 // very well, and the only way the heap walker's ListNearObjects will fail is if we have heap
7583 // corruption...which ICorDebug doesn't deal with anyway.
7584 if (FAILED(hr))
7585 return;
7586
7587 obj = TO_TADDR(fixed_addr);
7588 }
7589
7590 DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
7591 if (data != NULL)
7592 {
7593 data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
7594 data->objHnd.SetDacTargetPtr(obj);
7595 data->dwType = CorReferenceStack;
7596 data->i64ExtraData = 0;
7597 }
7598}
7599
7600
7601
7602HRESULT DacStackReferenceWalker::Next(ULONG count, DacGcReference stackRefs[], ULONG *pFetched)
7603{
7604 if (stackRefs == NULL || pFetched == NULL)
7605 return E_POINTER;
7606
7607 HRESULT hr = DoStackWalk<ULONG, DacGcReference,
7608 DacStackReferenceWalker::GCReportCallbackDac,
7609 DacStackReferenceWalker::GCEnumCallbackDac>
7610 (count, stackRefs, pFetched);
7611
7612 return hr;
7613}
7614