From e84270352a5a947a4b3816499c42439329171d89 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Fri, 29 Jul 2022 11:41:58 -0700 Subject: [PATCH] Enable more SOS commands for Linux/MacOS (#3233) Enable more SOS commands for Linux/MacOS Allows more SOS on Linux/MacOS and Linux core dumps on Windows under Windbg. Commands enabled for Linux/MacOS on lldb, windbg and dotnet-dump: DumpSig DumpSigElem DumpRuntimeTypes VerifyHeap AnalyzeOOM VerifyObj ListNearObj GCHeapStat ThreadPool EHInfo GCInfo ObjSize FindRoots Under dotnet-dump and lldb this commands are lowercase. Issue: https://github.com/dotnet/diagnostics/issues/3169 Fix invalid formatting char problems on Windows on a few of the commands. Fix dumpgcdata for server GCs Fix verifyheap failures Fix GCHeapTraverse for empty POH Co-authored-by: Andrew Au --- src/SOS/SOS.Hosting/Commands/SOSCommand.cs | 35 ++- src/SOS/SOS.UnitTests/Scripts/GCPOH.script | 7 + .../Scripts/OtherCommands.script | 10 + src/SOS/Strike/eeheap.cpp | 17 +- src/SOS/Strike/sos.cpp | 14 +- src/SOS/Strike/sos.h | 2 +- src/SOS/Strike/sos_unixexports.src | 9 +- src/SOS/Strike/sosdocsunix.txt | 248 ++++++++++++++++-- src/SOS/Strike/strike.cpp | 98 +++---- src/SOS/Strike/util.cpp | 22 +- src/SOS/Strike/util.h | 3 +- src/SOS/lldbplugin/soscommand.cpp | 33 ++- src/shared/dbgutil/elfreader.cpp | 2 +- src/shared/inc/gcdesc.h | 2 - 14 files changed, 350 insertions(+), 152 deletions(-) diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index 8904b3a559..c37b4f7b1e 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -10,6 +10,7 @@ namespace SOS.Hosting { + [Command(Name = "analyzeoom", DefaultOptions = "AnalyzeOOM", Help = "Displays the info of the last OOM occurred on an allocation request to the GC heap.")] [Command(Name = "clrstack", DefaultOptions = "ClrStack", Help = "Provides a stack trace of managed code only.")] [Command(Name = "clrthreads", DefaultOptions = "Threads", Help = "List the managed threads running.")] [Command(Name = "dbgout", DefaultOptions = "dbgout", Help = "Enable/disable (-off) internal SOS logging.")] @@ -19,6 +20,7 @@ namespace SOS.Hosting [Command(Name = "dumpclass", DefaultOptions = "DumpClass", Help = "Displays information about a EE class structure at the specified address.")] [Command(Name = "dumpdelegate", DefaultOptions = "DumpDelegate", Help = "Displays information about a delegate.")] [Command(Name = "dumpdomain", DefaultOptions = "DumpDomain", Help = "Displays information all the AppDomains and all assemblies within the domains.")] + [Command(Name = "dumpgcdata", DefaultOptions = "DumpGCData", Help = "Displays information about the GC data.")] [Command(Name = "dumpheap", DefaultOptions = "DumpHeap", Help = "Displays info about the garbage-collected heap and collection statistics about objects.")] [Command(Name = "dumpil", DefaultOptions = "DumpIL", Help = "Displays the Microsoft intermediate language (MSIL) that is associated with a managed method.")] [Command(Name = "dumplog", DefaultOptions = "DumpLog", Help = "Writes the contents of an in-memory stress log to the specified file.")] @@ -26,37 +28,44 @@ 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 = "dumpvc", DefaultOptions = "DumpVC", Help = "Displays info about the fields of a value class.")] + [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 = "This command dumps the signature of a method or field given by .")] + [Command(Name = "dumpsigelem", DefaultOptions = "DumpSigElem", Help = "This command 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.")] + [Command(Name = "dumpvc", DefaultOptions = "DumpVC", Help = "Displays info about the fields of a value class.")] [Command(Name = "eeheap", DefaultOptions = "EEHeap", Help = "Displays info about process memory consumed by internal runtime data structures.")] [Command(Name = "eeversion", DefaultOptions = "EEVersion", Help = "Displays information about the runtime version.")] + [Command(Name = "ehinfo", DefaultOptions = "EHInfo", Help = "Displays the exception handling blocks in a jitted method.")] [Command(Name = "finalizequeue", DefaultOptions = "FinalizeQueue", Help = "Displays all objects registered for finalization.")] + [Command(Name = "findappdomain", DefaultOptions = "FindAppDomain", Help = "Attempts to resolve the AppDomain of a GC object.")] + [Command(Name = "gchandles", DefaultOptions = "GCHandles", Help = "Provides statistics about GCHandles in the process.")] + [Command(Name = "gcheapstat", DefaultOptions = "GCHeapStat", Help = "Display various GC heap stats.")] [Command(Name = "gcroot", DefaultOptions = "GCRoot", Help = "Displays info about references (or roots) to an object at the specified address.")] + [Command(Name = "gcinfo", DefaultOptions = "GCInfo", Help = "Displays info JIT GC encoding for a method.")] [Command(Name = "gcwhere", DefaultOptions = "GCWhere", Help = "Displays the location in the GC heap of the argument passed in.")] - [Command(Name = "ip2md", DefaultOptions = "IP2MD", Help = "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.")] - [Command(Name = "name2ee", DefaultOptions = "Name2EE", Help = "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.")] - [Command(Name = "printexception", DefaultOptions = "PrintException", Aliases = new string[] { "pe" }, Help = "Displays and formats fields of any object derived from the Exception class at the specified address.")] - [Command(Name = "syncblk", DefaultOptions = "SyncBlk", Help = "Displays the SyncBlock holder info.")] [Command(Name = "histclear", DefaultOptions = "HistClear", Help = "Releases any resources used by the family of Hist commands.")] [Command(Name = "histinit", DefaultOptions = "HistInit", Help = "Initializes the SOS structures from the stress log saved in the debuggee.")] [Command(Name = "histobj", DefaultOptions = "HistObj", Help = "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument.")] [Command(Name = "histobjfind", DefaultOptions = "HistObjFind", Help = "Displays all the log entries that reference an object at the specified address.")] [Command(Name = "histroot", DefaultOptions = "HistRoot", Help = "Displays information related to both promotions and relocations of the specified root.")] - [Command(Name = "verifyheap", DefaultOptions = "VerifyHeap", Help = "Checks the GC heap for signs of corruption.")] - [Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")] + [Command(Name = "histstats", DefaultOptions = "HistStats", Help = "Displays stress log stats.")] + [Command(Name = "ip2md", DefaultOptions = "IP2MD", Help = "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.")] + [Command(Name = "listnearobj", DefaultOptions = "ListNearObj", Help = "Displays the object preceding and succeeding the address specified.")] + [Command(Name = "name2ee", DefaultOptions = "Name2EE", Help = "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.")] + [Command(Name = "objsize", DefaultOptions = "ObjSize", Help = "Lists the sizes of the all the objects found on managed threads.")] + [Command(Name = "pathto", DefaultOptions = "PathTo", Help = "Displays the GC path from to .")] + [Command(Name = "printexception", DefaultOptions = "PrintException", Aliases = new string[] { "pe" }, Help = "Displays and formats fields of any object derived from the Exception class at the specified address.")] [Command(Name = "soshelp", DefaultOptions = "Help", Help = "Displays help for a specific SOS command.")] + [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 = "verifyheap", DefaultOptions = "VerifyHeap", Help = "Checks the GC heap for signs of corruption.")] + [Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Help = "Checks the object for signs of corruption.")] [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Platform = CommandPlatform.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] [Command(Name = "dumpccw", DefaultOptions = "DumpCCW", Platform = CommandPlatform.Windows, Help = "Displays information about a COM Callable Wrapper.")] [Command(Name = "dumppermissionset",DefaultOptions = "DumpPermissionSet", Platform = CommandPlatform.Windows, Help = "Displays a PermissionSet object (debug build only).")] [Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Platform = CommandPlatform.Windows, Help = "Writes out a file in a format understood by the CLR Profiler.")] - [Command(Name = "analyzeoom", DefaultOptions = "AnalyzeOOM", Platform = CommandPlatform.Windows, Help = "Displays the info of the last OOM occurred on an allocation request to the GC heap.")] - [Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Platform = CommandPlatform.Windows, Help = "Checks the object for signs of corruption.")] - [Command(Name = "listnearobj", DefaultOptions = "ListNearObj", Platform = CommandPlatform.Windows, Help = "Displays the object preceding and succeeding the address specified.")] - [Command(Name = "gcheapstat", DefaultOptions = "GCHeapStat", Platform = CommandPlatform.Windows, Help = "Display various GC heap stats.")] [Command(Name = "watsonbuckets", DefaultOptions = "WatsonBuckets", Platform = CommandPlatform.Windows, Help = "Displays the Watson buckets.")] [Command(Name = "comstate", DefaultOptions = "COMState", Platform = CommandPlatform.Windows, Help = "Lists the COM apartment model for each thread.")] - [Command(Name = "gchandles", DefaultOptions = "GCHandles", Help = "Provides statistics about GCHandles in the process.")] - [Command(Name = "objsize", DefaultOptions = "ObjSize", Help = "Lists the sizes of the all the objects found on managed threads.")] [Command(Name = "gchandleleaks", DefaultOptions = "GCHandleLeaks", Platform = CommandPlatform.Windows, Help = "Helps in tracking down GCHandle leaks")] public class SOSCommand : CommandBase { diff --git a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script index ea211230ab..fb0e5138c1 100644 --- a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script +++ b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script @@ -24,6 +24,8 @@ SOSCOMMAND:DumpObj \w+\s+()\s+(System.Byte\[\]!\$0_)*System.Byte\[ VERIFY:\s+Name: System.Byte\[\]\s+ VERIFY:\s+Array: Rank 1, Number of elements 100, Type Byte\s+ +SOSCOMMAND:ObjSize + SOSCOMMAND:GCWhere # we care that the Gen is 4 (POH) VERIFY:\s+4\s+\d\s+\s+\s+\s+0x\s*\(\d+\) @@ -36,6 +38,11 @@ SOSCOMMAND:GCRoot -all VERIFY:.*Thread : VERIFY:\s+\s+\s+GCPOH\.Main\(\)\s+\[.*[Gg][Cc][Pp][Oo][Hh]\.cs\s+@\s+19\]\s+ +SOSCOMMAND:VerifyHeap +VERIFY:\s*No heap corruption detected.\s* + +SOSCOMMAND:GCHeapStat + SOSCOMMAND:DumpHeap VERIFY:\s+\s+\s+\s+ diff --git a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script index c26430486b..76470093ed 100644 --- a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script @@ -68,6 +68,10 @@ VERIFY:\s*\s+0x\s+\(\)\s+ EXTCOMMAND:registers VERIFY:\s*([r|e]ip|pc) = 0x\s+ +SOSCOMMAND:ThreadPool + +SOSCOMMAND:VerifyHeap + SOSCOMMAND:DumpHeap VERIFY:\s+Address\s+MT\s+Size\s+ VERIFY:\s+\s+\s+.* @@ -131,3 +135,9 @@ VERIFY:\s*Total\s+ VERIFY:\s*CCW\s+ VERIFY:\s*RCW\s+ ENDIF:WINDOWS + +SOSCOMMAND:GCHandles + +SOSCOMMAND:DumpGCData + +SOSCOMMAND:DumpRuntimeTypes diff --git a/src/SOS/Strike/eeheap.cpp b/src/SOS/Strike/eeheap.cpp index 7bb21cf8b0..53a7d62621 100644 --- a/src/SOS/Strike/eeheap.cpp +++ b/src/SOS/Strike/eeheap.cpp @@ -12,7 +12,6 @@ #include "safemath.h" #include "releaseholder.h" - // This is the increment for the segment lookup data const int nSegLookupStgIncrement = 100; @@ -849,7 +848,6 @@ BOOL GCObjInHeap(TADDR taddrObj, const GCHeapDetails &heap, TADDR_SEGINFO& rngSe return FALSE; } -#ifndef FEATURE_PAL // this function updates genUsage to reflect statistics from the range defined by [start, end) void GCGenUsageStats(TADDR start, TADDR alloc_end, TADDR commit_end, const std::unordered_set &liveObjs, const GCHeapDetails &heap, BOOL bLarge, BOOL bPinned, const AllocInfo *pAllocInfo, GenUsageStat *genUsage) @@ -943,7 +941,6 @@ void GCGenUsageStats(TADDR start, TADDR alloc_end, TADDR commit_end, const std:: } } } -#endif // !FEATURE_PAL BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsageStat *hpUsage) { @@ -977,9 +974,7 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage ExtErr("Error requesting heap segment %p\n", SOS_PTR(taddrSeg)); return FALSE; } -#ifndef FEATURE_PAL GCGenUsageStats((TADDR)dacpSeg.mem, (TADDR)dacpSeg.highAllocMark, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[n]); -#endif taddrSeg = (TADDR)dacpSeg.next; } } @@ -989,7 +984,6 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage // 1. Start with small object segments taddrSeg = (TADDR)heap.generation_table[GetMaxGeneration()].start_segment; -#ifndef FEATURE_PAL // 1a. enumerate all non-ephemeral segments while (taddrSeg != (TADDR)heap.generation_table[0].start_segment) { @@ -1004,7 +998,6 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage GCGenUsageStats((TADDR)dacpSeg.mem, (TADDR)dacpSeg.allocated, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[2]); taddrSeg = (TADDR)dacpSeg.next; } -#endif // 1b. now handle the ephemeral segment if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK) @@ -1028,9 +1021,7 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage startGen = TO_TADDR(heap.generation_table[n].allocation_start); } -#ifndef FEATURE_PAL GCGenUsageStats(startGen, endGen, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[n]); -#endif endGen = startGen; } } @@ -1048,9 +1039,7 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage return FALSE; } -#ifndef FEATURE_PAL GCGenUsageStats((TADDR) dacpSeg.mem, (TADDR) dacpSeg.allocated, (TADDR) dacpSeg.committed, liveObjs, heap, TRUE, FALSE, NULL, &hpUsage->genUsage[3]); -#endif taddrSeg = (TADDR)dacpSeg.next; } @@ -1069,9 +1058,7 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage return FALSE; } -#ifndef FEATURE_PAL GCGenUsageStats((TADDR) dacpSeg.mem, (TADDR) dacpSeg.allocated, (TADDR) dacpSeg.committed, liveObjs, heap, FALSE, TRUE, NULL, &hpUsage->genUsage[4]); -#endif taddrSeg = (TADDR)dacpSeg.next; } } @@ -1197,7 +1184,7 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B SOS_PTR(SegQueueLimit(heapDetails,gen_segment(m)))); } } -#ifndef FEATURE_PAL + if (bAllReady) { if (!bShort) @@ -1210,7 +1197,6 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B PrintNotReachableInRange(rngStart, rngEnd, TRUE, bAllReady ? stat : NULL, bShort); } -#endif if (!bShort) { @@ -1585,6 +1571,7 @@ BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEA } dwAddrCurrObj = (DWORD_PTR)segment.mem; + continue; } else { diff --git a/src/SOS/Strike/sos.cpp b/src/SOS/Strike/sos.cpp index f2052cfa2e..5764a86dd4 100644 --- a/src/SOS/Strike/sos.cpp +++ b/src/SOS/Strike/sos.cpp @@ -4,21 +4,9 @@ #include "strike.h" #include "util.h" - #include "sos.h" - - -#ifdef _ASSERTE -#undef _ASSERTE -#endif - -#define _ASSERTE(a) {;} - #include "gcdesc.h" - -#undef _ASSERTE - namespace sos { template @@ -505,7 +493,7 @@ namespace sos int entries = 0; if (FAILED(MOVE(entries, mt-sizeof(TADDR)))) - Throw("Failed to request number of entries."); + Throw("Failed to request number of entries for %p MT %p", mObject, mt); // array of vc? if (entries < 0) diff --git a/src/SOS/Strike/sos.h b/src/SOS/Strike/sos.h index 98a71b678e..2a58703c85 100644 --- a/src/SOS/Strike/sos.h +++ b/src/SOS/Strike/sos.h @@ -721,7 +721,7 @@ namespace sos inline const SyncBlkIterator &operator++() { SOS_Assert(mCurr <= mTotal); - mSyncBlk = ++mCurr; + mSyncBlk = mCurr++; return *this; } diff --git a/src/SOS/Strike/sos_unixexports.src b/src/SOS/Strike/sos_unixexports.src index 7928b2dfe6..35bd51fa0c 100644 --- a/src/SOS/Strike/sos_unixexports.src +++ b/src/SOS/Strike/sos_unixexports.src @@ -2,6 +2,7 @@ ; The .NET Foundation licenses this file to you under the MIT license. ; See the LICENSE file in the project root for more information. +AnalyzeOOM bpmd clrmodules ClrStack @@ -29,15 +30,17 @@ DumpStackObjects DumpVC EEHeap EEVersion -GCWhere EEStack EHInfo ext FinalizeQueue FindAppDomain +FindRoots GCHandles +GCHeapStat GCInfo GCRoot +GCWhere Help HistClear HistInit @@ -46,17 +49,18 @@ HistObjFind HistRoot HistStats IP2MD +ListNearObj logging Name2EE ObjSize PrintException PathTo +runtimes StopOnCatch SetClrPath SetSymbolServer SOSFlush SOSStatus -runtimes SuppressJitOptimization SyncBlk Threads @@ -65,6 +69,7 @@ ThreadState Token2EE u VerifyHeap +VerifyObj SOSInitializeByHost SOSUninitializeByHost diff --git a/src/SOS/Strike/sosdocsunix.txt b/src/SOS/Strike/sosdocsunix.txt index 11122de4f8..6eb004882b 100644 --- a/src/SOS/Strike/sosdocsunix.txt +++ b/src/SOS/Strike/sosdocsunix.txt @@ -32,22 +32,22 @@ DumpHeap (dumpheap) EEStack (eestack) DumpVC ClrStack (clrstack) FinalizeQueue (finalizequeue) GCInfo GCRoot (gcroot) EHInfo -ObjSize bpmd (bpmd) +ObjSize (objsize) bpmd (bpmd) PrintException (pe) Examining CLR data structures Diagnostic Utilities ----------------------------- ----------------------------- DumpDomain (dumpdomain) VerifyHeap EEHeap (eeheap) FindAppDomain -Name2EE (name2ee) GCHandles -SyncBlk (syncblk) DumpLog (dumplog) -DumpMT (dumpmt) SuppressJitOptimization -DumpClass (dumpclass) ThreadPool (threadpool) -DumpMD (dumpmd) -Token2EE +Name2EE (name2ee) DumpLog (dumplog) +SyncBlk (syncblk) SuppressJitOptimization +DumpMT (dumpmt) ThreadPool (threadpool) +DumpClass (dumpclass) AnalyzeOOM (analyzeoom) +DumpMD (dumpmd) VerifyObj (verifyobj) +Token2EE GCHandles (gchandles) DumpModule (dumpmodule) DumpAssembly (dumpassembly) -DumpRuntimeTypes +DumpRuntimeTypes (dumpruntimetypes) DumpIL (dumpil) DumpSig DumpSigElem @@ -443,27 +443,6 @@ DumpVC is quite a specialized function. Some managed programs make heavy use of value classes, while others do not. \\ -COMMAND: finalizequeue -FinalizeQueue [-detail] | [-allReady] [-short] - -Displays all objects registered for finalization. -The "-detail" option displays extra information about any SyncBlocks that need -to be cleaned up. This data structure is cached and cleaned up by the -finalizer thread when it runs. - -The "-allReady" option displays all objects that are ready for finalization, -regardless of whether they are already marked by the garbage collection -as such, or will be marked by the next garbage collection. The objects that -are in the "ready for finalization" list are finalizable objects that are -no longer rooted. This option can be very expensive, because it verifies -whether all the objects in the finalizable queues are still rooted. - -The "-short" option limits the output to the address of each object. If it is -used in conjunction with -allReady, it enumerates all objects that have -a finalizer that are no longer rooted. If it is used independently, it lists -all objects in the finalizable and "ready for finalization" queues. -\\ - COMMAND: gcroot. GCRoot [-nostacks] [-all] @@ -526,6 +505,61 @@ number of roots can share a common subgraph, and that part will be reported in the size of all the roots that reference the subgraph. \\ +COMMAND: finalizequeue. +FinalizeQueue [-detail] | [-allReady] [-short] + +This command lists the objects registered for finalization. Here is output from +a simple program: + + (lldb) finalizequeue + SyncBlocks to be cleaned up: 0 + MTA Interfaces to be released: 0 + STA Interfaces to be released: 1 + generation 0 has 4 finalizable objects (0015bc90->0015bca0) + generation 1 has 0 finalizable objects (0015bc90->0015bc90) + generation 2 has 0 finalizable objects (0015bc90->0015bc90) + Ready for finalization 0 objects (0015bca0->0015bca0) + Statistics: + MT Count TotalSize Class Name + 5ba6cf78 1 24 Microsoft.Win32.SafeHandles.SafeFileHandle + 5ba5db04 1 68 System.Threading.Thread + 5ba73e28 2 112 System.IO.StreamWriter + Total 4 objects + +The GC heap is divided into generations, and objects are listed accordingly. We +see that only generation 0 (the youngest generation) has any objects registered +for finalization. The notation "(0015bc90->0015bca0)" means that if you look at +memory in that range, you'll see the object pointers that are registered: + +0:000> dd 15bc90 15bca0-4 +0015bc90 00a743f4 00a79f00 00a7b3d8 00a7b47c + +You could run dumpobj on any of those pointers to learn more. In this example, +there are no objects ready for finalization, presumably because they still have +roots (You can use !GCRoot to find out). The statistics section provides a +higher-level summary of the objects registered for finalization. Note that +objects ready for finalization are also included in the statistics (if any). + +Specifying -short will inhibit any display related to SyncBlocks or RCWs. + +The arguments in detail: + +-allReady Specifying this argument will allow for the display of all objects + that are ready for finalization, whether they are already marked by + the GC as such, or whether the next GC will. The objects that are + not in the "Ready for finalization" list are finalizable objects that + are no longer rooted. This option can be very expensive, as it + verifies whether all the objects in the finalizable queues are still + rooted or not. +-short Limits the output to just the address of each object. If used in + conjunction with -allReady it enumerates all objects that have a + finalizer that are no longer rooted. If used independently it lists + all objects in the finalizable and "ready for finalization" queues. +-detail Will display extra information on any SyncBlocks that need to be + cleaned up, and on any RuntimeCallableWrappers (RCWs) that await + cleanup. Both of these data structures are cached and cleaned up by + the finalizer thread when it gets a chance to run. +\\ COMMAND: pe. COMMAND: printexception. PrintException [-nested] [-lines] [-ccw] [] [] @@ -1622,6 +1656,7 @@ is a simple example of the output for a dynamic method: IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret + \\ COMMAND: verifyheap. @@ -1662,6 +1697,127 @@ in the CLR. In user code, an error in constructing PInvoke calls can cause this problem, and running with Managed Debugging Assistants is advised. If that possibility is eliminated, consider contacting Microsoft Product Support for help. + +\\ + +COMMAND: verifyobj. +VerifyObj + +VerifyObj is a diagnostic tool that checks the object that is passed as an +argument for signs of corruption. + + 0:002> !verifyobj 028000ec + object 0x28000ec does not have valid method table + + 0:002> !verifyobj 0680017c + object 0x680017c: bad member 00000001 at 06800184 + +\\ + +COMMAND: findroots. +FindRoots -gen | -gen any | + +The "-gen" form causes the debugger to break in the debuggee on the next +collection of the specified generation. The effect is reset as soon as the +break occurs, in other words, if you need to break on the next collection you +would need to reissue the command. + +The last form of this command is meant to be used after the break caused by the +other forms has occurred. Now the debuggee is in the right state for +findroots to be able to identify roots for objects from the current condemned +generations. + +FindRoots is a diagnostic command that is meant to answer the following +question: + +"I see that GCs are happening, however my objects have still not been +collected. Why? Who is holding onto them?" + +The process of answering the question would go something like this: + +1. Find out the generation of the object of interest using the gcwhere +command, say it is gen 1: + (lldb) gcwhere + +2. Instruct the runtime to stop the next time it collects that generation using +the findroots command: + findroots -gen 1 + g + +3. When the next GC starts, and has proceeded past the mark phase a CLR +notification will cause a break in the debugger: + (fd0.ec4): CLR notification exception - code e0444143 (first chance) + CLR notification: GC - end of mark phase. + Condemned generation: 1. + +4. Now we can use the findroots to find out the cross +generational references to the object of interest. In other words, even if the +object is not referenced by any "proper" root it may still be referenced by an +older object (from an older generation), from a generation that has not yet been +scheduled for collection. At this point findroots will search those older +generations too, and report those roots. + (lldb) findroots 06808094 + older generations::Root: 068012f8(AAA.Test+a)-> + 06808094(AAA.Test+b) + +\\ + +COMMAND: analyzeoom. +AnalyzeOOM + +AnalyzeOOM displays the info of the last OOM occurred on an allocation request to +the GC heap (in Server GC it displays OOM, if any, on each GC heap). + +To see the managed exception(s) use the clrthreads command which will show you +managed exception(s), if any, on each managed thread. If you do see an +OutOfMemoryException exception you can use the !PrintException command on it. +To get the full callstack use the "kb" command in the debugger for that thread. +For example, to display thread 3's stack use ~3kb. + +OOM exceptions could be because of the following reasons: + +1) allocation request to GC heap + in which case you will see JIT_New* on the call stack because managed code called new. +2) other runtime allocation failure + for example, failure to expand the finalize queue when GC.ReRegisterForFinalize is + called. +3) some other code you use throws a managed OOM exception + for example, some .NET framework code converts a native OOM exception to managed + and throws it. + +The !AnalyzeOOM command aims to help you with investigating 1) which is the most +difficult because it requires some internal info from GC. The only exception is +we don't support allocating objects larger than 2GB on CLR v2.0 or prior. And this +command will not display any managed OOM because we will throw OOM right away +instead of even trying to allocate it on the GC heap. + +There are 2 legitimate scenarios where GC would return OOM to allocation requests - +one is if the process is running out of VM space to reserve a segment; the other +is if the system is running out physical memory (+ page file if you have one) so +GC can not commit memory it needs. You can look at these scenarios by using performance +counters or debugger commands. For example for the former scenario the "!address +-summary" debugger command will show you the largest free region in the VM. For +the latter scenario you can look at the "Memory% Committed Bytes In Use" see +if you are running low on commit space. One important thing to keep in mind is +when you do this kind of memory analysis it could an aftereffect and doesn't +completely agree with what this command tells you, in which case the command should +be respected because it truly reflects what happened during GC. + +The other cases should be fairly obvious from the callstack. + +Sample output: + +0:011> !analyzeoom +---------Heap 2 --------- +Managed OOM occurred after GC #28 (Requested to allocate 1234 bytes) +Reason: Didn't have enough memory to commit +Detail: SOH: Didn't have enough memory to grow the internal GC datastructures (800000 bytes) - + on GC entry available commit space was 500 MB +---------Heap 4 --------- +Managed OOM occurred after GC #12 (Requested to allocate 100000 bytes) +Reason: Didn't have enough memory to allocate an LOH segment +Detail: LOH: Failed to reserve memory (16777216 bytes) + \\ COMMAND: gcwhere. @@ -1681,6 +1837,40 @@ the "size" is displayed as 0: 0280003c 2 0 02800000 02800038 0282b740 0 \\ +COMMAND: listnearobj. +ListNearObj + +ListNearObj is a diagnostic tool that displays the object preceeding and +succeeding the address passed in: + +The command looks for the address in the GC heap that looks like a valid +beginning of a managed object (based on a valid method table) and the object +following the argument address. + + 0:002> listnearobj 028000ec + Before: 0x28000a4 72 (0x48 ) System.StackOverflowException + After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException + Heap local consistency confirmed. + + 0:002> listnearobj 028000f0 + Before: 0x28000ec 72 (0x48 ) System.ExecutionEngineException + After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException + Heap local consistency confirmed. + +The command considers the heap as "locally consistent" if: + prev_obj_addr + prev_obj_size = arg_addr && arg_obj + arg_size = next_obj_addr +OR + prev_obj_addr + prev_obj_size = next_obj_addr + +When the condition is not satisfied: + + 0:002> listnearobj 028000ec + Before: 0x28000a4 72 (0x48 ) System.StackOverflowException + After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException + Heap local consistency not confirmed. + +\\ + COMMAND: dumplog. DumpLog [-addr ] [] diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 97ceb48643..dd5177e95b 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -1044,7 +1044,6 @@ DECLARE_API(DumpSig) INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); // // Fetch arguments @@ -1092,7 +1091,6 @@ DECLARE_API(DumpSigElem) INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); // // Fetch arguments @@ -3940,7 +3938,6 @@ DECLARE_API(DumpRuntimeTypes) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); BOOL dml = FALSE; @@ -3961,7 +3958,16 @@ DECLARE_API(DumpRuntimeTypes) PrintRuntimeTypeArgs pargs; ZeroMemory(&pargs, sizeof(PrintRuntimeTypeArgs)); - GCHeapsTraverse(PrintRuntimeTypes, (LPVOID)&pargs); + try + { + GCHeapsTraverse(PrintRuntimeTypes, (LPVOID)&pargs); + } + catch(const sos::Exception &e) + { + ExtOut("%s\n", e.what()); + return E_FAIL; + } + return Status; } @@ -4495,7 +4501,6 @@ DECLARE_API(VerifyHeap) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); if (!g_snapshot.Build()) { @@ -4539,8 +4544,6 @@ DECLARE_API(VerifyHeap) } } -#ifndef FEATURE_PAL - enum failure_get_memory { fgm_no_failure = 0, @@ -4631,9 +4634,6 @@ DECLARE_API(AnalyzeOOM) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); - -#ifndef FEATURE_PAL if (!InitializeHeapData ()) { @@ -4699,17 +4699,12 @@ DECLARE_API(AnalyzeOOM) } return S_OK; -#else - _ASSERTE(false); - return E_FAIL; -#endif // FEATURE_PAL } DECLARE_API(VerifyObj) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); TADDR taddrObj = 0; TADDR taddrMT; @@ -4748,10 +4743,17 @@ DECLARE_API(VerifyObj) 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) @@ -4772,9 +4774,6 @@ DECLARE_API(ListNearObj) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); - -#if !defined(FEATURE_PAL) TADDR taddrArg = 0; TADDR taddrObj = 0; @@ -4946,23 +4945,12 @@ DECLARE_API(ListNearObj) } return Status; - -#else - - _ASSERTE(false); - return E_FAIL; - -#endif // FEATURE_PAL } - DECLARE_API(GCHeapStat) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); - -#ifndef FEATURE_PAL BOOL bIncUnreachable = FALSE; BOOL dml = FALSE; @@ -5026,7 +5014,7 @@ DECLARE_API(GCHeapStat) pohUnrootedUsage, "%"); } - ExtOut("\nCommitted space:"); + ExtOut("\nCommitted space:\n"); ExtOut("Heap%-4d %12" POINTERSIZE_TYPE "u %12" POINTERSIZE_TYPE "u %12" POINTERSIZE_TYPE "u %12" POINTERSIZE_TYPE "u %12" POINTERSIZE_TYPE "u\n", 0, hpUsage.genUsage[0].committed, hpUsage.genUsage[1].committed, hpUsage.genUsage[2].committed, hpUsage.genUsage[3].committed, @@ -5066,7 +5054,9 @@ DECLARE_API(GCHeapStat) } // aggregate stats across heaps / generation - GenUsageStat genUsageStat[5] = {0, 0, 0, 0, 0}; + GenUsageStat genUsageStat[5]; + memset(genUsageStat, 0, sizeof(genUsageStat)); + bool hasPoh = false; for (DWORD n = 0; n < dwNHeaps; n ++) { @@ -5151,17 +5141,8 @@ DECLARE_API(GCHeapStat) } return Status; - -#else - - _ASSERTE(false); - return E_FAIL; - -#endif // FEATURE_PAL } -#endif // FEATURE_PAL - /**********************************************************************\ * Routine Description: * * * @@ -8025,7 +8006,6 @@ DECLARE_API(ThreadPool) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); BOOL doHCDump = FALSE, doWorkItemDump = FALSE, dml = FALSE; @@ -8610,7 +8590,6 @@ DECLARE_API(FindAppDomain) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); DWORD_PTR p_Object = NULL; BOOL dml = FALSE; @@ -8879,7 +8858,6 @@ DECLARE_API(EHInfo) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); DWORD_PTR dwStartAddr = NULL; BOOL dml = FALSE; @@ -8961,7 +8939,6 @@ DECLARE_API(GCInfo) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); TADDR taStartAddr = NULL; TADDR taGCInfoAddr; @@ -10204,7 +10181,6 @@ DECLARE_API(DumpGCData) #ifdef GC_CONFIG_DRIVEN MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); if (!InitializeHeapData ()) { @@ -10213,16 +10189,17 @@ DECLARE_API(DumpGCData) } DacpGCInterestingInfoData interestingInfo; - interestingInfo.RequestGlobal(g_sos); - for (int i = 0; i < DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT; i++) + if (!IsServerBuild()) { - ExtOut("%-30s: %d\n", str_gc_global_mechanisms[i], interestingInfo.globalMechanisms[i]); - } + // Doesn't work (segfaults) for server GCs + interestingInfo.RequestGlobal(g_sos); + for (int i = 0; i < DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT; i++) + { + ExtOut("%-30s: %d\n", str_gc_global_mechanisms[i], interestingInfo.globalMechanisms[i]); + } - ExtOut("\n[info per heap]\n"); + ExtOut("\n[info per heap]\n"); - if (!IsServerBuild()) - { if (interestingInfo.Request(g_sos) != S_OK) { ExtOut("Error requesting interesting GC info\n"); @@ -10233,6 +10210,8 @@ DECLARE_API(DumpGCData) } else { + ExtOut("\n[info per heap]\n"); + DWORD dwNHeaps = GetGcHeapCount(); DWORD dwAllocSize; if (!ClrSafeInt::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize)) @@ -10912,7 +10891,6 @@ DECLARE_API(PathTo) { INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); DWORD_PTR root = NULL; DWORD_PTR target = NULL; @@ -11123,14 +11101,10 @@ DECLARE_API(GCWhere) return Status; } -#ifndef FEATURE_PAL - DECLARE_API(FindRoots) { -#ifndef FEATURE_PAL INIT_API(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); if (IsDumpFile()) { @@ -11189,7 +11163,11 @@ DECLARE_API(FindRoots) GcEvtArgs gea = { GC_MARK_END, { ((gen == -1) ? 7 : (1 << gen)) } }; idp2->SetGcNotification(gea); // ... and register the notification handler +#ifndef FEATURE_PAL g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "sxe -c \"!SOSHandleCLRN\" clrn", 0); +#else + g_ExtServices->SetExceptionCallback(HandleExceptionNotification); +#endif // FEATURE_PAL // the above notification is removed in CNotification::OnGcEvent() } else @@ -11232,13 +11210,8 @@ DECLARE_API(FindRoots) } return Status; -#else - return E_NOTIMPL; -#endif } -#endif // FEATURE_PAL - class GCHandleStatsForDomains { public: @@ -12234,7 +12207,6 @@ DECLARE_API(GCHandleLeaks) } #endif // FEATURE_PAL - class ClrStackImplWithICorDebug { private: diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index ab8f67eb3a..37b3f73ab4 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -4656,7 +4656,16 @@ OutputVaList( int length = _vsnprintf_s((char* const)&g_printBuffer, sizeof(g_printBuffer), _TRUNCATE, format, args); if (length > 0) { - return g_ExtControl->OutputVaList(mask, (char* const)&g_printBuffer, args); +#ifdef HOST_WINDOWS + if (IsInitializedByDbgEng()) + { + return g_ExtControl->Output(mask, "%s", g_printBuffer); + } + else +#endif + { + return g_ExtControl->OutputVaList(mask, (char* const)&g_printBuffer, args); + } } return E_FAIL; } @@ -4671,7 +4680,16 @@ ControlledOutputVaList( int length = _vsnprintf_s((char* const)&g_printBuffer, sizeof(g_printBuffer), _TRUNCATE, format, args); if (length > 0) { - return g_ExtControl->ControlledOutputVaList(outputControl, mask, (char* const)&g_printBuffer, args); +#ifdef HOST_WINDOWS + if (IsInitializedByDbgEng()) + { + return g_ExtControl->ControlledOutput(outputControl, mask, "%s", g_printBuffer); + } + else +#endif + { + return g_ExtControl->ControlledOutputVaList(outputControl, mask, (char* const)&g_printBuffer, args); + } } return E_FAIL; } diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index fcde9cd034..b8af171e80 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -658,9 +658,8 @@ inline void ExtOutIndent() { WhitespaceOut(Output::g_Indent << 2); } bool IsDMLEnabled(); - #ifndef SOS_Assert -#define SOS_Assert(x) +#define SOS_Assert _ASSERTE #endif void ConvertToLower(__out_ecount(len) char *buffer, size_t len); diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index f487f20d95..2ed9a26cf1 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -156,7 +156,6 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running."); g_services->AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method."); g_services->AddCommand("dbgout", new sosCommand("dbgout"), "Enable/disable (-off) internal SOS logging."); - g_services->AddCommand("logging", new sosCommand("logging"), "Enable/disable internal SOS logging."); g_services->AddCommand("dumpalc", new sosCommand("DumpALC"), "Displays details about a collectible AssemblyLoadContext to which the specified object is loaded."); g_services->AddCommand("dumparray", new sosCommand("DumpArray"), "Displays details about a managed array."); g_services->AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays information about async \"stacks\" on the garbage-collected heap."); @@ -164,6 +163,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address."); g_services->AddCommand("dumpdelegate", new sosCommand("DumpDelegate"), "Displays information about a delegate."); g_services->AddCommand("dumpdomain", new sosCommand("DumpDomain"), "Displays information all the AppDomains and all assemblies within the domains."); + g_services->AddCommand("dumpgcdata", new sosCommand("DumpGCData"), "Displays information about the GC data."); g_services->AddCommand("dumpheap", new sosCommand("DumpHeap"), "Displays info about the garbage-collected heap and collection statistics about objects."); g_services->AddCommand("dumpil", new sosCommand("DumpIL"), "Displays the Microsoft intermediate language (MSIL) that is associated with a managed method."); g_services->AddCommand("dumplog", new sosCommand("DumpLog"), "Writes the contents of an in-memory stress log to the specified file."); @@ -171,37 +171,52 @@ 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("dumpvc", new sosCommand("DumpVC"), "Displays info about the fields of a value class."); + 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->AddCommand("dumpsig", new sosCommand("DumpSig"), "This command dumps the signature of a method or field given by ."); + g_services->AddCommand("dumpsigelem", new sosCommand("DumpSigElem"), "This command dumps a single element of a signature object."); g_services->AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace."); + g_services->AddCommand("dumpstackobjects", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); g_services->AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); + g_services->AddCommand("dumpvc", new sosCommand("DumpVC"), "Displays info about the fields of a value class."); g_services->AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures."); g_services->AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process."); g_services->AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime version."); + g_services->AddCommand("ehinfo", new sosCommand("EHInfo"), "Displays the exception handling blocks in a jitted method."); g_services->AddCommand("finalizequeue", new sosCommand("FinalizeQueue"), "Displays all objects registered for finalization."); + g_services->AddCommand("findappdomain", new sosCommand("FindAppDomain"), "Attempts to resolve the AppDomain of a GC object."); + g_services->AddCommand("findroots", new sosCommand("FindRoots"), ""); g_services->AddCommand("gchandles", new sosCommand("GCHandles"), "Displays statistics about garbage collector handles in the process."); + g_services->AddCommand("gcheapstat", new sosCommand("GCHeapStat"), "Displays statistics about garbage collector."); + g_services->AddCommand("gcinfo", new sosCommand("GCInfo"), "Displays info JIT GC encoding for a method."); g_services->AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address."); g_services->AddCommand("gcwhere", new sosCommand("GCWhere"), "Displays the location in the GC heap of the argument passed in."); - g_services->AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled."); - g_services->AddCommand("loadsymbols", new sosCommand("SetSymbolServer", "-loadsymbols"), "Load the .NET Core native module symbols."); - g_services->AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module."); - g_services->AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); - g_services->AddCommand("syncblk", new sosCommand("SyncBlk"), "Displays the SyncBlock holder info."); g_services->AddCommand("histclear", new sosCommand("HistClear"), "Releases any resources used by the family of Hist commands."); g_services->AddCommand("histinit", new sosCommand("HistInit"), "Initializes the SOS structures from the stress log saved in the debuggee."); g_services->AddCommand("histobj", new sosCommand("HistObj"), "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument."); g_services->AddCommand("histobjfind", new sosCommand("HistObjFind"), "Displays all the log entries that reference an object at the specified address."); g_services->AddCommand("histroot", new sosCommand("HistRoot"), "Displays information related to both promotions and relocations of the specified root."); + g_services->AddCommand("histstats", new sosCommand("HistStats"), "Displays stress log stats."); + g_services->AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled."); + g_services->AddCommand("listnearobj", new sosCommand("ListNearObj"), "displays the object preceeding and succeeding the address passed."); + g_services->AddCommand("loadsymbols", new sosCommand("SetSymbolServer", "-loadsymbols"), "Load the .NET Core native module symbols."); + g_services->AddCommand("logging", new sosCommand("logging"), "Enable/disable internal SOS logging."); + g_services->AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module."); g_services->AddCommand("objsize", new sosCommand("ObjSize"), "Displays the size of the specified object."); + g_services->AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); + g_services->AddCommand("pathto", new sosCommand("PathTo"), "Displays the GC path from to ."); + g_services->AddCommand("runtimes", new sosCommand("runtimes"), "List the runtimes in the target or change the default runtime."); + g_services->AddCommand("stoponcatch", new sosCommand("StopOnCatch"), "Debuggee will break the next time a managed exception is caught during execution"); g_services->AddCommand("setclrpath", new sosCommand("SetClrPath"), "Set the path to load the runtime DAC/DBI files."); g_services->AddCommand("setsymbolserver", new sosCommand("SetSymbolServer"), "Enables the symbol server support "); g_services->AddCommand("sympath", new sosCommand("SetSymbolServer", "-sympath"), "Add server, cache and directory paths in the Windows symbol path format."); g_services->AddCommand("soshelp", new sosCommand("Help"), "Displays all available commands when no parameter is specified, or displays detailed help information about the specified command. soshelp "); - g_services->AddCommand("sosstatus", new sosCommand("SOSStatus"), "Displays the global SOS status."); - g_services->AddCommand("runtimes", new sosCommand("runtimes"), "List the runtimes in the target or change the default runtime."); g_services->AddCommand("sosflush", new sosCommand("SOSFlush"), "Flushes the DAC caches."); + g_services->AddCommand("sosstatus", new sosCommand("SOSStatus"), "Displays the global SOS status."); + g_services->AddCommand("syncblk", new sosCommand("SyncBlk"), "Displays the SyncBlock holder info."); g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool."); 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->AddCommand("verifyheap", new sosCommand("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."); return true; } diff --git a/src/shared/dbgutil/elfreader.cpp b/src/shared/dbgutil/elfreader.cpp index 0848b3f3fd..f01d8a5611 100644 --- a/src/shared/dbgutil/elfreader.cpp +++ b/src/shared/dbgutil/elfreader.cpp @@ -103,7 +103,7 @@ class ElfReaderFromFile : public ElfReader { return false; } - if (PAL_fseek(m_file, (LONG)address, SEEK_SET) != 0) + if (PAL_fseek(m_file, (LONG_PTR)address, SEEK_SET) != 0) { return false; } diff --git a/src/shared/inc/gcdesc.h b/src/shared/inc/gcdesc.h index 9b461a701a..2a9ca3529d 100644 --- a/src/shared/inc/gcdesc.h +++ b/src/shared/inc/gcdesc.h @@ -161,8 +161,6 @@ class CGCDesc // If it doesn't contain pointers, there isn't a GCDesc PTR_MethodTable mt(pMT); - _ASSERTE(mt->ContainsPointers()); - return PTR_CGCDesc(mt); }