internal override IList <ClrStackFrame> GetExceptionStackTrace(ulong obj, ClrType type) { List <ClrStackFrame> result = new List <ClrStackFrame>(); if (!GetStackTraceFromField(type, obj, out ulong _stackTrace)) { if (!ReadPointer(obj + GetStackTraceOffset(), out _stackTrace)) { return(result); } } if (_stackTrace == 0) { return(result); } DesktopGCHeap heap = (DesktopGCHeap)Heap; ClrType stackTraceType = heap.GetObjectType(_stackTrace); if (stackTraceType == null) { stackTraceType = heap.ArrayType; } if (!stackTraceType.IsArray) { return(result); } int len = stackTraceType.GetArrayLength(_stackTrace); if (len == 0) { return(result); } int elementSize = CLRVersion == DesktopVersion.v2 ? IntPtr.Size * 4 : IntPtr.Size * 3; ulong dataPtr = _stackTrace + (ulong)(IntPtr.Size * 2); if (!ReadPointer(dataPtr, out ulong count)) { return(result); } // Skip size and header dataPtr += (ulong)(IntPtr.Size * 2); DesktopThread thread = null; for (int i = 0; i < (int)count; ++i) { if (!ReadPointer(dataPtr, out ulong ip)) { break; } if (!ReadPointer(dataPtr + (ulong)IntPtr.Size, out ulong sp)) { break; } if (!ReadPointer(dataPtr + (ulong)(2 * IntPtr.Size), out ulong md)) { break; } if (i == 0) { thread = (DesktopThread)GetThreadByStackAddress(sp); } result.Add(new DesktopStackFrame(this, thread, null, ip, sp, md)); dataPtr += (ulong)elementSize; } return(result); }
internal DesktopBlockingObject[] InitLockInspection() { if (_result != null) { return(_result); } // First, enumerate all thinlocks on the heap. foreach (var seg in _heap.Segments) { for (ulong obj = seg.FirstObject; obj != 0; obj = seg.NextObject(obj)) { ClrType type = _heap.GetObjectType(obj); if (IsReaderWriterLock(obj, type)) { _locks[obj] = CreateRWLObject(obj, type); } else if (IsReaderWriterSlim(obj, type)) { _locks[obj] = CreateRWSObject(obj, type); } // Does this object have a syncblk with monitor associated with it? if (!_heap.GetObjectHeader(obj, out uint header)) { continue; } if ((header & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_SPIN_LOCK)) != 0) { continue; } uint threadId = header & SBLK_MASK_LOCK_THREADID; if (threadId == 0) { continue; } ClrThread thread = _runtime.GetThreadFromThinlockID(threadId); if (thread != null) { int recursion = ((int)header & SBLK_MASK_LOCK_RECLEVEL) >> SBLK_RECLEVEL_SHIFT; _monitors[obj] = new DesktopBlockingObject(obj, true, recursion + 1, thread, BlockingReason.Monitor); } } } // Enumerate syncblocks to find locks int syncblkCnt = _runtime.GetSyncblkCount(); for (int i = 0; i < syncblkCnt; ++i) { ISyncBlkData data = _runtime.GetSyncblkData(i); if (data == null || data.Free) { continue; } _syncblks[data.Address] = data.Object; _syncblks[data.Object] = data.Object; ClrThread thread = null; if (data.MonitorHeld) { ulong threadAddr = data.OwningThread; foreach (var clrThread in _runtime.Threads) { if (clrThread.Address == threadAddr) { thread = clrThread; break; } } } _monitors[data.Object] = new DesktopBlockingObject(data.Object, data.MonitorHeld, (int)data.Recursion, thread, BlockingReason.Monitor); } SetThreadWaiters(); int total = _monitors.Count + _locks.Count + _joinLocks.Count + _waitLocks.Count; _result = new DesktopBlockingObject[total]; int j = 0; foreach (DesktopBlockingObject blocker in _monitors.Values) { _result[j++] = blocker; } foreach (DesktopBlockingObject blocker in _locks.Values) { _result[j++] = blocker; } foreach (DesktopBlockingObject blocker in _joinLocks.Values) { _result[j++] = blocker; } foreach (DesktopBlockingObject blocker in _waitLocks.Values) { _result[j++] = blocker; } Debug.Assert(j == _result.Length); // Free up some memory. _monitors = null; _locks = null; _joinLocks = null; _waitLocks = null; _syncblks = null; return(_result); }