internal static int ReadArrayLength(MemorySection[] heap, UInt64 address, TypeDescription arrayType, VirtualMachineInformation virtualMachineInformation) { BytesAndOffset bo = heap.Find(address, virtualMachineInformation); UInt64 bounds = bo.Add(virtualMachineInformation.arrayBoundsOffsetInHeader).ReadPointer(); if (bounds == 0) #if UNITY_2017_2_OR_NEWER { return((int)bo.Add(virtualMachineInformation.arraySizeOffsetInHeader).ReadPointer()); } #else { return(bo.Add(virtualMachineInformation.arraySizeOffsetInHeader).ReadInt32()); } #endif BytesAndOffset cursor = heap.Find(bounds, virtualMachineInformation); int length = 1; for (int i = 0; i != arrayType.arrayRank; i++) { #if UNITY_2017_2_OR_NEWER length *= (int)cursor.ReadPointer(); cursor = cursor.Add(virtualMachineInformation.pointerSize == 4 ? 8 : 16); #else length *= cursor.ReadInt32(); cursor = cursor.Add(8); #endif } return(length); }
private void CrawlPointerNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, ulong pointer, int indexOfFrom, List <Connection> out_connections, List <PackedManagedObject> out_managedObjects, Stack <ThingToProfile> out_thingsToProfile) { BytesAndOffset bo = packedMemorySnapshot.managedHeapSections.Find(pointer, _virtualMachineInformation); if (!bo.IsValid) { return; } UInt64 typeInfoAddress; int indexOfObject; bool wasAlreadyCrawled; try { ParseObjectHeader(startIndices, packedMemorySnapshot.managedHeapSections, pointer, out typeInfoAddress, out indexOfObject, out wasAlreadyCrawled, out_managedObjects); } catch (Exception e) { UnityEngine.Debug.LogWarningFormat("Exception parsing object header. Skipping. {0}", e); return; } out_connections.Add(new Connection() { from = indexOfFrom, to = indexOfObject }); if (wasAlreadyCrawled) { return; } TypeDescription typeDescription = _typeInfoToTypeDescription[typeInfoAddress]; if (!typeDescription.isArray) { out_thingsToProfile.Push(new ThingToProfile(typeDescription, bo.Add(_virtualMachineInformation.objectHeaderSize), false, indexOfObject)); return; } int arrayLength = ArrayTools.ReadArrayLength(packedMemorySnapshot.managedHeapSections, pointer, typeDescription, _virtualMachineInformation); TypeDescription elementType = packedMemorySnapshot.typeDescriptions[typeDescription.baseOrElementTypeIndex]; BytesAndOffset cursor = bo.Add(_virtualMachineInformation.arrayHeaderSize); for (int i = 0; i != arrayLength; i++) { if (elementType.isValueType) { out_thingsToProfile.Push(new ThingToProfile(elementType, cursor, false, indexOfObject)); cursor = cursor.Add(elementType.size); } else { out_thingsToProfile.Push(new ThingToProfile(cursor.ReadPointer(), indexOfObject)); cursor = cursor.NextPointer(); } } }
private void CrawlRawObjectData(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom, List <Connection> out_connections, List <PackedManagedObject> out_managedObjects) { var fields = useStaticFields ? _staticFields[typeDescription.typeIndex] : _instanceFields[typeDescription.typeIndex]; foreach (var field in fields) { var fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex]; var fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize)); if (fieldType.isValueType) { CrawlRawObjectData(packedMemorySnapshot, startIndices, fieldLocation, fieldType, false, indexOfFrom, out_connections, out_managedObjects); continue; } //temporary workaround for a bug in 5.3b4 and earlier where we would get literals returned as fields with offset 0. soon we'll be able to remove this code. bool gotException = false; try { fieldLocation.ReadPointer(); } catch (ArgumentException) { UnityEngine.Debug.LogWarningFormat("Skipping field {0} on type {1}", field.name, typeDescription.name); UnityEngine.Debug.LogWarningFormat("FieldType.name: {0}", fieldType.name); gotException = true; } if (!gotException) { CrawlPointer(packedMemorySnapshot, startIndices, fieldLocation.ReadPointer(), indexOfFrom, out_connections, out_managedObjects); } } }
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 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 void CrawlRawObjectData(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom, List <Connection> out_connections, List <PackedManagedObject> out_managedObjects) { foreach (var field in TypeTools.AllFieldsOf(typeDescription, _typeDescriptions, useStaticFields ? TypeTools.FieldFindOptions.OnlyStatic : TypeTools.FieldFindOptions.OnlyInstance)) { if (field.typeIndex == typeDescription.typeIndex && typeDescription.isValueType) { //this happens in System.Single, which is a weird type that has a field of its own type. continue; } if (field.offset == -1) { //this is how we encode TLS fields. todo: actually treat TLS fields as roots continue; } var fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex]; var fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize)); if (fieldType.isValueType) { CrawlRawObjectData(packedMemorySnapshot, startIndices, fieldLocation, fieldType, false, indexOfFrom, out_connections, out_managedObjects); continue; } //temporary workaround for a bug in 5.3b4 and earlier where we would get literals returned as fields with offset 0. soon we'll be able to remove this code. bool gotException = false; try { fieldLocation.ReadPointer(); } catch (ArgumentException) { UnityEngine.Debug.LogWarningFormat("Skipping field {0} on type {1}", field.name, typeDescription.name); UnityEngine.Debug.LogWarningFormat("FieldType.name: {0}", fieldType.name); gotException = true; } if (!gotException) { CrawlPointer(packedMemorySnapshot, startIndices, fieldLocation.ReadPointer(), indexOfFrom, out_connections, out_managedObjects); } } }
private void CrawlRawObjectDataNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom, List <Connection> out_connections, List <PackedManagedObject> out_managedObjects, Stack <ThingToProfile> out_thingsToProfile) { // Do not crawl MemoryProfilerWindow objects if (typeDescription.name.StartsWith("MemoryProfilerWindow.")) { return; } FieldDescription[] fields = useStaticFields ? _staticFields[typeDescription.typeIndex] : _instanceFields[typeDescription.typeIndex]; for (int i = 0; i < fields.Length; ++i) { FieldDescription field = fields[i]; TypeDescription fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex]; BytesAndOffset fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize)); if (fieldType.isValueType) { out_thingsToProfile.Push(new ThingToProfile(fieldType, fieldLocation, false, indexOfFrom)); continue; } else { //temporary workaround for a bug in 5.3b4 and earlier where we would get literals returned as fields with offset 0. soon we'll be able to remove this code. bool gotException = false; try { fieldLocation.ReadPointer(); } catch (ArgumentException) { UnityEngine.Debug.LogWarningFormat("Skipping field {0} on type {1}", field.name, typeDescription.name); UnityEngine.Debug.LogWarningFormat("FieldType.name: {0}", fieldType.name); gotException = true; } if (!gotException) { out_thingsToProfile.Push(new ThingToProfile(fieldLocation.ReadPointer(), indexOfFrom)); } } } }
private void DrawFields(TypeDescription typeDescription, BytesAndOffset bytesAndOffset, bool useStatics = false) { int counter = 0; foreach (var field in TypeTools.AllFieldsOf(typeDescription, _unpackedCrawl.typeDescriptions, useStatics ? TypeTools.FieldFindOptions.OnlyStatic : TypeTools.FieldFindOptions.OnlyInstance)) { counter++; var gUIStyle = counter % 2 == 0 ? Styles.entryEven : Styles.entryOdd; gUIStyle.margin = new RectOffset(0, 0, 0, 0); gUIStyle.overflow = new RectOffset(0, 0, 0, 0); gUIStyle.padding = EditorStyles.label.padding; GUILayout.BeginHorizontal(gUIStyle); GUILayout.Label(field.name, labelWidth); GUILayout.BeginVertical(); DrawValueFor(field, bytesAndOffset.Add(field.offset)); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } }