void UpdateFrames_DbgThread() { dbgManager.Dispatcher.VerifyAccess(); bool raiseActiveFrameIndexChanged, raiseFramesChanged; DbgStackWalker stackWalker = null; DbgStackFrame[] newFrames = null; try { var thread = dbgManager.CurrentThread.Current; if (thread == null || thread.Process.State != DbgProcessState.Paused) { newFrames = Array.Empty <DbgStackFrame>(); } else { stackWalker = thread.CreateStackWalker(); newFrames = stackWalker.GetNextStackFrames(MaxShownFrames + 1); } lock (lockObj) { if (frames.Length > 0) { dbgManager.Close(frames); } int newActiveFrameIndex = GetFrameIndex(newFrames); // Always raise frames-changed event even if old and new arrays have 0 length. raiseFramesChanged = true; raiseActiveFrameIndexChanged = newActiveFrameIndex != activeFrameIndex; // Note that we keep the extra frame so we don't have to create a new array with one less // frame. If we got MaxShownFrames+1 frames, it's not very likely that the last one in the // array is actually the last frame. // Another solution is to create a custom IList<DbgStackFrame> that hides the last one // but that's not worth it. frames = newFrames; readOnlyFrames = newFrames.Length == 0 ? emptyFrames : new ReadOnlyCollection <DbgStackFrame>(newFrames); activeFrameIndex = newActiveFrameIndex; framesTruncated = newFrames.Length > MaxShownFrames; } } finally { stackWalker?.Close(); if (newFrames != null && frames != newFrames && newFrames.Length > 0) { dbgManager.Close(newFrames); } } if (raiseFramesChanged || raiseActiveFrameIndexChanged) { FramesChanged?.Invoke(this, new FramesChangedEventArgs(raiseFramesChanged, raiseActiveFrameIndexChanged)); } }
/// <summary> /// Gets the top stack frame or null if there's none /// </summary> /// <returns></returns> public DbgStackFrame GetTopStackFrame() { DbgStackWalker stackWalker = null; try { stackWalker = CreateStackWalker(); var frames = stackWalker.GetNextStackFrames(1); Debug.Assert(frames.Length <= 1); return(frames.Length == 0 ? null : frames[0]); } finally { stackWalker?.Close(); } }
/// <summary> /// Gets the first <paramref name="count"/> frames. /// The returned frame count can be less than <paramref name="count"/> if there's not enough frames available. /// </summary> /// <param name="count">Max number of frames to return</param> /// <returns></returns> public DbgStackFrame[] GetFrames(int count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count == 0) { return(Array.Empty <DbgStackFrame>()); } DbgStackWalker stackWalker = null; try { stackWalker = CreateStackWalker(); var frames = stackWalker.GetNextStackFrames(count); Debug.Assert(frames.Length <= count); return(frames); } finally { stackWalker?.Close(); } }
/// <summary> /// Gets the first non-null frame location. This location must be <see cref="DbgCodeLocation.Close"/>'d /// by the caller. /// </summary> /// <param name="thread">Thread</param> /// <returns></returns> public static (DbgCodeLocation location, int frameIndex) GetFirstFrameLocation(DbgThread thread) { DbgStackWalker stackWalker = null; var objsToFree = new List <DbgObject>(); try { stackWalker = thread.CreateStackWalker(); objsToFree.Add(stackWalker); int frameIndex = 0; while (frameIndex < 20) { // Usually the first frame contains a location and if not, the one after that. var frames = stackWalker.GetNextStackFrames(2); objsToFree.AddRange(frames); if (frames.Length == 0) { break; } foreach (var frame in frames) { var location = frame.Location; if (location != null) { return(location.Clone(), frameIndex); } frameIndex++; } } } finally { if (objsToFree.Count > 0) { thread.Process.DbgManager.Close(objsToFree); } } return(null, -1); }