Add LoaderAllocator as a dac/sos concept (#82437)
authorLee Culver <leculver@microsoft.com>
Tue, 21 Feb 2023 21:44:01 +0000 (13:44 -0800)
committerGitHub <noreply@github.com>
Tue, 21 Feb 2023 21:44:01 +0000 (13:44 -0800)
* Add LoaderAllocator as a dac/sos concept

- DacpModuleData: Repurposed two unused fields to produce the module's LoaderAllocator and ThunkHeap.  The LoaderAllocator often will be the same as the SystemDomain's, except in the case of collectable assemblies.
- Added the way to get the direct LoaderAllocator address from an AppDomain.
- Added a new way to enumerate the heaps associated with a LoaderAllocator in a future-proof way.  Now when the implementation of CLR changes to add, remove, or rename/repurpose an existing heap, we can still produce the right diagnostic data without needing to ship a new interface.

This does expose LoaderAllocators as a new concept to the dac, but the original design of hiding them actually causes a lot more problems than it solves.

For example, the SystemDomain and AppDomain share the same LoaderAllocator and associated heaps...but that implementation detail is opaque to something like ClrMD or SOS (and was different on desktop CLR, so it's tough to take a dependency on that detail).  This means things like !eeheap would dutifully double report heap ranges and sizes.

We also now need to know AppDomain's LoaderAllocator address to compare to DacpModuleData's to see if we should enumerate that module's heaps or not.

* Assign kinds, don't use _countof

- Add missing assignment to pKinds.
- Don't use _countof because non MSVC compilers don't like it

* Make LoaderHeapCount's usage more obvious

* Use ARRAY_SIZE()

src/coreclr/debug/daccess/dacimpl.h
src/coreclr/debug/daccess/request.cpp
src/coreclr/inc/dacprivate.h
src/coreclr/inc/sospriv.idl
src/coreclr/pal/prebuilt/inc/sospriv.h

index 01a475d..aa1f9ba 100644 (file)
@@ -1206,7 +1206,11 @@ public:
         CLRDATA_ADDRESS *allocPtr,
         CLRDATA_ADDRESS *allocLimit);
 
-    virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
+    // ISOSDacInterface13
+    virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);        
+    virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
+    virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
+    virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
 
     //
     // ClrDataAccess.
index 9feab06..1c14be2 100644 (file)
@@ -1625,6 +1625,8 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module
     ModuleData->dwModuleID = pModule->GetModuleID();
     ModuleData->dwModuleIndex = pModule->GetModuleIndex().m_dwIndex;
     ModuleData->dwTransientFlags = pModule->m_dwTransientFlags;
+    ModuleData->LoaderAllocator = HOST_CDADDR(pModule->m_loaderAllocator);
+    ModuleData->ThunkHeap = HOST_CDADDR(pModule->m_pThunkHeap);
 
     EX_TRY
     {
@@ -3551,6 +3553,121 @@ ClrDataAccess::TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType
     return hr;
 }
 
+HRESULT ClrDataAccess::GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator)
+{
+    if (pLoaderAllocator == nullptr)
+        return E_INVALIDARG;
+
+    if (domainAddress == 0)
+    {
+        *pLoaderAllocator = 0;
+        return S_FALSE;
+    }
+
+    SOSDacEnter();
+
+    PTR_BaseDomain pDomain = PTR_BaseDomain(TO_TADDR(domainAddress));
+    *pLoaderAllocator = pDomain != nullptr ? HOST_CDADDR(pDomain->GetLoaderAllocator()) : 0;
+
+    SOSDacLeave();
+    return hr;
+}
+
+// The ordering of these entries must match the order enumerated in GetLoaderAllocatorHeaps.
+// This array isn't fixed, we can reorder/add/remove entries as long as the corresponding
+// code in GetLoaderAllocatorHeaps is updated to match.
+static const char *LoaderAllocatorLoaderHeapNames[] = 
+{
+    "LowFrequencyHeap",
+    "HighFrequencyHeap",
+    "StubHeap",
+    "ExecutableHeap",
+    "FixupPrecodeHeap",
+    "NewStubPrecodeHeap",
+    "IndcellHeap",
+    "LookupHeap",
+    "ResolveHeap",
+    "DispatchHeap",
+    "CacheEntryHeap",
+    "VtableHeap",
+};
+
+
+HRESULT ClrDataAccess::GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocatorAddress, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded)
+{
+    if (loaderAllocatorAddress == 0)
+        return E_INVALIDARG;
+
+    SOSDacEnter();
+
+    const int loaderHeapCount = ARRAY_SIZE(LoaderAllocatorLoaderHeapNames);
+    PTR_LoaderAllocator pLoaderAllocator = PTR_LoaderAllocator(TO_TADDR(loaderAllocatorAddress));
+
+    if (pNeeded)
+        *pNeeded = loaderHeapCount;
+
+    if (pLoaderHeaps)
+    {
+        if (count < loaderHeapCount)
+        {
+            hr = E_INVALIDARG;
+        }
+        else
+        {
+            // Must match order of LoaderAllocatorLoaderHeapNames
+            int i = 0;
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap());
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap());
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetStubHeap());
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap());
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetFixupPrecodeHeap());
+            pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetNewStubPrecodeHeap());
+            
+            VirtualCallStubManager *pVcsMgr = pLoaderAllocator->GetVirtualCallStubManager();
+            if (pVcsMgr == nullptr)
+            {
+                for (; i < min(count, loaderHeapCount); i++)
+                    pLoaderHeaps[i] = 0;
+            }
+            else
+            {
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->indcell_heap);
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->lookup_heap);
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->resolve_heap);
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->dispatch_heap);
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->cache_entry_heap);
+                pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->vtable_heap);
+            }
+            
+            // All of the above are "LoaderHeap" and not the ExplicitControl version.
+            for (int j = 0; j < i; j++)
+                pKinds[j] = LoaderHeapKindNormal;
+        }
+    }
+
+    SOSDacLeave();
+    return hr;
+}
+
+HRESULT
+ClrDataAccess::GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded)
+{
+    SOSDacEnter();
+    
+    const int loaderHeapCount = ARRAY_SIZE(LoaderAllocatorLoaderHeapNames);
+    if (pNeeded)
+        *pNeeded = loaderHeapCount;
+
+    if (ppNames)
+        for (int i = 0; i < min(count, loaderHeapCount); i++)
+            ppNames[i] = LoaderAllocatorLoaderHeapNames[i];
+
+    if (count < loaderHeapCount)
+        hr = S_FALSE;
+
+    SOSDacLeave();
+    return hr;
+}
 
 HRESULT
 ClrDataAccess::GetSyncBlockData(unsigned int SBNumber, struct DacpSyncBlockData *pSyncBlockData)
index 5d920fd..e8d0be5 100644 (file)
@@ -250,8 +250,8 @@ struct MSLAYOUT DacpModuleData
     CLRDATA_ADDRESS FileReferencesMap = 0;
     CLRDATA_ADDRESS ManifestModuleReferencesMap = 0;
 
-    CLRDATA_ADDRESS pLookupTableHeap = 0;
-    CLRDATA_ADDRESS pThunkHeap = 0;
+    CLRDATA_ADDRESS LoaderAllocator = 0;
+    CLRDATA_ADDRESS ThunkHeap = 0;
 
     ULONG64 dwModuleIndex = 0;
 
index afadade..b1a3b18 100644 (file)
@@ -470,4 +470,7 @@ interface ISOSDacInterface12 : IUnknown
 interface ISOSDacInterface13 : IUnknown
 {
     HRESULT TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
+    HRESULT GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
+    HRESULT GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
+    HRESULT GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
 }
index 5b81914..cc34480 100644 (file)
@@ -3093,6 +3093,21 @@ EXTERN_C const IID IID_ISOSDacInterface13;
             LoaderHeapKind kind,
             VISITHEAP pCallback) = 0;
         
+        virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator( 
+            CLRDATA_ADDRESS domainAddress,
+            CLRDATA_ADDRESS *pLoaderAllocator) = 0;
+        
+        virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames( 
+            int count,
+            const char **ppNames,
+            int *pNeeded) = 0;
+        
+        virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps( 
+            CLRDATA_ADDRESS loaderAllocator,
+            int count,
+            CLRDATA_ADDRESS *pLoaderHeaps,
+            LoaderHeapKind *pKinds,
+            int *pNeeded) = 0;
     };