public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { var runtime = DebuggerSession.Instance.Runtime; var infoModel = new TargetProcessInfoOperationModel(); infoModel.AppDomains = string.Concat(runtime.AppDomains.Select(ad => ad.Name + ", ")).TrimEnd(); infoModel.AppDomains = infoModel.AppDomains.Remove(infoModel.AppDomains.Length - 1, 1); infoModel.AppDomainsCount = runtime.AppDomains.Count; infoModel.ThreadsCount = runtime.Threads.Count; infoModel.ModulesCount = runtime.AppDomains.Sum(appDomain => appDomain.Modules.Count); infoModel.SymbolPath = runtime.DataTarget.SymbolLocator.SymbolPath; infoModel.ClrVersions = string.Concat(runtime.DataTarget.ClrVersions.Select(clrVer => clrVer.Version + ", ")).TrimEnd(); infoModel.ClrVersions = infoModel.ClrVersions.Remove(infoModel.ClrVersions.Length - 1, 1); infoModel.DacInfo = string.Concat(runtime.DataTarget.ClrVersions.Select(ver => ver.DacInfo.FileName + ", ")).TrimEnd(); infoModel.DacInfo = infoModel.DacInfo.Remove(infoModel.DacInfo.Length - 1, 1); infoModel.Architecture = runtime.DataTarget.Architecture.ToString(); infoModel.IsGcServer = runtime.ServerGC; infoModel.HeapCount = runtime.HeapCount; infoModel.DumpCreatedTime = DebuggerSession.Instance.AttachedTime.ToShortTimeString(); infoModel.PointerSize = runtime.PointerSize; var enumerable = from prop in infoModel.GetType().GetProperties() select new { Name = prop.Name, Value = prop.GetValue(infoModel) }; return enumerable.ToList(); }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { List<string> types = model.Types?.Split(';').ToList(); return await DebuggerSession.Instance.ExecuteOperation(() => { var heap = DebuggerSession.Instance.Heap; var enumerable = from o in heap.EnumerateObjectAddresses() let type = heap.GetObjectType(o) where type == null || types == null || types.Any(t => type.Name.Contains(t)) group o by type into g let size = g.Sum(o => (uint)g.Key.GetSize(o)) orderby size select new { Name = g.Key.Name, Size = size, Count = g.Count() }; var results = new List<object>(); foreach (var item in enumerable) { results.Add(item); if (token.IsCancellationRequested) break; } return results; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { var result = from r in DebuggerSession.Instance.Runtime.EnumerateMemoryRegions() where r.Type != ClrMemoryRegionType.ReservedGCSegment group r by r.Type.ToString() into g let total = g.Sum(p => (uint)p.Size) orderby total ascending select new { TotalSize = total, Count = g.Count().ToString(), Type = g.Key }; var list = result.ToList(); list.Add(new { TotalSize = result.Sum(item => item.TotalSize), Count = "", Type = "All" }); return list; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { ClrType type = DebuggerSession.Instance.Runtime.GetHeap().GetTypeByName(model.Types); if (type == null) return new List<object>(); var enumerable = from method in type.Methods where method != null select new { MetadataToken = method.MetadataToken, Signature = method.GetFullSignature(), CompilationType = method.CompilationType, IsStatic = method.IsStatic }; return enumerable.ToList(); }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { List<string> types = model.Types?.Split(';').ToList(); return await DebuggerSession.Instance.ExecuteOperation(() => { var enumerable = from appDomain in DebuggerSession.Instance.Runtime.AppDomains from module in appDomain.Modules let name = module.Name where !string.IsNullOrEmpty(name) && (types == null || types.Any(t => name.ToLower().Contains(t.ToLower()))) select new { Identifier = module.AssemblyId, Name = name.Substring(name.LastIndexOf('\\') + 1), FilePath = name.Substring(0, name.LastIndexOf('\\')), Size = module.Size, IsDynamic = module.IsDynamic }; return enumerable.ToList(); }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { var heap = DebuggerSession.Instance.Runtime.GetHeap(); var enumerable = from segment in heap.Segments let type = segment.IsEphemeral ? "Ephemeral" : segment.IsLarge ? "Large" : "Ephemeral" select new { Start = segment.Start, End = segment.End, Committed = segment.CommittedEnd, Reserved = segment.ReservedEnd, ProcessorAffinity = segment.ProcessorAffinity, Type = type, Length = segment.Length, NotInUse = segment.CommittedEnd - segment.End }; return enumerable.ToList(); }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { List<string> types = model.Types?.Split(';').ToList(); return await DebuggerSession.Instance.ExecuteOperation(() => { var generation = (int)customeParameter; var heap = DebuggerSession.Instance.Heap; var results = new List<object>(); foreach (var obj in heap.EnumerateObjectAddresses().Where(ptr => (generation != -1 && generation == heap.GetGeneration(ptr)) || generation == -1)) { if (token.IsCancellationRequested) break; var type = heap.GetObjectType(obj); if (type == null) continue; if (types?.Any(t => type.Name.ToLower().Contains(t.ToLower())) ?? true) results.Add(new { Address = obj, Type = type.Name, Generation = heap.GetGeneration(obj), Size = type.GetSize(obj) }); } return results; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { //TODO: Add support of inner exceptions var heap = DebuggerSession.Instance.Heap; var enumerable = from obj in heap.EnumerateObjectAddresses() let type = heap.GetObjectType(obj) where type != null && type.IsException let ex = heap.GetExceptionObject(obj) from frame in ex.StackTrace let o = new { Address = ex.Address, Name = ex.Type.Name, Message = ex.Message, HResult = ex.HResult, DisplayString = frame.DisplayString, InstructionPointer = frame.InstructionPointer, StackPointer = frame.StackPointer, Method = frame.Method, Kind = frame.Kind, ModuleName = frame.ModuleName } group o by o.Address; var results = new List<object>(); foreach (var item in enumerable) { results.Add(item); if (token.IsCancellationRequested) break; } return results; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { return await DebuggerSession.Instance.ExecuteOperation(() => { ClrType type = DebuggerSession.Instance.Runtime.GetHeap().GetTypeByName(model.Types); var results = new List<object>(); if (type == null) { results.Add(new { Address = "Can not find this type" }); return results; } ulong metadataToken = model.ObjectAddress; foreach (ClrMethod method in type.Methods) { if (token.IsCancellationRequested) break; // add also method name? if (!method.Type.Name.StartsWith(model.Types) || method.MetadataToken != metadataToken) continue; // This is the first instruction of the JIT'ed (or NGEN'ed) machine code. ulong startAddress = method.NativeCode; // use the IL to native mapping to get the end address if (method.ILOffsetMap == null) { results.Add(new { Address = "The method is not yet jited" }); break; } ulong endAddress = method.ILOffsetMap.Select(entry => entry.EndAddress).Max(); // the assembly code is in the range [startAddress, endAddress] inclusive. var dbgCtrl = (IDebugControl)DebuggerSession.Instance.DataTarget.DebuggerInterface; int size = Math.Max(1000000, (int)(endAddress + 1 - startAddress)); uint disassemblySize; ulong nextInstruction; var sb = new StringBuilder(size); var result = dbgCtrl.Disassemble(startAddress, DEBUG_DISASM.EFFECTIVE_ADDRESS, sb, size, out disassemblySize, out nextInstruction); var disassembly = sb.ToString().Split(' ').ToList(); disassembly.RemoveAll(s => s == ""); results.Add(new { Address = disassembly.Count > 1 ? disassembly[0] + " " + disassembly[1] : "", OpCode = disassembly.Count > 2 ? disassembly[2] : "", Instruction = disassembly.Count > 4 ? disassembly[3] + " " + disassembly[4] : disassembly.Count > 3 ? disassembly[3] : "", }); while (nextInstruction < endAddress) { startAddress = nextInstruction; result = dbgCtrl.Disassemble(startAddress, DEBUG_DISASM.EFFECTIVE_ADDRESS, sb, size, out disassemblySize, out nextInstruction); disassembly = sb.ToString().Split(' ').ToList(); disassembly.RemoveAll(s => s == ""); results.Add(new { Address = disassembly.Count > 1 ? disassembly[0] + " " + disassembly[1] : "", OpCode = disassembly.Count > 2 ? disassembly[2] : "", Instruction = disassembly.Count > 4 ? disassembly[3] + " " + disassembly[4] : disassembly.Count > 3 ? disassembly[3] : "", }); } } if (results.Count == 0) results.Add(new { Address = "The metadata token does not exist in this type" }); return results; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { //TODO: add support of local variables return await DebuggerSession.Instance.ExecuteOperation(() => { var result = new List<ClrStackDump>(); foreach (var thread in DebuggerSession.Instance.Runtime.Threads) { if (token.IsCancellationRequested) break; var stackDetails = new ClrStackDump(); stackDetails.StackFrames = new List<object>(); stackDetails.StackObjects = new List<object>(); foreach (var stackFrame in thread.StackTrace) { stackDetails.StackBase = thread.StackBase; stackDetails.StackLimit = thread.StackLimit; stackDetails.Exception = thread.CurrentException; stackDetails.OSThreadID = thread.IsAlive ? thread.OSThreadId.ToString() : "XXX"; stackDetails.ManagedThreadId = thread.ManagedThreadId; stackDetails.StackFrames.Add( new { StackPointer = stackFrame.StackPointer, InstructionPointer = stackFrame.InstructionPointer, DisplayString = stackFrame.DisplayString, //FileAndLine = source != null ? source.FilePath + ": " + source.LineNumber : "", Method = stackFrame.Method }); } // We'll need heap data to find objects on the stack. ClrHeap heap = DebuggerSession.Instance.Runtime.GetHeap(); var pointerSize = DebuggerSession.Instance.Runtime.PointerSize; // Walk each pointer aligned address on the stack. Note that StackBase/StackLimit // is exactly what they are in the TEB. This means StackBase > StackLimit on AMD64. ulong start = thread.StackBase; ulong stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { ulong tmp = start; start = stop; stop = tmp; } // Walk each pointer aligned address. Ptr is a stack address. for (ulong ptr = start; ptr <= stop; ptr += (ulong)pointerSize) { // Read the value of this pointer. If we fail to read the memory, break. The // stack region should be in the crash dump. ulong obj; if (!DebuggerSession.Instance.Runtime.ReadPointer(ptr, out obj)) break; // We check to see if this address is a valid object by simply calling // GetObjectType. If that returns null, it's not an object. ClrType type = heap.GetObjectType(obj); if (type == null) continue; // Don't print out free objects as there tends to be a lot of them on // the stack. if (type.IsFree) continue; stackDetails.StackObjects.Add( new { Address = ptr, Object = obj, Name = type.Name, Value = new ClrObject(obj, type).Fields.Value }); } result.Add(stackDetails); } return result; }); }
public async Task<IEnumerable<object>> Execute(OperationModel model, CancellationToken token, object customeParameter) { ulong size; if (!ulong.TryParse(customeParameter.ToString(), out size)) return null; var operation = App.Container.GetExportedValue<IDebuggerOperation>(OperationNames.GetObjectSize); if (operation == null) return null; List<string> types = model.Types?.Split(';').ToList(); return await DebuggerSession.Instance.ExecuteOperation(() => { var heap = DebuggerSession.Instance.Heap; var results = new List<object>(); var heapObjects = (from obj in heap.EnumerateObjectAddresses() let type = heap.GetObjectType(obj) where types?.Any(t => type != null && type.Name.ToLower().Contains(t.ToLower())) ?? true select obj).AsParallel(); //It will not work properly because in the end i must be serial because the debugger operation must run on the same thread that attach to dump\process //It will work if we are inspecting a dump file and the dump reader is ClrMD //Parallel.ForEach( // // The values to be aggregated // heapObjects, // // The local initial partial result // () => new List<object>(), // // The loop body // (obj, loopState, partialResult) => // { // if (token.IsCancellationRequested) // return partialResult; // var type = heap.GetObjectType(obj); // dynamic result = operation.Execute(new OperationModel { ObjectAddress = obj }, token, null).Result.FirstOrDefault(); // if (result != null && result.TotalSize >= size) // partialResult.Add(new { Address = obj, Type = type.Name, Generation = heap.GetGeneration(obj), Size = result.TotalSize }); // return partialResult; // }, // // The final step of each local context // (localPartialSum) => // { // // Enforce serial access to single, shared result // lock (lockObject) // { // results.AddRange(localPartialSum); // } // }); foreach (var obj in heapObjects) { if (token.IsCancellationRequested) break; var type = heap.GetObjectType(obj); if (type == null) continue; if (types?.Any(t => type.Name.ToLower().Contains(t.ToLower())) ?? true) { dynamic result = operation.Execute(new OperationModel { ObjectAddress = obj }, token, null).Result.FirstOrDefault(); if (result == null || result.TotalSize < size) continue; results.Add(new { Address = obj, Type = type.Name, Generation = heap.GetGeneration(obj), Size = result.TotalSize }); } } return results; }); }
public BaseOperationViewModel() { CancelOperationVisibility = Visibility.Collapsed; Model = new OperationModel(); _results = new List<object[]>(); }