private void OpenDumpFile() { if (!File.Exists(_dumpFile)) { Bail("The specified dump file '{0}' does not exist.", _dumpFile); } _target = DataTarget.LoadCrashDump(_dumpFile, CrashDumpReader.ClrMD); _context.WriteInfoLine("Opened dump file '{0}', architecture {1}, {2} CLR versions detected.", _dumpFile, _target.Architecture, _target.ClrVersions.Count); _context.DumpFile = _dumpFile; _context.TargetType = _target.IsHeapAvailable ? TargetType.DumpFile : TargetType.DumpFileNoHeap; if (!_target.IsHeapAvailable) { _context.WriteWarningLine( "This dump does not have heap information present. Most commands will not work. " + "Basic triage commands such as !pe, !clrstack, !threads are still available."); } if (_target.IsMinidump) { _context.WriteWarningLine( "This dump is a minidump, which means it's possible that module contents were " + "not included in the file. To get good information, make sure to put your modules " + "(.exe/.dll files) on the symbol path, not just the symbols (.pdb files)."); } }
public void Execute(CommandExecutionContext context) { context.EnterDbgEngNativeMode(); // In case the user is going to use sos/sosex, make sure they have // the appropriate DAC location configured. context.WriteLine("Loading DAC from " + context.DacLocation); context.NativeDbgEngTarget.ExecuteDbgEngCommand( ".cordll -ve -sd -lp " + Path.GetDirectoryName(context.DacLocation), context); // SOS hasn't necessarily been loaded at this point; try to load it // from the symbol server and then issue the appropriate .load command // so that the user can have it immediately available. string sosLocation = context.Runtime.TryDownloadSos(); if (sosLocation == null) { context.WriteWarningLine( "Unable to load SOS automatically from symbol server, " + "try to find and .load it manually if needed."); } else { context.WriteLine("Loading SOS from " + sosLocation); context.NativeDbgEngTarget.ExecuteDbgEngCommand( ".load " + sosLocation, context); } }
public bool Build(int chunkSize, string indexFileName, bool enumerateAllRoots) { if (chunkSize < 256 || chunkSize > 1048576 || chunkSize % 16 != 0) { _context.WriteErrorLine("Chunk size must be between 256 bytes and 1MB, and must be a multiple of 16."); return(false); } _chunkSize = chunkSize; _staticRootsEnumerated = enumerateAllRoots; Measure(() => { _allRoots = (from root in _heap.EnumerateRoots(enumerateStatics: enumerateAllRoots) select new SimplifiedRoot(root)).ToList(); }, "Enumerating roots"); // Build an index of N-byte chunks in all heap segments. The index is from chunk-id (int?) to // the first non-free object in the chunk (not to start of the chunk, which could be in the middle // of an object). If a chunk is completely empty or doesn't contain the start of any object, it // doesn't have an id. Measure(BuildChunks, "Building chunks"); // Traverse all object relationships on the heap from roots. For each chunk, specify which other // chunks contain references to objects in that chunk. When traversing this information, we need to // keep in mind that roots can also contain references to objects in the chunk -- we don't store this // information again because it's very easy to obtain by enumerating the roots. This decision can be // changed if root enumeration turns out to be slow when there are many roots. // Note that only live objects are being enumerated. For dead objects, it's not interesting to ask who // has a reference to the object -- because the referencing object is also dead. Measure(BuildChunkIndex, "Building chunk index"); DisplayStatistics(); if (!String.IsNullOrEmpty(indexFileName)) { Measure(() => Save(indexFileName), "Saving index to disk"); } else { _context.WriteWarningLine("You did not specify a file name, so the index will be stored only in memory. " + "If you plan to perform further analysis in another session, it is recommended that you store " + "the index to disk and later load it using the !lhi command."); } return(true); }
public void Execute(CommandExecutionContext context) { _context = context; ClrType type; if (!String.IsNullOrEmpty(TypeName)) { type = context.Heap.GetTypeByName(TypeName); if (type == null) { context.WriteErrorLine("There is no type named '{0}'.", TypeName); return; } } else { type = context.Heap.GetObjectType(ObjectAddress); if (type == null || String.IsNullOrEmpty(type.Name)) { context.WriteErrorLine("The specified address is not an object."); return; } } ulong mt = 0; if (type.IsObjectReference && !context.Runtime.ReadPointer(ObjectAddress, out mt)) { context.WriteWarningLine("Unable to retrieve MT for object."); } var size = type.GetSize(ObjectAddress); context.Write("Name: {0}", type.Name); var dynamicObj = context.Heap.GetDynamicObject(ObjectAddress); if (type.IsArray || dynamicObj.IsList() || dynamicObj.IsDictionary()) { context.WriteLink(" <display elements>", String.Format("!dumpcollection {0:x16}", ObjectAddress)); } context.WriteLine(); if (mt != 0) { context.WriteLine("MT: {0:x16}", mt); } context.WriteLine("Size: {0}(0x{1:x}) bytes", size, size); if (type.IsArray) { context.WriteLine("Array: size {0}, element type {1}", type.GetArrayLength(ObjectAddress), type.ComponentType != null ? type.ComponentType.Name : "<unknown>"); } context.WriteLine("Assembly: {0}", type.Module.FileName); if (type.HasSimpleValue) { context.WriteLine("Value: {0}", type.GetValue(ObjectAddress)); } if (!NoFields && type.Fields.Count > 0) { context.WriteLine("Fields:"); context.WriteLine("{0,-8} {1,-20} {2,-3} {3,-10} {4,-20} {5}", "Offset", "Type", "VT", "Attr", "Value", "Name"); foreach (var field in type.Fields) { DisplayFieldRecursively(field, new InstanceFieldValueForDisplayRetriever(ObjectAddress), field.Offset, depth: type.IsValueClass ? 1 : 0); } foreach (var field in type.ThreadStaticFields) { context.WriteLine("{0,-8:x} {1,-20} {2,-3} {3,-10} {4,-20:x16} {5}", field.Offset, field.GetFieldTypeNameTrimmed(), (field.IsOfPrimitiveType() || field.IsOfValueClass()) ? 1 : 0, "shared", "thrstatic", field.Name); foreach (var appDomain in context.Runtime.AppDomains) { foreach (var thread in context.Runtime.Threads) { DisplayFieldRecursively(field, new ThreadStaticFieldValueForDisplayRetriever(appDomain, thread), field.Offset); } } } foreach (var field in type.StaticFields) { context.WriteLine("{0,-8:x} {1,-20} {2,-3} {3,-10} {4,-20:x16} {5}", field.Offset, field.GetFieldTypeNameTrimmed(), (field.IsOfPrimitiveType() || field.IsOfValueClass()) ? 1 : 0, "shared", "static", field.Name); foreach (var appDomain in context.Runtime.AppDomains) { DisplayFieldRecursively(field, new StaticFieldValueForDisplayRetriever(appDomain), field.Offset); } } } }