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);
}