internal PEMemoryBlock(AbstractMemoryBlock block, int offset = 0)
        {
            Debug.Assert(block != null);
            Debug.Assert(offset >= 0 && offset <= block.Size);

            _block = block;
            _offset = offset;
        }
Beispiel #2
0
        internal PEMemoryBlock(AbstractMemoryBlock block, int offset = 0)
        {
            DebugCorlib.Assert(block != null);
            DebugCorlib.Assert(offset >= 0 && offset < block.Size);

            this.block = block;
            this.offset = offset;
        }
Beispiel #3
0
        /// <summary>
        /// Disposes all memory allocated by the reader.
        /// </summary>
        /// <remarks>
        /// <see cref="Dispose"/>  can be called multiple times (but not in parallel).
        /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="PEReader"/>
        /// or reading from <see cref="PEMemoryBlock"/>s retrieved from the reader.
        /// </remarks>
        public void Dispose()
        {
            _peImage?.Dispose();
            _peImage = null;

            _lazyImageBlock?.Dispose();
            _lazyImageBlock = null;

            _lazyMetadataBlock?.Dispose();
            _lazyMetadataBlock = null;

            var peSectionBlocks = _lazyPESectionBlocks;
            if (peSectionBlocks != null)
            {
                foreach (var block in peSectionBlocks)
                {
                    block?.Dispose();
                }

                _lazyPESectionBlocks = null;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Creates a Portable Executable reader over a PE image of the given size beginning at the stream's current position.
        /// </summary>
        /// <param name="peStream">PE image stream.</param>
        /// <param name="size">PE image size.</param>
        /// <param name="options">
        /// Options specifying how sections of the PE image are read from the stream.
        /// 
        /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> 
        /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it.
        /// 
        /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data 
        /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated
        /// by caller while the <see cref="PEReader"/> is alive and undisposed.
        /// 
        /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> 
        /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also
        /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/>
        /// after construction.
        /// </param>
        /// <exception cref="ArgumentOutOfRangeException">Size is negative or extends past the end of the stream.</exception>
        /// <exception cref="IOException">Error reading from the stream (only when prefetching data).</exception>
        public unsafe PEReader(Stream peStream, PEStreamOptions options, int size)
        {
            if (peStream == null)
            {
                throw new ArgumentNullException(nameof(peStream));
            }

            if (!peStream.CanRead || !peStream.CanSeek)
            {
                throw new ArgumentException(SR.StreamMustSupportReadAndSeek, nameof(peStream));
            }

            if (!options.IsValid())
            {
                throw new ArgumentOutOfRangeException(nameof(options));
            }

            long start = peStream.Position;
            int actualSize = StreamExtensions.GetAndValidateSize(peStream, size, nameof(peStream));

            bool closeStream = true;
            try
            {
                bool isFileStream = FileStreamReadLightUp.IsFileStream(peStream);

                if ((options & (PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) == 0)
                {
                    _peImage = new StreamMemoryBlockProvider(peStream, start, actualSize, isFileStream, (options & PEStreamOptions.LeaveOpen) != 0);
                    closeStream = false;
                }
                else
                {
                    // Read in the entire image or metadata blob:
                    if ((options & PEStreamOptions.PrefetchEntireImage) != 0)
                    {
                        var imageBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, start, actualSize);
                        _lazyImageBlock = imageBlock;
                        _peImage = new ExternalMemoryBlockProvider(imageBlock.Pointer, imageBlock.Size);

                        // if the caller asked for metadata initialize the PE headers (calculates metadata offset):
                        if ((options & PEStreamOptions.PrefetchMetadata) != 0)
                        {
                            InitializePEHeaders();
                        }
                    }
                    else
                    {
                        // The peImage is left null, but the lazyMetadataBlock is initialized up front.
                        _lazyPEHeaders = new PEHeaders(peStream);
                        _lazyMetadataBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, _lazyPEHeaders.MetadataStartOffset, _lazyPEHeaders.MetadataSize);
                    }
                    // We read all we need, the stream is going to be closed.
                }
            }
            finally
            {
                if (closeStream && (options & PEStreamOptions.LeaveOpen) == 0)
                {
                    peStream.Dispose();
                }
            }
        }
 private MetadataReaderProvider(AbstractMemoryBlock metadataBlock)
 {
     Debug.Assert(metadataBlock != null);
     _lazyMetadataBlock = metadataBlock;
 }
        /// <summary>
        /// Disposes all memory allocated by the reader.
        /// </summary>
        /// <remarks>
        /// <see cref="Dispose"/>  can be called multiple times (but not in parallel).
        /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="MetadataReaderProvider"/>
        /// or reading from the underlying memory.
        /// </remarks>
        public void Dispose()
        {
            _blockProviderOpt?.Dispose();
            _blockProviderOpt = null;

            _lazyMetadataBlock?.Dispose();
            _lazyMetadataBlock = null;
        }
Beispiel #7
0
        /// <summary>
        /// Disposes all memory allocated by the reader.
        /// </summary>
        /// <remarks>
        /// <see cref="Dispose"/>  can be called multiple times (but not in parallel).
        /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="PEReader"/>
        /// or reading from <see cref="PEMemoryBlock"/>s retrieved from the reader.
        /// </remarks>
        public void Dispose()
        {
            var image = _peImage;
            if (image != null)
            {
                image.Dispose();
                _peImage = null;
            }

            var imageBlock = _lazyImageBlock;
            if (imageBlock != null)
            {
                imageBlock.Dispose();
                _lazyImageBlock = null;
            }

            var metadataBlock = _lazyMetadataBlock;
            if (metadataBlock != null)
            {
                metadataBlock.Dispose();
                _lazyMetadataBlock = null;
            }

            var peSectionBlocks = _lazyPESectionBlocks;
            if (peSectionBlocks != null)
            {
                foreach (var block in peSectionBlocks)
                {
                    if (block != null)
                    {
                        block.Dispose();
                    }
                }

                _lazyPESectionBlocks = null;
            }
        }
Beispiel #8
0
        // internal for testing
        internal static unsafe ImmutableArray<byte> DecodeEmbeddedPortablePdbDebugDirectoryData(AbstractMemoryBlock block)
        {
            byte[] decompressed;
            
            const int headerSize = 2 * sizeof(int);

            var headerReader = new BlobReader(block.Pointer, headerSize);

            if (headerReader.ReadUInt32() != PortablePdbVersions.DebugDirectoryEmbeddedSignature)
            {
                throw new BadImageFormatException(SR.UnexpectedEmbeddedPortablePdbDataSignature);
            }

            int decompressedSize = headerReader.ReadInt32();

            try
            {
                decompressed = new byte[decompressedSize];
            }
            catch
            {
                throw new BadImageFormatException(SR.DataTooBig);
            }

            var compressed = new ReadOnlyUnmanagedMemoryStream(block.Pointer + headerSize, block.Size - headerSize);
            var deflate = new DeflateStream(compressed, CompressionMode.Decompress, leaveOpen: true);

            if (decompressedSize > 0)
            {
                int actualLength;

                try
                {
                    actualLength = deflate.TryReadAll(decompressed, 0, decompressed.Length);
                }
                catch (InvalidDataException e)
                {
                    throw new BadImageFormatException(e.Message, e.InnerException);
                }

                if (actualLength != decompressed.Length)
                {
                    throw new BadImageFormatException(SR.SizeMismatch);
                }
            }

            // Check that there is no more compressed data left, 
            // in case the decompressed size specified in the header is smaller 
            // than the actual decompressed size of the data.
            if (deflate.ReadByte() != -1)
            {
                throw new BadImageFormatException(SR.SizeMismatch);
            }

            return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref decompressed);
        }