IEnumerator IEnumerable.GetEnumerator() { MDbgThread[] ret = new MDbgThread[m_items.Count]; m_items.Values.CopyTo(ret, 0); Array.Sort(ret); return(ret.GetEnumerator()); }
public static ThreadSnapshot GetThreadSnapshot(MDbgThread thread) { var snapshot = new ThreadSnapshot(); snapshot.Id = thread.Id; long creation = 0, exit = 0, kernel = 0, user = 0; try { GetThreadTimes(thread.CorThread.Handle, out creation, out exit, out kernel, out user); } catch (Exception ex) { Console.WriteLine(" Exception on GetThreadTimes for thread ID {0} : {1}", thread.Id, ex); } snapshot.KernelTime = kernel; snapshot.UserTime = user; snapshot.StackTrace = new List<string>(); foreach (MDbgFrame frame in thread.Frames) { try { snapshot.StackTrace.Add(frame.Function.FullName); } catch { // no frame, so ignore } } return snapshot; }
// Update list w/ current callstack. Return an array of FramePair representing the callstack. // Run on worker thread. static FramePair[] GetFrameList(MDbgThread thread) { // Populate listbox with frames. MDbgFrame f = thread.BottomFrame; MDbgFrame af = thread.HaveCurrentFrame ? thread.CurrentFrame : null; System.Collections.ArrayList l = new System.Collections.ArrayList(); int i = 0; int depth = 20; bool verboseOutput = true; while (f != null && (depth == 0 || i < depth)) { string line; if (f.IsInfoOnly) { line = string.Format(CultureInfo.InvariantCulture, "[{0}]", f.ToString()); } else { string frameDescription = "<unknown>"; try { // Get IP info. uint ipNative; uint ipIL; CorDebugMappingResult result; f.CorFrame.GetNativeIP(out ipNative); f.CorFrame.GetIP(out ipIL, out result); string frameLocation = String.Format(CultureInfo.InvariantCulture, " N=0x{0:x}, IL=0x{1:x} ({2})", ipNative, ipIL, result.ToString()); // This may actually do a ton of work, including evaluating parameters. frameDescription = f.ToString(verboseOutput ? "v" : null) + frameLocation; } catch (System.Runtime.InteropServices.COMException) { if (f.Function != null) { frameDescription = f.Function.FullName; } } line = string.Format(CultureInfo.InvariantCulture, "{0}{1}. {2}", f.Equals(af) ? "*" : " ", i, frameDescription); ++i; } l.Add(new FramePair(f, line)); f = f.NextUp; } if (f != null && depth != 0) // means we still have some frames to show.... { l.Add(new FramePair(null, string.Format(CultureInfo.InvariantCulture, "displayed only first {0} frames. For more frames use -c switch", depth) )); } return (FramePair[]) l.ToArray(typeof(FramePair)); }
/// <summary> /// Unwind unmanaged frames within an native chain. /// </summary> /// <param name="thread">thread containing an unmanged frame</param> /// <param name="context">context containing the current context of the stack frame</param> /// <param name="endValue">address of the next managed frame</param> /// <returns>enumeration of MDbgFrames for the native frames</returns> /// <remarks>ICorDebug stackwalking only unwinds managed chains. /// A derived class can override this function to provide native stacktracing.</remarks> protected virtual IEnumerable <MDbgFrame> UnwindNativeFrames(MDbgThread thread, INativeContext context, long endValue) { // Base class can't unwind unmanaged chains. // A derived class can override and provide native stack unwinding. // Use: // 1) chain.RegisterSet to get the starting context. // 2) chain.GetStackRange(out start, out end); to get the stackrange to unwind to // 3) a native unwinder (such as DbgHelp.dll) to actually do the native stack unwinding. yield break; }
// Update list w/ current callstack public void RefreshCallstack(MDbgThread thread) { ListBox.ObjectCollection list = this.listBoxCallstack.Items; list.Clear(); // Set Title. this.Text = "Callstack on Thread #" + thread.Number + " (tid=" + thread.Id + ")"; // Populate listbox with frames. MDbgFrame f = thread.BottomFrame; MDbgFrame af = thread.HaveCurrentFrame ? thread.CurrentFrame : null; int i = 0; int depth = 20; bool verboseOutput = true; while (f != null && (depth == 0 || i < depth)) { string line; if (f.IsInfoOnly) { line = string.Format(CultureInfo.InvariantCulture, "[{0}]", f.ToString()); } else { string frameDescription = "<unknown>"; try { // This may actually do a ton of work, including evaluating parameters. frameDescription = f.ToString(verboseOutput ? "v" : null); } catch (System.Runtime.InteropServices.COMException) { if (f.Function != null) { frameDescription = f.Function.FullName; } } line = string.Format(CultureInfo.InvariantCulture, "{0}{1}. {2}", f.Equals(af) ? "*" : " ", i, frameDescription); ++i; } AddItem(line, f); f = f.NextUp; } if (f != null && depth != 0) // means we still have some frames to show.... { AddItem( string.Format(CultureInfo.InvariantCulture, "displayed only first {0} frames. For more frames use -c switch", depth), null); } }
public IEnumerable <MDbgFrame> EnumerateFrames(MDbgThread thread) { IMDbgFrameFactory factory; if (thread.CorThread.IsV3) { factory = new MDbgV3FrameFactory(); return(factory.EnumerateFrames(thread)); } else { factory = new MDbgV2FrameFactory(); return(factory.EnumerateFrames(thread)); } }
/// <summary> /// Creates a new V2 StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> public IEnumerable <MDbgFrame> EnumerateFrames(MDbgThread thread) { // To do stackwalking using V2 ICorDebug, we enumerate through the chains, // and then enumerate each frame in every chain CorChain chain = null; try { chain = thread.CorThread.ActiveChain; } catch (System.Runtime.InteropServices.COMException ce) { // Sometimes we cannot get the callstack. For example, the thread // may not be scheduled yet (CORDBG_E_THREAD_NOT_SCHEDULED), // or the debuggee may be corrupt (CORDBG_E_BAD_THREAD_STATE). // In either case, we'll ignore the problem and return an empty callstack. Debug.Assert(ce.ErrorCode == (int)HResult.CORDBG_E_BAD_THREAD_STATE || ce.ErrorCode == (int)HResult.CORDBG_E_THREAD_NOT_SCHEDULED); } while (chain != null) { if (chain.IsManaged) { // Enumerate managed frames // A chain may have 0 managed frames. CorFrame f = chain.ActiveFrame; while (f != null) { MDbgFrame frame = new MDbgILFrame(thread, f); f = f.Caller; yield return(frame); } } else { // ICorDebug doesn't unwind unmanaged frames. Need to let a native-debug component handle that. foreach (MDbgFrame frame in UnwindNativeFrames(thread, chain)) { yield return(frame); } } // Move to next chain chain = chain.Caller; } }
/// <summary> /// We want to be able to interleave native and internal frames together and also minimize the exposure of internal frames. /// This method takes the internal frame cache and interleaves them with the native frames returned from UnwindNativeFrames. In this /// case, this function will merely return all of the internal frames since the interop extension isn't loaded. /// <param name="thread">current thread that we're creating the stackwalker on</param> /// <param name="internalFrameCache">the internal frame cache</param> /// <param name="nativeFrames">native frames returned from UnwindNativeFrames</param> /// <returns>enumeration of the interleaved internal and native MDbgFrames</returns> /// </summary> protected virtual IEnumerable <MDbgFrame> StitchInternalFrames(MDbgThread thread, IEnumerator <CorFrame> internalFrameCache, IEnumerable <MDbgFrame> nativeFrames) { if (internalFrameCache == null) { yield break; } MDbgFrame mf = null; // iterate through the internal frames internalFrameCache.Reset(); while (internalFrameCache.MoveNext()) { mf = thread.LookupFrame(internalFrameCache.Current); yield return(mf); } }
/// <summary> /// Gets the MDbgThread with the given ThreadId. /// </summary> /// <param name="threadId">The ThreadId to look up.</param> /// <returns>The MDbgThread.</returns> public MDbgThread GetThreadFromThreadId(int threadId) { // This sometimes fails because we're looking for a thread don't recognize. // Need to offer lazy create semantics here. MDbgThread te = (MDbgThread)m_items[threadId]; if (te == null) { CorThread t = m_process.CorProcess.GetThread(threadId); if (t != null) { Register(t); te = (MDbgThread)m_items[threadId]; } } return(te); }
internal void UnRegister(CorThread t) { m_items.Remove(t.Id); if (m_active != null && m_active.CorThread.Id == t.Id) { m_active = null; } }
internal MDbgILFrame(MDbgThread thread, CorFrame frame) : base(thread) { Debug.Assert(frame != null); m_frame = frame; }
private static void InternalWhereCommand(MDbgThread thread, int depth, bool verboseOutput) { Debug.Assert(thread != null); WriteOutput("Thread [#:" + g_threadNickNames.GetThreadName(thread) + "]"); MDbgFrame af = thread.HaveCurrentFrame ? thread.CurrentFrame : null; MDbgFrame f = thread.BottomFrame; int i = 0; while (f != null && (depth == 0 || i < depth)) { string line; if (f.IsInfoOnly) { if (!ShowInternalFrames) { // in cases when we don't want to show internal frames, we'll skip them f = f.NextUp; continue; } line = string.Format(CultureInfo.InvariantCulture, " {0}", f.ToString()); } else { string frameDescription = f.ToString(verboseOutput ? "v" : null); line = string.Format(CultureInfo.InvariantCulture, "{0}{1}. {2}", f.Equals(af) ? "*" : " ", i, frameDescription); ++i; } WriteOutput(line); f = f.NextUp; } if (f != null && depth != 0) // means we still have some frames to show.... { WriteOutput(string.Format(CultureInfo.InvariantCulture, "displayed only first {0} frames. For more frames use -c switch", depth)); } }
internal void Clear() { m_items.Clear(); m_active = null; m_freeThreadNumber = 0; }
public string GetThreadName(MDbgThread thread) { Debug.Assert(thread != null); if (thread == null) { throw new ArgumentException(); } string nick = GetNickNameFromThreadNumber(thread.Number); if (nick.Length == 0) { // no nick name return thread.Number.ToString(CultureInfo.InvariantCulture); } else { return nick; } }
private static string GetThreadStateDescriptionString(MDbgThread thread) { CorThread t = thread.CorThread; StringBuilder debuggerState = new StringBuilder(); StringBuilder clientState = new StringBuilder(); if (t.DebugState == CorDebugThreadState.THREAD_SUSPEND) debuggerState.Append("(SUSPENDED)"); try { CorDebugUserState userState = t.UserState; if ((userState & CorDebugUserState.USER_SUSPENDED) != 0) clientState.Append("user suspended"); if ((userState & CorDebugUserState.USER_WAIT_SLEEP_JOIN) != 0) { if (clientState.Length > 0) clientState.Append(", "); clientState.Append("waiting"); } } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)HResult.CORDBG_E_BAD_THREAD_STATE) throw; clientState.Append("in bad thread state"); } StringBuilder result = debuggerState; if (clientState.Length > 0) { if (result.Length > 0) result.Append(" "); result.Append("[").Append(clientState.ToString()).Append("]"); } return result.ToString(); }
/// <summary> From time to time the thread may be in invalid state. </summary> public static bool CheckValidState(MDbgThread th) { try { th.CorThread.UserState.ToString(); return true; } catch (COMException e) { // The state of the thread is invalid. if ((uint)e.ErrorCode == 0x8013132D) { return false; } } return true; }
public static StackSample GetThreadStacks(MDbgThread t, bool withArgs = false, bool originFirst = false) { //Console.WriteLine("Callstack for Thread {0}", t.Id.ToString()); StackSample sample = new StackSample { ThreadId = t.Id, Time = DateTime.Now }; MDbgFrame[] frames = new MDbgFrame[0]; try { frames = t.Frames.ToArray(); } catch (Exception ex) { DebuggerUtils.HandleExceptionSilently(ex); } foreach (MDbgFrame f in frames) { try { string frame = GetFrameString(f, withArgs).Trim(); if (string.IsNullOrWhiteSpace(frame)) frame = "[Missing frame]"; if (originFirst) sample.CallStack.Insert(0, frame); else sample.CallStack.Add(frame); } catch (Exception ex) { DebuggerUtils.HandleExceptionSilently(ex); } } return sample; }
public IEnumerable<MDbgFrame> EnumerateFrames(MDbgThread thread) { IMDbgFrameFactory factory; if (thread.CorThread.IsV3) { factory = new MDbgV3FrameFactory(); return factory.EnumerateFrames(thread); } else { factory = new MDbgV2FrameFactory(); return factory.EnumerateFrames(thread); } }
internal void SetActiveThread(CorThread thread) { if (thread == null) { m_active = null; } else { m_active = GetThreadFromThreadId(thread.Id); } lock (this.m_process) { m_frameFactory.InvalidateStackWalkers(); // @TODO can this line be removed??? } }
/// <summary> /// Unwind unmanaged frames within an native chain. /// </summary> /// <param name="thread">thread containing an unmanged frame</param> /// <param name="context">context containing the current context of the stack frame</param> /// <param name="endValue">address of the next managed frame</param> /// <returns>enumeration of MDbgFrames for the native frames</returns> /// <remarks>ICorDebug stackwalking only unwinds managed chains. /// A derived class can override this function to provide native stacktracing.</remarks> protected virtual IEnumerable<MDbgFrame> UnwindNativeFrames(MDbgThread thread, INativeContext context, long endValue) { // Base class can't unwind unmanaged chains. // A derived class can override and provide native stack unwinding. // Use: // 1) chain.RegisterSet to get the starting context. // 2) chain.GetStackRange(out start, out end); to get the stackrange to unwind to // 3) a native unwinder (such as DbgHelp.dll) to actually do the native stack unwinding. yield break; }
/// <summary> /// Creates a frame cache for the given thread /// </summary> /// <param name="frames">Enumeration of frames</param> /// <param name="thread">Thread associated the the stack walker</param> public FrameCache(IEnumerable<MDbgFrame> frames, MDbgThread thread) { m_frameEnum = frames.GetEnumerator(); m_thread = thread; }
/// <summary> /// We want to be able to interleave native and internal frames together and also minimize the exposure of internal frames. /// This method takes the internal frame cache and interleaves them with the native frames returned from UnwindNativeFrames. In this /// case, this function will merely return all of the internal frames since the interop extension isn't loaded. /// <param name="thread">current thread that we're creating the stackwalker on</param> /// <param name="internalFrameCache">the internal frame cache</param> /// <param name="nativeFrames">native frames returned from UnwindNativeFrames</param> /// <returns>enumeration of the interleaved internal and native MDbgFrames</returns> /// </summary> protected virtual IEnumerable<MDbgFrame> StitchInternalFrames(MDbgThread thread, IEnumerator<CorFrame> internalFrameCache, IEnumerable<MDbgFrame> nativeFrames) { if (internalFrameCache == null) { yield break; } MDbgFrame mf = null; // iterate through the internal frames internalFrameCache.Reset(); while (internalFrameCache.MoveNext()) { mf = thread.LookupFrame(internalFrameCache.Current); yield return mf; } }
public IEnumerable<MDbgFrame> EnumerateFrames(MDbgThread thread) { MDbgFrame frameToReturn = null; long pEndVal = Int64.MinValue; CorStackWalk m_v3StackWalk = thread.CorThread.CreateStackWalk(CorStackWalkType.ExtendedV3StackWalk); INativeContext ctxUnmanagedChain = null, currentCtx = null; IEnumerable<MDbgFrame> nFrames; List<CorFrame> iFrameCache = new List<CorFrame>(); //storage cache for internal frames // we need to call MoveNext() to make the enumerator valid while ((m_v3StackWalk != null) && (m_v3StackWalk.MoveNext())) { CorFrame frame = m_v3StackWalk.Current; if (frame != null) { // If we get a RuntimeUnwindableFrame, then the stackwalker is also stopped at a native // stack frame, but it's a native stack frame which requires special unwinding help from // the runtime. When a debugger gets a RuntimeUnwindableFrame, it should use the runtime // to unwind, but it has to do inspection on its own. It can call // ICorDebugStackWalk::GetContext() to retrieve the context of the native stack frame. if (frame.FrameType != CorFrameType.RuntimeUnwindableFrame) { // check for an internal frame...if the internal frame happens to come after the last // managed frame, any call to GetContext() will assert if (frame.FrameType != CorFrameType.InternalFrame) { // we need to store the CONTEXT when we're at a managed frame, if there's an internal frame // after this, then we'll need this CONTEXT currentCtx = m_v3StackWalk.GetContext(); } else if ((frame.FrameType == CorFrameType.InternalFrame) && (ctxUnmanagedChain != null)) { // we need to check to see if this internal frame could have been sandwiched between // native frames, this will be the case if ctxUnmanagedChain is not null // we need to store ALL internal frames until we hit the next managed frame iFrameCache.Add(frame); continue; } // else we'll use the 'stored' currentCtx if we're at an InternalFrame pEndVal = Int64.MaxValue; if (currentCtx != null) { pEndVal = currentCtx.StackPointer.ToInt64(); } //check to see if we have native frames to unwind nFrames = UnwindNativeFrames(thread, ctxUnmanagedChain, pEndVal); foreach (MDbgFrame fr in StitchInternalFrames(thread,iFrameCache.GetEnumerator(),nFrames)) { yield return fr; } //clear out the CONTEXT and native frame cache ctxUnmanagedChain = null; nFrames = null; iFrameCache.Clear(); //return the managed frame frameToReturn = thread.LookupFrame(frame); yield return frameToReturn; } else { continue; } } // If we don't get a frame, then the stackwalker is stopped at a native stack frame. else { // we've hit a native frame, we need to store the CONTEXT ctxUnmanagedChain = m_v3StackWalk.GetContext(); //we need to invalidate the currentCtx since it won't be valid on the next loop iteration currentCtx = null; } } //end while // we may have native frames at the end of the stack nFrames = UnwindNativeFrames(thread, ctxUnmanagedChain, Int64.MaxValue); foreach (MDbgFrame frame in StitchInternalFrames(thread, iFrameCache.GetEnumerator(), nFrames)) { yield return frame; } nFrames = null; ctxUnmanagedChain = null; // End of stackwalk. Return null as sentinel. yield return null; }
private static ExceptionInfo GetExceptionInfo(MDbgThread activeThread, MDbgValue ex) { ExceptionInfo exinfo = new ExceptionInfo(); exinfo.ExType = ex.TypeName; exinfo.Function = (ex.GetField("_exceptionMethodString").IsNull ? null : ex.GetField("_exceptionMethodString").ToString()); exinfo.Message = (ex.GetField("_message").IsNull ? null : ex.GetField("_message").GetStringValue(false)); exinfo.Source = (ex.GetField("_source").IsNull ? null : ex.GetField("_source").ToString()); //StringBuilder sbCallstack = new StringBuilder(); //try //{ // if (activeThread != null) // activeThread.Frames.ToList().ForEach(f => sbCallstack.AppendLine(f.ToString())); //} //catch (Exception ex1) //{ // DebuggerUtils.HandleExceptionSilently(ex1); //} exinfo.Callstack = DebuggerUtils.GetThreadStacks(activeThread, true).ToString(); return exinfo; }
/// <summary> /// Creates a new stack walker object. /// </summary> /// <param name="factory">FrameFactory owning this walker</param> /// <param name="thread">Thread associated with the stackwalker</param> public MDbgV2StackWalker(MDbgFrameFactoryBase factory, MDbgThread thread) : base(factory, thread) { }
private static string GetStringFromException(MDbgThread activeThread, MDbgValue ex) { ExceptionInfo exinfo = GetExceptionInfo(activeThread, ex); StringBuilder retVal = new StringBuilder(); string exceptionType = exinfo.ExType; if (!string.IsNullOrWhiteSpace(exinfo.Function)) { retVal.AppendLine("at function: " + exinfo.Function); } if (!string.IsNullOrWhiteSpace(exinfo.Message)) { retVal.AppendLine("Message: " + exinfo.Message); } if (!string.IsNullOrWhiteSpace(exinfo.Source)) { retVal.AppendLine("in source file: " + exinfo.Source); } if (!string.IsNullOrWhiteSpace(exinfo.Callstack)) { retVal.AppendLine("Callstack: " + exinfo.Callstack); } return retVal.ToString(); }
public void SetThreadNickName(string nickName, MDbgThread thread) { Debug.Assert(thread != null); if (thread == null) throw new ArgumentException(); { NickNamesHash.Remove(GetNickNameFromThreadNumber(thread.Number)); // remove old nick-name, if any } if (nickName == null || nickName.Length == 0) { return; // we just want to remove nickname } if (IsNumber(nickName)) { throw new MDbgShellException("invalid nickname"); } if (NickNamesHash.ContainsKey(nickName)) { throw new MDbgShellException("nickname already exists"); } NickNamesHash.Add(nickName, Debugger.Processes.Active.Threads.Active.Number); }
private string PrintObject(int indentLevel, CorObjectValue ov, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); bool fNeedToResumeThreads = true; // Print generics-aware type. string name = InternalUtil.PrintCorType(this.m_process, ov.ExactType); StringBuilder txt = new StringBuilder(); txt.Append(name); if (expandDepth > 0) { // we gather the field info of the class before we do // funceval since funceval requires running the debugger process // and this in turn can cause GC and invalidate our references. StringBuilder expandedDescription = new StringBuilder(); if (IsComplexType) { foreach (MDbgValue v in GetFields()) { expandedDescription.Append("\n").Append(IndentedString(indentLevel + 1, v.Name)). Append("=").Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, false))); } } // if the value we're printing is a nullable type that has no value (is null), we can't do a func eval // to get its value, since it will be boxed as a null pointer. We already have the information we need, so // we'll just take care of it now. Note that ToString() for null-valued nullable types just prints the // empty string. // bool hasValue = (bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue()); if (IsNullableType(ov.ExactType) && !(bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue())) { txt.Append(" < >"); } else if (ov.IsValueClass && canDoFunceval) // we could display even values for real Objects, but we will just show // "description" for valueclasses. { CorClass cls = ov.ExactType.Class; CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer; MetadataType mdType = importer.GetType(cls.Token) as MetadataType; if (mdType.ReallyIsEnum) { txt.AppendFormat(" <{0}>", InternalGetEnumString(ov, mdType)); } else if (m_process.IsRunning) { txt.Append(" <N/A during run>"); } else { MDbgThread activeThread = m_process.Threads.Active; CorValue thisValue; CorHeapValue hv = ov.CastToHeapValue(); if (hv != null) { // we need to pass reference value. CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION); thisValue = handle; } else { thisValue = ov; } try { CorEval eval = m_process.Threads.Active.CorThread.CreateEval(); m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_SUSPEND, activeThread.CorThread); MDbgFunction toStringFunc = m_process.ResolveFunctionName(null, "System.Object", "ToString", thisValue.ExactType.Class.Module.Assembly.AppDomain)[0]; Debug.Assert(toStringFunc != null); // we should be always able to resolve ToString function. eval.CallFunction(toStringFunc.CorFunction, new CorValue[] { thisValue }); m_process.Go(); do { m_process.StopEvent.WaitOne(); if (m_process.StopReason is EvalCompleteStopReason) { CorValue cv = eval.Result; Debug.Assert(cv != null); MDbgValue mv = new MDbgValue(m_process, cv); string valName = mv.GetStringValue(0); // just purely for esthetical reasons we 'discard' " if (valName.StartsWith("\"") && valName.EndsWith("\"")) { valName = valName.Substring(1, valName.Length - 2); } txt.Append(" <").Append(valName).Append(">"); break; } if ((m_process.StopReason is ProcessExitedStopReason) || (m_process.StopReason is EvalExceptionStopReason)) { txt.Append(" <N/A cannot evaluate>"); break; } // hitting bp or whatever should not matter -- we need to ignore it m_process.Go(); }while (true); } catch (COMException e) { // Ignore cannot copy a VC class error - Can't copy a VC with object refs in it. if (e.ErrorCode != (int)HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) { throw; } } catch (System.NotImplementedException) { fNeedToResumeThreads = false; } finally { if (fNeedToResumeThreads) { // we need to resume all the threads that we have suspended no matter what. m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, activeThread.CorThread); } } } } txt.Append(expandedDescription.ToString()); } return(txt.ToString()); }
// Helper to set the debug state and ignore certain errors. // Throws on error. static void SetDebugStateWrapper(MDbgThread t, CorDebugThreadState newState, bool showWarnings) { if ((newState == CorDebugThreadState.THREAD_SUSPEND) && ((t.CorThread.UserState & CorDebugUserState.USER_UNSAFE_POINT) != 0)) { // Hard-suspending a thread while the thread is not at GC-safe point is bad. // If the users resumes a process and the GC triggers, the GC suspension logic // will not be able to suspend because it will wait forever on the thread that // is not at the GC safe point. However, in this scenario, a debugger can always // async-break and resume the suspended thread to avoid a live lock. So we just // issue a warning here. if (showWarnings) { WriteOutput("Warning: You are suspending Thread " + t.Number + " at an unsafe spot."); WriteOutput("Until you resume this thread, the process may block if a garbage collection occurs."); WriteOutput("To unblock the process, you need to asynchronously break the process (e.g. Ctrl-C) and resume the thread."); } } try { t.CorThread.DebugState = newState; } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.CORDBG_E_BAD_THREAD_STATE) // CORDBG_E_BAD_THREAD_STATE { if (showWarnings) { WriteOutput(MDbgOutputConstants.Ignore, "Warning: Thread " + t.Number + " can't be set to " + newState); } return; // thread is unavailable, ignore it } throw; // let error propogate up. } }
/// <summary> /// Create a new instance of the ThreadCreatedStopReason class. /// </summary> /// <param name="thread">The thread that has been created.</param> public ThreadCreatedStopReason(MDbgThread thread) { Debug.Assert(thread != null); m_thread = thread; }
IEnumerator IEnumerable.GetEnumerator() { MDbgThread[] ret = new MDbgThread[m_items.Count]; m_items.Values.CopyTo(ret, 0); Array.Sort(ret); return ret.GetEnumerator(); }
public IEnumerable <MDbgFrame> EnumerateFrames(MDbgThread thread) { MDbgFrame frameToReturn = null; long pEndVal = Int64.MinValue; CorStackWalk m_v3StackWalk = thread.CorThread.CreateStackWalk(CorStackWalkType.ExtendedV3StackWalk); INativeContext ctxUnmanagedChain = null, currentCtx = null; IEnumerable <MDbgFrame> nFrames; List <CorFrame> iFrameCache = new List <CorFrame>(); //storage cache for internal frames // we need to call MoveNext() to make the enumerator valid while ((m_v3StackWalk != null) && (m_v3StackWalk.MoveNext())) { CorFrame frame = m_v3StackWalk.Current; if (frame != null) { // If we get a RuntimeUnwindableFrame, then the stackwalker is also stopped at a native // stack frame, but it's a native stack frame which requires special unwinding help from // the runtime. When a debugger gets a RuntimeUnwindableFrame, it should use the runtime // to unwind, but it has to do inspection on its own. It can call // ICorDebugStackWalk::GetContext() to retrieve the context of the native stack frame. if (frame.FrameType != CorFrameType.RuntimeUnwindableFrame) { // check for an internal frame...if the internal frame happens to come after the last // managed frame, any call to GetContext() will assert if (frame.FrameType != CorFrameType.InternalFrame) { // we need to store the CONTEXT when we're at a managed frame, if there's an internal frame // after this, then we'll need this CONTEXT currentCtx = m_v3StackWalk.GetContext(); } else if ((frame.FrameType == CorFrameType.InternalFrame) && (ctxUnmanagedChain != null)) { // we need to check to see if this internal frame could have been sandwiched between // native frames, this will be the case if ctxUnmanagedChain is not null // we need to store ALL internal frames until we hit the next managed frame iFrameCache.Add(frame); continue; } // else we'll use the 'stored' currentCtx if we're at an InternalFrame pEndVal = Int64.MaxValue; if (currentCtx != null) { pEndVal = currentCtx.StackPointer.ToInt64(); } //check to see if we have native frames to unwind nFrames = UnwindNativeFrames(thread, ctxUnmanagedChain, pEndVal); foreach (MDbgFrame fr in StitchInternalFrames(thread, iFrameCache.GetEnumerator(), nFrames)) { yield return(fr); } //clear out the CONTEXT and native frame cache ctxUnmanagedChain = null; nFrames = null; iFrameCache.Clear(); //return the managed frame frameToReturn = thread.LookupFrame(frame); yield return(frameToReturn); } else { continue; } } // If we don't get a frame, then the stackwalker is stopped at a native stack frame. else { // we've hit a native frame, we need to store the CONTEXT ctxUnmanagedChain = m_v3StackWalk.GetContext(); //we need to invalidate the currentCtx since it won't be valid on the next loop iteration currentCtx = null; } } //end while // we may have native frames at the end of the stack nFrames = UnwindNativeFrames(thread, ctxUnmanagedChain, Int64.MaxValue); foreach (MDbgFrame frame in StitchInternalFrames(thread, iFrameCache.GetEnumerator(), nFrames)) { yield return(frame); } nFrames = null; ctxUnmanagedChain = null; // End of stackwalk. Return null as sentinel. yield return(null); }
internal void SetActiveThread(CorThread thread) { if (thread == null) { m_active = null; } else { m_active = GetThreadFromThreadId(thread.Id); } InvalidateAllStacks(); }
/// <summary> /// Creates an instance of class MDbgFramebase. /// </summary> /// <param name="thread"></param> protected MDbgFrameBase(MDbgThread thread) { Debug.Assert(thread != null); m_thread = thread; }
/// <summary> /// Creates a new V2 StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> override public IMDbgStackWalker CreateStackWalker(MDbgThread thread) { return(new MDbgV2StackWalker(this, thread)); }
/// <summary> /// Creates a new V2 StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> public IEnumerable<MDbgFrame> EnumerateFrames(MDbgThread thread) { // To do stackwalking using V2 ICorDebug, we enumerate through the chains, // and then enumerate each frame in every chain CorChain chain = null; try { chain = thread.CorThread.ActiveChain; } catch (System.Runtime.InteropServices.COMException ce) { // Sometimes we cannot get the callstack. For example, the thread // may not be scheduled yet (CORDBG_E_THREAD_NOT_SCHEDULED), // or the debuggee may be corrupt (CORDBG_E_BAD_THREAD_STATE). // In either case, we'll ignore the problem and return an empty callstack. Debug.Assert(ce.ErrorCode == (int)HResult.CORDBG_E_BAD_THREAD_STATE || ce.ErrorCode == (int)HResult.CORDBG_E_THREAD_NOT_SCHEDULED); } while (chain != null) { if (chain.IsManaged) { // Enumerate managed frames // A chain may have 0 managed frames. CorFrame f = chain.ActiveFrame; while (f != null) { MDbgFrame frame = new MDbgILFrame(thread, f); f = f.Caller; yield return frame; } } else { // ICorDebug doesn't unwind unmanaged frames. Need to let a native-debug component handle that. foreach (MDbgFrame frame in UnwindNativeFrames(thread, chain)) { yield return frame; } } // Move to next chain chain = chain.Caller; } }
/// <summary> /// Gets an array of strings containing information about each level of the call stack. /// </summary> /// <param name="thread">The thread to get the call stack from</param> /// <returns>An array of strings containing information about each level of the call stack.</returns> private string[] GetStackTrace(MDbgThread thread) { List<string> stackTrace = new List<string>(); MDbgFrame af = thread.HaveCurrentFrame ? thread.CurrentFrame : null; MDbgFrame f = thread.BottomFrame; int i = 0; while (f != null) { if (f.IsInfoOnly) { f = f.NextUp; continue; } string functionName = f.Function.FullName; int sourceLine = -1; if (f.SourcePosition != null) sourceLine = f.SourcePosition.Line; string line = string.Format(CultureInfo.InvariantCulture, "{0}{1}. {2}:{3}", f.Equals(af) ? "*" : " ", i, functionName, sourceLine == -1 ? "" : sourceLine.ToString() ); stackTrace.Add(line); f = f.NextUp; ++i; } return stackTrace.ToArray(); }
/// <summary> /// Creates a stack walker and associates the walker with the frame factory and a thread. /// </summary> /// <param name="factory">FrameFactory that created the stackwalker</param> /// <param name="thread">Thread associated the the stack walker</param> protected MDbgStackWalkerBase(MDbgFrameFactoryBase factory, MDbgThread thread) { m_thread = thread; m_factory = factory; m_logicalStopClock = factory.m_logicalStopClock; }
public static ThreadSnapshot GetThreadSnapshot(MDbgThread thread) { var snapshot = new ThreadSnapshot(); snapshot.Id = thread.Id; long creation, exit, kernel, user; GetThreadTimes(thread.CorThread.Handle, out creation, out exit, out kernel, out user); snapshot.KernelTime = kernel; snapshot.UserTime = user; snapshot.StackTrace = new List<string>(); foreach (MDbgFrame frame in thread.Frames) { try { snapshot.StackTrace.Add(frame.Function.FullName); } catch { // no frame, so ignore } } return snapshot; }
/// <summary> /// Creates a new StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> public abstract IMDbgStackWalker CreateStackWalker(MDbgThread thread);
/// <summary> /// Creates a frame cache for the given thread /// </summary> /// <param name="frames">Enumeration of frames</param> /// <param name="thread">Thread associated the the stack walker</param> public FrameCache(IEnumerable <MDbgFrame> frames, MDbgThread thread) { m_frameEnum = frames.GetEnumerator(); m_thread = thread; }
/// <summary> /// Creates a new V2 StackWalker. /// </summary> /// <param name="thread">a thread object associated with the stackwalker</param> /// <returns>object implementing MDbgStackWalker interface</returns> public override IMDbgStackWalker CreateStackWalker(MDbgThread thread) { return new MDbgV2StackWalker(this, thread); }