// TODO // bool _hasModifiers; public EcmaSignatureParser(EcmaModule module, BlobReader reader) { _module = module; _reader = reader; // _hasModifiers = false; }
private void ReadXmlSecurityAttribute(ref SRM.BlobReader reader, CustomAttributeTypedArgument <IType> securityAction) { string xml = reader.ReadUTF16(reader.RemainingBytes); var b = new AttributeBuilder(module, KnownAttribute.PermissionSet); b.AddFixedArg(securityAction); b.AddNamedArg("XML", KnownTypeCode.String, xml); }
private unsafe static ImmutableArray<LocalSlotDebugInfo> UncompressSlotMap(ImmutableArray<byte> compressedSlotMap) { if (compressedSlotMap.IsDefaultOrEmpty) { return default(ImmutableArray<LocalSlotDebugInfo>); } var mapBuilder = ArrayBuilder<LocalSlotDebugInfo>.GetInstance(); int syntaxOffsetBaseline = -1; fixed (byte* compressedSlotMapPtr = &compressedSlotMap.ToArray()[0]) { var blobReader = new BlobReader(compressedSlotMapPtr, compressedSlotMap.Length); while (blobReader.RemainingBytes > 0) { byte b = blobReader.ReadByte(); if (b == SyntaxOffsetBaseline) { syntaxOffsetBaseline = -blobReader.ReadCompressedInteger(); continue; } if (b == 0) { // short-lived temp, no info mapBuilder.Add(new LocalSlotDebugInfo(SynthesizedLocalKind.LoweringTemp, default(LocalDebugId))); continue; } var kind = (SynthesizedLocalKind)((b & 0x3f) - 1); bool hasOrdinal = (b & (1 << 7)) != 0; int syntaxOffset; if (!blobReader.TryReadCompressedInteger(out syntaxOffset)) { // invalid data return default(ImmutableArray<LocalSlotDebugInfo>); } syntaxOffset += syntaxOffsetBaseline; int ordinal = 0; if (hasOrdinal && !blobReader.TryReadCompressedInteger(out ordinal)) { // invalid data return default(ImmutableArray<LocalSlotDebugInfo>); } mapBuilder.Add(new LocalSlotDebugInfo(kind, new LocalDebugId(syntaxOffset, ordinal))); } } return mapBuilder.ToImmutableAndFree(); }
/// <exception cref="InvalidDataException">Invalid data.</exception> private unsafe static ImmutableArray<LocalSlotDebugInfo> UncompressSlotMap(ImmutableArray<byte> compressedSlotMap) { if (compressedSlotMap.IsDefaultOrEmpty) { return default(ImmutableArray<LocalSlotDebugInfo>); } var mapBuilder = ArrayBuilder<LocalSlotDebugInfo>.GetInstance(); int syntaxOffsetBaseline = -1; fixed (byte* compressedSlotMapPtr = &compressedSlotMap.ToArray()[0]) { var blobReader = new BlobReader(compressedSlotMapPtr, compressedSlotMap.Length); while (blobReader.RemainingBytes > 0) { try { // Note: integer operations below can't overflow since compressed integers are in range [0, 0x20000000) byte b = blobReader.ReadByte(); if (b == SyntaxOffsetBaseline) { syntaxOffsetBaseline = -blobReader.ReadCompressedInteger(); continue; } if (b == 0) { // short-lived temp, no info mapBuilder.Add(new LocalSlotDebugInfo(SynthesizedLocalKind.LoweringTemp, default(LocalDebugId))); continue; } var kind = (SynthesizedLocalKind)((b & 0x3f) - 1); bool hasOrdinal = (b & (1 << 7)) != 0; int syntaxOffset = blobReader.ReadCompressedInteger() + syntaxOffsetBaseline; int ordinal = hasOrdinal ? blobReader.ReadCompressedInteger() : 0; mapBuilder.Add(new LocalSlotDebugInfo(kind, new LocalDebugId(syntaxOffset, ordinal))); } catch (BadImageFormatException) { throw CreateInvalidDataException(compressedSlotMap, blobReader.Offset); } } } return mapBuilder.ToImmutableAndFree(); }
// cf. MetadataDecoder<>.DecodeTypeOrThrow. private TypeSignature DecodeType(ref BlobReader signatureReader, SignatureTypeCode typeCode) { switch (typeCode) { case SignatureTypeCode.TypeHandle: { int typeArgumentOffset = 0; return DecodeType(signatureReader.ReadTypeHandle(), ImmutableArray<TypeSignature>.Empty, ref typeArgumentOffset); } case SignatureTypeCode.Array: { var elementType = DecodeModifiersAndType(ref signatureReader); int rank; int sizes; signatureReader.TryReadCompressedInteger(out rank); signatureReader.TryReadCompressedInteger(out sizes); if (sizes != 0) { throw UnhandledMetadata(); } return new ArrayTypeSignature(elementType, rank); } case SignatureTypeCode.SZArray: { var elementType = DecodeModifiersAndType(ref signatureReader); return new ArrayTypeSignature(elementType, 1); } case SignatureTypeCode.GenericTypeInstance: return DecodeGenericTypeInstance(ref signatureReader); case SignatureTypeCode.Pointer: { var pointedAtType = DecodeModifiersAndType(ref signatureReader); return new PointerTypeSignature(pointedAtType); } case SignatureTypeCode.GenericTypeParameter: return DecodeGenericTypeParameter(ref signatureReader, _allTypeParameters, _containingArity); case SignatureTypeCode.GenericMethodParameter: return DecodeGenericTypeParameter(ref signatureReader, _methodTypeParameters, 0); default: { var signature = typeCode.ToSpecialType().GetTypeSignature(); if (signature == null) { throw UnhandledMetadata(); } return signature; } } }
private IAttribute ReadBinarySecurityAttribute(ref SRM.BlobReader reader, CustomAttributeTypedArgument <IType> securityAction) { string attributeTypeName = reader.ReadSerializedString(); IType attributeType = module.TypeProvider.GetTypeFromSerializedName(attributeTypeName); reader.ReadCompressedInteger(); // ?? // The specification seems to be incorrect here, so I'm using the logic from Cecil instead. int numNamed = reader.ReadCompressedInteger(); var decoder = new Metadata.CustomAttributeDecoder <IType>(module.TypeProvider, module.metadata); var namedArgs = decoder.DecodeNamedArguments(ref reader, numNamed); return(new DefaultAttribute( attributeType, fixedArguments: ImmutableArray.Create(securityAction), namedArguments: namedArgs)); }
public static ILResult GetInstructions(BlobReader reader) { var instructions = ImmutableArray.CreateBuilder<Instruction>(); List<int[]> switches = null; while (reader.RemainingBytes > 0) { ushort pos = (ushort)reader.Offset; byte op0 = reader.ReadByte(); InstrCode code = (InstrCode)(op0 == 0xFE ? unchecked(0xFE00 + reader.ReadByte()) : op0); OperandType opType = code.GetOperandType(); ulong operand = 0; if (code == InstrCode.Switch) { if (switches == null) switches = new List<int[]>(); operand = (ulong)switches.Count; uint branchCount = reader.ReadUInt32(); int[] branches = new int[branchCount]; for (int i = 0; i < branchCount; i++) { branches[i] = reader.ReadInt32(); } switches.Add(branches); } else { byte operandSize = opType.GetOperandSize(); operand = operandSize == 8 ? reader.ReadUInt64() : operandSize == 4 ? reader.ReadUInt32() : operandSize == 2 ? reader.ReadUInt16() : operandSize == 1 ? (ulong)reader.ReadByte() : 0; } instructions.Add(new Instruction(pos, code, opType, operand)); } return new ILResult { Instructions = instructions.ToImmutable(), Switches = switches?.ToArray() }; }
/// <summary> /// Returns a body block of a method with specified Relative Virtual Address (RVA); /// </summary> /// <exception cref="ArgumentNullException"><paramref name="peReader"/> is null.</exception> /// <exception cref="BadImageFormatException">The body is not found in the metadata or is invalid.</exception> /// <exception cref="InvalidOperationException">Section where the method is stored is not available.</exception> public static unsafe MethodBodyBlock GetMethodBody(this PEReader peReader, int relativeVirtualAddress) { if (peReader == null) { throw new ArgumentNullException(nameof(peReader)); } var block = peReader.GetSectionData(relativeVirtualAddress); if (block.Length == 0) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodRva, relativeVirtualAddress)); } // Call to validating public BlobReader constructor is by design -- we need to throw PlatformNotSupported on big-endian architecture. var blobReader = new BlobReader(block.Pointer, block.Length); return MethodBodyBlock.Create(blobReader); }
public static unsafe string GetMethodIL(this ImmutableArray<byte> ilArray) { var result = new StringBuilder(); fixed (byte* ilPtr = ilArray.ToArray()) { int offset = 0; while (true) { // skip padding: while (offset < ilArray.Length && ilArray[offset] == 0) { offset++; } if (offset == ilArray.Length) { break; } var reader = new BlobReader(ilPtr + offset, ilArray.Length - offset); var methodIL = MethodBodyBlock.Create(reader); if (methodIL == null) { result.AppendFormat("<invalid byte 0x{0:X2} at offset {1}>", ilArray[offset], offset); offset++; } else { ILVisualizerAsTokens.Instance.DumpMethod( result, methodIL.MaxStack, methodIL.GetILContent(), ImmutableArray.Create<ILVisualizer.LocalInfo>(), ImmutableArray.Create<ILVisualizer.HandlerSpan>()); offset += methodIL.Size; } } } return result.ToString(); }
public unsafe BlobReader(byte* buffer, int length) { if (length < 0) { throw new ArgumentOutOfRangeException("length"); } if (buffer == null && length != 0) { throw new ArgumentNullException("buffer"); } // the reader performs little-endian specific operations if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); } this = new BlobReader(new MemoryBlock(buffer, length)); }
private static int IndexOfCharacter(BlobReader blobReader, char ch) { // This function is only safe for searching for ascii characters. Debug.Assert(ch < 127); unsafe { var ptr = blobReader.CurrentPointer; for (int i = 0, n = blobReader.RemainingBytes; i < n; i++) { if (*ptr == ch) { return i; } ptr++; } return -1; } }
// cf. MetadataDecoder<>.DecodeParameterOrThrow. private ParameterSignature DecodeParameter(ref BlobReader signatureReader) { bool isByRef = false; while (true) { var typeCode = signatureReader.ReadSignatureTypeCode(); switch (typeCode) { case SignatureTypeCode.RequiredModifier: case SignatureTypeCode.OptionalModifier: // Skip modifiers. break; case SignatureTypeCode.ByReference: isByRef = true; break; default: var type = DecodeType(ref signatureReader, typeCode); return new ParameterSignature(type, isByRef); } } }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception> /// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception> /// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { // Do not throw here when length is 0. We'll throw BadImageFormatException later on, so that the caller doesn't need to // worry about the image (stream) being empty and can handle all image errors by catching BadImageFormatException. if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(SR.MetadataStringDecoderEncodingMustBeUtf8, nameof(utf8Decoder)); } if (!BitConverter.IsLittleEndian) { Throw.LitteEndianArchitectureRequired(); } this.Block = new MemoryBlock(metadata, length); _options = options; this.UTF8Decoder = utf8Decoder; var headerReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref headerReader, out _versionString); _metadataKind = GetMetadataKind(_versionString); var streamHeaders = this.ReadStreamHeaders(ref headerReader); // storage header and stream headers: MemoryBlock metadataTableStream; MemoryBlock standalonePdbStream; this.InitializeStreamReaders(ref this.Block, streamHeaders, out _metadataStreamKind, out metadataTableStream, out standalonePdbStream); int[] externalTableRowCountsOpt; if (standalonePdbStream.Length > 0) { ReadStandalonePortablePdbStream(standalonePdbStream, out _debugMetadataHeader, out externalTableRowCountsOpt); } else { externalTableRowCountsOpt = null; } var tableReader = new BlobReader(metadataTableStream); HeapSizes heapSizes; int[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref tableReader, out heapSizes, out metadataTableRowCounts, out _sortedTables); this.InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (standalonePdbStream.Length == 0 && this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(SR.Format(SR.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.NamespaceCache = new NamespaceCache(this); if (_metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
/// <summary> /// Reads all Debug Directory table entries. /// </summary> /// <exception cref="BadImageFormatException">Bad format of the entry.</exception> /// <exception cref="IOException">IO error while reading from the underlying stream.</exception> public unsafe ImmutableArray<DebugDirectoryEntry> ReadDebugDirectory() { var debugDirectory = PEHeaders.PEHeader.DebugTableDirectory; if (debugDirectory.Size == 0) { return ImmutableArray<DebugDirectoryEntry>.Empty; } int position; if (!PEHeaders.TryGetDirectoryOffset(debugDirectory, out position)) { throw new BadImageFormatException(SR.InvalidDirectoryRVA); } if (debugDirectory.Size % DebugDirectoryEntry.Size != 0) { throw new BadImageFormatException(SR.InvalidDirectorySize); } using (AbstractMemoryBlock block = _peImage.GetMemoryBlock(position, debugDirectory.Size)) { var reader = new BlobReader(block.Pointer, block.Size); return ReadDebugDirectoryEntries(reader); } }
private static int[] ReadMetadataTableRowCounts(ref BlobReader memReader, ulong presentTableMask) { ulong currentTableBit = 1; var rowCounts = new int[MetadataTokens.TableCount]; for (int i = 0; i < rowCounts.Length; i++) { if ((presentTableMask & currentTableBit) != 0) { if (memReader.RemainingBytes < sizeof(uint)) { throw new BadImageFormatException(SR.TableRowCountSpaceTooSmall); } uint rowCount = memReader.ReadUInt32(); if (rowCount > TokenTypeIds.RIDMask) { throw new BadImageFormatException(SR.Format(SR.InvalidRowCount, rowCount)); } rowCounts[i] = (int)rowCount; } currentTableBit <<= 1; } return rowCounts; }
// internal for testing internal static void ReadStandalonePortablePdbStream(MemoryBlock block, out DebugMetadataHeader debugMetadataHeader, out int[] externalTableRowCounts) { var reader = new BlobReader(block); const int PdbIdSize = 20; byte[] pdbId = reader.ReadBytes(PdbIdSize); // ECMA-335 15.4.1.2: // The entry point to an application shall be static. // This entry point method can be a global method or it can appear inside a type. // The entry point method shall either accept no arguments or a vector of strings. // The return type of the entry point method shall be void, int32, or unsigned int32. // The entry point method cannot be defined in a generic class. uint entryPointToken = reader.ReadUInt32(); int entryPointRowId = (int)(entryPointToken & TokenTypeIds.RIDMask); if (entryPointToken != 0 && ((entryPointToken & TokenTypeIds.TypeMask) != TokenTypeIds.MethodDef || entryPointRowId == 0)) { throw new BadImageFormatException(string.Format(SR.InvalidEntryPointToken, entryPointToken)); } ulong externalTableMask = reader.ReadUInt64(); // EnC & Ptr tables can't be referenced from standalone PDB metadata: const ulong validTables = (ulong)TableMask.ValidPortablePdbExternalTables; if ((externalTableMask & ~validTables) != 0) { throw new BadImageFormatException(string.Format(SR.UnknownTables, (TableMask)externalTableMask)); } externalTableRowCounts = ReadMetadataTableRowCounts(ref reader, externalTableMask); debugMetadataHeader = new DebugMetadataHeader( ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref pdbId), MethodDefinitionHandle.FromRowId(entryPointRowId)); }
IAttribute ConvertMarshalInfo(SRM.BlobReader marshalInfo) { var b = new AttributeBuilder(module, KnownAttribute.MarshalAs); IType unmanagedTypeType = module.Compilation.FindType(new TopLevelTypeName(InteropServices, nameof(UnmanagedType))); int type = marshalInfo.ReadByte(); b.AddFixedArg(unmanagedTypeType, type); int size; switch (type) { case 0x1e: // FixedArray if (!marshalInfo.TryReadCompressedInteger(out size)) { size = 0; } b.AddNamedArg("SizeConst", KnownTypeCode.Int32, size); if (marshalInfo.RemainingBytes > 0) { type = marshalInfo.ReadByte(); if (type != 0x66) // None { b.AddNamedArg("ArraySubType", unmanagedTypeType, type); } } break; case 0x1d: // SafeArray if (marshalInfo.RemainingBytes > 0) { VarEnum varType = (VarEnum)marshalInfo.ReadByte(); if (varType != VarEnum.VT_EMPTY) { var varEnumType = new TopLevelTypeName(InteropServices, nameof(VarEnum)); b.AddNamedArg("SafeArraySubType", varEnumType, (int)varType); } } break; case 0x2a: // NATIVE_TYPE_ARRAY if (marshalInfo.RemainingBytes > 0) { type = marshalInfo.ReadByte(); } else { type = 0x66; // Cecil uses NativeType.None as default. } if (type != 0x50) // Max { b.AddNamedArg("ArraySubType", unmanagedTypeType, type); } int sizeParameterIndex = marshalInfo.TryReadCompressedInteger(out int value) ? value : -1; size = marshalInfo.TryReadCompressedInteger(out value) ? value : -1; int sizeParameterMultiplier = marshalInfo.TryReadCompressedInteger(out value) ? value : -1; if (size >= 0) { b.AddNamedArg("SizeConst", KnownTypeCode.Int32, size); } if (sizeParameterMultiplier != 0 && sizeParameterIndex >= 0) { b.AddNamedArg("SizeParamIndex", KnownTypeCode.Int16, (short)sizeParameterIndex); } break; case 0x2c: // CustomMarshaler string guidValue = marshalInfo.ReadSerializedString(); string unmanagedType = marshalInfo.ReadSerializedString(); string managedType = marshalInfo.ReadSerializedString(); string cookie = marshalInfo.ReadSerializedString(); if (managedType != null) { b.AddNamedArg("MarshalType", KnownTypeCode.String, managedType); } if (!string.IsNullOrEmpty(cookie)) { b.AddNamedArg("MarshalCookie", KnownTypeCode.String, cookie); } break; case 0x17: // FixedSysString b.AddNamedArg("SizeConst", KnownTypeCode.Int32, marshalInfo.ReadCompressedInteger()); break; } return(b.Build()); }
private MetadataRecord HandleConstant(Cts.Ecma.EcmaModule module, Ecma.ConstantHandle constantHandle) { Ecma.MetadataReader reader = module.MetadataReader; Ecma.Constant constant = reader.GetConstant(constantHandle); Ecma.BlobReader blob = reader.GetBlobReader(constant.Value); switch (constant.TypeCode) { case ConstantTypeCode.Boolean: return(new ConstantBooleanValue { Value = blob.ReadBoolean() }); case ConstantTypeCode.Byte: return(new ConstantByteValue { Value = blob.ReadByte() }); case ConstantTypeCode.Char: return(new ConstantCharValue { Value = blob.ReadChar() }); case ConstantTypeCode.Double: return(new ConstantDoubleValue { Value = blob.ReadDouble() }); case ConstantTypeCode.Int16: return(new ConstantInt16Value { Value = blob.ReadInt16() }); case ConstantTypeCode.Int32: return(new ConstantInt32Value { Value = blob.ReadInt32() }); case ConstantTypeCode.Int64: return(new ConstantInt64Value { Value = blob.ReadInt64() }); case ConstantTypeCode.SByte: return(new ConstantSByteValue { Value = blob.ReadSByte() }); case ConstantTypeCode.Single: return(new ConstantSingleValue { Value = blob.ReadSingle() }); case ConstantTypeCode.String: return(HandleString(blob.ReadUTF16(blob.Length))); case ConstantTypeCode.UInt16: return(new ConstantUInt16Value { Value = blob.ReadUInt16() }); case ConstantTypeCode.UInt32: return(new ConstantUInt32Value { Value = blob.ReadUInt32() }); case ConstantTypeCode.UInt64: return(new ConstantUInt64Value { Value = blob.ReadUInt64() }); case ConstantTypeCode.NullReference: return(new ConstantReferenceValue()); default: throw new BadImageFormatException(); } }
/// <summary> /// Looks like this function reads beginning of the header described in /// Ecma-335 24.2.1 Metadata root /// </summary> private void ReadMetadataHeader(ref BlobReader memReader) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) { throw new BadImageFormatException(MetadataResources.MetadataHeaderTooSmall); } this.metadataHeader.Signature = memReader.ReadUInt32(); if (this.metadataHeader.Signature != COR20Constants.COR20MetadataSignature) { throw new BadImageFormatException(MetadataResources.MetadataSignature); } this.metadataHeader.MajorVersion = memReader.ReadUInt16(); this.metadataHeader.MinorVersion = memReader.ReadUInt16(); this.metadataHeader.ExtraData = memReader.ReadUInt32(); this.metadataHeader.VersionStringSize = memReader.ReadInt32(); if (memReader.RemainingBytes < this.metadataHeader.VersionStringSize) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForVersionString); } int numberOfBytesRead; this.metadataHeader.VersionString = memReader.GetMemoryBlockAt(0, this.metadataHeader.VersionStringSize).PeekUtf8NullTerminated(0, null, utf8Decoder, out numberOfBytesRead, '\0'); memReader.SkipBytes(this.metadataHeader.VersionStringSize); this.metadataKind = GetMetadataKind(metadataHeader.VersionString); }
/// <summary> /// Reads stream headers described in Ecma-335 24.2.2 Stream header /// </summary> private StreamHeader[] ReadStreamHeaders(ref BlobReader memReader) { // storage header: memReader.ReadUInt16(); int streamCount = memReader.ReadInt16(); var streamHeaders = new StreamHeader[streamCount]; for (int i = 0; i < streamHeaders.Length; i++) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofStreamHeader) { throw new BadImageFormatException(MetadataResources.StreamHeaderTooSmall); } streamHeaders[i].Offset = memReader.ReadUInt32(); streamHeaders[i].Size = memReader.ReadInt32(); streamHeaders[i].Name = memReader.ReadUtf8NullTerminated(); bool aligned = memReader.TryAlign(4); if (!aligned || memReader.RemainingBytes == 0) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForStreamHeaderName); } } return streamHeaders; }
internal static ImmutableArray<DebugDirectoryEntry> ReadDebugDirectoryEntries(BlobReader reader) { int entryCount = reader.Length / DebugDirectoryEntry.Size; var builder = ImmutableArray.CreateBuilder<DebugDirectoryEntry>(entryCount); for (int i = 0; i < entryCount; i++) { // Reserved, must be zero. int characteristics = reader.ReadInt32(); if (characteristics != 0) { throw new BadImageFormatException(SR.InvalidDebugDirectoryEntryCharacteristics); } uint stamp = reader.ReadUInt32(); ushort majorVersion = reader.ReadUInt16(); ushort minorVersion = reader.ReadUInt16(); var type = (DebugDirectoryEntryType)reader.ReadInt32(); int dataSize = reader.ReadInt32(); int dataRva = reader.ReadInt32(); int dataPointer = reader.ReadInt32(); builder.Add(new DebugDirectoryEntry(stamp, majorVersion, minorVersion, type, dataSize, dataRva, dataPointer)); } return builder.MoveToImmutable(); }
private static ImmutableArray<ExceptionRegion> ReadFatExceptionHandlers(ref BlobReader memReader, int count) { var result = new ExceptionRegion[count]; for (int i = 0; i < result.Length; i++) { var sehFlags = (ExceptionRegionKind)memReader.ReadUInt32(); int tryOffset = memReader.ReadInt32(); int tryLength = memReader.ReadInt32(); int handlerOffset = memReader.ReadInt32(); int handlerLength = memReader.ReadInt32(); int classTokenOrFilterOffset = memReader.ReadInt32(); result[i] = new ExceptionRegion(sehFlags, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); } return ImmutableArray.Create(result); }
/// <summary> /// Reads all Debug Directory table entries. /// </summary> /// <exception cref="BadImageFormatException">Bad format of the entry.</exception> public unsafe ImmutableArray<DebugDirectoryEntry> ReadDebugDirectory() { var debugDirectory = PEHeaders.PEHeader.DebugTableDirectory; if (debugDirectory.Size == 0) { return ImmutableArray<DebugDirectoryEntry>.Empty; } int position; if (!PEHeaders.TryGetDirectoryOffset(debugDirectory, out position)) { throw new BadImageFormatException(SR.InvalidDirectoryRVA); } const int entrySize = 0x1c; if (debugDirectory.Size % entrySize != 0) { throw new BadImageFormatException(SR.InvalidDirectorySize); } using (AbstractMemoryBlock block = _peImage.GetMemoryBlock(position, debugDirectory.Size)) { var reader = new BlobReader(block.Pointer, block.Size); int entryCount = debugDirectory.Size / entrySize; var builder = ImmutableArray.CreateBuilder<DebugDirectoryEntry>(entryCount); for (int i = 0; i < entryCount; i++) { // Reserved, must be zero. int characteristics = reader.ReadInt32(); if (characteristics != 0) { throw new BadImageFormatException(SR.InvalidDebugDirectoryEntryCharacteristics); } uint stamp = reader.ReadUInt32(); ushort majorVersion = reader.ReadUInt16(); ushort minorVersion = reader.ReadUInt16(); var type = (DebugDirectoryEntryType)reader.ReadInt32(); int dataSize = reader.ReadInt32(); int dataRva = reader.ReadInt32(); int dataPointer = reader.ReadInt32(); builder.Add(new DebugDirectoryEntry(stamp, majorVersion, minorVersion, type, dataSize, dataRva, dataPointer)); } return builder.MoveToImmutable(); } }
public FieldSignature(BlobReader blobReader) { _reader = blobReader; }
public TypeSpecificationSignature(BlobReader blobReader) { _reader = blobReader; }
public static MethodBodyBlock Create(BlobReader reader) { int startOffset = reader.Offset; int ilSize; // Error need to check if the Memory Block is empty. This is calse for all the calls... byte headByte = reader.ReadByte(); if ((headByte & ILFormatMask) == ILTinyFormat) { // tiny IL can't have locals so technically this shouldn't matter, // but false is consistent with other metadata readers and helps // for use cases involving comparing our output with theirs. const bool initLocalsForTinyIL = false; ilSize = headByte >> ILTinyFormatSizeShift; return new MethodBodyBlock( initLocalsForTinyIL, 8, default(StandaloneSignatureHandle), reader.GetMemoryBlockAt(0, ilSize), ImmutableArray<ExceptionRegion>.Empty, 1 + ilSize // header + IL ); } if ((headByte & ILFormatMask) != ILFatFormat) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader1, headByte)); } // FatILFormat byte headByte2 = reader.ReadByte(); if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader2, headByte, headByte2)); } bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; ushort maxStack = reader.ReadUInt16(); ilSize = reader.ReadInt32(); int localSignatureToken = reader.ReadInt32(); StandaloneSignatureHandle localSignatureHandle; if (localSignatureToken == 0) { localSignatureHandle = default(StandaloneSignatureHandle); } else if ((localSignatureToken & TokenTypeIds.TokenTypeMask) == TokenTypeIds.Signature) { localSignatureHandle = StandaloneSignatureHandle.FromRowId((uint)localSignatureToken & TokenTypeIds.RIDMask); } else { throw new BadImageFormatException(string.Format(MetadataResources.InvalidLocalSignatureToken, unchecked((uint)localSignatureToken))); } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); reader.SkipBytes(ilSize); ImmutableArray<ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) { reader.Align(4); byte sehHeader = reader.ReadByte(); if ((sehHeader & SectEHTable) != SectEHTable) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidSehHeader, sehHeader)); } bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; int dataSize = reader.ReadByte(); if (sehFatFormat) { dataSize += reader.ReadUInt16() << 8; exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); } else { reader.SkipBytes(2); // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } else { exceptionHandlers = ImmutableArray<ExceptionRegion>.Empty; } return new MethodBodyBlock( localsInitialized, maxStack, localSignatureHandle, ilBlock, exceptionHandlers, reader.Offset - startOffset); }
private static ImmutableArray<ExceptionRegion> ReadSmallExceptionHandlers(ref BlobReader memReader, int count) { var result = new ExceptionRegion[count]; for (int i = 0; i < result.Length; i++) { var kind = (ExceptionRegionKind)memReader.ReadUInt16(); var tryOffset = memReader.ReadUInt16(); var tryLength = memReader.ReadByte(); var handlerOffset = memReader.ReadUInt16(); var handlerLength = memReader.ReadByte(); var classTokenOrFilterOffset = memReader.ReadInt32(); result[i] = new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); } return ImmutableArray.Create(result); }
/// <summary> /// Reads the data pointed to by the specified Debug Directory entry and interprets them as CodeView. /// </summary> /// <exception cref="ArgumentException"><paramref name="entry"/> is not a CodeView entry.</exception> /// <exception cref="BadImageFormatException">Bad format of the data.</exception> /// <exception cref="IOException">IO error while reading from the underlying stream.</exception> public unsafe CodeViewDebugDirectoryData ReadCodeViewDebugDirectoryData(DebugDirectoryEntry entry) { if (entry.Type != DebugDirectoryEntryType.CodeView) { throw new ArgumentException(SR.NotCodeViewEntry, nameof(entry)); } using (AbstractMemoryBlock block = _peImage.GetMemoryBlock(entry.DataPointer, entry.DataSize)) { var reader = new BlobReader(block.Pointer, block.Size); if (reader.ReadByte() != (byte)'R' || reader.ReadByte() != (byte)'S' || reader.ReadByte() != (byte)'D' || reader.ReadByte() != (byte)'S') { throw new BadImageFormatException(SR.UnexpectedCodeViewDataSignature); } Guid guid = reader.ReadGuid(); int age = reader.ReadInt32(); string path = reader.ReadUtf8NullTerminated(); // path may be padded with NULs while (reader.RemainingBytes > 0) { if (reader.ReadByte() != 0) { throw new BadImageFormatException(SR.InvalidPathPadding); } } return new CodeViewDebugDirectoryData(guid, age, path); } }
public static MethodBodyBlock Create(BlobReader reader) { int startOffset = reader.Offset; int ilSize; // Error need to check if the Memory Block is empty. This is false for all the calls... byte headByte = reader.ReadByte(); if ((headByte & ILFormatMask) == ILTinyFormat) { // tiny IL can't have locals so technically this shouldn't matter, // but false is consistent with other metadata readers and helps // for use cases involving comparing our output with theirs. const bool initLocalsForTinyIL = false; ilSize = headByte >> ILTinyFormatSizeShift; return(new MethodBodyBlock( initLocalsForTinyIL, 8, default(StandaloneSignatureHandle), reader.GetMemoryBlockAt(0, ilSize), ImmutableArray <ExceptionRegion> .Empty, 1 + ilSize // header + IL )); } if ((headByte & ILFormatMask) != ILFatFormat) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader1, headByte)); } // FatILFormat byte headByte2 = reader.ReadByte(); if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader2, headByte, headByte2)); } bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; ushort maxStack = reader.ReadUInt16(); ilSize = reader.ReadInt32(); int localSignatureToken = reader.ReadInt32(); StandaloneSignatureHandle localSignatureHandle; if (localSignatureToken == 0) { localSignatureHandle = default(StandaloneSignatureHandle); } else if ((localSignatureToken & TokenTypeIds.TypeMask) == TokenTypeIds.Signature) { localSignatureHandle = StandaloneSignatureHandle.FromRowId((int)((uint)localSignatureToken & TokenTypeIds.RIDMask)); } else { throw new BadImageFormatException(SR.Format(SR.InvalidLocalSignatureToken, unchecked ((uint)localSignatureToken))); } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); reader.Offset += ilSize; ImmutableArray <ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) { reader.Align(4); byte sehHeader = reader.ReadByte(); if ((sehHeader & SectEHTable) != SectEHTable) { throw new BadImageFormatException(SR.Format(SR.InvalidSehHeader, sehHeader)); } bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; int dataSize = reader.ReadByte(); if (sehFatFormat) { dataSize += reader.ReadUInt16() << 8; exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); } else { reader.Offset += 2; // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } else { exceptionHandlers = ImmutableArray <ExceptionRegion> .Empty; } return(new MethodBodyBlock( localsInitialized, maxStack, localSignatureHandle, ilBlock, exceptionHandlers, reader.Offset - startOffset)); }
private Property HandleProperty(Cts.Ecma.EcmaModule module, Ecma.PropertyDefinitionHandle property) { Ecma.MetadataReader reader = module.MetadataReader; Ecma.PropertyDefinition propDef = reader.GetPropertyDefinition(property); Ecma.PropertyAccessors acc = propDef.GetAccessors(); Cts.MethodDesc getterMethod = acc.Getter.IsNil ? null : module.GetMethod(acc.Getter); Cts.MethodDesc setterMethod = acc.Setter.IsNil ? null : module.GetMethod(acc.Setter); bool getterHasMetadata = getterMethod != null && _policy.GeneratesMetadata(getterMethod); bool setterHasMetadata = setterMethod != null && _policy.GeneratesMetadata(setterMethod); // Policy: If neither the getter nor setter have metadata, property doesn't have metadata if (!getterHasMetadata && !setterHasMetadata) { return(null); } Ecma.BlobReader sigBlobReader = reader.GetBlobReader(propDef.Signature); Cts.PropertySignature sig = new Cts.Ecma.EcmaSignatureParser(module, sigBlobReader, Cts.NotFoundBehavior.Throw).ParsePropertySignature(); Property result = new Property { Name = HandleString(reader.GetString(propDef.Name)), Flags = propDef.Attributes, Signature = new PropertySignature { CallingConvention = sig.IsStatic ? CallingConventions.Standard : CallingConventions.HasThis, Type = HandleType(sig.ReturnType) }, }; result.Signature.Parameters.Capacity = sig.Length; for (int i = 0; i < sig.Length; i++) { result.Signature.Parameters.Add(HandleType(sig[i])); } if (getterHasMetadata) { result.MethodSemantics.Add(new MethodSemantics { Attributes = MethodSemanticsAttributes.Getter, Method = HandleMethodDefinition(getterMethod), }); } if (setterHasMetadata) { result.MethodSemantics.Add(new MethodSemantics { Attributes = MethodSemanticsAttributes.Setter, Method = HandleMethodDefinition(setterMethod), }); } Ecma.ConstantHandle defaultValue = propDef.GetDefaultValue(); if (!defaultValue.IsNil) { result.DefaultValue = HandleConstant(module, defaultValue); } Ecma.CustomAttributeHandleCollection customAttributes = propDef.GetCustomAttributes(); if (customAttributes.Count > 0) { result.CustomAttributes = HandleCustomAttributes(module, customAttributes); } return(result); }
private unsafe static void UncompressLambdaMap( ImmutableArray<byte> compressedLambdaMap, out int methodOrdinal, out ImmutableArray<ClosureDebugInfo> closures, out ImmutableArray<LambdaDebugInfo> lambdas) { methodOrdinal = DebugId.UndefinedOrdinal; closures = default(ImmutableArray<ClosureDebugInfo>); lambdas = default(ImmutableArray<LambdaDebugInfo>); if (compressedLambdaMap.IsDefaultOrEmpty) { return; } var closuresBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance(); var lambdasBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance(); fixed (byte* blobPtr = &compressedLambdaMap.ToArray()[0]) { var blobReader = new BlobReader(blobPtr, compressedLambdaMap.Length); try { // Note: integer operations below can't overflow since compressed integers are in range [0, 0x20000000) // [-1, inf) methodOrdinal = blobReader.ReadCompressedInteger() - 1; int syntaxOffsetBaseline = -blobReader.ReadCompressedInteger(); int closureCount = blobReader.ReadCompressedInteger(); for (int i = 0; i < closureCount; i++) { int syntaxOffset = blobReader.ReadCompressedInteger(); var closureId = new DebugId(closuresBuilder.Count, generation: 0); closuresBuilder.Add(new ClosureDebugInfo(syntaxOffset + syntaxOffsetBaseline, closureId)); } while (blobReader.RemainingBytes > 0) { int syntaxOffset = blobReader.ReadCompressedInteger(); int closureOrdinal = blobReader.ReadCompressedInteger() + LambdaDebugInfo.MinClosureOrdinal; if (closureOrdinal >= closureCount) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } var lambdaId = new DebugId(lambdasBuilder.Count, generation: 0); lambdasBuilder.Add(new LambdaDebugInfo(syntaxOffset + syntaxOffsetBaseline, lambdaId, closureOrdinal)); } } catch (BadImageFormatException) { throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset); } } closures = closuresBuilder.ToImmutableAndFree(); lambdas = lambdasBuilder.ToImmutableAndFree(); }
private void ReadMetadataTableHeader(ref BlobReader memReader, out uint[] metadataTableRowCounts) { if (memReader.RemainingBytes < MetadataStreamConstants.SizeOfMetadataTableHeader) { throw new BadImageFormatException(MetadataResources.MetadataTableHeaderTooSmall); } this.MetadataTableHeader.Reserved = memReader.ReadUInt32(); this.MetadataTableHeader.MajorVersion = memReader.ReadByte(); this.MetadataTableHeader.MinorVersion = memReader.ReadByte(); this.MetadataTableHeader.HeapSizeFlags = (HeapSizeFlag)memReader.ReadByte(); this.MetadataTableHeader.RowId = memReader.ReadByte(); this.MetadataTableHeader.ValidTables = (TableMask)memReader.ReadUInt64(); this.MetadataTableHeader.SortedTables = (TableMask)memReader.ReadUInt64(); ulong presentTables = (ulong)this.MetadataTableHeader.ValidTables; // According to ECMA-335, MajorVersion and MinorVersion have fixed values and, // based on recommendation in 24.1 Fixed fields: When writing these fields it // is best that they be set to the value indicated, on reading they should be ignored.? // we will not be checking version values. We will continue checking that the set of // present tables is within the set we understand. ulong validTables = (ulong)TableMask.V2_0_TablesMask; if ((presentTables & ~validTables) != 0) { throw new BadImageFormatException(string.Format(MetadataResources.UnknownTables, presentTables)); } if (this.metadataStreamKind == MetadataStreamKind.Compressed) { // In general Ptr tables and EnC tables are not allowed in a compressed stream. // However when asked for a snapshot of the current metadata after an EnC change has been applied // the CLR includes the EnCLog table into the snapshot. We need to be able to read the image, // so we'll allow the table here but pretend it's empty later. if ((presentTables & (ulong)(TableMask.PtrTables | TableMask.EnCMap)) != 0) { throw new BadImageFormatException(MetadataResources.IllegalTablesInCompressedMetadataStream); } } int numberOfTables = this.MetadataTableHeader.GetNumberOfTablesPresent(); if (memReader.RemainingBytes < numberOfTables * sizeof(int)) { throw new BadImageFormatException(MetadataResources.TableRowCountSpaceTooSmall); } var rowCounts = new uint[numberOfTables]; for (int i = 0; i < rowCounts.Length; i++) { rowCounts[i] = memReader.ReadUInt32(); } metadataTableRowCounts = rowCounts; }
private Property HandleProperty(Cts.Ecma.EcmaModule module, Ecma.PropertyDefinitionHandle property) { Ecma.MetadataReader reader = module.MetadataReader; Ecma.PropertyDefinition propDef = reader.GetPropertyDefinition(property); Ecma.PropertyAccessors acc = propDef.GetAccessors(); Cts.MethodDesc getterMethod = acc.Getter.IsNil ? null : module.GetMethod(acc.Getter); Cts.MethodDesc setterMethod = acc.Setter.IsNil ? null : module.GetMethod(acc.Setter); bool getterHasMetadata = getterMethod != null && _policy.GeneratesMetadata(getterMethod); bool setterHasMetadata = setterMethod != null && _policy.GeneratesMetadata(setterMethod); // Policy: If neither the getter nor setter have metadata, property doesn't have metadata if (!getterHasMetadata && !setterHasMetadata) { return(null); } Ecma.BlobReader sigBlobReader = reader.GetBlobReader(propDef.Signature); Cts.PropertySignature sig = new Cts.Ecma.EcmaSignatureParser(module, sigBlobReader).ParsePropertySignature(); List <ParameterTypeSignature> parameters; if (sig.Length == 0) { parameters = null; } else { parameters = new List <ParameterTypeSignature>(sig.Length); for (int i = 0; i < parameters.Count; i++) { parameters.Add(HandleParameterTypeSignature(sig[i])); } } Property result = new Property { Name = HandleString(reader.GetString(propDef.Name)), Flags = propDef.Attributes, Signature = new PropertySignature { CallingConvention = sig.IsStatic ? CallingConventions.Standard : CallingConventions.HasThis, // TODO: CustomModifiers Type = HandleType(sig.ReturnType), Parameters = parameters, }, }; if (getterHasMetadata) { result.MethodSemantics.Add(new MethodSemantics { Attributes = MethodSemanticsAttributes.Getter, Method = HandleMethodDefinition(getterMethod), }); } if (setterHasMetadata) { result.MethodSemantics.Add(new MethodSemantics { Attributes = MethodSemanticsAttributes.Setter, Method = HandleMethodDefinition(setterMethod), }); } // TODO: DefaultValue // TODO: CustomAttributes return(result); }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { if (length <= 0) { throw new ArgumentOutOfRangeException("length"); } if (metadata == null) { throw new ArgumentNullException("metadata"); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(MetadataResources.MetadataStringDecoderEncodingMustBeUtf8, "utf8Decoder"); } if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); } this.Block = new MemoryBlock(metadata, length); this.options = options; this.utf8Decoder = utf8Decoder; BlobReader memReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref memReader); // storage header and stream headers: MemoryBlock metadataTableStream; var streamHeaders = this.ReadStreamHeaders(ref memReader); this.InitializeStreamReaders(ref this.Block, streamHeaders, out metadataTableStream); memReader = new BlobReader(metadataTableStream); uint[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref memReader, out metadataTableRowCounts); this.InitializeTableReaders(memReader.GetMemoryBlockAt(0, memReader.RemainingBytes), metadataTableRowCounts); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(string.Format(MetadataResources.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.namespaceCache = new NamespaceCache(this); if (this.metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
/// <summary> /// Looks like this function reads beginning of the header described in /// ECMA-335 24.2.1 Metadata root /// </summary> private void ReadMetadataHeader(ref BlobReader memReader, out string versionString) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) { throw new BadImageFormatException(SR.MetadataHeaderTooSmall); } uint signature = memReader.ReadUInt32(); if (signature != COR20Constants.COR20MetadataSignature) { throw new BadImageFormatException(SR.MetadataSignature); } // major version memReader.ReadUInt16(); // minor version memReader.ReadUInt16(); // reserved: memReader.ReadUInt32(); int versionStringSize = memReader.ReadInt32(); if (memReader.RemainingBytes < versionStringSize) { throw new BadImageFormatException(SR.NotEnoughSpaceForVersionString); } int numberOfBytesRead; versionString = memReader.GetMemoryBlockAt(0, versionStringSize).PeekUtf8NullTerminated(0, null, UTF8Decoder, out numberOfBytesRead, '\0'); memReader.SkipBytes(versionStringSize); }
private object ReadAndTranslateValue(ref BlobReader sigReader, SignatureTypeCode typeCode, out bool isEnumTypeCode) { switch (typeCode) { case SignatureTypeCode.Boolean: isEnumTypeCode = true; return (short)(sigReader.ReadBoolean() ? 1 : 0); case SignatureTypeCode.Char: isEnumTypeCode = true; return (ushort)sigReader.ReadChar(); case SignatureTypeCode.SByte: isEnumTypeCode = true; return (short)sigReader.ReadSByte(); case SignatureTypeCode.Byte: isEnumTypeCode = true; return (short)sigReader.ReadByte(); case SignatureTypeCode.Int16: isEnumTypeCode = true; return sigReader.ReadInt16(); case SignatureTypeCode.UInt16: isEnumTypeCode = true; return sigReader.ReadUInt16(); case SignatureTypeCode.Int32: isEnumTypeCode = true; return sigReader.ReadInt32(); case SignatureTypeCode.UInt32: isEnumTypeCode = true; return sigReader.ReadUInt32(); case SignatureTypeCode.Int64: isEnumTypeCode = true; return sigReader.ReadInt64(); case SignatureTypeCode.UInt64: isEnumTypeCode = true; return sigReader.ReadUInt64(); case SignatureTypeCode.Single: isEnumTypeCode = false; return sigReader.ReadSingle(); case SignatureTypeCode.Double: isEnumTypeCode = false; return sigReader.ReadDouble(); case SignatureTypeCode.String: isEnumTypeCode = false; if (sigReader.RemainingBytes == 1) { if (sigReader.ReadByte() != 0xff) { throw new BadImageFormatException(); } return NullReferenceValue; } if (sigReader.RemainingBytes % 2 != 0) { throw new BadImageFormatException(); } return sigReader.ReadUTF16(sigReader.RemainingBytes); case SignatureTypeCode.Object: // null reference isEnumTypeCode = false; return NullReferenceValue; default: throw new BadImageFormatException(); } }
private void ReadMetadataTableHeader(ref BlobReader reader, out HeapSizes heapSizes, out int[] metadataTableRowCounts, out TableMask sortedTables) { if (reader.RemainingBytes < MetadataStreamConstants.SizeOfMetadataTableHeader) { throw new BadImageFormatException(SR.MetadataTableHeaderTooSmall); } // reserved (shall be ignored): reader.ReadUInt32(); // major version (shall be ignored): reader.ReadByte(); // minor version (shall be ignored): reader.ReadByte(); // heap sizes: heapSizes = (HeapSizes)reader.ReadByte(); // reserved (shall be ignored): reader.ReadByte(); ulong presentTables = reader.ReadUInt64(); sortedTables = (TableMask)reader.ReadUInt64(); // According to ECMA-335, MajorVersion and MinorVersion have fixed values and, // based on recommendation in 24.1 Fixed fields: When writing these fields it // is best that they be set to the value indicated, on reading they should be ignored. // We will not be checking version values. We will continue checking that the set of // present tables is within the set we understand. ulong validTables = (ulong)(TableMask.TypeSystemTables | TableMask.DebugTables); if ((presentTables & ~validTables) != 0) { throw new BadImageFormatException(SR.Format(SR.UnknownTables, presentTables)); } if (_metadataStreamKind == MetadataStreamKind.Compressed) { // In general Ptr tables and EnC tables are not allowed in a compressed stream. // However when asked for a snapshot of the current metadata after an EnC change has been applied // the CLR includes the EnCLog table into the snapshot. We need to be able to read the image, // so we'll allow the table here but pretend it's empty later. if ((presentTables & (ulong)(TableMask.PtrTables | TableMask.EnCMap)) != 0) { throw new BadImageFormatException(SR.IllegalTablesInCompressedMetadataStream); } } metadataTableRowCounts = ReadMetadataTableRowCounts(ref reader, presentTables); if ((heapSizes & HeapSizes.ExtraData) == HeapSizes.ExtraData) { // Skip "extra data" used by some obfuscators. Although it is not mentioned in the CLI spec, // it is honored by the native metadata reader. reader.ReadUInt32(); } }