private PEImage()

in src/Microsoft.Diagnostics.Runtime/Utilities/PEImage/PEImage.cs [77:183]


        private PEImage(Stream stream, bool leaveOpen, bool isVirtual, ulong loadedImageBase)
        {
            _isVirtual = isVirtual;
            _stream = stream ?? throw new ArgumentNullException(nameof(stream));
            _leaveOpen = leaveOpen;

            if (!stream.CanSeek)
                throw new ArgumentException($"{nameof(stream)} is not seekable.");

            ushort dosHeaderMagic = Read<ushort>(0);
            if (dosHeaderMagic != ExpectedDosHeaderMagic)
            {
                IsValid = false;
                return;
            }

            _peHeaderOffset = Read<int>(PESignatureOffsetLocation);
            if (_peHeaderOffset == 0)
            {
                IsValid = false;
                return;
            }

            uint peSignature = Read<uint>(_peHeaderOffset);
            if (peSignature != ExpectedPESignature)
            {
                IsValid = false;
                return;
            }

            // Read image_file_header
            ImageFileHeader header = Read<ImageFileHeader>(HeaderOffset);
            _sectionCount = header.NumberOfSections;
            IndexTimeStamp = header.TimeDateStamp;

            if (TryRead(OptionalHeaderOffset, out ImageOptionalHeader optional))
            {
                IsPE64 = optional.Magic != OptionalMagic32;
                _imageBase = IsPE64 ? optional.ImageBase64 : optional.ImageBase;
                IndexFileSize = optional.SizeOfImage;

                // Read directories.  In order for us to read directories, we need to know if
                // this is a x64 image or not, hence why this is wrapped in the above TryRead
                SeekTo(DataDirectoryOffset);
                for (int i = 0; i < _directories.Length; i++)
                    if (!TryRead(out _directories[i]))
                        break;

            }

            if (loadedImageBase == 0)
                return;

            _loadedImageBase = loadedImageBase;


            int readingCursor = RvaToOffset(RelocationDataDirectory.VirtualAddress);
            int readingLimit = readingCursor + RelocationDataDirectory.Size;

            List<int> relocations = new();
            while (readingCursor < readingLimit)
            {
                ImageRelocation relocation = Read<ImageRelocation>(ref readingCursor);

                int numRelocationsInBlock = (relocation.blockSize - Unsafe.SizeOf<ImageRelocation>()) / Unsafe.SizeOf<ushort>();

                for (int i = 0; i < numRelocationsInBlock; i++)
                {
                    ushort reloc = Read<ushort>(ref readingCursor);
                    int withinPageOffset = (reloc & 0x0fff);
                    int type = reloc >> 12;
                    int rva = relocation.pageRVA + withinPageOffset;
                    int fileOffset = RvaToOffset(rva);

                    const int IMAGE_REL_BASED_ABSOLUTE = 0;
                    const int IMAGE_REL_BASED_HIGHLOW = 3;
                    const int IMAGE_REL_BASED_DIR64 = 10;

                    if (type == IMAGE_REL_BASED_ABSOLUTE)
                    {
                        continue;
                    }

                    relocations.Add(fileOffset);

                    if (type == IMAGE_REL_BASED_HIGHLOW)
                    {
                        relocations.Add(fileOffset + 3);
                    }
                    else if (type == IMAGE_REL_BASED_DIR64)
                    {
                        relocations.Add(fileOffset + 7);
                    }
                    else
                    {
                        // TODO: Implementation if this happens.
                    }
                }

                if (readingCursor % 4 != 0)
                {
                    readingCursor += 4 - (readingCursor % 4);
                }
            }
            _relocations = relocations.ToArray();
            Array.Sort(_relocations);
        }