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) { //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 }); } ClrHeap heap = DebuggerSession.Instance.Runtime.GetHeap(); var pointerSize = DebuggerSession.Instance.Runtime.PointerSize; // address of TEB (thread execution block) + pointer size ulong start = thread.StackBase; // address of TEB (thread execution block) + pointer size * 2 ulong stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { ulong tmp = start; start = stop; stop = tmp; } // ptr is a stack address. for (ulong ptr = start; ptr <= stop; ptr += (ulong)pointerSize) { HashSet <ulong> stackObjects = new HashSet <ulong>(); // fail to read the memory if (!heap.ReadPointer(ptr, out ulong obj)) { break; } // the object added already if (!stackObjects.Add(obj)) { continue; } // not an object ClrType type = heap.GetObjectType(obj); if (type == null) { continue; } // free space if (type.IsFree) { continue; } // All good, add it stackDetails.StackObjects.Add( new { Address = ptr, Object = obj, Name = type.Name, Value = new ClrObject(obj, type).Fields.Value }); } result.Add(stackDetails); } return result; })); }