private void TryGetTypeByMetadataToken(ArgumentOrLocal argOrLocal, IXCLRDataTypeInstance typeInstance) { object tmp; if (typeInstance.GetDefinition(out tmp) != HR.S_OK) { return; } IXCLRDataTypeDefinition typeDefinition = (IXCLRDataTypeDefinition)tmp; int typeTok; if (HR.S_OK == typeDefinition.GetTokenAndScope(out typeTok, out tmp)) { IXCLRDataModule module = (IXCLRDataModule)tmp; argOrLocal.ClrType = _context.GetTypeByMetadataToken( GetModuleName(module), typeTok); // This might fail if we don't have that type cached (unlikely) // or if the type is generic, which makes the token non-unique. } }
private void TryGetTypeByMetadataToken(ArgumentOrLocal argOrLocal, IXCLRDataTypeInstance typeInstance) { object tmp; if (typeInstance.GetDefinition(out tmp) != HR.S_OK) return; IXCLRDataTypeDefinition typeDefinition = (IXCLRDataTypeDefinition)tmp; int typeTok; if (HR.S_OK == typeDefinition.GetTokenAndScope(out typeTok, out tmp)) { IXCLRDataModule module = (IXCLRDataModule)tmp; argOrLocal.ClrType = _context.GetTypeByMetadataToken( GetModuleName(module), typeTok); // This might fail if we don't have that type cached (unlikely) // or if the type is generic, which makes the token non-unique. } }
private void FillValue(ArgumentOrLocal argOrLocal, IXCLRDataValue value) { object tmp; ulong size; if (HR.Failed(value.GetSize(out size))) { size = 0; // When the value is unavailable, GetSize fails; consider it 0 } argOrLocal.Size = size; bool probablyReferenceType = false; int getTypeHr = value.GetType(out tmp); if (getTypeHr == HR.S_FALSE) { // For reference types, GetType returns S_FALSE and we need to call GetAssociatedType // to retrieve the type that the reference points to. getTypeHr = value.GetAssociatedType(out tmp); probablyReferenceType = (getTypeHr == HR.S_OK); } if (getTypeHr != HR.S_OK) { return; } IXCLRDataTypeInstance typeInstance = (IXCLRDataTypeInstance)tmp; StringBuilder typeName = new StringBuilder(MaxNameSize); uint typeNameLen; if (FailedUnlessOnCLR2DAC(typeInstance.GetName(0 /*CLRDATA_GETNAME_DEFAULT*/, (uint)typeName.Capacity, out typeNameLen, typeName))) { return; } argOrLocal.StaticTypeName = typeName.ToString(); argOrLocal.ClrType = _context.Heap.GetTypeByName(argOrLocal.StaticTypeName); // If the value is unavailable, we're done here. if (size == 0) { return; } FillLocation(argOrLocal, value); argOrLocal.Value = new byte[size]; uint dataSize; if (HR.Failed(value.GetBytes((uint)argOrLocal.Value.Length, out dataSize, argOrLocal.Value))) { argOrLocal.Value = null; } // If the type is an array type (e.g. System.Byte[]), or a pointer type // (e.g. System.Byte*), or a by-ref type (e.g. System.Byte&), ClrHeap.GetTypeByName // will never return a good value. This is only a problem with variables that // are either ref types and null (and then we can't get the type name from // the object itself), variables that are pointers, and variables that are // by-ref types. Here's the plan: // 1) If the variable is a ref type and is null, we don't care about the // ClrType being correct anyway. We report the type returned by GetName // above, and report the value as null. // 2) If the value is a by-ref type or a pointer type, IXCLRDataValue::GetFlags // can detect it. Then, we keep the ClrType null (because ClrMD doesn't have // a representation for pointer types or by-ref types), but we read the // value anyway by dereferencing the pointer. According to the comments in // xclrdata.idl, IXCLRDataValue::GetAssociatedValue is supposed to return the // pointed-to value, but it doesn't (it only works for references). uint vf; CLRDataValueFlag valueFlags = CLRDataValueFlag.Invalid; if (HR.S_OK == value.GetFlags(out vf)) { valueFlags = (CLRDataValueFlag)vf; } // * Pointers are identified as CLRDATA_VALUE_IS_POINTER. // * By-refs are identified as CLRDATA_VALUE_DEFAULT regardless of referenced type. bool byRefOrPointerType = (valueFlags & CLRDataValueFlag.CLRDATA_VALUE_IS_POINTER) != 0 || (valueFlags == CLRDataValueFlag.CLRDATA_VALUE_DEFAULT /* it is 0 */); if (byRefOrPointerType) { // By-refs to pointers are identified as CLRDATA_VALUE_DEFAULT with target UInt64, // which makes them undistinguishable from 'ref ulong', unfortunately. But if the // type name reported didn't include the &, we know that's what it is. if (argOrLocal.StaticTypeName == "System.UInt64") { argOrLocal.ClrType = null; // We don't really know what the type is argOrLocal.StaticTypeName = "UNKNOWN*&"; } if (argOrLocal.Value != null) { ulong ptrValue = RawBytesToAddress(argOrLocal.Value); ulong potentialReference; if (_context.Runtime.ReadPointer(ptrValue, out potentialReference) && (argOrLocal.ClrType = _context.Heap.GetObjectType(potentialReference)) != null) { // If the type was resolved, then this was the address of a heap object. // In that case, we're done and we have a type. argOrLocal.ObjectAddress = potentialReference; } else { // Otherwise, this address is the address of a value type. We don't know // which type, because IXCLRDataValue::GetAssociatedType doesn't return anything // useful when the value is a pointer or by-ref. But we can try to remove // the * or & from the type name, and then try to figure out what the target // type is. string noRefNoPtrTypeName = argOrLocal.StaticTypeName.TrimEnd('&', '*'); if ((argOrLocal.ClrType = _context.Heap.GetTypeByName(noRefNoPtrTypeName)) != null) { argOrLocal.Location = ptrValue; } } } } if (argOrLocal.ClrType == null) { // If the type is an inner type, IXCLRDataTypeInstance::GetName reports only // the inner part of the type. This isn't enough for ClrHeap.GetTypeByName, // so we have yet another option in that case -- searching by metadata token. TryGetTypeByMetadataToken(argOrLocal, typeInstance); // If we had a pointer or by-ref type and didn't know what it was, we now do, // so we can store its location and have it displayed. if (byRefOrPointerType && argOrLocal.ClrType != null) { argOrLocal.Location = RawBytesToAddress(argOrLocal.Value); } } if (!byRefOrPointerType && (probablyReferenceType || argOrLocal.IsReferenceType)) { argOrLocal.ObjectAddress = RawBytesToAddress(argOrLocal.Value); // The type assigned here can be different from the previous value, // because the static and dynamic type of the argument could differ. // If the object reference is null or invalid, it could also be null -- // so we keep the previous type if it was already available. argOrLocal.ClrType = _context.Heap.GetObjectType(argOrLocal.ObjectAddress) ?? argOrLocal.ClrType; } }