Reimplement !verifyobj and !dumpruntimetypes (#3811)
authorLee Culver <leculver@microsoft.com>
Wed, 12 Apr 2023 21:36:19 +0000 (14:36 -0700)
committerGitHub <noreply@github.com>
Wed, 12 Apr 2023 21:36:19 +0000 (14:36 -0700)
* Update ClrMD Version

* Add C# based VerifyHeap command

* Fix verifyobj command impl

* Add !sos dumpruntimetypes

* Remove dead code

* Remove object verification code

* Remove last use of RefIterator

* Remove RefIterator

* Test updates

* Update src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs

Co-authored-by: Günther Foidl <gue@korporal.at>
* Update src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs

Co-authored-by: Günther Foidl <gue@korporal.at>
* Fix managed commands

* Update soscommand.cpp

---------

Co-authored-by: Günther Foidl <gue@korporal.at>
17 files changed:
eng/Version.Details.xml
eng/Versions.props
src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs
src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs
src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs
src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs [new file with mode: 0644]
src/SOS/SOS.Hosting/Commands/SOSCommand.cs
src/SOS/SOS.UnitTests/Scripts/GCTests.script
src/SOS/Strike/eeheap.cpp
src/SOS/Strike/gcroot.cpp
src/SOS/Strike/sos.cpp
src/SOS/Strike/sos.h
src/SOS/Strike/strike.cpp
src/SOS/Strike/util.h
src/SOS/lldbplugin/soscommand.cpp

index e15c03db7e478f36201c7adda65cb9dc7ddbf1ad..6dfbbd8a911f67fd903218385674c5046a19bbbe 100644 (file)
@@ -4,13 +4,13 @@
       <Uri>https://github.com/dotnet/symstore</Uri>
       <Sha>e09f81a0b38786cb20f66b589a8b88b6997a62da</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.0-beta.23205.1">
+    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.0-beta.23210.1">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>3368bf4451a9441076595022fdff0f2bbea57b1b</Sha>
+      <Sha>677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.0-beta.23205.1">
+    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.0-beta.23210.1">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>3368bf4451a9441076595022fdff0f2bbea57b1b</Sha>
+      <Sha>677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd</Sha>
     </Dependency>
   </ProductDependencies>
   <ToolsetDependencies>
index cc637c1da6f74c43ea80165f2820c0069c6dd239..cf0b959d034c191e4fa2612b4efd729a4bc4c9c2 100644 (file)
@@ -45,7 +45,7 @@
     <SystemReflectionMetadataVersion>5.0.0</SystemReflectionMetadataVersion>
     <!-- Other libs -->
     <MicrosoftBclAsyncInterfacesVersion>6.0.0</MicrosoftBclAsyncInterfacesVersion>
-    <MicrosoftDiagnosticsRuntimeVersion>3.0.0-beta.23205.1</MicrosoftDiagnosticsRuntimeVersion>
+    <MicrosoftDiagnosticsRuntimeVersion>3.0.0-beta.23210.1</MicrosoftDiagnosticsRuntimeVersion>
     <MicrosoftDiaSymReaderNativePackageVersion>16.9.0-beta1.21055.5</MicrosoftDiaSymReaderNativePackageVersion>
     <MicrosoftDiagnosticsTracingTraceEventVersion>3.0.7</MicrosoftDiagnosticsTracingTraceEventVersion>
     <MicrosoftExtensionsLoggingVersion>6.0.0</MicrosoftExtensionsLoggingVersion>
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs
new file mode 100644 (file)
index 0000000..fb81fa1
--- /dev/null
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Text;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Runtime;
+using static Microsoft.Diagnostics.ExtensionCommands.TableOutput;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+    [Command(Name = "dumpobjgcrefs", Help = "A helper command to implement !dumpobj -refs")]
+    public sealed class DumpObjGCRefsHelper : CommandBase
+    {
+        [ServiceImport]
+        public ClrRuntime Runtime { get; set; }
+
+        [Argument(Name = "object")]
+        public string ObjectAddress { get; set; }
+
+        public override void Invoke()
+        {
+            if (!TryParseAddress(ObjectAddress, out ulong objAddress))
+            {
+                throw new ArgumentException($"Invalid object address: '{ObjectAddress}'", nameof(ObjectAddress));
+            }
+
+            ClrObject obj = Runtime.Heap.GetObject(objAddress);
+            if (!obj.IsValid)
+            {
+                Console.WriteLine($"Unable to walk object references, invalid object.");
+                return;
+            }
+
+            ClrReference[] refs = obj.EnumerateReferencesWithFields(carefully: false, considerDependantHandles: false).ToArray();
+            if (refs.Length == 0 )
+            {
+                Console.WriteLine("GC Refs: none");
+                return;
+            }
+
+            Console.WriteLine("GC Refs:");
+
+            int fieldNameLen = Math.Max(refs.Max(r => GetFieldName(r)?.Length ?? 0), 5);
+            int offsetLen = Math.Max(refs.Max(r => r.Offset.ToSignedHexString().Length), 6);
+
+            TableOutput output = new(Console, (fieldNameLen, ""), (offsetLen, ""), (16, "x12"));
+            output.WriteRow("Field", "Offset", "Object", "Type");
+            foreach (ClrReference objRef in refs)
+            {
+                output.WriteRow(GetFieldName(objRef), objRef.Offset, new DmlDumpObj(objRef.Object), objRef.Object.Type?.Name);
+            }
+        }
+
+        private static string GetFieldName(ClrReference objRef)
+        {
+            if (objRef.Field is null)
+            {
+                return null;
+            }
+
+            if (objRef.InnerField is null)
+            {
+                return objRef.Field?.Name;
+            }
+
+            StringBuilder sb = new(260);
+            bool foundOneFieldName = false;
+
+            for (ClrReference? curr = objRef; curr.HasValue; curr = curr.Value.InnerField)
+            {
+                if (sb.Length > 0)
+                {
+                    sb.Append('.');
+                }
+
+                string fieldName = curr.Value.Field?.Name;
+                if (string.IsNullOrWhiteSpace(fieldName))
+                {
+                    sb.Append("???");
+                }
+                else
+                {
+                    sb.Append(fieldName);
+                    foundOneFieldName = true;
+                }
+            }
+
+            // Make sure we don't just return "???.???.???"
+            return foundOneFieldName ? sb.ToString() : null;
+        }
+    }
+}
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs
new file mode 100644 (file)
index 0000000..a1fee8a
--- /dev/null
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Runtime;
+using static Microsoft.Diagnostics.ExtensionCommands.TableOutput;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+    [Command(Name = "dumpruntimetypes", Help = "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.")]
+    public sealed class DumpRuntimeTypeCommand : CommandBase
+    {
+        [ServiceImport]
+        public ClrRuntime Runtime { get; set; }
+
+        public override void Invoke()
+        {
+            TableOutput output = null;
+
+            foreach (ClrObject runtimeType in Runtime.Heap.EnumerateObjects())
+            {
+                Console.CancellationToken.ThrowIfCancellationRequested();
+                if (!runtimeType.IsValid || !runtimeType.IsRuntimeType)
+                {
+                    continue;
+                }
+
+                if (!runtimeType.TryReadField("m_handle", out nuint m_handle))
+                {
+                    continue;
+                }
+
+                ClrAppDomain domain = null;
+                string typeName;
+                bool isMethodTable = (m_handle & 2) == 0;
+                if (isMethodTable)
+                {
+                    // Only lookup the type if we have a MethodTable.
+                    ClrType type = Runtime.GetTypeByMethodTable(m_handle);
+                    typeName = type?.Name ?? $"methodtable: {m_handle:x}";
+                    domain = type?.Module?.AppDomain;
+                }
+                else
+                {
+                    typeName = $"typehandle: {m_handle:x} (SOS does not support resolving typehandle names.)";
+                }
+
+                if (output is null)
+                {
+                    output = new(Console, (16, "x12"), (16, "x12"), (16, "x12"));
+                    output.WriteRow("Address", "Domain", "MT", "Type Name");
+                }
+
+                output.WriteRow(new DmlDumpObj(runtimeType.Address),
+                                domain is not null ? new DmlDumpDomain(domain.Address) : null,
+                                isMethodTable ? new DmlDumpMT(m_handle) : m_handle,
+                                typeName);
+            }
+
+            if (output is null)
+            {
+                Console.WriteLine("No System.RuntimeType objects found.");
+            }
+        }
+    }
+}
index 5f35b3938193ab9ba675850e5c40202e5fca94cc..348a23eb84d5d2a86cfad993ae4940254273b8ef 100644 (file)
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using Microsoft.Diagnostics.Runtime;
@@ -32,6 +33,8 @@ namespace Microsoft.Diagnostics.ExtensionCommands
             return $"{updated:0.00}gb";
         }
 
+        public static string ToSignedHexString(this int offset) => offset < 0 ? $"-{Math.Abs(offset):x2}" : offset.ToString("x2");
+
         internal static ulong FindMostCommonPointer(this IEnumerable<ulong> enumerable)
             => (from ptr in enumerable
                 group ptr by ptr into g
index c6b91c65ad562d9b7296bd010bfc5a7af40c9df8..30373068410f5cae5e2d420f99513c5fb0e4d9b7 100644 (file)
@@ -219,6 +219,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                 long l => l.ToString(format),
                 uint ui => ui.ToString(format),
                 int i => i.ToString(format),
+                nuint uni => ((ulong)uni).ToString(format),
                 StringBuilder sb => sb.ToString(),
                 IEnumerable<byte> bytes => string.Join("", bytes.Select(b => b.ToString("x2"))),
                 string s => s,
@@ -246,6 +247,22 @@ namespace Microsoft.Diagnostics.ExtensionCommands
             }
         }
 
+        public sealed class DmlDumpMT : DmlExec
+        {
+            public DmlDumpMT(ulong address)
+                : base(address, address != 0 ? $"!dumpmt /d {address:x}" : "")
+            {
+            }
+        }
+
+        public sealed class DmlDumpDomain : DmlExec
+        {
+            public DmlDumpDomain(ulong address)
+                : base(address, address != 0 ? $"!dumpdomain /d {address:x}" : "")
+            {
+            }
+        }
+
         public sealed class DmlListNearObj : DmlExec
         {
             public DmlListNearObj(ulong address)
index f204d69124ff22e923d605270a8eed93864cc63e..e86670959869d4cc7fb48112be54e02ec4a368a3 100644 (file)
@@ -152,7 +152,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                 ObjectCorruptionKind.SyncBlockZero => GetSyncBlockFailureMessage(corruption),
 
                 // Object reference failures
-                ObjectCorruptionKind.ObjectReferenceNotPointerAligned => $"Object {obj.Address:x} has an unaligned member at {corruption.Offset:x}: is not pointer aligned",
+                ObjectCorruptionKind.ObjectReferenceNotPointerAligned => $"Object {obj.Address:x} has an unaligned member at offset {corruption.Offset:x}: is not pointer aligned",
                 ObjectCorruptionKind.InvalidObjectReference => $"Object {obj.Address:x} has a bad member at offset {corruption.Offset:x}: {ReadPointerWithError(memory, obj + (uint)corruption.Offset)}",
                 ObjectCorruptionKind.FreeObjectReference => $"Object {obj.Address:x} contains free object at offset {corruption.Offset:x}: {ReadPointerWithError(memory, obj + (uint)corruption.Offset)}",
 
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs
new file mode 100644 (file)
index 0000000..818532c
--- /dev/null
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Runtime;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+    [Command(Name = "verifyobj", Help = "Checks the given object for signs of corruption.")]
+    public sealed class VerifyObjectCommand : CommandBase
+    {
+        [ServiceImport]
+        public ClrRuntime Runtime { get; set; }
+
+        [ServiceImport]
+        public IMemoryService Memory { get; set; }
+
+        [Argument(Name = "ObjectAddress", Help = "The object to verify.")]
+        public string ObjectAddress { get; set; }
+
+        public override void Invoke()
+        {
+            if (!TryParseAddress(ObjectAddress, out ulong objAddress))
+            {
+                throw new ArgumentException($"Invalid object address: '{ObjectAddress}'", nameof(ObjectAddress));
+            }
+
+            bool isNotCorrupt = Runtime.Heap.FullyVerifyObject(objAddress, out IEnumerable<ObjectCorruption> corruptionEnum);
+            if (isNotCorrupt)
+            {
+                Console.WriteLine($"object 0x{objAddress:x} is a valid object");
+                return;
+            }
+
+            ObjectCorruption[] corruption = corruptionEnum.OrderBy(r => r.Offset).ToArray();
+            int offsetColWidth = Math.Max(6, corruption.Max(r => r.Offset.ToSignedHexString().Length));
+            int kindColWidth = Math.Max(5, corruption.Max(ce => ce.Kind.ToString().Length));
+
+            TableOutput output = new(Console, (offsetColWidth, ""), (kindColWidth, ""))
+            {
+                AlignLeft = true,
+            };
+
+            output.WriteRow("Offset", "Issue", "Description");
+            foreach (ObjectCorruption oc in corruption)
+            {
+                output.WriteRow(oc.Offset.ToSignedHexString(), oc.Kind, VerifyHeapCommand.GetObjectCorruptionMessage(Memory, Runtime.Heap, oc));
+            }
+
+            Console.WriteLine();
+            Console.WriteLine($"{corruption.Length:n0} error{(corruption.Length == 1 ? "" : "s")}  detected.");
+        }
+    }
+}
index 355ccc311639a05a9ea3b65e27e82afa78503c06..7f740a181de9c7823c8ed3686da7c89141a80856 100644 (file)
@@ -25,7 +25,6 @@ namespace SOS.Hosting
     [Command(Name = "dumpmodule",        DefaultOptions = "DumpModule",          Help = "Displays information about a EE module structure at the specified address.")]
     [Command(Name = "dumpmt",            DefaultOptions = "DumpMT",              Help = "Displays information about a method table at the specified address.")]
     [Command(Name = "dumpobj",           DefaultOptions = "DumpObj",             Aliases = new string[] { "do" }, Help = "Displays info about an object at the specified address.")]
-    [Command(Name = "dumpruntimetypes",  DefaultOptions = "DumpRuntimeTypes",    Help = "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.")]
     [Command(Name = "dumpsig",           DefaultOptions = "DumpSig",             Help = "Dumps the signature of a method or field specified by <sigaddr> <moduleaddr>.")]
     [Command(Name = "dumpsigelem",       DefaultOptions = "DumpSigElem",         Help = "Dumps a single element of a signature object.")]
     [Command(Name = "dumpstackobjects",  DefaultOptions = "DumpStackObjects",    Aliases = new string[] { "dso" }, Help = "Displays all managed objects found within the bounds of the current stack.")]
@@ -50,7 +49,6 @@ namespace SOS.Hosting
     [Command(Name = "syncblk",           DefaultOptions = "SyncBlk",             Help = "Displays the SyncBlock holder info.")]
     [Command(Name = "threadpool",        DefaultOptions = "ThreadPool",          Help = "Lists basic information about the thread pool.")]
     [Command(Name = "threadstate",       DefaultOptions = "ThreadState",         Help = "Pretty prints the meaning of a threads state.")]
-    [Command(Name = "verifyobj",         DefaultOptions = "VerifyObj",           Help = "Checks the object for signs of corruption.")]
     [Command(Name = "comstate",          DefaultOptions = "COMState",            Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")]
     [Command(Name = "dumprcw",           DefaultOptions = "DumpRCW",             Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")]
     [Command(Name = "dumpccw",           DefaultOptions = "DumpCCW",             Flags = CommandFlags.Windows, Help = "Displays information about a COM Callable Wrapper.")]
index f65630b0cfbc6f685462eef85ead503202cdb44a..96f558f78090b414b1aea6b94c4655431a2de742 100644 (file)
@@ -71,8 +71,8 @@ VERIFY:\s+Fields:\s+
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
 VERIFY:\s+GC Refs:\s+
-VERIFY:\s+offset\s+object\s+
-VERIFY:\s+<DECVAL>\s+<HEXVAL>\s+
+VERIFY:\s+Field\s+Offset\s+Object\s+Type\s+
+VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>.*
 
 SOSCOMMAND:DumpHeap
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+
@@ -141,8 +141,8 @@ VERIFY:\s+Fields:\s+
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*_string\s+
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+System\.UInt64.*52704621242434 _static\s+
 VERIFY:\s+GC Refs:\s+
-VERIFY:\s+offset\s+object\s+
-VERIFY:\s+<DECVAL>\s+<HEXVAL>\s+
+VERIFY:\s+Field\s+Offset\s+Object\s+Type\s+
+VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>.*
 
 # Continue to the next DebugBreak
 CONTINUE
index be7c39aa009cea89aa155cd394d6f740d66b457c..3b89f7023d07257ab5be692168a4d2b69a9445d2 100644 (file)
@@ -612,443 +612,6 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B
     }
 }
 
-BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify)
-{
-    DWORD_PTR dwAddrSeg = 0;
-    DWORD_PTR dwAddr = 0;
-    DWORD_PTR dwAddrCurrObj = 0;
-    DWORD_PTR dwAddrPrevObj = 0;
-    size_t s, sPrev = 0;
-
-    DacpHeapSegmentData segment;
-    if (heap.has_regions)
-    {
-        BOOL bPrevFree = FALSE;
-        for (UINT n = 0; n <= GetMaxGeneration(); n++)
-        {
-            dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
-            while (dwAddrSeg != 0)
-            {
-                if (IsInterrupt())
-                {
-                    ExtOut("<heap walk interrupted>\n");
-                    return FALSE;
-                }
-                if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
-                {
-                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
-                    return FALSE;
-                }
-                dwAddrCurrObj = (DWORD_PTR)segment.mem;
-                DWORD_PTR end_of_segment = (DWORD_PTR)segment.highAllocMark;
-
-                while (true)
-                {
-                    if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_of_segment - Align(min_obj_size))
-                        break;
-
-                    if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
-                    {
-                        if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
-                        {
-                            ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n",
-                                SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
-                            if (dwAddrPrevObj) 
-                            {
-                                ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
-                            }
-                            return FALSE;
-                        }
-                        // done with this segment
-                        break;
-                    }
-
-                    if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment
-                        && dwAddrCurrObj >= end_of_segment)
-                    {
-                        if (dwAddrCurrObj > end_of_segment)
-                        {
-                            // prev_object length is too long
-                            ExtOut("curr_object: %p > end_of_segment: %p\n",
-                                SOS_PTR(dwAddrCurrObj), SOS_PTR(end_of_segment));
-                            if (dwAddrPrevObj) 
-                            {
-                                DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
-                            }
-                            return FALSE;
-                        }
-                        return FALSE;
-                    }
-
-                    DWORD_PTR dwAddrMethTable = 0;
-                    if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
-                    {
-                        return FALSE;
-                    }
-
-                    dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
-                    if (dwAddrMethTable == 0)
-                    {
-                        // Is this the beginning of an allocation context?
-                        int i;
-                        for (i = 0; i < pallocInfo->num; i++)
-                        {
-                            if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr)
-                            {
-                                dwAddrCurrObj =
-                                    (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size);
-                                break;
-                            }
-                        }
-                        if (i < pallocInfo->num)
-                            continue;
-
-                        // We also need to look at the gen0 alloc context.
-                        if (dwAddrCurrObj == (DWORD_PTR)heap.generation_table[0].allocContextPtr)
-                        {
-                            dwAddrCurrObj = (DWORD_PTR)heap.generation_table[0].allocContextLimit + Align(min_obj_size);
-                            continue;
-                        }
-                    }
-
-                    BOOL bContainsPointers;
-                    size_t s;
-                    BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers);
-                    if (verify && bMTOk)
-                        bMTOk = VerifyObject(heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
-                    if (!bMTOk)
-                    {
-                        DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
-                        if (dwAddrPrevObj)
-                            DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
-
-                        ExtOut("----------------\n");
-                        return FALSE;
-                    }
-
-                    pFunc(dwAddrCurrObj, s, dwAddrMethTable, token);
-
-                    // We believe we did this alignment in ObjectSize above.
-                    assert((s & ALIGNCONST) == 0);
-                    dwAddrPrevObj = dwAddrCurrObj;
-                    sPrev = s;
-                    bPrevFree = IsMTForFreeObj(dwAddrMethTable);
-
-                    dwAddrCurrObj += s;
-                }
-                dwAddrSeg = (DWORD_PTR)segment.next;
-            }
-        }
-    }
-    else
-    {
-        DWORD_PTR begin_youngest;
-        DWORD_PTR end_youngest;
-
-        begin_youngest = (DWORD_PTR)heap.generation_table[0].allocation_start;
-        dwAddr = (DWORD_PTR)heap.ephemeral_heap_segment;
-
-        end_youngest = (DWORD_PTR)heap.alloc_allocated;
-
-        dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment;
-        dwAddr = dwAddrSeg;
-
-        if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-        {
-            ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-            return FALSE;
-        }
-
-        // DWORD_PTR dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].allocation_start;
-        dwAddrCurrObj = (DWORD_PTR)segment.mem;
-
-        BOOL bPrevFree = FALSE;
-
-        while (1)
-        {
-            if (IsInterrupt())
-            {
-                ExtOut("<heap walk interrupted>\n");
-                return FALSE;
-            }
-            DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated;
-            if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment)
-            {
-                end_of_segment = end_youngest;
-                if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_youngest - Align(min_obj_size))
-                    break;
-            }
-            if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
-            {
-                if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
-                {
-                    ExtOut ("curr_object: %p > heap_segment_allocated (seg: %p)\n",
-                        SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
-                    if (dwAddrPrevObj) {
-                        ExtOut ("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
-                    }
-                    return FALSE;
-                }
-                dwAddrSeg = (DWORD_PTR)segment.next;
-                if (dwAddrSeg)
-                {
-                    dwAddr = dwAddrSeg;
-                    if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-                    {
-                        ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-                        return FALSE;
-                    }
-                    dwAddrCurrObj = (DWORD_PTR)segment.mem;
-                    continue;
-                }
-                else
-                {
-                    break;  // Done Verifying Heap
-                }
-            }
-
-            if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment
-                && dwAddrCurrObj >= end_youngest)
-            {
-                if (dwAddrCurrObj > end_youngest)
-                {
-                    // prev_object length is too long
-                    ExtOut("curr_object: %p > end_youngest: %p\n",
-                        SOS_PTR(dwAddrCurrObj), SOS_PTR(end_youngest));
-                    if (dwAddrPrevObj) {
-                        DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
-                    }
-                    return FALSE;
-                }
-                return FALSE;
-            }
-
-            DWORD_PTR dwAddrMethTable = 0;
-            if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
-            {
-                return FALSE;
-            }
-
-            dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
-            if (dwAddrMethTable == 0)
-            {
-                // Is this the beginning of an allocation context?
-                int i;
-                for (i = 0; i < pallocInfo->num; i ++)
-                {
-                    if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr)
-                    {
-                        dwAddrCurrObj =
-                            (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size);
-                        break;
-                    }
-                }
-                if (i < pallocInfo->num)
-                    continue;
-
-                // We also need to look at the gen0 alloc context.
-                if (dwAddrCurrObj == (DWORD_PTR) heap.generation_table[0].allocContextPtr)
-                {
-                    dwAddrCurrObj = (DWORD_PTR) heap.generation_table[0].allocContextLimit + Align(min_obj_size);
-                    continue;
-                }
-            }
-
-            BOOL bContainsPointers;
-            BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers);
-            if (verify && bMTOk)
-                bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
-            if (!bMTOk)
-            {
-                DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
-                if (dwAddrPrevObj)
-                    DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
-
-                ExtOut ("----------------\n");
-                return FALSE;
-            }
-
-            pFunc (dwAddrCurrObj, s, dwAddrMethTable, token);
-
-            // We believe we did this alignment in ObjectSize above.
-            assert((s & ALIGNCONST) == 0);
-            dwAddrPrevObj = dwAddrCurrObj;
-            sPrev = s;
-            bPrevFree = IsMTForFreeObj(dwAddrMethTable);
-
-            dwAddrCurrObj += s;
-        }
-    }
-
-    // Now for the large object and pinned object generations:
-
-    BOOL bPinnedDone = FALSE;
-
-    dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()+1].start_segment;
-    dwAddr = dwAddrSeg;
-
-    if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-    {
-        ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-        return FALSE;
-    }
-
-    // dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()+1].allocation_start;
-    dwAddrCurrObj = (DWORD_PTR)segment.mem;
-
-    dwAddrPrevObj=0;
-
-    while(1)
-    {
-        if (IsInterrupt())
-        {
-            ExtOut("<heap traverse interrupted>\n");
-            return FALSE;
-        }
-
-        DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated;
-
-        if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
-        {
-            if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
-            {
-                ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n",
-                            SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
-                if (dwAddrPrevObj) {
-                    ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
-                }
-                return FALSE;
-            }
-
-            dwAddrSeg = (DWORD_PTR)segment.next;
-            if (dwAddrSeg)
-            {
-                dwAddr = dwAddrSeg;
-                if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-                {
-                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-                    return FALSE;
-                }
-                dwAddrCurrObj = (DWORD_PTR)segment.mem;
-                continue;
-            }
-            else if (heap.has_poh && !bPinnedDone)
-            {
-                bPinnedDone = TRUE;
-                dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration() + 2].start_segment;
-                dwAddr = dwAddrSeg;
-
-                if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-                {
-                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-                    return FALSE;
-                }
-
-                dwAddrCurrObj = (DWORD_PTR)segment.mem;
-                continue;
-            }
-            else
-            {
-                break;  // Done Verifying Heap
-            }
-        }
-
-        DWORD_PTR dwAddrMethTable = 0;
-        if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
-        {
-            return FALSE;
-        }
-
-        dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
-        BOOL bContainsPointers;
-        BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, TRUE, s, bContainsPointers);
-        if (verify && bMTOk)
-            bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
-        if (!bMTOk)
-        {
-            DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
-
-            if (dwAddrPrevObj)
-                DMLOut("Last good object: %s\n", dwAddrPrevObj);
-
-            ExtOut ("----------------\n");
-            return FALSE;
-        }
-
-        pFunc (dwAddrCurrObj, s, dwAddrMethTable, token);
-
-        // We believe we did this alignment in ObjectSize above.
-        assert((s & ALIGNCONSTLARGE) == 0);
-        dwAddrPrevObj = dwAddrCurrObj;
-        dwAddrCurrObj += s;
-    }
-
-    return TRUE;
-}
-
-BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify)
-{
-    // Obtain allocation context for each managed thread.
-    AllocInfo allocInfo;
-    allocInfo.Init();
-
-    if (!IsServerBuild())
-    {
-        DacpGcHeapDetails dacHeapDetails;
-        if (dacHeapDetails.Request(g_sos) != S_OK)
-        {
-            ExtOut("Error requesting gc heap details\n");
-            return FALSE;
-        }
-
-        GCHeapDetails heapDetails(dacHeapDetails);
-        return GCHeapTraverse (heapDetails, &allocInfo, pFunc, token, verify);
-    }
-    else
-    {
-        DacpGcHeapData gcheap;
-        if (gcheap.Request(g_sos) != S_OK)
-        {
-            ExtOut("Error requesting GC Heap data\n");
-            return FALSE;
-        }
-
-        DWORD dwAllocSize;
-        DWORD dwNHeaps = gcheap.HeapCount;
-        if (!ClrSafeInt<DWORD>::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize))
-        {
-            ExtOut("Failed to get GCHeaps:  integer overflow error\n");
-            return FALSE;
-        }
-        CLRDATA_ADDRESS *heapAddrs = (CLRDATA_ADDRESS*)alloca(dwAllocSize);
-        if (g_sos->GetGCHeapList(dwNHeaps, heapAddrs, NULL) != S_OK)
-        {
-            ExtOut("Failed to get GCHeaps\n");
-            return FALSE;
-        }
-
-        DWORD n;
-        for (n = 0; n < dwNHeaps; n ++)
-        {
-            DacpGcHeapDetails dacHeapDetails;
-            if (dacHeapDetails.Request(g_sos, heapAddrs[n]) != S_OK)
-            {
-                ExtOut("Error requesting details\n");
-                return FALSE;
-            }
-
-            GCHeapDetails heapDetails(dacHeapDetails, heapAddrs[n]);
-            if (!GCHeapTraverse (heapDetails, &allocInfo, pFunc, token, verify))
-            {
-                ExtOut("Traversing a gc heap failed\n");
-                return FALSE;
-            }
-        }
-    }
-
-    return TRUE;
-}
-
 GCHeapSnapshot::GCHeapSnapshot()
 {
     m_isBuilt = FALSE;
index 34df3bc577d2791bfa48817aceb0ba43aa683ae4..8a426ca7c3d138a914897ce7799a5751bb355e35 100644 (file)
@@ -143,686 +143,3 @@ UINT FindAllPinnedAndStrong(DWORD_PTR handlearray[], UINT arraySize)
 
     return pos;
 }
-
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// Some defines for cards taken from gc code
-//
-#define card_word_width ((size_t)32)
-
-//
-// The value of card_size is determined empirically according to the average size of an object
-// In the code we also rely on the assumption that one card_table entry (DWORD) covers an entire os page
-//
-#if defined (_TARGET_WIN64_)
-#define card_size ((size_t)(2*DT_GC_PAGE_SIZE/card_word_width))
-#else
-#define card_size ((size_t)(DT_GC_PAGE_SIZE/card_word_width))
-#endif //_TARGET_WIN64_
-
-// so card_size = 128 on x86, 256 on x64
-
-inline
-size_t card_word (size_t card)
-{
-    return card / card_word_width;
-}
-
-inline
-unsigned card_bit (size_t card)
-{
-    return (unsigned)(card % card_word_width);
-}
-
-inline
-size_t card_of ( BYTE* object)
-{
-    return (size_t)(object) / card_size;
-}
-
-BOOL CardIsSet(const GCHeapDetails &heap, TADDR objAddr)
-{
-    // The card table has to be translated to look at the refcount, etc.
-    // g_card_table[card_word(card_of(g_lowest_address))].
-
-    TADDR card_table = TO_TADDR(heap.card_table);
-    card_table = card_table + card_word(card_of((BYTE *)heap.lowest_address))*sizeof(DWORD);
-
-    do
-    {
-        TADDR card_table_lowest_addr;
-        TADDR card_table_next;
-
-        if (MOVE(card_table_lowest_addr, ALIGN_DOWN(card_table, 0x1000) + sizeof(PVOID)) != S_OK)
-        {
-            ExtErr("Error getting card table lowest address\n");
-            return FALSE;
-        }
-
-        if (MOVE(card_table_next, card_table - sizeof(PVOID)) != S_OK)
-        {
-            ExtErr("Error getting next card table\n");
-            return FALSE;
-        }
-
-        size_t card = (objAddr - card_table_lowest_addr) / card_size;
-        TADDR card_addr = card_table + (card_word(card) * sizeof(DWORD));
-        DWORD value;
-        if (MOVE(value, card_addr) != S_OK)
-        {
-            ExtErr("Error reading card bits - obj %p card %08x card_addr %p card_table %p\n", objAddr, card, card_addr, card_table);
-            return FALSE;
-        }
-
-        if (value & 1<<card_bit(card))
-            return TRUE;
-
-        card_table = card_table_next;
-    }
-    while(card_table);
-
-    return FALSE;
-}
-
-BOOL NeedCard(TADDR parent, TADDR child)
-{
-    int iChildGen = g_snapshot.GetGeneration(child);
-
-    if (iChildGen == 2)
-        return FALSE;
-
-    int iParentGen = g_snapshot.GetGeneration(parent);
-
-    return (iChildGen < iParentGen);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// Some defines for mark_array taken from gc code
-//
-
-#define mark_bit_pitch 8
-#define mark_word_width 32
-#define mark_word_size (mark_word_width * mark_bit_pitch)
-#define heap_segment_flags_swept 16
-
-inline
-size_t mark_bit_bit_of(CLRDATA_ADDRESS add)
-{
-    return  (size_t)((add / mark_bit_pitch) % mark_word_width);
-}
-
-inline
-size_t mark_word_of(CLRDATA_ADDRESS add)
-{
-    return (size_t)(add / mark_word_size);
-}
-
-inline BOOL mark_array_marked(const GCHeapDetails &heap, CLRDATA_ADDRESS add)
-{
-
-    DWORD entry = 0;
-    HRESULT hr = MOVE(entry, heap.mark_array + sizeof(DWORD) * mark_word_of(add));
-
-    if (FAILED(hr))
-        ExtOut("Failed to read card table entry.\n");
-
-    return entry & (1 << mark_bit_bit_of(add));
-}
-
-BOOL background_object_marked(const GCHeapDetails &heap, CLRDATA_ADDRESS o)
-{
-    BOOL m = TRUE;
-
-    if ((o >= heap.background_saved_lowest_address) && (o < heap.background_saved_highest_address))
-        m = mark_array_marked(heap, o);
-
-    return m;
-}
-
-BOOL fgc_should_consider_object(const GCHeapDetails &heap,
-                                CLRDATA_ADDRESS o,
-                                const DacpHeapSegmentData &seg,
-                                BOOL consider_bgc_mark_p,
-                                BOOL check_current_sweep_p,
-                                BOOL check_saved_sweep_p)
-{
-    // the logic for this function must be kept in sync with the analogous function in gc.cpp
-    BOOL no_bgc_mark_p = FALSE;
-
-    if (consider_bgc_mark_p)
-    {
-        if (check_current_sweep_p && (o < heap.next_sweep_obj))
-        {
-            no_bgc_mark_p = TRUE;
-        }
-
-        if (!no_bgc_mark_p)
-        {
-            if(check_saved_sweep_p && (o >= heap.saved_sweep_ephemeral_start))
-            {
-                no_bgc_mark_p = TRUE;
-            }
-
-            if (!check_saved_sweep_p)
-            {
-                CLRDATA_ADDRESS background_allocated = seg.background_allocated;
-                if (o >= background_allocated)
-                {
-                    no_bgc_mark_p = TRUE;
-                }
-            }
-        }
-    }
-    else
-    {
-        no_bgc_mark_p = TRUE;
-    }
-
-    return no_bgc_mark_p ? TRUE : background_object_marked(heap, o);
-}
-
-enum c_gc_state
-{
-    c_gc_state_marking,
-    c_gc_state_planning,
-    c_gc_state_free
-};
-
-inline BOOL in_range_for_segment(const DacpHeapSegmentData &seg, CLRDATA_ADDRESS addr)
-{
-    return (addr >= seg.mem) && (addr < seg.reserved);
-}
-
-void should_check_bgc_mark(const GCHeapDetails &heap,
-                           const DacpHeapSegmentData &seg,
-                           BOOL* consider_bgc_mark_p,
-                           BOOL* check_current_sweep_p,
-                           BOOL* check_saved_sweep_p)
-{
-    // the logic for this function must be kept in sync with the analogous function in gc.cpp
-    *consider_bgc_mark_p = FALSE;
-    *check_current_sweep_p = FALSE;
-    *check_saved_sweep_p = FALSE;
-
-    if (heap.current_c_gc_state == c_gc_state_planning)
-    {
-        // We are doing the next_sweep_obj comparison here because we have yet to
-        // turn on the swept flag for the segment but in_range_for_segment will return
-        // FALSE if the address is the same as reserved.
-        if ((seg.flags & heap_segment_flags_swept) || (heap.next_sweep_obj == seg.reserved))
-        {
-            // this seg was already swept.
-        }
-        else
-        {
-            *consider_bgc_mark_p = TRUE;
-
-            if ((heap.saved_sweep_ephemeral_seg != -1) && (seg.segmentAddr == heap.saved_sweep_ephemeral_seg))
-            {
-                *check_saved_sweep_p = TRUE;
-            }
-
-            if (in_range_for_segment(seg, heap.next_sweep_obj))
-            {
-                *check_current_sweep_p = TRUE;
-            }
-        }
-    }
-}
-
-// TODO: FACTOR TOGETHER THE OBJECT MEMBER WALKING CODE FROM
-// TODO: VerifyObjectMember(), GetListOfRefs(), HeapTraverser::PrintRefs()
-BOOL VerifyObjectMember(const GCHeapDetails &heap, DWORD_PTR objAddr)
-{
-    BOOL ret = TRUE;
-    BOOL bCheckCard = TRUE;
-    size_t size = 0;
-    {
-        DWORD_PTR dwAddrCard = objAddr;
-        while (dwAddrCard < objAddr + size)
-        {
-            if (CardIsSet(heap, dwAddrCard))
-            {
-                bCheckCard = FALSE;
-                break;
-            }
-            dwAddrCard += card_size;
-        }
-
-        if (bCheckCard)
-        {
-            dwAddrCard = objAddr + size - 2*sizeof(PVOID);
-            if (CardIsSet(heap, dwAddrCard))
-            {
-                bCheckCard = FALSE;
-            }
-        }
-    }
-
-    for (sos::RefIterator itr(TO_TADDR(objAddr)); itr; ++itr)
-    {
-        TADDR dwAddr1 = (DWORD_PTR)*itr;
-        if (dwAddr1)
-        {
-           TADDR dwChild = dwAddr1;
-           // Try something more efficient than IsObject here. Is the methodtable valid?
-           size_t s;
-           BOOL bPointers;
-           TADDR dwAddrMethTable;
-           if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) ||
-                (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE))
-           {
-               DMLOut("object %s: bad member %p at %p\n", DMLObject(objAddr), SOS_PTR(dwAddr1), SOS_PTR(itr.GetOffset()));
-               ret = FALSE;
-           }
-
-           if (IsMTForFreeObj(dwAddrMethTable))
-           {
-               DMLOut("object %s contains free object %p at %p\n", DMLObject(objAddr),
-                      SOS_PTR(dwAddr1), SOS_PTR(objAddr+itr.GetOffset()));
-              ret = FALSE;
-           }
-
-           // verify card table
-           if (bCheckCard && NeedCard(objAddr+itr.GetOffset(), dwAddr1))
-           {
-               DMLOut("object %s:%s missing card_table entry for %p\n",
-                      DMLObject(objAddr), (dwChild == dwAddr1) ? "" : " maybe",
-                      SOS_PTR(objAddr+itr.GetOffset()));
-               ret = FALSE;
-           }
-        }
-    }
-
-    return ret;
-}
-
-// search for can_verify_deep in gc.cpp for examples of how these functions are used.
-BOOL VerifyObject(const GCHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize,
-    BOOL bVerifyMember)
-{
-    if (IsMTForFreeObj(MTAddr))
-    {
-        return TRUE;
-    }
-
-    if (objSize < min_obj_size)
-    {
-        DMLOut("object %s: size %d too small\n", DMLObject(objAddr), objSize);
-        return FALSE;
-    }
-
-    // If we requested to verify the object's members, the GC may be in a state where that's not possible.
-    // Here we check to see if the object in question needs to have its members updated.  If so, we turn off
-    // verification for the object.
-    if (bVerifyMember)
-    {
-        BOOL consider_bgc_mark = FALSE, check_current_sweep = FALSE, check_saved_sweep = FALSE;
-        should_check_bgc_mark(heap, seg, &consider_bgc_mark, &check_current_sweep, &check_saved_sweep);
-        bVerifyMember = fgc_should_consider_object(heap, objAddr, seg, consider_bgc_mark, check_current_sweep, check_saved_sweep);
-    }
-
-    return bVerifyMember ? VerifyObjectMember(heap, objAddr) : TRUE;
-}
-
-
-BOOL FindSegment(const GCHeapDetails &heap, DacpHeapSegmentData &seg, CLRDATA_ADDRESS addr)
-{
-    if (heap.has_regions)
-    {
-        CLRDATA_ADDRESS dwAddrSeg;
-        for (UINT n = 0; n <= GetMaxGeneration(); n++)
-        {
-            dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
-            while (dwAddrSeg != 0)
-            {
-                if (IsInterrupt())
-                    return FALSE;
-                if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
-                {
-                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
-                    return FALSE;
-                }
-                if (addr >= TO_TADDR(seg.mem) && addr < seg.highAllocMark)
-                {
-                    return TRUE;
-                }
-                dwAddrSeg = (DWORD_PTR)seg.next;
-            }
-        }
-        return FALSE;
-    }
-    else
-    {
-        CLRDATA_ADDRESS dwAddrSeg = heap.generation_table[GetMaxGeneration()].start_segment;
-
-        // Request the initial segment.
-        if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
-        {
-            ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg));
-            return FALSE;
-        }
-
-        // Loop while the object is not in range of the segment.
-        while (addr < TO_TADDR(seg.mem) ||
-            addr >= (dwAddrSeg == heap.ephemeral_heap_segment ? heap.alloc_allocated : TO_TADDR(seg.allocated)))
-        {
-            // get the next segment
-            dwAddrSeg = seg.next;
-
-            // We reached the last segment without finding the object.
-            if (dwAddrSeg == NULL)
-                return FALSE;
-
-            if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
-            {
-                ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg));
-                return FALSE;
-            }
-        }
-    }
-
-    return TRUE;
-}
-
-BOOL VerifyObject(const GCHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, BOOL bVerifyMember)
-{
-    // This is only used by the other VerifyObject function if bVerifyMember is true,
-    // so we only initialize it if we need it for verifying object members.
-    DacpHeapSegmentData seg;
-
-    if (bVerifyMember)
-    {
-        // if we fail to find the segment, we cannot verify the object's members
-        bVerifyMember = FindSegment(heap, seg, objAddr);
-    }
-
-    return VerifyObject(heap, seg, objAddr, MTAddr, objSize, bVerifyMember);
-}
-
-void sos::ObjectIterator::BuildError(char *out, size_t count, const char *format, ...) const
-{
-    if (out == NULL || count == 0)
-        return;
-
-    va_list args;
-    va_start(args, format);
-
-    int written = vsprintf_s(out, count, format, args);
-    if (written > 0 && mLastObj)
-        sprintf_s(out+written, count-written, "\nLast good object: %p.\n", (int*)mLastObj);
-
-    va_end(args);
-}
-
-bool sos::ObjectIterator::VerifyObjectMembers(char *reason, size_t count) const
-{
-    if (!mCurrObj.HasPointers())
-        return true;
-
-    size_t size = mCurrObj.GetSize();
-    size_t objAddr = (size_t)mCurrObj.GetAddress();
-    TADDR mt = mCurrObj.GetMT();
-
-    INT_PTR nEntries;
-    MOVE(nEntries, mt-sizeof(PVOID));
-    if (nEntries < 0)
-        nEntries = -nEntries;
-
-    size_t nSlots = 1 + nEntries * sizeof(CGCDescSeries)/sizeof(DWORD_PTR);
-    ArrayHolder<DWORD_PTR> buffer = new DWORD_PTR[nSlots];
-
-    if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(mt - nSlots*sizeof(DWORD_PTR)),
-                                      buffer, (ULONG) (nSlots*sizeof(DWORD_PTR)), NULL)))
-    {
-        BuildError(reason, count, "Object %s has a bad GCDesc.", DMLObject(objAddr));
-        return false;
-    }
-
-    CGCDesc *map = (CGCDesc *)(buffer+nSlots);
-    CGCDescSeries* cur = map->GetHighestSeries();
-    CGCDescSeries* last = map->GetLowestSeries();
-
-    const size_t bufferSize = sizeof(size_t)*128;
-    size_t objBuffer[bufferSize/sizeof(size_t)];
-    size_t dwBeginAddr = (size_t)objAddr;
-    size_t bytesInBuffer = bufferSize;
-    if (size < bytesInBuffer)
-        bytesInBuffer = size;
-
-
-    if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer,NULL)))
-    {
-        BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr));
-        return false;
-    }
-
-    BOOL bCheckCard = TRUE;
-    {
-        DWORD_PTR dwAddrCard = (DWORD_PTR)objAddr;
-        while (dwAddrCard < objAddr + size)
-        {
-            if (CardIsSet (mHeaps[mCurrHeap], dwAddrCard))
-            {
-                bCheckCard = FALSE;
-                break;
-            }
-            dwAddrCard += card_size;
-        }
-        if (bCheckCard)
-        {
-            dwAddrCard = objAddr + size - 2*sizeof(PVOID);
-            if (CardIsSet (mHeaps[mCurrHeap], dwAddrCard))
-            {
-                bCheckCard = FALSE;
-            }
-        }
-    }
-
-    if (cur >= last)
-    {
-        do
-        {
-            BYTE** parm = (BYTE**)((objAddr) + cur->GetSeriesOffset());
-            BYTE** ppstop =
-                (BYTE**)((BYTE*)parm + cur->GetSeriesSize() + (size));
-            while (parm < ppstop)
-            {
-                CheckInterrupt();
-                size_t dwAddr1;
-
-                // Do we run out of cache?
-                if ((size_t)parm >= dwBeginAddr+bytesInBuffer)
-                {
-                    // dwBeginAddr += bytesInBuffer;
-                    dwBeginAddr = (size_t)parm;
-                    if (dwBeginAddr >= objAddr + size)
-                    {
-                        return true;
-                    }
-                    bytesInBuffer = bufferSize;
-                    if (objAddr+size-dwBeginAddr < bytesInBuffer)
-                    {
-                        bytesInBuffer = objAddr+size-dwBeginAddr;
-                    }
-                    if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer, NULL)))
-                    {
-                       BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr));
-                       return false;
-                    }
-                }
-                dwAddr1 = objBuffer[((size_t)parm-dwBeginAddr)/sizeof(size_t)];
-                if (dwAddr1) {
-                    DWORD_PTR dwChild = dwAddr1;
-                    // Try something more efficient than IsObject here. Is the methodtable valid?
-                    size_t s;
-                    BOOL bPointers;
-                    DWORD_PTR dwAddrMethTable;
-                    if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) ||
-                         (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE))
-                    {
-                        BuildError(reason, count, "object %s: bad member %p at %p", DMLObject(objAddr),
-                               SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr));
-
-                        return false;
-                    }
-
-                    if (IsMTForFreeObj(dwAddrMethTable))
-                    {
-                        sos::Throw<HeapCorruption>("object %s contains free object %p at %p", DMLObject(objAddr),
-                               SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr));
-                    }
-
-                    // verify card table
-                    if (bCheckCard &&
-                        NeedCard(objAddr+(size_t)parm-objAddr,dwChild))
-                    {
-                        BuildError(reason, count, "Object %s: %s missing card_table entry for %p",
-                                DMLObject(objAddr), (dwChild == dwAddr1)? "" : " maybe",
-                                SOS_PTR(objAddr+(size_t)parm-objAddr));
-
-                        return false;
-                    }
-                }
-                parm++;
-            }
-            cur--;
-            CheckInterrupt();
-
-        } while (cur >= last);
-    }
-    else
-    {
-        int cnt = (int) map->GetNumSeries();
-        BYTE** parm = (BYTE**)((objAddr) + cur->startoffset);
-        while ((BYTE*)parm < (BYTE*)((objAddr)+(size)-plug_skew))
-        {
-            for (int __i = 0; __i > cnt; __i--)
-            {
-                CheckInterrupt();
-
-                unsigned skip =  cur->val_serie[__i].skip;
-                unsigned nptrs = cur->val_serie[__i].nptrs;
-                BYTE** ppstop = parm + nptrs;
-                do
-                {
-                    size_t dwAddr1;
-                    // Do we run out of cache?
-                    if ((size_t)parm >= dwBeginAddr+bytesInBuffer)
-                    {
-                        // dwBeginAddr += bytesInBuffer;
-                        dwBeginAddr = (size_t)parm;
-                        if (dwBeginAddr >= objAddr + size)
-                            return true;
-
-                        bytesInBuffer = bufferSize;
-                        if (objAddr+size-dwBeginAddr < bytesInBuffer)
-                            bytesInBuffer = objAddr+size-dwBeginAddr;
-
-                        if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer, NULL)))
-                        {
-                            BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr));
-                            return false;
-                        }
-                    }
-                    dwAddr1 = objBuffer[((size_t)parm-dwBeginAddr)/sizeof(size_t)];
-                    {
-                         if (dwAddr1)
-                         {
-                             DWORD_PTR dwChild = dwAddr1;
-                             // Try something more efficient than IsObject here. Is the methodtable valid?
-                             size_t s;
-                             BOOL bPointers;
-                             DWORD_PTR dwAddrMethTable;
-                             if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) ||
-                                  (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE))
-                             {
-                                 BuildError(reason, count, "Object %s: Bad member %p at %p.\n", DMLObject(objAddr),
-                                         SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr));
-
-                                 return false;
-                             }
-
-                             if (IsMTForFreeObj(dwAddrMethTable))
-                             {
-                                 BuildError(reason, count, "Object %s contains free object %p at %p.", DMLObject(objAddr),
-                                        SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr));
-                                 return false;
-                             }
-
-                             // verify card table
-                             if (bCheckCard &&
-                                 NeedCard (objAddr+(size_t)parm-objAddr,dwAddr1))
-                             {
-                                 BuildError(reason, count, "Object %s:%s missing card_table entry for %p",
-                                        DMLObject(objAddr), (dwChild == dwAddr1) ? "" : " maybe",
-                                        SOS_PTR(objAddr+(size_t)parm-objAddr));
-
-                                 return false;
-                             }
-                         }
-                    }
-                   parm++;
-                   CheckInterrupt();
-                } while (parm < ppstop);
-                parm = (BYTE**)((BYTE*)parm + skip);
-            }
-        }
-    }
-
-    return true;
-}
-
-bool sos::ObjectIterator::Verify(char *reason, size_t count) const
-{
-    try
-    {
-        TADDR mt = mCurrObj.GetMT();
-
-        if (MethodTable::GetFreeMT() == mt)
-        {
-            return true;
-        }
-
-        size_t size = mCurrObj.GetSize();
-        if (size < min_obj_size)
-        {
-            BuildError(reason, count, "Object %s: Size %d is too small.", DMLObject(mCurrObj.GetAddress()), size);
-            return false;
-        }
-
-        if (mCurrObj.GetAddress() + mCurrObj.GetSize() > mSegmentEnd)
-        {
-            BuildError(reason, count, "Object %s is too large.  End of segment at %p.", DMLObject(mCurrObj), mSegmentEnd);
-            return false;
-        }
-
-        BOOL bVerifyMember = TRUE;
-
-        // If we requested to verify the object's members, the GC may be in a state where that's not possible.
-        // Here we check to see if the object in question needs to have its members updated.  If so, we turn off
-        // verification for the object.
-        BOOL consider_bgc_mark = FALSE, check_current_sweep = FALSE, check_saved_sweep = FALSE;
-        should_check_bgc_mark(mHeaps[mCurrHeap], mSegment, &consider_bgc_mark, &check_current_sweep, &check_saved_sweep);
-        bVerifyMember = fgc_should_consider_object(mHeaps[mCurrHeap], mCurrObj.GetAddress(), mSegment,
-                                                   consider_bgc_mark, check_current_sweep, check_saved_sweep);
-
-        if (bVerifyMember)
-            return VerifyObjectMembers(reason, count);
-    }
-    catch(const sos::Exception &e)
-    {
-        BuildError(reason, count, e.GetMesssage());
-        return false;
-    }
-
-    return true;
-}
-
-bool sos::ObjectIterator::Verify() const
-{
-    char *c = NULL;
-    return Verify(c, 0);
-}
index 33368fe60b795472d622a027ae5640aac2e568dc..d637289253d363214c25535b79fed0978840bff7 100644 (file)
@@ -376,187 +376,6 @@ namespace sos
         return (size_t)stInfo.m_StringLength;
     }
 
-
-    RefIterator::RefIterator(TADDR obj, LinearReadCache *cache)
-        : mCache(cache), mGCDesc(0), mArrayOfVC(false), mDone(false), mBuffer(0), mCurrSeries(0), mLoaderAllocatorObjectHandle(0),
-          i(0), mCount(0), mCurr(0), mStop(0), mObject(obj), mObjSize(0)
-    {
-        Init();
-    }
-
-    RefIterator::RefIterator(TADDR obj, CGCDesc *desc, bool arrayOfVC, LinearReadCache *cache)
-        : mCache(cache), mGCDesc(desc), mArrayOfVC(arrayOfVC), mDone(false), mBuffer(0), mCurrSeries(0), mLoaderAllocatorObjectHandle(0),
-          i(0), mCount(0), mCurr(0), mStop(0), mObject(obj), mObjSize(0)
-    {
-        Init();
-    }
-
-    RefIterator::~RefIterator()
-    {
-        if (mBuffer)
-            delete [] mBuffer;
-    }
-
-    const RefIterator &RefIterator::operator++()
-    {
-        if (mDone)
-            Throw<Exception>("Attempt to move past the end of the iterator.");
-
-        if (mCurr == mLoaderAllocatorObjectHandle)
-        {
-            // The mLoaderAllocatorObjectHandle is always the last reference returned
-            mDone = true;
-            return *this;
-        }
-
-        if (!mArrayOfVC)
-        {
-            mCurr += sizeof(TADDR);
-            if (mCurr >= mStop)
-            {
-                mCurrSeries--;
-                if (mCurrSeries < mGCDesc->GetLowestSeries())
-                {
-                    mDone = true;
-                }
-                else
-                {
-                    mCurr = mObject + mCurrSeries->GetSeriesOffset();
-                    mStop = mCurr + mCurrSeries->GetSeriesSize() + mObjSize;
-                }
-            }
-        }
-        else
-        {
-            mCurr += sizeof(TADDR);
-            if (mCurr >= mStop)
-            {
-                int i_last = i;
-                i--;
-
-                if (i == mCount)
-                    i = 0;
-
-                mCurr += mCurrSeries->val_serie[i_last].skip;
-                mStop = mCurr + mCurrSeries->val_serie[i].nptrs * sizeof(TADDR);
-            }
-
-            if (mCurr >= mObject + mObjSize - plug_skew)
-                mDone = true;
-        }
-
-        if (mDone && mLoaderAllocatorObjectHandle != NULL)
-        {
-            // The iteration over all regular object references is done, but there is one more
-            // reference for collectible types - the LoaderAllocator for GC
-            mCurr = mLoaderAllocatorObjectHandle;
-            mDone = false;
-        }
-
-        return *this;
-    }
-
-    TADDR RefIterator::operator*() const
-    {
-        return ReadPointer(mCurr);
-    }
-
-    TADDR RefIterator::GetOffset() const
-    {
-        return mCurr - mObject;
-    }
-
-    void RefIterator::Init()
-    {
-        TADDR mt = ReadPointer(mObject);
-        BOOL bContainsPointers = FALSE;
-        BOOL bCollectible = FALSE;
-        TADDR loaderAllocatorObjectHandle;
-
-        if (!GetSizeEfficient(mObject, mt, FALSE, mObjSize, bContainsPointers))
-            Throw<DataRead>("Failed to get size of object.");
-
-        if (!GetCollectibleDataEfficient(mt, bCollectible, loaderAllocatorObjectHandle))
-            Throw<DataRead>("Failed to get collectible info of object.");
-
-        if (!bContainsPointers && !bCollectible)
-        {
-            mDone = true;
-            return;
-        }
-
-        if (bContainsPointers)
-        {
-            if (!mGCDesc)
-            {
-                int entries = 0;
-
-                if (FAILED(MOVE(entries, mt-sizeof(TADDR))))
-                    Throw<DataRead>("Failed to request number of entries for %p MT %p", mObject, mt);
-
-                // array of vc?
-                if (entries < 0)
-                {
-                    entries = -entries;
-                    mArrayOfVC = true;
-                }
-                else
-                {
-                    mArrayOfVC = false;
-                }
-
-                size_t slots = 1 + entries * sizeof(CGCDescSeries)/sizeof(TADDR);
-
-                ArrayHolder<TADDR> buffer = new TADDR[slots];
-
-                ULONG fetched = 0;
-                CLRDATA_ADDRESS address = TO_CDADDR(mt - slots*sizeof(TADDR));
-                if (FAILED(g_ExtData->ReadVirtual(address, buffer, (ULONG)(slots*sizeof(TADDR)), &fetched)))
-                    Throw<DataRead>("Failed to request GCDesc.");
-
-                mBuffer = buffer.Detach();
-                mGCDesc = (CGCDesc*)(mBuffer + slots);
-            }
-
-            mCurrSeries = mGCDesc->GetHighestSeries();
-
-            if (!mArrayOfVC)
-            {
-                mCurr = mObject + mCurrSeries->GetSeriesOffset();
-                mStop = mCurr + mCurrSeries->GetSeriesSize() + mObjSize;
-            }
-            else
-            {
-                i = 0;
-                mCurr = mObject + mCurrSeries->startoffset;
-                mStop = mCurr + mCurrSeries->val_serie[i].nptrs * sizeof(TADDR);
-                mCount = (int)mGCDesc->GetNumSeries();
-            }
-
-            if (mCurr == mStop)
-                operator++();
-            else if (mCurr >= mObject + mObjSize - plug_skew)
-                mDone = true;
-        }
-        else
-        {
-            mDone = true;
-        }
-
-        if (bCollectible)
-        {
-            mLoaderAllocatorObjectHandle = loaderAllocatorObjectHandle;
-            if (mDone)
-            {
-                // There are no object references, but there is still a reference for
-                // collectible types - the LoaderAllocator for GC
-                mCurr = mLoaderAllocatorObjectHandle;
-                mDone = false;
-            }
-        }
-    }
-
-
     const TADDR GCHeap::HeapStart = 0;
     const TADDR GCHeap::HeapEnd = ~0;
 
index b514244d952982e190c81d78f502ec303346de5a..c0fed3a3b2f3f7858df0a9ae1498975eb5ee7c07 100644 (file)
@@ -452,77 +452,6 @@ namespace sos
         mutable WCHAR *mTypeName;
     };
 
-    /* Enumerates all the GC references (objects) contained in an object.  This uses the GCDesc
-     * map exactly as the GC does.
-     */
-    class RefIterator
-    {
-    public:
-        RefIterator(TADDR obj, LinearReadCache *cache = NULL);
-        RefIterator(TADDR obj, CGCDesc *desc, bool arrayOfVC, LinearReadCache *cache = NULL);
-        ~RefIterator();
-
-        /* Moves to the next reference in the object.
-         */
-        const RefIterator &operator++();
-
-        /* Returns the address of the current reference.
-         */
-        TADDR operator*() const;
-
-        /* Gets the offset into the object where the current reference comes from.
-         */
-        TADDR GetOffset() const;
-
-        /* Returns true if there are more objects in the iteration, false otherwise.
-         * Used as:
-         *     if (itr)
-         *        ...
-         */
-        inline operator void *() const
-        {
-            return (void*)!mDone;
-        }
-
-        bool IsLoaderAllocator() const
-        {
-            return mLoaderAllocatorObjectHandle == mCurr;
-        }
-
-    private:
-        void Init();
-        inline TADDR ReadPointer(TADDR addr) const
-        {
-            if (mCache)
-            {
-                if (!mCache->Read(addr, &addr, false))
-                    Throw<DataRead>("Could not read address %p.", addr);
-            }
-            else
-            {
-                MOVE(addr, addr);
-            }
-
-            return addr;
-        }
-
-    private:
-        LinearReadCache *mCache;
-        CGCDesc *mGCDesc;
-        bool mArrayOfVC, mDone;
-
-        TADDR *mBuffer;
-        CGCDescSeries *mCurrSeries;
-
-        TADDR mLoaderAllocatorObjectHandle;
-
-        int i, mCount;
-
-        TADDR mCurr, mStop, mObject;
-        size_t mObjSize;
-    };
-
-
     /* The Iterator used to walk the managed objects on the GC heap.
      * The general usage pattern for this class is:
      *   for (ObjectIterator itr = gcheap.WalkHeap(); itr; ++itr)
@@ -580,27 +509,6 @@ namespace sos
             return bLarge;
         }
 
-        /* Verifies the current object.  Returns true if the current object is valid.
-         * Returns false and fills 'buffer' with the reason the object is corrupted.
-         * This is a deeper validation than Object::IsValid as it checks the card
-         * table entires for the object in addition to the rest of the references.
-         * This function does not throw exceptions.
-         * Params:
-         *   buffer - out buffer that is filled if and only if this function returns
-         *            false.
-         *   size - the total size of the buffer
-         * Returns:
-         *   True if the object is valid, false otherwise.
-         */
-        bool Verify(__out_ecount(size) char *buffer, size_t size) const;
-
-        /* The same as Verify(char*, size_t), except it does not write out the failure
-         * reason to a provided buffer.
-         * See:
-         *   ObjectIterator::Verify(char *, size_t)
-         */
-        bool Verify() const;
-
         /* Attempts to move to the next object (similar to ObjectIterator++), but
          * attempts to recover from any heap corruption by skipping to the next
          * segment.  If Verify returns false, meaning it detected heap corruption
@@ -622,9 +530,6 @@ namespace sos
     private:
         ObjectIterator(const GCHeapDetails *heap, int numHeaps, TADDR start, TADDR stop);
 
-        bool VerifyObjectMembers(__out_ecount(size) char *buffer, size_t size) const;
-        void BuildError(__out_ecount(count) char *out, size_t count, const char *format, ...) const;
-
         void AssertSanity() const;
 
         /*
index 08b39a1a23df8d4940fadd7618c1ba35fb86ffe4..410a8ea409a785e5e5ee405ee1a16e311862ae97 100644 (file)
@@ -2192,11 +2192,9 @@ DECLARE_API(DumpObj)
 
         if (SUCCEEDED(Status) && bRefs)
         {
-            ExtOut("GC Refs:\n");
-            TableOutput out(2, POINTERSIZE_HEX, AlignRight, 4);
-            out.WriteRow("offset", "object");
-            for (sos::RefIterator itr(TO_TADDR(p_Object)); itr; ++itr)
-                out.WriteRow(Hex(itr.GetOffset()), ObjectPtr(*itr));
+            std::stringstream argsBuilder;
+            argsBuilder << std::hex << p_Object << " ";
+            return ExecuteCommand("dumpobjgcrefs", argsBuilder.str().c_str());
         }
     }
     catch(const sos::Exception &e)
@@ -3652,114 +3650,11 @@ DECLARE_API(TraverseHeap)
     return ExecuteCommand("traverseheap", args);
 }
 
-struct PrintRuntimeTypeArgs
-{
-    DWORD_PTR mtOfRuntimeType;
-    int handleFieldOffset;
-    DacpAppDomainStoreData adstore;
-};
-
-void PrintRuntimeTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token)
-{
-    PrintRuntimeTypeArgs *pArgs = (PrintRuntimeTypeArgs *)token;
-
-    if (pArgs->mtOfRuntimeType == NULL)
-    {
-        NameForMT_s(methodTable, g_mdName, mdNameLen);
-
-        if (_wcscmp(g_mdName, W("System.RuntimeType")) == 0)
-        {
-            pArgs->mtOfRuntimeType = methodTable;
-            pArgs->handleFieldOffset = GetObjFieldOffset(TO_CDADDR(objAddr), TO_CDADDR(methodTable), W("m_handle"));
-            if (pArgs->handleFieldOffset <= 0)
-                ExtOut("Error getting System.RuntimeType.m_handle offset\n");
-
-            pArgs->adstore.Request(g_sos);
-        }
-    }
-
-    if ((methodTable == pArgs->mtOfRuntimeType) && (pArgs->handleFieldOffset > 0))
-    {
-        // Get the method table and display the information.
-        DWORD_PTR mtPtr;
-        if (MOVE(mtPtr, objAddr + pArgs->handleFieldOffset) == S_OK)
-        {
-            DMLOut(DMLObject(objAddr));
-
-            // Check if TypeDesc
-            if ((mtPtr & RUNTIMETYPE_HANDLE_IS_TYPEDESC) != 0)
-            {
-                ExtOut(" %p\n", mtPtr & ~RUNTIMETYPE_HANDLE_IS_TYPEDESC);
-            }
-            else
-            {
-                CLRDATA_ADDRESS appDomain = GetAppDomainForMT(mtPtr);
-                if (appDomain != NULL)
-                {
-                    if (appDomain == pArgs->adstore.sharedDomain)
-                        ExtOut(" %" POINTERSIZE "s", "Shared");
-
-                    else if (appDomain == pArgs->adstore.systemDomain)
-                        ExtOut(" %" POINTERSIZE "s", "System");
-                    else
-                        DMLOut(" %s", DMLDomain(appDomain));
-                }
-                else
-                {
-                    ExtOut(" %" POINTERSIZE "s", "?");
-                }
-
-                if (NameForMT_s(mtPtr, g_mdName, mdNameLen))
-                {
-                    DMLOut(" %s %S\n", DMLMethodTable(mtPtr), g_mdName);
-                }
-            }
-        }
-    }
-}
-
-
 DECLARE_API(DumpRuntimeTypes)
 {
-    INIT_API();
+    INIT_API_EXT();
     MINIDUMP_NOT_SUPPORTED();
-
-    BOOL dml = FALSE;
-
-    CMDOption option[] =
-    {   // name, vptr, type, hasValue
-        {"/d", &dml, COBOOL, FALSE},
-    };
-
-    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
-        return Status;
-
-    EnableDMLHolder dmlHolder(dml);
-
-    ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s Type Name              \n",
-           "Address", "Domain", "MT");
-    ExtOut("------------------------------------------------------------------------------\n");
-
-    if (!g_snapshot.Build())
-    {
-        ExtOut("Unable to build snapshot of the garbage collector state\n");
-        return E_FAIL;
-    }
-
-    PrintRuntimeTypeArgs pargs;
-    ZeroMemory(&pargs, sizeof(PrintRuntimeTypeArgs));
-
-    try
-    {
-        GCHeapsTraverse(PrintRuntimeTypes, (LPVOID)&pargs);
-    }
-    catch(const sos::Exception &e)
-    {
-        ExtOut("%s\n", e.what());
-        return E_FAIL;
-    }
-
-    return Status;
+    return ExecuteCommand("dumpruntimetypes", args);
 }
 
 namespace sos
@@ -3823,65 +3718,10 @@ DECLARE_API(AnalyzeOOM)
 
 DECLARE_API(VerifyObj)
 {
-    INIT_API();
+    INIT_API_EXT();
     MINIDUMP_NOT_SUPPORTED();
 
-    TADDR  taddrObj = 0;
-    TADDR  taddrMT;
-    size_t objSize;
-
-    BOOL bValid = FALSE;
-    BOOL dml = FALSE;
-
-    CMDOption option[] =
-    {   // name, vptr, type, hasValue
-        {"/d", &dml, COBOOL, FALSE},
-    };
-    CMDValue arg[] =
-    {   // vptr, type
-        {&taddrObj, COHEX}
-    };
-    size_t nArg;
-    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
-    {
-        return Status;
-    }
-
-    EnableDMLHolder dmlHolder(dml);
-    BOOL bContainsPointers;
-
-    if (FAILED(GetMTOfObject(taddrObj, &taddrMT)) ||
-        !GetSizeEfficient(taddrObj, taddrMT, FALSE, objSize, bContainsPointers))
-    {
-        ExtOut("object %#p does not have valid method table\n", SOS_PTR(taddrObj));
-        goto Exit;
-    }
-
-    // we need to build g_snapshot as it is later used in GetGeneration
-    if (!g_snapshot.Build())
-    {
-        ExtOut("Unable to build snapshot of the garbage collector state\n");
-        goto Exit;
-    }
-
-    try
-    {
-        GCHeapDetails *pheapDetails = g_snapshot.GetHeap(taddrObj);
-        bValid = VerifyObject(*pheapDetails, taddrObj, taddrMT, objSize, TRUE);
-    }
-    catch(const sos::Exception &e)
-    {
-        ExtOut("%s\n", e.what());
-        return E_FAIL;
-    }
-
-Exit:
-    if (bValid)
-    {
-        ExtOut("object %#p is a valid object\n", SOS_PTR(taddrObj));
-    }
-
-    return Status;
+    return ExecuteCommand("verifyobj", args);
 }
 
 DECLARE_API(ListNearObj)
index 6400aafa50b7dd7dd939abb26ab1d19869a5ee0b..9fd90c7ba0ecc38408943f343393826fbe4b690a 100644 (file)
@@ -2043,10 +2043,6 @@ HRESULT GetModuleFromAddress(___in CLRDATA_ADDRESS peAddress, ___out IXCLRDataMo
 void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name, mdTypeDef* retMdTypeDef=NULL);
 void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret=NULL);
 
-
-typedef void (*VISITGCHEAPFUNC)(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token);
-BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify=true);
-
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 struct strobjInfo
@@ -2080,11 +2076,6 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B
 CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr);
 CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr);
 
-BOOL VerifyObject(const GCHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize,
-    BOOL bVerifyMember);
-BOOL VerifyObject(const GCHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize,
-    BOOL bVerifyMember);
-
 BOOL IsMTForFreeObj(DWORD_PTR pMT);
 void DumpStackObjectsHelper (TADDR StackTop, TADDR StackBottom, BOOL verifyFields);
 
index 24b5a6e6543c4de541a643dfdf23f51ed49d30cb..a5dbbbefc53f8811a3868306be2e26c254bfee3d 100644 (file)
@@ -177,7 +177,7 @@ sosCommandInitialize(lldb::SBDebugger debugger)
     g_services->AddCommand("dumpmodule", new sosCommand("DumpModule"), "Displays information about a EE module structure at the specified address.");
     g_services->AddCommand("dumpmt", new sosCommand("DumpMT"), "Displays information about a method table at the specified address.");
     g_services->AddCommand("dumpobj", new sosCommand("DumpObj"), "Displays info about an object at the specified address.");
-    g_services->AddCommand("dumpruntimetypes", new sosCommand("DumpRuntimeTypes"), "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.");
+    g_services->AddManagedCommand("dumpruntimetypes", "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.");
     g_services->AddCommand("dumpsig", new sosCommand("DumpSig"), "Dumps the signature of a method or field specified by '<sigaddr> <moduleaddr>'.");
     g_services->AddCommand("dumpsigelem", new sosCommand("DumpSigElem"), "Dumps a single element of a signature object.");
     g_services->AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace.");
@@ -223,6 +223,6 @@ sosCommandInitialize(lldb::SBDebugger debugger)
     g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state.");
     g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module.");
     g_services->AddManagedCommand("verifyheap", "Checks the GC heap for signs of corruption.");
-    g_services->AddCommand("verifyobj", new sosCommand("VerifyObj"), "Checks the object that is passed as an argument for signs of corruption.");
+    g_services->AddManagedCommand("verifyobj", "Checks the object that is passed as an argument for signs of corruption.");
     return true;
 }