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.")]
[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.")]
[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 <sigaddr> <moduleaddr>.")]
+ [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 <root> to <target>.")]
+ [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
{
VERIFY:\s+Name: System.Byte\[\]\s+
VERIFY:\s+Array: Rank 1, Number of elements 100, Type Byte\s+
+SOSCOMMAND:ObjSize <PREVPOUT>
+
SOSCOMMAND:GCWhere <PREVPOUT>
# we care that the Gen is 4 (POH)
VERIFY:<HEXVAL>\s+4\s+\d\s+<HEXVAL>\s+<HEXVAL>\s+<HEXVAL>\s+0x<HEXVAL>\s*\(\d+\)
VERIFY:.*Thread <HEXVAL>:
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\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+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>\s+
EXTCOMMAND:registers
VERIFY:\s*([r|e]ip|pc) = 0x<HEXVAL>\s+
+SOSCOMMAND:ThreadPool
+
+SOSCOMMAND:VerifyHeap
+
SOSCOMMAND:DumpHeap
VERIFY:\s+Address\s+MT\s+Size\s+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+<DECVAL>.*
VERIFY:\s*CCW\s+<DECVAL>
VERIFY:\s*RCW\s+<DECVAL>
ENDIF:WINDOWS
+
+SOSCOMMAND:GCHandles
+
+SOSCOMMAND:DumpGCData
+
+SOSCOMMAND:DumpRuntimeTypes
#include "safemath.h"
#include "releaseholder.h"
-
// This is the increment for the segment lookup data
const int nSegLookupStgIncrement = 100;
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<TADDR> &liveObjs,
const GCHeapDetails &heap, BOOL bLarge, BOOL bPinned, const AllocInfo *pAllocInfo, GenUsageStat *genUsage)
}
}
}
-#endif // !FEATURE_PAL
BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsageStat *hpUsage)
{
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;
}
}
// 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)
{
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)
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;
}
}
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;
}
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;
}
}
SOS_PTR(SegQueueLimit(heapDetails,gen_segment(m))));
}
}
-#ifndef FEATURE_PAL
+
if (bAllReady)
{
if (!bShort)
PrintNotReachableInRange(rngStart, rngEnd, TRUE, bAllReady ? stat : NULL, bShort);
}
-#endif
if (!bShort)
{
}
dwAddrCurrObj = (DWORD_PTR)segment.mem;
+ continue;
}
else
{
#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 <class T>
int entries = 0;
if (FAILED(MOVE(entries, mt-sizeof(TADDR))))
- Throw<DataRead>("Failed to request number of entries.");
+ Throw<DataRead>("Failed to request number of entries for %p MT %p", mObject, mt);
// array of vc?
if (entries < 0)
inline const SyncBlkIterator &operator++()
{
SOS_Assert(mCurr <= mTotal);
- mSyncBlk = ++mCurr;
+ mSyncBlk = mCurr++;
return *this;
}
; 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
DumpVC
EEHeap
EEVersion
-GCWhere
EEStack
EHInfo
ext
FinalizeQueue
FindAppDomain
+FindRoots
GCHandles
+GCHeapStat
GCInfo
GCRoot
+GCWhere
Help
HistClear
HistInit
HistRoot
HistStats
IP2MD
+ListNearObj
logging
Name2EE
ObjSize
PrintException
PathTo
+runtimes
StopOnCatch
SetClrPath
SetSymbolServer
SOSFlush
SOSStatus
-runtimes
SuppressJitOptimization
SyncBlk
Threads
Token2EE
u
VerifyHeap
+VerifyObj
SOSInitializeByHost
SOSUninitializeByHost
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
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] <Object address>
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] [<Exception object address>] [<CCW pointer>]
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: ret
+
\\
COMMAND: verifyheap.
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 <object address>
+
+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 <N> | -gen any | <object address>
+
+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 <object address>
+
+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 <object address> 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.
0280003c 2 0 02800000 02800038 0282b740 0
\\
+COMMAND: listnearobj.
+ListNearObj <object address>
+
+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 <addressOfStressLog>] [<Filename>]
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
//
// Fetch arguments
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
//
// Fetch arguments
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
BOOL dml = FALSE;
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;
}
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
if (!g_snapshot.Build())
{
}
}
-#ifndef FEATURE_PAL
-
enum failure_get_memory
{
fgm_no_failure = 0,
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
-
-#ifndef FEATURE_PAL
if (!InitializeHeapData ())
{
}
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;
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)
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
-
-#if !defined(FEATURE_PAL)
TADDR taddrArg = 0;
TADDR taddrObj = 0;
}
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;
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,
}
// 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 ++)
{
}
return Status;
-
-#else
-
- _ASSERTE(false);
- return E_FAIL;
-
-#endif // FEATURE_PAL
}
-#endif // FEATURE_PAL
-
/**********************************************************************\
* Routine Description: *
* *
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
BOOL doHCDump = FALSE, doWorkItemDump = FALSE, dml = FALSE;
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
DWORD_PTR p_Object = NULL;
BOOL dml = FALSE;
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
DWORD_PTR dwStartAddr = NULL;
BOOL dml = FALSE;
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
TADDR taStartAddr = NULL;
TADDR taGCInfoAddr;
#ifdef GC_CONFIG_DRIVEN
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
if (!InitializeHeapData ())
{
}
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");
}
else
{
+ ExtOut("\n[info per heap]\n");
+
DWORD dwNHeaps = GetGcHeapCount();
DWORD dwAllocSize;
if (!ClrSafeInt<DWORD>::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize))
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
DWORD_PTR root = NULL;
DWORD_PTR target = NULL;
return Status;
}
-#ifndef FEATURE_PAL
-
DECLARE_API(FindRoots)
{
-#ifndef FEATURE_PAL
INIT_API();
MINIDUMP_NOT_SUPPORTED();
- ONLY_SUPPORTED_ON_WINDOWS_TARGET();
if (IsDumpFile())
{
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
}
return Status;
-#else
- return E_NOTIMPL;
-#endif
}
-#endif // FEATURE_PAL
-
class GCHandleStatsForDomains
{
public:
}
#endif // FEATURE_PAL
-
class ClrStackImplWithICorDebug
{
private:
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;
}
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;
}
bool IsDMLEnabled();
-
#ifndef SOS_Assert
-#define SOS_Assert(x)
+#define SOS_Assert _ASSERTE
#endif
void ConvertToLower(__out_ecount(len) char *buffer, size_t len);
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.");
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.");
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 <sigaddr> <moduleaddr>.");
+ 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 <root> to <target>.");
+ 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 <command>");
- 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;
}
{
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;
}
// If it doesn't contain pointers, there isn't a GCDesc
PTR_MethodTable mt(pMT);
- _ASSERTE(mt->ContainsPointers());
-
return PTR_CGCDesc(mt);
}