Example #1
0
            private void FillLocation(ArgumentOrLocal argOrLocal, IXCLRDataValue value)
            {
                uint numLocs;

                if (HR.Failed(value.GetNumLocations(out numLocs)))
                {
                    return;
                }

                // Values could span multiple locations when they are enregistered.
                // The IXCLRDataValue::GetBytes method is supposed to take care of it,
                // but we don't have a location to display. We don't even get the
                // register name(s), so there's really nothing to display in this case.
                if (numLocs != 1)
                {
                    return;
                }

                uint  flags;
                ulong address;

                if (HR.Failed(value.GetLocationByIndex(0, out flags, out address)))
                {
                    return;
                }

                // Only memory locations have a memory address.
                if (flags == (uint)ClrDataValueLocationFlag.CLRDATA_VLOC_MEMORY)
                {
                    argOrLocal.Location = address;
                }
            }
Example #2
0
            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;
                }
            }
Example #3
0
            private void FillLocation(ArgumentOrLocal argOrLocal, IXCLRDataValue value)
            {
                uint numLocs;
                if (HR.Failed(value.GetNumLocations(out numLocs)))
                    return;

                // Values could span multiple locations when they are enregistered.
                // The IXCLRDataValue::GetBytes method is supposed to take care of it,
                // but we don't have a location to display. We don't even get the
                // register name(s), so there's really nothing to display in this case.
                if (numLocs != 1)
                    return;

                uint flags;
                ulong address;
                if (HR.Failed(value.GetLocationByIndex(0, out flags, out address)))
                    return;

                // Only memory locations have a memory address.
                if (flags == (uint)ClrDataValueLocationFlag.CLRDATA_VLOC_MEMORY)
                {
                    argOrLocal.Location = address;
                }
            }
Example #4
0
            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;
                }
            }