From 10852ea82428ce91ca31108c802435cc8d860220 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 28 Jan 2026 15:53:10 -0800 Subject: [PATCH 1/4] Add -all flag to DumpMT command - Add -all flag to DumpMT that includes class details and method descriptors - -all implies -MD but -MD remains independently usable - Create DisplayClassDetails() helper to avoid duplication between DumpMT -all and DumpClass - Simplify Canonical MethodTable display: only show when it differs from current MT - Update PrintVC and PrintObj to use same simplified logic - Keep DumpClass as separate command for backward compatibility - Update documentation for both Windows and Unix --- src/SOS/Strike/sosdocs.txt | 6 +- src/SOS/Strike/sosdocsunix.txt | 6 +- src/SOS/Strike/strike.cpp | 185 ++++++++++++++++++++------------- src/SOS/Strike/util.cpp | 8 +- 4 files changed, 122 insertions(+), 83 deletions(-) diff --git a/src/SOS/Strike/sosdocs.txt b/src/SOS/Strike/sosdocs.txt index 7196fb6804..660dbd4dc0 100644 --- a/src/SOS/Strike/sosdocs.txt +++ b/src/SOS/Strike/sosdocs.txt @@ -1065,11 +1065,13 @@ You can use "!DumpHeap -thinlock" to list objects locked in this way. \\ COMMAND: dumpmt. -!DumpMT [-MD] +!DumpMT [-MD] [-all] Examine a MethodTable. Each managed object has a MethodTable pointer at the start. If you pass the "-MD" flag, you'll also see a list of all the methods -defined on the object. +defined on the object. If you pass the "-all" flag, you'll see class details +(attributes and fields) as well as the method list. The "-all" flag implies +"-MD". \\ COMMAND: dumpclass. diff --git a/src/SOS/Strike/sosdocsunix.txt b/src/SOS/Strike/sosdocsunix.txt index 443a134a4e..77d1906fb4 100644 --- a/src/SOS/Strike/sosdocsunix.txt +++ b/src/SOS/Strike/sosdocsunix.txt @@ -980,11 +980,13 @@ You can use "dumpheap -thinlock" to list objects locked in this way. \\ COMMAND: dumpmt. -DumpMT [-MD] +DumpMT [-MD] [-all] Examine a MethodTable. Each managed object has a MethodTable pointer at the start. If you pass the "-MD" flag, you'll also see a list of all the methods -defined on the object. +defined on the object. If you pass the "-all" flag, you'll see class details +(attributes and fields) as well as the method list. The "-all" flag implies +"-MD". \\ COMMAND: dumpclass. diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 5ea9d956d2..00554dff19 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -1017,6 +1017,59 @@ DECLARE_API(DumpSigElem) return Status; } +/**********************************************************************\ +* Routine Description: * +* * +* Helper function to display class details (attributes, vtable * +* slots, and fields). * +* * +\**********************************************************************/ +static void DisplayClassDetails(CLRDATA_ADDRESS methodTable, DacpMethodTableData *pMTData) +{ + ExtOut("Class Attributes: %x ", pMTData->dwAttrClass); + if (IsTdInterface(pMTData->dwAttrClass)) + ExtOut("Interface, "); + if (IsTdAbstract(pMTData->dwAttrClass)) + ExtOut("Abstract, "); + if (IsTdImport(pMTData->dwAttrClass)) + ExtOut("ComImport, "); + if (IsTdSealed(pMTData->dwAttrClass)) + ExtOut("Sealed, "); + ExtOut("\n"); + + if (pMTData->wNumVirtuals != 0) + { + ExtOut("Vtable Slots: %d\n", pMTData->wNumVirtuals); + } + if (pMTData->wNumVtableSlots != 0) + { + ExtOut("Total Method Slots: %d\n", pMTData->wNumVtableSlots); + } + + DacpMethodTableFieldData vMethodTableFields; + if (SUCCEEDED(vMethodTableFields.Request(g_sos, methodTable))) + { + ExtOut("NumInstanceFields: %d\n", vMethodTableFields.wNumInstanceFields); + ExtOut("NumStaticFields: %d\n", vMethodTableFields.wNumStaticFields); + + if (vMethodTableFields.wNumThreadStaticFields != 0) + { + ExtOut("NumThreadStaticFields: %d\n", vMethodTableFields.wNumThreadStaticFields); + } + + if (vMethodTableFields.wContextStaticsSize) + { + ExtOut("ContextStaticOffset: 0x%x\n", vMethodTableFields.wContextStaticOffset); + ExtOut("ContextStaticsSize: %d\n", vMethodTableFields.wContextStaticsSize); + } + + if (vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0) + { + DisplayFields(methodTable, pMTData, &vMethodTableFields, (TADDR)0, TRUE, FALSE); + } + } +} + /**********************************************************************\ * Routine Description: * * * @@ -1096,57 +1149,16 @@ DECLARE_API(DumpClass) } else { - DMLOut("Parent MethodTable: %s\n", DMLMethodTable(mtdata.ParentMethodTable)); + DMLOut("Parent: %s\n", DMLMethodTable(mtdata.ParentMethodTable)); } DMLOut("Module: %s\n", DMLModule(mtdata.Module)); DMLOut("Method Table: %s\n", DMLMethodTable(methodTable)); - if (preferMT) + if (preferMT && methodTable != mtdata.Class) { - DMLOut("Canonical MethodTable: %s\n", DMLClass(mtdata.Class)); + DMLOut("Canonical: %s\n", DMLMethodTable(mtdata.Class)); } - if (mtdata.wNumVirtuals != 0) - { - ExtOut("Vtable Slots: %x\n", mtdata.wNumVirtuals); - } - if (mtdata.wNumVtableSlots != 0) - { - ExtOut("Total Method Slots: %x\n", mtdata.wNumVtableSlots); - } - ExtOut("Class Attributes: %x ", mtdata.dwAttrClass); - if (IsTdInterface(mtdata.dwAttrClass)) - ExtOut("Interface, "); - if (IsTdAbstract(mtdata.dwAttrClass)) - ExtOut("Abstract, "); - if (IsTdImport(mtdata.dwAttrClass)) - ExtOut("ComImport, "); - - ExtOut("\n"); - - DacpMethodTableFieldData vMethodTableFields; - if (SUCCEEDED(vMethodTableFields.Request(g_sos, methodTable))) - { - ExtOut("NumInstanceFields: %x\n", vMethodTableFields.wNumInstanceFields); - ExtOut("NumStaticFields: %x\n", vMethodTableFields.wNumStaticFields); - - if (vMethodTableFields.wNumThreadStaticFields != 0) - { - ExtOut("NumThreadStaticFields: %x\n", vMethodTableFields.wNumThreadStaticFields); - } - - - if (vMethodTableFields.wContextStaticsSize) - { - ExtOut("ContextStaticOffset: %x\n", vMethodTableFields.wContextStaticOffset); - ExtOut("ContextStaticsSize: %x\n", vMethodTableFields.wContextStaticsSize); - } - - - if (vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0) - { - DisplayFields(methodTable, &mtdata, &vMethodTableFields, (TADDR)0, TRUE, FALSE); - } - } + DisplayClassDetails(methodTable, &mtdata); return Status; } @@ -1168,11 +1180,13 @@ DECLARE_API(DumpMT) MINIDUMP_NOT_SUPPORTED(); BOOL bDumpMDTable = FALSE; + BOOL bDumpAll = FALSE; BOOL dml = FALSE; CMDOption option[] = { // name, vptr, type, hasValue {"-MD", &bDumpMDTable, COBOOL, FALSE}, + {"-all", &bDumpAll, COBOOL, FALSE}, {"/d", &dml, COBOOL, FALSE} }; CMDValue arg[] = @@ -1188,6 +1202,9 @@ DECLARE_API(DumpMT) EnableDMLHolder dmlHolder(dml); TableOutput table(2, 20, AlignLeft, false); + if (bDumpAll) + bDumpMDTable = TRUE; + if (nArg == 0) { Print("Missing MethodTable address\n"); @@ -1215,13 +1232,25 @@ DECLARE_API(DumpMT) DacpMethodTableCollectibleData vMethTableCollectible; vMethTableCollectible.Request(g_sos, TO_CDADDR(dwStartAddr)); - BOOL preferCanonMT = FALSE; - if (SUCCEEDED(PreferCanonMTOverEEClass(vMethTable.Class, &preferCanonMT)) && preferCanonMT) + // Check if runtime returns canonical MT instead of EEClass (.NET 9+) + BOOL runtimePrefersCanonMT = FALSE; + CLRDATA_ADDRESS canonicalMT = 0; + Status = PreferCanonMTOverEEClass(vMethTable.Class, &runtimePrefersCanonMT, &canonicalMT); + + table.WriteRow("Parent:", DMLMethodTable(vMethTable.ParentMethodTable)); + + if (SUCCEEDED(Status) && runtimePrefersCanonMT) { - table.WriteRow("Canonical MethodTable:", EEClassPtr(vMethTable.Class)); + // .NET 9+: vMethTable.Class contains canonical MT, not EEClass + // Only show "Canonical" if it differs from the current MT + if (canonicalMT != 0 && canonicalMT != TO_CDADDR(dwStartAddr)) + { + table.WriteRow("Canonical:", DMLMethodTable(canonicalMT)); + } } else { + // Legacy: vMethTable.Class contains EEClass table.WriteRow("EEClass:", EEClassPtr(vMethTable.Class)); } @@ -1263,14 +1292,23 @@ DECLARE_API(DumpMT) } table.WriteRow("BaseSize:", PrefixHex(vMethTable.BaseSize)); - table.WriteRow("ComponentSize:", PrefixHex(vMethTable.ComponentSize)); - table.WriteRow("DynamicStatics:", vMethTable.bIsDynamic ? "true" : "false"); - table.WriteRow("ContainsPointers:", vMethTable.bContainsPointers ? "true" : "false"); + if (vMethTable.ComponentSize != 0) + table.WriteRow("ComponentSize:", PrefixHex(vMethTable.ComponentSize)); + table.WriteRow("Has GC Pointers:", vMethTable.bContainsPointers ? "true" : "false"); table.WriteRow("Number of Methods:", Decimal(vMethTable.wNumMethods)); table.SetColWidth(0, 29); table.WriteRow("Number of IFaces in IFaceMap:", Decimal(vMethTable.wNumInterfaces)); + // When -all is specified, include class details (similar to DumpClass output) + if (bDumpAll) + { + Print("--------------------------------------\n"); + Print("Additional Details\n"); + + DisplayClassDetails(TO_CDADDR(dwStartAddr), &vMethTable); + } + if (bDumpMDTable) { table.ReInit(5, POINTERSIZE_HEX, AlignRight); @@ -1381,13 +1419,24 @@ HRESULT PrintVC(TADDR taMT, TADDR taObject, BOOL bPrintFields = TRUE) ExtOut("Name: %S\n", g_mdName); DMLOut("MethodTable: %s\n", DMLMethodTable(taMT)); - BOOL preferCanonMT = FALSE; - if (SUCCEEDED(PreferCanonMTOverEEClass(TO_CDADDR(taMT), &preferCanonMT)) && preferCanonMT) + + // Check if runtime returns canonical MT instead of EEClass (.NET 9+) + BOOL runtimePrefersCanonMT = FALSE; + CLRDATA_ADDRESS canonicalMT = 0; + Status = PreferCanonMTOverEEClass(mtabledata.Class, &runtimePrefersCanonMT, &canonicalMT); + + if (SUCCEEDED(Status) && runtimePrefersCanonMT) { - DMLOut("Canonical MethodTable: %s\n", DMLClass(mtabledata.Class)); + // .NET 9+: mtabledata.Class contains canonical MT, not EEClass + // Only show "Canonical" if it differs from the current MT + if (canonicalMT != 0 && canonicalMT != TO_CDADDR(taMT)) + { + DMLOut("Canonical: %s\n", DMLMethodTable(canonicalMT)); + } } else { + // Legacy: mtabledata.Class contains EEClass DMLOut("EEClass: %s\n", DMLClass(mtabledata.Class)); } ExtOut("Size: %d(0x%x) bytes\n", size, size); @@ -1478,23 +1527,10 @@ HRESULT PrintObj(TADDR taObj, BOOL bPrintFields = TRUE) ExtOut("Name: %S\n", obj.GetTypeName()); DMLOut("MethodTable: %s\n", DMLMethodTable(objData.MethodTable)); - DacpMethodTableData mtabledata; - if ((Status=mtabledata.Request(g_sos,objData.MethodTable)) == S_OK) - { - BOOL preferCanonMT = FALSE; - if (SUCCEEDED(PreferCanonMTOverEEClass(mtabledata.Class, &preferCanonMT)) && preferCanonMT) - { - DMLOut("Canonical MethodTable: %s\n", DMLClass(mtabledata.Class)); - } - else - { - DMLOut("EEClass: %s\n", DMLClass(mtabledata.Class)); - } - } - else + if ((Status=mtabledata.Request(g_sos,objData.MethodTable)) != S_OK) { - ExtOut("Invalid EEClass address\n"); + ExtOut("Invalid MethodTable address\n"); return Status; } @@ -1557,9 +1593,12 @@ HRESULT PrintObj(TADDR taObj, BOOL bPrintFields = TRUE) CLRDATA_ADDRESS objAddr = TO_CDADDR(taObj); BOOL isTrackedType; BOOL hasTaggedMemory; - if (SUCCEEDED(sos11->IsTrackedType(objAddr, &isTrackedType, &hasTaggedMemory))) + if (SUCCEEDED(sos11->IsTrackedType(objAddr, &isTrackedType, &hasTaggedMemory)) + && (isTrackedType || hasTaggedMemory)) { - ExtOut("Tracked Type: %s\n", isTrackedType ? "true" : "false"); + if (isTrackedType) + ExtOut("Tracked Type: true\n"); + if (hasTaggedMemory) { CLRDATA_ADDRESS taggedMemory = (TADDR)0; @@ -1639,10 +1678,6 @@ HRESULT PrintObj(TADDR taObj, BOOL bPrintFields = TRUE) StringObjectContent(taObj); ExtOut("\n"); } - else if (objData.ObjectType == OBJ_OBJECT) - { - ExtOut("Object\n"); - } if (bPrintFields) { diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 69a238a291..1a0d4c7d57 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -1123,7 +1123,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT } } - ExtOut("%2s ", (IsElementValueType(vFieldDesc.Type)) ? "1" : "0"); + ExtOut("%2s ", (IsElementValueType(vFieldDesc.Type)) ? "T" : "F"); if (vFieldDesc.bIsStatic && (vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal)) { @@ -1229,7 +1229,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT } else { - ExtOut(" %8s", " "); + ExtOut(" %" POINTERSIZE "s", " "); } @@ -5524,7 +5524,7 @@ WString DmlEscape(const WString &input) const WCHAR *str = input.c_str(); size_t len = input.length(); WString result; - + for (size_t i = 0; i < len; i++) { // Ampersand must be escaped FIRST to avoid double-escaping @@ -5548,7 +5548,7 @@ WString DmlEscape(const WString &input) result += temp; } } - + return result; } From 7998b7f29fb869fc532b75bc7c107483155a2b96 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 28 Jan 2026 16:23:17 -0800 Subject: [PATCH 2/4] Fix formatting in DisplayDataMember and handle unallocated statics in GetStaticFieldPTR --- src/SOS/Strike/util.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 1a0d4c7d57..25f1105267 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -574,7 +574,7 @@ void DisplayDataMember (DacpFieldDescData* pFD, DWORD_PTR dwAddr, BOOL fAlign=TR } else { - ExtOut("%" POINTERSIZE "s", " "); + ExtOut(" %" POINTERSIZE "s", " "); } } @@ -606,10 +606,14 @@ HRESULT GetStaticFieldPTR(DWORD_PTR* pOutPtr, DacpDomainLocalModuleData* pDLMD, } } - dwTmp = (DWORD_PTR)pBaseAddress + pFDD->dwOffset; - *pOutPtr = 0; + // Statics for this type may not be allocated yet, this is okay. + // See dynamic statics for more information. + if (pBaseAddress == 0) + return S_OK; + + dwTmp = (DWORD_PTR)pBaseAddress + pFDD->dwOffset; if (pSOS14) { MethodTableInitializationFlags initFlags; From 7c265b96a9931fee9e9d307ce507e11020526761 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 29 Jan 2026 10:54:07 -0800 Subject: [PATCH 3/4] PR feedback. Update tests. --- src/SOS/Strike/strike.cpp | 27 +++++++++---------- src/SOS/Strike/util.cpp | 10 +++---- .../SOS.UnitTests/Scripts/GCTests.script | 6 ----- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 00554dff19..5f4d6364cd 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -1026,15 +1026,15 @@ DECLARE_API(DumpSigElem) \**********************************************************************/ static void DisplayClassDetails(CLRDATA_ADDRESS methodTable, DacpMethodTableData *pMTData) { - ExtOut("Class Attributes: %x ", pMTData->dwAttrClass); + ExtOut("Class Attributes: %08x ", pMTData->dwAttrClass); if (IsTdInterface(pMTData->dwAttrClass)) - ExtOut("Interface, "); + ExtOut("Interface "); if (IsTdAbstract(pMTData->dwAttrClass)) - ExtOut("Abstract, "); + ExtOut("Abstract "); if (IsTdImport(pMTData->dwAttrClass)) - ExtOut("ComImport, "); + ExtOut("ComImport "); if (IsTdSealed(pMTData->dwAttrClass)) - ExtOut("Sealed, "); + ExtOut("Sealed "); ExtOut("\n"); if (pMTData->wNumVirtuals != 0) @@ -1300,15 +1300,6 @@ DECLARE_API(DumpMT) table.SetColWidth(0, 29); table.WriteRow("Number of IFaces in IFaceMap:", Decimal(vMethTable.wNumInterfaces)); - // When -all is specified, include class details (similar to DumpClass output) - if (bDumpAll) - { - Print("--------------------------------------\n"); - Print("Additional Details\n"); - - DisplayClassDetails(TO_CDADDR(dwStartAddr), &vMethTable); - } - if (bDumpMDTable) { table.ReInit(5, POINTERSIZE_HEX, AlignRight); @@ -1401,6 +1392,14 @@ DECLARE_API(DumpMT) } } } + // When -all is specified, include class details (similar to DumpClass output) + if (bDumpAll) + { + Print("--------------------------------------\n"); + Print("Additional Details\n"); + + DisplayClassDetails(TO_CDADDR(dwStartAddr), &vMethTable); + } return Status; } diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 25f1105267..7af2ee2d61 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -574,7 +574,7 @@ void DisplayDataMember (DacpFieldDescData* pFD, DWORD_PTR dwAddr, BOOL fAlign=TR } else { - ExtOut(" %" POINTERSIZE "s", " "); + ExtOut("%" POINTERSIZE "s", " "); } } @@ -1036,7 +1036,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT if (bFirst) { ExtOutIndent(); - ExtOut("%" POINTERSIZE "s %8s %8s %20s %2s %8s %" POINTERSIZE "s %s\n", + ExtOut("%" POINTERSIZE "s %8s %8s %20s %4s %8s %" POINTERSIZE "s %s\n", "MT", "Field", "Offset", "Type", "VT", "Attr", "Value", "Name"); numInstanceFields = 0; } @@ -1098,7 +1098,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT } } - DMLOut("%s %8x %8x ", DMLMethodTable(vFieldDesc.MTOfType), + DMLOut("%s %08x %8x ", DMLMethodTable(vFieldDesc.MTOfType), TokenFromRid(vFieldDesc.mb, mdtFieldDef), offset); @@ -1127,7 +1127,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT } } - ExtOut("%2s ", (IsElementValueType(vFieldDesc.Type)) ? "T" : "F"); + ExtOut("%4s ", (IsElementValueType(vFieldDesc.Type)) ? "Yes" : "No"); if (vFieldDesc.bIsStatic && (vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal)) { @@ -1233,7 +1233,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT } else { - ExtOut(" %" POINTERSIZE "s", " "); + ExtOut("%" POINTERSIZE "s", " "); } diff --git a/src/tests/SOS.UnitTests/Scripts/GCTests.script b/src/tests/SOS.UnitTests/Scripts/GCTests.script index acd1cdefc8..974f6509a3 100644 --- a/src/tests/SOS.UnitTests/Scripts/GCTests.script +++ b/src/tests/SOS.UnitTests/Scripts/GCTests.script @@ -53,7 +53,6 @@ VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+ SOSCOMMAND:DumpObj VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ @@ -61,12 +60,10 @@ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _stati SOSCOMMAND:DumpObj -nofields VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ SOSCOMMAND:DumpObj -refs VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ @@ -133,7 +130,6 @@ VERIFY:\s+\s+\s+GCWhere\.Main\(\)\s+ SOSCOMMAND:DumpObj VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ @@ -141,12 +137,10 @@ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _stati SOSCOMMAND:DumpObj -nofields VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ SOSCOMMAND:DumpObj -refs VERIFY:\s*Name:\s+GCWhere\s+ VERIFY:\s+MethodTable:\s+\s+ -VERIFY:\s+(EEClass|Canonical MethodTable):\s+\s+ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ From 3d379072f71acec86a2c35df825844b705db6618 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 29 Jan 2026 14:23:53 -0800 Subject: [PATCH 4/4] Fix test. --- src/tests/SOS.UnitTests/Scripts/GCTests.script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/SOS.UnitTests/Scripts/GCTests.script b/src/tests/SOS.UnitTests/Scripts/GCTests.script index 974f6509a3..98261ec89a 100644 --- a/src/tests/SOS.UnitTests/Scripts/GCTests.script +++ b/src/tests/SOS.UnitTests/Scripts/GCTests.script @@ -32,7 +32,7 @@ VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+sh VERIFY:\s+>>\s+Domain:Value\s+:(|NotInit)\s+<<\s+ ENDIF:MAJOR_RUNTIME_VERSION_2 IFDEF:MAJOR_RUNTIME_VERSION_GE_3 -VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+static\s+\s+Null\s+ +VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+No\s+static\s+\s+Null\s+ ENDIF:MAJOR_RUNTIME_VERSION_GE_3 SOSCOMMAND:DumpStackObjects