/// <summary> /// Enumerates objects that are either located in thread stack (f.e. structures), or mentioned there by pointer (reference types). /// </summary> /// <param name="thread">A thread to have stack inspected.</param> /// <returns>A stream of non-duplicated objects that match criterias.</returns> public virtual IEnumerable <ClrObject> Enumerate(ClrThread thread) { if (thread == null) { yield break; } var clrRoots = thread.EnumerateStackObjects(this.IncludePossiblyDead); var processed = new HashSet <ulong>(); var heap = thread.Runtime.GetHeap(); foreach (var root in clrRoots) { var clrObject = new ClrObject(root.Object, heap); if (processed.Contains(clrObject.Address)) { continue; } if (this.ShouldSkip(clrObject, thread)) { continue; } if (processed.Add(clrObject.Address)) { yield return(clrObject); } } }
public static List <StackFrameInfo> GetDetailedStackTrace(this ClrThread thread) { List <StackFrameInfo> stackframes = new List <StackFrameInfo>(); List <ClrRoot> stackObjects = thread.EnumerateStackObjects().ToList(); ulong lastAddress = 0; foreach (ClrStackFrame frame in thread.StackTrace) { ClrStackFrame f = frame; List <ClrDynamic> objectsInFrame = stackObjects .Where(o => o.Address > lastAddress && o.Address <= f.StackPointer) .OrderBy(o => o.Address) .Select(o => ClrMDSession.Current.Heap.GetDynamicObject(o.Object)) .ToList(); stackframes.Add(new StackFrameInfo { Function = f.DisplayString, Objects = objectsInFrame }); lastAddress = f.StackPointer; } return(stackframes); }
private string GetFrameInformation(ClrThread thread, ClrStackFrame frame, ClrStackFrame firstFrame) { // get the method call from the given frame string info = ""; var sourceLocation = frame.GetFileAndLineNumber(); if (sourceLocation == null) { info = frame.DisplayString; } else // it seems that GetFileAndLineNumber() does not work --> need to figure out what is the other ClrMD API to dig into the symbols { info = frame.DisplayString + "[" + sourceLocation.FilePath + ", Line " + sourceLocation.LineNumber.ToString() + "]"; } // look for locking information if (firstFrame.Method.Name.Contains("Wait") || (firstFrame.Method.Name == "Enter") && (firstFrame.Method.Type.Name == "System.Threading.Monitor")) { // special case for MonitorEnter --> not a WaitHandle to wait on bool isMonitorEnter = (firstFrame.Method.Name == "Enter") && (firstFrame.Method.Type.Name == "System.Threading.Monitor"); info = info + "\r\n => " + firstFrame.Method.Type.Name + "." + firstFrame.Method.Name; // look for object used as lock int maxStackObjects = 10; foreach (var so in thread.EnumerateStackObjects(true)) { if (so == null) { continue; } var type = so.Type; if (so.Type == null) { continue; } string typeName = so.Type.Name; if (typeName.Contains("WaitHandle") || isMonitorEnter) { info = info + string.Format("({0} = 0x{1:X16})\r\n", typeName, so.Object); break; } else { } maxStackObjects--; if (maxStackObjects == 0) { break; } } } return(info); }
public void NullValueOkTest() { ClrThread clrThread = Thread.Current.FindClrThread(); StackFrame frame = clrThread.ClrStackTrace.Frames.Where(f => f.FunctionNameWithoutModule.StartsWith("Program.Main(")).Single(); Variable fooObject = frame.Locals["containsnullref"]; Assert.AreEqual(42, (int)fooObject.GetField("SetValue").GetField("i")); Assert.IsTrue(fooObject.GetField("NullValue").IsNullPointer()); Assert.IsTrue(clrThread.EnumerateStackObjects().Contains(fooObject)); }
public void PrimitiveVariableConversionTest() { ClrThread clrThread = Thread.Current.FindClrThread(); StackFrame frame; foreach (var f in clrThread.ClrStackTrace.Frames) { foreach (var variable in f.Locals) { System.Console.WriteLine(" {2} = ({0}) {1:X}", variable.GetCodeType(), variable.GetPointerAddress(), variable.GetName()); } } foreach (Variable variable in clrThread.EnumerateStackObjects()) { System.Console.WriteLine(" ({0}) {1:X}", variable.GetCodeType(), variable.GetPointerAddress()); } frame = clrThread.ClrStackTrace.Frames.Where(f => f.FunctionNameWithoutModule.StartsWith("Program.Inner(")).Single(); Assert.IsTrue((bool)frame.Locals["b"]); Assert.AreEqual('c', (char)frame.Locals["c"]); Assert.AreEqual("hello world", new ClrString(frame.Locals["s"]).Text); Assert.AreEqual(42, (int)frame.Locals["st"].GetField("i")); Assert.IsTrue(clrThread.EnumerateStackObjects().Contains(frame.Locals["s"])); frame = clrThread.ClrStackTrace.Frames.Where(f => f.FunctionNameWithoutModule.StartsWith("Program.Middle(")).Single(); Assert.AreEqual(0x42, (byte)frame.Locals["b"]); Assert.AreEqual(0x43, (sbyte)frame.Locals["sb"]); Assert.AreEqual(0x4242, (short)frame.Locals["sh"]); Assert.AreEqual(0x4243, (ushort)frame.Locals["ush"]); Assert.AreEqual(0x42424242, (int)frame.Locals["i"]); Assert.AreEqual(0x42424243u, (uint)frame.Locals["ui"]); frame = clrThread.ClrStackTrace.Frames.Where(f => f.FunctionNameWithoutModule.StartsWith("Program.Outer(")).Single(); Assert.AreEqual(42.0f, (float)frame.Locals["f"]); Assert.AreEqual(43.0, (double)frame.Locals["d"]); Assert.AreEqual((ulong)0x42424242, (ulong)frame.Locals["ptr"]); Assert.AreEqual((ulong)0x43434343, (ulong)frame.Locals["uptr"]); }
private IEnumerable <Tuple <ulong, int> > EnumerateClrThreadStackObjects(ClrThread clrThread) { foreach (ClrRoot root in clrThread.EnumerateStackObjects()) { if (root.Type.IsFree || root.Type.Module == null) { continue; } int clrTypeId = GetClrTypeId(root.Type); ulong address = root.Address; yield return(Tuple.Create(address, clrTypeId)); } }
private string GetFrameInformation(ClrThread thread, ClrStackFrame frame, ClrStackFrame firstFrame) { // get the method call from the given frame string info = frame.DisplayString; // look for locking information if (firstFrame.Method.Name.Contains("Wait") || (firstFrame.Method.Name == "Enter") && (firstFrame.Method.Type.Name == "System.Threading.Monitor")) { // special case for MonitorEnter --> not a WaitHandle to wait on bool isMonitorEnter = (firstFrame.Method.Name == "Enter") && (firstFrame.Method.Type.Name == "System.Threading.Monitor"); info = info + "\r\n => " + firstFrame.Method.Type.Name + "." + firstFrame.Method.Name; // look for object used as lock int maxStackObjects = 10; foreach (var so in thread.EnumerateStackObjects(true)) { if (so == null) { continue; } var type = so.Type; if (so.Type == null) { continue; } string typeName = so.Type.Name; if (typeName.Contains("WaitHandle") || isMonitorEnter) { info = info + string.Format("({0} = 0x{1:X16})\r\n", typeName, so.Object); break; } else { } maxStackObjects--; if (maxStackObjects == 0) { break; } } } return(info); }
/// <summary> /// Enumerates the GC references (objects) on the stack. /// </summary> public IEnumerable <Variable> EnumerateStackObjects() { CLR.ClrMdProvider provider = ((ClrMdRuntime)Runtime).Provider; foreach (Microsoft.Diagnostics.Runtime.ClrRoot root in ClrThread.EnumerateStackObjects()) { if (root.Type.IsFree || root.Type.Module == null) { continue; } Variable field = Variable.CreateNoCast(Process.FromClrType(provider.FromClrType(root.Type)), root.Address); yield return(Variable.UpcastClrVariable(field)); } }
public void ObjectFieldTest() { ClrThread clrThread = Thread.Current.FindClrThread(); StackFrame frame = clrThread.ClrStackTrace.Frames.Where(f => f.FunctionNameWithoutModule.StartsWith("Program.Main(")).Single(); Variable foo = frame.Locals["foo"]; Assert.IsTrue(clrThread.EnumerateStackObjects().Contains(foo)); Assert.AreEqual(42, (int)foo.GetField("i")); Assert.AreEqual(0x42u, (uint)foo.GetField("ui")); Assert.AreEqual("string", new ClrString(foo.GetField("s")).Text); Assert.AreEqual(true, (bool)foo.GetField("b")); Assert.AreEqual(4.2f, (float)foo.GetField("f")); Assert.AreEqual(8.4, (double)foo.GetField("d")); Assert.AreEqual('c', (char)foo.GetField("c")); Assert.AreEqual(0x12, (byte)foo.GetField("by")); Assert.AreEqual((sbyte)0x13, (sbyte)foo.GetField("sby")); Assert.AreEqual((short)0x4242, (short)foo.GetField("sh")); Assert.AreEqual((ushort)0x4343, (ushort)foo.GetField("ush")); Assert.AreEqual(0x424242ul, (ulong)foo.GetField("ulng")); Assert.AreEqual(0x434343L, (long)foo.GetField("lng")); }
/// <summary> /// Enumerates the GC references (objects) on the stack. This is equivalent to /// EnumerateStackObjects(true). /// </summary> /// <returns>An enumeration of GC references on the stack as the GC sees them.</returns> /// <inheritdoc /> public IEnumerable <IClrRoot> EnumerateStackObjects() => Thread.EnumerateStackObjects().Select(Converter.Convert);