public static int ReadStringObjectSizeInBytes(BytesAndOffset bo, VirtualMachineInformation virtualMachineInformation) { var lengthPointer = bo.Add(virtualMachineInformation.objectHeaderSize); var length = lengthPointer.ReadInt32(); return(virtualMachineInformation.objectHeaderSize + /*lengthfield*/ 1 + (length * /*utf16=2bytes per char*/ 2) + /*2 zero terminators*/ 2); }
public BytesAndOffset Find(ulong address, VirtualMachineInformation virtualMachineInformation) { using (cacheFind.Auto()) { var bytesAndOffset = new BytesAndOffset(); if (address != 0 && address >= minAddress && address < maxAddress) { int idx = Array.BinarySearch(startAddress, address); if (idx < 0) { idx = ~idx - 1; } if (address >= startAddress[idx] && address < (startAddress[idx] + (ulong)bytes[idx].Length)) { bytesAndOffset.bytes = bytes[idx]; bytesAndOffset.offset = (int)(address - startAddress[idx]); bytesAndOffset.pointerSize = virtualMachineInformation.pointerSize; } } return(bytesAndOffset); } }
public static int ReadArrayLength(CachedSnapshot data, BytesAndOffset arrayData, int iTypeDescriptionArrayType) { if (iTypeDescriptionArrayType < 0) { return(0); } var virtualMachineInformation = data.virtualMachineInformation; var heap = data.managedHeapSections; var bo = arrayData; var bounds = bo.Add(virtualMachineInformation.arrayBoundsOffsetInHeader).ReadPointer(); if (bounds == 0) { return(bo.Add(virtualMachineInformation.arraySizeOffsetInHeader).ReadInt32()); } var cursor = heap.Find(bounds, virtualMachineInformation); int length = 1; int rank = data.typeDescriptions.GetRank(iTypeDescriptionArrayType); for (int i = 0; i != rank; i++) { length *= cursor.ReadInt32(); cursor = cursor.Add(8); } return(length); }
static void CrawlRawObjectData(IntermediateCrawlData crawlData, BytesAndOffset bytesAndOffset, int iTypeDescription, bool useStaticFields, ulong ptrFrom, int indexOfFrom) { var snapshot = crawlData.CachedMemorySnapshot; var fields = useStaticFields ? snapshot.typeDescriptions.fieldIndicesOwned_static[iTypeDescription] : snapshot.typeDescriptions.fieldIndices_instance[iTypeDescription]; foreach (var iField in fields) { int iField_TypeDescription_TypeIndex = snapshot.fieldDescriptions.typeIndex[iField]; int iField_TypeDescription_ArrayIndex = snapshot.typeDescriptions.TypeIndex2ArrayIndex(iField_TypeDescription_TypeIndex); var fieldLocation = bytesAndOffset.Add(snapshot.fieldDescriptions.offset[iField] - (useStaticFields ? 0 : snapshot.virtualMachineInformation.objectHeaderSize)); if (snapshot.typeDescriptions.HasFlag(iField_TypeDescription_ArrayIndex, TypeFlags.kValueType)) { CrawlRawObjectData(crawlData, fieldLocation, iField_TypeDescription_ArrayIndex, useStaticFields, ptrFrom, indexOfFrom); continue; } ulong fieldAddr; if (fieldLocation.TryReadPointer(out fieldAddr) == BytesAndOffset.PtrReadError.Success) { crawlData.CrawlDataStack.Push(new StackCrawlData() { ptr = fieldAddr, ptrFrom = ptrFrom, typeFrom = iTypeDescription, indexOfFrom = indexOfFrom, fieldFrom = iField, fromArrayIndex = -1 }); } } }
public static string ReadString(BytesAndOffset bo, VirtualMachineInformation virtualMachineInformation) { var lengthPointer = bo.Add(virtualMachineInformation.objectHeaderSize); var length = lengthPointer.ReadInt32(); var firstChar = lengthPointer.Add(4); return(System.Text.Encoding.Unicode.GetString(firstChar.bytes, firstChar.offset, length * 2)); }
private ObjectData(ObjectDataType t) { m_dataType = t; m_data = new Data(); m_data.managed.objectPtr = 0; managedObjectData = new BytesAndOffset(); m_data.managed.iType = -1; m_Parent = null; }
public static ManagedObjectInfo ParseObjectHeader(CachedSnapshot snapshot, BytesAndOffset byteOffset, bool ignoreBadHeaderError) { var heap = snapshot.managedHeapSections; ManagedObjectInfo objectInfo; objectInfo = new ManagedObjectInfo(); objectInfo.PtrObject = 0; objectInfo.ManagedObjectIndex = -1; var boHeader = byteOffset; ulong ptrIdentity; boHeader.TryReadPointer(out ptrIdentity); objectInfo.PtrTypeInfo = ptrIdentity; objectInfo.ITypeDescription = snapshot.typeDescriptions.TypeInfo2ArrayIndex(objectInfo.PtrTypeInfo); bool error = false; if (objectInfo.ITypeDescription < 0) { var boIdentity = heap.Find(ptrIdentity, snapshot.virtualMachineInformation); if (boIdentity.IsValid) { ulong ptrTypeInfo; boIdentity.TryReadPointer(out ptrTypeInfo); objectInfo.PtrTypeInfo = ptrTypeInfo; objectInfo.ITypeDescription = snapshot.typeDescriptions.TypeInfo2ArrayIndex(objectInfo.PtrTypeInfo); error = objectInfo.ITypeDescription < 0; } else { error = true; } } if (!error) { objectInfo.Size = SizeOfObjectInBytes(snapshot, objectInfo.ITypeDescription, boHeader, heap); objectInfo.data = boHeader; } else { if (!ignoreBadHeaderError) { #if DEBUG_VALIDATION UnityEngine.Debug.LogError("Bad object header at address: " + ptrIdentity); #endif } objectInfo.PtrTypeInfo = 0; objectInfo.ITypeDescription = -1; objectInfo.Size = 0; } return(objectInfo); }
public static ArrayInfo GetArrayInfo(CachedSnapshot data, BytesAndOffset arrayData, int iTypeDescriptionArrayType) { var virtualMachineInformation = data.virtualMachineInformation; var arrayInfo = new ArrayInfo(); arrayInfo.baseAddress = 0; arrayInfo.arrayTypeDescription = iTypeDescriptionArrayType; arrayInfo.header = arrayData; arrayInfo.data = arrayInfo.header.Add(virtualMachineInformation.arrayHeaderSize); ulong bounds; arrayInfo.header.Add(virtualMachineInformation.arrayBoundsOffsetInHeader).TryReadPointer(out bounds); if (bounds == 0) { arrayInfo.length = arrayInfo.header.Add(virtualMachineInformation.arraySizeOffsetInHeader).ReadInt32(); arrayInfo.rank = new int[1] { arrayInfo.length }; } else { var cursor = data.managedHeapSections.Find(bounds, virtualMachineInformation); int rank = data.typeDescriptions.GetRank(iTypeDescriptionArrayType); arrayInfo.rank = new int[rank]; arrayInfo.length = 1; for (int i = 0; i != rank; i++) { var l = cursor.ReadInt32(); arrayInfo.length *= l; arrayInfo.rank[i] = l; cursor = cursor.Add(8); } } arrayInfo.elementTypeDescription = data.typeDescriptions.baseOrElementTypeIndex[iTypeDescriptionArrayType]; if (arrayInfo.elementTypeDescription == -1) //We currently do not handle uninitialized types as such override the type, making it return pointer size { arrayInfo.elementTypeDescription = iTypeDescriptionArrayType; } if (data.typeDescriptions.HasFlag(arrayInfo.elementTypeDescription, TypeFlags.kValueType)) { arrayInfo.elementSize = data.typeDescriptions.size[arrayInfo.elementTypeDescription]; } else { arrayInfo.elementSize = virtualMachineInformation.pointerSize; } return(arrayInfo); }
public static int ReadArrayObjectSizeInBytes(CachedSnapshot data, BytesAndOffset arrayData, int iTypeDescriptionArrayType) { var arrayLength = ReadArrayLength(data, arrayData, iTypeDescriptionArrayType); var virtualMachineInformation = data.virtualMachineInformation; var ti = data.typeDescriptions.baseOrElementTypeIndex[iTypeDescriptionArrayType]; if (ti == -1) // check added as element type index can be -1 if we are dealing with a class member (eg: Dictionary.Entry) whose type is uninitialized due to their generic data not getting inflated a.k.a unused types { ti = iTypeDescriptionArrayType; } var ai = data.typeDescriptions.TypeIndex2ArrayIndex(ti); var isValueType = data.typeDescriptions.HasFlag(ai, TypeFlags.kValueType); var elementSize = isValueType ? data.typeDescriptions.size[ai] : virtualMachineInformation.pointerSize; return(virtualMachineInformation.arrayHeaderSize + elementSize * arrayLength); }
static void CrawlRawObjectData(IntermediateCrawlData crawlData, BytesAndOffset bytesAndOffset, int iTypeDescription, bool useStaticFields, ulong ptrFrom, int indexOfFrom) { var snapshot = crawlData.CachedMemorySnapshot; var fields = useStaticFields ? snapshot.typeDescriptions.fieldIndicesOwned_static[iTypeDescription] : snapshot.typeDescriptions.fieldIndices_instance[iTypeDescription]; foreach (var iField in fields) { int iField_TypeDescription_TypeIndex = snapshot.fieldDescriptions.typeIndex[iField]; int iField_TypeDescription_ArrayIndex = snapshot.typeDescriptions.TypeIndex2ArrayIndex(iField_TypeDescription_TypeIndex); var fieldLocation = bytesAndOffset.Add(snapshot.fieldDescriptions.offset[iField] - (useStaticFields ? 0 : snapshot.virtualMachineInformation.objectHeaderSize)); if (snapshot.typeDescriptions.HasFlag(iField_TypeDescription_ArrayIndex, TypeFlags.kValueType)) { CrawlRawObjectData(crawlData, fieldLocation, iField_TypeDescription_ArrayIndex, useStaticFields, ptrFrom, indexOfFrom); continue; } //Workaround that was done to not error out when trying to read an array where the remaining length is less than that pointer size. bool gotException = false; try { ulong ptr = fieldLocation.ReadPointer(); if (ptr == 0) { gotException = true; } } catch (ArgumentException) { gotException = true; } if (!gotException) { crawlData.CrawlDataStack.Push(new StackCrawlData() { ptr = fieldLocation.ReadPointer(), ptrFrom = ptrFrom, typeFrom = iTypeDescription, indexOfFrom = indexOfFrom, fieldFrom = iField, fromArrayIndex = -1 }); } } }
static int SizeOfObjectInBytes(CachedSnapshot snapshot, int iTypeDescription, BytesAndOffset byteOffset, CachedSnapshot.ManagedMemorySectionEntriesCache heap) { if (iTypeDescription < 0) { return(0); } if (snapshot.typeDescriptions.HasFlag(iTypeDescription, TypeFlags.kArray)) { return(ArrayTools.ReadArrayObjectSizeInBytes(snapshot, byteOffset, iTypeDescription)); } if (snapshot.typeDescriptions.typeDescriptionName[iTypeDescription] == "System.String") { return(StringTools.ReadStringObjectSizeInBytes(byteOffset, snapshot.virtualMachineInformation)); } //array and string are the only types that are special, all other types just have one size, which is stored in the type description return(snapshot.typeDescriptions.size[iTypeDescription]); }
public static IEnumerator Crawl(CachedSnapshot snapshot) { const int stepCount = 5; var status = new EnumerationUtilities.EnumerationStatus(stepCount); IntermediateCrawlData crawlData = new IntermediateCrawlData(snapshot); crawlData.ManagedObjectInfos.Capacity = (int)snapshot.gcHandles.Count * 3; crawlData.ManagedConnections.Capacity = (int)snapshot.gcHandles.Count * 6; //Gather handles and duplicates status.StepStatus = "Gathering snapshot managed data."; yield return(status); GatherIntermediateCrawlData(snapshot, crawlData); //crawl handle data status.IncrementStep(); status.StepStatus = "Crawling GC handles."; yield return(status); while (crawlData.CrawlDataStack.Count > 0) { CrawlPointer(crawlData); } //crawl data pertaining to types with static fields and enqueue any heap objects status.IncrementStep(); status.StepStatus = "Crawling data types with static fields"; yield return(status); for (int i = 0; i < crawlData.TypesWithStaticFields.Count; i++) { var iTypeDescription = crawlData.TypesWithStaticFields[i]; var bytesOffset = new BytesAndOffset { bytes = snapshot.typeDescriptions.staticFieldBytes[iTypeDescription], offset = 0, pointerSize = snapshot.virtualMachineInformation.pointerSize }; CrawlRawObjectData(crawlData, bytesOffset, iTypeDescription, true, 0, -1); } //crawl handles belonging to static instances status.IncrementStep(); status.StepStatus = "Crawling static instances heap data."; yield return(status); while (crawlData.CrawlDataStack.Count > 0) { CrawlPointer(crawlData); } //copy crawled object source data for duplicate objects foreach (var i in crawlData.DuplicatedGCHandlesStack) { var ptr = snapshot.CrawledData.ManagedObjects[i].PtrObject; snapshot.CrawledData.ManagedObjects[i] = snapshot.CrawledData.ManagedObjectByAddress[ptr]; } //crawl connection data status.IncrementStep(); status.StepStatus = "Crawling connection data"; yield return(status); ConnectNativeToManageObject(crawlData); AddupRawRefCount(crawlData.CachedMemorySnapshot); }
// Returns a new ObjectData pointing to the object's (that this ObjectData is currently pointing at) field // using a field index from snapshot.fieldDescriptions public ObjectData GetInstanceFieldBySnapshotFieldIndex(CachedSnapshot snapshot, int iField, bool expandToTarget) { ObjectData obj; ulong objectPtr; switch (m_dataType) { case ObjectDataType.ReferenceObject: objectPtr = GetReferencePointer(); obj = FromManagedPointer(snapshot, objectPtr); break; case ObjectDataType.BoxedValue: case ObjectDataType.Object: case ObjectDataType.Value: case ObjectDataType.Type: objectPtr = m_data.managed.objectPtr; obj = this; break; //case ObjectDataType.ReferenceArray: default: //TODO: add proper handling for missing types //DebugUtility.LogError("Requesting a field on an invalid data type"); return(new ObjectData()); } var fieldOffset = snapshot.fieldDescriptions.offset[iField]; var fieldType = snapshot.fieldDescriptions.typeIndex[iField]; bool isStatic = snapshot.fieldDescriptions.isStatic[iField]; switch (m_dataType) { case ObjectDataType.Value: if (!isStatic) { fieldOffset -= snapshot.virtualMachineInformation.objectHeaderSize; } break; case ObjectDataType.Object: case ObjectDataType.BoxedValue: break; case ObjectDataType.Type: if (!isStatic) { Debug.LogError("Requesting a non-static field on a type"); return(invalid); } break; default: break; } ObjectData o = new ObjectData(); o.m_Parent = new ObjectDataParent(obj, iField, -1, expandToTarget); o.SetManagedType(snapshot, fieldType); o.m_dataType = TypeToSubDataType(snapshot, fieldType); if (isStatic) { //the field requested might come from a base class. make sure we are using the right staticFieldBytes. var iOwningType = obj.m_data.managed.iType; while (iOwningType >= 0) { var fieldIndex = System.Array.FindIndex(snapshot.typeDescriptions.fieldIndicesOwned_static[iOwningType], x => x == iField); if (fieldIndex >= 0) { //field iField is owned by type iCurrentBase break; } iOwningType = snapshot.typeDescriptions.baseOrElementTypeIndex[iOwningType]; } if (iOwningType < 0) { Debug.LogError("Field requested is not owned by the type not any of its bases"); return(invalid); } o.m_data.managed.objectPtr = 0; var typeStaticData = new BytesAndOffset(snapshot.typeDescriptions.staticFieldBytes[iOwningType], snapshot.virtualMachineInformation.pointerSize); o.managedObjectData = typeStaticData.Add(fieldOffset); } else { o.m_data.managed.objectPtr = objectPtr;// m_data.managed.objectPtr; o.managedObjectData = obj.managedObjectData.Add(fieldOffset); } return(o); }