// The function verifies that the stackwalker for this thread is "current". The stack-walker will become // invalid when a debugger performs an operation that invalidats active stackwalkers. Examples of such // operations are: // - calling Continue(), calling SetIP() or calling RefreshStack() methods. // // If the current stack-walker is not current, a new stack-walker is created for the thread. The function // also sets the current frame if the stack walker is refreshed. // private void EnsureCurrentStackWalker() { if (m_stackWalker != null && m_stackWalker.IsUsable) { return; } m_stackWalker = m_threadMgr.FrameFactory.CreateStackWalker(this); // initialize the frame index to be the invalid index m_currentFrameIndex = -1; // set m_currentFrame to first non-virtual frame MDbgFrame f = m_stackWalker.GetFrame(0); if (f == null) { return; } // we have at least one frame, so set the frame index to 0 m_currentFrameIndex = 0; while (f != null && f.IsInfoOnly) { f = f.NextUp; if (f != null) { ++m_currentFrameIndex; } } }
/// <summary> /// Moves the Current Frame up or down. /// </summary> /// <param name="down">Moves frame down if true, else up.</param> public void MoveCurrentFrame(bool down) { lock (m_stackLock) { MDbgFrame f = CurrentFrame; Debug.Assert(!f.IsInfoOnly); bool frameCanBeMoved; int idx = m_currentFrameIndex; if (down) { do { --idx; }while (idx >= 0 && m_stackWalker.GetFrame(idx).IsInfoOnly); frameCanBeMoved = (idx >= 0); } else { do { ++idx; f = m_stackWalker.GetFrame(idx); } while (f != null && f.IsInfoOnly); frameCanBeMoved = f != null; } if (!frameCanBeMoved) { throw new MDbgException("Operation hit " + (down ? "bottom" : "top") + " of the stack."); } m_currentFrameIndex = idx; } }
/// <summary> /// Finds the leaf-most frame in the stack. /// </summary> /// <returns>the top-most frame in the stack</returns> protected MDbgFrame ReturnLeafFrame() { MDbgFrame leafFrame = null; CorChain c = null; try { c = 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 CLR 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); } if (c != null) { if (!c.IsManaged) { leafFrame = FillAndGetLeafFrameFromNativeChain(c); } if (leafFrame == null) { // if we still have no frame, we'll get one from the managed code. while (c != null && (!c.IsManaged || (c.IsManaged && c.ActiveFrame == null)) ) { c = c.Caller; } if (c == null) { leafFrame = null; } else { Debug.Assert(c != null && c.IsManaged); leafFrame = new MDbgILFrame(Thread, c.ActiveFrame); } } } else { leafFrame = null; } return(leafFrame); }
/// <summary> /// Returns the caller of the frame. /// </summary> /// <param name="frame">frame to return the caller of</param> /// <returns>the caller of the frame or null if the frame is the last frame in the chain</returns> protected virtual MDbgFrame GetFrameCaller(MDbgFrame frame) { Debug.Assert(frame != null); CorFrame f = frame.CorFrame.Caller; if (f == null) { return(null); } return(new MDbgILFrame(Thread, f)); }
/// <summary> /// The function returns the index of the frame in the stack. /// </summary> /// <param name="frame">A frame returned with call to GetFrame.</param> /// <returns>an index of the frame</returns> /// <remarks> /// If the frame passed in was not created with this StackWalker object the function /// throws an exception. /// </remarks> public int GetFrameIndex(MDbgFrame frame) { CheckUsability(); if (m_frameCache != null) { for (int i = 0; i < m_frameCache.Count; ++i) { if (m_frameCache[i] == frame) { return(i); } } } throw new ArgumentException("Invalid frame"); }
/// <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> /// The function returns the index of the frame in the stack. /// </summary> /// <param name="frame">A frame returned with call to GetFrame.</param> /// <returns>an index of the frame</returns> /// <remarks> /// If the frame passed in was not created with this StackWalker object the function /// throws an exception. /// </remarks> public int GetFrameIndex(MDbgFrame frame) { lock (m_leafLock) { CheckUsability(); // We do not need to grow frame cache. If it's not already in the cache, it can't be valid. if (m_frameCache != null) { for (int i = 0; i < m_frameCache.Count; ++i) { if (m_frameCache[i] == frame) { return(i); } } } throw new ArgumentException("Invalid frame"); } }
bool IEnumerator.MoveNext() { if (m_currentFrame == null) { if (m_bottomFrame == null) { return(false); } m_currentFrame = m_bottomFrame; } else { MDbgFrame f = m_currentFrame.NextUp; if (f == null) { return(false); } m_currentFrame = f; } return(true); }
/// <summary> /// Function returns mdbg frame for the thred it was created for. /// </summary> /// <param name="index">index of the frame. The leaf-most frame is indexed with 0.</param> /// <returns>the object representing frame</returns> /// <remarks> /// When the stack has 10 frames, it returns the frame for indexes 0-9. It returns null /// for index 10 and throws otherwise. /// </remarks> public MDbgFrame GetFrame(int index) { lock (m_cacheLock) { CheckUsability(); // Need to check for out-of-range if (index < 0) { throw new ArgumentOutOfRangeException("index"); } // Grow the cache until it is large enough to contain the index. // This should be the only place that calls IterateNextFrame(). while (index >= InternalFrameCache.Count) { MDbgFrame frame = IterateNextFrame(); InternalFrameCache.Add(frame); // Check if the index is asking for more frames than the callstack has. if (frame == null) { if (index > InternalFrameCache.Count) { throw new ArgumentOutOfRangeException("index", index, "Callstack only has " + InternalFrameCache.Count + " frame(s)."); } } else { // Ensure that that the same frame is not added multiple times. // This can cause infinite loops in the stackwalker because each frame // must have a unique index. Debug.Assert(GetFrameIndex(frame) == index, "FrameFactory " + m_frameEnum.ToString() + " added same frame (" + frame.ToString() + ") multiple times."); } } return(InternalFrameCache[index]); } }
/// <summary> /// Gets the variables available for inspection in the supplied MDbgFrame. /// Currently does nothing with those variables. Left here for future use. /// </summary> /// <param name="frame">The frame to get the local variables from.</param> private IEnumerable<LocalVariableInformation> GetScopeVariables(MDbgFrame frame) { frame.Function.GetArguments(frame); LocalVariableProcessor processor = new LocalVariableProcessor(); processor.AddLocalValues(frame.Function.GetActiveLocalVars(frame)); processor.AddLocalValues(frame.Function.GetArguments(frame)); return processor.LocalVariables; }
public FramePair(MDbgFrame f, String s) { m_frame = f; m_displayString = s; }
public CorValue ParseExpression2(string value, MDbgProcess process, MDbgFrame scope) { if (value.Length == 0) { return null; } CorGenericValue result; if (TryCreatePrimitiveValue(value, out result)) { //value is a primitive type return result; } if (value[0] == '"' && value[value.Length - 1] == '"') { //value is a string return CreateString(value); } //value is some variable Debug.Assert(process != null); MDbgValue var = process.ResolveVariable(value, scope); return (var == null ? null : var.CorValue); }
public MDbgFrameEnumerable(MDbgFrame bottomFrame) { m_bottomFrame = bottomFrame; }
internal MDbgFrameEnumerator(MDbgFrame bottomFrame) { m_bottomFrame = bottomFrame; }
/// <summary> /// A function that returns the new MdbgFrame. The function is expected to be overriden by derived implementations. /// </summary> /// <param name="index">0 based index from top of the stack</param> /// <returns>frame from the stack</returns> protected override MDbgFrame GetFrameImpl(int index) { if (index < FrameCache.Count) { return(FrameCache[index]); } MDbgFrame frameToReturn; if (index == 0) { // special case the first frame frameToReturn = ReturnLeafFrame(); } else { // use recursion... MDbgFrame prevFrame = GetFrameImpl(index - 1); if (prevFrame == null) { throw new ArgumentException(); } frameToReturn = GetFrameCaller(prevFrame); if (frameToReturn == null) { // we need to get the next frame from the following chain CorChain chain = GetFrameChain(prevFrame); Debug.Assert(chain != null); // 1. find next chain while (true) { chain = chain.Caller; if (chain == null) { break; } if (chain.IsManaged) { CorFrame f = chain.ActiveFrame; if (f != null) { frameToReturn = new MDbgILFrame(Thread, f); break; } } else { frameToReturn = FillAndGetLeafFrameFromNativeChain(chain); if (frameToReturn != null) { break; } } } } } // store and return frameToReturn if (frameToReturn != null) { Debug.Assert(FrameCache.Count >= index); if (FrameCache.Count == index) { FrameCache.Add(frameToReturn); } else { Debug.Assert(FrameCache[index] == frameToReturn, "List of frames pre-filled with incorrect frame"); } } return(frameToReturn); }
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; }
////////////////////////////////////////////////////////////////////////////////// // // Support for printing local printing variables // ////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets an Array of MDbgValues for the Active Local Vars in the given frame. /// </summary> /// <param name="managedFrame">The Frame to look in.</param> /// <returns>The MDbgValue[] Active Local Valiables.</returns> public MDbgValue[] GetActiveLocalVars(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) throw new ArgumentException(); CorFrame frame = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(frame.FunctionToken == m_function.Token); if (!(frame.FunctionToken == m_function.Token)) throw new ArgumentException(); EnsureIsUpToDate(); if (!m_haveSymbols) { // if we don't have symbols -- we'll print local variables as (loca1_0,local_1,local_2,...) // to give them names consistent with ILasm. int c = frame.GetLocalVariablesCount(); if (c < 0) c = 0; // in case we cannot get locals, // we'll hide them. MDbgValue[] locals = new MDbgValue[c]; for (int i = 0; i < c; ++i) { CorValue arg = null; try { arg = frame.GetLocalVariable(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) throw; } locals[i] = new MDbgValue(m_module.Process, "local_" + (i), arg); } return locals; } uint ip; CorDebugMappingResult mappingResult; frame.GetIP(out ip, out mappingResult); ArrayList al = new ArrayList(); ISymbolScope scope = SymMethod.RootScope; AddLocalVariablesToList(frame, (int)ip, al, scope); return (MDbgValue[])al.ToArray(typeof(MDbgValue)); }
// Helper to parse args to get a value for a GC handle. // // Syntax for gchandle. Ultimately need to compute an address. // gchandle(var) where var is System.Runtime.InteropServices.GCHandle, address=var.m_handle // gchandle(integer) where address =integer // gchandle(var, offset) where var is a valuetype, then we do address= (IntPtr*) (&var + offset*sizeof(IntPtr)) internal MDbgValue ParseGCHandleArgs(string stName, string[] args, MDbgFrame scope) { if (args.Length != 1 && args.Length != 2) { throw new MDbgException("Wrong number of args to gchandle function."); } string stVarBase = args[0]; MDbgValue varBase = ResolveVariable(stVarBase, scope); //MDbgValue varBase = Shell.ExpressionParser.ParseExpression(stVarBase,this, scope); IntPtr add; if (args.Length == 2) { if (varBase == null) { throw new MDbgException("Can't resolve var '" + stVarBase + "'"); } // Form: gchandle(var, offset) CorGenericValue gv = varBase.CorValue.CastToGenericValue(); IntPtr[] ar = null; if (gv != null) { ar = gv.GetValueAsIntPtrArray(); } if (ar == null) { throw new MDbgException("Variable '" + stVarBase + "' is not a value type."); } int offset = Int32.Parse(args[1], CultureInfo.InvariantCulture); add = ar[offset]; } else { if (varBase != null) { add = IntPtr.Zero; // Form: gchandle(var) if (varBase.TypeName != "System.Runtime.InteropServices.GCHandle") { throw new MDbgException("Variable is not of type \"System.Runtime.InteropServices.GCHandle\"."); } foreach (MDbgValue field in varBase.GetFields()) { if (field.Name == "m_handle") { int handleAddress = Int32.Parse(field.GetStringValue(0)); add = new IntPtr(handleAddress); break; } } } else { // Trying to resolve as a raw address now // form: gchandle(integer) int handleAddress; if (!Int32.TryParse(stVarBase, out handleAddress)) { throw new MDbgException("Couldn't recognize the argument as a variable name or address"); } add = new IntPtr(handleAddress); } } CorReferenceValue result; try { result = this.CorProcess.GetReferenceValueFromGCHandle(add); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.CORDBG_E_BAD_REFERENCE_VALUE) { throw new MDbgException("Invalid handle address."); } else { throw; } } MDbgValue var = new MDbgValue(this, stName, result); return var; }
/// <summary> /// Return the chain the frame belongs to. /// </summary> /// <param name="frame">frame created by this stackwalker</param> /// <returns>The chain that owns the frame.</returns> protected virtual CorChain GetFrameChain(MDbgFrame frame) { Debug.Assert(frame != null); return(frame.CorFrame.Chain); }
public static string GetFrameString(MDbgFrame frame, bool withArgs = false) { try { if (withArgs) { if (frame.IsManaged && !frame.Function.FullName.StartsWith("System.")) return string.Format("{0}({1})", frame.Function.FullName, string.Join(", ", frame.Function.GetArguments(frame).Select(arg => string.Format("{0} = {1}", arg.Name, arg.GetStringValue(false))))); } else { if (frame.IsInfoOnly) return null; string retVal = frame.Function.FullName + " ("; foreach (MDbgValue value2 in frame.Function.GetArguments(frame)) { retVal += value2.TypeName + ", "; } retVal = retVal.TrimEnd(", ".ToCharArray()) + ")"; return retVal; } //return frame.Function.FullName; } catch (Exception ex) { DebuggerUtils.HandleExceptionSilently(ex); } return null; }
/// <summary> /// The function returns the index of the frame in the stack. /// </summary> /// <param name="frame">A frame returned with call to GetFrame.</param> /// <returns>an index of the frame</returns> /// <remarks> /// If the frame passed in was not created with this StackWalker object the function /// throws an exception. /// </remarks> public int GetFrameIndex(MDbgFrame frame) { CheckUsability(); if (m_frameCache != null) { for (int i = 0; i < m_frameCache.Count; ++i) { if (m_frameCache[i] == frame) { return i; } } } throw new ArgumentException("Invalid frame"); }
// Helper to get all the fields, including static fields and base types. private MDbgValue[] InternalGetFields() { List <MDbgValue> al = new List <MDbgValue>(); //dereference && (unbox); CorValue value = Dereference(CorValue, null); if (value == null) { throw new MDbgValueException("null value"); } Unbox(ref value); CorObjectValue ov = value.CastToObjectValue(); CorType cType = ov.ExactType; CorFrame cFrame = null; if (Process.Threads.HaveActive) { // we need a current frame to display thread local static values if (Process.Threads.Active.HaveCurrentFrame) { MDbgFrame temp = Process.Threads.Active.CurrentFrame; while (temp != null && !temp.IsManaged) { temp = temp.NextUp; } if (temp != null) { cFrame = temp.CorFrame; } } } MDbgModule classModule; // initialization CorClass corClass = ov.Class; classModule = Process.Modules.Lookup(corClass.Module); // iteration through class hierarchy while (true) { Type classType = classModule.Importer.GetType(corClass.Token); foreach (MetadataFieldInfo fi in classType.GetFields()) { CorValue fieldValue = null; try { if (fi.IsLiteral) { fieldValue = null; // for now we just hide the constant fields. continue; } else if (fi.IsStatic) { if (cFrame == null) { // Without a frame, we won't be able to find static values. So // just skip this guy continue; } fieldValue = cType.GetStaticFieldValue(fi.MetadataToken, cFrame); } else { // we are asuming normal field value fieldValue = ov.GetFieldValue(corClass, fi.MetadataToken); } } catch (COMException) { // we won't report any problems. } al.Add(new MDbgValue(Process, fi.Name, fieldValue)); } cType = cType.Base; if (cType == null) { break; } corClass = cType.Class; classModule = Process.Modules.Lookup(corClass.Module); } return(al.ToArray()); }
/// <summary> /// Returns the caller of the frame. /// </summary> /// <param name="frame">frame to return the caller of</param> /// <returns>the caller of the frame or null if the frame is the last frame in the chain</returns> protected virtual MDbgFrame GetFrameCaller(MDbgFrame frame) { Debug.Assert(frame != null); CorFrame f = frame.CorFrame.Caller; if (f == null) { return null; } return new MDbgILFrame(Thread, f); }
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); }
/// <summary> /// Return the chain the frame belongs to. /// </summary> /// <param name="frame">frame created by this stackwalker</param> /// <returns>The chain that owns the frame.</returns> protected virtual CorChain GetFrameChain(MDbgFrame frame) { Debug.Assert(frame != null); return frame.CorFrame.Chain; }
////////////////////////////////////////////////////////////////////////////////// // // Support for printing local printing variables // ////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets an Array of MDbgValues for the Active Local Vars in the given frame. /// </summary> /// <param name="managedFrame">The Frame to look in.</param> /// <returns>The MDbgValue[] Active Local Valiables.</returns> public MDbgValue[] GetActiveLocalVars(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) { throw new ArgumentException(); } CorFrame frame = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(frame.FunctionToken == m_function.Token); if (!(frame.FunctionToken == m_function.Token)) { throw new ArgumentException(); } EnsureIsUpToDate(); if (!m_haveSymbols) { // if we don't have symbols -- we'll print local variables as (loca1_0,local_1,local_2,...) // to give them names consistent with ILasm. int c = frame.GetLocalVariablesCount(); if (c < 0) { c = 0; // in case we cannot get locals, } // we'll hide them. MDbgValue[] locals = new MDbgValue[c]; for (int i = 0; i < c; ++i) { CorValue arg = null; try { arg = frame.GetLocalVariable(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) { throw; } } locals[i] = new MDbgValue(m_module.Process, "local_" + (i), arg); } return(locals); } uint ip; CorDebugMappingResult mappingResult; frame.GetIP(out ip, out mappingResult); ArrayList al = new ArrayList(); ISymbolScope scope = SymMethod.RootScope; AddLocalVariablesToList(frame, (int)ip, al, scope); return((MDbgValue[])al.ToArray(typeof(MDbgValue))); }
/// <summary> /// Gets an array of MDbgValues that are the Arguments to the Function in the given Frame. /// </summary> /// <param name="managedFrame">The Frame to use.</param> /// <returns>The MDbgValue[] Arguments.</returns> public MDbgValue[] GetArguments(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) { throw new ArgumentException(); } CorFrame f = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(f.FunctionToken == m_function.Token); if (!(f.FunctionToken == m_function.Token)) { throw new ArgumentException(); } EnsureIsUpToDate(); ArrayList al = new ArrayList(); int c = f.GetArgumentCount(); if (c == -1) { throw new MDbgException("Could not get metainformation. (Jit tracking information not turned on)"); } int i; for (i = 0; i < c; i++) { CorValue arg = null; try { arg = f.GetArgument(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) { throw; } } al.Add(new MDbgValue(m_module.Process, arg)); } MDbgValue[] argArray = (MDbgValue[])al.ToArray(typeof(MDbgValue)); MethodInfo mi = managedFrame.Function.MethodInfo; foreach (ParameterInfo pi in mi.GetParameters()) { int pos = pi.Position; // ParameterInfo at Position 0 refers to the return type (eg. when it has an attribute applied) if (pos == 0) { continue; } if (mi.IsStatic) { pos--; } Debug.Assert(pos < c); argArray[pos].InternalSetName(pi.Name); } i = 0; foreach (MDbgValue v in argArray) { if (v.Name == null) { if (i == 0 && !mi.IsStatic) { v.InternalSetName("this"); } else { v.InternalSetName("unnamed_param_" + i); } i++; } } return(argArray); }
public MDbgValue ParseExpression(string variableName, MDbgProcess process, MDbgFrame scope) { Debug.Assert(process != null); return process.ResolveVariable(variableName, scope); }
/// <summary> /// The function returns the index of the frame in the stack. /// </summary> /// <param name="frame">A frame returned with call to GetFrame.</param> /// <returns>an index of the frame</returns> /// <remarks> /// If the frame passed in was not created with this StackWalker object the function /// throws an exception. /// </remarks> public int GetFrameIndex(MDbgFrame frame) { lock (m_leafLock) { CheckUsability(); // We do not need to grow frame cache. If it's not already in the cache, it can't be valid. if (m_frameCache != null) { for (int i = 0; i < m_frameCache.Count; ++i) { if (m_frameCache[i] == frame) { return i; } } } throw new ArgumentException("Invalid frame"); } }
// The function verifies that the stackwalker for this thread is "current". The stack-walker will become // invalid when a debugger performs an operation that invalidats active stackwalkers. Examples of such // operations are: // - calling Continue(), calling SetIP() or calling RefreshStack() methods. // // If the current stack-walker is not current, a new stack-walker is created for the thread. The function // also sets the current frame if the stack walker is refreshed. // private void EnsureCurrentStackWalker() { lock (m_stackLock) { if (m_stackWalker != null) { return; } m_stackWalker = new FrameCache(m_threadMgr.FrameFactory.EnumerateFrames(this), this); // initialize the frame index to be the invalid index. -1 is a special value here. m_currentFrameIndex = -1; int idx = 0; try { while (true) { MDbgFrame f = null; try { // set m_currentFrame to first non-Internal frame f = m_stackWalker.GetFrame(idx); } catch { // It is acceptable that the above might throw an exception, if the // reason is that the OS thread is not in the dump. This // can happen because the CLR debugging API can notify us of managed // threads whose OS counterpart has already been destroyed, and is thus // no longer in the dump. In such a case, just fall through and return // without having found a current frame for this thread's stack walk. // Otherwise, propagate the exception. if (m_threadMgr.m_process.DumpReader == null) { // Not debugging a dump, so we wouldn't expect an exception here. // Don't swallow throw; } if (IsOSThreadPresentInDump()) { // Looks like we're trying to get a stackwalk of a valid thread in the dump, // meaning the exception that was thrown was a bad one. Rethrow it. throw; } } if (f == null) { // Hit the end of the stack without finding a frame that we can set as the // current frame. Should still be set to "no current frame" Debug.Assert(m_currentFrameIndex == -1); return; } // Skip InfoOnly frames. if (!f.IsInfoOnly) { m_currentFrameIndex = idx; return; } idx++; } } catch (NotImplementedException) { // If any of the stackwalking APIs are not implemented, then we have no // stackwalker, and act like there's no current frame. } } }
private MDbgThread GetMainThread(MDbgProcess proc) { MDbgThread mainthread = null; foreach (MDbgThread thread in proc.Threads) { if (DebuggerUtils.CheckValidState(thread)) { MDbgFrame[] frames = new MDbgFrame[0]; try { frames = thread.Frames.ToArray(); } catch { } foreach (MDbgFrame f in frames) { string line = DebuggerUtils.GetFrameString(f); if (line.Contains("System.Windows.Application.Run") || line.Contains("Program.Main") || line.Contains("System.Windows.Forms.Application.Run")) { mainthread = thread; //m_intMainThreadId = thread.Id; break; } } } } return mainthread; }
bool IEnumerator.MoveNext() { if (m_currentFrame == null) { if (m_bottomFrame == null) return false; m_currentFrame = m_bottomFrame; } else { MDbgFrame f = m_currentFrame.NextUp; if (f == null) return false; m_currentFrame = f; } return true; }
// Add item to list // 'stText' is what we display in the list box. // 'frame' is the underlying frame associated with the text. Can be null if there's no frame. void AddItem(string stText, MDbgFrame frame) { ListBox.ObjectCollection list = this.listBoxCallstack.Items; list.Add(new FramePair(frame, stText)); }
void IEnumerator.Reset() { m_currentFrame = null; }
/// <summary> /// Gets an array of MDbgValues that are the Arguments to the Function in the given Frame. /// </summary> /// <param name="managedFrame">The Frame to use.</param> /// <returns>The MDbgValue[] Arguments.</returns> public MDbgValue[] GetArguments(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) throw new ArgumentException(); CorFrame f = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(f.FunctionToken == m_function.Token); if (!(f.FunctionToken == m_function.Token)) throw new ArgumentException(); EnsureIsUpToDate(); ArrayList al = new ArrayList(); int c = f.GetArgumentCount(); if (c == -1) throw new MDbgException("Could not get metainformation. (Jit tracking information not turned on)"); int i; for (i = 0; i < c; i++) { CorValue arg = null; try { arg = f.GetArgument(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) throw; } al.Add(new MDbgValue(m_module.Process, arg)); } MDbgValue[] argArray = (MDbgValue[])al.ToArray(typeof(MDbgValue)); MethodInfo mi = managedFrame.Function.MethodInfo; foreach (ParameterInfo pi in mi.GetParameters()) { int pos = pi.Position; // ParameterInfo at Position 0 refers to the return type (eg. when it has an attribute applied) if (pos == 0) continue; if (mi.IsStatic) pos--; Debug.Assert(pos < c); argArray[pos].InternalSetName(pi.Name); } i = 0; foreach (MDbgValue v in argArray) if (v.Name == null) { if (i == 0 && !mi.IsStatic) v.InternalSetName("this"); else v.InternalSetName("unnamed_param_" + i); i++; } return argArray; }
/// <summary> /// Resolves a Variable name in a given scope. /// </summary> /// <param name="variableName">The name of the variable to resolve.</param> /// <param name="scope">The MDbgFrame to look in for that variable.</param> /// <returns>The MDbgValue that the given variable has in the given scope.</returns> public MDbgValue ResolveVariable(string variableName, MDbgFrame scope) { Debug.Assert(variableName != null); Debug.Assert(scope != null); // variableName should have this form: // [[module][#<appdomain>]!][(([namespace.]+)<type.>)|.]variable([.field]*) // Syntax in BNF form: // // Expr --> module_scope '!' var_expr // | var_expr // module_scope --> <module name> // as determined by Modules.Lookup // var_expr --> var_root // | var_expr '.' <id:field> // | var_expr '[' <integer> ']' // var_root --> psuedo_var | local_var | parameter_var | global_var | static_class_var\ // | 'gchandle(' ... ')' // see ParseGCHandleArgs // psuedo_var --> '$' <id> // as determined by DebuggerVars.HaveVariable // local_var --> <id> // as determined by f.GetActiveLocalVars // parameter_var --> <id> // as determined by f.GetArguments // global_var --> <id> // as determined by fields on global token in each module // static_class_var --> (<id:namespace> '.')* <id:class> '.' <id:static field> MDbgModule variableModule; // name of the module we should look into for variable resolution // will contain null, if no module was specified { // limit scope of moduleVar string[] moduleVar = variableName.Split(new char[] { '!' }, 2); Debug.Assert(moduleVar != null); if (moduleVar.Length > 2) { throw new MDbgException("Illegal variable syntax."); } else if (moduleVar.Length == 2) { variableModule = Modules.Lookup(moduleVar[0]); variableName = moduleVar[1]; if (variableModule == null) throw new MDbgException("Module not found"); } else variableModule = null; } // lookup 1st part MDbgValue var = null; int nextPart = 0; // Check for predicates if (variableName.StartsWith("gchandle(")) { string stName; string[] args; GetExpressionFunctionArgs(ref variableName, out stName, out args); nextPart = 1; var = this.ParseGCHandleArgs(stName, args, scope); } // end gchandle string[] nameParts = variableName.Split(new char[] { '.', '[' }); Debug.Assert(nameParts.Length >= 1); // there must be at least one part. if (var != null) { // already resolved, no extra work to do. } // Let's check if we are asking for debugger var. Those vars are prefixed with $. // if yes, return the var. else if (variableName.StartsWith("$") && variableModule == null // debugger vars cannot have module specifier ) { string varName = nameParts[nextPart]; Debug.Assert(varName.StartsWith("$")); if (DebuggerVars.HaveVariable(nameParts[nextPart])) { MDbgDebuggerVar dv = DebuggerVars[nameParts[0]]; var = new MDbgValue(this, dv.Name, dv.CorValue); } else var = null; nextPart++; } else { ArrayList vars = new ArrayList(); { // fill up vars with locals+arguments MDbgFunction f = scope.Function; MDbgValue[] vals = f.GetActiveLocalVars(scope); if (vals != null) vars.AddRange(vals); vals = f.GetArguments(scope); if (vals != null) vars.AddRange(vals); } // try to find a match in locals and arguments first foreach (MDbgValue v in vars) if (v.Name == nameParts[nextPart]) { var = v; nextPart++; break; } // if no match for locals and arguments, look for globals and static class members if (var == null) { // now let's try to resolve static var of form Namespace.namespace.typeName.var bool bGlobal = (nameParts[nextPart].Length == 0); if (bGlobal) nextPart++; foreach (MDbgModule m in this.Modules) { if (variableModule != null && variableModule != m) continue; // we're interested only in certain module if (bGlobal) // global variables { // nil type token is used to enum global static data members MetadataType gType = (MetadataType)m.Importer.GetType(0); FieldInfo[] gField = gType.GetFields(0); for (int i = 0; i < gField.Length; i++) { if (nameParts[nextPart] == gField[i].Name) { var = new MDbgValue(this, "." + gField[i].Name, scope.Function.Module.CorModule.GetGlobalVariableValue(gField[i].MetadataToken)); nextPart++; break; } } if (var != null) // done if we find the first match in any module break; } else // static class members { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(nameParts[nextPart]); for (int i = nextPart + 1; i < nameParts.Length; i++) { int typeToken = m.Importer.GetTypeTokenFromName(sb.ToString()); if (typeToken != CorMetadataImport.TokenNotFound) { // we resolved type, let's try to get statics CorClass cl = m.CorModule.GetClassFromToken(typeToken); Type classType = m.Importer.GetType(cl.Token); foreach (MetadataFieldInfo fi in classType.GetFields()) { if (fi.Name != nameParts[i]) continue; if (fi.IsStatic) { sb.Append(".").Append(nameParts[i]); CorValue fieldValue = cl.GetStaticFieldValue(fi.MetadataToken, scope.CorFrame); var = new MDbgValue(this, sb.ToString(), fieldValue); nextPart = i + 1; goto FieldValueFound; // done if we find the first match in any module } } } sb.Append(".").Append(nameParts[i]); } } } FieldValueFound: ; } }; if (var != null) { // now try to resolve remaining parts. for (int i = nextPart; i < nameParts.Length; i++) { string part = nameParts[i]; if (part.EndsWith("]")) { // it is probably array index string[] indexStrings = part.Substring(0, part.Length - 1).Split(','); Debug.Assert(indexStrings != null && indexStrings.Length > 0); int[] indexes = new int[indexStrings.Length]; for (int j = 0; j < indexStrings.Length; ++j) indexes[j] = Int32.Parse(indexStrings[j], CultureInfo.InvariantCulture); var = var.GetArrayItem(indexes); } else { // we'll treat it as field name var = var.GetField(part); } } } return var; }