Esempio n. 1
0
        /// <summary>
        /// Reads a single exception handler from the given input stream.
        /// </summary>
        /// <param name="cilMethodBody">The method body that contains the exception handler.</param>
        /// <param name="reader">The input stream to read from.</param>
        /// <param name="fatFormat">A value indicating whether the fat format or the small format should be used.</param>
        /// <returns>The exception handler.</returns>
        public static ExceptionHandler FromReader(CilMethodBody cilMethodBody, IBinaryStreamReader reader, bool fatFormat)
        {
            var  handlerType              = (ExceptionHandlerType)(fatFormat ? reader.ReadUInt32() : reader.ReadUInt16());
            int  tryOffset                = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            int  tryLength                = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            int  handlerOffset            = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            int  handlerLength            = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            uint classTokenOrFilterOffset = reader.ReadUInt32();

            var handler = new ExceptionHandler(handlerType)
            {
                IsFat        = fatFormat,
                TryStart     = cilMethodBody.Instructions.GetByOffset(tryOffset),
                TryEnd       = cilMethodBody.Instructions.GetByOffset(tryOffset + tryLength),
                HandlerStart = cilMethodBody.Instructions.GetByOffset(handlerOffset),
                HandlerEnd   = cilMethodBody.Instructions.GetByOffset(handlerOffset + handlerLength),
            };

            switch (handler.HandlerType)
            {
            case ExceptionHandlerType.Exception:
                handler.CatchType = (ITypeDefOrRef)((IOperandResolver)cilMethodBody).ResolveMember(
                    new MetadataToken(classTokenOrFilterOffset));
                break;

            case ExceptionHandlerType.Filter:
                handler.FilterStart = cilMethodBody.Instructions.GetByOffset((int)classTokenOrFilterOffset);
                break;
            }

            return(handler);
        }
Esempio n. 2
0
        public static ExceptionHandler FromReader(MethodBody methodBody, IBinaryStreamReader reader, bool fatFormat)
        {
            var offset                   = reader.Position;
            var handerType               = fatFormat ? reader.ReadUInt32() : reader.ReadUInt16();
            var tryOffset                = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            var tryLength                = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            var handlerOffset            = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            var handlerLength            = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            var classTokenOrFilterOffset = reader.ReadUInt32();

            var handler = new ExceptionHandler((ExceptionHandlerType)handerType)
            {
                StartOffset  = offset,
                IsFat        = fatFormat,
                MethodBody   = methodBody,
                TryStart     = methodBody.GetInstructionByOffset(tryOffset),
                TryEnd       = methodBody.GetInstructionByOffset(tryOffset + tryLength),
                HandlerStart = methodBody.GetInstructionByOffset(handlerOffset),
                HandlerEnd   = methodBody.GetInstructionByOffset(handlerOffset + handlerLength),
            };

            switch (handler.HandlerType)
            {
            case ExceptionHandlerType.Exception:
                handler.CatchType = (ITypeDefOrRef)((IOperandResolver)methodBody).ResolveMember(new MetadataToken(classTokenOrFilterOffset));
                break;

            case ExceptionHandlerType.Filter:
                handler.FilterStart = methodBody.GetInstructionByOffset((int)classTokenOrFilterOffset);
                break;
            }

            return(handler);
        }
        /// <summary>
        /// Reads a single exception handler from the provided input stream.
        /// </summary>
        /// <param name="body">The method body containing the exception handler.</param>
        /// <param name="reader">The input stream.</param>
        /// <param name="isFat"><c>true</c> if the fat format should be used, <c>false</c> otherwise.</param>
        /// <returns>The exception handler.</returns>
        public static CilExceptionHandler FromReader(CilMethodBody body, IBinaryStreamReader reader, bool isFat)
        {
            CilExceptionHandlerType handlerType;
            int tryStartOffset;
            int tryEndOffset;
            int handlerStartOffset;
            int handlerEndOffset;

            // Read raw structure.
            if (isFat)
            {
                handlerType        = (CilExceptionHandlerType)reader.ReadUInt32();
                tryStartOffset     = reader.ReadInt32();
                tryEndOffset       = tryStartOffset + reader.ReadInt32();
                handlerStartOffset = reader.ReadInt32();
                handlerEndOffset   = handlerStartOffset + reader.ReadInt32();
            }
            else
            {
                handlerType        = (CilExceptionHandlerType)reader.ReadUInt16();
                tryStartOffset     = reader.ReadUInt16();
                tryEndOffset       = tryStartOffset + reader.ReadByte();
                handlerStartOffset = reader.ReadUInt16();
                handlerEndOffset   = handlerStartOffset + reader.ReadByte();
            }

            int exceptionTokenOrFilterStart = reader.ReadInt32();

            // Create handler.
            var handler = new CilExceptionHandler
            {
                HandlerType = handlerType,
                TryStart    = body.Instructions.GetByOffset(tryStartOffset)?.CreateLabel() ??
                              new CilOffsetLabel(tryStartOffset),
                TryEnd       = body.Instructions.GetByOffset(tryEndOffset)?.CreateLabel() ?? new CilOffsetLabel(tryEndOffset),
                HandlerStart = body.Instructions.GetByOffset(handlerStartOffset)?.CreateLabel() ??
                               new CilOffsetLabel(handlerStartOffset),
                HandlerEnd = body.Instructions.GetByOffset(handlerEndOffset)?.CreateLabel() ??
                             new CilOffsetLabel(handlerEndOffset),
            };

            // Interpret last field.
            switch (handler.HandlerType)
            {
            case CilExceptionHandlerType.Exception when body.Owner.Module.TryLookupMember(exceptionTokenOrFilterStart, out var member):
                handler.ExceptionType = member as ITypeDefOrRef;

                break;

            case CilExceptionHandlerType.Filter:
                handler.FilterStart = body.Instructions.GetByOffset(exceptionTokenOrFilterStart)?.CreateLabel()
                                      ?? new CilOffsetLabel(exceptionTokenOrFilterStart);
                break;;
            }

            return(handler);
        }
Esempio n. 4
0
        private static object ReadRawOperand(IBinaryStreamReader reader, CilOperandType cilOperandType)
        {
            switch (cilOperandType)
            {
            case CilOperandType.InlineNone:
                return(null);

            case CilOperandType.InlineArgument:
            case CilOperandType.InlineVar:
                return(reader.ReadUInt16());

            case CilOperandType.InlineI:
            case CilOperandType.InlineBrTarget:
                return(reader.ReadInt32());

            case CilOperandType.ShortInlineArgument:
            case CilOperandType.ShortInlineVar:
                return(reader.ReadByte());

            case CilOperandType.ShortInlineBrTarget:
            case CilOperandType.ShortInlineI:
                return(reader.ReadSByte());

            case CilOperandType.ShortInlineR:
                return(reader.ReadSingle());

            case CilOperandType.InlineR:
                return(reader.ReadDouble());

            case CilOperandType.InlineI8:
                return(reader.ReadInt64());

            case CilOperandType.InlineField:
            case CilOperandType.InlineMethod:
            case CilOperandType.InlineSig:
            case CilOperandType.InlineTok:
            case CilOperandType.InlineType:
            case CilOperandType.InlineString:
                return(new MetadataToken(reader.ReadUInt32()));

            case CilOperandType.InlineSwitch:
                var offsets = new int[reader.ReadUInt32()];
                for (int i = 0; i < offsets.Length; i++)
                {
                    offsets[i] = reader.ReadInt32();
                }
                return(offsets);
            }
            throw new NotSupportedException();
        }
Esempio n. 5
0
        public new static CilRawFatMethodBody FromReader(IBinaryStreamReader reader)
        {
            var body = new CilRawFatMethodBody
            {
                _header  = reader.ReadUInt16(),
                MaxStack = reader.ReadUInt16()
            };

            int codeSize = reader.ReadInt32();

            body.LocalVarSigToken = reader.ReadUInt32();

            body.Code = reader.ReadBytes(codeSize);

            if (body.HasSections)
            {
                reader.Align(4);

                CilExtraSection section;
                do
                {
                    section = CilExtraSection.FromReader(reader);
                    body.ExtraSections.Add(section);
                } while (section.HasMoreSections);
            }

            return(body);
        }
Esempio n. 6
0
        private static object ReadRawOperand(IBinaryStreamReader reader, MsilOperandType msilOperandType)
        {
            switch (msilOperandType)
            {
                case MsilOperandType.InlineNone:
                    return null;

                case MsilOperandType.InlineArgument:
                case MsilOperandType.InlineVar:
                    return reader.ReadUInt16();

                case MsilOperandType.InlineI:
                case MsilOperandType.InlineBrTarget:
                    return reader.ReadInt32();

                case MsilOperandType.ShortInlineArgument:
                case MsilOperandType.ShortInlineVar:
                    return reader.ReadByte();

                case MsilOperandType.ShortInlineBrTarget:
                case MsilOperandType.ShortInlineI:
                    return reader.ReadSByte();

                case MsilOperandType.ShortInlineR:
                    return reader.ReadSingle();
                case MsilOperandType.InlineR:
                    return reader.ReadDouble();
                case MsilOperandType.InlineI8:
                    return reader.ReadInt64();

                case MsilOperandType.InlineField :
                case MsilOperandType.InlineMethod :
                case MsilOperandType.InlineSig:
                case MsilOperandType.InlineTok:
                case MsilOperandType.InlineType:
                case MsilOperandType.InlineString:
                    return new MetadataToken(reader.ReadUInt32());

                case MsilOperandType.InlineSwitch:
                    var offsets = new int[reader.ReadUInt32()];
                    for (int i = 0; i < offsets.Length; i++)
                        offsets[i] = reader.ReadInt32();
                    return offsets;
            }
            throw new NotSupportedException();
        }
Esempio n. 7
0
        private object ReadSignedImmediateData(X86OperandSize size)
        {
            switch (size)
            {
            case X86OperandSize.Byte:
                return(_reader.ReadSByte());

            case X86OperandSize.Word:
                return(_reader.ReadInt16());

            case X86OperandSize.Dword:
                return(_reader.ReadInt32());

            case X86OperandSize.WordOrDword:
                return(_reader.ReadInt32());    // TODO: use operand-size override opcode
                // TODO: fword
            }
            throw new NotSupportedException();
        }
Esempio n. 8
0
        /// <summary>
        /// Reads a metadata directory from an input stream.
        /// </summary>
        /// <param name="context">The reader context.</param>
        /// <param name="directoryReader">The input stream containing the metadata directory.</param>
        /// <exception cref="ArgumentNullException">Occurs when any of the arguments are <c>null</c>.</exception>
        /// <exception cref="NotSupportedException">Occurs when an unsupported metadata directory format was encountered.</exception>
        /// <exception cref="BadImageFormatException">Occurs when the metadata directory header is invalid.</exception>
        public SerializedMetadata(PEReaderContext context, IBinaryStreamReader directoryReader)
        {
            if (directoryReader == null)
            {
                throw new ArgumentNullException(nameof(directoryReader));
            }
            _context = context ?? throw new ArgumentNullException(nameof(context));

            _streamContentsReader = directoryReader.Fork();

            var signature = (MetadataSignature)directoryReader.ReadUInt32();

            switch (signature)
            {
            case MetadataSignature.Bsjb:
                // BSJB header is the default header.
                break;

            case MetadataSignature.Moc:
                _context.NotSupported("Old +MOC metadata header format is not supported.");
                return;

            default:
                _context.BadImage($"Invalid metadata header ({(uint) signature:X8}).");
                return;
            }

            MajorVersion = directoryReader.ReadUInt16();
            MinorVersion = directoryReader.ReadUInt16();
            Reserved     = directoryReader.ReadUInt32();

            int versionLength = directoryReader.ReadInt32();

            if (!directoryReader.CanRead(versionLength))
            {
                _context.BadImage($"Invalid version length in metadata header ({versionLength.ToString()} characters).");
                return;
            }

            var versionBytes = new byte[versionLength];

            directoryReader.ReadBytes(versionBytes, 0, versionBytes.Length);
            VersionString = Encoding.ASCII.GetString(versionBytes);

            Flags                = directoryReader.ReadUInt16();
            _numberOfStreams     = directoryReader.ReadInt16();
            _streamEntriesReader = directoryReader.Fork();
        }
Esempio n. 9
0
        /// <summary>
        /// Reads a metadata directory from an input stream.
        /// </summary>
        /// <param name="reader">The input stream.</param>
        /// <param name="metadataStreamReader"></param>
        /// <exception cref="ArgumentNullException">Occurs when any of the arguments are <c>null</c>.</exception>
        /// <exception cref="NotSupportedException">Occurs when an unsupported metadata directory format was encountered.</exception>
        /// <exception cref="BadImageFormatException">Occurs when the metadata directory header is invalid.</exception>
        public SerializedMetadata(IBinaryStreamReader reader, IMetadataStreamReader metadataStreamReader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }
            _metadataStreamReader = metadataStreamReader;

            _streamContentsReader = reader.Fork();

            var signature = (MetadataSignature)reader.ReadUInt32();

            switch (signature)
            {
            case MetadataSignature.Bsjb:
                // BSJB header is the default header.
                break;

            case MetadataSignature.Moc:
                throw new NotSupportedException("Old +MOC metadata header format is not supported.");

            default:
                throw new BadImageFormatException($"Invalid metadata header ({(uint) signature:X8}).");
            }

            MajorVersion = reader.ReadUInt16();
            MinorVersion = reader.ReadUInt16();
            Reserved     = reader.ReadUInt32();

            int versionLength = reader.ReadInt32();

            if (!reader.CanRead(versionLength))
            {
                throw new BadImageFormatException($"Invalid version length in metadata header ({versionLength} characters).");
            }

            var versionBytes = new byte[versionLength];

            reader.ReadBytes(versionBytes, 0, versionBytes.Length);
            VersionString = Encoding.ASCII.GetString(versionBytes);

            Flags                = reader.ReadUInt16();
            _numberOfStreams     = reader.ReadInt16();
            _streamEntriesReader = reader.Fork();
        }
Esempio n. 10
0
        private static object ReadElement(IBinaryStreamReader reader, ElementType elementType)
        {
            switch (elementType)
            {
            case ElementType.I1:
                return(reader.ReadSByte());

            case ElementType.I2:
                return(reader.ReadInt16());

            case ElementType.I4:
                return(reader.ReadInt32());

            case ElementType.I8:
                return(reader.ReadInt64());

            case ElementType.U1:
                return(reader.ReadByte());

            case ElementType.U2:
                return(reader.ReadUInt16());

            case ElementType.U4:
                return(reader.ReadUInt32());

            case ElementType.U8:
                return(reader.ReadUInt64());

            case ElementType.R4:
                return(reader.ReadSingle());

            case ElementType.R8:
                return(reader.ReadDouble());
            }

            ThrowUnsupportedElementType(elementType);
            return(null);
        }
Esempio n. 11
0
        private static object ReadValue(MetadataHeader header, TypeSignature typeSignature, IBinaryStreamReader reader)
        {
            switch (typeSignature.ElementType)
            {
            case ElementType.Boolean:
                return(reader.ReadByte() == 1);

            case ElementType.Char:
                return((char)reader.ReadUInt16());

            case ElementType.R4:
                return(reader.ReadSingle());

            case ElementType.R8:
                return(reader.ReadDouble());

            case ElementType.I1:
                return(reader.ReadSByte());

            case ElementType.I2:
                return(reader.ReadInt16());

            case ElementType.I4:
                return(reader.ReadInt32());

            case ElementType.I8:
                return(reader.ReadInt64());

            case ElementType.U1:
                return(reader.ReadByte());

            case ElementType.U2:
                return(reader.ReadUInt16());

            case ElementType.U4:
                return(reader.ReadUInt32());

            case ElementType.U8:
                return(reader.ReadUInt64());

            case ElementType.String:
                return(reader.ReadSerString());

            case ElementType.Object:
            case ElementType.Class:
            case ElementType.Enum:
            case ElementType.ValueType:
                var enumTypeDef = header.MetadataResolver.ResolveType(typeSignature);
                if (enumTypeDef == null)
                {
                    throw new MemberResolutionException(typeSignature);
                }

                if (enumTypeDef.IsEnum)
                {
                    return(ReadValue(header, enumTypeDef.GetEnumUnderlyingType(), reader));
                }
                break;
            }
            if (typeSignature.IsTypeOf("System", "Type"))
            {
                return(reader.ReadSerString());
            }
            throw new NotSupportedException("Unsupported element type " + typeSignature.ElementType);
        }
Esempio n. 12
0
        public static ExceptionHandler FromReader(MethodBody methodBody, IBinaryStreamReader reader, bool fatFormat)
        {
            var offset = reader.Position;
            var handerType = fatFormat ? reader.ReadUInt32() : reader.ReadUInt16();
            var tryOffset = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            var tryLength = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            var handlerOffset = fatFormat ? reader.ReadInt32() : reader.ReadUInt16();
            var handlerLength = fatFormat ? reader.ReadInt32() : reader.ReadByte();
            var classTokenOrFilterOffset = reader.ReadUInt32();

            var handler = new ExceptionHandler((ExceptionHandlerType)handerType)
            {
                StartOffset = offset,
                IsFat = fatFormat,
                TryStart = methodBody.GetInstructionByOffset(tryOffset),
                TryEnd = methodBody.GetInstructionByOffset(tryOffset + tryLength),
                HandlerStart = methodBody.GetInstructionByOffset(handlerOffset),
                HandlerEnd = methodBody.GetInstructionByOffset(handlerOffset + handlerLength),
            };

            switch (handler.HandlerType)
            {
                case ExceptionHandlerType.Exception:
                    handler.CatchType = (ITypeDefOrRef)((IOperandResolver)methodBody).ResolveMember(new MetadataToken(classTokenOrFilterOffset));
                    break;
                case ExceptionHandlerType.Filter:
                    handler.FilterStart = methodBody.GetInstructionByOffset((int)classTokenOrFilterOffset);
                    break;
            }

            return handler;
        }
Esempio n. 13
0
        private static object ReadValue(ModuleDefinition parentModule, TypeSignature valueType, IBinaryStreamReader reader)
        {
            switch (valueType.ElementType)
            {
            case ElementType.Boolean:
                return(reader.ReadByte() == 1);

            case ElementType.Char:
                return((char)reader.ReadUInt16());

            case ElementType.R4:
                return(reader.ReadSingle());

            case ElementType.R8:
                return(reader.ReadDouble());

            case ElementType.I1:
                return(reader.ReadSByte());

            case ElementType.I2:
                return(reader.ReadInt16());

            case ElementType.I4:
                return(reader.ReadInt32());

            case ElementType.I8:
                return(reader.ReadInt64());

            case ElementType.U1:
                return(reader.ReadByte());

            case ElementType.U2:
                return(reader.ReadUInt16());

            case ElementType.U4:
                return(reader.ReadUInt32());

            case ElementType.U8:
                return(reader.ReadUInt64());

            case ElementType.String:
                return(reader.ReadSerString());

            case ElementType.Object:
                return(ReadValue(parentModule, TypeSignature.ReadFieldOrPropType(parentModule, reader), reader));

            case ElementType.Class:
            case ElementType.Enum:
            case ElementType.ValueType:
                var enumTypeDef = parentModule.MetadataResolver.ResolveType(valueType);
                if (enumTypeDef != null && enumTypeDef.IsEnum)
                {
                    return(ReadValue(parentModule, enumTypeDef.GetEnumUnderlyingType(), reader));
                }
                break;
            }

            if (valueType.IsTypeOf("System", "Type"))
            {
                return(TypeNameParser.Parse(parentModule, reader.ReadSerString()));
            }

            throw new NotSupportedException($"Unsupported element type {valueType.ElementType}.");
        }
Esempio n. 14
0
        private static object ReadValue(MetadataHeader header, TypeSignature typeSignature, IBinaryStreamReader reader)
        {
            switch (typeSignature.ElementType)
            {
                case ElementType.Boolean:
                    return reader.ReadByte() == 1;
                case ElementType.Char:
                    return (char)reader.ReadUInt16();
                case ElementType.R4:
                    return reader.ReadSingle();
                case ElementType.R8:
                    return reader.ReadDouble();
                case ElementType.I1:
                    return reader.ReadSByte();
                case ElementType.I2:
                    return reader.ReadInt16();
                case ElementType.I4:
                    return reader.ReadInt32();
                case ElementType.I8:
                    return reader.ReadInt64();
                case ElementType.U1:
                    return reader.ReadByte();
                case ElementType.U2:
                    return reader.ReadUInt16();
                case ElementType.U4:
                    return reader.ReadUInt32();
                case ElementType.U8:
                    return reader.ReadUInt64();
                case ElementType.String:
                    return reader.ReadSerString();
                case ElementType.Object:
                    return ReadValue(header, TypeSignature.ReadFieldOrPropType(header, reader), reader);
                case ElementType.Class:
                case ElementType.Enum:
                case ElementType.ValueType:
                    var enumTypeDef = header.MetadataResolver.ResolveType(typeSignature);
                    if (enumTypeDef == null)
                        throw new MemberResolutionException(typeSignature);

                    if (enumTypeDef.IsEnum)
                        return ReadValue(header, enumTypeDef.GetEnumUnderlyingType(), reader);
                    break;
            }
            if (typeSignature.IsTypeOf("System", "Type"))
                return TypeSignature.FromAssemblyQualifiedName(header, reader.ReadSerString());
            throw new NotSupportedException("Unsupported element type " + typeSignature.ElementType);
        }
Esempio n. 15
0
        private object ReadOperand(CilOperandType operandType)
        {
            switch (operandType)
            {
            case CilOperandType.InlineNone:
                return(null);

            case CilOperandType.ShortInlineI:
                return(_reader.ReadSByte());

            case CilOperandType.ShortInlineBrTarget:
                return(new CilOffsetLabel(_reader.ReadSByte() + (int)(_reader.Offset - _reader.StartOffset)));

            case CilOperandType.ShortInlineVar:
                byte shortLocalIndex = _reader.ReadByte();
                return(_operandResolver?.ResolveLocalVariable(shortLocalIndex) ?? shortLocalIndex);

            case CilOperandType.ShortInlineArgument:
                byte shortArgIndex = _reader.ReadByte();
                return(_operandResolver?.ResolveParameter(shortArgIndex) ?? shortArgIndex);

            case CilOperandType.InlineVar:
                ushort longLocalIndex = _reader.ReadUInt16();
                return(_operandResolver?.ResolveLocalVariable(longLocalIndex) ?? longLocalIndex);

            case CilOperandType.InlineArgument:
                ushort longArgIndex = _reader.ReadUInt16();
                return(_operandResolver?.ResolveParameter(longArgIndex) ?? longArgIndex);

            case CilOperandType.InlineI:
                return(_reader.ReadInt32());

            case CilOperandType.InlineBrTarget:
                return(new CilOffsetLabel(_reader.ReadInt32() + (int)(_reader.Offset - _reader.StartOffset)));

            case CilOperandType.ShortInlineR:
                return(_reader.ReadSingle());

            case CilOperandType.InlineI8:
                return(_reader.ReadInt64());

            case CilOperandType.InlineR:
                return(_reader.ReadDouble());

            case CilOperandType.InlineString:
                var stringToken = new MetadataToken(_reader.ReadUInt32());
                return(_operandResolver?.ResolveString(stringToken) ?? stringToken);

            case CilOperandType.InlineField:
            case CilOperandType.InlineMethod:
            case CilOperandType.InlineSig:
            case CilOperandType.InlineTok:
            case CilOperandType.InlineType:
                var memberToken = new MetadataToken(_reader.ReadUInt32());
                return(_operandResolver?.ResolveMember(memberToken) ?? memberToken);

            case CilOperandType.InlinePhi:
                throw new NotSupportedException();

            case CilOperandType.InlineSwitch:
                return(ReadSwitchTable());

            default:
                throw new ArgumentOutOfRangeException(nameof(operandType), operandType, null);
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Reads a type signature from a blob reader.
        /// </summary>
        /// <param name="module">The module containing the blob signature.</param>
        /// <param name="reader">The blob signature reader.</param>
        /// <param name="protection">The object responsible for detecting infinite recursion.</param>
        /// <returns>The type signature.</returns>
        /// <exception cref="ArgumentOutOfRangeException">Occurs when the blob reader points to an element type that is
        /// invalid or unsupported.</exception>
        public static TypeSignature FromReader(ModuleDefinition module, IBinaryStreamReader reader,
                                               RecursionProtection protection)
        {
            var elementType = (ElementType)reader.ReadByte();

            switch (elementType)
            {
            case ElementType.Void:
            case ElementType.Boolean:
            case ElementType.Char:
            case ElementType.I1:
            case ElementType.U1:
            case ElementType.I2:
            case ElementType.U2:
            case ElementType.I4:
            case ElementType.U4:
            case ElementType.I8:
            case ElementType.U8:
            case ElementType.R4:
            case ElementType.R8:
            case ElementType.String:
            case ElementType.I:
            case ElementType.U:
            case ElementType.TypedByRef:
            case ElementType.Object:
                return(module.CorLibTypeFactory.FromElementType(elementType));

            case ElementType.ValueType:
                return(new TypeDefOrRefSignature(ReadTypeDefOrRef(module, reader, protection, false), true));

            case ElementType.Class:
                return(new TypeDefOrRefSignature(ReadTypeDefOrRef(module, reader, protection, false), false));

            case ElementType.Ptr:
                return(new PointerTypeSignature(FromReader(module, reader, protection)));

            case ElementType.ByRef:
                return(new ByReferenceTypeSignature(FromReader(module, reader, protection)));

            case ElementType.Var:
                return(new GenericParameterSignature(module, GenericParameterType.Type,
                                                     (int)reader.ReadCompressedUInt32()));

            case ElementType.MVar:
                return(new GenericParameterSignature(module, GenericParameterType.Method,
                                                     (int)reader.ReadCompressedUInt32()));

            case ElementType.Array:
                return(ArrayTypeSignature.FromReader(module, reader, protection));

            case ElementType.GenericInst:
                return(GenericInstanceTypeSignature.FromReader(module, reader, protection));

            case ElementType.FnPtr:
                throw new NotImplementedException();

            case ElementType.SzArray:
                return(new SzArrayTypeSignature(FromReader(module, reader, protection)));

            case ElementType.CModReqD:
                return(new CustomModifierTypeSignature(
                           ReadTypeDefOrRef(module, reader, protection, true),
                           true,
                           FromReader(module, reader, protection)));

            case ElementType.CModOpt:
                return(new CustomModifierTypeSignature(
                           ReadTypeDefOrRef(module, reader, protection, true),
                           false,
                           FromReader(module, reader, protection)));

            case ElementType.Sentinel:
                return(new SentinelTypeSignature());

            case ElementType.Pinned:
                return(new PinnedTypeSignature(FromReader(module, reader, protection)));

            case ElementType.Boxed:
                return(new BoxedTypeSignature(FromReader(module, reader, protection)));

            case ElementType.Internal:
                IntPtr address = IntPtr.Size switch
                {
                    4 => new IntPtr(reader.ReadInt32()),
                    _ => new IntPtr(reader.ReadInt64())
                };

                //Get Internal Method Through Reflection
                var GetTypeFromHandleUnsafeReflection = typeof(Type)
                                                        .GetMethod("GetTypeFromHandleUnsafe", ((BindingFlags)(-1)), null, new[] { typeof(IntPtr) },
                                                                   null);
                //Invoke It To Get The Value
                var Type = (Type)GetTypeFromHandleUnsafeReflection?.Invoke(null, new object[] { address });
                //Import it
                return(new TypeDefOrRefSignature(new ReferenceImporter(module).ImportType((Type))));

            default:
                throw new ArgumentOutOfRangeException($"Invalid or unsupported element type {elementType}.");
            }
        }
        public void ReadValue(TypeSignature valueType)
        {
            if (valueType.IsTypeOf("System", "Type"))
            {
                Elements.Add(TypeNameParser.Parse(_parentModule, _reader.ReadSerString()));
                return;
            }

            switch (valueType.ElementType)
            {
            case ElementType.Boolean:
                Elements.Add(_reader.ReadByte() == 1);
                break;

            case ElementType.Char:
                Elements.Add((char)_reader.ReadUInt16());
                break;

            case ElementType.R4:
                Elements.Add(_reader.ReadSingle());
                break;

            case ElementType.R8:
                Elements.Add(_reader.ReadDouble());
                break;

            case ElementType.I1:
                Elements.Add(_reader.ReadSByte());
                break;

            case ElementType.I2:
                Elements.Add(_reader.ReadInt16());
                break;

            case ElementType.I4:
                Elements.Add(_reader.ReadInt32());
                break;

            case ElementType.I8:
                Elements.Add(_reader.ReadInt64());
                break;

            case ElementType.U1:
                Elements.Add(_reader.ReadByte());
                break;

            case ElementType.U2:
                Elements.Add(_reader.ReadUInt16());
                break;

            case ElementType.U4:
                Elements.Add(_reader.ReadUInt32());
                break;

            case ElementType.U8:
                Elements.Add(_reader.ReadUInt64());
                break;

            case ElementType.String:
                Elements.Add(_reader.ReadSerString());
                break;

            case ElementType.Object:
                var reader = new CustomAttributeArgumentReader(_parentModule, _reader);
                var type   = TypeSignature.ReadFieldOrPropType(_parentModule, _reader);
                reader.ReadValue(type);
                Elements.Add(new BoxedArgument(type, type.ElementType == ElementType.SzArray
                        ? reader.Elements.ToArray()
                        : reader.Elements[0]));
                break;

            case ElementType.SzArray:
                var  arrayElementType = ((SzArrayTypeSignature)valueType).BaseType;
                uint elementCount     = _reader.CanRead(sizeof(uint)) ? _reader.ReadUInt32() : uint.MaxValue;
                IsNullArray = elementCount == uint.MaxValue;

                if (!IsNullArray)
                {
                    for (uint i = 0; i < elementCount; i++)
                    {
                        ReadValue(arrayElementType);
                    }
                }

                break;

            case ElementType.Class:
            case ElementType.Enum:
            case ElementType.ValueType:
                // Value is an enum, resolve it and get underlying type.
                // If that fails, most enums are int32s, assume that is the case in an attempt to recover.

                var enumTypeDef = _parentModule.MetadataResolver.ResolveType(valueType);

                TypeSignature underlyingType;
                if (enumTypeDef is null)
                {
                    underlyingType = _parentModule.CorLibTypeFactory.Int32;
                }
                else if (enumTypeDef.IsEnum)
                {
                    underlyingType = enumTypeDef.GetEnumUnderlyingType() ?? _parentModule.CorLibTypeFactory.Int32;
                }
                else
                {
                    throw new NotSupportedException($"Type {valueType} is not an enum.");
                }

                ReadValue(underlyingType);
                break;

            default:
                throw new NotSupportedException($"Unsupported element type {valueType.ElementType}.");
            }
        }