public void GetObjectField_WhenTypeHasFieldWithName_FindsField(ClrHeap heap, ClrType objectType, ClrInstanceField clrField, ulong clrObj, ulong fieldAddress, ulong fieldValue, string fieldName) { // Arrange heap.GetObjectType(Arg.Is <ulong>(address => address == clrObj || address == fieldValue)).Returns(objectType); objectType.GetFieldByName(fieldName).Returns(clrField); clrField.IsObjectReference.Returns(true); objectType.Heap.Returns(heap); clrField.GetAddress(clrObj).Returns(fieldAddress); heap.ReadPointer(fieldAddress, out var whatever) .Returns (call => { call[1] = fieldValue; return(true); }); // Act var fieldFoundByName = new ClrObject(clrObj, objectType).GetObjectField(fieldName); // Assert fieldFoundByName.Address.Should().Be(fieldValue); }
public void RootCallback(IntPtr ptr, ulong addr, ulong obj, int hndType, uint refCount, int strong) { bool isDependent = hndType == (int)HandleType.Dependent; if ((isDependent && m_dependentSupport) || strong != 0) { if (Roots == null) { Roots = new List <ClrRoot>(128); } string name = Enum.GetName(typeof(HandleType), hndType) + " handle"; if (isDependent) { ulong dependentTarget = obj; if (!m_heap.ReadPointer(addr, out obj)) { obj = 0; } ClrType type = m_heap.GetObjectType(obj); Roots.Add(new RhHandleRoot(addr, obj, dependentTarget, type, hndType, m_domain, name)); } else { ClrType type = m_heap.GetObjectType(obj); Roots.Add(new RhHandleRoot(addr, obj, type, hndType, m_domain, name)); } } }
protected virtual ClrObject[] ExecuteFallbackLogic(ClrObject clrObject) { int length; if (this.IsEmptyArray(clrObject, out length)) { return(new ClrObject[0]); } var res = new ClrObject[length]; ClrHeap heap = clrObject.Type.Heap; int pointerSize = heap.PointerSize; ulong arrayStart = this.CalculateArrayStart(clrObject, pointerSize); var isValueType = clrObject.Type.ComponentType.IsValueClass; var shiftSize = isValueType ? clrObject.Type.ComponentType.ElementSize : pointerSize; ulong dataReadPosition = arrayStart; for (int i = 0; i < length; i++) { dataReadPosition += (ulong)shiftSize; ulong elemAddress; ClrObject clrObj; if (!isValueType) { heap.ReadPointer(dataReadPosition, out elemAddress); if (elemAddress == default(ulong)) { continue; } clrObj = new ClrObject(elemAddress, clrObject.Type.Heap); } else { clrObj = new ClrObject(dataReadPosition, clrObject.Type.Heap); } // object val = elemType.GetValue(elemAddress); // if (val == default(object) ) // continue; // TODO: think should we skip object without type ? if (clrObj.Type == null) { continue; } res[i] = clrObj; } return(res); }
/// <summary> /// Returns only referenced objects that do not contain further pointers, /// and referenced arrays of objects that do not contain further pointers. /// This provides a fast estimate of the amount of memory that is likely /// only retained by the target object. /// </summary> public static IEnumerable <Tuple <ulong, ClrType> > FlatSubgraphOf(this ClrHeap heap, ulong objPtr) { var type = heap.GetObjectType(objPtr); if (type == null || type.IsFree || String.IsNullOrEmpty(type.Name)) { yield break; } yield return(new Tuple <ulong, ClrType>(objPtr, type)); List <Tuple <ulong, ClrType> > results = new List <Tuple <ulong, ClrType> >(); type.EnumerateRefsOfObject(objPtr, (inner, offset) => { var innerType = heap.GetObjectType(inner); if (innerType == null || innerType.IsFree) { return; } if (innerType.IsArray && (innerType.ComponentType == null || innerType.ComponentType.ContainsPointers)) { return; } if (!innerType.IsArray && innerType.ContainsPointers) { return; } results.Add(new Tuple <ulong, ClrType>(inner, innerType)); // Value type instances are sized along with the containing array. if (innerType.IsArray && innerType.ElementType != ClrElementType.Struct) { var arraySize = innerType.GetArrayLength(inner); for (int i = 0; i < arraySize; ++i) { var address = innerType.GetArrayElementAddress(inner, i); ulong value; if (heap.ReadPointer(address, out value)) { results.Add(new Tuple <ulong, ClrType>( value, innerType.ComponentType)); } } } }); foreach (var result in results) { yield return(result); } }
public void GetObjectField_WhenHeapWasUnableToReadPointer_ThrowsMemoryReadException([Frozen] ClrHeap heap, [Frozen] ClrType objectType, ClrObject clrObject, ClrInstanceField clrField, ulong corruptedFieldPointer) { // Arrange clrField.IsObjectReference.Returns(true); clrField.GetAddress(clrObject.Address).Returns(corruptedFieldPointer); heap.ReadPointer(corruptedFieldPointer, out var whatever).Returns(false); // Act Action locateObjectFromValueTypeField = () => clrObject.GetObjectField(clrField.Name); // Assert locateObjectFromValueTypeField.Should().Throw <MemoryReadException>(); }
public void Can_cast_to_string() { var proxy = GetProxy <ClassWithStringField>(); ClrType type = proxy.GetClrType(); var address = type.GetFieldByName("Value").GetAddress((ulong)proxy); ulong stringAddress; _heap.ReadPointer(address, out stringAddress); Assert.AreEqual("OK", (string)_heap.GetProxy(stringAddress)); }
static protected TypeInstance GetObjectReference(ClrHeap heap, ulong objAddress, ClrType type, string fieldName, bool bInner = false) { var fieldType = type.GetFieldByName(fieldName); if (fieldType == null) { throw new ArgumentException(String.Format("Field {0} not found in type {1}", fieldName, type.Name)); } ulong objAdr = fieldType.GetAddress(objAddress, bInner); if (!heap.ReadPointer(objAdr, out objAdr)) { throw new InvalidOperationException(String.Format("Could not read from address 0x{0:X} which was field {1} in type {2}. Object Address: 0x:{3:X}", objAddress, fieldName, type.Name, objAddress)); } return(new TypeInstance(objAdr, heap.GetObjectType(objAdr))); }
public void GetObjectField_WhenTypeHasFieldWithName_FindsField([Frozen] ClrHeap heap, [Frozen] ClrType objectType, ClrObject source, ClrInstanceField clrField, ulong fieldAddress, ClrObject target) { // Arrange clrField.IsObjectReference.Returns(true); clrField.GetAddress(source.Address).Returns(fieldAddress); heap.ReadPointer(fieldAddress, out var whatever) .Returns(call => { call[1] = target.Address; return(true); }); // Act var fieldFoundByName = source.GetObjectField(clrField.Name); // Assert fieldFoundByName.Address.Should().Be(target); }
public void GetObjectField_WhenFieldFound_ReturnsField([Frozen] ClrHeap heap, ClrObject target, [Frozen] ClrType structType, ClrValueClass someStruct, ClrInstanceField structReferenceField, ulong fieldAddress) { // Arrange structReferenceField.IsObjectReference.Returns(true); structReferenceField.GetAddress(someStruct.Address, Arg.Any <bool>()).Returns(fieldAddress); heap.ReadPointer(fieldAddress, out var whatever) .Returns(call => { call[1] = target.Address; return(true); }); // Act var structRefFieldTarget = someStruct.GetObjectField(structReferenceField.Name); // Assert structRefFieldTarget.Should().Be(target); }
public void GetObjectField_WhenHeapWasUnableToReadPointer_ThrowsMemoryReadException(ClrHeap heap, ClrType objectType, ClrInstanceField clrField, ulong clrObj, ulong corruptedFieldPointer, string fieldName) { // Arrange heap.GetObjectType(clrObj).Returns(objectType); objectType.GetFieldByName(fieldName).Returns(clrField); clrField.IsObjectReference.Returns(true); objectType.Heap.Returns(heap); clrField.GetAddress(clrObj).Returns(corruptedFieldPointer); heap.ReadPointer(corruptedFieldPointer, out var whatever).Returns(false); // Act Action locateObjectFromValueTypeField = () => new ClrObject(clrObj, objectType).GetObjectField(fieldName); // Assert locateObjectFromValueTypeField.Should().Throw <MemoryReadException>(); }
public void GetFieldFrom_WhenStructureHasReferenceField_ReturnsField([Frozen] ClrHeap heap, ClrObject target, [Frozen] ClrType structType, ClrValueClass rawStruct, ClrInstanceField structReferenceField, ulong fieldAddress) { // Arrange IAddressableTypedEntity entity = rawStruct; structReferenceField.IsObjectReference.Returns(true); structReferenceField.GetAddress(entity.Address, Arg.Any <bool>()).Returns(fieldAddress); heap.ReadPointer(fieldAddress, out var whatever) .Returns(call => { call[1] = target.Address; return(true); }); // Act var fieldByName = entity.GetFieldFrom(structReferenceField.Name); // Assert fieldByName.Address.Should().Be(target.Address); }
public void GetFieldFrom_WhenClrObjectHasReferenceField_ReturnsField([Frozen] ClrHeap heap, [Frozen] ClrType objectType, ClrObject rawClrObject, ClrInstanceField clrField, ulong fieldAddress, ClrObject target) { // Arrange IAddressableTypedEntity entity = rawClrObject; clrField.IsObjectReference.Returns(true); clrField.GetAddress(entity.Address).Returns(fieldAddress); heap.ReadPointer(fieldAddress, out var whatever) .Returns(call => { call[1] = target.Address; return(true); }); // Act var fieldFoundByName = entity.GetFieldFrom(clrField.Name); // Assert fieldFoundByName.Address.Should().Be(target.Address); }
/// <summary> /// Attempts to efficiently read a pointer from memory. This acts exactly like ClrRuntime.ReadPointer, but /// there is a greater chance you will hit a chache for a more efficient memory read. /// </summary> /// <param name="addr">The address to read.</param> /// <param name="value">The pointer value.</param> /// <returns>True if we successfully read the value, false if addr is not mapped into the process space.</returns> /// <inheritdoc /> public bool ReadPointer(ulong addr, out ulong value) => Heap.ReadPointer(addr, out value);
public StringSummary GetTypeReferenceStringSummary(ClrType referrerType, int fieldOffset, CancellationToken token = default) { var tallyByString = new Dictionary <string, ObjectTally>(); ulong stringCount = 0; ulong stringByteCount = 0; ulong totalManagedObjectByteCount = 0; long charCount = 0; foreach (var seg in _heap.Segments) { var segType = seg.IsEphemeral ? GCSegmentType.Ephemeral : seg.IsLarge ? GCSegmentType.LargeObject : GCSegmentType.Regular; for (ulong refObj = seg.GetFirstObject(out ClrType referringType); refObj != 0; refObj = seg.NextObject(refObj, out referringType)) { if (referringType == null) { continue; } totalManagedObjectByteCount += referringType.GetSize(refObj); if (!ReferenceEquals(referringType, referrerType)) { continue; } token.ThrowIfCancellationRequested(); if (!_heap.ReadPointer(refObj + (ulong)fieldOffset, out var strObjRef) || strObjRef == 0) { continue; } var type = _heap.GetObjectType(strObjRef); if (type == null) { continue; } var value = (string)type.GetValue(strObjRef); charCount += value.Length; stringCount++; if (!tallyByString.TryGetValue(value, out var tally)) { var size = type.GetSize(strObjRef); tally = new ObjectTally(size); tallyByString[value] = tally; } var strSeg = _heap.GetSegmentByAddress(strObjRef); int generation = strSeg.GetGeneration(strObjRef); if (tally.Add(strObjRef, segType, generation)) { stringByteCount += tally.InstanceSize; } } } var uniqueStringCount = tallyByString.Count; var stringCharCount = tallyByString.Sum(s => s.Key.Length * (long)s.Value.Count); var uniqueStringCharCount = tallyByString.Keys.Sum(s => s.Length); var wastedBytes = tallyByString.Values.Sum(t => (long)t.WastedBytes); var stringOverhead = ((double)stringByteCount - (charCount * 2)) / stringCount; return(new StringSummary( tallyByString.OrderByDescending(p => p.Value.WastedBytes) .Select( p => new StringItem( p.Key, (uint)p.Key.Length, p.Value.InstanceSize, p.Value.Addresses, p.Value.CountBySegmentType, p.Value.CountByGeneration)).ToList(), totalManagedObjectByteCount, stringByteCount, (ulong)stringCharCount, (ulong)uniqueStringCharCount, stringCount, (ulong)uniqueStringCount, ulong.MaxValue, // TODO review (ulong)wastedBytes, (uint)Math.Round(stringOverhead))); }
public async Task <IEnumerable <object> > Execute(OperationModel model, CancellationToken token, object customeParameter) { //TODO: add support of local variables return(await DebuggerSession.Instance.ExecuteOperation(() => { var result = new List <ClrStackDump>(); foreach (var thread in DebuggerSession.Instance.Runtime.Threads) { if (token.IsCancellationRequested) { break; } var stackDetails = new ClrStackDump(); stackDetails.StackFrames = new List <object>(); stackDetails.StackObjects = new List <object>(); foreach (var stackFrame in thread.StackTrace) { stackDetails.StackBase = thread.StackBase; stackDetails.StackLimit = thread.StackLimit; stackDetails.Exception = thread.CurrentException; stackDetails.OSThreadID = thread.IsAlive ? thread.OSThreadId.ToString() : "XXX"; stackDetails.ManagedThreadId = thread.ManagedThreadId; stackDetails.StackFrames.Add( new { StackPointer = stackFrame.StackPointer, InstructionPointer = stackFrame.InstructionPointer, DisplayString = stackFrame.DisplayString, //FileAndLine = source != null ? source.FilePath + ": " + source.LineNumber : "", Method = stackFrame.Method }); } ClrHeap heap = DebuggerSession.Instance.Runtime.GetHeap(); var pointerSize = DebuggerSession.Instance.Runtime.PointerSize; // address of TEB (thread execution block) + pointer size ulong start = thread.StackBase; // address of TEB (thread execution block) + pointer size * 2 ulong stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { ulong tmp = start; start = stop; stop = tmp; } // ptr is a stack address. for (ulong ptr = start; ptr <= stop; ptr += (ulong)pointerSize) { HashSet <ulong> stackObjects = new HashSet <ulong>(); // fail to read the memory if (!heap.ReadPointer(ptr, out ulong obj)) { break; } // the object added already if (!stackObjects.Add(obj)) { continue; } // not an object ClrType type = heap.GetObjectType(obj); if (type == null) { continue; } // free space if (type.IsFree) { continue; } // All good, add it stackDetails.StackObjects.Add( new { Address = ptr, Object = obj, Name = type.Name, Value = new ClrObject(obj, type).Fields.Value }); } result.Add(stackDetails); } return result; })); }