private bool FillGCDesc() { NativeRuntime runtime = _heap.NativeRuntime; int entries; if (!runtime.MemoryReader.TryReadDword(_eeType - (ulong)IntPtr.Size, out entries)) { return(false); } // Get entries in map if (entries < 0) { entries = -entries; } int read; int slots = 1 + entries * 2; byte[] buffer = new byte[slots * IntPtr.Size]; if (!runtime.ReadMemory(_eeType - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length) { return(false); } // Construct the gc desc _gcDesc = new GCDesc(buffer); return(true); }
public override IEnumerable <ClrReference> EnumerateReferencesWithFields(ulong obj, ClrType type, bool carefully, bool considerDependantHandles) { if (type is null) { throw new ArgumentNullException(nameof(type)); } if (considerDependantHandles) { ImmutableArray <(ulong Source, ulong Target)> dependent = GetHeapData().GetDependentHandles(_helpers); if (dependent.Length > 0) { int index = dependent.Search(obj, (x, y) => x.Source.CompareTo(y)); if (index != -1) { while (index >= 1 && dependent[index - 1].Source == obj) { index--; } while (index < dependent.Length && dependent[index].Source == obj) { ulong dependantObj = dependent[index++].Target; ClrObject target = new ClrObject(dependantObj, GetObjectType(dependantObj)); yield return(ClrReference.CreateFromDependentHandle(target)); } } } } if (type.ContainsPointers) { GCDesc gcdesc = type.GCDesc; if (!gcdesc.IsEmpty) { ulong size = GetObjectSize(obj, type); if (carefully) { ClrSegment?seg = GetSegmentByAddress(obj); if (seg is null || obj + size > seg.End || (!seg.IsLargeObjectSegment && size > MaxGen2ObjectSize)) { yield break; } } foreach ((ulong reference, int offset) in gcdesc.WalkObject(obj, size, _helpers.DataReader)) { ClrObject target = new ClrObject(reference, GetObjectType(reference)); yield return(ClrReference.CreateFromFieldOrArray(target, type, offset)); } } } }
private bool FillGCDesc() { DesktopRuntimeBase runtime = DesktopHeap.DesktopRuntime; int entries; if (!runtime.ReadDword(_constructedMT - (ulong)IntPtr.Size, out entries)) return false; // Get entries in map if (entries < 0) entries = -entries; int read; int slots = 1 + entries * 2; byte[] buffer = new byte[slots * IntPtr.Size]; if (!runtime.ReadMemory(_constructedMT - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length) return false; // Construct the gc desc _gcDesc = new GCDesc(buffer); return true; }
private bool FillGCDesc() { NativeRuntime runtime = _heap.NativeRuntime; int entries; if (!runtime.MemoryReader.TryReadDword(_eeType - (ulong)IntPtr.Size, out entries)) return false; // Get entries in map if (entries < 0) entries = -entries; int read; int slots = 1 + entries * 2; byte[] buffer = new byte[slots * IntPtr.Size]; if (!runtime.ReadMemory(_eeType - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length) return false; // Construct the gc desc _gcDesc = new GCDesc(buffer); return true; }
private static object DeserializeInner(RuntimeTypeHandle[] runtimeTypeHandles, byte *buffer, long length) { byte *objectId = buffer + IntPtr.Size; while (objectId < buffer + length) { IntPtr typeHandle = IntPtr.Size == 8 ? runtimeTypeHandles[(int)*(long *)objectId].Value : runtimeTypeHandles[*(int *)objectId].Value; bool isArray = ((long)typeHandle & 0x2) == 0x2; var mt = (MethodTable *)typeHandle; if (isArray) { mt = IntPtr.Size == 8 ? (MethodTable *)*(long *)(typeHandle + 6) : (MethodTable *)*(int *)(typeHandle + 6); // TODO: Is this correct for 32-bit? } long objectSize = mt->BaseSize; var flags = mt->Flags; bool hasComponentSize = (flags & 0x80000000) == 0x80000000; if (hasComponentSize) { var numComponents = (long)*(int *)(objectId + IntPtr.Size); objectSize += numComponents * mt->ComponentSize; } bool containsPointerOrCollectible = (flags & 0x10000000) == 0x10000000 || (flags & 0x1000000) == 0x1000000; if (containsPointerOrCollectible) { var entries = *(int *)((byte *)mt - IntPtr.Size); if (entries < 0) { entries -= entries; } var slots = 1 + entries * 2; var gcdesc = new GCDesc(buffer, (byte *)mt - (slots * IntPtr.Size), slots * IntPtr.Size); if (IntPtr.Size == 8) { gcdesc.FixupObject64(objectId, objectSize); } else { gcdesc.FixupObject32(objectId, objectSize); } } if (IntPtr.Size == 8) { *(long *)objectId = (long)mt; } else { *(int *)objectId = (int)mt; } objectId += objectSize + Padding(objectSize, IntPtr.Size); } var tmp = buffer + IntPtr.Size; return(Unsafe.Read <object>(&tmp)); }
public override IEnumerable <ClrObject> EnumerateObjectReferences(ulong obj, ClrType type, bool carefully, bool considerDependantHandles) { if (type is null) { throw new ArgumentNullException(nameof(type)); } if (considerDependantHandles) { ImmutableArray <(ulong Source, ulong Target)> dependent = GetHeapData().GetDependentHandles(_helpers); if (dependent.Length > 0) { int index = dependent.Search(obj, (x, y) => x.Source.CompareTo(y)); if (index != -1) { while (index >= 1 && dependent[index - 1].Source == obj) { index--; } while (index < dependent.Length && dependent[index].Source == obj) { ulong dependantObj = dependent[index++].Target; yield return(new ClrObject(dependantObj, GetObjectType(dependantObj))); } } } } if (type.IsCollectible) { ulong la = _helpers.DataReader.ReadPointer(type.LoaderAllocatorHandle); if (la != 0) { yield return(new ClrObject(la, GetObjectType(la))); } } if (type.ContainsPointers) { GCDesc gcdesc = type.GCDesc; if (!gcdesc.IsEmpty) { ulong size = GetObjectSize(obj, type); if (carefully) { ClrSegment?seg = GetSegmentByAddress(obj); if (seg is null || obj + size > seg.End || (!seg.IsLargeObjectSegment && size > MaxGen2ObjectSize)) { yield break; } } int intSize = (int)size; byte[] buffer = ArrayPool <byte> .Shared.Rent(intSize); try { int read = _helpers.DataReader.Read(obj, new Span <byte>(buffer, 0, intSize)); if (read > IntPtr.Size) { foreach ((ulong reference, int offset) in gcdesc.WalkObject(buffer, read)) { yield return(new ClrObject(reference, GetObjectType(reference))); } } } finally { ArrayPool <byte> .Shared.Return(buffer); } } } }
private static unsafe void WriteObjectGraphToDisk(byte *stackAllocatedData, Stream stream, Dictionary <object, long> serializedObjectMap, Queue <object> objectQueue, RuntimeTypeHandleDictionary mtTokenMap, ref long lastReservedObjectEnd) { long nextObjectHeaderFilePointer = 0; while (objectQueue.Count != 0) { object o = objectQueue.Dequeue(); ref TypeInfo typeInfo = ref mtTokenMap.GetOrAddValueRef(Type.GetTypeHandle(o)); long mtToken; if (typeInfo != null) { mtToken = typeInfo.MTToken; } else { mtToken = mtTokenMap.Count - 1; typeInfo = GetObjectInfo(o, mtToken); } long hashCode = (RuntimeHelpers.GetHashCode(o) & 0x0fffffff) | (1 << 27) | (1 << 26); fixed(byte *data = &GetRawData(o)) { MethodTable *mt; if (IntPtr.Size == 8) { *(long *)stackAllocatedData = hashCode; *(long *)(stackAllocatedData + 8) = mtToken; stream.Write(new ReadOnlySpan <byte>(stackAllocatedData, 16)); mt = (MethodTable *)*(long *)(data - IntPtr.Size); } else { *(int *)stackAllocatedData = (int)hashCode; *(int *)(stackAllocatedData + 4) = (int)mtToken; stream.Write(new ReadOnlySpan <byte>(stackAllocatedData, 8)); mt = (MethodTable *)*(int *)(data - IntPtr.Size); } uint flags = mt->Flags; bool hasComponentSize = (flags & 0x80000000) == 0x80000000; long objectSize = mt->BaseSize; if (hasComponentSize) { var numComponents = (long)*(int *)data; objectSize += numComponents * mt->ComponentSize; } var remainingSize = objectSize - IntPtr.Size - IntPtr.Size; // because we have already written the object header and MT Token if (remainingSize <= int.MaxValue) { stream.Write(new ReadOnlySpan <byte>(data, (int)remainingSize)); } else { WriteLargeObject(stream, data, remainingSize); } bool containsPointersOrCollectible = (flags & 0x10000000) == 0x10000000 || (flags & 0x1000000) == 0x1000000; if (containsPointersOrCollectible) { var gcdesc = new GCDesc(typeInfo.GCDescData, typeInfo.GCDescSize); gcdesc.EnumerateObject(data, objectSize, serializedObjectMap, objectQueue, stream, nextObjectHeaderFilePointer, ref lastReservedObjectEnd); } nextObjectHeaderFilePointer += objectSize + Padding(objectSize, IntPtr.Size); stream.Seek(nextObjectHeaderFilePointer, SeekOrigin.Begin); } }