private void ReadMetadataTableHeader(ref BlobReader reader, out HeapSizes heapSizes, out int[] metadataTableRowCounts, out TableMask sortedTables) { if (reader.RemainingBytes < MetadataStreamConstants.SizeOfMetadataTableHeader) { throw new BadImageFormatException("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("UnknownTables"); } 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("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(); } }
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)); }
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() }; }
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(); }
/// <summary> /// We want to know if a given method implements a redirected interface. /// For example, if we are given the method RemoveAt on a class "A" /// which implements the IVector interface (which is redirected /// to IList in .NET) then this method would return true. The most /// likely reason why we would want to know this is that we wish to hide /// (mark private) all methods which implement methods on a redirected /// interface. /// </summary> /// <param name="memberRef">The declaration token for the method</param> /// <param name="isIDisposable"> /// Returns true if the redirected interface is <see cref="IDisposable"/>. /// </param> /// <returns>True if the method implements a method on a redirected interface. /// False otherwise.</returns> private bool ImplementsRedirectedInterface(MemberReferenceHandle memberRef, out bool isIDisposable) { isIDisposable = false; EntityHandle parent = MemberRefTable.GetClass(memberRef); TypeReferenceHandle typeRef; if (parent.Kind == HandleKind.TypeReference) { typeRef = (TypeReferenceHandle)parent; } else if (parent.Kind == HandleKind.TypeSpecification) { BlobHandle blob = TypeSpecTable.GetSignature((TypeSpecificationHandle)parent); BlobReader sig = new BlobReader(BlobStream.GetMemoryBlock(blob)); if (sig.Length < 2 || sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_GENERICINST || sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_CLASS) { return(false); } EntityHandle token = sig.ReadTypeHandle(); if (token.Kind != HandleKind.TypeReference) { return(false); } typeRef = (TypeReferenceHandle)token; } else { return(false); } return(GetProjectionIndexForTypeReference(typeRef, out isIDisposable) >= 0); }
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); }
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 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; }
/// <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); } }
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(); } }
/// <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(); }
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 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); }
public DynamicAnalysisDataReader(byte* buffer, int size) { var reader = new BlobReader(buffer, size); // header: if (reader.ReadByte() != 'D' || reader.ReadByte() != 'A' || reader.ReadByte() != 'M' || reader.ReadByte() != 'D') { throw new BadImageFormatException(); } // version byte major = reader.ReadByte(); byte minor = reader.ReadByte(); if (major != 0 || minor < 1 || minor > 2) { throw new NotSupportedException(); } // table sizes: int documentRowCount = reader.ReadInt32(); int methodSpanRowCount = reader.ReadInt32(); // blob heap sizes: int stringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int userStringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int guidHeapSize = reader.ReadInt32(); int blobHeapSize = reader.ReadInt32(); // TODO: check size ranges bool isBlobHeapSmall = blobHeapSize <= ushort.MaxValue; bool isGuidHeapSmall = guidHeapSize / GuidSize <= ushort.MaxValue; var documentsBuilder = ArrayBuilder<DynamicAnalysisDocument>.GetInstance(documentRowCount); for (int i = 0; i < documentRowCount; i++) { var name = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); var hashAlgorithm = MetadataTokens.GuidHandle(ReadReference(ref reader, isGuidHeapSmall)); var hash = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); documentsBuilder.Add(new DynamicAnalysisDocument(name, hashAlgorithm, hash)); } Documents = documentsBuilder.ToImmutableAndFree(); var methodsBuilder = ArrayBuilder<DynamicAnalysisMethod>.GetInstance(methodSpanRowCount); for (int i = 0; i < methodSpanRowCount; i++) { methodsBuilder.Add(new DynamicAnalysisMethod(MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)))); } Methods = methodsBuilder.ToImmutableAndFree(); int stringHeapOffset = reader.Offset; int userStringHeapOffset = stringHeapOffset + stringHeapSize; int guidHeapOffset = userStringHeapOffset + userStringHeapSize; int blobHeapOffset = guidHeapOffset + guidHeapSize; if (reader.Length != blobHeapOffset + blobHeapSize) { throw new BadImageFormatException(); } _guidHeapBlob = new Blob(buffer + guidHeapOffset, guidHeapSize); _blobHeapBlob = new Blob(buffer + blobHeapOffset, blobHeapSize); }
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> /// We want to know if a given method implements a redirected interface. /// For example, if we are given the method RemoveAt on a class "A" /// which implements the IVector interface (which is redirected /// to IList in .NET) then this method would return true. The most /// likely reason why we would want to know this is that we wish to hide /// (mark private) all methods which implement methods on a redirected /// interface. /// </summary> /// <param name="memberRef">The declaration token for the method</param> /// <param name="isIDisposable"> /// Returns true if the redirected interface is <see cref="IDisposable"/>. /// </param> /// <returns>True if the method implements a method on a redirected interface. /// False otherwise.</returns> private bool ImplementsRedirectedInterface(MemberReferenceHandle memberRef, out bool isIDisposable) { isIDisposable = false; EntityHandle parent = MemberRefTable.GetClass(memberRef); TypeReferenceHandle typeRef; if (parent.Kind == HandleKind.TypeReference) { typeRef = (TypeReferenceHandle)parent; } else if (parent.Kind == HandleKind.TypeSpecification) { BlobHandle blob = TypeSpecTable.GetSignature((TypeSpecificationHandle)parent); BlobReader sig = new BlobReader(BlobHeap.GetMemoryBlock(blob)); if (sig.Length < 2 || sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_GENERICINST || sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_CLASS) { return false; } EntityHandle token = sig.ReadTypeHandle(); if (token.Kind != HandleKind.TypeReference) { return false; } typeRef = (TypeReferenceHandle)token; } else { return false; } return GetProjectionIndexForTypeReference(typeRef, out isIDisposable) >= 0; }
private unsafe void WriteEditAndContinueLocalSlotMap(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.EditAndContinueLocalSlotMap); _writer.WriteStartElement("encLocalSlotMap"); try { int syntaxOffsetBaseline = -1; fixed (byte* compressedSlotMapPtr = &record.Data.ToArray()[0]) { var blobReader = new BlobReader(compressedSlotMapPtr, record.Data.Length); while (blobReader.RemainingBytes > 0) { byte b = blobReader.ReadByte(); if (b == 0xff) { if (!blobReader.TryReadCompressedInteger(out syntaxOffsetBaseline)) { _writer.WriteElementString("baseline", "?"); return; } syntaxOffsetBaseline = -syntaxOffsetBaseline; continue; } _writer.WriteStartElement("slot"); if (b == 0) { // short-lived temp, no info _writer.WriteAttributeString("kind", "temp"); } else { int synthesizedKind = (b & 0x3f) - 1; bool hasOrdinal = (b & (1 << 7)) != 0; int syntaxOffset; bool badSyntaxOffset = !blobReader.TryReadCompressedInteger(out syntaxOffset); syntaxOffset += syntaxOffsetBaseline; int ordinal = 0; bool badOrdinal = hasOrdinal && !blobReader.TryReadCompressedInteger(out ordinal); _writer.WriteAttributeString("kind", CultureInvariantToString(synthesizedKind)); _writer.WriteAttributeString("offset", badSyntaxOffset ? "?" : CultureInvariantToString(syntaxOffset)); if (badOrdinal || hasOrdinal) { _writer.WriteAttributeString("ordinal", badOrdinal ? "?" : CultureInvariantToString(ordinal)); } } _writer.WriteEndElement(); } } } finally { _writer.WriteEndElement(); //encLocalSlotMap } }
/// <exception cref="BadImageFormatException">Invalid blob format.</exception> public bool MoveNext() { if (_reader.RemainingBytes == 0) { return(false); } var kind = (ImportDefinitionKind)_reader.ReadByte(); switch (kind) { case ImportDefinitionKind.ImportType: _current = new ImportDefinition( kind, typeOrNamespace: _reader.ReadTypeHandle()); break; case ImportDefinitionKind.ImportNamespace: _current = new ImportDefinition( kind, typeOrNamespace: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger())); break; case ImportDefinitionKind.ImportAssemblyNamespace: _current = new ImportDefinition( kind, assembly: MetadataTokens.AssemblyReferenceHandle(_reader.ReadCompressedInteger()), typeOrNamespace: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger())); break; case ImportDefinitionKind.ImportAssemblyReferenceAlias: _current = new ImportDefinition( kind, alias: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger())); break; case ImportDefinitionKind.AliasAssemblyReference: _current = new ImportDefinition( kind, alias: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger()), assembly: MetadataTokens.AssemblyReferenceHandle(_reader.ReadCompressedInteger())); break; case ImportDefinitionKind.AliasType: _current = new ImportDefinition( kind, alias: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger()), typeOrNamespace: _reader.ReadTypeHandle()); break; case ImportDefinitionKind.ImportXmlNamespace: case ImportDefinitionKind.AliasNamespace: _current = new ImportDefinition( kind, alias: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger()), typeOrNamespace: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger())); break; case ImportDefinitionKind.AliasAssemblyNamespace: _current = new ImportDefinition( kind, alias: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger()), assembly: MetadataTokens.AssemblyReferenceHandle(_reader.ReadCompressedInteger()), typeOrNamespace: MetadataTokens.BlobHandle(_reader.ReadCompressedInteger())); break; default: throw new BadImageFormatException(SR.Format(SR.InvalidImportDefinitionKind, kind)); } return(true); }
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(); } }