/// <summary> /// Can only be used when we have a live heap. returns the type type given a ICorDebug COR_TYPEID token /// </summary> internal ICorDebugGCHeapType GetObjectTypeFromID(COR_TYPEID typeID) { Debug.Assert(m_process5 != null); // only used when we have a live heap ICorDebugGCHeapType ret; if (m_typeTable.TryGetValue(typeID, out ret)) { return(ret); } ret = new ICorDebugGCHeapType(this, typeID); return(ret); }
private void SetNameModuleAndFields(CorElementType typeKind, COR_TYPEID typeID, int numFields) { // THere is recursion in the definition of primitive types (they have a value field of the primtitive type. // Cut this off here. if (GCRootNames.IsPrimitiveType(typeKind)) { numFields = 0; } var buffer = new StringBuilder(1024); IMetadataImport metaData = null; int bufferSizeRet; // This is getting names. If we fail, we can still plow on .... try { ICorDebugType corType = null; // Console.WriteLine("Calling GetTypeForTypeID {0:x} {1:x}", typeID.token1, typeID.token2); m_heap.m_process5.GetTypeForTypeID(typeID, out corType); string moduleFilePath; m_name = GCRootNames.GetTypeName(corType, out moduleFilePath, out metaData, buffer); m_moduleFilePath = moduleFilePath; } catch (Exception e) { Console.WriteLine("Error: Caught exception for type ID {0:x} {1:x}: {2}", typeID.token1, typeID.token2, e.Message); m_name = string.Format("!ERROR TYPE ID {0:x} {1:x}", typeID.token1, typeID.token2); m_moduleFilePath = Name; } if (numFields > 0) { m_fields = new ICorDebugGCHeapField[numFields]; var corFields = new COR_FIELD[numFields]; int fieldsFetched; m_heap.m_process5.GetTypeFields(typeID, corFields.Length, corFields, out fieldsFetched); Debug.Assert(fieldsFetched == m_fields.Length); for (int i = 0; i < corFields.Length; i++) { int fieldTypeToken, fieldAttr, sigBlobSize, cplusTypeFlab, fieldValSize; IntPtr sigBlob, fieldVal; buffer.Length = 0; if (metaData != null) { metaData.GetFieldProps(corFields[i].token, out fieldTypeToken, buffer, buffer.Capacity, out bufferSizeRet, out fieldAttr, out sigBlob, out sigBlobSize, out cplusTypeFlab, out fieldVal, out fieldValSize); } var fieldName = buffer.ToString(); ICorDebugGCHeapType fieldType = null; // If the type has never been loaded, then you can get a null field type. // TODO FIX NOW, think about this. if (corFields[i].id.token1 != 0 || corFields[i].id.token2 != 0) { // Console.WriteLine("Looking up field {0}.{1} typeId {2:x} {3:x}", Name, fieldName, corFields[i].id.token1, corFields[i].id.token2); Debug.Assert(corFields[i].fieldType != CorElementType.ELEMENT_TYPE_END); // TODO FIX NOW remove the condition if (!GCRootNames.IsReferenceType(corFields[i].fieldType)) { fieldType = m_heap.GetObjectTypeFromID(corFields[i].id); } } else { // Console.WriteLine("Warning, NULL type token for {0}.{1} assuming it is an objectRef", Name, fieldName); // Zero means the type is not loaded. This can only happen if it is a reference type corFields[i].fieldType = CorElementType.ELEMENT_TYPE_CLASS; } // The element types match. (string matches class) #if DEBUG if (fieldType != null) { var fieldTypeKind = fieldType.TypeKind; if (fieldTypeKind == CorElementType.ELEMENT_TYPE_STRING) { fieldTypeKind = CorElementType.ELEMENT_TYPE_CLASS; } if (fieldTypeKind == CorElementType.ELEMENT_TYPE_OBJECT) { fieldTypeKind = CorElementType.ELEMENT_TYPE_CLASS; } Debug.Assert(fieldTypeKind == corFields[i].fieldType); } #endif m_fields[i] = new ICorDebugGCHeapField(fieldName, corFields[i].offset, fieldType, corFields[i].fieldType); } } }
} // Used for deserialization internal ICorDebugGCHeapType(ICorDebugGCHeap heap, COR_TYPEID typeID) { // Console.WriteLine("Creating type for typeId {0:x} {1:x}", typeID.token1, typeID.token2); m_heap = heap; m_index = heap.m_types.Count; m_name = ""; m_moduleFilePath = ""; heap.m_typeTable[typeID] = this; heap.m_types.Add(this); COR_TYPE_LAYOUT header = new COR_TYPE_LAYOUT(); // Console.WriteLine("Calling GetTypeLayout for typeId {0:x} {1:x}", typeID.token1, typeID.token2); heap.m_process5.GetTypeLayout(typeID, out header); m_typeKind = header.type; m_boxOffset = header.boxOffset; m_size = header.objectSize; // Strings are considered arrays. m_isArray = (header.type == CorElementType.ELEMENT_TYPE_ARRAY || header.type == CorElementType.ELEMENT_TYPE_SZARRAY || header.type == CorElementType.ELEMENT_TYPE_STRING); if (m_isArray) { // Console.WriteLine("Calling GetArrayLayout for typeId {0:x} {1:x}", typeID.token1, typeID.token2); heap.m_process5.GetArrayLayout(typeID, out m_array); m_elementType = heap.GetObjectTypeFromID(m_array.componentID); m_moduleFilePath = ComponentType.Module.FileName; if (m_typeKind == CorElementType.ELEMENT_TYPE_SZARRAY) { m_name = ComponentType.Name + "[]"; } else if (m_typeKind == CorElementType.ELEMENT_TYPE_ARRAY) { if (m_array.numRanks == 1) { m_name = ComponentType.Name + "[*]"; } else { m_name = ComponentType.Name + "[" + new string(',', m_array.numRanks - 1) + "]"; } Debug.Assert(m_array.firstElementOffset > m_array.rankOffset); } else if (m_typeKind == CorElementType.ELEMENT_TYPE_STRING) { m_name = "System.String"; } Debug.Assert(m_array.firstElementOffset > 0); } else { if (header.parentID.token1 != 0 || header.parentID.token2 != 0) // If we have a parent get it. { m_baseType = heap.GetObjectTypeFromID(header.parentID); } SetNameModuleAndFields(m_typeKind, typeID, header.numFields); #if DEBUG if (m_fields != null) { foreach (var field in m_fields) { Debug.Assert(field != null); } } #endif } }