// address = object address (start of header) System.ArraySegment <byte> ReadObjectBytes(System.UInt64 address, PackedManagedType typeDescription) { var size = ReadObjectSize(address, typeDescription); if (size <= 0) { return(new System.ArraySegment <byte>()); } var offset = TryBeginRead(address); if (offset < 0) { return(new System.ArraySegment <byte>()); } // Unity bug? For a reason that I do not understand, sometimes a memory segment is smaller // than the actual size of an object. In order to workaround this issue, we make sure to never // try to read more data from the segment than is available. if ((m_Bytes.Length - offset) < size) { //var wantedLength = size; size = m_Bytes.Length - offset; //Debug.LogErrorFormat("Cannot read entire string 0x{0:X}. The requested length in bytes is {1}, but the memory segment holds {2} bytes only.\n{3}...", address, wantedLength, size, System.Text.Encoding.Unicode.GetString(m_bytes, offset, Mathf.Min(size, 32))); if (size <= 0) { return(new System.ArraySegment <byte>()); } } var segment = new System.ArraySegment <byte>(m_Bytes, offset, size); return(segment); }
public static bool HasTypeOrBaseAnyStaticField(PackedMemorySnapshot snapshot, PackedManagedType type, out PackedManagedType fieldType) { fieldType = new PackedManagedType(); fieldType.managedTypesArrayIndex = -1; fieldType.nativeTypeArrayIndex = -1; fieldType.baseOrElementTypeIndex = -1; var loopguard = 0; do { if (++loopguard > 64) { Debug.LogError("loopguard kicked in"); break; } if (type.staticFields.Length > 0) { fieldType = snapshot.managedTypes[type.staticFields[0].managedTypesArrayIndex]; return(true); } if (type.baseOrElementTypeIndex != -1) { type = snapshot.managedTypes[type.baseOrElementTypeIndex]; } } while (type.baseOrElementTypeIndex != -1 && type.managedTypesArrayIndex != type.baseOrElementTypeIndex); return(false); }
/// <summary> /// Computes a checksum of the managed object specified at 'address'. /// This is used to find object duplicates. /// </summary> public UnityEngine.Hash128 ComputeObjectHash(System.UInt64 address, PackedManagedType type) { if (m_Hasher == null) { m_Hasher = System.Security.Cryptography.MD5.Create(); } var content = ReadObjectBytes(address, type); if (content.Count == 0) { return(new Hash128()); } var bytes = m_Hasher.ComputeHash(content.Array, content.Offset, content.Count); if (bytes.Length != 16) { return(new Hash128()); } var v0 = (uint)(bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24); var v1 = (uint)(bytes[4] << 32 | bytes[5] << 40 | bytes[6] << 48 | bytes[7] << 56); var v2 = (uint)(bytes[8] | bytes[9] << 8 | bytes[10] << 16 | bytes[11] << 24); var v3 = (uint)(bytes[12] << 32 | bytes[13] << 40 | bytes[14] << 48 | bytes[15] << 56); return(new Hash128(v0, v1, v2, v3)); }
/// <summary> /// Gets whether any type in its inheritance chain has an instance field. /// </summary> public static bool HasTypeOrBaseAnyField(PackedMemorySnapshot snapshot, PackedManagedType type, bool checkInstance, bool checkStatic) { var loopguard = 0; do { if (++loopguard > 64) { Debug.LogError("loopguard kicked in"); break; } if (checkInstance && type.instanceFields.Length > 0) { return(true); } if (checkStatic && type.staticFields.Length > 0) { return(true); } if (type.baseOrElementTypeIndex != -1) { type = snapshot.managedTypes[type.baseOrElementTypeIndex]; } } while (type.baseOrElementTypeIndex != -1 && type.managedTypesArrayIndex != type.baseOrElementTypeIndex); return(false); }
public static PackedManagedType[] FromMemoryProfiler(UnityEditor.MemoryProfiler.TypeDescription[] source) { var value = new PackedManagedType[source.Length]; for (int n = 0, nend = source.Length; n < nend; ++n) { value[n] = new PackedManagedType { isValueType = source[n].isValueType, isArray = source[n].isArray, arrayRank = source[n].arrayRank, name = source[n].name, assembly = source[n].assembly, fields = PackedManagedField.FromMemoryProfiler(source[n].fields), staticFieldBytes = source[n].staticFieldBytes, baseOrElementTypeIndex = source[n].baseOrElementTypeIndex, size = source[n].size, typeInfoAddress = source[n].typeInfoAddress, managedTypesArrayIndex = source[n].typeIndex, nativeTypeArrayIndex = -1, }; // namespace-less types have a preceding dot, which we remove here if (value[n].name != null && value[n].name.Length > 0 && value[n].name[0] == '.') { value[n].name = value[n].name.Substring(1); } } return(value); }
public bool IsSubclassOf(PackedManagedType type, int baseTypeIndex) { if (type.managedTypesArrayIndex == baseTypeIndex) { return(true); } if (type.managedTypesArrayIndex < 0 || baseTypeIndex < 0) { return(false); } var guard = 0; while (type.baseOrElementTypeIndex != -1) { // safety code in case of an infite loop if (++guard > 64) { return(false); } if (type.managedTypesArrayIndex == baseTypeIndex) { return(true); } // get type of the base class type = managedTypes[type.baseOrElementTypeIndex]; } return(false); }
/// <summary> /// Loads a memory snapshot from the specified 'filePath' and stores the result in 'snapshot'. /// </summary> /// <param name="filePath">Absolute file path</param> public bool LoadFromFile(string filePath) { busyString = "Loading"; using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open)) { using (var reader = new System.IO.BinaryReader(fileStream)) { try { PackedMemorySnapshotHeader.Read(reader, out header, out busyString); if (!header.isValid) { throw new Exception("Invalid header."); } PackedNativeType.Read(reader, out nativeTypes, out busyString); PackedNativeUnityEngineObject.Read(reader, out nativeObjects, out busyString); PackedGCHandle.Read(reader, out gcHandles, out busyString); PackedConnection.Read(reader, out connections, out busyString); PackedMemorySection.Read(reader, out managedHeapSections, out busyString); PackedManagedType.Read(reader, out managedTypes, out busyString); PackedVirtualMachineInformation.Read(reader, out virtualMachineInformation, out busyString); } catch (System.Exception e) { Debug.LogException(e); return(false); } } } return(true); }
/// <summary> /// Gets whether this native type is a subclass of the specified type 't'. /// </summary> public bool IsSubclassOf(PackedManagedType t) { if (!isValid || t.managedTypesArrayIndex == -1) { return(false); } var me = m_Snapshot.managedTypes[m_ManagedTypesArrayIndex]; if (me.managedTypesArrayIndex == t.managedTypesArrayIndex) { return(true); } var guard = 0; while (me.baseOrElementTypeIndex != -1) { if (++guard > 64) { break; // no inheritance should have more depths than this } if (me.baseOrElementTypeIndex == t.managedTypesArrayIndex) { return(true); } me = m_Snapshot.managedTypes[me.baseOrElementTypeIndex]; } return(false); }
void SetObjectSize(ref PackedManagedObject managedObj, PackedManagedType type) { if (managedObj.size > 0) { return; // size is set already } managedObj.size = m_MemoryReader.ReadObjectSize(managedObj.address, type); }
public static void ManagedTypeIcon(Rect position, PackedManagedType type) { var isValueType = type.isValueType; var icon = isValueType ? HeEditorStyles.csValueTypeImage : HeEditorStyles.csReferenceTypeImage; var content = new GUIContent(icon, isValueType ? "ValueType" : "ReferenceType"); GUI.Box(HeEditorGUI.SpaceL(ref position, position.height), content, HeEditorStyles.iconStyle); }
public void Initialize(PackedMemorySnapshot snapshot, AbstractMemoryReader memoryReader, System.UInt64 address, PackedManagedType type) { m_Snapshot = snapshot; m_Address = address; m_Type = type; m_MemoryReader = memoryReader; m_Title = string.Format("{0} Visualizer", type.name); OnInitialize(); }
/// <summary> /// Converts an Unity PackedMemorySnapshot to our own format. /// </summary> public static PackedMemorySnapshot FromMemoryProfiler(MemorySnapshotProcessingArgs args) { var source = args.source; var value = new PackedMemorySnapshot(); try { VerifyMemoryProfilerSnapshot(source); value.busyString = "Loading Header"; value.header = PackedMemorySnapshotHeader.FromMemoryProfiler(); value.busyString = string.Format("Loading {0} Native Types", source.nativeTypes.Length); value.nativeTypes = PackedNativeType.FromMemoryProfiler(source.nativeTypes); value.busyString = string.Format("Loading {0} Native Objects", source.nativeObjects.Length); value.nativeObjects = PackedNativeUnityEngineObject.FromMemoryProfiler(source.nativeObjects); value.busyString = string.Format("Loading {0} GC Handles", source.gcHandles.Length); value.gcHandles = PackedGCHandle.FromMemoryProfiler(source.gcHandles); value.busyString = string.Format("Loading {0} Object Connections", source.connections.Length); if (args.excludeNativeFromConnections) { value.connections = ConnectionsFromMemoryProfilerWithoutNativeHACK(value, source); } else { value.connections = PackedConnection.FromMemoryProfiler(source.connections); } value.busyString = string.Format("Loading {0} Managed Heap Sections", source.managedHeapSections.Length); value.managedHeapSections = PackedMemorySection.FromMemoryProfiler(source.managedHeapSections); value.busyString = string.Format("Loading {0} Managed Types", source.typeDescriptions.Length); value.managedTypes = PackedManagedType.FromMemoryProfiler(source.typeDescriptions); value.busyString = "Loading VM Information"; value.virtualMachineInformation = PackedVirtualMachineInformation.FromMemoryProfiler(source.virtualMachineInformation); } catch (System.Exception e) { Debug.LogException(e); value = null; throw; } return(value); }
public void FindManagedStaticFieldsOfType(PackedManagedType type, List <int> target) { if (target == null) { return; } for (int n = 0, nend = managedStaticFields.Length; n < nend; ++n) { if (managedStaticFields[n].managedTypesArrayIndex == type.managedTypesArrayIndex) { target.Add(managedStaticFields[n].staticFieldsArrayIndex); } } }
void TryCreateDataVisualizer(AbstractMemoryReader reader, PackedManagedType type, ulong address, bool resolveAddress) { m_DataVisualizer = null; m_DataVisualizerScrollPos = new Vector2(); //if (AbstractDataVisualizer.HasVisualizer(type.name)) { if (type.isPointer && resolveAddress) { address = reader.ReadPointer(address); } m_DataVisualizer = AbstractDataVisualizer.CreateVisualizer(type.name); m_DataVisualizer.Initialize(m_Snapshot, reader, address, type); } }
public static GUIContent GetTypeContent(PackedMemorySnapshot snapshot, PackedManagedType type) { const string valueTypeLabel = "Value types are either stack-allocated or allocated inline in a structure."; const string referenceTypeLabel = "Reference types are heap-allocated."; if (type.isValueType) { if (snapshot.IsSubclassOf(type, snapshot.coreTypes.systemEnum)) { return(new GUIContent(csEnumTypeImage, valueTypeLabel)); } return(new GUIContent(csValueTypeImage, valueTypeLabel)); } return(new GUIContent(csReferenceTypeImage, referenceTypeLabel)); }
/// <summary> /// Saves the specfified memory snapshot as a file, using the specified 'filePath'. /// </summary> public void SaveToFile(string filePath) { using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.OpenOrCreate)) { using (var writer = new System.IO.BinaryWriter(fileStream)) { PackedMemorySnapshotHeader.Write(writer, header); PackedNativeType.Write(writer, nativeTypes); PackedNativeUnityEngineObject.Write(writer, nativeObjects); PackedGCHandle.Write(writer, gcHandles); PackedConnection.Write(writer, connections); PackedMemorySection.Write(writer, managedHeapSections); PackedManagedType.Write(writer, managedTypes); PackedVirtualMachineInformation.Write(writer, virtualMachineInformation); } } }
public bool IsEnum(PackedManagedType type) { if (!type.isValueType) { return(false); } if (type.baseOrElementTypeIndex == -1) { return(false); } if (type.baseOrElementTypeIndex != coreTypes.systemEnum) { return(false); } return(true); }
public int ReadArrayLength(System.UInt64 address, PackedManagedType arrayType) { var vm = m_Snapshot.virtualMachineInformation; var bounds = ReadPointer(address + (ulong)vm.arrayBoundsOffsetInHeader); if (bounds == 0) { return((int)ReadPointer(address + (ulong)vm.arraySizeOffsetInHeader)); } int length = 1; for (int i = 0; i != arrayType.arrayRank; i++) { var ptr = bounds + (ulong)(i * vm.pointerSize); length *= (int)ReadPointer(ptr); } return(length); }
public static void Read(System.IO.BinaryReader reader, out PackedManagedType[] value, out string stateString) { value = new PackedManagedType[0]; stateString = ""; var version = reader.ReadInt32(); if (version >= 1) { var length = reader.ReadInt32(); stateString = string.Format("Loading {0} Managed Types", length); value = new PackedManagedType[length]; for (int n = 0, nend = value.Length; n < nend; ++n) { value[n].isValueType = reader.ReadBoolean(); value[n].isArray = reader.ReadBoolean(); value[n].arrayRank = reader.ReadInt32(); value[n].name = reader.ReadString(); value[n].assembly = reader.ReadString(); var count = reader.ReadInt32(); value[n].staticFieldBytes = reader.ReadBytes(count); value[n].baseOrElementTypeIndex = reader.ReadInt32(); value[n].size = reader.ReadInt32(); value[n].typeInfoAddress = reader.ReadUInt64(); value[n].managedTypesArrayIndex = reader.ReadInt32(); PackedManagedField.Read(reader, out value[n].fields); // Types without namespace have a preceding period, which we remove here // https://issuetracker.unity3d.com/issues/packedmemorysnapshot-leading-period-symbol-in-typename if (value[n].name != null && value[n].name.Length > 0 && value[n].name[0] == '.') { value[n].name = value[n].name.Substring(1); } value[n].nativeTypeArrayIndex = -1; } } }
public int ReadObjectSize(System.UInt64 address, PackedManagedType typeDescription) { // System.Array // Do not display its pointer-size, but the actual size of its content. if (typeDescription.isArray) { if (typeDescription.baseOrElementTypeIndex < 0 || typeDescription.baseOrElementTypeIndex >= m_Snapshot.managedTypes.Length) { var details = ""; details = "arrayRank=" + typeDescription.arrayRank + ", " + "isArray=" + typeDescription.isArray + ", " + "typeInfoAddress=" + typeDescription.typeInfoAddress.ToString("X") + ", " + "address=" + address.ToString("X") + ", " + "memoryreader=" + GetType().Name + ", " + "isValueType=" + typeDescription.isValueType; Debug.LogErrorFormat("ERROR: '{0}.baseOrElementTypeIndex' = {1} is out of range, ignoring. Details in second line\n{2}", typeDescription.name, typeDescription.baseOrElementTypeIndex, details); return(1); } var arrayLength = ReadArrayLength(address, typeDescription); var elementType = m_Snapshot.managedTypes[typeDescription.baseOrElementTypeIndex]; var elementSize = elementType.isValueType ? elementType.size : m_Snapshot.virtualMachineInformation.pointerSize; var size = m_Snapshot.virtualMachineInformation.arrayHeaderSize; size += elementSize * arrayLength; return(size); } // System.String if (typeDescription.managedTypesArrayIndex == m_Snapshot.coreTypes.systemString) { var size = m_Snapshot.virtualMachineInformation.objectHeaderSize; size += sizeof(System.Int32); // string length size += ReadStringLength(address + (uint)m_Snapshot.virtualMachineInformation.objectHeaderSize) * sizeof(char); size += 2; // two null terminators aka \0\0 return(size); } return(typeDescription.size); }
public int ReadArrayLength(System.UInt64 address, PackedManagedType arrayType, int dimension) { if (dimension >= arrayType.arrayRank) { return(0); } var vm = m_Snapshot.virtualMachineInformation; var bounds = ReadPointer(address + (ulong)vm.arrayBoundsOffsetInHeader); if (bounds == 0) { return((int)ReadPointer(address + (ulong)vm.arraySizeOffsetInHeader)); } var pointer = bounds + (ulong)(dimension * vm.pointerSize); var length = (int)ReadPointer(pointer); return(length); }
bool ContainsFieldOfReferenceType(PackedManagedType type) { var managedTypesLength = managedTypes.Length; var instanceFields = type.instanceFields; for (int n = 0, nend = instanceFields.Length; n < nend; ++n) { var fieldTypeIndex = instanceFields[n].managedTypesArrayIndex; if (fieldTypeIndex < 0 || fieldTypeIndex >= managedTypesLength) { Error("'{0}' field '{1}' is out of bounds '{2}', ignoring.", type.name, n, fieldTypeIndex); continue; } var fieldType = managedTypes[instanceFields[n].managedTypesArrayIndex]; if (!fieldType.isValueType) { return(true); } } return(false); }
bool ContainsFieldOfReferenceTypeInInheritenceChain(PackedManagedType type) { var loopGuard = 0; var typeIndex = type.managedTypesArrayIndex; while (typeIndex >= 0 && typeIndex < managedTypes.Length) { if (++loopGuard > 64) { break; } type = managedTypes[typeIndex]; if (ContainsFieldOfReferenceType(type)) { return(true); } typeIndex = type.baseOrElementTypeIndex; } return(false); }
public void InspectStaticType(PackedMemorySnapshot snapshot, PackedManagedType managedType) { m_Snapshot = snapshot; var m_type = managedType; var m_address = 0ul; var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" }; if (m_Snapshot == null) { root.AddChild(new TreeViewItem { id = 1, depth = -1, displayName = "" }); return; } var args = new PropertyGridItem.BuildChildrenArgs(); args.parent = root; args.type = m_type; args.address = m_address; args.memoryReader = new StaticMemoryReader(snapshot, managedType.staticFieldBytes); AddType(args); // add at least one item to the tree, otherwise it outputs an error if (!root.hasChildren) { root.AddChild(new TreeViewItem(1, 0, "")); } SetTree(root); TryCreateDataVisualizer(args.memoryReader, args.type, args.address, false); }
public static Texture2D GetTypeImage(PackedMemorySnapshot snapshot, PackedManagedType type) { if (type.isArray) { return(csReferenceTypeImage); } if (type.isValueType) { if (snapshot.IsSubclassOf(type, snapshot.coreTypes.systemEnum)) { return(csEnumTypeImage); } return(csValueTypeImage); } if (snapshot.IsSubclassOf(type, snapshot.coreTypes.systemDelegate)) { return(csDelegateTypeImage); } return(csReferenceTypeImage); }
public void Initialize(StaticFieldsControl owner, PackedMemorySnapshot snapshot, PackedManagedType typeDescription) { m_Owner = owner; m_TypeDescription = typeDescription; }
public void Initialize(PackedMemorySnapshot snapshot, PackedManagedType type) { m_Type = new RichManagedType(snapshot, type.managedTypesArrayIndex); }
public static EditorWindow CreateWindow(PackedMemorySnapshot snapshot, AbstractMemoryReader memoryReader, System.UInt64 address, PackedManagedType type) { var visualizer = AbstractDataVisualizer.CreateVisualizer(type.name); if (visualizer == null) { Debug.LogWarningFormat("Could not create DataVisualizer for type '{0}'", type.name); return(null); } visualizer.Initialize(snapshot, memoryReader, address, type); var window = DataVisualizerWindow.CreateInstance <DataVisualizerWindow>(); window.SetVisualizer(visualizer); window.ShowUtility(); return(window); }
void AddArrayElement(PackedManagedType elementType, int elementIndex, System.Action <BuildChildrenArgs> add) { if (elementType.isArray) { var pointer = m_MemoryReader.ReadPointer(address + (ulong)(elementIndex * m_Snapshot.virtualMachineInformation.pointerSize) + (ulong)m_Snapshot.virtualMachineInformation.arrayHeaderSize); var item = new ArrayPropertyGridItem(m_Owner, m_Snapshot, pointer, m_MemoryReader) { depth = this.depth + 1, type = elementType }; item.OnInitialize(); this.AddChild(item); } else if (elementType.isValueType) { if (elementType.isPrimitive) { var args = new BuildChildrenArgs(); args.parent = this; args.type = elementType; args.address = address + (ulong)(elementIndex * elementType.size) + (ulong)m_Snapshot.virtualMachineInformation.arrayHeaderSize - (ulong)m_Snapshot.virtualMachineInformation.objectHeaderSize; args.memoryReader = new MemoryReader(m_Snapshot); add(args); } else { // this is the container node for the array elements. // if we don't add the container, all fields are simply added to the array node itself. // however, we want each array element being groupped var pointer = address + (ulong)(elementIndex * elementType.size) + (ulong)m_Snapshot.virtualMachineInformation.arrayHeaderSize; var item = new ArrayElementPropertyGridItem(m_Owner, m_Snapshot, pointer, new MemoryReader(m_Snapshot)) { depth = this.depth + 1, type = elementType }; item.Initialize(); this.AddChild(item); pointer = address + (ulong)(elementIndex * elementType.size) + (ulong)m_Snapshot.virtualMachineInformation.arrayHeaderSize - (ulong)m_Snapshot.virtualMachineInformation.objectHeaderSize; var args = new BuildChildrenArgs(); args.parent = item; args.type = elementType; args.address = pointer; args.memoryReader = new MemoryReader(m_Snapshot); add(args); } } else { // address of element var addressOfElement = address + (ulong)(elementIndex * m_Snapshot.virtualMachineInformation.pointerSize) + (ulong)m_Snapshot.virtualMachineInformation.arrayHeaderSize; var pointer = m_MemoryReader.ReadPointer(addressOfElement); if (pointer != 0) { var i = m_Snapshot.FindManagedObjectTypeOfAddress(pointer); if (i != -1) { elementType = m_Snapshot.managedTypes[i]; } } // this is the container node for the reference type. // if we don't add the container, all fields are simply added to the array node itself. // however, we want each array element being groupped var item = new ArrayElementPropertyGridItem(m_Owner, m_Snapshot, addressOfElement, m_MemoryReader) { depth = this.depth + 1, type = elementType }; item.Initialize(); this.AddChild(item); // Only add the actual element fields if the pointer is valid if (pointer != 0) { var args = new BuildChildrenArgs(); args.parent = item; args.type = elementType; args.address = pointer; args.memoryReader = new MemoryReader(m_Snapshot); add(args); } } }
public void Select(PackedManagedType managedType) { var item = FindItemByType(rootItem, managedType.managedTypesArrayIndex); SelectItem(item); }