Add printing of LoaderAllocator to MethodTable in SOS (#20255)
authorJan Vorlicek <janvorli@microsoft.com>
Fri, 5 Oct 2018 00:11:35 +0000 (02:11 +0200)
committerGitHub <noreply@github.com>
Fri, 5 Oct 2018 00:11:35 +0000 (02:11 +0200)
This change adds printing of LoaderAllocator to MethodTable dump in SOS
for collectible types.

src/ToolBox/SOS/Strike/gcroot.cpp
src/ToolBox/SOS/Strike/sos.cpp
src/ToolBox/SOS/Strike/sos.h
src/ToolBox/SOS/Strike/strike.cpp
src/ToolBox/SOS/Strike/util.h

index cd13719..1417748 100644 (file)
@@ -1972,6 +1972,22 @@ void HeapTraverser::PrintObjectHead(size_t objAddr,size_t typeID,size_t Size)
     }
 }
 
+void HeapTraverser::PrintLoaderAllocator(size_t memberValue)
+{
+    if (m_format == FORMAT_XML)
+    {
+        fprintf(m_file,
+            "    <loaderallocator address=\"0x%p\"/>\n",
+            (PBYTE)memberValue);
+    }
+    else if (m_format == FORMAT_CLRPROFILER)
+    {
+        fprintf(m_file,
+            " 0x%p",
+            (PBYTE)memberValue);
+    }
+}
+
 void HeapTraverser::PrintObjectMember(size_t memberValue, bool dependentHandle)
 {
     if (m_format==FORMAT_XML)
@@ -2172,43 +2188,55 @@ void HeapTraverser::PrintRefs(size_t obj, size_t methodTable, size_t size)
     MethodTableInfo* info = g_special_mtCache.Lookup((DWORD_PTR)methodTable);
     _ASSERTE(info->IsInitialized());    // This is the second pass, so we should be initialized
 
-    if (!info->bContainsPointers)
+    if (!info->bContainsPointers && !info->bCollectible)
         return;
     
-    // Fetch the GCInfo from the other process 
-    CGCDesc *map = info->GCInfo;
-    if (map == NULL)
+    if (info->bContainsPointers)
     {
-        INT_PTR nEntries;
-        move_xp (nEntries, dwAddr-sizeof(PVOID));
-        bool arrayOfVC = false;
-        if (nEntries<0)
-        {
-            arrayOfVC = true;
-            nEntries = -nEntries;
-        }
-        
-        size_t nSlots = 1+nEntries*sizeof(CGCDescSeries)/sizeof(DWORD_PTR);
-        info->GCInfoBuffer = new DWORD_PTR[nSlots];
-        if (info->GCInfoBuffer == NULL)
+        // Fetch the GCInfo from the other process 
+        CGCDesc *map = info->GCInfo;
+        if (map == NULL)
         {
-            ReportOOM();
-            return;
-        }
+            INT_PTR nEntries;
+            move_xp (nEntries, dwAddr-sizeof(PVOID));
+            bool arrayOfVC = false;
+            if (nEntries<0)
+            {
+                arrayOfVC = true;
+                nEntries = -nEntries;
+            }
 
-        if (FAILED(rvCache->Read(TO_CDADDR(dwAddr - nSlots*sizeof(DWORD_PTR)),
-                                        info->GCInfoBuffer, (ULONG) (nSlots*sizeof(DWORD_PTR)), NULL))) 
-            return;
-        
-        map = info->GCInfo = (CGCDesc*)(info->GCInfoBuffer+nSlots);
-        info->ArrayOfVC = arrayOfVC;
+            size_t nSlots = 1+nEntries*sizeof(CGCDescSeries)/sizeof(DWORD_PTR);
+            info->GCInfoBuffer = new DWORD_PTR[nSlots];
+            if (info->GCInfoBuffer == NULL)
+            {
+                ReportOOM();
+                return;
+            }
+
+            if (FAILED(rvCache->Read(TO_CDADDR(dwAddr - nSlots*sizeof(DWORD_PTR)),
+                                            info->GCInfoBuffer, (ULONG) (nSlots*sizeof(DWORD_PTR)), NULL)))
+                return;
+
+            map = info->GCInfo = (CGCDesc*)(info->GCInfoBuffer+nSlots);
+            info->ArrayOfVC = arrayOfVC;
+        }
     }
 
     mCache.EnsureRangeInCache((TADDR)obj, (unsigned int)size);
     for (sos::RefIterator itr(obj, info->GCInfo, info->ArrayOfVC, &mCache); itr; ++itr)
     {
         if (*itr && (!m_verify || sos::IsObject(*itr)))
-            PrintObjectMember(*itr, false);
+        {
+            if (itr.IsLoaderAllocator())
+            {
+                PrintLoaderAllocator(*itr);
+            }
+            else
+            {
+                PrintObjectMember(*itr, false);
+            }
+        }
     }
     
     std::unordered_map<TADDR, std::list<TADDR>>::iterator itr = mDependentHandleMap.find((TADDR)obj);
index 5ff77a9..bf84e1d 100644 (file)
@@ -562,6 +562,7 @@ namespace sos
                 // There are no object references, but there is still a reference for 
                 // collectible types - the LoaderAllocator for GC
                 mCurr = mLoaderAllocatorObjectHandle;
+                mDone = false;
             }
         }
     }
index ff5b53a..80608dd 100644 (file)
@@ -475,6 +475,11 @@ namespace sos
         {
             return (void*)!mDone;
         }
+
+        bool IsLoaderAllocator() const
+        {
+            return mLoaderAllocatorObjectHandle == mCurr;
+        }
         
     private:
         void Init();
index cd3b9f2..70e6031 100644 (file)
@@ -1338,6 +1338,9 @@ DECLARE_API(DumpMT)
         return Status;
     }
 
+    DacpMethodTableCollectibleData vMethTableCollectible;
+    vMethTableCollectible.Request(g_sos, TO_CDADDR(dwStartAddr));
+
     table.WriteRow("EEClass:", EEClassPtr(vMethTable.Class));
 
     table.WriteRow("Module:", ModulePtr(vMethTable.Module));
@@ -1350,6 +1353,15 @@ DECLARE_API(DumpMT)
     table.WriteRow("mdToken:", Pointer(vMethTable.cl));
     table.WriteRow("File:", fileName[0] ? fileName : W("Unknown Module"));
 
+    if (vMethTableCollectible.LoaderAllocatorObjectHandle != NULL)
+    {
+        TADDR loaderAllocator;
+        if (SUCCEEDED(MOVE(loaderAllocator, vMethTableCollectible.LoaderAllocatorObjectHandle)))
+        {
+            table.WriteRow("LoaderAllocator:", ObjectPtr(loaderAllocator));
+        }
+    }
+
     table.WriteRow("BaseSize:", PrefixHex(vMethTable.BaseSize));
     table.WriteRow("ComponentSize:", PrefixHex(vMethTable.ComponentSize));
     table.WriteRow("Slots in VTable:", Decimal(vMethTable.wNumMethods));
index ebad2e4..1a4cd12 100644 (file)
@@ -2831,6 +2831,7 @@ private:
 
     void PrintObjectHead(size_t objAddr,size_t typeID,size_t Size);
     void PrintObjectMember(size_t memberValue, bool dependentHandle);
+    void PrintLoaderAllocator(size_t memberValue);
     void PrintObjectTail();
 
     void PrintRootHead();