コード例 #1
0
        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
                    });
                }
            }
        }
コード例 #2
0
        static void GatherIntermediateCrawlData(CachedSnapshot snapshot, IntermediateCrawlData crawlData)
        {
            unsafe
            {
                var uniqueHandlesPtr = (ulong *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <ulong>() * snapshot.gcHandles.Count, UnsafeUtility.AlignOf <ulong>(), Collections.Allocator.Temp);

                ulong *uniqueHandlesBegin = uniqueHandlesPtr;
                ulong *uniqueHandlesEnd   = uniqueHandlesPtr + snapshot.gcHandles.Count;

                // Parse all handles
                for (int i = 0; i != snapshot.gcHandles.Count; i++)
                {
                    var moi    = new ManagedObjectInfo();
                    var target = snapshot.gcHandles.target[i];
                    if (target == 0)
                    {
#if SNAPSHOT_CRAWLER_DIAG
                        Debuging.DebugUtility.LogWarning("null object in gc handles " + i);
#endif
                        moi.ManagedObjectIndex = i;
                        crawlData.ManagedObjectInfos.Add(moi);
                    }
                    else if (snapshot.CrawledData.ManagedObjectByAddress.ContainsKey(target))
                    {
#if SNAPSHOT_CRAWLER_DIAG
                        Debuging.DebugUtility.LogWarning("Duplicate gc handles " + i + " addr:" + snapshot.gcHandles.target[i]);
#endif
                        moi.ManagedObjectIndex = i;
                        moi.PtrObject          = target;
                        crawlData.ManagedObjectInfos.Add(moi);
                        crawlData.DuplicatedGCHandlesStack.Push(i);
                    }
                    else
                    {
                        moi.ManagedObjectIndex = i;
                        crawlData.ManagedObjectInfos.Add(moi);
                        snapshot.CrawledData.ManagedObjectByAddress.Add(target, moi);
                        UnsafeUtility.CopyStructureToPtr(ref target, uniqueHandlesBegin++);
                    }
                }
                uniqueHandlesBegin = uniqueHandlesPtr; //reset iterator

                //add handles for processing
                while (uniqueHandlesBegin != uniqueHandlesEnd)
                {
                    crawlData.CrawlDataStack.Push(new StackCrawlData {
                        ptr = UnsafeUtility.ReadArrayElement <ulong>(uniqueHandlesBegin++, 0), ptrFrom = 0, typeFrom = -1, indexOfFrom = -1, fieldFrom = -1, fromArrayIndex = -1
                    });
                }
                UnsafeUtility.Free(uniqueHandlesPtr, Collections.Allocator.Temp);
            }
        }
コード例 #3
0
        static void GatherIntermediateCrawlData(CachedSnapshot snapshot, IntermediateCrawlData crawlData)
        {
            unsafe
            {
                var uniqueHandlesPtr = (ulong *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <ulong>() * snapshot.gcHandles.Count, UnsafeUtility.AlignOf <ulong>(), Collections.Allocator.Temp);

                ulong *uniqueHandlesBegin = uniqueHandlesPtr;
                int    writtenRange       = 0;

                // Parse all handles
                for (int i = 0; i != snapshot.gcHandles.Count; i++)
                {
                    var moi    = new ManagedObjectInfo();
                    var target = snapshot.gcHandles.target[i];

                    moi.ManagedObjectIndex = i;

                    //this can only happen pre 19.3 scripting snapshot implementations where we dumped all handle targets but not the handles.
                    //Eg: multiple handles can have the same target. Future facing we need to start adding that as we move forward
                    if (snapshot.CrawledData.MangedObjectIndexByAddress.ContainsKey(target))
                    {
                        moi.PtrObject = target;
                        crawlData.DuplicatedGCHandleTargetsStack.Push(i);
                    }
                    else
                    {
                        snapshot.CrawledData.MangedObjectIndexByAddress.Add(target, moi.ManagedObjectIndex);
                        *(uniqueHandlesBegin++) = target;
                        ++writtenRange;
                    }

                    crawlData.ManagedObjectInfos.Add(moi);
                }
                uniqueHandlesBegin = uniqueHandlesPtr; //reset iterator
                ulong *uniqueHandlesEnd = uniqueHandlesPtr + writtenRange;
                //add handles for processing
                while (uniqueHandlesBegin != uniqueHandlesEnd)
                {
                    crawlData.CrawlDataStack.Push(new StackCrawlData {
                        ptr = UnsafeUtility.ReadArrayElement <ulong>(uniqueHandlesBegin++, 0), ptrFrom = 0, typeFrom = -1, indexOfFrom = -1, fieldFrom = -1, fromArrayIndex = -1
                    });
                }
                UnsafeUtility.Free(uniqueHandlesPtr, Collections.Allocator.Temp);
            }
        }
コード例 #4
0
        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
                    });
                }
            }
        }
コード例 #5
0
        static bool CrawlPointer(IntermediateCrawlData dataStack)
        {
            UnityEngine.Debug.Assert(dataStack.CrawlDataStack.Count > 0);

            var snapshot                  = dataStack.CachedMemorySnapshot;
            var typeDescriptions          = snapshot.typeDescriptions;
            var data                      = dataStack.CrawlDataStack.Pop();
            var virtualMachineInformation = snapshot.virtualMachineInformation;
            var managedHeapSections       = snapshot.managedHeapSections;
            var byteOffset                = managedHeapSections.Find(data.ptr, virtualMachineInformation);

            if (!byteOffset.IsValid)
            {
                return(false);
            }

            ManagedObjectInfo obj;
            bool wasAlreadyCrawled;

            obj = ParseObjectHeader(snapshot, data.ptr, out wasAlreadyCrawled, false);
            ++obj.RefCount;

            snapshot.CrawledData.ManagedObjects[obj.ManagedObjectIndex] = obj;
            snapshot.CrawledData.ManagedObjectByAddress[obj.PtrObject]  = obj;

            dataStack.ManagedConnections.Add(ManagedConnection.MakeConnection(snapshot, data.indexOfFrom, data.ptrFrom, obj.ManagedObjectIndex, data.ptr, data.typeFrom, data.fieldFrom, data.fromArrayIndex));

            if (!obj.IsKnownType())
            {
                return(false);
            }
            if (wasAlreadyCrawled)
            {
                return(true);
            }

            if (!typeDescriptions.HasFlag(obj.ITypeDescription, TypeFlags.kArray))
            {
                CrawlRawObjectData(dataStack, byteOffset.Add(snapshot.virtualMachineInformation.objectHeaderSize), obj.ITypeDescription, false, data.ptr, obj.ManagedObjectIndex);
                return(true);
            }

            var arrayLength             = ArrayTools.ReadArrayLength(snapshot, data.ptr, obj.ITypeDescription);
            int iElementTypeDescription = typeDescriptions.baseOrElementTypeIndex[obj.ITypeDescription];

            if (iElementTypeDescription == -1)
            {
                return(false); //do not crawl uninitialized object types, as we currently don't have proper handling for these
            }
            var arrayData = byteOffset.Add(virtualMachineInformation.arrayHeaderSize);

            for (int i = 0; i != arrayLength; i++)
            {
                if (typeDescriptions.HasFlag(iElementTypeDescription, TypeFlags.kValueType))
                {
                    CrawlRawObjectData(dataStack, arrayData, iElementTypeDescription, false, data.ptr, obj.ManagedObjectIndex);
                    arrayData = arrayData.Add(typeDescriptions.size[iElementTypeDescription]);
                }
                else
                {
                    dataStack.CrawlDataStack.Push(new StackCrawlData()
                    {
                        ptr = arrayData.ReadPointer(), ptrFrom = data.ptr, typeFrom = obj.ITypeDescription, indexOfFrom = obj.ManagedObjectIndex, fieldFrom = -1, fromArrayIndex = i
                    });
                    arrayData = arrayData.NextPointer();
                }
            }
            return(true);
        }
コード例 #6
0
        static void ConnectNativeToManageObject(IntermediateCrawlData crawlData)
        {
            var snapshot    = crawlData.CachedMemorySnapshot;
            var objectInfos = crawlData.ManagedObjectInfos;

            if (snapshot.typeDescriptions.Count == 0)
            {
                return;
            }

            // Get UnityEngine.Object
            int iTypeDescription_UnityEngineObject = snapshot.typeDescriptions.typeDescriptionName.FindIndex(x => x == "UnityEngine.Object");

            if (iTypeDescription_UnityEngineObject < 0)
            {
                //No Unity Object ?
                return;
            }

            //Get UnityEngine.Object.m_InstanceID field
            int iField_UnityEngineObject_m_InstanceID = Array.FindIndex(
                snapshot.typeDescriptions.fieldIndices[iTypeDescription_UnityEngineObject]
                , iField => snapshot.fieldDescriptions.fieldDescriptionName[iField] == "m_InstanceID");

            int instanceIDOffset = -1;
            int cachedPtrOffset  = -1;

            if (iField_UnityEngineObject_m_InstanceID >= 0)
            {
                var fieldIndex = snapshot.typeDescriptions.fieldIndices[iTypeDescription_UnityEngineObject][iField_UnityEngineObject_m_InstanceID];
                instanceIDOffset = snapshot.fieldDescriptions.offset[fieldIndex];
            }
            if (instanceIDOffset < 0)
            {
                // on UNITY_5_4_OR_NEWER, there is the member m_CachedPtr we can use to identify the connection
                //Since Unity 5.4, UnityEngine.Object no longer stores instance id inside when running in the player. Use cached ptr instead to find the instanceID of native object
                int iField_UnityEngineObject_m_CachedPtr = Array.FindIndex(
                    snapshot.typeDescriptions.fieldIndices[iTypeDescription_UnityEngineObject]
                    , iField => snapshot.fieldDescriptions.fieldDescriptionName[iField] == "m_CachedPtr");

                if (iField_UnityEngineObject_m_CachedPtr >= 0)
                {
                    cachedPtrOffset = snapshot.fieldDescriptions.offset[iField_UnityEngineObject_m_CachedPtr];
                }
            }
            if (instanceIDOffset < 0 && cachedPtrOffset < 0)
            {
                Debug.LogWarning("Could not find unity object instance id field or m_CachedPtr");
                return;
            }


            for (int i = 0; i != objectInfos.Count; i++)
            {
                //Must derive of unity Object
                var objectInfo = objectInfos[i];
                objectInfo.NativeObjectIndex = -1;
                int instanceID = CachedSnapshot.NativeObjectEntriesCache.InstanceID_None;

                if (DerivesFrom(snapshot.typeDescriptions, objectInfo.ITypeDescription, iTypeDescription_UnityEngineObject))
                {
                    //Find object instance id
                    if (iField_UnityEngineObject_m_InstanceID >= 0)
                    {
                        var h = snapshot.managedHeapSections.Find(objectInfo.PtrObject + (UInt64)instanceIDOffset, snapshot.virtualMachineInformation);
                        if (h.IsValid)
                        {
                            instanceID = h.ReadInt32();
                        }
                        else
                        {
                            Debug.LogWarning("Managed object missing head (addr:" + objectInfo.PtrObject + ", index:" + objectInfo.ManagedObjectIndex + ")");
                        }
                    }
                    else if (cachedPtrOffset >= 0)
                    {
                        // If you get a compilation error on the following 2 lines, update to Unity 5.4b14.
                        var heapSection = snapshot.managedHeapSections.Find(objectInfo.PtrObject + (UInt64)cachedPtrOffset, snapshot.virtualMachineInformation);
                        if (!heapSection.IsValid)
                        {
                            Debug.LogWarning("Managed object (addr:" + objectInfo.PtrObject + ", index:" + objectInfo.ManagedObjectIndex + ") does not have data at cachedPtr offset(" + cachedPtrOffset + ")");
                        }
                        else
                        {
                            var cachedPtr           = heapSection.ReadPointer();
                            var indexOfNativeObject = snapshot.nativeObjects.nativeObjectAddress.FindIndex(no => no == cachedPtr);
                            if (indexOfNativeObject >= 0)
                            {
                                instanceID = snapshot.nativeObjects.instanceId[indexOfNativeObject];
                            }
                        }
                    }

                    if (instanceID != CachedSnapshot.NativeObjectEntriesCache.InstanceID_None && snapshot.nativeObjects.instanceId2Index.TryGetValue(instanceID, out objectInfo.NativeObjectIndex))
                    {
                        snapshot.nativeObjects.managedObjectIndex[objectInfo.NativeObjectIndex] = i;
                    }
                }

                objectInfos[i] = objectInfo;

                if (snapshot.HasConnectionOverhaul && instanceID != CachedSnapshot.NativeObjectEntriesCache.InstanceID_None)
                {
                    snapshot.CrawledData.Connections.Add(ManagedConnection.MakeUnityEngineObjectConnection(objectInfo.NativeObjectIndex, objectInfo.ManagedObjectIndex));
                    ++snapshot.nativeObjects.refcount[objectInfo.NativeObjectIndex];
                }
                snapshot.CrawledData.ManagedObjectByAddress[objectInfo.PtrObject] = objectInfo;
            }
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        static void ConnectNativeToManageObject(IntermediateCrawlData crawlData)
        {
            var snapshot    = crawlData.CachedMemorySnapshot;
            var objectInfos = crawlData.ManagedObjectInfos;

            if (snapshot.typeDescriptions.Count == 0)
            {
                return;
            }

            // Get UnityEngine.Object
            int iTypeDescription_UnityEngineObject = snapshot.typeDescriptions.typeDescriptionName.FindIndex(x => x == "UnityEngine.Object");

#if DEBUG_VALIDATION //This shouldn't really happen
            if (iTypeDescription_UnityEngineObject < 0)
            {
                throw new Exception("Unable to find UnityEngine.Object");
            }
#endif
            int cachedPtrOffset = -1;
            int iField_UnityEngineObject_m_CachedPtr = Array.FindIndex(
                snapshot.typeDescriptions.fieldIndices[iTypeDescription_UnityEngineObject]
                , iField => snapshot.fieldDescriptions.fieldDescriptionName[iField] == "m_CachedPtr");

            if (iField_UnityEngineObject_m_CachedPtr >= 0)
            {
                cachedPtrOffset = snapshot.fieldDescriptions.offset[iField_UnityEngineObject_m_CachedPtr];
            }

#if DEBUG_VALIDATION
            if (cachedPtrOffset < 0)
            {
                Debug.LogWarning("Could not find unity object instance id field or m_CachedPtr");
                return;
            }
#endif

            for (int i = 0; i != objectInfos.Count; i++)
            {
                //Must derive of unity Object
                var objectInfo = objectInfos[i];
                objectInfo.NativeObjectIndex = -1;
                int instanceID = CachedSnapshot.NativeObjectEntriesCache.k_InstanceIDNone;

                if (DerivesFrom(snapshot.typeDescriptions, objectInfo.ITypeDescription, iTypeDescription_UnityEngineObject))
                {
                    var heapSection = snapshot.managedHeapSections.Find(objectInfo.PtrObject + (ulong)cachedPtrOffset, snapshot.virtualMachineInformation);
                    if (!heapSection.IsValid)
                    {
                        Debug.LogWarning("Managed object (addr:" + objectInfo.PtrObject + ", index:" + objectInfo.ManagedObjectIndex + ") does not have data at cachedPtr offset(" + cachedPtrOffset + ")");
                    }
                    else
                    {
                        ulong cachedPtr;
                        heapSection.TryReadPointer(out cachedPtr);

                        if (!snapshot.nativeObjects.nativeObjectAddressToInstanceId.TryGetValue(cachedPtr, out instanceID))
                        {
                            instanceID = CachedSnapshot.NativeObjectEntriesCache.k_InstanceIDNone;
                        }
                    }

                    if (instanceID != CachedSnapshot.NativeObjectEntriesCache.k_InstanceIDNone && snapshot.nativeObjects.instanceId2Index.TryGetValue(instanceID, out objectInfo.NativeObjectIndex))
                    {
                        snapshot.nativeObjects.managedObjectIndex[objectInfo.NativeObjectIndex] = i;
                    }
                }

                objectInfos[i] = objectInfo;

                if (snapshot.HasConnectionOverhaul && instanceID != CachedSnapshot.NativeObjectEntriesCache.k_InstanceIDNone)
                {
                    snapshot.CrawledData.Connections.Add(ManagedConnection.MakeUnityEngineObjectConnection(objectInfo.NativeObjectIndex, objectInfo.ManagedObjectIndex));
                    ++snapshot.nativeObjects.refcount[objectInfo.NativeObjectIndex];
                }
            }
        }