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
9 // Implement DAC/DBI interface
11 //*****************************************************************************
16 #include "dacdbiinterface.h"
18 #include "typestring.h"
20 #include "debuginfostore.h"
21 #include "peimagelayout.inl"
25 #include "stackwalk.h"
27 #include "dacdbiimpl.h"
29 #ifdef FEATURE_COMINTEROP
30 #include "runtimecallablewrapper.h"
31 #include "comcallablewrapper.h"
32 #endif // FEATURE_COMINTEROP
34 //-----------------------------------------------------------------------------
35 // Have standard enter and leave macros at the DacDbi boundary to enforce
37 // 1. catch exceptions and convert them at the boundary.
38 // 2. provide a space to hook logging and transitions.
39 // 3. provide a hook to verify return values.
42 // - use this at the DacDbi boundary; but not at internal functions
43 // - it's ok to Return from the middle.
50 // if (...) { ThrowHr(E_SOME_FAILURE); }
52 // if (...) { return; } // early success case
55 //-----------------------------------------------------------------------------
60 // Global allocator for DD. Access is protected under the g_dacCritSec lock.
61 IDacDbiInterface::IAllocator * g_pAllocator = NULL;
63 //---------------------------------------------------------------------------------------
65 // Extra sugar for wrapping IAllocator under friendly New/Delete operators.
68 // void Foo(TestClass ** ppOut)
71 // TestClass * p = new (forDbi) TestClass();
76 // return; // DBI will then free this memory.
79 // DeleteDbiMemory(p);
82 // Be very careful when using this on classes since Dbi and DAC may be in
83 // separate dlls. This is best used when operating on blittable data-structures.
84 // (no ctor/dtor, plain data fields) to guarantee the proper DLL isolation.
85 // You don't want to call the ctor in DAC's context and the dtor in DBI's context
86 // unless you really know what you're doing and that it's safe.
89 // Need a class to serve as a tag that we can use to overload New/Delete.
92 void * operator new(size_t lenBytes, const forDbiWorker &)
94 _ASSERTE(g_pAllocator != NULL);
95 void *result = g_pAllocator->Alloc(lenBytes);
103 void * operator new[](size_t lenBytes, const forDbiWorker &)
105 _ASSERTE(g_pAllocator != NULL);
106 void *result = g_pAllocator->Alloc(lenBytes);
114 // Note: there is no C++ syntax for manually invoking this, but if a constructor throws an exception I understand that
115 // this delete operator will be invoked automatically to destroy the object.
116 void operator delete(void *p, const forDbiWorker &)
123 _ASSERTE(g_pAllocator != NULL);
124 g_pAllocator->Free((BYTE*) p);
128 // Note: there is no C++ syntax for manually invoking this, but if a constructor throws an exception I understand that
129 // this delete operator will be invoked automatically to destroy the object.
130 void operator delete[](void *p, const forDbiWorker &)
137 _ASSERTE(g_pAllocator != NULL);
138 g_pAllocator->Free((BYTE*) p);
141 // @dbgtodo dac support: determine how to handle an array of class instances to ensure the dtors get
142 // called correctly or document that they won't
143 // Delete memory and invoke dtor for memory allocated with 'operator (forDbi) new'
144 template<class T> void DeleteDbiMemory(T *p)
152 _ASSERTE(g_pAllocator != NULL);
153 g_pAllocator->Free((BYTE*) p);
157 //---------------------------------------------------------------------------------------
158 // Creates the DacDbiInterface object, used by Dbi.
161 // pTarget - pointer to a Data-Target
162 // baseAddress - non-zero base address of mscorwks in target to debug.
163 // pAllocator - pointer to client allocator object. This lets DD allocate objects and
164 // pass them out back to the client, which can then delete them.
165 // DD takes a weak ref to this, so client must keep it alive until it
167 // pMetadataLookup - callback interface to do internal metadata lookup. This is because
168 // metadata is not dac-ized.
169 // ppInterface - mandatory out-parameter
176 // On Windows, this is public function that can be retrieved by GetProcAddress.
178 // On Mac, this is used internally by DacDbiMarshalStubInstance below
179 // This will yield an IDacDbiInterface to provide structured access to the
182 // Must call Destroy to on interface to free its resources.
184 //---------------------------------------------------------------------------------------
186 DacDbiInterfaceInstance(
187 ICorDebugDataTarget * pTarget,
188 CORDB_ADDRESS baseAddress,
189 IDacDbiInterface::IAllocator * pAllocator,
190 IDacDbiInterface::IMetaDataLookup * pMetaDataLookup,
191 IDacDbiInterface ** ppInterface)
193 // No marshalling is done by the instantiationf function - we just need to setup the infrastructure.
194 // We don't want to warn if this involves creating and accessing undacized data structures,
195 // because it's for the infrastructure, not DACized code itself.
196 SUPPORTS_DAC_HOST_ONLY;
198 // Since this is public, verify it.
199 if ((ppInterface == NULL) || (pTarget == NULL) || (baseAddress == 0))
207 // Actually allocate the real object and initialize it.
209 DacDbiInterfaceImpl * pDac = new (nothrow) DacDbiInterfaceImpl(pTarget, baseAddress, pAllocator, pMetaDataLookup);
212 return E_OUTOFMEMORY;
215 HRESULT hrStatus = pDac->Initialize();
217 if (SUCCEEDED(hrStatus))
229 //---------------------------------------------------------------------------------------
230 // Constructor. Instantiates a DAC/DBI interface around a DataTarget.
233 // pTarget - pointer to a Data-Target
234 // baseAddress - non-zero base address of mscorwks in target to debug.
235 // pAllocator - pointer to client allocator object. This lets DD allocate objects and
236 // pass them out back to the client, which can then delete them.
237 // DD takes a weak ref to this, so client must keep it alive until it
239 // pMetadataLookup - callback interface to do internal metadata lookup. This is because
240 // metadata is not dac-ized.
243 // pAllocator is a weak reference.
244 //---------------------------------------------------------------------------------------
245 DacDbiInterfaceImpl::DacDbiInterfaceImpl(
246 ICorDebugDataTarget* pTarget,
247 CORDB_ADDRESS baseAddress,
248 IAllocator * pAllocator,
249 IMetaDataLookup * pMetaDataLookup
250 ) : ClrDataAccess(pTarget),
251 m_pAllocator(pAllocator),
252 m_pMetaDataLookup(pMetaDataLookup),
253 m_pCachedPEFile(VMPTR_PEFile::NullPtr()),
254 m_pCachedImporter(NULL),
255 m_isCachedHijackFunctionValid(FALSE)
257 _ASSERTE(baseAddress != NULL);
258 m_globalBase = CORDB_ADDRESS_TO_TADDR(baseAddress);
260 _ASSERTE(pMetaDataLookup != NULL);
261 _ASSERTE(pAllocator != NULL);
262 _ASSERTE(pTarget != NULL);
265 // Enable verification asserts in ICorDebug scenarios. ICorDebug never guesses at the DAC path, so any
266 // mismatch should be fatal, and so always of interest to the user.
267 // This overrides the assignment in the base class ctor (which runs first).
268 m_fEnableDllVerificationAsserts = true;
272 //-----------------------------------------------------------------------------
276 // This gets invoked after Destroy().
277 //-----------------------------------------------------------------------------
278 DacDbiInterfaceImpl::~DacDbiInterfaceImpl()
280 SUPPORTS_DAC_HOST_ONLY;
281 // This will automatically chain to the base class dtor
284 //-----------------------------------------------------------------------------
285 // Called from DAC-ized code to get a IMDInternalImport
288 // pPEFile - PE file for which to get importer for
289 // fThrowEx - if true, throw instead of returning NULL.
292 // an Internal importer object for this file.
293 // May return NULL or throw (depending on fThrowEx).
294 // May throw in exceptional circumstances (eg, corrupt debuggee).
297 // This is called from DAC-ized code within the VM, which
298 // was in turn called from some DD primitive. The returned importer will
299 // be used by the DAC-ized code in the callstack, but it won't be cached.
302 // This is an Internal importer, not a public Metadata importer.
304 interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
305 const PEFile* pPEFile,
306 const ReflectionModule * pReflectionModule,
309 // Since this is called from an existing DAC-primitive, we already hold the g_dacCritSec lock.
310 // The lock conveniently protects our cache.
313 IDacDbiInterface::IMetaDataLookup * pLookup = m_pMetaDataLookup;
314 _ASSERTE(pLookup != NULL);
316 VMPTR_PEFile vmPEFile = VMPTR_PEFile::NullPtr();
320 vmPEFile.SetHostPtr(pPEFile);
322 else if (pReflectionModule != NULL)
324 // SOS and ClrDataAccess rely on special logic to find the metadata for methods in dynamic modules.
325 // We don't need to. The RS has already taken care of the special logic for us.
326 // So here we just grab the PEFile off of the ReflectionModule and continue down the normal
327 // code path. See code:ClrDataAccess::GetMDImport for comparison.
328 vmPEFile.SetHostPtr(pReflectionModule->GetFile());
331 // Optimize for the case where the VM queries the same Importer many times in a row.
332 if (m_pCachedPEFile == vmPEFile)
334 return m_pCachedImporter;
337 // Go to DBI to find the metadata.
338 IMDInternalImport * pInternal = NULL;
339 bool isILMetaDataForNI = false;
342 // If test needs it in the future, prop isILMetaDataForNI back up to
343 // ClrDataAccess.m_mdImports.Add() call.
344 // example in code:ClrDataAccess::GetMDImport
345 // CordbModule::GetMetaDataInterface also looks up MetaData and would need attention.
347 // This is the new codepath that uses ICorDebugMetaDataLookup.
348 // To get the old codepath that uses the v2 metadata lookup methods,
349 // you'd have to load DAC only and then you'll get ClrDataAccess's implementation
351 pInternal = pLookup->LookupMetaData(vmPEFile, isILMetaDataForNI);
355 // Any expected error we should ignore.
356 if ((GET_EXCEPTION()->GetHR() != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) &&
357 (GET_EXCEPTION()->GetHR() != CORDBG_E_READVIRTUAL_FAILURE) &&
358 (GET_EXCEPTION()->GetHR() != CORDBG_E_SYMBOLS_NOT_AVAILABLE) &&
359 (GET_EXCEPTION()->GetHR() != CORDBG_E_MODULE_LOADED_FROM_DISK))
364 EX_END_CATCH(SwallowAllExceptions)
366 if (pInternal == NULL)
368 SIMPLIFYING_ASSUMPTION(!"MD lookup failed");
377 // Cache it such that it we look for the exact same Importer again, we'll return it.
378 m_pCachedPEFile = vmPEFile;
379 m_pCachedImporter = pInternal;
385 //-----------------------------------------------------------------------------
386 // Implementation of IDacDbiInterface
387 // See DacDbiInterface.h for full descriptions of all of these functions
388 //-----------------------------------------------------------------------------
390 // Destroy the connection, freeing up any resources.
391 void DacDbiInterfaceImpl::Destroy()
396 // Memory is deleted, don't access this object any more
399 // Check whether the version of the DBI matches the version of the runtime.
400 // See code:CordbProcess::CordbProcess#DBIVersionChecking for more information regarding version checking.
401 HRESULT DacDbiInterfaceImpl::CheckDbiVersion(const DbiVersion * pVersion)
405 if (pVersion->m_dwFormat != kCurrentDbiVersionFormat)
407 return CORDBG_E_INCOMPATIBLE_PROTOCOL;
410 if ((pVersion->m_dwProtocolBreakingChangeCounter != kCurrentDacDbiProtocolBreakingChangeCounter) ||
411 (pVersion->m_dwReservedMustBeZero1 != 0))
413 return CORDBG_E_INCOMPATIBLE_PROTOCOL;
419 // Flush the DAC cache. This should be called when target memory changes.
420 HRESULT DacDbiInterfaceImpl::FlushCache()
422 // Non-reentrant. We don't want to flush cached instances from a callback.
423 // That would remove host DAC instances while they're being used.
424 DD_NON_REENTRANT_MAY_THROW;
426 m_pCachedPEFile = VMPTR_PEFile::NullPtr();
427 m_pCachedImporter = NULL;
428 m_isCachedHijackFunctionValid = FALSE;
430 HRESULT hr = ClrDataAccess::Flush();
432 // Current impl of Flush() should always succeed. If it ever fails, we want to know.
433 _ASSERTE(SUCCEEDED(hr));
437 // enable or disable DAC target consistency checks
438 void DacDbiInterfaceImpl::DacSetTargetConsistencyChecks(bool fEnableAsserts)
440 // forward on to our ClrDataAccess base class
441 ClrDataAccess::SetTargetConsistencyChecks(fEnableAsserts);
444 // Query if Left-side is started up?
445 BOOL DacDbiInterfaceImpl::IsLeftSideInitialized()
449 if (g_pDebugger != NULL)
451 // This check is "safe".
452 // The initialize order in the left-side is:
453 // 1) g_pDebugger is an RVA based global initialized to NULL when the module is loaded.
454 // 2) Allocate a "Debugger" object.
455 // 3) run the ctor, which will set m_fLeftSideInitialized = FALSE.
456 // 4) assign the object to g_pDebugger.
457 // 5) later, LS initialization code will assign g_pDebugger->m_fLeftSideInitialized = TRUE.
459 // The memory write in #5 is atomic. There is no window where we're reading unitialized data.
461 return (g_pDebugger->m_fLeftSideInitialized != 0);
468 // Determines if a given adddress is a CLR stub.
469 BOOL DacDbiInterfaceImpl::IsTransitionStub(CORDB_ADDRESS address)
473 BOOL fIsStub = FALSE;
475 #if defined(FEATURE_PAL)
476 // Currently IsIPInModule() is not implemented in the PAL. Rather than skipping the check, we should
477 // either E_NOTIMPL this API or implement IsIPInModule() in the PAL. Since ICDProcess::IsTransitionStub()
478 // is only called by VS in mixed-mode debugging scenarios, and mixed-mode debugging is not supported on
479 // POSIX systems, there is really no incentive to implement this API at this point.
482 #else // !FEATURE_PAL
484 TADDR ip = (TADDR)address;
492 fIsStub = StubManager::IsStub(ip);
495 // If it's in Mscorwks, count that as a stub too.
496 if (fIsStub == FALSE)
498 fIsStub = IsIPInModule(m_globalBase, ip);
501 #endif // FEATURE_PAL
506 // Gets the type of 'address'.
507 IDacDbiInterface::AddressType DacDbiInterfaceImpl::GetAddressType(CORDB_ADDRESS address)
510 TADDR taAddr = CORDB_ADDRESS_TO_TADDR(address);
512 if (IsPossibleCodeAddress(taAddr) == S_OK)
514 if (ExecutionManager::IsManagedCode(taAddr))
516 return kAddressManagedMethod;
519 if (StubManager::IsStub(taAddr))
521 return kAddressRuntimeUnmanagedStub;
525 return kAddressUnrecognized;
529 // Get a VM appdomain pointer that matches the appdomain ID
530 VMPTR_AppDomain DacDbiInterfaceImpl::GetAppDomainFromId(ULONG appdomainId)
534 VMPTR_AppDomain vmAppDomain;
536 // @dbgtodo dac support - We would like to wean ourselves off the IXClrData interfaces.
537 IXCLRDataProcess * pDAC = this;
538 ReleaseHolder<IXCLRDataAppDomain> pDacAppDomain;
540 HRESULT hrStatus = pDAC->GetAppDomainByUniqueID(appdomainId, &pDacAppDomain);
541 IfFailThrow(hrStatus);
543 IXCLRDataAppDomain * pIAppDomain = pDacAppDomain;
544 AppDomain * pAppDomain = (static_cast<ClrDataAppDomain *> (pIAppDomain))->GetAppDomain();
545 SIMPLIFYING_ASSUMPTION(pAppDomain != NULL);
546 if (pAppDomain == NULL)
548 ThrowHR(E_FAIL); // corrupted left-side?
551 TADDR addrAppDomain = PTR_HOST_TO_TADDR(pAppDomain);
552 vmAppDomain.SetDacTargetPtr(addrAppDomain);
558 // Get the AppDomain ID for an AppDomain.
559 ULONG DacDbiInterfaceImpl::GetAppDomainId(VMPTR_AppDomain vmAppDomain)
563 if (vmAppDomain.IsNull())
569 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
570 return pAppDomain->GetId().m_dwId;
574 // Get the managed AppDomain object for an AppDomain.
575 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetAppDomainObject(VMPTR_AppDomain vmAppDomain)
579 AppDomain* pAppDomain = vmAppDomain.GetDacPtr();
580 OBJECTHANDLE hAppDomainManagedObject = pAppDomain->GetRawExposedObjectHandleForDebugger();
581 VMPTR_OBJECTHANDLE vmObj = VMPTR_OBJECTHANDLE::NullPtr();
582 vmObj.SetDacTargetPtr(hAppDomainManagedObject);
587 // Determine if the specified AppDomain is the default domain
588 BOOL DacDbiInterfaceImpl::IsDefaultDomain(VMPTR_AppDomain vmAppDomain)
592 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
593 BOOL fDefaultDomain = pAppDomain->IsDefaultDomain();
595 return fDefaultDomain;
599 // Get the full AD friendly name for the given EE AppDomain.
600 void DacDbiInterfaceImpl::GetAppDomainFullName(
601 VMPTR_AppDomain vmAppDomain,
602 IStringHolder * pStrName )
605 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
607 // Get the AppDomain name from the VM without changing anything
608 // We might be able to simplify this, eg. by returning an SString.
610 PVOID pRawName = pAppDomain->GetFriendlyNameNoSet(&fIsUtf8);
614 ThrowHR(E_NOINTERFACE);
617 HRESULT hrStatus = S_OK;
620 // we have to allocate a temporary string
621 // we could avoid this by adding a version of IStringHolder::AssignCopy that takes a UTF8 string
622 // We should also probably check to see when fIsUtf8 is ever true (it looks like it should normally be false).
623 ULONG32 dwNameLen = 0;
624 hrStatus = ConvertUtf8((LPCUTF8)pRawName, 0, &dwNameLen, NULL);
625 if (SUCCEEDED( hrStatus ))
627 NewArrayHolder<WCHAR> pwszName(new WCHAR[dwNameLen]);
628 hrStatus = ConvertUtf8((LPCUTF8)pRawName, dwNameLen, &dwNameLen, pwszName );
629 IfFailThrow(hrStatus);
631 hrStatus = pStrName->AssignCopy(pwszName);
636 hrStatus = pStrName->AssignCopy(static_cast<PCWSTR>(pRawName));
639 // Very important that this either sets pStrName or Throws.
640 // Don't set it and then then throw.
641 IfFailThrow(hrStatus);
644 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
645 // JIT Compiler Flags
646 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
648 // Get the values of the JIT Optimization and EnC flags.
649 void DacDbiInterfaceImpl::GetCompilerFlags (
650 VMPTR_DomainFile vmDomainFile,
651 BOOL *pfAllowJITOpts,
656 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
658 if (pDomainFile == NULL)
663 // Get the underlying module - none of this is AppDomain specific
664 Module * pModule = pDomainFile->GetModule();
665 DWORD dwBits = pModule->GetDebuggerInfoBits();
666 *pfAllowJITOpts = !CORDisableJITOptimizations(dwBits);
667 *pfEnableEnC = pModule->IsEditAndContinueEnabled();
672 //-----------------------------------------------------------------------------
673 // Helper function for SetCompilerFlags to set EnC status.
676 // pModule - The runtime module for which flags are being set.
679 // true if the Enc bits can be set on this module
680 //-----------------------------------------------------------------------------
682 bool DacDbiInterfaceImpl::CanSetEnCBits(Module * pModule)
684 _ASSERTE(pModule != NULL);
686 // If we're using explicit sequence points (from the PDB), then we can't do EnC
687 // because EnC won't get updated pdbs and so the sequence points will be wrong.
688 bool fIgnorePdbs = ((pModule->GetDebuggerInfoBits() & DACF_IGNORE_PDBS) != 0);
690 bool fAllowEnc = pModule->IsEditAndContinueCapable() &&
692 #ifdef PROFILING_SUPPORTED_DATA
693 !CORProfilerPresent() && // this queries target
696 #else // ! EnC_SUPPORTED
697 // Enc not supported on any other platforms.
698 bool fAllowEnc = false;
702 } // DacDbiInterfaceImpl::SetEnCBits
704 // Set the values of the JIT optimization and EnC flags.
705 HRESULT DacDbiInterfaceImpl::SetCompilerFlags(VMPTR_DomainFile vmDomainFile,
712 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
713 Module * pModule = pDomainFile->GetCurrentModule();
717 #ifdef FEATURE_PREJIT
718 if (pModule->HasNativeImage())
720 ThrowHR(CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE);
723 _ASSERTE(pModule != NULL);
725 // Initialize dwBits.
726 dwBits = (pModule->GetDebuggerInfoBits() & ~(DACF_ALLOW_JIT_OPTS | DACF_ENC_ENABLED));
727 dwBits &= DACF_CONTROL_FLAGS_MASK;
731 dwBits |= DACF_ALLOW_JIT_OPTS;
735 if (CanSetEnCBits(pModule))
737 dwBits |= DACF_ENC_ENABLED;
741 hr = CORDBG_S_NOT_ALL_BITS_SET;
744 // Settings from the debugger take precedence over all other settings.
745 dwBits |= DACF_USER_OVERRIDE;
747 // set flags. This will write back to the target
748 pModule->SetDebuggerInfoBits((DebuggerAssemblyControlFlags)dwBits);
751 LOG((LF_CORDB, LL_INFO100, "D::HIPCE, Changed Jit-Debug-Info: fOpt=%d, fEnableEnC=%d, new bits=0x%08x\n",
752 (dwBits & DACF_ALLOW_JIT_OPTS) != 0,
753 (dwBits & DACF_ENC_ENABLED) != 0,
756 _ASSERTE(SUCCEEDED(hr));
759 } // DacDbiInterfaceImpl::SetCompilerFlags
762 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
763 // sequence points and var info
764 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
766 // Initialize the native/IL sequence points and native var info for a function.
767 void DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc,
768 CORDB_ADDRESS startAddr,
770 NativeVarData * pNativeVarData,
771 SequencePoints * pSequencePoints)
775 _ASSERTE(!vmMethodDesc.IsNull());
777 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
779 _ASSERTE(fCodeAvailable != 0);
781 // get information about the locations of arguments and local variables
782 GetNativeVarData(pMD, startAddr, GetArgCount(pMD), pNativeVarData);
784 // get the sequence points
785 GetSequencePoints(pMD, startAddr, pSequencePoints);
787 } // GetNativeCodeSequencePointsAndVarInfo
789 //-----------------------------------------------------------------------------
790 // Get the number of fixed arguments to a function, i.e., the explicit args and the "this" pointer.
791 // This does not include other implicit arguments or varargs. This is used to compute a variable ID
792 // (see comment in CordbJITILFrame::ILVariableToNative for more detail)
794 // input: pMD pointer to the method desc for the function
797 // the number of fixed arguments to the function
798 //-----------------------------------------------------------------------------
799 SIZE_T DacDbiInterfaceImpl::GetArgCount(MethodDesc * pMD)
802 // Create a MetaSig for the given method's sig. (Easier than
803 // picking the sig apart ourselves.)
804 PCCOR_SIGNATURE pCallSig;
807 pMD->GetSig(&pCallSig, &cbCallSigSize);
809 if (pCallSig == NULL)
811 // Sig should only be null if the image is corrupted. (Even for lightweight-codegen)
812 // We expect the jit+verifier to catch this, so that we never land here.
813 // But just in case ...
814 CONSISTENCY_CHECK_MSGF(false, ("Corrupted image, null sig.(%s::%s)",
815 pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
819 MetaSig msig(pCallSig, cbCallSigSize, pMD->GetModule(), NULL, MetaSig::sigMember);
821 // Get the arg count.
822 UINT32 NumArguments = msig.NumFixedArgs();
824 // Account for the 'this' argument.
825 if (!pMD->IsStatic())
830 SigParser sigParser(pCallSig, cbCallSigSize);
831 sigParser.SkipMethodHeaderSignature(&m_allArgsCount);
836 // Allocator to pass to DebugInfoStores, allocating forDBI
837 BYTE* InfoStoreForDbiNew(void * pData, size_t cBytes)
839 return new(forDbi) BYTE[cBytes];
842 // Allocator to pass to the debug-info-stores...
843 BYTE* InfoStoreNew(void * pData, size_t cBytes)
845 return new BYTE[cBytes];
848 //-----------------------------------------------------------------------------
849 // Get locations and code offsets for local variables and arguments in a function
850 // This information is used to find the location of a value at a given IP.
853 // pMethodDesc pointer to the method desc for the function
854 // startAddr starting address of the function--used to differentiate
856 // fixedArgCount number of fixed arguments to the function
858 // pVarInfo data structure containing a list of variable and
859 // argument locations by range of IP offsets
860 // Note: this function may throw
861 //-----------------------------------------------------------------------------
862 void DacDbiInterfaceImpl::GetNativeVarData(MethodDesc * pMethodDesc,
863 CORDB_ADDRESS startAddr,
864 SIZE_T fixedArgCount,
865 NativeVarData * pVarInfo)
867 // make sure we haven't done this already
868 if (pVarInfo->IsInitialized())
873 NewHolder<ICorDebugInfo::NativeVarInfo> nativeVars(NULL);
875 DebugInfoRequest request;
876 request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));
880 BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
881 InfoStoreNew, NULL, // allocator
883 &entryCount, &nativeVars);
888 // set key fields of pVarInfo
889 pVarInfo->InitVarDataList(nativeVars, (int)fixedArgCount, (int)entryCount);
890 } // GetNativeVarData
893 //-----------------------------------------------------------------------------
894 // Given a instrumented IL map from the profiler that maps:
895 // Original offset IL_A -> Instrumentend offset IL_B
896 // And a native mapping from the JIT that maps:
897 // Instrumented offset IL_B -> native offset Native_C
898 // This function merges the two maps and stores the result back into the nativeMap.
899 // The nativeMap now maps:
900 // Original offset IL_A -> native offset Native_C
901 // pEntryCount is the number of valid entries in nativeMap, and it may be adjusted downwards
902 // as part of the composition.
903 //-----------------------------------------------------------------------------
904 void DacDbiInterfaceImpl::ComposeMapping(InstrumentedILOffsetMapping profilerILMap, ICorDebugInfo::OffsetMapping nativeMap[], ULONG32* pEntryCount)
906 // Translate the IL offset if the profiler has provided us with a mapping.
907 // The ICD public API should always expose the original IL offsets, but GetBoundaries()
908 // directly accesses the debug info, which stores the instrumented IL offsets.
910 ULONG32 entryCount = *pEntryCount;
911 if (!profilerILMap.IsNull())
913 // If we did instrument, then we can't have any sequence points that
914 // are "in-between" the old-->new map that the profiler gave us.
918 // And the jit gives us an entry for 44 new, that will map back to 6 old.
919 // Since the map can only have one entry for 6 old, we remove 44 new.
921 // First Pass: invalidate all the duplicate entries by setting their IL offset to MAX_ILNUM
922 ULONG32 cDuplicate = 0;
923 ULONG32 prevILOffset = (ULONG32)(ICorDebugInfo::MAX_ILNUM);
924 for (ULONG32 i = 0; i < entryCount; i++)
926 ULONG32 origILOffset = TranslateInstrumentedILOffsetToOriginal(nativeMap[i].ilOffset, &profilerILMap);
928 if (origILOffset == prevILOffset)
930 // mark this sequence point as invalid; refer to the comment above
931 nativeMap[i].ilOffset = (ULONG32)(ICorDebugInfo::MAX_ILNUM);
936 // overwrite the instrumented IL offset with the original IL offset
937 nativeMap[i].ilOffset = origILOffset;
938 prevILOffset = origILOffset;
942 // Second Pass: move all the valid entries up front
943 ULONG32 realIndex = 0;
944 for (ULONG32 curIndex = 0; curIndex < entryCount; curIndex++)
946 if (nativeMap[curIndex].ilOffset != (ULONG32)(ICorDebugInfo::MAX_ILNUM))
948 // This is a valid entry. Move it up front.
949 nativeMap[realIndex] = nativeMap[curIndex];
954 // make sure we have done the bookkeeping correctly
955 _ASSERTE((realIndex + cDuplicate) == entryCount);
957 // Final Pass: derecement entryCount
958 entryCount -= cDuplicate;
959 *pEntryCount = entryCount;
964 //-----------------------------------------------------------------------------
965 // Get the native/IL sequence points for a function
968 // pMethodDesc pointer to the method desc for the function
969 // startAddr starting address of the function--used to differentiate
971 // pNativeMap data structure containing a list of sequence points
972 // Note: this function may throw
973 //-----------------------------------------------------------------------------
974 void DacDbiInterfaceImpl::GetSequencePoints(MethodDesc * pMethodDesc,
975 CORDB_ADDRESS startAddr,
976 SequencePoints * pSeqPoints)
979 // make sure we haven't done this already
980 if (pSeqPoints->IsInitialized())
985 // Use the DebugInfoStore to get IL->Native maps.
986 // It doesn't matter whether we're jitted, ngenned etc.
987 DebugInfoRequest request;
988 request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));
992 NewArrayHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
995 BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
996 InfoStoreNew, NULL, // allocator
997 &entryCount, &mapCopy,
1002 // if there is a rejit IL map for this function, apply that in preference to load-time mapping
1003 #ifdef FEATURE_REJIT
1004 ReJitManager * pReJitMgr = pMethodDesc->GetReJitManager();
1005 ReJitInfo* pReJitInfo = pReJitMgr->FindReJitInfo(dac_cast<PTR_MethodDesc>(pMethodDesc), (PCODE)startAddr, 0);
1006 if (pReJitInfo != NULL)
1008 InstrumentedILOffsetMapping rejitMapping = pReJitInfo->m_pShared->m_instrumentedILMap;
1009 ComposeMapping(rejitMapping, mapCopy, &entryCount);
1014 // if there is a profiler load-time mapping and not a rejit mapping, apply that instead
1015 InstrumentedILOffsetMapping loadTimeMapping =
1016 pMethodDesc->GetModule()->GetInstrumentedILOffsetMapping(pMethodDesc->GetMemberDef());
1017 ComposeMapping(loadTimeMapping, mapCopy, &entryCount);
1018 #ifdef FEATURE_REJIT
1022 pSeqPoints->InitSequencePoints(entryCount);
1024 // mapCopy and pSeqPoints have elements of different types. Thus, we
1025 // need to copy the individual members from the elements of mapCopy to the
1026 // elements of pSeqPoints. Once we're done, we can release mapCopy
1027 pSeqPoints->CopyAndSortSequencePoints(mapCopy);
1029 } // GetSequencePoints
1031 // ----------------------------------------------------------------------------
1032 // DacDbiInterfaceImpl::TranslateInstrumentedILOffsetToOriginal
1035 // Helper function to convert an instrumented IL offset to the corresponding original IL offset.
1038 // * ilOffset - offset to be translated
1039 // * pMapping - the profiler-provided mapping between original IL offsets and instrumented IL offsets
1042 // Return the translated offset.
1045 ULONG DacDbiInterfaceImpl::TranslateInstrumentedILOffsetToOriginal(ULONG ilOffset,
1046 const InstrumentedILOffsetMapping * pMapping)
1048 SIZE_T cMap = pMapping->GetCount();
1049 ARRAY_PTR_COR_IL_MAP rgMap = pMapping->GetOffsets();
1051 _ASSERTE((cMap == 0) == (rgMap == NULL));
1053 // Early out if there is no mapping, or if we are dealing with a special IL offset such as
1054 // prolog, epilog, etc.
1055 if ((cMap == 0) || ((int)ilOffset < 0))
1061 for (i = 1; i < cMap; i++)
1063 if (ilOffset < rgMap[i].newOffset)
1065 return rgMap[i - 1].oldOffset;
1068 return rgMap[i - 1].oldOffset;
1071 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1073 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1076 // GetILCodeAndSig returns the function's ILCode and SigToken given
1077 // a module and a token. The info will come from a MethodDesc, if
1078 // one exists or from metadata.
1080 void DacDbiInterfaceImpl::GetILCodeAndSig(VMPTR_DomainFile vmDomainFile,
1081 mdToken functionToken,
1082 TargetBuffer * pCodeInfo,
1083 mdToken * pLocalSigToken)
1087 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1088 Module * pModule = pDomainFile->GetCurrentModule();
1092 // preinitialize out params
1094 *pLocalSigToken = mdSignatureNil;
1096 // Get the RVA and impl flags for this method.
1097 IfFailThrow(pModule->GetMDImport()->GetMethodImplProps(functionToken,
1101 MethodDesc* pMethodDesc =
1102 FindLoadedMethodRefOrDef(pModule, functionToken);
1104 // If the RVA is 0 or it's native, then the method is not IL
1107 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Function is not IL - methodRVA == NULL!\n"));
1108 // return (CORDBG_E_FUNCTION_NOT_IL);
1109 // Sanity check this....
1111 if(!pMethodDesc || !pMethodDesc->IsIL())
1113 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: And the MD agrees..\n"));
1114 ThrowHR(CORDBG_E_FUNCTION_NOT_IL);
1118 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: But the MD says it's IL..\n"));
1121 if (pMethodDesc != NULL && pMethodDesc->GetRVA() == 0)
1123 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Actually, MD says RVA is 0 too - keep going...!\n"));
1126 if (IsMiNative(implFlags))
1128 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: Function is not IL - IsMiNative!\n"));
1129 ThrowHR(CORDBG_E_FUNCTION_NOT_IL);
1132 *pLocalSigToken = GetILCodeAndSigHelper(pModule, pMethodDesc, functionToken, methodRVA, pCodeInfo);
1137 LOG((LF_CORDB,LL_INFO100000, "DDI::GICAS: GetMethodImplProps failed!\n"));
1140 } // GetILCodeAndSig
1142 //---------------------------------------------------------------------------------------
1144 // This is just a worker function for GetILCodeAndSig. It returns the function's ILCode and SigToken
1145 // given a module, a token, and the RVA. If a MethodDesc is provided, it has to be consistent with
1146 // the token and the RVA.
1149 // pModule - the Module containing the specified method
1150 // pMD - the specified method; can be NULL
1151 // mdMethodToken - the MethodDef token of the specified method
1152 // methodRVA - the RVA of the IL for the specified method
1153 // pIL - out parameter; return the target address and size of the IL of the specified method
1156 // Return the local variable signature token of the specified method. Can be mdSignatureNil.
1159 mdSignature DacDbiInterfaceImpl::GetILCodeAndSigHelper(Module * pModule,
1161 mdMethodDef mdMethodToken,
1165 _ASSERTE(pModule != NULL);
1167 // If a MethodDesc is provided, it has to be consistent with the MethodDef token and the RVA.
1168 _ASSERTE((pMD == NULL) || ((pMD->GetMemberDef() == mdMethodToken) && (pMD->GetRVA() == methodRVA)));
1170 TADDR pTargetIL; // target address of start of IL blob
1172 // This works for methods in dynamic modules, and methods overriden by a profiler.
1173 pTargetIL = pModule->GetDynamicIL(mdMethodToken, TRUE);
1175 // Method not overriden - get the original copy of the IL by going to the PE file/RVA
1176 // If this is in a dynamic module then don't even attempt this since ReflectionModule::GetIL isn't
1177 // implemend for DAC.
1178 if (pTargetIL == 0 && !pModule->IsReflection())
1180 pTargetIL = (TADDR)pModule->GetIL(methodRVA);
1183 mdSignature mdSig = mdSignatureNil;
1186 // Currently this should only happen for LCG methods (including IL stubs).
1187 // LCG methods have a 0 RVA, and so we don't currently have any way to get the IL here.
1188 _ASSERTE(pMD->IsDynamicMethod());
1189 _ASSERTE(pMD->AsDynamicMethodDesc()->IsLCGMethod()||
1190 pMD->AsDynamicMethodDesc()->IsILStub());
1192 // Clear the buffer.
1197 // Now we have the target address of the IL blob, we need to bring it over to the host.
1198 // DacGetILMethod will copy the COR_ILMETHOD information that we need
1199 COR_ILMETHOD * pHostIL = DacGetIlMethod(pTargetIL); // host address of start of IL blob
1200 COR_ILMETHOD_DECODER header(pHostIL); // host address of header
1203 // Get the IL code info. We need the address of the IL itself, which will be beyond the header
1204 // at the beginning of the blob. We ultimately need the target address. To get this, we take
1205 // target address of the target IL blob and add the offset from the beginning of the host IL blob
1206 // (the header) to the beginning of the IL itself (we get this information from the header).
1207 pIL->pAddress = pTargetIL + ((SIZE_T)(header.Code) - (SIZE_T)pHostIL);
1208 pIL->cbSize = header.GetCodeSize();
1210 // Now we get the signature token
1211 if (header.LocalVarSigTok != NULL)
1213 mdSig = header.GetLocalVarSigTok();
1217 mdSig = mdSignatureNil;
1225 bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
1229 IStringHolder* pStrFilename)
1231 #if !defined(FEATURE_PREJIT)
1235 #else // defined(FEATURE_PREJIT)
1241 PEFile * pPEFile = vmPEFile.GetDacPtr();
1242 _ASSERTE(pPEFile != NULL);
1243 if (pPEFile == NULL)
1246 WCHAR wszFilePath[MAX_LONGPATH] = {0};
1247 DWORD cchFilePath = MAX_LONGPATH;
1248 bool ret = ClrDataAccess::GetMetaDataFileInfoFromPEFile(pPEFile,
1257 pStrFilename->AssignCopy(wszFilePath);
1259 #endif // !defined(FEATURE_PREJIT)
1263 bool DacDbiInterfaceImpl::GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
1266 IStringHolder* pStrFilename)
1268 #if !defined(FEATURE_PREJIT)
1272 #else // defined(FEATURE_PREJIT)
1276 PEFile * pPEFile = vmPEFile.GetDacPtr();
1277 _ASSERTE(pPEFile != NULL);
1278 if (pPEFile == NULL)
1283 WCHAR wszFilePath[MAX_LONGPATH] = {0};
1284 DWORD cchFilePath = MAX_LONGPATH;
1285 bool ret = ClrDataAccess::GetILImageInfoFromNgenPEFile(pPEFile,
1291 pStrFilename->AssignCopy(wszFilePath);
1293 #endif // !defined(FEATURE_PREJIT)
1296 // Get start addresses and sizes for hot and cold regions for a native code blob.
1299 // pMethodDesc - method desc for the function we are inspecting
1300 // Output (required):
1301 // pCodeInfo - initializes the m_rgCodeRegions field of this structure
1302 // if the native code is available. Otherwise,
1303 // pCodeInfo->IsValid() is false.
1305 void DacDbiInterfaceImpl::GetMethodRegionInfo(MethodDesc * pMethodDesc,
1306 NativeCodeFunctionData * pCodeInfo)
1312 PRECONDITION(CheckPointer(pCodeInfo));
1316 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
1317 PCODE functionAddress = pMethodDesc->GetNativeCode();
1319 // get the start address of the hot region and initialize the jit manager
1320 pCodeInfo->m_rgCodeRegions[kHot].pAddress = CORDB_ADDRESS(PCODEToPINSTR(functionAddress));
1322 // if the start address is NULL, the code isn't available yet, so just return
1323 if (functionAddress != NULL)
1325 EECodeInfo codeInfo(functionAddress);
1326 _ASSERTE(codeInfo.IsValid());
1328 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
1330 // now get the rest of the region information
1331 pCodeInfo->m_rgCodeRegions[kHot].cbSize = (ULONG)methodRegionInfo.hotSize;
1332 pCodeInfo->m_rgCodeRegions[kCold].Init(PCODEToPINSTR(methodRegionInfo.coldStartAddress),
1333 (ULONG)methodRegionInfo.coldSize);
1334 _ASSERTE(pCodeInfo->IsValid());
1338 _ASSERTE(!pCodeInfo->IsValid());
1340 } // GetMethodRegionInfo
1343 // Gets the following information about a native code blob:
1344 // - its method desc
1345 // - whether it's an instantiated generic
1346 // - its EnC version number
1347 // - hot and cold region information.
1348 // If the hot region start address is NULL at the end, it means the native code
1349 // isn't currently available. In this case, all values in pCodeInfo will be
1352 void DacDbiInterfaceImpl::GetNativeCodeInfo(VMPTR_DomainFile vmDomainFile,
1353 mdToken functionToken,
1354 NativeCodeFunctionData * pCodeInfo)
1358 _ASSERTE(pCodeInfo != NULL);
1363 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1364 Module * pModule = pDomainFile->GetCurrentModule();
1366 MethodDesc* pMethodDesc = FindLoadedMethodRefOrDef(pModule, functionToken);
1367 pCodeInfo->vmNativeCodeMethodDescToken.SetHostPtr(pMethodDesc);
1369 // if we are loading a module and trying to bind a previously set breakpoint, we may not have
1370 // a method desc yet, so check for that situation
1371 if(pMethodDesc != NULL)
1373 GetMethodRegionInfo(pMethodDesc, pCodeInfo);
1374 if (pCodeInfo->m_rgCodeRegions[kHot].pAddress != NULL)
1376 pCodeInfo->isInstantiatedGeneric = pMethodDesc->HasClassOrMethodInstantiation();
1377 LookupEnCVersions(pModule,
1378 pCodeInfo->vmNativeCodeMethodDescToken,
1380 pCodeInfo->m_rgCodeRegions[kHot].pAddress,
1381 &(pCodeInfo->encVersion));
1384 } // GetNativeCodeInfo
1386 // Gets the following information about a native code blob:
1387 // - its method desc
1388 // - whether it's an instantiated generic
1389 // - its EnC version number
1390 // - hot and cold region information.
1391 void DacDbiInterfaceImpl::GetNativeCodeInfoForAddr(VMPTR_MethodDesc vmMethodDesc,
1392 CORDB_ADDRESS hotCodeStartAddr,
1393 NativeCodeFunctionData * pCodeInfo)
1397 _ASSERTE(pCodeInfo != NULL);
1399 if (hotCodeStartAddr == NULL)
1401 // if the start address is NULL, the code isn't available yet, so just return
1402 _ASSERTE(!pCodeInfo->IsValid());
1406 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
1407 TADDR codeAddr = CORDB_ADDRESS_TO_TADDR(hotCodeStartAddr);
1410 // TADDR should not have the thumb code bit set.
1411 _ASSERTE((codeAddr & THUMB_CODE) == 0);
1412 codeAddr &= ~THUMB_CODE;
1415 EECodeInfo codeInfo(codeAddr);
1416 _ASSERTE(codeInfo.IsValid());
1418 // We may not have the memory for the cold code region in a minidump.
1419 // Do not fail stackwalking because of this.
1420 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
1422 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
1424 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
1426 // Even if GetMethodRegionInfo() fails to retrieve the cold code region info,
1427 // we should still be able to get the hot code region info. We are counting on this for
1428 // stackwalking to work in dump debugging scenarios.
1429 _ASSERTE(methodRegionInfo.hotStartAddress == codeAddr);
1431 // now get the rest of the region information
1432 pCodeInfo->m_rgCodeRegions[kHot].Init(PCODEToPINSTR(methodRegionInfo.hotStartAddress),
1433 (ULONG)methodRegionInfo.hotSize);
1434 pCodeInfo->m_rgCodeRegions[kCold].Init(PCODEToPINSTR(methodRegionInfo.coldStartAddress),
1435 (ULONG)methodRegionInfo.coldSize);
1436 _ASSERTE(pCodeInfo->IsValid());
1438 MethodDesc* pMethodDesc = vmMethodDesc.GetDacPtr();
1439 pCodeInfo->isInstantiatedGeneric = pMethodDesc->HasClassOrMethodInstantiation();
1440 pCodeInfo->vmNativeCodeMethodDescToken = vmMethodDesc;
1442 SIZE_T unusedLatestEncVersion;
1443 Module * pModule = pMethodDesc->GetModule();
1444 _ASSERTE(pModule != NULL);
1445 LookupEnCVersions(pModule,
1447 pMethodDesc->GetMemberDef(),
1449 &unusedLatestEncVersion, //unused by caller
1450 &(pCodeInfo->encVersion));
1452 } // GetNativeCodeInfo
1455 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1457 // Functions to get Type and Class information
1459 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1460 //-----------------------------------------------------------------------------
1461 //DacDbiInterfaceImpl::GetTypeHandles
1462 // Get the approximate and exact type handles for a type
1465 // vmThExact - VMPTR of the exact type handle. If this method is called
1466 // to get information for a new generic instantiation, this will already
1467 // be initialized. If it's called to get type information for an arbitrary
1468 // type (i.e., called to initialize an instance of CordbClass), it will be NULL
1469 // vmThApprox - VMPTR of the approximate type handle. If this method is called
1470 // to get information for a new generic instantiation, this will already
1471 // be initialized. If it's called to get type information for an arbitrary
1472 // type (i.e., called to initialize an instance of CordbClass), it will be NULL
1474 // pThExact - handle for exact type information for a generic instantiation
1475 // pThApprox - handle for type information
1477 // pThExact and pTHApprox must be pointers to existing memory.
1478 //-----------------------------------------------------------------------------
1479 void DacDbiInterfaceImpl::GetTypeHandles(VMPTR_TypeHandle vmThExact,
1480 VMPTR_TypeHandle vmThApprox,
1481 TypeHandle * pThExact,
1482 TypeHandle * pThApprox)
1484 _ASSERTE((pThExact != NULL) && (pThApprox != NULL));
1486 *pThExact = TypeHandle::FromPtr(vmThExact.GetDacPtr());
1487 *pThApprox = TypeHandle::FromPtr(vmThApprox.GetDacPtr());
1489 // 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
1490 // the class is also not restored, then we must pretend that the class is still not loaded. We are gonna let
1491 // unrestored value classes slide, though, and special case access to the class's parent below.
1492 if ((pThApprox->IsNull()) || ((!pThApprox->IsValueType()) && (!pThApprox->IsRestored())))
1494 LOG((LF_CORDB, LL_INFO10000, "D::GASCI: class isn't loaded.\n"));
1495 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
1497 // If the exact type handle is not restored ignore it.
1498 if (!pThExact->IsNull() && !pThExact->IsRestored())
1500 *pThExact = TypeHandle();
1502 } // DacDbiInterfaceImpl::GetTypeHandles
1504 //-----------------------------------------------------------------------------
1505 // DacDbiInterfaceImpl::GetTotalFieldCount
1506 // Gets the total number of fields for a type.
1507 // Input Argument: thApprox - type handle used to determine the number of fields
1508 // Return Value: count of the total fields of the type.
1509 //-----------------------------------------------------------------------------
1510 unsigned int DacDbiInterfaceImpl::GetTotalFieldCount(TypeHandle thApprox)
1512 MethodTable *pMT = thApprox.GetMethodTable();
1514 // Count the instance and static fields for this class (not including parent).
1515 // This will not include any newly added EnC fields.
1516 unsigned int IFCount = pMT->GetNumIntroducedInstanceFields();
1517 unsigned int SFCount = pMT->GetNumStaticFields();
1519 #ifdef EnC_SUPPORTED
1520 PTR_Module pModule = pMT->GetModule();
1522 // Stats above don't include EnC fields. So add them now.
1523 if (pModule->IsEditAndContinueEnabled())
1525 PTR_EnCEEClassData pEncData =
1526 (dac_cast<PTR_EditAndContinueModule>(pModule))->GetEnCEEClassData(pMT, TRUE);
1528 if (pEncData != NULL)
1530 _ASSERTE(pEncData->GetMethodTable() == pMT);
1532 // EnC only adds fields, never removes them.
1533 IFCount += pEncData->GetAddedInstanceFields();
1534 SFCount += pEncData->GetAddedStaticFields();
1538 return IFCount + SFCount;
1539 } // DacDbiInterfaceImpl::GetTotalFieldCount
1541 //-----------------------------------------------------------------------------
1542 // DacDbiInterfaceImpl::InitClassData
1543 // initializes various values of the ClassInfo data structure, including the
1544 // field count, generic args count, size and value class flag
1546 // input: thApprox - used to get access to all the necessary values
1547 // fIsInstantiatedType - used to determine how to compute the size
1548 // output: pData - contains fields to be initialized
1549 //-----------------------------------------------------------------------------
1550 void DacDbiInterfaceImpl::InitClassData(TypeHandle thApprox,
1551 BOOL fIsInstantiatedType,
1554 pData->m_fieldList.Alloc(GetTotalFieldCount(thApprox));
1556 // For Generic classes you must get the object size via the type handle, which
1557 // will get you to the right information for the particular instantiation
1558 // you're working with...
1559 pData->m_objectSize = 0;
1560 if ((!thApprox.GetNumGenericArgs()) || fIsInstantiatedType)
1562 pData->m_objectSize = thApprox.GetMethodTable()->GetNumInstanceFieldBytes();
1565 } // DacDbiInterfaceImpl::InitClassData
1567 //-----------------------------------------------------------------------------
1568 // DacDbiInterfaceImpl::GetStaticsBases
1569 // Gets the base table addresses for both GC and non-GC statics
1571 // input: thExact - exact type handle for the class
1572 // pAppDomain - AppDomain in which the class is loaded
1573 // output: ppGCStaticsBase - base pointer for GC statics
1574 // ppNonGCStaticsBase - base pointer for non GC statics
1576 // If this is a non-generic type, or an instantiated type, then we'll be able to get the static var bases
1577 // If the typeHandle represents a generic type constructor (i.e. an uninstantiated generic class), then
1578 // the static bases will be null (since statics are per-instantiation).
1579 //-----------------------------------------------------------------------------
1580 void DacDbiInterfaceImpl::GetStaticsBases(TypeHandle thExact,
1581 AppDomain * pAppDomain,
1582 PTR_BYTE * ppGCStaticsBase,
1583 PTR_BYTE * ppNonGCStaticsBase)
1585 MethodTable * pMT = thExact.GetMethodTable();
1586 Module * pModuleForStatics = pMT->GetModuleForStatics();
1587 if (pModuleForStatics != NULL)
1589 PTR_DomainLocalModule pLocalModule = pModuleForStatics->GetDomainLocalModule(pAppDomain);
1590 if (pLocalModule != NULL)
1592 *ppGCStaticsBase = pLocalModule->GetGCStaticsBasePointer(pMT);
1593 *ppNonGCStaticsBase = pLocalModule->GetNonGCStaticsBasePointer(pMT);
1596 } // DacDbiInterfaceImpl::GetStaticsBases
1598 //-----------------------------------------------------------------------------
1599 // DacDbiInterfaceImpl::ComputeFieldData
1600 // Computes the field info for pFD and stores it in pcurrentFieldData
1602 // input: pFD - FieldDesc used to get necessary information
1603 // pGCStaticsBase - base table address for GC statics
1604 // pNonGCStaticsBase - base table address for non-GC statics
1605 // output: pCurrentFieldData - contains fields to be initialized
1606 //-----------------------------------------------------------------------------
1607 void DacDbiInterfaceImpl::ComputeFieldData(PTR_FieldDesc pFD,
1608 PTR_BYTE pGCStaticsBase,
1609 PTR_BYTE pNonGCStaticsBase,
1610 FieldData * pCurrentFieldData)
1612 pCurrentFieldData->Initialize(pFD->IsStatic(), pFD->IsPrimitive(), pFD->GetMemberDef());
1614 #ifdef EnC_SUPPORTED
1615 // If the field was newly introduced via EnC, and hasn't yet
1616 // been fixed up, then we'll send back a marker indicating
1617 // that it isn't yet available.
1618 if (pFD->IsEnCNew())
1620 // @dbgtodo Microsoft inspection: eliminate the debugger token when ICDClass and ICDType are
1621 // completely DACized
1622 pCurrentFieldData->m_vmFieldDesc.SetHostPtr(pFD);
1623 pCurrentFieldData->m_fFldStorageAvailable = FALSE;
1624 pCurrentFieldData->m_fFldIsTLS = FALSE;
1625 pCurrentFieldData->m_fFldIsContextStatic = FALSE;
1626 pCurrentFieldData->m_fFldIsRVA = FALSE;
1627 pCurrentFieldData->m_fFldIsCollectibleStatic = FALSE;
1630 #endif // EnC_SUPPORTED
1632 // Otherwise, we'll compute the info & send it back.
1633 pCurrentFieldData->m_fFldStorageAvailable = TRUE;
1634 // @dbgtodo Microsoft inspection: eliminate the debugger token when ICDClass and ICDType are
1635 // completely DACized
1636 pCurrentFieldData->m_vmFieldDesc.SetHostPtr(pFD);
1637 pCurrentFieldData->m_fFldIsTLS = (pFD->IsThreadStatic() == TRUE);
1638 pCurrentFieldData->m_fFldIsContextStatic = (pFD->IsContextStatic() == TRUE);
1639 pCurrentFieldData->m_fFldIsRVA = (pFD->IsRVA() == TRUE);
1640 pCurrentFieldData->m_fFldIsCollectibleStatic = (pFD->IsStatic() == TRUE &&
1641 pFD->GetEnclosingMethodTable()->Collectible());
1643 // Compute the address of the field
1644 if (pFD->IsStatic())
1646 // statics are addressed using an absolute address.
1649 // RVA statics are relative to a base module address
1650 DWORD offset = pFD->GetOffset();
1651 PTR_VOID addr = pFD->GetModule()->GetRvaField(offset, pFD->IsZapped());
1652 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1654 pCurrentFieldData->SetStaticAddress(PTR_TO_TADDR(addr));
1657 else if (pFD->IsThreadStatic() || pFD->IsContextStatic() ||
1658 pCurrentFieldData->m_fFldIsCollectibleStatic)
1660 // this is a special type of static that must be queried using DB_IPCE_GET_SPECIAL_STATIC
1664 // This is a normal static variable in the GC or Non-GC static base table
1665 PTR_BYTE base = pFD->IsPrimitive() ? pNonGCStaticsBase : pGCStaticsBase;
1668 // static var not available. This may be an open generic class (not an instantiated type),
1669 // or we might only have approximate type information because the type hasn't been
1672 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1674 pCurrentFieldData->SetStaticAddress(NULL);
1679 if (pCurrentFieldData->OkToGetOrSetStaticAddress())
1681 // calculate the absolute address using the base and the offset from the base
1682 pCurrentFieldData->SetStaticAddress(PTR_TO_TADDR(base) + pFD->GetOffset());
1689 // instance variables are addressed using an offset within the instance
1690 if (pCurrentFieldData->OkToGetOrSetInstanceOffset())
1692 pCurrentFieldData->SetInstanceOffset(pFD->GetOffset());
1697 } // DacDbiInterfaceImpl::ComputeFieldData
1699 //-----------------------------------------------------------------------------
1700 // DacDbiInterfaceImpl::CollectFields
1701 // Gets information for all the fields for a given type
1703 // input: thExact - used to determine whether we need to get statics base tables
1704 // thApprox - used to get the field desc iterator
1705 // pAppDomain - used to get statics base tables
1707 // pFieldList - contains fields to be initialized
1708 // Note: the caller must ensure that *ppFields is NULL (i.e., any previously allocated memory
1709 // must have been deallocated.
1710 //-----------------------------------------------------------------------------
1711 void DacDbiInterfaceImpl::CollectFields(TypeHandle thExact,
1712 TypeHandle thApprox,
1713 AppDomain * pAppDomain,
1714 DacDbiArrayList<FieldData> * pFieldList)
1716 PTR_BYTE pGCStaticsBase = NULL;
1717 PTR_BYTE pNonGCStaticsBase = NULL;
1718 if (!thExact.IsNull() && !thExact.GetMethodTable()->Collectible())
1720 // get base tables for static fields
1721 GetStaticsBases(thExact, pAppDomain, &pGCStaticsBase, &pNonGCStaticsBase);
1724 unsigned int fieldCount = 0;
1726 // <TODO> we are losing exact type information for static fields in generic types. We have
1727 // field desc iterators only for approximate types, but statics are per instantiation, so we
1728 // need an exact type to be able to handle these correctly. We need to use
1729 // FieldDesc::GetExactDeclaringType to get at the correct field. This requires the exact
1730 // TypeHandle. </TODO>
1731 EncApproxFieldDescIterator fdIterator(thApprox.GetMethodTable(),
1732 ApproxFieldDescIterator::ALL_FIELDS,
1733 FALSE); // don't fixup EnC (we can't, we're stopped)
1735 PTR_FieldDesc pCurrentFD;
1737 while (((pCurrentFD = fdIterator.Next()) != NULL) && (index < pFieldList->Count()))
1739 // fill in the pCurrentEntry structure
1740 ComputeFieldData(pCurrentFD, pGCStaticsBase, pNonGCStaticsBase, &((*pFieldList)[index]));
1742 // Bump our counts and pointers.
1746 _ASSERTE(fieldCount == (unsigned int)pFieldList->Count());
1748 } // DacDbiInterfaceImpl::CollectFields
1751 // Determine if a type is a ValueType
1752 BOOL DacDbiInterfaceImpl::IsValueType (VMPTR_TypeHandle vmTypeHandle)
1756 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
1757 return th.IsValueType();
1760 // Determine if a type has generic parameters
1761 BOOL DacDbiInterfaceImpl::HasTypeParams (VMPTR_TypeHandle vmTypeHandle)
1765 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
1766 return th.ContainsGenericVariables();
1769 // DacDbi API: Get type information for a class
1770 void DacDbiInterfaceImpl::GetClassInfo(VMPTR_AppDomain vmAppDomain,
1771 VMPTR_TypeHandle vmThExact,
1776 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
1779 TypeHandle thApprox;
1781 GetTypeHandles(vmThExact, vmThExact, &thExact, &thApprox);
1783 // initialize field count, generic args count, size and value class flag
1784 InitClassData(thApprox, false, pData);
1786 if (pAppDomain != NULL)
1787 CollectFields(thExact, thApprox, pAppDomain, &(pData->m_fieldList));
1788 } // DacDbiInterfaceImpl::GetClassInfo
1790 // DacDbi API: Get field information and object size for an instantiated generic type
1791 void DacDbiInterfaceImpl::GetInstantiationFieldInfo (VMPTR_DomainFile vmDomainFile,
1792 VMPTR_TypeHandle vmThExact,
1793 VMPTR_TypeHandle vmThApprox,
1794 DacDbiArrayList<FieldData> * pFieldList,
1795 SIZE_T * pObjectSize)
1799 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
1800 _ASSERTE(pDomainFile != NULL);
1801 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
1803 TypeHandle thApprox;
1805 GetTypeHandles(vmThExact, vmThApprox, &thExact, &thApprox);
1807 *pObjectSize = thApprox.GetMethodTable()->GetNumInstanceFieldBytes();
1809 pFieldList->Alloc(GetTotalFieldCount(thApprox));
1811 CollectFields(thExact, thApprox, pAppDomain, pFieldList);
1813 } // DacDbiInterfaceImpl::GetInstantiationFieldInfo
1815 //-----------------------------------------------------------------------------------
1816 // DacDbiInterfaceImpl::TypeDataWalk member functions
1817 //-----------------------------------------------------------------------------------
1819 //-----------------------------------------------------------------------------
1820 // TypeDataWalk constructor--initialize the buffer and number of remaining items from input data
1821 // Arguments: pData - pointer to a list of records containing information about type parameters for an
1822 // instantiated type
1823 // nData - number of entries in pData
1824 //-----------------------------------------------------------------------------
1825 DacDbiInterfaceImpl::TypeDataWalk::TypeDataWalk(DebuggerIPCE_TypeArgData * pData, unsigned int nData)
1827 m_pCurrentData = pData;
1828 m_nRemaining = nData;
1829 } // DacDbiInterfaceImpl::TypeDataWalk::TypeDataWalk
1831 //-----------------------------------------------------------------------------
1832 // DacDbiInterfaceImpl::TypeDataWalk::ReadOne
1833 // read and return a single node from the list of type parameters
1834 // Arguments: none (uses internal state)
1835 // Return value: information about the next type parameter in m_pCurrentData
1836 //-----------------------------------------------------------------------------
1837 DebuggerIPCE_TypeArgData * DacDbiInterfaceImpl::TypeDataWalk::ReadOne()
1839 LIMITED_METHOD_CONTRACT;
1843 return m_pCurrentData++;
1849 } // DacDbiInterfaceImpl::TypeDataWalk::ReadOne
1851 //-----------------------------------------------------------------------------
1852 // DacDbiInterfaceImpl::TypeDataWalk::Skip
1853 // Skip a single node from the list of type handles along with any children it might have
1854 // Arguments: none (uses internal state)
1855 // Return value: none (updates internal state)
1856 //-----------------------------------------------------------------------------
1857 void DacDbiInterfaceImpl::TypeDataWalk::Skip()
1859 LIMITED_METHOD_CONTRACT;
1861 DebuggerIPCE_TypeArgData * pData = ReadOne();
1864 for (unsigned int i = 0; i < pData->numTypeArgs; i++)
1869 } // DacDbiInterfaceImpl::TypeDataWalk::Skip
1871 //-----------------------------------------------------------------------------
1872 // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg
1873 // Read a type handle when it is used in the position of a generic argument or
1874 // argument of an array or address type. Take into account generic code sharing if we
1875 // have been requested to find the canonical representation amongst a set of shared-
1876 // code generic types. That is, if generics code sharing is enabled then return "Object"
1877 // for all reference types, and canonicalize underneath value types, e.g. V<string> --> V<object>.
1878 // Return TypeHandle() if any of the type handles are not loaded.
1880 // Arguments: retrieveWhich - indicates whether to retrieve a canonical representation or
1881 // an exact representation
1882 // Return value: the type handle for the type parameter
1883 //-----------------------------------------------------------------------------
1884 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg(TypeHandleReadType retrieveWhich)
1893 #if !defined(FEATURE_SHARE_GENERIC_CODE)
1894 return ReadLoadedTypeHandle(kGetExact);
1897 if (retrieveWhich == kGetExact)
1898 return ReadLoadedTypeHandle(kGetExact);
1900 // This nasty bit of code works out what the "canonicalization" of a
1901 // parameter to a generic is once we take into account generics code sharing.
1903 // This logic is somewhat a duplication of logic in vm\typehandle.cpp, though
1904 // that logic operates on a TypeHandle format, i.e. assumes we're finding the
1905 // canonical form of a type that has already been loaded. Here we are finding
1906 // the canonical form of a type that may not have been loaded (but where we expect
1907 // its canonical form to have been loaded).
1909 // Ideally this logic would not be duplicated in this way, but it is difficult
1910 // to arrange for that.
1911 DebuggerIPCE_TypeArgData * pData = ReadOne();
1913 return TypeHandle();
1915 // If we have code sharing then the process of canonicalizing is trickier.
1916 // unfortunately we have to include the exact specification of compatibility at
1918 CorElementType elementType = pData->data.elementType;
1920 switch (elementType)
1922 case ELEMENT_TYPE_PTR:
1923 _ASSERTE(pData->numTypeArgs == 1);
1924 return PtrOrByRefTypeArg(pData, retrieveWhich);
1927 case ELEMENT_TYPE_CLASS:
1928 case ELEMENT_TYPE_VALUETYPE:
1929 return ClassTypeArg(pData, retrieveWhich);
1932 case ELEMENT_TYPE_FNPTR:
1933 return FnPtrTypeArg(pData, retrieveWhich);
1937 return ObjRefOrPrimitiveTypeArg(pData, elementType);
1941 #endif // FEATURE_SHARE_GENERIC_CODE
1942 } // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeArg
1944 //-----------------------------------------------------------------------------
1945 // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles
1946 // Iterate through the type argument data, creating type handles as we go.
1949 // input: retrieveWhich - indicates whether we can return a canonical type handle
1950 // or we must return an exact type handle
1951 // nTypeArgs - number of type arguments to be read
1952 // output: ppResults - pointer to a list of TypeHandles that will hold the type handles
1953 // for each type parameter
1955 // Return Value: FALSE iff any of the type handles are not loaded.
1956 //-----------------------------------------------------------------------------
1957 BOOL DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles(TypeHandleReadType retrieveWhich,
1958 unsigned int nTypeArgs,
1959 TypeHandle * ppResults)
1961 WRAPPER_NO_CONTRACT;
1964 for (unsigned int i = 0; i < nTypeArgs; i++)
1966 ppResults[i] = ReadLoadedTypeArg(retrieveWhich);
1967 allOK &= !ppResults[i].IsNull();
1970 } // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandles
1972 //-----------------------------------------------------------------------------
1973 // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation
1974 // Read an instantiation of a generic type if it has already been created.
1977 // input: retrieveWhich - indicates whether we can return a canonical type handle
1978 // or we must return an exact type handle
1979 // pModule - module in which the instantiated type is loaded
1980 // mdToken - metadata token for the type
1981 // nTypeArgs - number of type arguments to be read
1982 // Return value: the type handle for the instantiated type
1983 //-----------------------------------------------------------------------------
1984 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation(TypeHandleReadType retrieveWhich,
1987 unsigned int nTypeArgs)
1989 WRAPPER_NO_CONTRACT;
1991 NewHolder<TypeHandle> pInst(new TypeHandle[nTypeArgs]);
1993 // get the type handle for each of the type parameters
1994 if (!ReadLoadedTypeHandles(retrieveWhich, nTypeArgs, pInst))
1996 return TypeHandle();
1999 // get the type handle for the particular instantiation that corresponds to
2000 // the given type parameters
2001 return FindLoadedInstantiation(pModule, mdToken, nTypeArgs, pInst);
2003 } // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedInstantiation
2006 //-----------------------------------------------------------------------------
2007 // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle
2009 // Compute the type handle for a given type.
2010 // This is the top-level function that will return the type handle for an
2011 // arbitrary type. It uses mutual recursion with ReadLoadedTypeArg to get
2012 // the type handle for a (possibly parameterized) type. Note that the referent of
2013 // address types or the element type of an array type are viewed as type parameters.
2015 // For example, assume that we are retrieving only exact types, and we have as our
2016 // top level type an array defined as int [][].
2017 // We start by noting that the type is an array type, so we call ReadLoadedTypeArg to
2018 // get the element type. We find that the element type is also an array:int [].
2019 // ReadLoadedTypeArg will call ReadLoadedTypeHandle with this type information.
2020 // Again, we determine that the top-level type is an array, so we call ReadLoadedTypeArg
2021 // to get the element type, int. ReadLoadedTypeArg will again call ReadLoadedTypeHandle
2022 // which will find that this time, the top-level type is a primitive type. It will request
2023 // the loaded type handle from the loader and return it. On return, we get the type handle
2024 // for an array of int from the loader. We return again and request the type handle for an
2025 // array of arrays of int. This is the type handle we will return.
2028 // input: retrieveWhich - determines whether we can return the type handle for
2029 // a canonical type or only for an exact type
2030 // we use the list of type data stored in the TypeDataWalk data members
2031 // for other input information
2032 // Return value: type handle for the current type.
2033 //-----------------------------------------------------------------------------
2034 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle(TypeHandleReadType retrieveWhich)
2043 // get the type information at the head of the list m_pCurrentData
2044 DebuggerIPCE_TypeArgData * pData = ReadOne();
2046 return TypeHandle();
2048 // get the type handle that corresponds to its elementType
2049 TypeHandle typeHandle;
2050 switch (pData->data.elementType)
2052 case ELEMENT_TYPE_ARRAY:
2053 case ELEMENT_TYPE_SZARRAY:
2054 typeHandle = ArrayTypeArg(pData, retrieveWhich);
2057 case ELEMENT_TYPE_PTR:
2058 case ELEMENT_TYPE_BYREF:
2059 typeHandle = PtrOrByRefTypeArg(pData, retrieveWhich);
2061 case ELEMENT_TYPE_CLASS:
2062 case ELEMENT_TYPE_VALUETYPE:
2064 Module * pModule = pData->data.ClassTypeData.vmModule.GetDacPtr();
2065 typeHandle = ReadLoadedInstantiation(retrieveWhich,
2067 pData->data.ClassTypeData.metadataToken,
2068 pData->numTypeArgs);
2072 case ELEMENT_TYPE_FNPTR:
2074 typeHandle = FnPtrTypeArg(pData, retrieveWhich);
2079 typeHandle = FindLoadedElementType(pData->data.elementType);
2083 } // DacDbiInterfaceImpl::TypeDataWalk::ReadLoadedTypeHandle
2085 //-----------------------------------------------------------------------------
2086 // DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg
2087 // get a loaded type handle for an array type (E_T_ARRAY or E_T_SZARRAY)
2090 // input: pArrayTypeInfo - type information for an array type
2091 // Although this is in fact a pointer (in)to a list, we treat it here
2092 // simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2093 // which holds type information for an array.
2094 // This is the most recent type node (for an array type) retrieved
2095 // by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeArg will
2096 // result in call(s) to ReadOne to retrieve one or more type nodes
2097 // that are needed to compute the type handle for the
2098 // element type of the array. When we return from that call, we pass
2099 // pArrayTypeInfo along with arrayElementTypeArg to FindLoadedArrayType
2100 // to get the type handle for this particular array type.
2102 // On entry, we know that pArrayTypeInfo is the same as m_pCurrentData - 1,
2103 // but by the time we need to use it, this is no longer true. Because
2104 // we can't predict how many nodes will be consumed by the call to
2105 // ReadLoadedTypeArg, we can't compute this value from the member fields
2106 // of TypeDataWalk and therefore pass it as a parameter.
2107 // retrieveWhich - determines whether we can return the type handle for
2108 // a canonical type or only for an exact type
2109 // Return value: the type handle corresponding to the array type
2110 //-----------------------------------------------------------------------------
2112 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg(DebuggerIPCE_TypeArgData * pArrayTypeInfo,
2113 TypeHandleReadType retrieveWhich)
2115 TypeHandle arrayElementTypeArg = ReadLoadedTypeArg(retrieveWhich);
2116 if (!arrayElementTypeArg.IsNull())
2118 return FindLoadedArrayType(pArrayTypeInfo->data.elementType,
2119 arrayElementTypeArg,
2120 pArrayTypeInfo->data.ArrayTypeData.arrayRank);
2122 return TypeHandle();
2123 } // DacDbiInterfaceImpl::TypeDataWalk::ArrayTypeArg
2126 //-----------------------------------------------------------------------------
2127 // DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg
2128 // get a loaded type handle for an address type (E_T_PTR or E_T_BYREF)
2131 // input: pPtrOrByRefTypeInfo - type information for a pointer or byref type
2132 // Although this is in fact a pointer (in)to a list, we treat it here
2133 // simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2134 // which holds type information for a pointer or byref type.
2135 // This is the most recent type node (for a pointer or byref type) retrieved
2136 // by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeArg will
2137 // result in call(s) to ReadOne to retrieve one or more type nodes
2138 // that are needed to compute the type handle for the
2139 // referent type of the pointer. When we return from that call, we pass
2140 // pPtrOrByRefTypeInfo along with referentTypeArg to FindLoadedPointerOrByrefType
2141 // to get the type handle for this particular pointer or byref type.
2143 // On entry, we know that pPtrOrByRefTypeInfo is the same as m_pCurrentData - 1,
2144 // but by the time we need to use it, this is no longer true. Because
2145 // we can't predict how many nodes will be consumed by the call to
2146 // ReadLoadedTypeArg, we can't compute this value from the member fields
2147 // of TypeDataWalk and therefore pass it as a parameter.
2148 // retrieveWhich - determines whether we can return the type handle for
2149 // a canonical type or only for an exact type
2150 // Return value: the type handle corresponding to the address type
2151 //-----------------------------------------------------------------------------
2152 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg(DebuggerIPCE_TypeArgData * pPtrOrByRefTypeInfo,
2153 TypeHandleReadType retrieveWhich)
2155 TypeHandle referentTypeArg = ReadLoadedTypeArg(retrieveWhich);
2156 if (!referentTypeArg.IsNull())
2158 return FindLoadedPointerOrByrefType(pPtrOrByRefTypeInfo->data.elementType, referentTypeArg);
2161 return TypeHandle();
2163 } // DacDbiInterfaceImpl::TypeDataWalk::PtrOrByRefTypeArg
2165 //-----------------------------------------------------------------------------
2166 // DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg
2167 // get a loaded type handle for a class type (E_T_CLASS or E_T_VALUETYPE)
2170 // input: pClassTypeInfo - type information for a class type
2171 // Although this is in fact a pointer (in)to a list, we treat it here
2172 // simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2173 // which holds type information for a pointer or byref type.
2174 // This is the most recent type node (for a pointer or byref type) retrieved
2175 // by TypeDataWalk::ReadOne(). The call to ReadLoadedInstantiation will
2176 // result in call(s) to ReadOne to retrieve one or more type nodes
2177 // that are needed to compute the type handle for the type parameters
2178 // for the class. If we can't find an exact loaded type for the class, we will
2179 // instead return a canonical method table. In this case, we need to skip
2180 // the type parameter information for each actual parameter to the class.
2181 // This is necessary because we may be getting a type handle for a class which is
2182 // in turn an argument to a parent type. If the parent type has more arguments, we
2183 // need to be at the right place in the list when we return. We use
2184 // pClassTypeInfo to get the number of type arguments that we need to skip.
2185 // retrieveWhich - determines whether we can return the type handle for
2186 // a canonical type or only for an exact type
2187 // Return value: the type handle corresponding to the class type
2188 //-----------------------------------------------------------------------------
2189 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg(DebuggerIPCE_TypeArgData * pClassTypeInfo,
2190 TypeHandleReadType retrieveWhich)
2192 Module * pModule = pClassTypeInfo->data.ClassTypeData.vmModule.GetDacPtr();
2193 TypeHandle typeDef = ClassLoader::LookupTypeDefOrRefInModule(pModule,
2194 pClassTypeInfo->data.ClassTypeData.metadataToken);
2196 if ((!typeDef.IsNull() && typeDef.IsValueType()) || (pClassTypeInfo->data.elementType == ELEMENT_TYPE_VALUETYPE))
2198 return ReadLoadedInstantiation(retrieveWhich,
2200 pClassTypeInfo->data.ClassTypeData.metadataToken,
2201 pClassTypeInfo->numTypeArgs);
2205 _ASSERTE(retrieveWhich == kGetCanonical);
2206 // skip the instantiation - no need to look at it since the type canonicalizes to "Object"
2207 for (unsigned int i = 0; i < pClassTypeInfo->numTypeArgs; i++)
2211 return TypeHandle(g_pCanonMethodTableClass);
2213 }// DacDbiInterfaceImpl::TypeDataWalk::ClassTypeArg
2215 //-----------------------------------------------------------------------------
2216 // DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg
2217 // get a loaded type handle for a function pointer type (E_T_FNPTR)
2220 // input: pFnPtrTypeInfo - type information for a pointer or byref type
2221 // Although this is in fact a pointer (in)to a list, we treat it here
2222 // simply as a pointer to a single instance of DebuggerIPCE_TypeArgData
2223 // which holds type information for a function pointer type.
2224 // This is the most recent type node (for a function pointer type) retrieved
2225 // by TypeDataWalk::ReadOne(). The call to ReadLoadedTypeHandles will
2226 // result in call(s) to ReadOne to retrieve one or more type nodes
2227 // that are needed to compute the type handle for the return type and
2228 // parameter types of the function. When we return from that call, we pass
2229 // pFnPtrTypeInfo along with pInst to FindLoadedFnptrType
2230 // to get the type handle for this particular function pointer type.
2231 // retrieveWhich - determines whether we can return the type handle for
2232 // a canonical type or only for an exact type
2233 // Return value: the type handle corresponding to the function pointer type
2234 //-----------------------------------------------------------------------------
2235 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg(DebuggerIPCE_TypeArgData * pFnPtrTypeInfo,
2236 TypeHandleReadType retrieveWhich)
2238 // allocate space to store a list of type handles, one for the return type and one for each
2239 // of the parameter types of the function to which the FnPtr type refers.
2240 NewHolder<TypeHandle> pInst(new TypeHandle[sizeof(TypeHandle) * pFnPtrTypeInfo->numTypeArgs]);
2242 if (ReadLoadedTypeHandles(retrieveWhich, pFnPtrTypeInfo->numTypeArgs, pInst))
2244 return FindLoadedFnptrType(pFnPtrTypeInfo->numTypeArgs, pInst);
2247 return TypeHandle();
2249 } // DacDbiInterfaceImpl::TypeDataWalk::FnPtrTypeArg
2251 //-----------------------------------------------------------------------------
2252 // DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg
2253 // get a loaded type handle for a primitive type or ObjRef
2256 // input: pArgInfo - type information for an objref or primitive type.
2257 // This is called only when the objref or primitive type
2258 // is a type argument for a parent type. In this case,
2259 // we treat all objrefs the same, that is, we don't care
2260 // about type parameters for the referent. Instead, we will
2261 // simply return the canonical object type handle as the type
2262 // of the referent. <@dbgtodo Microsoft: why is this?>
2263 // If this is a primitive type, we'll simply get the
2264 // type handle for that type.
2265 // elementType - type of the argument
2266 // Return value: the type handle corresponding to the elementType
2267 //-----------------------------------------------------------------------------
2268 TypeHandle DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg(DebuggerIPCE_TypeArgData * pArgInfo,
2269 CorElementType elementType)
2271 // If there are any type args (e.g. for arrays) they can be skipped. The thing
2272 // is a reference type anyway.
2273 for (unsigned int i = 0; i < pArgInfo->numTypeArgs; i++)
2278 // for an ObjRef, just return the CLASS____CANON type handle
2279 if (CorTypeInfo::IsObjRef_NoThrow(elementType))
2281 return TypeHandle(g_pCanonMethodTableClass);
2285 return FindLoadedElementType(elementType);
2287 } // DacDbiInterfaceImpl::TypeDataWalk::ObjRefOrPrimitiveTypeArg
2290 //-------------------------------------------------------------------------
2291 // end of TypeDataWalk implementations
2292 //-------------------------------------------------------------------------
2293 //-------------------------------------------------------------------------
2294 // functions to use loader to get type handles
2295 // ------------------------------------------------------------------------
2297 // Note, in these functions, the use of ClassLoader::DontLoadTypes was chosen
2298 // instead of FailIfNotLoaded because, although we may want to debug unrestored
2299 // VCs, we can't do it because the debug API is not set up to handle them.
2301 //-----------------------------------------------------------------------------
2302 // DacDbiInterfaceImpl::FindLoadedArrayType
2303 // Use ClassLoader to find a loaded type handle for an array type (E_T_ARRAY or E_T_SZARRAY)
2305 // input: arrayType - type of the array
2306 // TypeArg - type handle for the base type
2307 // rank - array rank
2308 // Return Value: type handle for the array type
2309 //-----------------------------------------------------------------------------
2311 TypeHandle DacDbiInterfaceImpl::FindLoadedArrayType(CorElementType arrayType,
2315 // Lookup operations run the class loader in non-load mode.
2316 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2318 if (typeArg.IsNull())
2320 return TypeHandle();
2324 return ClassLoader::LoadArrayTypeThrowing(typeArg,
2327 ClassLoader::DontLoadTypes );
2329 } // DacDbiInterfaceImpl::FindLoadedArrayType;
2331 //-----------------------------------------------------------------------------
2332 // DacDbiInterfaceImpl::FindLoadedPointerOrByrefType
2333 // Use ClassLoader to find a loaded type handle for an address type (E_T_PTR or E_T_BYREF)
2335 // input: addressType - type of the address type
2336 // TypeArg - type handle for the base type
2337 // Return Value: type handle for the address type
2338 //-----------------------------------------------------------------------------
2340 TypeHandle DacDbiInterfaceImpl::FindLoadedPointerOrByrefType(CorElementType addressType, TypeHandle typeArg)
2342 // Lookup operations run the class loader in non-load mode.
2343 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2345 return ClassLoader::LoadPointerOrByrefTypeThrowing(addressType,
2347 ClassLoader::DontLoadTypes);
2348 } // DacDbiInterfaceImpl::FindLoadedPointerOrByrefType
2350 //-----------------------------------------------------------------------------
2351 // DacDbiInterfaceImpl::FindLoadedFnptrType
2352 // Use ClassLoader to find a loaded type handle for a function pointer type (E_T_FNPTR)
2354 // input: pInst - type handles of the function's return value and arguments
2355 // numTypeArgs - number of type handles in pInst
2356 // Return Value: type handle for the function pointer type
2357 //-----------------------------------------------------------------------------
2359 TypeHandle DacDbiInterfaceImpl::FindLoadedFnptrType(DWORD numTypeArgs, TypeHandle * pInst)
2361 // Lookup operations run the class loader in non-load mode.
2362 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2364 // @dbgtodo : Do we need to worry about calling convention here?
2365 // LoadFnptrTypeThrowing expects the count of arguments, not
2366 // including return value, so we subtract 1 from numTypeArgs.
2367 return ClassLoader::LoadFnptrTypeThrowing(0,
2370 ClassLoader::DontLoadTypes);
2371 } // DacDbiInterfaceImpl::FindLoadedFnptrType
2373 //-----------------------------------------------------------------------------
2374 // DacDbiInterfaceImpl::FindLoadedInstantiation
2375 // Use ClassLoader to find a loaded type handle for a particular instantiation of a
2376 // class type (E_T_CLASS or E_T_VALUECLASS)
2379 // input: pModule - module in which the type is loaded
2380 // mdToken - metadata token for the type
2381 // nTypeArgs - number of type arguments in pInst
2382 // pInst - list of type handles for the type parameters
2383 // Return value: type handle for the instantiated class type
2384 //-----------------------------------------------------------------------------
2386 TypeHandle DacDbiInterfaceImpl::FindLoadedInstantiation(Module * pModule,
2391 // Lookup operations run the class loader in non-load mode.
2392 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2394 return ClassLoader::LoadGenericInstantiationThrowing(pModule,
2396 Instantiation(pInst,nTypeArgs),
2397 ClassLoader::DontLoadTypes);
2399 } // DacDbiInterfaceImpl::FindLoadedInstantiation
2401 //-----------------------------------------------------------------------------
2402 // DacDbiInterfaceImpl::FindLoadedElementType
2403 // Get the type handle for a primitive type
2405 // input: elementType - type of the primitive type
2406 // Return Value: Type handle for the primitive type
2407 //-----------------------------------------------------------------------------
2409 TypeHandle DacDbiInterfaceImpl::FindLoadedElementType(CorElementType elementType)
2411 // Lookup operations run the class loader in non-load mode.
2412 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2414 MethodTable * pMethodTable = (&g_Mscorlib)->GetElementType(elementType);
2416 return TypeHandle(pMethodTable);
2417 } // DacDbiInterfaceImpl::FindLoadedElementType
2420 //-----------------------------------------------------------------------------
2421 // DacDbiInterfaceImpl::GetArrayTypeInfo
2422 // Gets additional information to convert a type handle to an instance of CordbType if the type is E_T_ARRAY.
2423 // Specifically, we get the rank and the type of the array elements
2426 // input: typeHandle - type handle for the array type
2427 // pAppDomain - AppDomain into which the type is loaded
2428 // output: pTypeInfo - information for the array rank and element type
2430 //-----------------------------------------------------------------------------
2431 void DacDbiInterfaceImpl::GetArrayTypeInfo(TypeHandle typeHandle,
2432 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2433 AppDomain * pAppDomain)
2435 _ASSERTE(typeHandle.IsArray());
2436 pTypeInfo->ArrayTypeData.arrayRank = typeHandle.AsArray()->GetRank();
2437 TypeHandleToBasicTypeInfo(typeHandle.AsArray()->GetArrayElementTypeHandle(),
2438 &(pTypeInfo->ArrayTypeData.arrayTypeArg),
2440 } // DacDbiInterfaceImpl::GetArrayTypeInfo
2442 //-----------------------------------------------------------------------------
2443 // DacDbiInterfaceImpl::GetPtrTypeInfo
2444 // Gets additional information to convert a type handle to an instance of CordbType if the type is
2445 // E_T_PTR or E_T_BYREF. Specifically, we get the type for the referent of the address type
2448 // input: boxed - indicates what, if anything, is boxed (see code:AreValueTypesBoxed for
2449 // more specific information)
2450 // typeHandle - type handle for the address type
2451 // pAppDomain - AppDomain into which the type is loaded
2452 // output: pTypeInfo - information for the referent type
2454 //-----------------------------------------------------------------------------
2455 void DacDbiInterfaceImpl::GetPtrTypeInfo(AreValueTypesBoxed boxed,
2456 TypeHandle typeHandle,
2457 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2458 AppDomain * pAppDomain)
2460 if (boxed == AllBoxed)
2462 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2466 _ASSERTE(typeHandle.IsTypeDesc());
2467 TypeHandleToBasicTypeInfo(typeHandle.AsTypeDesc()->GetTypeParam(),
2468 &(pTypeInfo->UnaryTypeData.unaryTypeArg),
2471 } // DacDbiInterfaceImpl::GetPtrTypeInfo
2473 //-----------------------------------------------------------------------------
2474 // DacDbiInterfaceImpl::GetFnPtrTypeInfo
2475 // Gets additional information to convert a type handle to an instance of CordbType if the type is
2476 // E_T_FNPTR, specifically the typehandle for the referent.
2479 // input: boxed - indicates what, if anything, is boxed (see code:AreValueTypesBoxed for
2480 // more specific information)
2481 // typeHandle - type handle for the address type
2482 // pAppDomain - AppDomain into which the type is loaded
2483 // output: pTypeInfo - information for the referent type
2485 //-----------------------------------------------------------------------------
2486 void DacDbiInterfaceImpl::GetFnPtrTypeInfo(AreValueTypesBoxed boxed,
2487 TypeHandle typeHandle,
2488 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2489 AppDomain * pAppDomain)
2491 if (boxed == AllBoxed)
2493 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2497 pTypeInfo->NaryTypeData.typeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2499 } // DacDbiInterfaceImpl::GetFnPtrTypeInfo
2502 //-----------------------------------------------------------------------------
2503 // DacDbiInterfaceImpl::GetClassTypeInfo
2504 // Gets additional information to convert a type handle to an instance of CordbType if the type is
2505 // E_T_CLASS or E_T_VALUETYPE
2508 // input: typeHandle - type handle for the address type
2509 // pAppDomain - AppDomain into which the type is loaded
2510 // output: pTypeInfo - information for the referent type
2512 //-----------------------------------------------------------------------------
2513 void DacDbiInterfaceImpl::GetClassTypeInfo(TypeHandle typeHandle,
2514 DebuggerIPCE_ExpandedTypeData * pTypeInfo,
2515 AppDomain * pAppDomain)
2517 Module * pModule = typeHandle.GetModule();
2519 if (typeHandle.HasInstantiation()) // the type handle represents a generic instantiation
2521 pTypeInfo->ClassTypeData.typeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2525 pTypeInfo->ClassTypeData.typeHandle = VMPTR_TypeHandle::NullPtr();
2528 pTypeInfo->ClassTypeData.metadataToken = typeHandle.GetCl();
2531 pTypeInfo->ClassTypeData.vmModule.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule));
2534 pTypeInfo->ClassTypeData.vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule->GetDomainFile(pAppDomain)));
2538 pTypeInfo->ClassTypeData.vmDomainFile = VMPTR_DomainFile::NullPtr();
2540 } // DacDbiInterfaceImpl::GetClassTypeInfo
2542 //-----------------------------------------------------------------------------
2543 // DacDbiInterfaceImpl::GetElementType
2544 // Gets the correct CorElementType value from a type handle
2547 // input: typeHandle - type handle for the address type
2548 // Return Value: the CorElementType enum value for the type handle
2549 //-----------------------------------------------------------------------------
2550 CorElementType DacDbiInterfaceImpl::GetElementType (TypeHandle typeHandle)
2552 if (typeHandle.IsNull())
2554 return ELEMENT_TYPE_VOID;
2556 else if (typeHandle.GetMethodTable() == g_pObjectClass)
2558 return ELEMENT_TYPE_OBJECT;
2560 else if (typeHandle.GetMethodTable() == g_pStringClass)
2562 return ELEMENT_TYPE_STRING;
2566 // GetSignatureCorElementType returns E_T_CLASS for E_T_STRING... :-(
2567 return typeHandle.GetSignatureCorElementType();
2570 } // DacDbiInterfaceImpl::GetElementType
2572 //-----------------------------------------------------------------------------
2573 // DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo
2574 // Gets additional information to convert a type handle to an instance of CordbType for the referent of an
2575 // E_T_BYREF or E_T_PTR or for the element type of an E_T_ARRAY or E_T_SZARRAY
2578 // input: typeHandle - type handle for the address type
2579 // pAppDomain - AppDomain into which the type is loaded
2580 // output: pTypeInfo - information for the referent type
2582 //-----------------------------------------------------------------------------
2583 void DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo(TypeHandle typeHandle,
2584 DebuggerIPCE_BasicTypeData * pTypeInfo,
2585 AppDomain * pAppDomain)
2587 pTypeInfo->elementType = GetElementType(typeHandle);
2589 switch (pTypeInfo->elementType)
2591 case ELEMENT_TYPE_ARRAY:
2592 case ELEMENT_TYPE_SZARRAY:
2593 case ELEMENT_TYPE_FNPTR:
2594 case ELEMENT_TYPE_PTR:
2595 case ELEMENT_TYPE_BYREF:
2596 pTypeInfo->vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2597 pTypeInfo->metadataToken = mdTokenNil;
2598 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2601 case ELEMENT_TYPE_CLASS:
2602 case ELEMENT_TYPE_VALUETYPE:
2604 Module * pModule = typeHandle.GetModule();
2606 if (typeHandle.HasInstantiation()) // only set if instantiated
2608 pTypeInfo->vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2612 pTypeInfo->vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2615 pTypeInfo->metadataToken = typeHandle.GetCl();
2618 pTypeInfo->vmModule.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule));
2621 pTypeInfo->vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pModule->GetDomainFile(pAppDomain)));
2625 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2631 pTypeInfo->vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2632 pTypeInfo->metadataToken = mdTokenNil;
2633 pTypeInfo->vmDomainFile = VMPTR_DomainFile::NullPtr();
2637 } // DacDbiInterfaceImpl::TypeHandleToBasicTypeInfo
2640 void DacDbiInterfaceImpl::GetObjectExpandedTypeInfoFromID(AreValueTypesBoxed boxed,
2641 VMPTR_AppDomain vmAppDomain,
2643 DebuggerIPCE_ExpandedTypeData *pTypeInfo)
2647 PTR_MethodTable pMT(TO_TADDR(id.token1));
2651 // ArrayBase::GetTypeHandle() may return a NULL handle in corner case scenarios. This check prevents
2652 // us from an AV but doesn't actually fix the problem. See DevDiv 653441 for more info.
2653 TypeHandle arrayHandle = ArrayBase::GetTypeHandle(pMT);
2654 if (arrayHandle.IsNull())
2656 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2659 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, arrayHandle, pTypeInfo);
2663 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, TypeHandle::FromPtr(TO_TADDR(id.token1)), pTypeInfo);
2667 void DacDbiInterfaceImpl::GetObjectExpandedTypeInfo(AreValueTypesBoxed boxed,
2668 VMPTR_AppDomain vmAppDomain,
2670 DebuggerIPCE_ExpandedTypeData *pTypeInfo)
2674 PTR_Object obj(TO_TADDR(addr));
2675 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, obj->GetGCSafeTypeHandle(), pTypeInfo);
2678 // DacDbi API: use a type handle to get the information needed to create the corresponding RS CordbType instance
2679 void DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed,
2680 VMPTR_AppDomain vmAppDomain,
2681 VMPTR_TypeHandle vmTypeHandle,
2682 DebuggerIPCE_ExpandedTypeData * pTypeInfo)
2687 TypeHandle typeHandle = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
2688 TypeHandleToExpandedTypeInfoImpl(boxed, vmAppDomain, typeHandle, pTypeInfo);
2692 void DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed,
2693 VMPTR_AppDomain vmAppDomain,
2694 TypeHandle typeHandle,
2695 DebuggerIPCE_ExpandedTypeData * pTypeInfo)
2697 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
2698 pTypeInfo->elementType = GetElementType(typeHandle);
2700 switch (pTypeInfo->elementType)
2702 case ELEMENT_TYPE_ARRAY:
2703 case ELEMENT_TYPE_SZARRAY:
2704 GetArrayTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2707 case ELEMENT_TYPE_PTR:
2708 case ELEMENT_TYPE_BYREF:
2709 GetPtrTypeInfo(boxed, typeHandle, pTypeInfo, pAppDomain);
2712 case ELEMENT_TYPE_VALUETYPE:
2713 if (boxed == OnlyPrimitivesUnboxed || boxed == AllBoxed)
2715 pTypeInfo->elementType = ELEMENT_TYPE_CLASS;
2717 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2720 case ELEMENT_TYPE_CLASS:
2721 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2724 case ELEMENT_TYPE_FNPTR:
2725 GetFnPtrTypeInfo(boxed, typeHandle, pTypeInfo, pAppDomain);
2728 if (boxed == AllBoxed)
2730 pTypeInfo->elementType = ELEMENT_TYPE_CLASS;
2731 GetClassTypeInfo(typeHandle, pTypeInfo, pAppDomain);
2733 // else the element type is sufficient
2736 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 } // DacDbiInterfaceImpl::TypeHandleToExpandedTypeInfo
2740 // Get type handle for a TypeDef token, if one exists. For generics this returns the open type.
2741 VMPTR_TypeHandle DacDbiInterfaceImpl::GetTypeHandle(VMPTR_Module vmModule,
2742 mdTypeDef metadataToken)
2745 Module* pModule = vmModule.GetDacPtr();
2746 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2748 TypeHandle th = ClassLoader::LookupTypeDefOrRefInModule(pModule, metadataToken);
2751 LOG((LF_CORDB, LL_INFO10000, "D::GTH: class isn't loaded.\n"));
2752 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2755 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
2756 return vmTypeHandle;
2759 // DacDbi API: GetAndSendApproxTypeHandle finds the type handle for the layout of the instance fields of an
2760 // instantiated type if it is available.
2761 VMPTR_TypeHandle DacDbiInterfaceImpl::GetApproxTypeHandle(TypeInfoList * pTypeData)
2765 LOG((LF_CORDB, LL_INFO10000, "D::GATH: getting info.\n"));
2768 TypeDataWalk walk(&((*pTypeData)[0]), pTypeData->Count());
2769 TypeHandle typeHandle = walk.ReadLoadedTypeHandle(TypeDataWalk::kGetCanonical);
2770 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2772 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2773 if (!typeHandle.IsNull())
2775 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2779 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2782 LOG((LF_CORDB, LL_INFO10000,
2783 "D::GATH: sending result, result = 0x%0x8\n",
2785 return vmTypeHandle;
2786 } // DacDbiInterfaceImpl::GetApproxTypeHandle
2788 // DacDbiInterface API: Get the exact type handle from type data
2789 HRESULT DacDbiInterfaceImpl::GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData,
2790 ArgInfoList * pArgInfo,
2791 VMPTR_TypeHandle& vmTypeHandle)
2795 LOG((LF_CORDB, LL_INFO10000, "D::GETH: getting info.\n"));
2801 vmTypeHandle = vmTypeHandle.NullPtr();
2803 // convert the type information to a type handle
2804 TypeHandle typeHandle = ExpandedTypeInfoToTypeHandle(pTypeData, pArgInfo);
2805 _ASSERTE(!typeHandle.IsNull());
2806 vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr());
2808 EX_CATCH_HRESULT(hr);
2811 } // DacDbiInterfaceImpl::GetExactTypeHandle
2813 // Retrieve the generic type params for a given MethodDesc. This function is specifically
2814 // for stackwalking because it requires the generic type token on the stack.
2815 void DacDbiInterfaceImpl::GetMethodDescParams(
2816 VMPTR_AppDomain vmAppDomain,
2817 VMPTR_MethodDesc vmMethodDesc,
2818 GENERICS_TYPE_TOKEN genericsToken,
2819 UINT32 * pcGenericClassTypeParams,
2820 TypeParamsList * pGenericTypeParams)
2824 if (vmAppDomain.IsNull() || vmMethodDesc.IsNull())
2826 ThrowHR(E_INVALIDARG);
2829 _ASSERTE((pcGenericClassTypeParams != NULL) && (pGenericTypeParams != NULL));
2831 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
2833 // Retrieve the number of type parameters for the class and
2834 // the number of type parameters for the method itself.
2835 // For example, the method Foo<T, U>::Bar<V>() has 2 class type parameters and 1 method type parameters.
2836 UINT32 cGenericClassTypeParams = pMD->GetNumGenericClassArgs();
2837 UINT32 cGenericMethodTypeParams = pMD->GetNumGenericMethodArgs();
2838 UINT32 cTotalGenericTypeParams = cGenericClassTypeParams + cGenericMethodTypeParams;
2840 // Set the out parameter.
2841 *pcGenericClassTypeParams = cGenericClassTypeParams;
2843 TypeHandle thSpecificClass;
2844 MethodDesc * pSpecificMethod;
2846 // Try to retrieve a more specific MethodDesc and TypeHandle via the generics type token.
2847 // The generics token is not always guaranteed to be available.
2848 // For example, it may be unavailable in prologs and epilogs.
2849 // In dumps, not available can also mean a thrown exception for missing memory.
2850 BOOL fExact = FALSE;
2851 ALLOW_DATATARGET_MISSING_MEMORY(
2852 fExact = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
2854 PTR_VOID((TADDR)genericsToken),
2859 !thSpecificClass.GetMethodTable()->SanityCheck() ||
2860 !pSpecificMethod->GetMethodTable()->SanityCheck())
2862 // Use the canonical MethodTable and MethodDesc if the exact generics token is not available.
2863 thSpecificClass = TypeHandle(pMD->GetMethodTable());
2864 pSpecificMethod = pMD;
2867 // Retrieve the array of class type parameters and the array of method type parameters.
2868 Instantiation classInst = pSpecificMethod->GetExactClassInstantiation(thSpecificClass);
2869 Instantiation methodInst = pSpecificMethod->GetMethodInstantiation();
2871 _ASSERTE((classInst.IsEmpty()) == (cGenericClassTypeParams == 0));
2872 _ASSERTE((methodInst.IsEmpty()) == (cGenericMethodTypeParams == 0));
2874 // allocate memory for the return array
2875 pGenericTypeParams->Alloc(cTotalGenericTypeParams);
2877 for (UINT32 i = 0; i < cTotalGenericTypeParams; i++)
2879 // Retrieve the current type parameter depending on the index.
2880 TypeHandle thCurrent;
2881 if (i < cGenericClassTypeParams)
2883 thCurrent = classInst[i];
2887 thCurrent = methodInst[i - cGenericClassTypeParams];
2890 // There is the possiblity that we'll get this far with a dump and not fail, but still
2891 // not be able to get full info for a particular param.
2892 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2894 // Fill in the struct using the TypeHandle of the current type parameter if we can.
2895 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
2896 vmTypeHandle.SetDacTargetPtr(thCurrent.AsTAddr());
2897 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
2900 &((*pGenericTypeParams)[i]));
2902 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2904 // On failure for a particular type, default it back to System.__Canon.
2905 VMPTR_TypeHandle vmTHCanon = VMPTR_TypeHandle::NullPtr();
2906 TypeHandle thCanon = TypeHandle(g_pCanonMethodTableClass);
2907 vmTHCanon.SetDacTargetPtr(thCanon.AsTAddr());
2908 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
2911 &((*pGenericTypeParams)[i]));
2913 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
2917 //-----------------------------------------------------------------------------
2918 // DacDbiInterfaceImpl::GetClassOrValueTypeHandle
2919 // get a typehandle for a class or valuetype from basic type data (metadata token
2920 // and domain file).
2922 // input: pData - contains the metadata token and domain file
2923 // Return value: the type handle for the corresponding type
2924 //-----------------------------------------------------------------------------
2925 TypeHandle DacDbiInterfaceImpl::GetClassOrValueTypeHandle(DebuggerIPCE_BasicTypeData * pData)
2927 TypeHandle typeHandle;
2929 // if we already have a type handle, just return it
2930 if (!pData->vmTypeHandle.IsNull())
2932 typeHandle = TypeHandle::FromPtr(pData->vmTypeHandle.GetDacPtr());
2934 // otherwise, have the loader look it up using the metadata token and domain file
2937 DomainFile * pDomainFile = pData->vmDomainFile.GetDacPtr();
2938 Module * pModule = pDomainFile->GetModule();
2940 typeHandle = ClassLoader::LookupTypeDefOrRefInModule(pModule, pData->metadataToken);
2941 if (typeHandle.IsNull())
2943 LOG((LF_CORDB, LL_INFO10000, "D::BTITTH: class isn't loaded.\n"));
2944 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
2947 _ASSERTE(typeHandle.GetNumGenericArgs() == 0);
2952 } // DacDbiInterfaceImpl::GetClassOrValueTypeHandle
2954 //-----------------------------------------------------------------------------
2955 // DacDbiInterfaceImpl::GetExactArrayTypeHandle
2956 // get an exact type handle for an array type
2958 // input: pTopLevelTypeData - type information for a top-level array type
2959 // pArgInfo - contains the following information:
2960 // m_genericArgsCount - number of generic parameters for the element type--this should be 1
2961 // m_pGenericArgs - pointer to the generic parameter for the element type--this is
2962 // effectively a one-element list. These are the actual parameters
2963 // Return Value: the exact type handle for the type
2964 //-----------------------------------------------------------------------------
2965 TypeHandle DacDbiInterfaceImpl::GetExactArrayTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
2966 ArgInfoList * pArgInfo)
2970 _ASSERTE(pArgInfo->Count() == 1);
2972 // get the type handle for the element type
2973 typeArg = BasicTypeInfoToTypeHandle(&((*pArgInfo)[0]));
2975 // get the exact type handle for the array type
2976 return FindLoadedArrayType(pTopLevelTypeData->elementType,
2978 pTopLevelTypeData->ArrayTypeData.arrayRank);
2980 } // DacDbiInterfaceImpl::GetExactArrayTypeHandle
2982 //-----------------------------------------------------------------------------
2983 // DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle
2984 // get an exact type handle for a PTR or BYREF type
2986 // input: pTopLevelTypeData - type information for the PTR or BYREF type
2987 // pArgInfo - contains the following information:
2988 // m_genericArgsCount - number of generic parameters for the element type--this should be 1
2989 // m_pGenericArgs - pointer to the generic parameter for the element type--this is
2990 // effectively a one-element list. These are the actual parameters
2991 // Return Value: the exact type handle for the type
2992 //-----------------------------------------------------------------------------
2993 TypeHandle DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
2994 ArgInfoList * pArgInfo)
2997 _ASSERTE(pArgInfo->Count() == 1);
2999 // get the type handle for the referent
3000 typeArg = BasicTypeInfoToTypeHandle(&((*pArgInfo)[0]));
3002 // get the exact type handle for the PTR or BYREF type
3003 return FindLoadedPointerOrByrefType(pTopLevelTypeData->elementType, typeArg);
3005 } // DacDbiInterfaceImpl::GetExactPtrOrByRefTypeHandle
3007 //-----------------------------------------------------------------------------
3008 // DacDbiInterfaceImpl::GetExactClassTypeHandle
3009 // get an exact type handle for a CLASS or VALUETYPE type
3011 // input: pTopLevelTypeData - type information for the CLASS or VALUETYPE type
3012 // pArgInfo - contains the following information:
3013 // m_genericArgsCount - number of generic parameters for the class
3014 // m_pGenericArgs - list of generic parameters for the class--these
3015 // are the actual parameters
3016 // Return Value: the exact type handle for the type
3017 //-----------------------------------------------------------------------------
3018 TypeHandle DacDbiInterfaceImpl::GetExactClassTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
3019 ArgInfoList * pArgInfo)
3021 Module * pModule = pTopLevelTypeData->ClassTypeData.vmModule.GetDacPtr();
3022 int argCount = pArgInfo->Count();
3024 TypeHandle typeConstructor =
3025 ClassLoader::LookupTypeDefOrRefInModule(pModule, pTopLevelTypeData->ClassTypeData.metadataToken);
3027 // If we can't find the class, throw the appropriate HR. Note: if the class is not a value class and
3028 // the class is also not restored, then we must pretend that the class is still not loaded. We are gonna let
3029 // unrestored value classes slide, though, and special case access to the class's parent below.
3030 if (typeConstructor.IsNull())
3032 LOG((LF_CORDB, LL_INFO10000, "D::ETITTH: class isn't loaded.\n"));
3033 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3036 // if there are no generic parameters, we already have the correct type handle
3039 return typeConstructor;
3042 // we have generic parameters--first validate we have a number consistent with the list
3043 // of parameters we received
3044 if ((unsigned int)argCount != typeConstructor.GetNumGenericArgs())
3046 LOG((LF_CORDB, LL_INFO10000,
3047 "D::ETITTH: wrong number of type parameters, %d given, %d expected\n",
3048 argCount, typeConstructor.GetNumGenericArgs()));
3049 _ASSERTE((unsigned int)argCount == typeConstructor.GetNumGenericArgs());
3053 // now we allocate a list to store the type handles for each parameter
3054 S_UINT32 allocSize = S_UINT32(argCount) * S_UINT32(sizeof(TypeHandle));
3055 if (allocSize.IsOverflow())
3057 ThrowHR(E_OUTOFMEMORY);
3060 NewHolder<TypeHandle> pInst(new TypeHandle[allocSize.Value()]);
3062 // convert the type information for each parameter to its corresponding type handle
3063 // and store it in the list
3064 for (unsigned int i = 0; i < (unsigned int)argCount; i++)
3066 pInst[i] = BasicTypeInfoToTypeHandle(&((*pArgInfo)[i]));
3069 // Finally, we find the type handle corresponding to this particular instantiation
3070 return FindLoadedInstantiation(typeConstructor.GetModule(),
3071 typeConstructor.GetCl(),
3075 } // DacDbiInterfaceImpl::GetExactClassTypeHandle
3077 //-----------------------------------------------------------------------------
3078 // DacDbiInterfaceImpl::GetExactFnPtrTypeHandle
3079 // get an exact type handle for a FNPTR type
3081 // input: pArgInfo - Contains the following information:
3082 // m_genericArgsCount - number of generic parameters for the referent
3083 // m_pGenericArgs - list of generic parameters for the referent--these
3084 // are the actual parameters for the function signature
3085 // Return Value: the exact type handle for the type
3086 //-----------------------------------------------------------------------------
3087 TypeHandle DacDbiInterfaceImpl::GetExactFnPtrTypeHandle(ArgInfoList * pArgInfo)
3089 // allocate a list to store the type handles for each parameter
3090 S_UINT32 allocSize = S_UINT32(pArgInfo->Count()) * S_UINT32(sizeof(TypeHandle));
3091 if( allocSize.IsOverflow() )
3093 ThrowHR(E_OUTOFMEMORY);
3095 NewHolder<TypeHandle> pInst(new TypeHandle[allocSize.Value()]);
3097 // convert the type information for each parameter to its corresponding type handle
3098 // and store it in the list
3099 for (int i = 0; i < pArgInfo->Count(); i++)
3101 pInst[i] = BasicTypeInfoToTypeHandle(&((*pArgInfo)[i]));
3104 // find the type handle corresponding to this particular FNPTR
3105 return FindLoadedFnptrType(pArgInfo->Count(), pInst);
3106 } // DacDbiInterfaceImpl::GetExactFnPtrTypeHandle
3108 //-----------------------------------------------------------------------------
3109 // DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle
3110 // Convert basic type info for a type parameter that came from a top-level type to
3111 // the corresponding type handle. If the type parameter is an array or pointer
3112 // type, we simply extract the LS type handle from the VMPTR_TypeHandle that is
3113 // part of the type information. If the type parameter is a class or value type,
3114 // we use the metadata token and domain file in the type info to look up the
3115 // appropriate type handle. If the type parameter is any other types, we get the
3116 // type handle by having the loader look up the type handle for the element type.
3118 // input: pArgTypeData - basic type information for the type.
3119 // Return Value: the type handle for the type.
3120 //-----------------------------------------------------------------------------
3121 TypeHandle DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle(DebuggerIPCE_BasicTypeData * pArgTypeData)
3123 LOG((LF_CORDB, LL_INFO10000,
3124 "D::BTITTH: expanding basic right-side type to left-side type, ELEMENT_TYPE: %d.\n",
3125 pArgTypeData->elementType));
3126 TypeHandle typeHandle = TypeHandle();
3128 switch (pArgTypeData->elementType)
3130 case ELEMENT_TYPE_ARRAY:
3131 case ELEMENT_TYPE_SZARRAY:
3132 case ELEMENT_TYPE_PTR:
3133 case ELEMENT_TYPE_BYREF:
3134 case ELEMENT_TYPE_FNPTR:
3135 _ASSERTE(!pArgTypeData->vmTypeHandle.IsNull());
3136 typeHandle = TypeHandle::FromPtr(pArgTypeData->vmTypeHandle.GetDacPtr());
3139 case ELEMENT_TYPE_CLASS:
3140 case ELEMENT_TYPE_VALUETYPE:
3141 typeHandle = GetClassOrValueTypeHandle(pArgTypeData);
3145 typeHandle = FindLoadedElementType(pArgTypeData->elementType);
3148 if (typeHandle.IsNull())
3150 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3153 } // DacDbiInterfaceImpl::BasicTypeInfoToTypeHandle
3156 //-----------------------------------------------------------------------------
3157 // DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle
3158 // Convert type information for a top-level type to an exact type handle. This
3159 // information includes information about the element type if the top-level type is
3160 // an array type, the referent if the top-level type is a pointer type, or actual
3161 // parameters if the top-level type is a generic class or value type.
3163 // input: pTopLevelTypeData - type information for the top-level type
3164 // pArgInfo - contains the following information:
3165 // m_genericArtsCount - number of parameters
3166 // m_pGenericArgs - list of actual parameters
3167 // Return Value: the exact type handle corresponding to the type represented by
3168 // pTopLevelTypeData
3169 //-----------------------------------------------------------------------------
3170 TypeHandle DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle(DebuggerIPCE_ExpandedTypeData * pTopLevelTypeData,
3171 ArgInfoList * pArgInfo)
3173 WRAPPER_NO_CONTRACT;
3175 LOG((LF_CORDB, LL_INFO10000,
3176 "D::ETITTH: expanding right-side type to left-side type, ELEMENT_TYPE: %d.\n",
3177 pData->elementType));
3179 TypeHandle typeHandle = TypeHandle();
3180 // depending on the top-level type, get the type handle incorporating information about any type arguments
3181 switch (pTopLevelTypeData->elementType)
3183 case ELEMENT_TYPE_ARRAY:
3184 case ELEMENT_TYPE_SZARRAY:
3185 typeHandle = GetExactArrayTypeHandle(pTopLevelTypeData, pArgInfo);
3188 case ELEMENT_TYPE_PTR:
3189 case ELEMENT_TYPE_BYREF:
3190 typeHandle = GetExactPtrOrByRefTypeHandle(pTopLevelTypeData, pArgInfo);
3193 case ELEMENT_TYPE_CLASS:
3194 case ELEMENT_TYPE_VALUETYPE:
3195 typeHandle = GetExactClassTypeHandle(pTopLevelTypeData, pArgInfo);
3197 case ELEMENT_TYPE_FNPTR:
3198 typeHandle = GetExactFnPtrTypeHandle(pArgInfo);
3201 typeHandle = FindLoadedElementType(pTopLevelTypeData->elementType);
3203 } // end switch (pData->elementType)
3205 if (typeHandle.IsNull())
3207 // This may fail because there are cases when a type can be used (and so visible to the
3208 // debugger), but not yet loaded to the point of being available in the EETypeHashTable.
3209 // For example, generic value types (without explicit constructors) may not need their
3210 // exact instantiation type to be loaded in order to be used as a field of an object
3211 // created on the heap
3212 LOG((LF_CORDB, LL_INFO10000, "D::ETITTH: type isn't loaded.\n"));
3213 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3216 } // DacDbiInterfaceImpl::ExpandedTypeInfoToTypeHandle
3218 // ----------------------------------------------------------------------------
3219 // DacDbi API: GetThreadOrContextStaticAddress
3220 // Get the target field address of a context or thread local static.
3223 // The address is constant and could be cached.
3225 // If this is a context-static, the function uses the thread's current context.
3226 // [This is important because it means that you can't lookup a context static
3227 // unless you have a thread in that context. If anybody actually cared about contexts,
3228 // we might have to revise this in the future]
3230 // This can commonly fail, in which case, it will return NULL.
3231 // ----------------------------------------------------------------------------
3232 CORDB_ADDRESS DacDbiInterfaceImpl::GetThreadOrContextStaticAddress(VMPTR_FieldDesc vmField,
3233 VMPTR_Thread vmRuntimeThread)
3237 Thread * pRuntimeThread = vmRuntimeThread.GetDacPtr();
3238 PTR_FieldDesc pFieldDesc = vmField.GetDacPtr();
3239 TADDR fieldAddress = NULL;
3241 _ASSERTE(pRuntimeThread != NULL);
3243 // Find out whether the field is thread local or context local and get its
3245 if (pFieldDesc->IsThreadStatic())
3247 fieldAddress = pRuntimeThread->GetStaticFieldAddrNoCreate(pFieldDesc, NULL);
3249 #ifdef FEATURE_REMOTING
3250 else if (pFieldDesc->IsContextStatic())
3252 fieldAddress = PTR_TO_TADDR(pRuntimeThread->GetContext()->GetStaticFieldAddrNoCreate(pFieldDesc));
3257 // In case we have more special cases added later, this will allow us to notice the need to
3258 // update this function.
3261 return fieldAddress;
3263 } // DacDbiInterfaceImpl::GetThreadOrContextStaticAddress
3265 // Get the target field address of a collectible types static.
3266 CORDB_ADDRESS DacDbiInterfaceImpl::GetCollectibleTypeStaticAddress(VMPTR_FieldDesc vmField,
3267 VMPTR_AppDomain vmAppDomain)
3271 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3272 PTR_FieldDesc pFieldDesc = vmField.GetDacPtr();
3273 _ASSERTE(pAppDomain != NULL);
3276 // Verify this field is of the right type
3278 if(!pFieldDesc->IsStatic() ||
3279 pFieldDesc->IsSpecialStatic())
3281 _ASSERTE(!"BUG: Unsupported static field type for collectible types");
3285 // Check that the data is available
3287 /* TODO: Ideally we should be checking if the class is allocated first, however
3288 we don't appear to be doing this even for non-collectible statics and
3289 we have never seen an issue.
3295 PTR_VOID base = pFieldDesc->GetBaseInDomain(pAppDomain);
3296 if (base == PTR_NULL)
3298 return PTR_HOST_TO_TADDR(NULL);
3302 // Store the result and return
3304 PTR_VOID addr = pFieldDesc->GetStaticAddressHandle(base);
3305 return PTR_TO_TADDR(addr);
3307 } // DacDbiInterfaceImpl::GetCollectibleTypeStaticAddress
3309 // DacDbi API: GetTypeHandleParams
3310 // - gets the necessary data for a type handle, i.e. its type parameters, e.g. "String" and "List<int>" from the type handle
3311 // for "Dict<String,List<int>>", and sends it back to the right side.
3312 // - pParams is allocated and initialized by this function
3313 // - This should not fail except for OOM
3314 void DacDbiInterfaceImpl::GetTypeHandleParams(VMPTR_AppDomain vmAppDomain,
3315 VMPTR_TypeHandle vmTypeHandle,
3316 TypeParamsList * pParams)
3320 TypeHandle typeHandle = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
3321 LOG((LF_CORDB, LL_INFO10000, "D::GTHP: getting type parameters for 0x%08x 0x%0x8.\n",
3322 vmAppDomain.GetDacPtr(), typeHandle.AsPtr()));
3325 // Find the class given its type handle.
3326 _ASSERTE(pParams->IsEmpty());
3327 pParams->Alloc(typeHandle.GetNumGenericArgs());
3329 // collect type information for each type parameter
3330 for (int i = 0; i < pParams->Count(); ++i)
3332 VMPTR_TypeHandle thInst = VMPTR_TypeHandle::NullPtr();
3333 thInst.SetDacTargetPtr(typeHandle.GetInstantiation()[i].AsTAddr());
3335 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3341 LOG((LF_CORDB, LL_INFO10000, "D::GTHP: sending result"));
3342 } // DacDbiInterfaceImpl::GetTypeHandleParams
3344 //-----------------------------------------------------------------------------
3345 // DacDbi API: GetSimpleType
3346 // gets the metadata token and domain file corresponding to a simple type
3347 //-----------------------------------------------------------------------------
3348 void DacDbiInterfaceImpl::GetSimpleType(VMPTR_AppDomain vmAppDomain,
3349 CorElementType simpleType,
3350 mdTypeDef *pMetadataToken,
3351 VMPTR_Module *pVmModule,
3352 VMPTR_DomainFile *pVmDomainFile)
3356 AppDomain *pAppDomain = vmAppDomain.GetDacPtr();
3358 // if we fail to get either a valid type handle or module, we will want to send back
3359 // a NULL domain file too, so we'll to preinitialize this here.
3360 _ASSERTE(pVmDomainFile != NULL);
3361 *pVmDomainFile = VMPTR_DomainFile::NullPtr();
3362 // FindLoadedElementType will return NULL if the type hasn't been loaded yet.
3363 TypeHandle typeHandle = FindLoadedElementType(simpleType);
3365 if (typeHandle.IsNull())
3367 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3371 _ASSERTE(pMetadataToken != NULL);
3372 *pMetadataToken = typeHandle.GetCl();
3374 Module * pModule = typeHandle.GetModule();
3375 if (pModule == NULL)
3376 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
3378 pVmModule->SetHostPtr(pModule);
3382 pVmDomainFile->SetHostPtr(pModule->GetDomainFile(pAppDomain));
3383 if (pVmDomainFile->IsNull())
3384 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
3388 LOG((LF_CORDB, LL_INFO10000, "D::STI: sending result.\n"));
3389 } // DacDbiInterfaceImpl::GetSimpleType
3391 BOOL DacDbiInterfaceImpl::IsExceptionObject(VMPTR_Object vmObject)
3395 Object* objPtr = vmObject.GetDacPtr();
3396 MethodTable* pMT = objPtr->GetMethodTable();
3398 return IsExceptionObject(pMT);
3401 BOOL DacDbiInterfaceImpl::IsExceptionObject(MethodTable* pMT)
3403 PTR_MethodTable pExMT = g_pExceptionClass;
3405 TADDR targetMT = dac_cast<TADDR>(pMT);
3406 TADDR exceptionMT = dac_cast<TADDR>(pExMT);
3410 if (targetMT == exceptionMT)
3413 pMT = pMT->GetParentMethodTable();
3414 targetMT = dac_cast<TADDR>(pMT);
3420 void DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList<DacExceptionCallStackData>& dacStackFrames)
3424 PTR_Object objPtr = vmObject.GetDacPtr();
3427 // ensure we have an Exception object
3428 MethodTable* pMT = objPtr->GetMethodTable();
3429 _ASSERTE(IsExceptionObject(pMT));
3432 OBJECTREF objRef = ObjectToOBJECTREF(objPtr);
3434 DebugStackTrace::GetStackFramesData stackFramesData;
3436 stackFramesData.pDomain = NULL;
3437 stackFramesData.skip = 0;
3438 stackFramesData.NumFramesRequested = 0;
3440 DebugStackTrace::GetStackFramesFromException(&objRef, &stackFramesData);
3442 INT32 dacStackFramesLength = stackFramesData.cElements;
3444 if (dacStackFramesLength > 0)
3446 dacStackFrames.Alloc(dacStackFramesLength);
3448 for (INT32 index = 0; index < dacStackFramesLength; ++index)
3450 DebugStackTrace::DebugStackTraceElement const& currentElement = stackFramesData.pElements[index];
3451 DacExceptionCallStackData& currentFrame = dacStackFrames[index];
3453 Module* pModule = currentElement.pFunc->GetModule();
3454 BaseDomain* pBaseDomain = currentElement.pFunc->GetAssembly()->GetDomain();
3456 AppDomain* pDomain = NULL;
3457 DomainFile* pDomainFile = NULL;
3459 if (pBaseDomain->IsSharedDomain())
3460 pDomain = SystemDomain::System()->DefaultDomain();
3462 pDomain = pBaseDomain->AsAppDomain();
3464 _ASSERTE(pDomain != NULL);
3466 pDomainFile = pModule->FindDomainFile(pDomain);
3467 _ASSERTE(pDomainFile != NULL);
3469 currentFrame.vmAppDomain.SetHostPtr(pDomain);
3470 currentFrame.vmDomainFile.SetHostPtr(pDomainFile);
3471 currentFrame.ip = currentElement.ip;
3472 currentFrame.methodDef = currentElement.pFunc->GetMemberDef();
3473 #if defined(FEATURE_EXCEPTIONDISPATCHINFO)
3474 currentFrame.isLastForeignExceptionFrame = currentElement.fIsLastFrameFromForeignStackTrace;
3476 // for CLRs lacking exception dispatch info just set it to 0
3477 currentFrame.isLastForeignExceptionFrame = 0;
3483 #ifdef FEATURE_COMINTEROP
3485 PTR_RCW GetRcwFromVmptrObject(VMPTR_Object vmObject)
3487 PTR_RCW pRCW = NULL;
3489 Object* objPtr = vmObject.GetDacPtr();
3491 PTR_SyncBlock pSyncBlock = NULL;
3492 pSyncBlock = objPtr->PassiveGetSyncBlock();
3493 if (pSyncBlock == NULL)
3496 PTR_InteropSyncBlockInfo pInfo = NULL;
3497 pInfo = pSyncBlock->GetInteropInfoNoCreate();
3501 pRCW = dac_cast<PTR_RCW>(pInfo->DacGetRawRCW());
3508 BOOL DacDbiInterfaceImpl::IsRcw(VMPTR_Object vmObject)
3510 #ifdef FEATURE_COMINTEROP
3512 return GetRcwFromVmptrObject(vmObject) != NULL;
3515 #endif // FEATURE_COMINTEROP
3519 void DacDbiInterfaceImpl::GetRcwCachedInterfaceTypes(
3520 VMPTR_Object vmObject,
3521 VMPTR_AppDomain vmAppDomain,
3522 BOOL bIInspectableOnly,
3523 DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pDacInterfaces)
3525 #ifdef FEATURE_COMINTEROP
3529 Object* objPtr = vmObject.GetDacPtr();
3531 InlineSArray<PTR_MethodTable, INTERFACE_ENTRY_CACHE_SIZE> rgMT;
3533 PTR_RCW pRCW = GetRcwFromVmptrObject(vmObject);
3536 pRCW->GetCachedInterfaceTypes(bIInspectableOnly, &rgMT);
3538 pDacInterfaces->Alloc(rgMT.GetCount());
3540 for (COUNT_T i = 0; i < rgMT.GetCount(); ++i)
3542 // There is the possiblity that we'll get this far with a dump and not fail, but still
3543 // not be able to get full info for a particular param.
3544 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3546 // Fill in the struct using the current TypeHandle
3547 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3548 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(rgMT[i]));
3549 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3550 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3553 &((*pDacInterfaces)[i]));
3555 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3557 // On failure for a particular type, default it to NULL.
3558 (*pDacInterfaces)[i].elementType = ELEMENT_TYPE_END;
3560 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3566 #endif // FEATURE_COMINTEROP
3568 pDacInterfaces->Alloc(0);
3572 void DacDbiInterfaceImpl::GetRcwCachedInterfacePointers(
3573 VMPTR_Object vmObject,
3574 BOOL bIInspectableOnly,
3575 DacDbiArrayList<CORDB_ADDRESS> * pDacItfPtrs)
3577 #ifdef FEATURE_COMINTEROP
3581 Object* objPtr = vmObject.GetDacPtr();
3583 InlineSArray<TADDR, INTERFACE_ENTRY_CACHE_SIZE> rgUnks;
3585 PTR_RCW pRCW = GetRcwFromVmptrObject(vmObject);
3588 pRCW->GetCachedInterfacePointers(bIInspectableOnly, &rgUnks);
3590 pDacItfPtrs->Alloc(rgUnks.GetCount());
3592 for (COUNT_T i = 0; i < rgUnks.GetCount(); ++i)
3594 (*pDacItfPtrs)[i] = (CORDB_ADDRESS)(rgUnks[i]);
3599 #endif // FEATURE_COMINTEROP
3601 pDacItfPtrs->Alloc(0);
3605 void DacDbiInterfaceImpl::GetCachedWinRTTypesForIIDs(
3606 VMPTR_AppDomain vmAppDomain,
3607 DacDbiArrayList<GUID> & iids,
3608 OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes)
3610 #ifdef FEATURE_COMINTEROP
3614 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3615 if (pAppDomain->IsUnloading())
3621 pTypes->Alloc(iids.Count());
3623 for (int i = 0; i < iids.Count(); ++i)
3625 // There is the possiblity that we'll get this far with a dump and not fail, but still
3626 // not be able to get full info for a particular param.
3627 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3629 PTR_MethodTable pMT = pAppDomain->LookupTypeByGuid(iids[i]);
3631 // Fill in the struct using the current TypeHandle
3632 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3633 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(pMT));
3634 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3635 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3640 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3642 // On failure for a particular type, default it to NULL.
3643 (*pTypes)[i].elementType = ELEMENT_TYPE_END;
3645 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3648 #else // FEATURE_COMINTEROP
3652 #endif // FEATURE_COMINTEROP
3655 void DacDbiInterfaceImpl::GetCachedWinRTTypes(
3656 VMPTR_AppDomain vmAppDomain,
3657 OUT DacDbiArrayList<GUID> * pGuids,
3658 OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes)
3660 #ifdef FEATURE_COMINTEROP
3664 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
3665 if (pAppDomain->IsUnloading())
3670 InlineSArray<PTR_MethodTable, 32> rgMT;
3671 InlineSArray<GUID, 32> rgGuid;
3674 pAppDomain->GetCachedWinRTTypes(&rgMT, &rgGuid, 0, NULL);
3676 pTypes->Alloc(rgMT.GetCount());
3677 pGuids->Alloc(rgGuid.GetCount());
3679 for (COUNT_T i = 0; i < rgMT.GetCount(); ++i)
3681 // There is the possiblity that we'll get this far with a dump and not fail, but still
3682 // not be able to get full info for a particular param.
3683 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3685 // Fill in the struct using the current TypeHandle
3686 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
3687 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(rgMT[i]));
3688 vmTypeHandle.SetDacTargetPtr(th.AsTAddr());
3689 TypeHandleToExpandedTypeInfo(NoValueTypeBoxing,
3694 EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3696 // On failure for a particular type, default it to NULL.
3697 (*pTypes)[i].elementType = ELEMENT_TYPE_END;
3699 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER
3700 (*pGuids)[i] = rgGuid[i];
3705 #else // FEATURE_COMINTEROP
3709 #endif // FEATURE_COMINTEROP
3712 //-----------------------------------------------------------------------------
3713 // DacDbiInterfaceImpl::FindField
3714 // Finds information for a particular class field
3716 // input: thApprox - type handle for the type to which the field belongs
3717 // fldToken - metadata token for the field
3718 // Return Value: FieldDesc containing information for the field if found or NULL otherwise
3719 //-----------------------------------------------------------------------------
3720 PTR_FieldDesc DacDbiInterfaceImpl::FindField(TypeHandle thApprox, mdFieldDef fldToken)
3722 EncApproxFieldDescIterator fdIterator(thApprox.GetMethodTable(),
3723 ApproxFieldDescIterator::ALL_FIELDS,
3724 FALSE); // don't fixup EnC (we can't, we're stopped)
3726 PTR_FieldDesc pCurrentFD;
3728 while ((pCurrentFD = fdIterator.Next()) != NULL)
3730 // We're looking for a specific fieldDesc, see if we got it.
3731 if (pCurrentFD->GetMemberDef() == fldToken)
3737 // we never found it...
3739 } // DacDbiInterfaceImpl::FindField
3741 //-----------------------------------------------------------------------------
3742 // DacDbiInterfaceImpl::GetEnCFieldDesc
3743 // Get the FieldDesc corresponding to a particular EnC field token
3745 // input: pEnCFieldInfo
3746 // Return Value: pointer to the FieldDesc that corresponds to the EnC field
3747 // Note: this function may throw
3748 //-----------------------------------------------------------------------------
3749 FieldDesc * DacDbiInterfaceImpl::GetEnCFieldDesc(const EnCHangingFieldInfo * pEnCFieldInfo)
3751 FieldDesc * pFD = NULL;
3753 DomainFile * pDomainFile = pEnCFieldInfo->GetObjectTypeData().vmDomainFile.GetDacPtr();
3754 Module * pModule = pDomainFile->GetModule();
3756 // get the type handle for the object
3757 TypeHandle typeHandle = ClassLoader::LookupTypeDefOrRefInModule(pModule,
3758 pEnCFieldInfo->GetObjectTypeData().metadataToken);
3759 if (typeHandle == NULL)
3761 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
3763 // and find the field desc
3764 pFD = FindField(typeHandle, pEnCFieldInfo->GetFieldToken());
3767 // FieldDesc is not yet available, so can't get EnC field info
3768 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3772 } // DacDbiInterfaceImpl::GetEnCFieldDesc
3774 //-----------------------------------------------------------------------------
3775 // DacDbiInterfaceImpl::GetPtrToEnCField
3776 // Get the address of a field added with EnC.
3778 // input: pFD - field desc for the added field
3779 // pEnCFieldInfo - information about the new field
3780 // Return Value: The field address if the field is available (i.e., it has been accessed)
3781 // or NULL otherwise
3782 // Note: this function may throw
3783 //-----------------------------------------------------------------------------
3784 PTR_CBYTE DacDbiInterfaceImpl::GetPtrToEnCField(FieldDesc * pFD, const EnCHangingFieldInfo * pEnCFieldInfo)
3786 #ifndef EnC_SUPPORTED
3787 _ASSERTE(!"Trying to get the address of an EnC field where EnC is not supported! ");
3791 PTR_EditAndContinueModule pEnCModule;
3792 DomainFile * pDomainFile = pEnCFieldInfo->GetObjectTypeData().vmDomainFile.GetDacPtr();
3793 Module * pModule = pDomainFile->GetModule();
3795 // make sure we actually have an EditAndContinueModule
3796 _ASSERTE(pModule->IsEditAndContinueCapable());
3797 pEnCModule = dac_cast<PTR_EditAndContinueModule>(pModule);
3799 // we should also have an EnCFieldDesc
3800 _ASSERTE(pFD->IsEnCNew());
3801 EnCFieldDesc * pEnCFieldDesc;
3802 pEnCFieldDesc = dac_cast<PTR_EnCFieldDesc>(pFD);
3804 // If it hasn't been fixed up yet, then we can't return the pointer.
3805 if (pEnCFieldDesc->NeedsFixup())
3807 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3809 // Get a pointer to the field
3810 PTR_CBYTE pORField = NULL;
3812 PTR_Object pObject = pEnCFieldInfo->GetVmObject().GetDacPtr();
3813 pORField = pEnCModule->ResolveField(ObjectToOBJECTREF(pObject),
3816 // The field could be absent because the code hasn't accessed it yet. If so, we're not going to add it
3817 // since we can't allocate anyway.
3818 if (pORField == NULL)
3820 ThrowHR(CORDBG_E_ENC_HANGING_FIELD);
3823 #endif // EnC_SUPPORTED
3824 } // DacDbiInterfaceImpl::GetPtrToEnCField
3826 //-----------------------------------------------------------------------------
3827 // DacDbiInterfaceImpl::InitFieldData
3828 // Initialize information about a field added with EnC
3831 // pFD - provides information about whether the field is static,
3832 // the metadata token, etc.
3833 // pORField - provides the field address or offset
3834 // pEnCFieldData - provides the offset to the fields of the object
3835 // output: pFieldData - initialized in accordance with the input information
3836 //-----------------------------------------------------------------------------
3837 void DacDbiInterfaceImpl::InitFieldData(const FieldDesc * pFD,
3838 const PTR_CBYTE pORField,
3839 const EnCHangingFieldInfo * pEnCFieldData,
3840 FieldData * pFieldData)
3843 pFieldData->ClearFields();
3845 pFieldData->m_fFldIsStatic = (pFD->IsStatic() != 0);
3846 pFieldData->m_vmFieldDesc.SetHostPtr(pFD);
3847 pFieldData->m_fFldIsTLS = (pFD->IsThreadStatic() == TRUE);
3848 pFieldData->m_fldMetadataToken = pFD->GetMemberDef();
3849 pFieldData->m_fFldIsRVA = (pFD->IsRVA() == TRUE);
3850 pFieldData->m_fFldIsContextStatic = (pFD->IsContextStatic() == TRUE);
3851 pFieldData->m_fFldIsCollectibleStatic = FALSE;
3852 pFieldData->m_fFldStorageAvailable = true;
3854 if (pFieldData->m_fFldIsStatic)
3856 //EnC is only supported on regular static fields
3857 _ASSERTE(!pFieldData->m_fFldIsContextStatic);
3858 _ASSERTE(!pFieldData->m_fFldIsTLS);
3859 _ASSERTE(!pFieldData->m_fFldIsRVA);
3861 // pORField contains the absolute address
3862 pFieldData->SetStaticAddress(PTR_TO_TADDR(pORField));
3866 // fldInstanceOffset is computed to work correctly with GetFieldValue
3868 // addr of pORField = object + pEnCFieldInfo->m_offsetToVars + offsetToFld
3869 pFieldData->SetInstanceOffset(PTR_TO_TADDR(pORField) -
3870 (PTR_TO_TADDR(pEnCFieldData->GetVmObject().GetDacPtr()) +
3871 pEnCFieldData->GetOffsetToVars()));
3873 } // DacDbiInterfaceImpl::InitFieldData
3876 // ----------------------------------------------------------------------------
3877 // DacDbi API: GetEnCHangingFieldInfo
3878 // After a class has been loaded, if a field has been added via EnC we'll have to jump through
3879 // some hoops to get at it (it hangs off the sync block or FieldDesc).
3881 // GENERICS: TODO: this method will need to be modified if we ever support EnC on
3883 //-----------------------------------------------------------------------------
3884 void DacDbiInterfaceImpl::GetEnCHangingFieldInfo(const EnCHangingFieldInfo * pEnCFieldInfo,
3885 FieldData * pFieldData,
3890 LOG((LF_CORDB, LL_INFO100000, "DDI::IEnCHFI: Obj:0x%x, objType"
3891 ":0x%x, offset:0x%x\n", pEnCFieldInfo->m_pObject, pEnCFieldInfo->m_objectTypeData.elementType,
3892 pEnCFieldInfo->m_offsetToVars));
3894 FieldDesc * pFD = NULL;
3895 PTR_CBYTE pORField = NULL;
3897 pFD = GetEnCFieldDesc(pEnCFieldInfo);
3898 _ASSERTE(pFD->IsEnCNew()); // We shouldn't be here if it wasn't added to an
3899 // already loaded class.
3901 #ifdef EnC_SUPPORTED
3902 pORField = GetPtrToEnCField(pFD, pEnCFieldInfo);
3904 _ASSERTE(!"We shouldn't be here: EnC not supported");
3905 #endif // EnC_SUPPORTED
3907 InitFieldData(pFD, pORField, pEnCFieldInfo, pFieldData);
3908 *pfStatic = (pFD->IsStatic() != 0);
3910 } // DacDbiInterfaceImpl::GetEnCHangingFieldInfo
3912 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3915 void DacDbiInterfaceImpl::GetAssemblyFromDomainAssembly(VMPTR_DomainAssembly vmDomainAssembly, VMPTR_Assembly *vmAssembly)
3919 _ASSERTE(vmAssembly != NULL);
3921 DomainAssembly * pDomainAssembly = vmDomainAssembly.GetDacPtr();
3922 vmAssembly->SetHostPtr(pDomainAssembly->GetAssembly());
3925 // Determines whether the runtime security system has assigned full-trust to this assembly.
3926 BOOL DacDbiInterfaceImpl::IsAssemblyFullyTrusted(VMPTR_DomainAssembly vmDomainAssembly)
3930 DomainAssembly * pAssembly = vmDomainAssembly.GetDacPtr();
3931 IAssemblySecurityDescriptor * pSecDisc = pAssembly->GetSecurityDescriptor();
3932 return pSecDisc->IsFullyTrusted();
3935 // Get the full path and file name to the assembly's manifest module.
3936 BOOL DacDbiInterfaceImpl::GetAssemblyPath(
3937 VMPTR_Assembly vmAssembly,
3938 IStringHolder * pStrFilename)
3942 // Get the manifest module for this assembly
3943 Assembly * pAssembly = vmAssembly.GetDacPtr();
3944 Module * pManifestModule = pAssembly->GetManifestModule();
3946 // Get the path for the manifest module.
3947 // since we no longer support Win9x, we assume all paths will be in unicode format already
3948 const WCHAR * szPath = pManifestModule->GetPath().DacGetRawUnicode();
3949 HRESULT hrStatus = pStrFilename->AssignCopy(szPath);
3950 IfFailThrow(hrStatus);
3952 if(szPath == NULL || *szPath=='\0')
3954 // The asembly has no (and will never have a) file name, but we didn't really fail
3962 // Get a resolved type def from a type ref. The type ref may come from a module other than the
3963 // referencing module.
3964 void DacDbiInterfaceImpl::ResolveTypeReference(const TypeRefData * pTypeRefInfo,
3965 TypeRefData * pTargetRefInfo)
3968 DomainFile * pDomainFile = pTypeRefInfo->vmDomainFile.GetDacPtr();
3969 Module * pReferencingModule = pDomainFile->GetCurrentModule();
3970 BOOL fSuccess = FALSE;
3972 // Resolve the type ref
3973 // g_pEEInterface->FindLoadedClass is almost what we want, but it isn't guaranteed to work if
3974 // the typeRef was originally loaded from a different assembly. Also, we need to ensure that
3975 // we can resolve even unloaded types in fully loaded assemblies, so APIs such as
3976 // LoadTypeDefOrRefThrowing aren't acceptable.
3978 Module * pTargetModule = NULL;
3979 mdTypeDef targetTypeDef = mdTokenNil;
3981 // The loader won't need to trigger a GC or throw because we've told it not to load anything
3982 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
3984 fSuccess = ClassLoader::ResolveTokenToTypeDefThrowing(pReferencingModule,
3985 pTypeRefInfo->typeToken,
3988 Loader::SafeLookup //don't load, no locks/allocations
3992 _ASSERTE(pTargetModule != NULL);
3993 _ASSERTE( TypeFromToken(targetTypeDef) == mdtTypeDef );
3995 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
3997 pTargetRefInfo->vmDomainFile.SetDacTargetPtr(PTR_HOST_TO_TADDR(pTargetModule->GetDomainFile(pAppDomain)));
3998 pTargetRefInfo->typeToken = targetTypeDef;
4002 // failed - presumably because the target assembly isn't loaded
4003 ThrowHR(CORDBG_E_CLASS_NOT_LOADED);
4005 } // DacDbiInterfaceImpl::ResolveTypeReference
4008 // Get the full path and file name to the module (if any).
4009 BOOL DacDbiInterfaceImpl::GetModulePath(VMPTR_Module vmModule,
4010 IStringHolder * pStrFilename)
4014 Module * pModule = vmModule.GetDacPtr();
4015 PEFile * pFile = pModule->GetFile();
4018 if( !pFile->GetPath().IsEmpty() )
4020 // Module has an on-disk path
4021 const WCHAR * szPath = pFile->GetPath().DacGetRawUnicode();
4024 szPath = pFile->GetModuleFileNameHint().DacGetRawUnicode();
4030 IfFailThrow(pStrFilename->AssignCopy(szPath));
4037 IfFailThrow(pStrFilename->AssignCopy(W("")));
4041 // Get the full path and file name to the ngen image for the module (if any).
4042 BOOL DacDbiInterfaceImpl::GetModuleNGenPath(VMPTR_Module vmModule,
4043 IStringHolder * pStrFilename)
4046 #ifdef FEATURE_PREJIT
4047 Module * pModule = vmModule.GetDacPtr();
4048 PEFile * pFile = pModule->GetFile();
4049 if (pFile != NULL && pFile->HasNativeImage())
4051 PEImage * pImage = pFile->GetPersistentNativeImage();
4052 if (pImage != NULL && pImage->IsFile())
4054 // We have an on-disk ngen image. Return the path.
4055 // since we no longer support Win9x, we assume all paths will be in unicode format already
4056 const WCHAR * szPath = pImage->GetPath().DacGetRawUnicode();
4059 szPath = pFile->GetModuleFileNameHint().DacGetRawUnicode();
4065 IfFailThrow(pStrFilename->AssignCopy(szPath));
4069 #endif // FEATURE_PREJIT
4073 IfFailThrow(pStrFilename->AssignCopy(W("")));
4077 // Implementation of IDacDbiInterface::GetModuleSimpleName
4078 void DacDbiInterfaceImpl::GetModuleSimpleName(VMPTR_Module vmModule, IStringHolder * pStrFilename)
4082 _ASSERTE(pStrFilename != NULL);
4084 Module * pModule = vmModule.GetDacPtr();
4085 LPCUTF8 szNameUtf8 = pModule->GetSimpleName();
4087 SString convert(SString::Utf8, szNameUtf8);
4088 IfFailThrow(pStrFilename->AssignCopy(convert.GetUnicode()));
4091 // Helper to intialize a TargetBuffer from a MemoryRange
4094 // memoryRange - memory range.
4095 // pTargetBuffer - required out parameter to be initialized to value of memory range.
4098 // MemoryRange and TargetBuffer both conceptually describe a single contiguous buffer of memory in the
4099 // target. MemoryRange is a VM structure, which can't bleed across the DacDbi boundary. TargetBuffer is
4100 // a DacDbi structure, which can cross the DacDbi boundary.
4101 void InitTargetBufferFromMemoryRange(const MemoryRange memoryRange, TargetBuffer * pTargetBuffer)
4105 _ASSERTE(pTargetBuffer != NULL);
4106 PTR_CVOID p = memoryRange.StartAddress();
4107 CORDB_ADDRESS addr = PTR_TO_CORDB_ADDRESS(PTR_TO_TADDR(p));
4109 _ASSERTE(memoryRange.Size() <= 0xffffffff);
4110 pTargetBuffer->Init(addr, (ULONG)memoryRange.Size());
4113 // Helper to intialize a TargetBuffer (host representation of target) from an SBuffer (target)
4116 // pBuffer - target pointer to a SBuffer structure. If pBuffer is NULL, then target buffer will be empty.
4117 // pTargetBuffer - required out pointer to hold buffer description.
4120 // PTR_SBuffer and TargetBuffer are both semantically equivalent structures. They both are a pointer and length
4121 // describing a buffer in the target address space. (SBufer also has ownership semantics, but for DAC's
4122 // read-only nature, that doesn't matter).
4123 // Neither of these will actually copy the target buffer into the host without explicit action.
4124 // The important difference is that TargetBuffer is a host datastructure and so easier to manipulate.
4126 void InitTargetBufferFromTargetSBuffer(PTR_SBuffer pBuffer, TargetBuffer * pTargetBuffer)
4130 _ASSERTE(pTargetBuffer != NULL);
4132 SBuffer * pBufferHost = pBuffer;
4133 if (pBufferHost == NULL)
4135 pTargetBuffer->Clear();
4139 MemoryRange m = pBufferHost->DacGetRawBuffer();
4140 InitTargetBufferFromMemoryRange(m, pTargetBuffer);
4144 // Implementation of IDacDbiInterface::GetMetadata
4145 void DacDbiInterfaceImpl::GetMetadata(VMPTR_Module vmModule, TargetBuffer * pTargetBuffer)
4149 pTargetBuffer->Clear();
4151 Module * pModule = vmModule.GetDacPtr();
4153 // Target should only be asking about modules that are visible to debugger.
4154 _ASSERTE(pModule->IsVisibleToDebugger());
4156 // For dynamic modules, metadata is stored as an eagerly-serialized buffer hanging off the Reflection Module.
4157 if (pModule->IsReflection())
4159 // Here is the fetch.
4160 ReflectionModule * pReflectionModule = pModule->GetReflectionModule();
4161 InitTargetBufferFromTargetSBuffer(pReflectionModule->GetDynamicMetadataBuffer(), pTargetBuffer);
4165 PEFile * pFile = pModule->GetFile();
4167 // For non-dynamic modules, metadata is in the pe-image.
4169 CORDB_ADDRESS address = PTR_TO_CORDB_ADDRESS(dac_cast<TADDR>(pFile->GetLoadedMetadata(&size)));
4171 pTargetBuffer->Init(address, (ULONG) size);
4174 if (pTargetBuffer->IsEmpty())
4176 // We never expect this to happen in a well-behaved scenario. But just in case.
4177 ThrowHR(CORDBG_E_MISSING_METADATA);
4182 // Implementation of IDacDbiInterface::GetSymbolsBuffer
4183 void DacDbiInterfaceImpl::GetSymbolsBuffer(VMPTR_Module vmModule, TargetBuffer * pTargetBuffer, SymbolFormat * pSymbolFormat)
4187 pTargetBuffer->Clear();
4188 *pSymbolFormat = kSymbolFormatNone;
4190 Module * pModule = vmModule.GetDacPtr();
4192 // Target should only be asking about modules that are visible to debugger.
4193 _ASSERTE(pModule->IsVisibleToDebugger());
4195 PTR_CGrowableStream pStream = pModule->GetInMemorySymbolStream();
4196 if (pStream == NULL)
4198 // Common case is to not have PDBs in-memory.
4202 const MemoryRange m = pStream->GetRawBuffer();
4205 // We may be prepared to store symbols (in some particular format) but none are there yet.
4206 // We treat this the same as not having any symbols above.
4209 InitTargetBufferFromMemoryRange(m, pTargetBuffer);
4211 // Set the symbol format appropriately
4212 ESymbolFormat symFormat = pModule->GetInMemorySymbolStreamFormat();
4215 case eSymbolFormatPDB:
4216 *pSymbolFormat = kSymbolFormatPDB;
4219 case eSymbolFormatILDB:
4220 *pSymbolFormat = kSymbolFormatILDB;
4224 CONSISTENCY_CHECK_MSGF(false, "Unexpected symbol format");
4225 pTargetBuffer->Clear();
4226 ThrowHR(E_UNEXPECTED);
4232 void DacDbiInterfaceImpl::GetModuleForDomainFile(VMPTR_DomainFile vmDomainFile, OUT VMPTR_Module * pModule)
4236 _ASSERTE(pModule != NULL);
4238 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
4239 pModule->SetHostPtr(pDomainFile->GetModule());
4243 // Implement IDacDbiInterface::GetDomainFileData
4244 void DacDbiInterfaceImpl::GetDomainFileData(VMPTR_DomainFile vmDomainFile, DomainFileInfo * pData)
4248 _ASSERTE(pData != NULL);
4250 ZeroMemory(pData, sizeof(*pData));
4252 DomainFile * pDomainFile = vmDomainFile.GetDacPtr();
4253 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
4255 // @dbgtodo - is this efficient DAC usage (perhaps a dac-cop rule)? Are we round-tripping the pointer?
4256 // Should we have a GetDomainAssembly() that returns a PTR_DomainAssembly?
4257 pData->vmDomainAssembly.SetHostPtr(pDomainFile->GetDomainAssembly());
4258 pData->vmAppDomain.SetHostPtr(pAppDomain);
4261 // Implement IDacDbiInterface::GetModuleData
4262 void DacDbiInterfaceImpl::GetModuleData(VMPTR_Module vmModule, ModuleInfo * pData)
4266 _ASSERTE(pData != NULL);
4268 ZeroMemory(pData, sizeof(*pData));
4270 Module * pModule = vmModule.GetDacPtr();
4271 PEFile * pFile = pModule->GetFile();
4273 pData->vmPEFile.SetHostPtr(pFile);
4274 pData->vmAssembly.SetHostPtr(pModule->GetAssembly());
4277 BOOL fIsDynamic = pModule->IsReflection();
4278 pData->fIsDynamic = fIsDynamic;
4280 // Get PE BaseAddress and Size
4281 // For dynamic modules, these are 0. Else,
4282 pData->pPEBaseAddress = NULL;
4288 pData->pPEBaseAddress = PTR_TO_TADDR(pFile->GetDebuggerContents(&size));
4289 pData->nPESize = (ULONG) size;
4292 // In-memory is determined by whether the module has a filename.
4293 pData->fInMemory = FALSE;
4296 pData->fInMemory = pFile->GetPath().IsEmpty();
4301 // Enumerate all AppDomains in the process.
4302 void DacDbiInterfaceImpl::EnumerateAppDomains(
4303 FP_APPDOMAIN_ENUMERATION_CALLBACK fpCallback,
4308 _ASSERTE(fpCallback != NULL);
4310 // Only include active appdomains in the enumeration.
4311 // This includes appdomains sent before the AD load event,
4312 // and does not include appdomains that are in shutdown after the AD exit event.
4313 const BOOL bOnlyActive = TRUE;
4314 AppDomainIterator iterator(bOnlyActive);
4316 while(iterator.Next())
4318 // It's critical that we don't yield appdomains after the unload event has been sent.
4319 // See code:IDacDbiInterface#Enumeration for details.
4320 AppDomain * pAppDomain = iterator.GetDomain();
4321 if (pAppDomain->IsUnloading())
4326 VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
4327 vmAppDomain.SetHostPtr(pAppDomain);
4329 fpCallback(vmAppDomain, pUserData);
4333 // Enumerate all Assemblies in an appdomain.
4334 void DacDbiInterfaceImpl::EnumerateAssembliesInAppDomain(
4335 VMPTR_AppDomain vmAppDomain,
4336 FP_ASSEMBLY_ENUMERATION_CALLBACK fpCallback,
4342 _ASSERTE(fpCallback != NULL);
4344 // Iterate through all Assemblies (including shared) in the appdomain.
4345 AppDomain::AssemblyIterator iterator;
4347 // If the containing appdomain is unloading, then don't enumerate any assemblies
4348 // in the domain. This is to enforce rules at code:IDacDbiInterface#Enumeration.
4349 // See comment in code:DacDbiInterfaceImpl::EnumerateModulesInAssembly code for details.
4350 AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
4351 if (pAppDomain->IsUnloading())
4356 // Pass the magical flags to the loader enumerator to get all Execution-only assemblies.
4357 iterator = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution));
4358 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4360 while (iterator.Next(pDomainAssembly.This()))
4362 if (!pDomainAssembly->IsVisibleToDebugger())
4367 VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr();
4368 vmDomainAssembly.SetHostPtr(pDomainAssembly);
4370 fpCallback(vmDomainAssembly, pUserData);
4374 // Implementation of IDacDbiInterface::EnumerateModulesInAssembly,
4375 // Enumerate all the modules (non-resource) in an assembly.
4376 void DacDbiInterfaceImpl::EnumerateModulesInAssembly(
4377 VMPTR_DomainAssembly vmAssembly,
4378 FP_MODULE_ENUMERATION_CALLBACK fpCallback,
4383 _ASSERTE(fpCallback != NULL);
4385 DomainAssembly * pDomainAssembly = vmAssembly.GetDacPtr();
4387 // If the appdomain or assembly containing this module is unloading, then don't enumerate any modules.
4388 // in the domain. This is to enforce rules at code:IDacDbiInterface#Enumeration, specifically
4389 // that new objects are not available after the unload event is sent.
4390 // This is a very large hammer, but since modules only unload with appdomains or assemblies, we're
4391 // erring on the side of safety. If the debugger happens to have VMPTR_DomainFiles (CordbModules) already
4392 // cached, it can still use those until the unload event.
4393 if (pDomainAssembly->IsUnloading())
4399 // If the domain is not yet fully-loaded, don't advertise it yet.
4400 // It's not ready to be inspected.
4401 DomainModuleIterator iterator = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
4403 while (iterator.Next())
4405 DomainFile * pDomainFile = iterator.GetDomainFile();
4407 // Debugger isn't notified of Resource / Inspection-only modules.
4408 if (!pDomainFile->GetModule()->IsVisibleToDebugger())
4413 _ASSERTE(pDomainFile->IsLoaded());
4415 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
4416 vmDomainFile.SetHostPtr(pDomainFile);
4418 fpCallback(vmDomainFile, pUserData);
4422 // Implementation of IDacDbiInterface::ResolveAssembly
4423 // Returns NULL if not found.
4424 VMPTR_DomainAssembly DacDbiInterfaceImpl::ResolveAssembly(
4425 VMPTR_DomainFile vmScope,
4426 mdToken tkAssemblyRef)
4431 DomainFile * pDomainFile = vmScope.GetDacPtr();
4432 AppDomain * pAppDomain = pDomainFile->GetAppDomain();
4433 Module * pModule = pDomainFile->GetCurrentModule();
4435 VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr();
4437 Assembly * pAssembly = pModule->LookupAssemblyRef(tkAssemblyRef);
4438 if (pAssembly != NULL)
4440 DomainAssembly * pDomainAssembly = pAssembly->FindDomainAssembly(pAppDomain);
4441 vmDomainAssembly.SetHostPtr(pDomainAssembly);
4443 return vmDomainAssembly;
4446 // When stopped at an event, request a synchronization.
4447 // See DacDbiInterface.h for full comments
4448 void DacDbiInterfaceImpl::RequestSyncAtEvent()
4452 // To request a sync, we just need to set g_pDebugger->m_RSRequestedSync high.
4453 if (g_pDebugger != NULL)
4455 TADDR addr = PTR_HOST_MEMBER_TADDR(Debugger, g_pDebugger, m_RSRequestedSync);
4458 SafeWriteStructOrThrow<BOOL>(addr, &fTrue);
4463 HRESULT DacDbiInterfaceImpl::SetSendExceptionsOutsideOfJMC(BOOL sendExceptionsOutsideOfJMC)
4470 if (g_pDebugger != NULL)
4472 TADDR addr = PTR_HOST_MEMBER_TADDR(Debugger, g_pDebugger, m_sendExceptionsOutsideOfJMC);
4473 SafeWriteStructOrThrow<BOOL>(addr, &sendExceptionsOutsideOfJMC);
4476 EX_CATCH_HRESULT(hr);
4480 // Notify the debuggee that a debugger attach is pending.
4481 // See DacDbiInterface.h for full comments
4482 void DacDbiInterfaceImpl::MarkDebuggerAttachPending()
4486 if (g_pDebugger != NULL)
4488 DWORD flags = g_CORDebuggerControlFlags;
4489 flags |= DBCF_PENDING_ATTACH;
4491 // Uses special DAC writing. PTR_TO_TADDR doesn't fetch for globals.
4492 // @dbgtodo dac support - the exact mechanism of writing to the target needs to be flushed out,
4493 // especially as it relates to DAC cop and enforcing undac-ized writes.
4494 g_CORDebuggerControlFlags = flags;
4498 // Caller should have gauranteed that the LS is loaded.
4499 // If we're detaching, then don't throw because we don't care.
4500 ThrowHR(CORDBG_E_NOTREADY);
4505 // Notify the debuggee that a debugger is attached.
4506 // See DacDbiInterface.h for full comments
4507 void DacDbiInterfaceImpl::MarkDebuggerAttached(BOOL fAttached)
4511 if (g_pDebugger != NULL)
4513 // To be attached, we need to set the following
4514 // g_CORDebuggerControlFlags |= DBCF_ATTACHED;
4515 // To detach (if !fAttached), we need to do the opposite.
4517 DWORD flags = g_CORDebuggerControlFlags;
4520 flags |= DBCF_ATTACHED;
4524 flags &= ~ (DBCF_ATTACHED | DBCF_PENDING_ATTACH);
4527 // Uses special DAC writing. PTR_TO_TADDR doesn't fetch for globals.
4528 // @dbgtodo dac support - the exact mechanism of writing to the target needs to be flushed out,
4529 // especially as it relates to DAC cop and enforcing undac-ized writes.
4530 g_CORDebuggerControlFlags = flags;
4534 // Caller should have gauranteed that the LS is loaded.
4535 // If we're detaching, then don't throw because we don't care.
4536 ThrowHR(CORDBG_E_NOTREADY);
4541 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
4542 // Enumerate all the Connections in the process.
4543 void DacDbiInterfaceImpl::EnumerateConnections(FP_CONNECTION_CALLBACK fpCallback, void * pUserData)
4547 ConnectionNameHashEntry * pConnection;
4551 pConnection = CCLRDebugManager::FindFirst(&hashfind);
4554 DWORD id = pConnection->m_dwConnectionId;
4555 LPCWSTR pName = pConnection->m_pwzName;
4557 fpCallback(id, pName, pUserData);
4559 // now get the next connection record
4560 pConnection = CCLRDebugManager::FindNext(&hashfind);
4566 // Enumerate all threads in the process.
4567 void DacDbiInterfaceImpl::EnumerateThreads(FP_THREAD_ENUMERATION_CALLBACK fpCallback, void * pUserData)
4571 if (ThreadStore::s_pThreadStore == NULL)
4576 Thread *pThread = ThreadStore::GetThreadList(NULL);
4578 while (pThread != NULL)
4581 // Don't want to publish threads via enumeration before they're ready to be inspected.
4582 // Use the same window that we used in whidbey.
4583 Thread::ThreadState threadState = pThread->GetSnapshotState();
4584 if (!((IsThreadMarkedDeadWorker(pThread)) || (threadState & Thread::TS_Unstarted)))
4586 VMPTR_Thread vmThread = VMPTR_Thread::NullPtr();
4587 vmThread.SetHostPtr(pThread);
4588 fpCallback(vmThread, pUserData);
4591 pThread = ThreadStore::GetThreadList(pThread);
4595 // public implementation of IsThreadMarkedDead
4596 bool DacDbiInterfaceImpl::IsThreadMarkedDead(VMPTR_Thread vmThread)
4599 Thread * pThread = vmThread.GetDacPtr();
4600 return IsThreadMarkedDeadWorker(pThread);
4603 // Private worker for IsThreadMarkedDead
4606 // pThread - valid thread to check if dead
4609 // true iff thread is marked as dead.
4612 // This is an internal method that skips public validation.
4613 // See code:IDacDbiInterface::#IsThreadMarkedDead for purpose.
4614 bool DacDbiInterfaceImpl::IsThreadMarkedDeadWorker(Thread * pThread)
4616 _ASSERTE(pThread != NULL);
4618 Thread::ThreadState threadState = pThread->GetSnapshotState();
4620 bool fIsDead = (threadState & Thread::TS_Dead) != 0;
4626 // Return the handle of the specified thread.
4627 HANDLE DacDbiInterfaceImpl::GetThreadHandle(VMPTR_Thread vmThread)
4631 Thread * pThread = vmThread.GetDacPtr();
4632 return pThread->GetThreadHandle();
4635 // Return the object handle for the managed Thread object corresponding to the specified thread.
4636 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetThreadObject(VMPTR_Thread vmThread)
4640 Thread * pThread = vmThread.GetDacPtr();
4641 Thread::ThreadState threadState = pThread->GetSnapshotState();
4643 if ( (threadState & Thread::TS_Dead) ||
4644 (threadState & Thread::TS_Unstarted) ||
4645 (threadState & Thread::TS_Detached) ||
4648 ThrowHR(CORDBG_E_BAD_THREAD_STATE);
4652 VMPTR_OBJECTHANDLE vmObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
4653 vmObjHandle.SetDacTargetPtr(pThread->GetExposedObjectHandleForDebugger());
4658 // Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
4659 // according to the CorDebugThreadState.
4660 void DacDbiInterfaceImpl::SetDebugState(VMPTR_Thread vmThread,
4661 CorDebugThreadState debugState)
4665 Thread * pThread = vmThread.GetDacPtr();
4667 // update the field on the host copy
4668 if (debugState == THREAD_SUSPEND)
4670 pThread->SetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
4672 else if (debugState == THREAD_RUN)
4674 pThread->ResetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
4678 ThrowHR(E_INVALIDARG);
4681 // update the field on the target copy
4682 TADDR taThreadState = PTR_HOST_MEMBER_TADDR(Thread, pThread, m_StateNC);
4683 SafeWriteStructOrThrow<Thread::ThreadStateNoConcurrency>(taThreadState, &(pThread->m_StateNC));
4686 // Gets the debugger unhandled exception threadstate flag
4687 BOOL DacDbiInterfaceImpl::HasUnhandledException(VMPTR_Thread vmThread)
4691 Thread * pThread = vmThread.GetDacPtr();
4693 // some managed exceptions don't have any underlying
4694 // native exception processing going on. They just consist
4695 // of a managed throwable that we have stashed away followed
4696 // by a debugger notification and some form of failfast.
4697 // Everything that comes through EEFatalError is in this category
4698 if(pThread->IsLastThrownObjectUnhandled())
4703 // most managed exceptions are just a throwable bound to a
4704 // native exception. In that case this handle will be non-null
4705 OBJECTHANDLE ohException = pThread->GetThrowableAsHandle();
4706 if (ohException != NULL)
4708 // during the UEF we set the unhandled bit, if it is set the exception
4710 // however if the exception has intercept info then we consider it handled
4712 return pThread->GetExceptionState()->GetFlags()->IsUnhandled() &&
4713 !(pThread->GetExceptionState()->GetFlags()->DebuggerInterceptInfo());
4719 // Return the user state of the specified thread.
4720 CorDebugUserState DacDbiInterfaceImpl::GetUserState(VMPTR_Thread vmThread)
4725 result = GetPartialUserState(vmThread);
4727 if (!IsThreadAtGCSafePlace(vmThread))
4729 result |= USER_UNSAFE_POINT;
4732 return (CorDebugUserState)result;
4736 // Return the connection ID of the specified thread.
4737 CONNID DacDbiInterfaceImpl::GetConnectionID(VMPTR_Thread vmThread)
4741 Thread * pThread = vmThread.GetDacPtr();
4742 return pThread->GetConnectionId();
4745 // Return the task ID of the specified thread.
4746 TASKID DacDbiInterfaceImpl::GetTaskID(VMPTR_Thread vmThread)
4750 Thread * pThread = vmThread.GetDacPtr();
4751 return pThread->GetTaskId();
4754 // Return the OS thread ID of the specified thread
4755 DWORD DacDbiInterfaceImpl::TryGetVolatileOSThreadID(VMPTR_Thread vmThread)
4759 Thread * pThread = vmThread.GetDacPtr();
4760 _ASSERTE(pThread != NULL);
4762 DWORD dwThreadId = pThread->GetOSThreadIdForDebugger();
4764 // If the thread ID is a the magical cookie value, then this is really
4765 // a switched out thread and doesn't have an OS tid. In that case, the
4766 // DD contract is to return 0 (a much more sane value)
4767 const DWORD dwSwitchedOutThreadId = SWITCHED_OUT_FIBER_OSID;
4768 if (dwThreadId == dwSwitchedOutThreadId)
4775 // Return the unique thread ID of the specified thread.
4776 DWORD DacDbiInterfaceImpl::GetUniqueThreadID(VMPTR_Thread vmThread)
4780 Thread * pThread = vmThread.GetDacPtr();
4781 _ASSERTE(pThread != NULL);
4783 if (CLRTaskHosted())
4785 return pThread->GetThreadId();
4789 return pThread->GetOSThreadId();
4793 // Return the object handle to the managed Exception object of the current exception
4794 // on the specified thread. The return value could be NULL if there is no current exception.
4795 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetCurrentException(VMPTR_Thread vmThread)
4799 Thread * pThread = vmThread.GetDacPtr();
4801 // OBJECTHANDLEs are really just TADDRs.
4802 OBJECTHANDLE ohException = pThread->GetThrowableAsHandle(); // ohException can be NULL
4804 if (ohException == NULL)
4806 if (pThread->IsLastThrownObjectUnhandled())
4808 ohException = pThread->LastThrownObjectHandle();
4812 VMPTR_OBJECTHANDLE vmObjHandle;
4813 vmObjHandle.SetDacTargetPtr(ohException);
4817 // Return the object handle to the managed object for a given CCW pointer.
4818 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetObjectForCCW(CORDB_ADDRESS ccwPtr)
4822 OBJECTHANDLE ohCCW = NULL;
4824 #ifdef FEATURE_COMINTEROP
4825 ComCallWrapper *pCCW = DACGetCCWFromAddress(ccwPtr);
4828 ohCCW = pCCW->GetObjectHandle();
4832 VMPTR_OBJECTHANDLE vmObjHandle;
4833 vmObjHandle.SetDacTargetPtr(ohCCW);
4837 // Return the object handle to the managed CustomNotification object of the current notification
4838 // on the specified thread. The return value could be NULL if there is no current notification.
4840 // input: vmThread - the thread on which the notification occurred
4841 // Return value: object handle for the current notification (if any) on the thread. This will return non-null
4842 // if and only if we are currently inside a CustomNotification Callback (or a dump was generated while in this
4845 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetCurrentCustomDebuggerNotification(VMPTR_Thread vmThread)
4849 Thread * pThread = vmThread.GetDacPtr();
4851 // OBJECTHANDLEs are really just TADDRs.
4852 OBJECTHANDLE ohNotification = pThread->GetThreadCurrNotification(); // ohNotification can be NULL
4854 VMPTR_OBJECTHANDLE vmObjHandle;
4855 vmObjHandle.SetDacTargetPtr(ohNotification);
4859 // Return the current appdomain the specified thread is in.
4860 VMPTR_AppDomain DacDbiInterfaceImpl::GetCurrentAppDomain(VMPTR_Thread vmThread)
4864 Thread * pThread = vmThread.GetDacPtr();
4865 AppDomain * pAppDomain = pThread->GetDomain();
4867 if (pAppDomain == NULL)
4872 VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
4873 vmAppDomain.SetDacTargetPtr(PTR_HOST_TO_TADDR(pAppDomain));
4878 // Returns a bitfield reflecting the managed debugging state at the time of
4880 CLR_DEBUGGING_PROCESS_FLAGS DacDbiInterfaceImpl::GetAttachStateFlags()
4884 CLR_DEBUGGING_PROCESS_FLAGS res = (CLR_DEBUGGING_PROCESS_FLAGS)0;
4885 if (g_pDebugger != NULL)
4887 res = g_pDebugger->GetAttachStateFlags();
4891 // When launching the process under a managed debugger we
4892 // request these flags when CLR is loaded (before g_pDebugger
4893 // had a chance to be initialized). In these cases simply
4899 //---------------------------------------------------------------------------------------
4900 // Helper to get the address of the 2nd-chance hijack function Or throw
4903 // Non-null Target Address of hijack function.
4904 TADDR DacDbiInterfaceImpl::GetHijackAddress()
4907 if (g_pDebugger != NULL)
4909 // Get the start address of the redirect function for unhandled exceptions.
4910 addr = dac_cast<TADDR>(g_pDebugger->m_rgHijackFunction[Debugger::kUnhandledException].StartAddress());
4914 ThrowHR(CORDBG_E_NOTREADY);
4919 //---------------------------------------------------------------------------------------
4920 // Helper to determine whether a control PC is in any native stub which the runtime knows how to unwind.
4923 // taControlPC - control PC to be checked
4926 // Returns true if the control PC is in a runtime unwindable stub.
4929 // Currently this function only recognizes the ExceptionHijack() stub,
4930 // which is used for unhandled exceptions.
4933 bool DacDbiInterfaceImpl::IsRuntimeUnwindableStub(PCODE targetControlPC)
4936 TADDR controlPC = PCODEToPINSTR(targetControlPC);
4937 // we call this function a lot while walking the stack and the values here will never change
4938 // Getting the g_pDebugger and each entry in the m_rgHijackFunction is potentially ~7 DAC
4939 // accesses per frame. Caching the data into a single local array is much faster. This optimization
4940 // recovered a few % of DAC stackwalking time
4941 if(!m_isCachedHijackFunctionValid)
4943 Debugger* pDebugger = g_pDebugger;
4944 if ((pDebugger == NULL) || (pDebugger->m_rgHijackFunction == NULL))
4946 // The in-process debugging infrastructure hasn't been fully initialized, which means that we could
4947 // NOT have hijacked anything yet.
4951 // PERF NOTE: if needed this array copy could probably be made more efficient
4952 // hitting the DAC only once for a single memory block, or even better
4953 // put the array inline in the Debugger object so that we only do 1 DAC
4954 // access for this entire thing
4955 for (int i = 0; i < Debugger::kMaxHijackFunctions; i++)
4957 InitTargetBufferFromMemoryRange(pDebugger->m_rgHijackFunction[i], &m_pCachedHijackFunction[i] );
4959 m_isCachedHijackFunctionValid = TRUE;
4962 // Check whether the control PC is in any of the thread redirection functions.
4963 for (int i = 0; i < Debugger::kMaxHijackFunctions; i++)
4965 CORDB_ADDRESS start = m_pCachedHijackFunction[i].pAddress;
4966 CORDB_ADDRESS end = start + m_pCachedHijackFunction[i].cbSize;
4967 if ((start <= controlPC) && (controlPC < end))
4975 //---------------------------------------------------------------------------------------
4976 // Align a stack pointer for the given architecture
4979 // pEsp - in/out: pointer to stack pointer.
4981 void DacDbiInterfaceImpl::AlignStackPointer(CORDB_ADDRESS * pEsp)
4987 // on 64-bit, stack pointer must be 16-byte aligned.
4988 // Stacks grown down, so round down to nearest 0xF bits.
4989 *pEsp &= ~((CORDB_ADDRESS) 0xF);
4993 //---------------------------------------------------------------------------------------
4994 // Emulate pushing something on a thread's stack.
4997 // pEsp - in/out: pointer to stack pointer to push object at. On output,
4998 // updated stack pointer.
4999 // pData - object to push on the stack.
5000 // fAlignStack - whether to align the stack pointer before and after the push.
5001 // Callers which specify FALSE must be very careful and know exactly
5002 // what they are doing.
5005 // address of pushed object. Throws on error.
5007 CORDB_ADDRESS DacDbiInterfaceImpl::PushHelper(CORDB_ADDRESS * pEsp,
5013 if (fAlignStack == TRUE)
5015 AlignStackPointer(pEsp);
5018 if (fAlignStack == TRUE)
5020 AlignStackPointer(pEsp);
5022 SafeWriteStructOrThrow(*pEsp, pData);
5026 //---------------------------------------------------------------------------------------
5027 // Write an EXCEPTION_RECORD structure to the remote target at the specified address while taking
5028 // into account the number of exception parameters. On 64-bit OS and on the WOW64, the OS always
5029 // pushes the entire EXCEPTION_RECORD onto the stack. However, on native x86 OS, the OS only pushes
5030 // enough of the EXCEPTION_RECORD to cover the specified number of exception parameters. Thus we
5031 // need to be extra careful when we overwrite an EXCEPTION_RECORD on the stack.
5034 // pRemotePtr - address of the EXCEPTION_RECORD in the remote target
5035 // pExcepRecord - EXCEPTION_RECORD to be written
5038 // This function is only used by the code which hijacks a therad when there's an unhandled exception.
5039 // It only works when we are actually debugging a live process, not a dump.
5042 void DacDbiInterfaceImpl::WriteExceptionRecordHelper(CORDB_ADDRESS pRemotePtr,
5043 const EXCEPTION_RECORD * pExcepRecord)
5045 // Calculate the correct size to push onto the stack.
5046 ULONG32 cbSize = offsetof(EXCEPTION_RECORD, ExceptionInformation);
5047 cbSize += pExcepRecord->NumberParameters * sizeof(pExcepRecord->ExceptionInformation[0]);
5049 // Use the data target to write to the remote target. Here we are assuming that we are debugging a
5050 // live process, since this function is only called by the hijacking code for unhandled exceptions.
5051 HRESULT hr = m_pMutableTarget->WriteVirtual(pRemotePtr,
5052 reinterpret_cast<const BYTE *>(pExcepRecord),
5061 // Implement IDacDbiInterface::Hijack
5062 void DacDbiInterfaceImpl::Hijack(
5063 VMPTR_Thread vmThread,
5065 const EXCEPTION_RECORD * pRecord,
5066 T_CONTEXT * pOriginalContext,
5067 ULONG32 cbSizeContext,
5068 EHijackReason::EHijackReason reason,
5070 CORDB_ADDRESS * pRemoteContextAddr)
5075 // Validate parameters
5078 // pRecord may be NULL if we're not hijacking at an exception
5079 // pOriginalContext may be NULL if caller doesn't want a copy of the context.
5080 // (The hijack function already has the context)
5081 _ASSERTE((pOriginalContext == NULL) == (cbSizeContext == 0));
5082 _ASSERTE(EHijackReason::IsValid(reason));
5083 #ifdef PLATFORM_UNIX
5084 _ASSERTE(!"Not supported on this platform");
5088 // If we hijack a thread which might not be managed we can set vmThread = NULL
5089 // The only side-effect in this case is that we can't reuse CONTEXT and
5090 // EXCEPTION_RECORD space on the stack by an already underway in-process exception
5091 // filter. If you depend on those being used and updated you must provide the vmThread
5093 Thread* pThread = NULL;
5094 if(!vmThread.IsNull())
5096 pThread = vmThread.GetDacPtr();
5097 _ASSERTE(pThread->GetOSThreadIdForDebugger() == dwThreadId);
5100 TADDR pfnHijackFunction = GetHijackAddress();
5103 // Setup context for hijack
5106 HRESULT hr = m_pTarget->GetThreadContext(
5113 // If caller requested, copy back the original context that we're hijacking from.
5114 if (pOriginalContext != NULL)
5116 // Since Dac + DBI are tightly coupled, context sizes should be the same.
5117 if (cbSizeContext != sizeof(T_CONTEXT))
5119 ThrowHR(E_INVALIDARG);
5122 memcpy(pOriginalContext, &ctx, cbSizeContext);
5125 // Make sure the trace flag isn't on. This can happen if we were single stepping the thread when we faulted. This
5126 // will ensure that we don't try to single step through the OS's exception logic, which greatly confuses our second
5127 // chance hijack logic. This also mimics what the OS does for us automaically when single stepping in process, i.e.,
5128 // when you turn the trace flag on in-process and go, if there is a fault, the fault is reported and the trace flag
5129 // is automatically turned off.
5131 // The debugger could always re-enable the single-step flag if it wants to.
5132 #ifndef _TARGET_ARM_
5133 UnsetSSFlag(reinterpret_cast<DT_CONTEXT *>(&ctx));
5137 void* espContext = NULL;
5138 void* espRecord = NULL;
5139 const void* pData = pUserData;
5141 // @dbgtodo cross-plat - this is not cross plat
5142 CORDB_ADDRESS esp = GetSP(&ctx);
5145 // Find out where the OS exception dispatcher has pushed the EXCEPTION_RECORD and CONTEXT. The ExInfo and
5146 // ExceptionTracker have pointers to these data structures, but when we get the unhandled exception
5147 // notification, the OS exception dispatcher is no longer on the stack, so these pointers are no longer
5148 // valid. We need to either update these pointers in the ExInfo/ExcepionTracker, or reuse the stack
5149 // space used by the OS exception dispatcher. We are using the latter approach here.
5152 CORDB_ADDRESS espOSContext = NULL;
5153 CORDB_ADDRESS espOSRecord = NULL;
5154 if (pThread != NULL && pThread->IsExceptionInProgress())
5156 espOSContext = (CORDB_ADDRESS)PTR_TO_TADDR(pThread->GetExceptionState()->GetContextRecord());
5157 espOSRecord = (CORDB_ADDRESS)PTR_TO_TADDR(pThread->GetExceptionState()->GetExceptionRecord());
5159 // The managed exception may not be related to the unhandled exception for which we are trying to
5160 // hijack. An example would be when a thread hits a managed exception, VS tries to do func eval on
5161 // the thread, but the func eval causes an unhandled exception (e.g. AV in mscorwks.dll). In this
5162 // case, the pointers stored on the ExInfo/ExceptionTracker are closer to the root than the current
5163 // SP of the thread. The check below makes sure we don't reuse the pointers in this case.
5164 if (espOSContext < esp)
5166 SafeWriteStructOrThrow(espOSContext, &ctx);
5167 espContext = CORDB_ADDRESS_TO_PTR(espOSContext);
5169 // We should have an EXCEPTION_RECORD if we are hijacked at an exception.
5170 // We need to be careful when we overwrite the exception record. On x86, the OS doesn't
5171 // always push the full record onto the stack, and so we can't blindly use sizeof(EXCEPTION_RECORD).
5172 // Instead, we have to look at the number of exception parameters and calculate the size.
5173 _ASSERTE(pRecord != NULL);
5174 WriteExceptionRecordHelper(espOSRecord, pRecord);
5175 espRecord = CORDB_ADDRESS_TO_PTR(espOSRecord);
5177 esp = min(espOSContext, espOSRecord);
5181 // If we haven't reused the pointers, then push everything at the leaf of the stack.
5182 if (espContext == NULL)
5184 _ASSERTE(espRecord == NULL);
5186 // Push on full Context and ExceptionRecord structures. We'll then push pointers to these,
5187 // and those pointers will serve as the actual args to the function.
5188 espContext = CORDB_ADDRESS_TO_PTR(PushHelper(&esp, &ctx, TRUE));
5190 // If caller didn't pass an exception-record, then we're not being hijacked at an exception.
5191 // We'll just pass NULL for the exception-record to the Hijack function.
5192 if (pRecord != NULL)
5194 espRecord = CORDB_ADDRESS_TO_PTR(PushHelper(&esp, pRecord, TRUE));
5198 if(pRemoteContextAddr != NULL)
5200 *pRemoteContextAddr = PTR_TO_CORDB_ADDRESS(espContext);
5204 // Push args onto the stack to be able to call the hijack function
5207 // Prototype of hijack is:
5208 // void __stdcall ExceptionHijackWorker(CONTEXT * pContext, EXCEPTION_RECORD * pRecord, EHijackReason, void * pData)
5209 // Set up everything so that the hijack stub can just do a "call" instruction.
5211 // Regarding stack overflow: We could do an explicit check against the thread's stack base limit.
5212 // However, we don't need an explicit overflow check because if the stack does overflow,
5213 // the hijack will just hit a regular stack-overflow exception.
5214 #if defined(_TARGET_X86_) // TARGET
5215 // X86 calling convention is to push args on the stack in reverse order.
5216 // If we fail here, the stack is written, but esp hasn't been committed yet so it shouldn't matter.
5217 PushHelper(&esp, &pData, TRUE);
5218 PushHelper(&esp, &reason, TRUE);
5219 PushHelper(&esp, &espRecord, TRUE);
5220 PushHelper(&esp, &espContext, TRUE);
5221 #elif defined (_TARGET_AMD64_) // TARGET
5222 // AMD64 calling convention is to place first 4 parameters in: rcx, rdx, r8 and r9
5223 ctx.Rcx = (DWORD64) espContext;
5224 ctx.Rdx = (DWORD64) espRecord;
5225 ctx.R8 = (DWORD64) reason;
5226 ctx.R9 = (DWORD64) pData;
5228 // Caller must allocate stack space to spill for args.
5229 // Push the arguments onto the outgoing argument homes.
5230 // Make sure we push pointer-sized values to keep the stack aligned.
5231 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.R9)), FALSE);
5232 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.R8)), FALSE);
5233 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.Rdx)), FALSE);
5234 PushHelper(&esp, reinterpret_cast<SIZE_T *>(&(ctx.Rcx)), FALSE);
5235 #elif defined(_TARGET_ARM_)
5236 ctx.R0 = (DWORD)espContext;
5237 ctx.R1 = (DWORD)espRecord;
5238 ctx.R2 = (DWORD)reason;
5239 ctx.R3 = (DWORD)pData;
5240 #elif defined(_TARGET_ARM64_)
5241 ctx.X0 = (DWORD64)espContext;
5242 ctx.X1 = (DWORD64)espRecord;
5243 ctx.X2 = (DWORD64)reason;
5244 ctx.X3 = (DWORD64)pData;
5246 PORTABILITY_ASSERT("CordbThread::HijackForUnhandledException is not implemented on this platform.");
5248 SetSP(&ctx, CORDB_ADDRESS_TO_TADDR(esp));
5250 // @dbgtodo cross-plat - not cross-platform safe
5251 SetIP(&ctx, pfnHijackFunction);
5254 // Commit the context.
5256 hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(ctx), reinterpret_cast<BYTE*> (&ctx));
5260 // Return the filter CONTEXT on the LS.
5261 VMPTR_CONTEXT DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Thread vmThread)
5265 VMPTR_CONTEXT vmContext = VMPTR_CONTEXT::NullPtr();
5267 Thread * pThread = vmThread.GetDacPtr();
5268 if (pThread->GetInteropDebuggingHijacked())
5270 _ASSERTE(!ISREDIRECTEDTHREAD(pThread));
5271 vmContext = VMPTR_CONTEXT::NullPtr();
5275 DT_CONTEXT * pLSContext = reinterpret_cast<DT_CONTEXT *>(pThread->GetFilterContext());
5276 if (pLSContext != NULL)
5278 _ASSERTE(!ISREDIRECTEDTHREAD(pThread));
5279 vmContext.SetHostPtr(pLSContext);
5281 else if (ISREDIRECTEDTHREAD(pThread))
5283 pLSContext = reinterpret_cast<DT_CONTEXT *>(GETREDIRECTEDCONTEXT(pThread));
5284 _ASSERTE(pLSContext != NULL);
5286 if (pLSContext != NULL)
5288 vmContext.SetHostPtr(pLSContext);
5296 // Return a TargetBuffer for the raw vararg signature.
5297 TargetBuffer DacDbiInterfaceImpl::GetVarArgSig(CORDB_ADDRESS VASigCookieAddr,
5298 CORDB_ADDRESS * pArgBase)
5302 _ASSERTE(pArgBase != NULL);
5305 // First, read the VASigCookie pointer.
5306 TADDR taVASigCookie = NULL;
5307 SafeReadStructOrThrow(VASigCookieAddr, &taVASigCookie);
5309 // Now create a DAC copy of VASigCookie.
5310 VASigCookie * pVACookie = PTR_VASigCookie(taVASigCookie);
5312 // Figure out where the first argument is.
5313 #if defined(_TARGET_X86_) // (STACK_GROWS_DOWN_ON_ARGS_WALK)
5314 *pArgBase = VASigCookieAddr + pVACookie->sizeOfArgs;
5315 #else // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
5316 *pArgBase = VASigCookieAddr + sizeof(VASigCookie *);
5317 #endif // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
5319 return TargetBuffer(PTR_TO_CORDB_ADDRESS(pVACookie->signature.GetRawSig()),
5320 pVACookie->signature.GetRawSigLen());
5323 // returns TRUE if the type requires 8-byte alignment
5324 BOOL DacDbiInterfaceImpl::RequiresAlign8(VMPTR_TypeHandle thExact)
5328 #ifdef FEATURE_64BIT_ALIGNMENT
5329 TypeHandle th = TypeHandle::FromPtr(thExact.GetDacPtr());
5330 PTR_MethodTable mt = th.AsMethodTable();
5332 return mt->RequiresAlign8();
5338 // Resolve the raw generics token to the real generics type token. The resolution is based on the
5340 GENERICS_TYPE_TOKEN DacDbiInterfaceImpl::ResolveExactGenericArgsToken(DWORD dwExactGenericArgsTokenIndex,
5341 GENERICS_TYPE_TOKEN rawToken)
5345 if (dwExactGenericArgsTokenIndex == 0)
5347 // In this case the real generics type token is the MethodTable of the "this" object.
5348 // Note that we want the target address here.
5350 // Incoming rawToken is actually a PTR_Object for the 'this' pointer.
5351 // Need to do some casting to convert GENERICS_TYPE_TOKEN --> PTR_Object
5352 TADDR addrObjThis = CORDB_ADDRESS_TO_TADDR(rawToken);
5353 PTR_Object pObjThis = dac_cast<PTR_Object>(addrObjThis);
5356 PTR_MethodTable pMT = pObjThis->GetMethodTable();
5358 // Now package up the PTR_MethodTable back into a GENERICS_TYPE_TOKEN
5359 TADDR addrMT = dac_cast<TADDR>(pMT);
5360 GENERICS_TYPE_TOKEN realToken = (GENERICS_TYPE_TOKEN) addrMT;
5363 else if (dwExactGenericArgsTokenIndex == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
5365 // rawToken is already initialized correctly. Nothing to do here.
5369 // The index of the generics type token should not be anything else.
5370 // This is indeed an error condition, and so we throw here.
5371 _ASSERTE(!"DDII::REGAT - Unexpected generics type token index.");
5372 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
5375 // Check if the given method is an IL stub or an LCD method.
5376 IDacDbiInterface::DynamicMethodType DacDbiInterfaceImpl::IsILStubOrLCGMethod(VMPTR_MethodDesc vmMethodDesc)
5380 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
5382 if (pMD->IsILStub())
5386 else if (pMD->IsLCGMethod())
5396 //---------------------------------------------------------------------------------------
5398 // Determine whether the specified thread is at a GC safe place.
5401 // vmThread - the thread to be examined
5404 // Return TRUE if the thread is at a GC safe place.
5405 // and under what conditions
5408 // This function basically does a one-frame stackwalk.
5409 // The logic is adopted from Debugger::IsThreadAtSafePlace().
5412 BOOL DacDbiInterfaceImpl::IsThreadAtGCSafePlace(VMPTR_Thread vmThread)
5416 BOOL fIsGCSafe = FALSE;
5417 Thread * pThread = vmThread.GetDacPtr();
5419 // Check if the runtime has entered "Shutdown for Finalizer" mode.
5420 if ((g_fEEShutDown & ShutDown_Finalize2) != 0)
5428 SetUpRegdisplayForStackWalk(pThread, &ctx, &rd);
5430 ULONG32 flags = (QUICKUNWIND | HANDLESKIPPEDFRAMES | DISABLE_MISSING_FRAME_DETECTION);
5432 StackFrameIterator iter;
5433 iter.Init(pThread, pThread->GetFrame(), &rd, flags);
5435 CrawlFrame * pCF = &(iter.m_crawl);
5436 if (pCF->IsFrameless() && pCF->IsActiveFunc())
5438 if (pCF->IsGcSafe())
5448 //---------------------------------------------------------------------------------------
5450 // Return a partial user state of the specified thread. The returned user state doesn't contain
5451 // information about USER_UNSAFE_POINT. The caller needs to call IsThreadAtGCSafePlace() to get
5452 // the full user state.
5455 // vmThread - the specified thread
5458 // Return the partial user state except for USER_UNSAFE_POINT
5461 CorDebugUserState DacDbiInterfaceImpl::GetPartialUserState(VMPTR_Thread vmThread)
5465 Thread * pThread = vmThread.GetDacPtr();
5466 Thread::ThreadState ts = pThread->GetSnapshotState();
5469 if (ts & Thread::TS_Background)
5471 result |= USER_BACKGROUND;
5474 if (ts & Thread::TS_Unstarted)
5476 result |= USER_UNSTARTED;
5479 // Don't report a StopRequested if the thread has actually stopped.
5480 if (ts & Thread::TS_Dead)
5482 result |= USER_STOPPED;
5485 // The interruptible flag is unreliable (see issue 699245)
5486 // The Debugger_SleepWaitJoin is always accurate when it is present, but it is still
5487 // just a band-aid fix to cover some of the race conditions interruptible has.
5489 if (ts & Thread::TS_Interruptible || pThread->HasThreadStateNC(Thread::TSNC_DebuggerSleepWaitJoin))
5491 result |= USER_WAIT_SLEEP_JOIN;
5494 // Don't report a SuspendRequested if the thread has actually Suspended.
5495 if ((ts & Thread::TS_UserSuspendPending) && (ts & Thread::TS_SyncSuspended))
5497 result |= USER_SUSPENDED;
5499 else if (ts & Thread::TS_UserSuspendPending)
5501 result |= USER_SUSPEND_REQUESTED;
5504 if (pThread->IsThreadPoolThread())
5506 result |= USER_THREADPOOL;
5509 return (CorDebugUserState)result;
5512 //---------------------------------------------------------------------------------------
5514 // Look up the EnC version number of a particular jitted instance of a managed method.
5517 // pModule - the module containing the managed method
5518 // vmMethodDesc - the MethodDesc of the managed method
5519 // mdMethod - the MethodDef metadata token of the managed method
5520 // pNativeStartAddress - the native start address of the jitted code
5521 // pJittedInstanceEnCVersion - out parameter; the version number of the version
5522 // corresponding to the specified native start address
5523 // pLatestEnCVersion - out parameter; the version number of the latest version
5526 // vmMethodDesc and mdMethod must match (see below).
5529 // mdMethod is not strictly necessary, since we can always get that from vmMethodDesc.
5530 // It is just a perf optimization since the caller has the metadata token around already.
5532 // Today, there is no way to retrieve the EnC version number from the RS data structures.
5533 // This primitive uses DAC to retrieve it from the LS data structures. This function may
5534 // very well be ripped out in the future if we DACize this information, but the current
5535 // thinking is that some of the RS data structures will remain, most likely in a reduced form.
5538 void DacDbiInterfaceImpl::LookupEnCVersions(Module* pModule,
5539 VMPTR_MethodDesc vmMethodDesc,
5540 mdMethodDef mdMethod,
5541 CORDB_ADDRESS pNativeStartAddress,
5542 SIZE_T * pLatestEnCVersion,
5543 SIZE_T * pJittedInstanceEnCVersion /* = NULL */)
5545 MethodDesc * pMD = vmMethodDesc.GetDacPtr();
5547 // make sure the vmMethodDesc and mdMethod match
5548 _ASSERTE(pMD->GetMemberDef() == mdMethod);
5550 _ASSERTE(pLatestEnCVersion != NULL);
5552 // @dbgtodo inspection - once we do EnC, stop using DMIs.
5553 // If the method wasn't EnCed, DMIs may not exist. And since this is DAC, we can't create them.
5555 // We may not have the memory for the DebuggerMethodInfos in a minidump.
5556 // When dump debugging EnC information isn't very useful so just fallback
5557 // to default version.
5558 DebuggerMethodInfo * pDMI = NULL;
5559 DebuggerJitInfo * pDJI = NULL;
5560 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
5562 pDMI = g_pDebugger->GetOrCreateMethodInfo(pModule, mdMethod);
5565 pDJI = pDMI->FindJitInfo(pMD, CORDB_ADDRESS_TO_TADDR(pNativeStartAddress));
5568 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
5571 if (pJittedInstanceEnCVersion != NULL)
5573 *pJittedInstanceEnCVersion = pDJI->m_encVersion;
5575 *pLatestEnCVersion = pDMI->GetCurrentEnCVersion();
5579 // If we have no DMI/DJI, then we must never have EnCed. So we can use default EnC info
5580 // Several cases where we don't have a DMI/DJI:
5582 // - method was never "touched" by debugger. (DJIs are created lazily).
5583 if (pJittedInstanceEnCVersion != NULL)
5585 *pJittedInstanceEnCVersion = CorDB_DEFAULT_ENC_FUNCTION_VERSION;
5587 *pLatestEnCVersion = CorDB_DEFAULT_ENC_FUNCTION_VERSION;
5591 // Get the address of the Debugger control block on the helper thread
5593 // Return Value: The remote address of the Debugger control block allocated on the helper thread
5594 // if it has been successfully allocated or NULL otherwise.
5595 CORDB_ADDRESS DacDbiInterfaceImpl::GetDebuggerControlBlockAddress()
5599 if ((g_pDebugger != NULL) &&
5600 (g_pDebugger->m_pRCThread != NULL))
5602 return CORDB_ADDRESS(dac_cast<TADDR>(g_pDebugger->m_pRCThread->GetDCB()));
5608 // DacDbi API: Get the context for a particular thread of the target process
5609 void DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer)
5613 _ASSERTE(pContextBuffer != NULL);
5615 Thread * pThread = vmThread.GetDacPtr();
5617 // @dbgtodo Once the filter context is removed, then we should always
5618 // start with the leaf CONTEXT.
5619 DT_CONTEXT * pFilterContext = reinterpret_cast<DT_CONTEXT *>(pThread->GetFilterContext());
5621 if (pFilterContext == NULL)
5623 // If the filter context is NULL, then we use the true context of the thread.
5624 pContextBuffer->ContextFlags = CONTEXT_ALL;
5625 HRESULT hr = m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
5626 pContextBuffer->ContextFlags,
5627 sizeof(*pContextBuffer),
5628 reinterpret_cast<BYTE *>(pContextBuffer));
5629 if (hr == E_NOTIMPL)
5631 // GetThreadContext is not implemented on this data target.
5632 // That's why we have to make do with context we can obtain from Frames explicitly stored in Thread object.
5633 // It suffices for managed debugging stackwalk.
5634 REGDISPLAY tmpRd = {};
5635 T_CONTEXT tmpContext = {};
5636 FillRegDisplay(&tmpRd, &tmpContext);
5638 // Going through thread Frames and looking for first (deepest one) one that
5639 // that has context available for stackwalking (SP and PC)
5640 // For example: RedirectedThreadFrame, InlinedCallFrame, HelperMethodFrame, ComPlusMethodFrame
5641 Frame *frame = pThread->GetFrame();
5642 while (frame != NULL && frame != FRAME_TOP)
5644 frame->UpdateRegDisplay(&tmpRd);
5645 if (GetRegdisplaySP(&tmpRd) != 0 && GetControlPC(&tmpRd) != 0)
5647 UpdateContextFromRegDisp(&tmpRd, &tmpContext);
5648 CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer));
5649 pContextBuffer->ContextFlags = DT_CONTEXT_CONTROL;
5652 frame = frame->Next();
5655 // It looks like this thread is not running managed code.
5656 ZeroMemory(pContextBuffer, sizeof(*pContextBuffer));
5665 *pContextBuffer = *pFilterContext;
5668 } // DacDbiInterfaceImpl::GetContext
5670 // Create a VMPTR_Object from a target object address
5671 // @dbgtodo validate the VMPTR_Object is in fact a object, possibly by DACizing
5673 VMPTR_Object DacDbiInterfaceImpl::GetObject(CORDB_ADDRESS ptr)
5677 VMPTR_Object vmObj = VMPTR_Object::NullPtr();
5678 vmObj.SetDacTargetPtr(CORDB_ADDRESS_TO_TADDR(ptr));
5682 HRESULT DacDbiInterfaceImpl::EnableNGENPolicy(CorDebugNGENPolicy ePolicy)
5687 HRESULT DacDbiInterfaceImpl::SetNGENCompilerFlags(DWORD dwFlags)
5691 #ifndef FEATURE_PREJIT
5692 return CORDBG_E_NGEN_NOT_SUPPORTED;
5694 // verify that we are still early enough in runtime lifecycle to mutate these
5695 // flags. Typically this is done in the CreateProcess event though it is possible
5696 // to do it even earlier
5697 if(!Debugger::s_fCanChangeNgenFlags)
5698 return CORDBG_E_MUST_BE_IN_CREATE_PROCESS;
5701 ((dwFlags & CORDEBUG_JIT_DISABLE_OPTIMIZATION) != CORDEBUG_JIT_DISABLE_OPTIMIZATION);
5702 PEFile::SetNGENDebugFlags(fAllowOpt);
5707 HRESULT DacDbiInterfaceImpl::GetNGENCompilerFlags(DWORD *pdwFlags)
5711 #ifndef FEATURE_PREJIT
5712 return CORDBG_E_NGEN_NOT_SUPPORTED;
5714 BOOL fAllowOpt = TRUE;
5715 PEFile::GetNGENDebugFlags(&fAllowOpt);
5718 *pdwFlags = CORDEBUG_JIT_DISABLE_OPTIMIZATION;
5722 *pdwFlags = CORDEBUG_JIT_DEFAULT;
5729 typedef DPTR(OBJECTREF) PTR_ObjectRef;
5731 // Create a VMPTR_Object from an address which points to a reference to an object
5732 // @dbgtodo validate the VMPTR_Object is in fact a object, possibly by DACizing
5734 VMPTR_Object DacDbiInterfaceImpl::GetObjectFromRefPtr(CORDB_ADDRESS ptr)
5738 VMPTR_Object vmObj = VMPTR_Object::NullPtr();
5739 PTR_ObjectRef objRef = PTR_ObjectRef(CORDB_ADDRESS_TO_TADDR(ptr));
5740 vmObj.SetDacTargetPtr(PTR_TO_TADDR(*objRef));
5745 // Create a VMPTR_OBJECTHANDLE from a handle
5746 VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetVmObjectHandle(CORDB_ADDRESS handleAddress)
5750 VMPTR_OBJECTHANDLE vmObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
5751 vmObjHandle.SetDacTargetPtr(CORDB_ADDRESS_TO_TADDR(handleAddress));
5757 // Validate that the VMPTR_OBJECTHANDLE refers to a legitimate managed object
5758 BOOL DacDbiInterfaceImpl::IsVmObjectHandleValid(VMPTR_OBJECTHANDLE vmHandle)
5763 // this may cause unallocated debuggee memory to be read
5764 // SEH exceptions will be caught
5767 OBJECTREF objRef = ObjectFromHandle((OBJECTHANDLE)vmHandle.GetDacPtr());
5769 // NULL is certinally valid...
5772 if (objRef->ValidateObjectWithPossibleAV())
5781 EX_END_CATCH(SwallowAllExceptions);
5786 // determines if the specified module is a WinRT module
5787 HRESULT DacDbiInterfaceImpl::IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT)
5796 Module* pModule = vmModule.GetDacPtr();
5797 isWinRT = pModule->GetFile()->GetAssembly()->IsWindowsRuntime();
5799 EX_CATCH_HRESULT(hr);
5804 // Determines the app domain id for the object refered to by a given VMPTR_OBJECTHANDLE
5805 ULONG DacDbiInterfaceImpl::GetAppDomainIdFromVmObjectHandle(VMPTR_OBJECTHANDLE vmHandle)
5809 OBJECTHANDLE handle = (OBJECTHANDLE) vmHandle.GetDacPtr();
5810 return HndGetHandleADIndex(handle).m_dwIndex;
5813 // Get the target address from a VMPTR_OBJECTHANDLE, i.e., the handle address
5814 CORDB_ADDRESS DacDbiInterfaceImpl::GetHandleAddressFromVmHandle(VMPTR_OBJECTHANDLE vmHandle)
5818 CORDB_ADDRESS handle = vmHandle.GetDacPtr();
5823 // Create a TargetBuffer which describes the location of the object
5824 TargetBuffer DacDbiInterfaceImpl::GetObjectContents(VMPTR_Object vmObj)
5827 PTR_Object objPtr = vmObj.GetDacPtr();
5829 _ASSERTE(objPtr->GetSize() <= 0xffffffff);
5830 return TargetBuffer(PTR_TO_TADDR(objPtr), (ULONG)objPtr->GetSize());
5833 // ============================================================================
5834 // functions to get information about objects referenced via an instance of CordbReferenceValue or
5836 // ============================================================================
5838 // DacDbiInterfaceImpl::FastSanityCheckObject
5839 // Helper function for CheckRef. Sanity check an object.
5840 // We use a fast and easy check to improve confidence that objPtr points to a valid object.
5841 // We can't tell cheaply if this is really a valid object (that would require walking the GC heap), but at
5842 // least we can check if we get an EEClass from the supposed method table and then get the method table from
5843 // the class. If we can, we have improved the probability that the object is valid.
5845 // input: objPtr - address of the object we are checking
5846 // Return Value: E_INVALIDARG or S_OK.
5847 HRESULT DacDbiInterfaceImpl::FastSanityCheckObject(PTR_Object objPtr)
5861 // NULL is certainly valid...
5864 if (!objPtr->ValidateObjectWithPossibleAV())
5866 LOG((LF_CORDB, LL_INFO10000, "GOI: object methodtable-class invariant doesn't hold.\n"));
5873 LOG((LF_CORDB, LL_INFO10000, "GOI: exception indicated ref is bad.\n"));
5876 EX_END_CATCH(SwallowAllExceptions);
5879 } // DacDbiInterfaceImpl::FastSanityCheckObject
5881 // Perform a sanity check on an object address to determine if this _could be_ a valid object.
5882 // We can't tell this for certain without walking the GC heap, but we do some fast tests to rule
5883 // out clearly invalid object addresses. See code:DacDbiInterfaceImpl::FastSanityCheckObject for more
5886 // input: objPtr - address of the object we are checking
5888 // objRefBad - true iff we have determined the address cannot be pointing to a valid object.
5889 // Note that a value of false doesn't necessarily guarantee the object is really
5891 bool DacDbiInterfaceImpl::CheckRef(PTR_Object objPtr)
5893 bool objRefBad = false;
5895 // Shortcut null references now...
5898 LOG((LF_CORDB, LL_INFO10000, "D::GOI: ref is NULL.\n"));
5904 // Try to verify the integrity of the object. This is not fool proof.
5905 // @todo - this whole idea of expecting AVs is broken, but it does rule
5906 // out a fair bit of rubbish. Find another
5907 // way to test if the object is valid?
5908 if (FAILED(FastSanityCheckObject(objPtr)))
5910 LOG((LF_CORDB, LL_INFO10000, "D::GOI: address is not a valid object.\n"));
5917 } // DacDbiInterfaceImpl::CheckRef
5919 // DacDbiInterfaceImpl::InitObjectData
5920 // Initialize basic object information: type handle, object size, offset to fields and expanded type
5923 // input: objPtr - address of object of interest
5924 // vmAppDomain - AppDomain for the type f the object
5925 // output: pObjectData - object information
5926 // Note: It is assumed that pObjectData is non-null.
5927 void DacDbiInterfaceImpl::InitObjectData(PTR_Object objPtr,
5928 VMPTR_AppDomain vmAppDomain,
5929 DebuggerIPCE_ObjectData * pObjectData)
5931 _ASSERTE(pObjectData != NULL);
5932 // @todo - this is still dangerous because the object may still be invalid.
5933 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
5934 vmTypeHandle.SetDacTargetPtr(objPtr->GetGCSafeTypeHandle().AsTAddr());
5936 // Save basic object info.
5937 pObjectData->objSize = objPtr->GetSize();
5938 pObjectData->objOffsetToVars = dac_cast<TADDR>((objPtr)->GetData()) - dac_cast<TADDR>(objPtr);
5940 TypeHandleToExpandedTypeInfo(AllBoxed, vmAppDomain, vmTypeHandle, &(pObjectData->objTypeData));
5942 // If this is a string object, set the type to ELEMENT_TYPE_STRING.
5943 if (objPtr->GetGCSafeMethodTable() == g_pStringClass)
5945 pObjectData->objTypeData.elementType = ELEMENT_TYPE_STRING;
5946 if(pObjectData->objSize < MIN_OBJECT_SIZE)
5948 pObjectData->objSize = PtrAlign(pObjectData->objSize);
5951 } // DacDbiInterfaceImpl::InitObjectData
5955 // Get object information for a TypedByRef object (System.TypedReference).
5957 // These are objects that contain a managed pointer to a location and the type of the value at that location.
5958 // They are most commonly used for varargs but also may be used for parameters and locals. They are
5959 // stack-allocated. They provide a means for adding dynamic type information to a value type, whereas boxing
5960 // provides only static type information. This means they can be passed as reference parameters to
5961 // polymorphic methods that don't statically restrict the type of arguments they can receive.
5963 // Although they are represented simply as an address, unlike other object references, they don't point
5964 // directly to the object. Instead, there is an extra level of indirection. The reference points to a struct
5965 // that contains the address of the object, so we need to treat them differently. They have their own
5966 // CorElementType (ELEMENT_TYPE_TYPEDBYREF) which makes it possible to identify this special case.
5969 // static int AddABunchOfInts (__arglist)
5973 // System.ArgIterator iter = new System.ArgIterator (__arglist);
5974 // int argCount = iter.GetRemainingCount();
5976 // for (int i = 0; i < argCount; i++)
5978 // System.TypedReference typedRef = iter.GetNextArg();
5979 // result += (int)TypedReference.ToObject(typedRef);
5985 // static int Main (string[] args)
5987 // int result = AddABunchOfInts (__arglist (2, 3, 4));
5988 // Console.WriteLine ("Answer: {0}", result);
5996 // Initializes the objRef and typedByRefType fields of pObjectData (type info for the referent).
5997 void DacDbiInterfaceImpl::GetTypedByRefInfo(CORDB_ADDRESS pTypedByRef,
5998 VMPTR_AppDomain vmAppDomain,
5999 DebuggerIPCE_ObjectData * pObjectData)
6003 // pTypedByRef is really the address of a TypedByRef struct rather than of a normal object.
6004 // The data field of the TypedByRef struct is the actual object ref.
6005 PTR_TypedByRef refAddr = PTR_TypedByRef(TADDR(pTypedByRef));
6007 _ASSERTE(refAddr != NULL);
6008 _ASSERTE(pObjectData != NULL);
6010 // The type of the referent is in the type field of the TypedByRef. We need to initialize the object
6011 // data type information.
6012 TypeHandleToBasicTypeInfo(refAddr->type,
6013 &(pObjectData->typedByrefInfo.typedByrefType),
6014 vmAppDomain.GetDacPtr());
6016 // The reference to the object is in the data field of the TypedByRef.
6017 CORDB_ADDRESS tempRef = dac_cast<TADDR>(refAddr->data);
6018 pObjectData->objRef = CORDB_ADDRESS_TO_PTR(tempRef);
6020 LOG((LF_CORDB, LL_INFO10000, "D::GASOI: sending REFANY result: "
6021 "ref=0x%08x, cls=0x%08x, mod=0x%p\n",
6022 pObjectData->objRef,
6023 pObjectData->typedByrefType.metadataToken,
6024 pObjectData->typedByrefType.vmDomainFile.GetDacPtr()));
6025 } // DacDbiInterfaceImpl::GetTypedByRefInfo
6027 // Get the string data associated withn obj and put it into the pointers
6029 // Get the string length and offset to string base for a string object
6030 void DacDbiInterfaceImpl::GetStringData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData)
6034 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
6035 LOG((LF_CORDB, LL_INFO10000, "D::GOI: The referent is a string.\n"));
6037 if (objPtr->GetGCSafeMethodTable() != g_pStringClass)
6039 ThrowHR(CORDBG_E_TARGET_INCONSISTENT);
6042 PTR_StringObject pStrObj = dac_cast<PTR_StringObject>(objPtr);
6044 _ASSERTE(pStrObj != NULL);
6045 pObjectData->stringInfo.length = pStrObj->GetStringLength();
6046 pObjectData->stringInfo.offsetToStringBase = (UINT_PTR) pStrObj->GetBufferOffset();
6048 } // DacDbiInterfaceImpl::GetStringData
6052 // Get information for an array type referent of an objRef, including rank, upper and lower
6053 // bounds, element size and type, and the number of elements.
6054 void DacDbiInterfaceImpl::GetArrayData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData)
6058 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
6059 PTR_MethodTable pMT = objPtr->GetGCSafeMethodTable();
6061 if (!objPtr->GetGCSafeTypeHandle().IsArray())
6063 LOG((LF_CORDB, LL_INFO10000,
6064 "D::GASOI: object should be an array.\n"));
6066 pObjectData->objRefBad = true;
6070 PTR_ArrayBase arrPtr = dac_cast<PTR_ArrayBase>(objPtr);
6072 // this is also returned in the type information for the array - we return both for sanity checking...
6073 pObjectData->arrayInfo.rank = arrPtr->GetRank();
6074 pObjectData->arrayInfo.componentCount = arrPtr->GetNumComponents();
6075 pObjectData->arrayInfo.offsetToArrayBase = arrPtr->GetDataPtrOffset(pMT);
6077 if (arrPtr->IsMultiDimArray())
6079 pObjectData->arrayInfo.offsetToUpperBounds = SIZE_T(arrPtr->GetBoundsOffset(pMT));
6081 pObjectData->arrayInfo.offsetToLowerBounds = SIZE_T(arrPtr->GetLowerBoundsOffset(pMT));
6085 pObjectData->arrayInfo.offsetToUpperBounds = 0;
6086 pObjectData->arrayInfo.offsetToLowerBounds = 0;
6089 pObjectData->arrayInfo.elementSize = arrPtr->GetComponentSize();
6091 LOG((LF_CORDB, LL_INFO10000, "D::GOI: array info: "
6092 "baseOff=%d, lowerOff=%d, upperOff=%d, cnt=%d, rank=%d, rank (2) = %d,"
6093 "eleSize=%d, eleType=0x%02x\n",
6094 pObjectData->arrayInfo.offsetToArrayBase,
6095 pObjectData->arrayInfo.offsetToLowerBounds,
6096 pObjectData->arrayInfo.offsetToUpperBounds,
6097 pObjectData->arrayInfo.componentCount,
6098 pObjectData->arrayInfo.rank,
6099 pObjectData->objTypeData.ArrayTypeData.arrayRank,
6100 pObjectData->arrayInfo.elementSize,
6101 pObjectData->objTypeData.ArrayTypeData.arrayTypeArg.elementType));
6103 } // DacDbiInterfaceImpl::GetArrayData
6105 // DAC/DBI API: Get information about an object for which we have a reference, including the object size and
6106 // type information.
6107 void DacDbiInterfaceImpl::GetBasicObjectInfo(CORDB_ADDRESS objectAddress,
6108 CorElementType type,
6109 VMPTR_AppDomain vmAppDomain,
6110 DebuggerIPCE_ObjectData * pObjectData)
6114 PTR_Object objPtr = PTR_Object(TADDR(objectAddress));
6115 pObjectData->objRefBad = CheckRef(objPtr);
6116 if (pObjectData->objRefBad != true)
6118 // initialize object type, size, offset information. Note: We may have a different element type
6119 // after this. For example, we may start with E_T_CLASS but return with something more specific.
6120 InitObjectData (objPtr, vmAppDomain, pObjectData);
6122 } // DacDbiInterfaceImpl::GetBasicObjectInfo
6124 // This is the data passed to EnumerateBlockingObjectsCallback below
6125 struct BlockingObjectUserDataWrapper
6127 CALLBACK_DATA pUserData;
6128 IDacDbiInterface::FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK fpCallback;
6131 // The callback helper used by EnumerateBlockingObjects below, this
6132 // callback in turn invokes the user's callback with the right arguments
6133 void EnumerateBlockingObjectsCallback(PTR_DebugBlockingItem obj, VOID* pUserData)
6135 BlockingObjectUserDataWrapper* wrapper = (BlockingObjectUserDataWrapper*)pUserData;
6136 DacBlockingObject dacObj;
6138 // init to an arbitrary value to avoid mac compiler error about unintialized use
6139 // it will be correctly set in the switch and is never used with only this init here
6140 dacObj.blockingReason = DacBlockReason_MonitorCriticalSection;
6142 dacObj.vmBlockingObject.SetDacTargetPtr(dac_cast<TADDR>(OBJECTREFToObject(obj->pMonitor->GetOwningObject())));
6143 dacObj.dwTimeout = obj->dwTimeout;
6144 dacObj.vmAppDomain.SetDacTargetPtr(dac_cast<TADDR>(obj->pAppDomain));
6147 case DebugBlock_MonitorCriticalSection:
6148 dacObj.blockingReason = DacBlockReason_MonitorCriticalSection;
6150 case DebugBlock_MonitorEvent:
6151 dacObj.blockingReason = DacBlockReason_MonitorEvent;
6154 _ASSERTE(!"obj->type has an invalid value");
6158 wrapper->fpCallback(dacObj, wrapper->pUserData);
6162 // Enumerate all monitors blocking a thread
6163 void DacDbiInterfaceImpl::EnumerateBlockingObjects(VMPTR_Thread vmThread,
6164 FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK fpCallback,
6165 CALLBACK_DATA pUserData)
6169 Thread * pThread = vmThread.GetDacPtr();
6170 _ASSERTE(pThread != NULL);
6172 BlockingObjectUserDataWrapper wrapper;
6173 wrapper.fpCallback = fpCallback;
6174 wrapper.pUserData = pUserData;
6176 pThread->DebugBlockingInfo.VisitBlockingItems((DebugBlockingItemVisitor)EnumerateBlockingObjectsCallback,
6181 // Returns the thread which owns the monitor lock on an object and the acquisition count
6182 MonitorLockInfo DacDbiInterfaceImpl::GetThreadOwningMonitorLock(VMPTR_Object vmObject)
6185 MonitorLockInfo info;
6186 info.lockOwner = VMPTR_Thread::NullPtr();
6187 info.acquisitionCount = 0;
6189 Object* pObj = vmObject.GetDacPtr();
6191 DWORD acquisitionCount;
6192 if(!pObj->GetHeader()->GetThreadOwningMonitorLock(&threadId, &acquisitionCount))
6197 Thread *pThread = ThreadStore::GetThreadList(NULL);
6198 while (pThread != NULL)
6200 if(pThread->GetThreadId() == threadId)
6202 info.lockOwner.SetDacTargetPtr(PTR_HOST_TO_TADDR(pThread));
6203 info.acquisitionCount = acquisitionCount;
6206 pThread = ThreadStore::GetThreadList(pThread);
6208 _ASSERTE(!"A thread should have been found");
6212 // The data passed to EnumerateThreadsCallback below
6213 struct ThreadUserDataWrapper
6215 CALLBACK_DATA pUserData;
6216 IDacDbiInterface::FP_THREAD_ENUMERATION_CALLBACK fpCallback;
6219 // The callback helper used for EnumerateMonitorEventWaitList below. This callback
6220 // invokes the user's callback with the correct arguments.
6221 void EnumerateThreadsCallback(PTR_Thread pThread, VOID* pUserData)
6223 ThreadUserDataWrapper* wrapper = (ThreadUserDataWrapper*)pUserData;
6224 VMPTR_Thread vmThread = VMPTR_Thread::NullPtr();
6225 vmThread.SetDacTargetPtr(dac_cast<TADDR>(pThread));
6226 wrapper->fpCallback(vmThread, wrapper->pUserData);
6230 // Enumerate all threads waiting on the monitor event for an object
6231 void DacDbiInterfaceImpl::EnumerateMonitorEventWaitList(VMPTR_Object vmObject,
6232 FP_THREAD_ENUMERATION_CALLBACK fpCallback,
6233 CALLBACK_DATA pUserData)
6237 Object* pObj = vmObject.GetDacPtr();
6238 SyncBlock* psb = pObj->PassiveGetSyncBlock();
6240 // no sync block means no wait list
6244 ThreadUserDataWrapper wrapper;
6245 wrapper.fpCallback = fpCallback;
6246 wrapper.pUserData = pUserData;
6247 ThreadQueue::EnumerateThreads(psb, (FP_TQ_THREAD_ENUMERATION_CALLBACK)EnumerateThreadsCallback, (VOID*) &wrapper);
6251 bool DacDbiInterfaceImpl::AreGCStructuresValid()
6256 HeapData::HeapData()
6257 : YoungestGenPtr(0), YoungestGenLimit(0), Gen0Start(0), Gen0End(0), SegmentCount(0), Segments(0)
6261 HeapData::~HeapData()
6267 LinearReadCache::LinearReadCache()
6268 : mCurrPageStart(0), mPageSize(0), mCurrPageSize(0), mPage(0)
6273 mPageSize = si.dwPageSize;
6274 mPage = new (nothrow) BYTE[mPageSize];
6277 LinearReadCache::~LinearReadCache()
6283 bool LinearReadCache::MoveToPage(CORDB_ADDRESS addr)
6285 mCurrPageStart = addr - (addr % mPageSize);
6286 HRESULT hr = g_dacImpl->m_pTarget->ReadVirtual(mCurrPageStart, mPage, mPageSize, &mCurrPageSize);
6299 CORDB_ADDRESS DacHeapWalker::HeapStart = 0;
6300 CORDB_ADDRESS DacHeapWalker::HeapEnd = ~0;
6302 DacHeapWalker::DacHeapWalker()
6303 : mThreadCount(0), mAllocInfo(0), mHeapCount(0), mHeaps(0),
6304 mCurrObj(0), mCurrSize(0), mCurrMT(0),
6305 mCurrHeap(0), mCurrSeg(0), mStart((TADDR)HeapStart), mEnd((TADDR)HeapEnd)
6309 DacHeapWalker::~DacHeapWalker()
6312 delete [] mAllocInfo;
6318 SegmentData *DacHeapWalker::FindSegment(CORDB_ADDRESS obj)
6320 for (size_t i = 0; i < mHeapCount; ++i)
6321 for (size_t j = 0; j < mHeaps[i].SegmentCount; ++j)
6322 if (mHeaps[i].Segments[j].Start <= obj && obj <= mHeaps[i].Segments[j].End)
6323 return &mHeaps[i].Segments[j];
6328 HRESULT DacHeapWalker::Next(CORDB_ADDRESS *pValue, CORDB_ADDRESS *pMT, ULONG64 *pSize)
6330 if (!HasMoreObjects())
6337 *pMT = (CORDB_ADDRESS)mCurrMT;
6340 *pSize = (ULONG64)mCurrSize;
6342 HRESULT hr = MoveToNextObject();
6343 return FAILED(hr) ? hr : S_OK;
6348 HRESULT DacHeapWalker::MoveToNextObject()
6352 // Move to the next object
6353 mCurrObj += mCurrSize;
6355 // Check to see if we are in the correct bounds.
6356 if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
6357 CheckAllocAndSegmentRange();
6359 // Check to see if we've moved off the end of a segment
6360 if (mCurrObj >= mHeaps[mCurrHeap].Segments[mCurrSeg].End || mCurrObj > mEnd)
6362 HRESULT hr = NextSegment();
6363 if (FAILED(hr) || hr == S_FALSE)
6367 // Get the method table pointer
6368 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6371 if (!GetSize(mCurrMT, mCurrSize))
6373 } while (mCurrObj < mStart);
6375 _ASSERTE(mStart <= mCurrObj && mCurrObj <= mEnd);
6379 bool DacHeapWalker::GetSize(TADDR tMT, size_t &size)
6381 // With heap corruption, it's entierly possible that the MethodTable
6382 // we get is bad. This could cause exceptions, which we will catch
6383 // and return false. This causes the heapwalker to move to the next
6388 MethodTable *mt = PTR_MethodTable(tMT);
6389 size_t cs = mt->GetComponentSize();
6394 if (mCache.Read(mCurrObj+sizeof(TADDR), &tmp))
6400 size = mt->GetBaseSize() + cs;
6402 // The size is not guaranteed to be aligned, we have to
6404 if (mHeaps[mCurrHeap].Segments[mCurrSeg].Generation == 3)
6405 size = AlignLarge(size);
6413 EX_END_CATCH(SwallowAllExceptions)
6419 HRESULT DacHeapWalker::NextSegment()
6428 while (mCurrSeg >= mHeaps[mCurrHeap].SegmentCount)
6433 if (mCurrHeap >= mHeapCount)
6439 mCurrObj = mHeaps[mCurrHeap].Segments[mCurrSeg].Start;
6441 if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
6442 CheckAllocAndSegmentRange();
6444 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6449 if (!GetSize(mCurrMT, mCurrSize))
6453 } while((mHeaps[mCurrHeap].Segments[mCurrSeg].Start > mEnd) || (mHeaps[mCurrHeap].Segments[mCurrSeg].End < mStart));
6458 void DacHeapWalker::CheckAllocAndSegmentRange()
6460 const size_t MinObjSize = sizeof(TADDR)*3;
6462 for (int i = 0; i < mThreadCount; ++i)
6463 if (mCurrObj == mAllocInfo[i].Ptr)
6465 mCurrObj = mAllocInfo[i].Limit + Align(MinObjSize);
6469 if (mCurrObj == mHeaps[mCurrHeap].YoungestGenPtr)
6471 mCurrObj = mHeaps[mCurrHeap].YoungestGenLimit + Align(MinObjSize);
6475 HRESULT DacHeapWalker::Init(CORDB_ADDRESS start, CORDB_ADDRESS end)
6477 // Collect information about the allocation contexts in the process.
6478 ThreadStore* threadStore = ThreadStore::s_pThreadStore;
6479 if (threadStore != NULL)
6481 int count = (int)threadStore->ThreadCountInEE();
6482 mAllocInfo = new (nothrow) AllocInfo[count];
6483 if (mAllocInfo == NULL)
6484 return E_OUTOFMEMORY;
6486 Thread *thread = NULL;
6488 for (int i = 0; i < count; ++i)
6490 // The thread or allocation context being null is troubling, but not fatal.
6491 // We may have stopped the process where the thread list or thread's alloc
6492 // context was in an inconsistent state. We will simply skip over affected
6493 // segments during the heap walk if we encounter problems due to this.
6494 thread = ThreadStore::GetThreadList(thread);
6498 gc_alloc_context *ctx = thread->GetAllocContext();
6502 if ((CORDB_ADDRESS)ctx->alloc_ptr != NULL)
6504 mAllocInfo[j].Ptr = (CORDB_ADDRESS)ctx->alloc_ptr;
6505 mAllocInfo[j].Limit = (CORDB_ADDRESS)ctx->alloc_limit;
6513 #ifdef FEATURE_SVR_GC
6514 HRESULT hr = GCHeapUtilities::IsServerHeap() ? InitHeapDataSvr(mHeaps, mHeapCount) : InitHeapDataWks(mHeaps, mHeapCount);
6516 HRESULT hr = InitHeapDataWks(mHeaps, mHeapCount);
6519 // Set up mCurrObj/mCurrMT.
6521 hr = Reset(start, end);
6523 // Collect information about GC heaps
6527 HRESULT DacHeapWalker::Reset(CORDB_ADDRESS start, CORDB_ADDRESS end)
6530 _ASSERTE(mHeapCount > 0);
6531 _ASSERTE(mHeaps[0].Segments);
6532 _ASSERTE(mHeaps[0].SegmentCount > 0);
6537 // Set up first object
6538 mCurrObj = mHeaps[0].Segments[0].Start;
6544 if (!mCache.ReadMT(mCurrObj, &mCurrMT))
6547 if (!GetSize(mCurrMT, mCurrSize))
6550 if (mCurrObj < mStart || mCurrObj > mEnd)
6556 HRESULT DacHeapWalker::ListNearObjects(CORDB_ADDRESS obj, CORDB_ADDRESS *pPrev, CORDB_ADDRESS *pContaining, CORDB_ADDRESS *pNext)
6558 SegmentData *seg = FindSegment(obj);
6563 HRESULT hr = Reset(seg->Start, seg->End);
6566 CORDB_ADDRESS prev = 0;
6567 CORDB_ADDRESS curr = 0;
6571 while (!found && HasMoreObjects())
6574 hr = Next(&curr, NULL, &size);
6578 if (obj >= curr && obj < curr + size)
6588 *pContaining = curr;
6592 if (HasMoreObjects())
6594 hr = Next(&curr, NULL, NULL);
6606 else if (SUCCEEDED(hr))
6615 #include "gceewks.cpp"
6616 HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
6618 // Scrape basic heap details
6620 pHeaps = new (nothrow) HeapData[1];
6622 return E_OUTOFMEMORY;
6624 pHeaps[0].YoungestGenPtr = (CORDB_ADDRESS)WKS::generation_table[0].allocation_context.alloc_ptr;
6625 pHeaps[0].YoungestGenLimit = (CORDB_ADDRESS)WKS::generation_table[0].allocation_context.alloc_limit;
6627 pHeaps[0].Gen0Start = (CORDB_ADDRESS)WKS::generation_table[0].allocation_start;
6628 pHeaps[0].Gen0End = (CORDB_ADDRESS)WKS::gc_heap::alloc_allocated.GetAddr();
6629 pHeaps[0].Gen1Start = (CORDB_ADDRESS)WKS::generation_table[1].allocation_start;
6632 int count = GetSegmentCount(WKS::generation_table[NUMBERGENERATIONS-1].start_segment);
6633 count += GetSegmentCount(WKS::generation_table[NUMBERGENERATIONS-2].start_segment);
6635 pHeaps[0].SegmentCount = count;
6636 pHeaps[0].Segments = new (nothrow) SegmentData[count];
6637 if (pHeaps[0].Segments == NULL)
6638 return E_OUTOFMEMORY;
6640 // Small object heap segments
6641 WKS::heap_segment *seg = WKS::generation_table[NUMBERGENERATIONS-2].start_segment;
6643 for (; seg && (i < count); ++i)
6645 pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
6646 if (seg == WKS::gc_heap::ephemeral_heap_segment)
6648 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)WKS::gc_heap::alloc_allocated.GetAddr();
6649 pHeaps[0].Segments[i].Generation = 1;
6650 pHeaps[0].EphemeralSegment = i;
6654 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
6655 pHeaps[0].Segments[i].Generation = 2;
6661 // Large object heap segments
6662 seg = WKS::generation_table[NUMBERGENERATIONS-1].start_segment;
6663 for (; seg && (i < count); ++i)
6665 pHeaps[0].Segments[i].Generation = 3;
6666 pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
6667 pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
6675 HRESULT DacDbiInterfaceImpl::CreateHeapWalk(IDacDbiInterface::HeapWalkHandle *pHandle)
6679 DacHeapWalker *data = new (nothrow) DacHeapWalker;
6681 return E_OUTOFMEMORY;
6683 HRESULT hr = data->Init();
6685 *pHandle = reinterpret_cast<HeapWalkHandle>(data);
6692 void DacDbiInterfaceImpl::DeleteHeapWalk(HeapWalkHandle handle)
6696 DacHeapWalker *data = reinterpret_cast<DacHeapWalker*>(handle);
6701 HRESULT DacDbiInterfaceImpl::WalkHeap(HeapWalkHandle handle,
6703 OUT COR_HEAPOBJECT * objects,
6707 if (fetched == NULL)
6708 return E_INVALIDARG;
6710 DacHeapWalker *walk = reinterpret_cast<DacHeapWalker*>(handle);
6713 if (!walk->HasMoreObjects())
6716 CORDB_ADDRESS freeMT = (CORDB_ADDRESS)g_pFreeObjectMethodTable.GetAddr();
6719 CORDB_ADDRESS addr, mt;
6723 while (i < count && walk->HasMoreObjects())
6725 hr = walk->Next(&addr, &mt, &size);
6732 objects[i].address = addr;
6733 objects[i].type.token1 = mt;
6734 objects[i].type.token2 = NULL;
6735 objects[i].size = size;
6741 hr = (i < count) ? S_FALSE : S_OK;
6749 HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *pSegments)
6754 size_t heapCount = 0;
6755 HeapData *heaps = 0;
6757 #ifdef FEATURE_SVR_GC
6758 HRESULT hr = GCHeapUtilities::IsServerHeap() ? DacHeapWalker::InitHeapDataSvr(heaps, heapCount) : DacHeapWalker::InitHeapDataWks(heaps, heapCount);
6760 HRESULT hr = DacHeapWalker::InitHeapDataWks(heaps, heapCount);
6763 NewArrayHolder<HeapData> _heapHolder = heaps;
6765 // Count the number of segments to know how much to allocate.
6767 for (size_t i = 0; i < heapCount; ++i)
6769 // SegmentCount is +1 due to the ephemeral segment containing more than one
6770 // generation (Gen1 + Gen0, and sometimes part of Gen2).
6771 total += (int)heaps[i].SegmentCount + 1;
6773 // It's possible that part of Gen2 lives on the ephemeral segment. If so,
6774 // we need to add one more to the output.
6775 const size_t eph = heaps[i].EphemeralSegment;
6776 _ASSERTE(eph < heaps[i].SegmentCount);
6777 if (heaps[i].Segments[eph].Start != heaps[i].Gen1Start)
6781 pSegments->Alloc(total);
6783 // Now walk all segments and write them to the array.
6785 for (size_t i = 0; i < heapCount; ++i)
6787 // Generation 0 is not in the segment list.
6788 _ASSERTE(curr < total);
6790 COR_SEGMENT &seg = (*pSegments)[curr++];
6791 seg.start = heaps[i].Gen0Start;
6792 seg.end = heaps[i].Gen0End;
6793 seg.type = CorDebug_Gen0;
6794 seg.heap = (ULONG)i;
6797 for (size_t j = 0; j < heaps[i].SegmentCount; ++j)
6799 if (heaps[i].Segments[j].Generation == 1)
6801 // This is the ephemeral segment. We have already written Gen0,
6803 _ASSERTE(heaps[i].Segments[j].Start <= heaps[i].Gen1Start);
6804 _ASSERTE(heaps[i].Segments[j].End > heaps[i].Gen1Start);
6807 _ASSERTE(curr < total);
6808 COR_SEGMENT &seg = (*pSegments)[curr++];
6809 seg.start = heaps[i].Gen1Start;
6810 seg.end = heaps[i].Gen0Start;
6811 seg.type = CorDebug_Gen1;
6812 seg.heap = (ULONG)i;
6815 // It's possible for Gen2 to take up a portion of the ephemeral segment.
6816 // We test for that here.
6817 if (heaps[i].Segments[j].Start != heaps[i].Gen1Start)
6819 _ASSERTE(curr < total);
6820 COR_SEGMENT &seg = (*pSegments)[curr++];
6821 seg.start = heaps[i].Segments[j].Start;
6822 seg.end = heaps[i].Gen1Start;
6823 seg.type = CorDebug_Gen2;
6824 seg.heap = (ULONG)i;
6829 // Otherwise, we have a gen2 or gen3 (LOH) segment
6830 _ASSERTE(curr < total);
6831 COR_SEGMENT &seg = (*pSegments)[curr++];
6832 seg.start = heaps[i].Segments[j].Start;
6833 seg.end = heaps[i].Segments[j].End;
6835 _ASSERTE(heaps[i].Segments[j].Generation <= CorDebug_LOH);
6836 seg.type = (CorDebugGenerationTypes)heaps[i].Segments[j].Generation;
6837 seg.heap = (ULONG)i;
6842 _ASSERTE(total == curr);
6846 bool DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS addr)
6850 bool isValid = false;
6853 PTR_Object obj(TO_TADDR(addr));
6855 PTR_MethodTable mt = obj->GetMethodTable();
6856 PTR_EEClass cls = mt->GetClass();
6858 if (mt == cls->GetMethodTable())
6860 else if (!mt->IsCanonicalMethodTable())
6861 isValid = cls->GetMethodTable()->GetClass() == cls;
6867 EX_END_CATCH(SwallowAllExceptions)
6872 bool DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS addr, OUT VMPTR_AppDomain * pAppDomain,
6873 OUT VMPTR_Module *pModule, OUT VMPTR_DomainFile *pDomainFile)
6877 PTR_Object obj(TO_TADDR(addr));
6878 MethodTable *mt = obj->GetMethodTable();
6880 PTR_Module module = mt->GetModule();
6881 PTR_Assembly assembly = module->GetAssembly();
6882 BaseDomain *baseDomain = assembly->GetDomain();
6884 if (baseDomain->IsSharedDomain())
6886 pModule->SetDacTargetPtr(PTR_HOST_TO_TADDR(module));
6887 *pAppDomain = VMPTR_AppDomain::NullPtr();
6888 *pDomainFile = VMPTR_DomainFile::NullPtr();
6890 else if (baseDomain->IsAppDomain())
6892 pAppDomain->SetDacTargetPtr(PTR_HOST_TO_TADDR(baseDomain->AsAppDomain()));
6893 pModule->SetDacTargetPtr(PTR_HOST_TO_TADDR(module));
6894 pDomainFile->SetDacTargetPtr(PTR_HOST_TO_TADDR(module->GetDomainFile(baseDomain->AsAppDomain())));
6904 HRESULT DacDbiInterfaceImpl::CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask)
6908 DacRefWalker *walker = new (nothrow) DacRefWalker(this, walkStacks, walkFQ, handleWalkMask);
6911 return E_OUTOFMEMORY;
6913 HRESULT hr = walker->Init();
6920 *pHandle = reinterpret_cast<RefWalkHandle>(walker);
6927 void DacDbiInterfaceImpl::DeleteRefWalk(IN RefWalkHandle handle)
6931 DacRefWalker *walker = reinterpret_cast<DacRefWalker*>(handle);
6938 HRESULT DacDbiInterfaceImpl::WalkRefs(RefWalkHandle handle, ULONG count, OUT DacGcReference * objects, OUT ULONG *pFetched)
6940 if (objects == NULL || pFetched == NULL)
6945 DacRefWalker *walker = reinterpret_cast<DacRefWalker*>(handle);
6947 return E_INVALIDARG;
6949 return walker->Next(count, objects, pFetched);
6952 HRESULT DacDbiInterfaceImpl::GetTypeID(CORDB_ADDRESS dbgObj, COR_TYPEID *pID)
6958 HRESULT hr = g_dacImpl->m_pTarget->ReadVirtual(dbgObj, (BYTE*)obj, sizeof(obj), &read);
6962 pID->token1 = (UINT64)(obj[0] & ~1);
6968 HRESULT DacDbiInterfaceImpl::GetTypeIDForType(VMPTR_TypeHandle vmTypeHandle, COR_TYPEID *pID)
6972 _ASSERTE(pID != NULL);
6973 _ASSERTE(!vmTypeHandle.IsNull());
6975 TypeHandle th = TypeHandle::FromPtr(vmTypeHandle.GetDacPtr());
6976 PTR_MethodTable pMT = th.GetMethodTable();
6977 pID->token1 = pMT.GetAddr();
6978 _ASSERTE(pID->token1 != 0);
6983 HRESULT DacDbiInterfaceImpl::GetObjectFields(COR_TYPEID id, ULONG32 celt, COR_FIELD *layout, ULONG32 *pceltFetched)
6985 if (layout == NULL || pceltFetched == NULL)
6989 return CORDBG_E_CLASS_NOT_LOADED;
6995 TypeHandle typeHandle = TypeHandle::FromPtr(TO_TADDR(id.token1));
6997 if (typeHandle.IsTypeDesc())
6998 return E_INVALIDARG;
7000 ApproxFieldDescIterator fieldDescIterator(typeHandle.AsMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7002 ULONG32 cFields = fieldDescIterator.Count();
7004 // Handle case where user only wanted to know the number of fields.
7007 *pceltFetched = cFields;
7015 // we are returning less than the total
7019 // This must be non-null due to check at beginning of function.
7020 *pceltFetched = celt;
7022 CorElementType componentType = typeHandle.AsMethodTable()->GetInternalCorElementType();
7023 BOOL fReferenceType = CorTypeInfo::IsObjRef_NoThrow(componentType);
7024 for (ULONG32 i = 0; i < cFields; ++i)
7026 FieldDesc *pField = fieldDescIterator.Next();
7027 layout[i].token = pField->GetMemberDef();
7028 layout[i].offset = (ULONG32)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7030 TypeHandle fieldHandle = pField->LookupFieldTypeHandle();
7032 if (fieldHandle.IsNull())
7034 layout[i].id.token1 = 0;
7035 layout[i].id.token2 = 0;
7036 layout[i].fieldType = (CorElementType)0;
7040 PTR_MethodTable mt = fieldHandle.GetMethodTable();
7041 layout[i].fieldType = mt->GetInternalCorElementType();
7042 layout[i].id.token1 = (ULONG64)mt.GetAddr();
7046 layout[i].id.token2 = 0;
7050 TypeHandle hnd = mt->GetApproxArrayElementTypeHandle();
7051 PTR_MethodTable cmt = hnd.GetMethodTable();
7052 layout[i].id.token2 = (ULONG64)cmt.GetAddr();
7061 HRESULT DacDbiInterfaceImpl::GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout)
7063 if (pLayout == NULL)
7067 return CORDBG_E_CLASS_NOT_LOADED;
7071 PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
7072 PTR_MethodTable parentMT = mt->GetParentMethodTable();
7074 COR_TYPEID parent = {parentMT.GetAddr(), 0};
7075 pLayout->parentID = parent;
7077 DWORD size = mt->GetBaseSize();
7078 ApproxFieldDescIterator fieldDescIterator(mt, ApproxFieldDescIterator::INSTANCE_FIELDS);
7080 pLayout->objectSize = size;
7081 pLayout->numFields = fieldDescIterator.Count();
7084 CorElementType componentType = mt->IsString() ? ELEMENT_TYPE_STRING : mt->GetInternalCorElementType();
7085 pLayout->type = componentType;
7086 pLayout->boxOffset = CorTypeInfo::IsObjRef_NoThrow(componentType) ? 0 : sizeof(TADDR);
7091 HRESULT DacDbiInterfaceImpl::GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout)
7093 if (pLayout == NULL)
7097 return CORDBG_E_CLASS_NOT_LOADED;
7101 PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
7103 if (!mt->IsStringOrArray())
7104 return E_INVALIDARG;
7109 token.token1 = MscorlibBinder::GetElementType(ELEMENT_TYPE_CHAR).GetAddr();
7112 pLayout->componentID = token;
7114 pLayout->rankSize = 4;
7115 pLayout->numRanks = 1;
7116 pLayout->rankOffset = sizeof(TADDR);
7117 pLayout->firstElementOffset = sizeof(TADDR) + 4;
7118 pLayout->countOffset = sizeof(TADDR);
7119 pLayout->componentType = ELEMENT_TYPE_CHAR;
7120 pLayout->elementSize = 2;
7124 DWORD ranks = mt->GetRank();
7125 pLayout->rankSize = 4;
7126 pLayout->numRanks = ranks;
7127 bool multiDim = (ranks > 1);
7129 pLayout->rankOffset = multiDim ? sizeof(TADDR)*2 : sizeof(TADDR);
7130 pLayout->countOffset = sizeof(TADDR);
7131 pLayout->firstElementOffset = ArrayBase::GetDataPtrOffset(mt);
7134 TypeHandle hnd = mt->GetApproxArrayElementTypeHandle();
7135 PTR_MethodTable cmt = hnd.GetMethodTable();
7137 CorElementType componentType = cmt->GetInternalCorElementType();
7138 if ((UINT64)cmt.GetAddr() == (UINT64)g_pStringClass.GetAddr())
7139 componentType = ELEMENT_TYPE_STRING;
7142 token.token1 = cmt.GetAddr(); // This could be type handle
7144 pLayout->componentID = token;
7145 pLayout->componentType = componentType;
7147 if (CorTypeInfo::IsObjRef_NoThrow(componentType))
7148 pLayout->elementSize = sizeof(TADDR);
7149 else if (CorIsPrimitiveType(componentType))
7150 pLayout->elementSize = gElementTypeInfo[componentType].m_cbSize;
7152 pLayout->elementSize = cmt->GetNumInstanceFieldBytes();
7159 void DacDbiInterfaceImpl::GetGCHeapInformation(COR_HEAPINFO * pHeapInfo)
7163 size_t heapCount = 0;
7164 pHeapInfo->areGCStructuresValid = GCScan::GetGcRuntimeStructuresValid();
7166 #ifdef FEATURE_SVR_GC
7167 if (GCHeapUtilities::IsServerHeap())
7169 pHeapInfo->gcType = CorDebugServerGC;
7170 pHeapInfo->numHeaps = DacGetNumHeaps();
7175 pHeapInfo->gcType = CorDebugWorkstationGC;
7176 pHeapInfo->numHeaps = 1;
7179 pHeapInfo->pointerSize = sizeof(TADDR);
7180 pHeapInfo->concurrent = g_pConfig->GetGCconcurrent() ? TRUE : FALSE;
7184 HRESULT DacDbiInterfaceImpl::GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW)
7187 if (pAddrMDInternalRW == NULL)
7188 return E_INVALIDARG;
7189 PEFile * pPEFile = vmPEFile.GetDacPtr();
7190 *pAddrMDInternalRW = pPEFile->GetMDInternalRWAddress();
7194 HRESULT DacDbiInterfaceImpl::GetReJitInfo(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ReJitInfo* pvmReJitInfo)
7197 if (pvmReJitInfo == NULL)
7198 return E_INVALIDARG;
7199 #ifdef FEATURE_REJIT
7200 PTR_Module pModule = vmModule.GetDacPtr();
7201 ReJitManager * pReJitMgr = pModule->GetReJitManager();
7202 PTR_ReJitInfo pReJitInfoCurrent = pReJitMgr->FindNonRevertedReJitInfo(pModule, methodTk);
7203 // if the token lookup failed, we need to search again by method desc
7204 // The rejit manager will index by token if the method isn't loaded when RequestReJIT runs
7205 // and by methoddesc if it was loaded
7206 if (pReJitInfoCurrent == NULL)
7208 MethodDesc* pMD = pModule->LookupMethodDef(methodTk);
7211 pReJitInfoCurrent = pReJitMgr->FindNonRevertedReJitInfo(dac_cast<PTR_MethodDesc>(pMD));
7214 pvmReJitInfo->SetDacTargetPtr(PTR_TO_TADDR(pReJitInfoCurrent));
7216 pvmReJitInfo->SetDacTargetPtr(0);
7221 HRESULT DacDbiInterfaceImpl::GetReJitInfo(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeStartAddress, OUT VMPTR_ReJitInfo* pvmReJitInfo)
7224 if (pvmReJitInfo == NULL)
7225 return E_INVALIDARG;
7226 #ifdef FEATURE_REJIT
7227 PTR_MethodDesc pMD = vmMethod.GetDacPtr();
7228 ReJitManager * pReJitMgr = pMD->GetReJitManager();
7229 PTR_ReJitInfo pReJitInfoCurrent = pReJitMgr->FindReJitInfo(pMD, (PCODE)codeStartAddress, 0);
7230 pvmReJitInfo->SetDacTargetPtr(PTR_TO_TADDR(pReJitInfoCurrent));
7232 pvmReJitInfo->SetDacTargetPtr(0);
7237 HRESULT DacDbiInterfaceImpl::GetSharedReJitInfo(VMPTR_ReJitInfo vmReJitInfo, OUT VMPTR_SharedReJitInfo* pvmSharedReJitInfo)
7240 if (pvmSharedReJitInfo == NULL)
7241 return E_INVALIDARG;
7242 #ifdef FEATURE_REJIT
7243 ReJitInfo* pReJitInfo = vmReJitInfo.GetDacPtr();
7244 pvmSharedReJitInfo->SetDacTargetPtr(PTR_TO_TADDR(pReJitInfo->m_pShared));
7246 _ASSERTE(!"You shouldn't be calling this - how did you get a ReJitInfo?");
7247 pvmSharedReJitInfo->SetDacTargetPtr(0);
7252 HRESULT DacDbiInterfaceImpl::GetSharedReJitInfoData(VMPTR_SharedReJitInfo vmSharedReJitInfo, DacSharedReJitInfo* pData)
7255 #ifdef FEATURE_REJIT
7256 SharedReJitInfo* pSharedReJitInfo = vmSharedReJitInfo.GetDacPtr();
7257 pData->m_state = pSharedReJitInfo->GetState();
7258 pData->m_pbIL = PTR_TO_CORDB_ADDRESS(pSharedReJitInfo->m_pbIL);
7259 pData->m_dwCodegenFlags = pSharedReJitInfo->m_dwCodegenFlags;
7260 pData->m_cInstrumentedMapEntries = (ULONG)pSharedReJitInfo->m_instrumentedILMap.GetCount();
7261 pData->m_rgInstrumentedMapEntries = PTR_TO_CORDB_ADDRESS(dac_cast<ULONG_PTR>(pSharedReJitInfo->m_instrumentedILMap.GetOffsets()));
7263 _ASSERTE(!"You shouldn't be calling this - how did you get a SharedReJitInfo?");
7268 HRESULT DacDbiInterfaceImpl::GetDefinesBitField(ULONG32 *pDefines)
7271 if (pDefines == NULL)
7272 return E_INVALIDARG;
7273 *pDefines = g_pDebugger->m_defines;
7277 HRESULT DacDbiInterfaceImpl::GetMDStructuresVersion(ULONG32* pMDStructuresVersion)
7280 if (pMDStructuresVersion == NULL)
7281 return E_INVALIDARG;
7282 *pMDStructuresVersion = g_pDebugger->m_mdDataStructureVersion;
7287 DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, BOOL walkFQ, UINT32 handleMask)
7288 : mDac(dac), mWalkStacks(walkStacks), mWalkFQ(walkFQ), mHandleMask(handleMask), mStackWalker(NULL),
7289 mHandleWalker(NULL), mFQStart(PTR_NULL), mFQEnd(PTR_NULL), mFQCurr(PTR_NULL)
7293 DacRefWalker::~DacRefWalker()
7298 HRESULT DacRefWalker::Init()
7303 // Will throw on OOM, which is fine.
7304 mHandleWalker = new DacHandleWalker();
7306 hr = mHandleWalker->Init(GetHandleWalkerMask());
7309 if (mWalkStacks && SUCCEEDED(hr))
7317 void DacRefWalker::Clear()
7321 delete mHandleWalker;
7322 mHandleWalker = NULL;
7327 delete mStackWalker;
7328 mStackWalker = NULL;
7334 UINT32 DacRefWalker::GetHandleWalkerMask()
7337 if (mHandleMask & CorHandleStrong)
7338 result |= (1 << HNDTYPE_STRONG);
7340 if (mHandleMask & CorHandleStrongPinning)
7341 result |= (1 << HNDTYPE_PINNED);
7343 if (mHandleMask & CorHandleWeakShort)
7344 result |= (1 << HNDTYPE_WEAK_SHORT);
7346 if (mHandleMask & CorHandleWeakLong)
7347 result |= (1 << HNDTYPE_WEAK_LONG);
7349 #ifdef FEATURE_COMINTEROP
7350 if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount))
7351 result |= (1 << HNDTYPE_REFCOUNTED);
7353 if (mHandleMask & CorHandleWeakWinRT)
7354 result |= (1 << HNDTYPE_WEAK_WINRT);
7355 #endif // FEATURE_COMINTEROP
7357 if (mHandleMask & CorHandleStrongDependent)
7358 result |= (1 << HNDTYPE_DEPENDENT);
7360 if (mHandleMask & CorHandleStrongAsyncPinned)
7361 result |= (1 << HNDTYPE_ASYNCPINNED);
7363 if (mHandleMask & CorHandleStrongSizedByref)
7364 result |= (1 << HNDTYPE_SIZEDREF);
7371 HRESULT DacRefWalker::Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched)
7373 if (roots == NULL || pceltFetched == NULL)
7381 hr = mHandleWalker->Next(celt, roots, &total);
7383 if (hr == S_FALSE || FAILED(hr))
7385 delete mHandleWalker;
7386 mHandleWalker = NULL;
7395 while (total < celt && mFQCurr < mFQEnd)
7397 DacGcReference &ref = roots[total++];
7399 ref.vmDomain = VMPTR_AppDomain::NullPtr();
7400 ref.objHnd.SetDacTargetPtr(mFQCurr.GetAddr());
7401 ref.dwType = (DWORD)CorReferenceFinalizer;
7402 ref.i64ExtraData = 0;
7408 while (total < celt && mStackWalker)
7411 hr = mStackWalker->Next(celt-total, roots+total, &fetched);
7427 *pceltFetched = total;
7429 return total < celt ? S_FALSE : S_OK;
7432 HRESULT DacRefWalker::NextThread()
7434 Thread *pThread = NULL;
7437 pThread = mStackWalker->GetThread();
7438 delete mStackWalker;
7439 mStackWalker = NULL;
7442 pThread = ThreadStore::GetThreadList(pThread);
7447 mStackWalker = new DacStackReferenceWalker(mDac, pThread->GetOSThreadId());
7448 return mStackWalker->Init();
7451 HRESULT DacHandleWalker::Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched)
7455 if (roots == NULL || pceltFetched == NULL)
7458 return DoHandleWalk<DacGcReference, ULONG, DacHandleWalker::EnumCallbackDac>(celt, roots, pceltFetched);
7462 void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, uintptr_t *pExtraInfo, uintptr_t param1, uintptr_t param2)
7466 DacHandleWalkerParam *param = (DacHandleWalkerParam *)param1;
7467 HandleChunkHead *curr = param->Curr;
7469 // If we failed on a previous call (OOM) don't keep trying to allocate, it's not going to work.
7470 if (FAILED(param->Result))
7473 // We've moved past the size of the current chunk. We'll allocate a new chunk
7474 // and stuff the handles there. These are cleaned up by the destructor
7475 if (curr->Count >= (curr->Size/sizeof(DacGcReference)))
7477 if (curr->Next == NULL)
7479 HandleChunk *next = new (nothrow) HandleChunk;
7486 param->Result = E_OUTOFMEMORY;
7491 curr = param->Curr = param->Curr->Next;
7494 // Fill the current handle.
7495 DacGcReference *dataArray = (DacGcReference*)curr->pData;
7496 DacGcReference &data = dataArray[curr->Count++];
7498 data.objHnd.SetDacTargetPtr(handle.GetAddr());
7499 data.vmDomain.SetDacTargetPtr(TO_TADDR(param->AppDomain));
7501 data.i64ExtraData = 0;
7502 unsigned int refCnt = 0;
7504 switch (param->Type)
7506 case HNDTYPE_STRONG:
7507 data.dwType = (DWORD)CorHandleStrong;
7510 case HNDTYPE_PINNED:
7511 data.dwType = (DWORD)CorHandleStrongPinning;
7514 case HNDTYPE_WEAK_SHORT:
7515 data.dwType = (DWORD)CorHandleWeakShort;
7518 case HNDTYPE_WEAK_LONG:
7519 data.dwType = (DWORD)CorHandleWeakLong;
7522 #ifdef FEATURE_COMINTEROP
7523 case HNDTYPE_REFCOUNTED:
7524 data.dwType = (DWORD)(data.i64ExtraData ? CorHandleStrongRefCount : CorHandleWeakRefCount);
7525 GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &refCnt, NULL, NULL, NULL);
7526 data.i64ExtraData = refCnt;
7529 case HNDTYPE_WEAK_WINRT:
7530 data.dwType = (DWORD)CorHandleWeakWinRT;
7534 case HNDTYPE_DEPENDENT:
7535 data.dwType = (DWORD)CorHandleStrongDependent;
7536 data.i64ExtraData = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
7539 case HNDTYPE_ASYNCPINNED:
7540 data.dwType = (DWORD)CorHandleStrongAsyncPinned;
7543 case HNDTYPE_SIZEDREF:
7544 data.dwType = (DWORD)CorHandleStrongSizedByref;
7550 void DacStackReferenceWalker::GCEnumCallbackDac(LPVOID hCallback, OBJECTREF *pObject, uint32_t flags, DacSlotLocation loc)
7552 GCCONTEXT *gcctx = (GCCONTEXT *)hCallback;
7553 DacScanContext *dsc = (DacScanContext*)gcctx->sc;
7555 CORDB_ADDRESS obj = 0;
7557 if (flags & GC_CALL_INTERIOR)
7560 obj = (CORDB_ADDRESS)(*PTR_PTR_Object((TADDR)pObject)).GetAddr();
7562 obj = (CORDB_ADDRESS)TO_TADDR(pObject);
7564 HRESULT hr = dsc->pWalker->mHeap.ListNearObjects(obj, NULL, &obj, NULL);
7566 // If we failed don't add this instance to the list. ICorDebug doesn't handle invalid pointers
7567 // very well, and the only way the heap walker's ListNearObjects will fail is if we have heap
7568 // corruption...which ICorDebug doesn't deal with anyway.
7573 DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
7576 data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
7578 data->pObject = obj | 1;
7579 else if (loc.targetPtr)
7580 data->objHnd.SetDacTargetPtr(TO_TADDR(pObject));
7582 data->pObject = pObject->GetAddr() | 1;
7584 data->dwType = CorReferenceStack;
7585 data->i64ExtraData = 0;
7590 void DacStackReferenceWalker::GCReportCallbackDac(PTR_PTR_Object ppObj, ScanContext *sc, uint32_t flags)
7592 DacScanContext *dsc = (DacScanContext*)sc;
7594 TADDR obj = ppObj.GetAddr();
7595 if (flags & GC_CALL_INTERIOR)
7597 CORDB_ADDRESS fixed_addr = 0;
7598 HRESULT hr = dsc->pWalker->mHeap.ListNearObjects((CORDB_ADDRESS)obj, NULL, &fixed_addr, NULL);
7600 // If we failed don't add this instance to the list. ICorDebug doesn't handle invalid pointers
7601 // very well, and the only way the heap walker's ListNearObjects will fail is if we have heap
7602 // corruption...which ICorDebug doesn't deal with anyway.
7606 obj = TO_TADDR(fixed_addr);
7609 DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
7612 data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
7613 data->objHnd.SetDacTargetPtr(obj);
7614 data->dwType = CorReferenceStack;
7615 data->i64ExtraData = 0;
7621 HRESULT DacStackReferenceWalker::Next(ULONG count, DacGcReference stackRefs[], ULONG *pFetched)
7623 if (stackRefs == NULL || pFetched == NULL)
7626 HRESULT hr = DoStackWalk<ULONG, DacGcReference,
7627 DacStackReferenceWalker::GCReportCallbackDac,
7628 DacStackReferenceWalker::GCEnumCallbackDac>
7629 (count, stackRefs, pFetched);