private DesktopBlockingObject CreateRWSObject(ulong obj, ClrType type) { if (type == null) { return(new DesktopBlockingObject(obj, false, 0, null, BlockingReason.None)); } ClrInstanceField field = type.GetFieldByName("writeLockOwnerId"); if (field != null && field.ElementType == ClrElementType.Int32) { int id = (int)field.GetValue(obj); ClrThread thread = GetThreadById(id); if (thread != null) { return(new DesktopBlockingObject(obj, true, 0, thread, BlockingReason.WriterAcquired)); } } field = type.GetFieldByName("upgradeLockOwnerId"); if (field != null && field.ElementType == ClrElementType.Int32) { int id = (int)field.GetValue(obj); ClrThread thread = GetThreadById(id); if (thread != null) { return(new DesktopBlockingObject(obj, true, 0, thread, BlockingReason.WriterAcquired)); } } field = type.GetFieldByName("rwc"); if (field != null) { List <ClrThread> threads = null; ulong rwc = (ulong)field.GetValue(obj); ClrType rwcArrayType = _heap.GetObjectType(rwc); if (rwcArrayType != null && rwcArrayType.IsArray && rwcArrayType.ComponentType != null) { ClrType rwcType = rwcArrayType.ComponentType; ClrInstanceField threadId = rwcType.GetFieldByName("threadid"); ClrInstanceField next = rwcType.GetFieldByName("next"); if (threadId != null && next != null) { int count = rwcArrayType.GetArrayLength(rwc); for (int i = 0; i < count; ++i) { ulong entry = (ulong)rwcArrayType.GetArrayElementValue(rwc, i); GetThreadEntry(ref threads, threadId, next, entry, false); } } } if (threads != null) { return(new DesktopBlockingObject(obj, true, 0, BlockingReason.ReaderAcquired, threads.ToArray())); } } return(new DesktopBlockingObject(obj, false, 0, null, BlockingReason.None)); }
private static void PrintArray(ClrRuntime runtime) { var heap = runtime.Heap; var intArrays = from o in heap.EnumerateObjects() let t = heap.GetObjectType(o) where t.IsArray && t.Name == "System.Int32[]" select new { Address = o, Type = t }; foreach (var item in intArrays) { ClrType type = item.Type; ulong obj = item.Address; int len = type.GetArrayLength(obj); Console.WriteLine("Object: {0:X}", obj); Console.WriteLine("Length: {0}", len); Console.WriteLine("Elements:"); for (int i = 0; i < len; i++) { Console.WriteLine("{0,3} - {1}", i, type.GetArrayElementValue(obj, i)); } } }
static void ReadComplexArray(ClrType type, ulong obj) { int len = type.GetArrayLength(obj); Console.WriteLine("Object: {0:X}", obj); Console.WriteLine("Type: {0}", type.Name); Console.WriteLine("Length: {0}", len); for (int i = 0; i < len; i++) { ulong addr = type.GetArrayElementAddress(obj, i); foreach (var field in type.ComponentType.Fields) { string output; if (field.HasSimpleValue) { var tmpOutput = field.GetValue(addr, true); if (tmpOutput == null) { continue; } output = tmpOutput.ToString(); // <- true here, as this is an embedded struct } else { output = field.GetAddress(addr, true).ToString("X"); // <- true here as well } Console.WriteLine("{0} +{1,2:X2} {2} {3} = {4}", i, field.Offset, field.Type.Name, field.Name, output); } } }
public static List <KVP> GetKVPs(ClrType type, ulong items) { int length = type.GetArrayLength(items); var ret = new List <KVP>(); for (int i = 0; i < length; i++) { ulong addr = type.GetArrayElementAddress(items, i); var keyField = type.ComponentType.GetFieldByName("key"); var key = (ulong)keyField.GetValue(addr - (ulong)IntPtr.Size); // no need to add these pre-allocated entries if (key == 0) { continue; } var valueField = type.ComponentType.GetFieldByName("value"); var value = (ulong)valueField.GetValue(addr - (ulong)IntPtr.Size); ret.Add(new KVP(key, value)); } return(ret); }
private int GetClrTypeArrayLength(Tuple <int, ulong> input) { int clrTypeId = input.Item1; ulong address = input.Item2; ClrType clrType = clrTypesCache[clrTypeId]; return(clrType.GetArrayLength(address)); }
static void ReadSimpleArray(ClrType type, ulong obj) { int len = type.GetArrayLength(obj); Console.WriteLine("Object: {0:X}", obj); Console.WriteLine("Length: {0}", len); Console.WriteLine("Elements:"); for (int i = 0; i < len; i++) { Console.WriteLine("{0,3} - {1}", i, type.GetArrayElementValue(obj, i)); } }
public string GetFieldNameReferenceImpl(ulong refAddress, ulong address, bool prefixWithType) { ClrType type = GetObjectTypeImpl(address); if (type == null) { return("Unknown"); } string fieldName = "???"; ClrObject obj = new ClrObject(address, type); if (type.IsArray) { fieldName = "[ ? ]"; var length = type.GetArrayLength(address); for (int i = 0; i < length; i++) { if (obj[i].Address == refAddress) { fieldName = $"[ {i} ]"; } } } else { foreach (var field in type.Fields) { switch (field.ElementType) { case ClrElementType.Struct: case ClrElementType.String: case ClrElementType.Array: case ClrElementType.SZArray: case ClrElementType.Object: var fieldValue = obj[field]; if (fieldValue.Address == refAddress) { fieldName = field.Name; } break; } } } if (prefixWithType) { fieldName = $"{fieldName}@{type.Name}"; } return(fieldName); }
public static List <ulong> GetArrayItems(ClrType type, ulong items) { int length = type.GetArrayLength(items); var ret = new List <ulong>(); for (int i = 0; i < length; i++) { var val = (ulong)type.GetArrayElementValue(items, i); if (val != 0) { ret.Add(val); } } return(ret); }
public void ForEach(ulong arrayAddress, Action <ulong> action) { ClrType type = ManagedHeap.GetObjectType(arrayAddress); int length = type.GetArrayLength(arrayAddress); for (int element = 0; element < length; element++) { var val = type.GetArrayElementValue(arrayAddress, element); ulong elementAddress = (ulong)val; if (elementAddress == 0) { continue; } action(elementAddress); } }
public void ArrayLengthTest() { using (DataTarget dt = TestTargets.Types.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ClrAppDomain domain = runtime.AppDomains.Single(); ClrModule typesModule = runtime.GetModule("types.exe"); ClrType type = heap.GetTypeByName("Types"); ulong s_array = (ulong)type.GetStaticFieldByName("s_array").GetValue(domain); ClrType arrayType = heap.GetObjectType(s_array); Assert.Equal(3, arrayType.GetArrayLength(s_array)); } }
public List <T> Read <T>() where T : new() { ClrType type = Heap.GetObjectType(Value.Address); // Only consider types which are arrays that do not have simple values (I.E., are structs). if (!type.IsArray || type.ComponentType.HasSimpleValue) { return(null); } int len = type.GetArrayLength(Value.Address); List <T> list = new List <T>(); FieldInfo[] fields = typeof(T).GetFields(); for (int i = 0; i < len; i++) { ulong addr = type.GetArrayElementAddress(Value.Address, i); T item = new T(); foreach (var field in type.ComponentType.Fields) { if (!field.HasSimpleValue) { continue; } for (int j = 0; j < fields.Length; j++) { if (fields[j].Name == field.Name) { var val = field.GetValue(addr, true); typeof(T).GetField(field.Name).SetValueDirect(__makeref(item), val); } } } list.Add(item); } return(list); }
internal override IList <ClrStackFrame> GetExceptionStackTrace(ulong obj, ClrType type) { // TODO: Review this and if it works on v4.5, merge the two implementations back into RuntimeBase. List <ClrStackFrame> result = new List <ClrStackFrame>(); if (type == null) { return(result); } if (!GetStackTraceFromField(type, obj, out ulong _stackTrace)) { if (!ReadPointer(obj + GetStackTraceOffset(), out _stackTrace)) { return(result); } } if (_stackTrace == 0) { return(result); } ClrHeap heap = Heap; ClrType stackTraceType = heap.GetObjectType(_stackTrace); if (stackTraceType == null || !stackTraceType.IsArray) { return(result); } int len = stackTraceType.GetArrayLength(_stackTrace); if (len == 0) { return(result); } int elementSize = IntPtr.Size * 4; ulong dataPtr = _stackTrace + (ulong)(IntPtr.Size * 2); if (!ReadPointer(dataPtr, out ulong count)) { return(result); } // Skip size and header dataPtr += (ulong)(IntPtr.Size * 2); DesktopThread thread = null; for (int i = 0; i < (int)count; ++i) { if (!ReadPointer(dataPtr, out ulong ip)) { break; } if (!ReadPointer(dataPtr + (ulong)IntPtr.Size, out ulong sp)) { break; } if (!ReadPointer(dataPtr + (ulong)(2 * IntPtr.Size), out ulong md)) { break; } if (i == 0 && sp != 0) { thread = (DesktopThread)GetThreadByStackAddress(sp); } // it seems that the first frame often has 0 for IP and SP. Try the 2nd frame as well if (i == 1 && thread == null && sp != 0) { thread = (DesktopThread)GetThreadByStackAddress(sp); } result.Add(new DesktopStackFrame(this, thread, null, ip, sp, md)); dataPtr += (ulong)elementSize; } return(result); }
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (IsNull()) { result = new ClrNullValue(m_heap); return(true); } if (m_type.IsArray) { // Populate length for bounds check. if (m_len == -1) { m_len = m_type.GetArrayLength(m_addr); } int index = GetIndexFromObjects(indexes); return(GetArrayValue(m_type, m_addr, index, out result)); } // Dictionary if (IsDictionary()) { if (indexes.Length != 1) { throw new ArgumentException("Only one index is allowed for Dictionary indexing."); } dynamic dict = ((dynamic)this); dynamic entries = dict.entries; ClrInstanceField key = ((ClrType)entries).ArrayComponentType.GetFieldByName("key"); // Two cases: The key is an object or string, denoted by "System.__Canon", or it's a primitive. // otherwise we don't support it. var keyType = key.Type; if (keyType.IsObjectReference) { Debug.Assert(keyType.Name == "System.__Canon"); if (indexes[0].GetType() == typeof(string)) { string index = (string)indexes[0]; int len = dict.count; for (int i = 0; i < len; ++i) { if ((string)entries[i].key == index) { result = entries[i].value; return(true); } } throw new KeyNotFoundException(); } else { ulong addr; if (indexes[0].GetType() == typeof(long)) { addr = (ulong)(long)indexes[0]; } else if (indexes[0].GetType() == typeof(ulong)) { addr = (ulong)indexes[0]; } else { addr = (ulong)(dynamic)indexes[0]; } int len = dict.count; for (int i = 0; i < len; ++i) { if ((ulong)entries[i].key == addr) { result = entries[i].value; return(true); } } } } else if (keyType.IsPrimitive) { object index = indexes[0]; if (index is ClrPrimitiveValue) { index = ((ClrPrimitiveValue)index).GetValue(); } Type type = index.GetType(); int len = dict.count; for (int i = 0; i < len; ++i) { ClrPrimitiveValue value = entries[i].key; if (value.GetValue().Equals(index)) { result = entries[i].value; return(true); } } throw new KeyNotFoundException(); } } if (IsList()) { int index = GetIndexFromObjects(indexes); var itemsField = m_type.GetFieldByName("_items"); ulong addr = (ulong)itemsField.GetFieldValue(m_addr); // Populate length for bounds check. if (m_len == -1) { var sizeField = m_type.GetFieldByName("_size"); m_len = (int)sizeField.GetFieldValue(m_addr); } // If type is null, then we've hit a dac bug. Attempt to work around it, // but we'll have to give up if getting the object type directly doesn't work. ClrType type = itemsField.Type; if (type == null || type.ArrayComponentType == null) { type = m_heap.GetObjectType(addr); if (type == null || type.ArrayComponentType == null) { result = new ClrNullValue(m_heap); return(true); } } return(GetArrayValue(type, addr, index, out result)); } throw new InvalidOperationException(string.Format("Object of type '{0}' is not indexable.", m_type.Name)); }
private static Dictionary <string, HeapObjectCounter> GetObjectOwners(ClrRuntime runtime, HashSet <ulong> instances) { Dictionary <string, HeapObjectCounter> dict = new Dictionary <string, HeapObjectCounter>(); if (!runtime.Heap.CanWalkHeap) { Console.WriteLine("Cannot walk the heap!"); } else { foreach (ClrSegment seg in runtime.Heap.Segments) { for (ulong obj = seg.FirstObject; obj != 0; obj = seg.NextObject(obj)) { ClrType type = runtime.Heap.GetObjectType(obj); if (type == null || type.IsFree == true) { continue; } string typeName = type.ToString(); int gen = runtime.Heap.GetGeneration(obj); if (gen != 2) { continue; } if (type.IsArray == true) { int arrayLength = type.GetArrayLength(obj); for (int i = 0; i < arrayLength; i++) { ulong elemAddress = type.GetArrayElementAddress(obj, i); ClrType elemType = type.ComponentType; if (elemType.IsValueClass == false) { ulong elemRef = ReadMemory(runtime, elemAddress); if (instances.Contains(elemRef) == true) { if (dict.ContainsKey(typeName) == true) { dict[typeName].AddCount(obj); } else { dict.Add(typeName, new HeapObjectCounter(obj)); } } } else { AddItem(type, typeName, obj); } } } else { AddItem(type, typeName, obj); } } } } return(dict); void AddItem(ClrType type, string typeName, ulong objAddress) { foreach (ClrInstanceField field in type.Fields) { ulong fieldAddress = GetFieldAddressValue(runtime, field, objAddress); if (instances.Contains(fieldAddress) == true) { if (dict.ContainsKey(typeName) == true) { dict[typeName].AddCount(objAddress); } else { dict.Add(typeName, new HeapObjectCounter(objAddress)); } } } } }
internal override IList <ClrStackFrame> GetExceptionStackTrace(ulong obj, ClrType type) { List <ClrStackFrame> result = new List <ClrStackFrame>(); if (!GetStackTraceFromField(type, obj, out ulong _stackTrace)) { if (!ReadPointer(obj + GetStackTraceOffset(), out _stackTrace)) { return(result); } } if (_stackTrace == 0) { return(result); } DesktopGCHeap heap = (DesktopGCHeap)Heap; ClrType stackTraceType = heap.GetObjectType(_stackTrace); if (stackTraceType == null) { stackTraceType = heap.ArrayType; } if (!stackTraceType.IsArray) { return(result); } int len = stackTraceType.GetArrayLength(_stackTrace); if (len == 0) { return(result); } int elementSize = CLRVersion == DesktopVersion.v2 ? IntPtr.Size * 4 : IntPtr.Size * 3; ulong dataPtr = _stackTrace + (ulong)(IntPtr.Size * 2); if (!ReadPointer(dataPtr, out ulong count)) { return(result); } // Skip size and header dataPtr += (ulong)(IntPtr.Size * 2); DesktopThread thread = null; for (int i = 0; i < (int)count; ++i) { if (!ReadPointer(dataPtr, out ulong ip)) { break; } if (!ReadPointer(dataPtr + (ulong)IntPtr.Size, out ulong sp)) { break; } if (!ReadPointer(dataPtr + (ulong)(2 * IntPtr.Size), out ulong md)) { break; } if (i == 0) { thread = (DesktopThread)GetThreadByStackAddress(sp); } result.Add(new DesktopStackFrame(this, thread, null, ip, sp, md)); dataPtr += (ulong)elementSize; } return(result); }
/// <summary> /// If the type is an array, then GetArrayLength returns the number of elements in the array. Undefined /// behavior if this type is not an array. /// </summary> /// <param name="objRef">The object reference.</param> /// <returns>System.Int32.</returns> public int GetArrayLength(ulong objRef) => ClrType.GetArrayLength(objRef);
public override IClrObjMappingModel ReadEntity(ClrObject obj, ModelMapperFactory factory) { var hashtableModel = new HashtableMappingModel { Obj = obj }; ClrObject entriesField = obj.GetRefFld(entriesFldName); if (entriesField == null || entriesField.Type == null) { // Object contains this field, but value is null. // Most likely dictionary is either in the middle of construction, or destruction. // Anyway we can assume it is empty. return(hashtableModel); } ClrType type = entriesField.Type; ClrHeap heap = type.Heap; var componentType = type.ComponentType; if (componentType == null) { // TODO :Try reload type. return(null); } ClrInstanceField valueField = componentType.GetFieldByName("value"); ClrInstanceField keyField = componentType.GetFieldByName("key"); int len = type.GetArrayLength(entriesField.Address); ulong entriesFieldAddress = entriesField.Address; for (int i = 0; i < len; i++) { ulong addr = type.GetArrayElementAddress(entriesFieldAddress, i); if (addr == 0) { continue; } try { var key = keyField.GetValue(addr, true); if (!(key is ulong)) { continue; } var keyPointer = (ulong)key; if (keyPointer == 0) { continue; } var val = valueField.GetValue(addr, true); ulong valuePointer; if (val is ulong) { valuePointer = (ulong)val; } else { valuePointer = 0; } var keyObj = new ClrObject(keyPointer, heap); var valObj = new ClrObject(valuePointer, heap); hashtableModel.Elements.Add(factory.BuildModel(keyObj), factory.BuildModel(valObj)); } catch (Exception) { Trace.TraceError("Count not read {0} object", obj.HexAddress); // Do nothing for now } } return(hashtableModel); }
private IEnumerable <ulong> EnumerateManagedThreadpoolObjects() { _heap = _runtime.GetHeap(); ClrModule mscorlib = GetMscorlib(); if (mscorlib != null) { ClrType queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolGlobals"); if (queueType != null) { ClrStaticField workQueueField = queueType.GetStaticFieldByName("workQueue"); if (workQueueField != null) { foreach (var appDomain in _runtime.AppDomains) { object workQueueValue = workQueueField.GetValue(appDomain); ulong workQueue = workQueueValue == null ? 0L : (ulong)workQueueValue; ClrType workQueueType = _heap.GetObjectType(workQueue); if (workQueue == 0 || workQueueType == null) { continue; } ulong queueHead; ClrType queueHeadType; do { if (!GetFieldObject(workQueueType, workQueue, "queueHead", out queueHeadType, out queueHead)) { break; } ulong nodes; ClrType nodesType; if (GetFieldObject(queueHeadType, queueHead, "nodes", out nodesType, out nodes) && nodesType.IsArray) { int len = nodesType.GetArrayLength(nodes); for (int i = 0; i < len; ++i) { ulong addr = (ulong)nodesType.GetArrayElementValue(nodes, i); if (addr != 0) { yield return(addr); } } } if (!GetFieldObject(queueHeadType, queueHead, "Next", out queueHeadType, out queueHead)) { break; } } while (queueHead != 0); } } } queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); if (queueType != null) { ClrStaticField threadQueuesField = queueType.GetStaticFieldByName("allThreadQueues"); if (threadQueuesField != null) { foreach (ClrAppDomain domain in _runtime.AppDomains) { ulong?threadQueue = (ulong?)threadQueuesField.GetValue(domain); if (!threadQueue.HasValue || threadQueue.Value == 0) { continue; } ClrType threadQueueType = _heap.GetObjectType(threadQueue.Value); if (threadQueueType == null) { continue; } ulong outerArray = 0; ClrType outerArrayType = null; if (!GetFieldObject(threadQueueType, threadQueue.Value, "m_array", out outerArrayType, out outerArray) || !outerArrayType.IsArray) { continue; } int outerLen = outerArrayType.GetArrayLength(outerArray); for (int i = 0; i < outerLen; ++i) { ulong entry = (ulong)outerArrayType.GetArrayElementValue(outerArray, i); if (entry == 0) { continue; } ClrType entryType = _heap.GetObjectType(entry); if (entryType == null) { continue; } ulong array; ClrType arrayType; if (!GetFieldObject(entryType, entry, "m_array", out arrayType, out array) || !arrayType.IsArray) { continue; } int len = arrayType.GetArrayLength(array); for (int j = 0; j < len; ++j) { ulong addr = (ulong)arrayType.GetArrayElementValue(array, i); if (addr != 0) { yield return(addr); } } } } } } } }
public static void PrintDict(ClrRuntime runtime, string args) { bool failed = false; ulong obj = 0; try { obj = Convert.ToUInt64(args, 16); failed = obj == 0; } catch (ArgumentException) { failed = true; } if (failed) { Console.WriteLine("Usage: !PrintDict <dictionary>"); return; } ClrHeap heap = runtime.GetHeap(); ClrType type = heap.GetObjectType(obj); if (type == null) { Console.WriteLine("Invalid object {0:X}", obj); return; } if (!type.Name.StartsWith("System.Collections.Generic.Dictionary")) { Console.WriteLine("Error: Expected object {0:X} to be a dictionary, instead it's of type '{1}'."); return; } // Get the entries field. ulong entries = type.GetFieldValue(obj, "entries"); if (entries == 0) { return; } ClrType entryArray = heap.GetObjectType(entries); ClrType arrayComponent = entryArray.ComponentType; ClrInstanceField hashCodeField = arrayComponent.GetFieldByName("hashCode"); ClrInstanceField keyField = arrayComponent.GetFieldByName("key"); ClrInstanceField valueField = arrayComponent.GetFieldByName("value"); Console.WriteLine("{0,8} {1,16} : {2}", "hash", "key", "value"); int len = entryArray.GetArrayLength(entries); for (int i = 0; i < len; ++i) { ulong arrayElementAddr = entryArray.GetArrayElementAddress(entries, i); int hashCode = (int)hashCodeField.GetValue(arrayElementAddr, true); object key = keyField.GetValue(arrayElementAddr, true); object value = valueField.GetValue(arrayElementAddr, true); key = Format(heap, key); value = Format(heap, value); bool skip = key is ulong && (ulong)key == 0 && value is ulong && (ulong)value == 0; if (!skip) { Console.WriteLine("{0,8:X} {1,16} : {2}", hashCode, key, value); } } }
private List <ClrObjectModel> GetValues(ulong obj, ClrType type, string baseName, int offset, bool inner, List <ClrObjectModel> values) { if (type.Name == "System.String") { object value; try { value = type.GetValue(obj); } catch (Exception ex) { value = ex.Message; } values.Add(new ClrObjectModel { Address = obj, BaseName = baseName, TypeName = type.Name, Value = value }); values.AddRange(type.Fields.Select(field => new ClrObjectModel { Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = field.GetValue(obj, inner).ToString() })); } else if (type.IsArray) { int len = type.GetArrayLength(obj); if (type.ComponentType == null) { try { for (int i = 0; i < len; i++) { values.Add(new ClrObjectModel { Address = obj, BaseName = baseName, TypeName = type.Name, Value = type.GetArrayElementValue(obj, i) }); } } catch { } } else if (type.ComponentType.HasSimpleValue) { for (int i = 0; i < len; i++) { values.Add(new ClrObjectModel { Address = obj, BaseName = baseName, TypeName = type.Name, Value = type.GetArrayElementValue(obj, i) }); } } else { for (int i = 0; i < len; i++) { ulong arrAddress = type.GetArrayElementAddress(obj, i); foreach (var field in type.ComponentType.Fields) { string value; if (field.HasSimpleValue) { value = field.GetValue(arrAddress, inner).ToString(); // an embedded struct } else { value = field.GetAddress(arrAddress, inner).ToString(); } values.Add(new ClrObjectModel { Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = value }); if (field.ElementType == ClrElementType.Struct) { values.AddRange(GetValues(arrAddress, field.Type, baseName + field.Name, offset + field.Offset, true, new List <ClrObjectModel>())); } } } } } else { foreach (var field in type.Fields) { ulong addr = field.GetAddress(obj, inner); object value; if (field.HasSimpleValue) { try { value = field.GetValue(obj, inner); } catch (Exception) { value = "{Unknown}"; } } else { value = addr; } string sValue = value?.ToString() ?? "{Null}"; values.Add(new ClrObjectModel { Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = sValue }); if (field.ElementType == ClrElementType.Struct) { values.AddRange(GetValues(addr, field.Type, baseName + field.Name, offset + field.Offset, true, new List <ClrObjectModel>())); } } } return(values); }
public void GetArrayLength(ulong objRef, out int pLength) { pLength = m_type.GetArrayLength(objRef); }