Skip to content
43 changes: 15 additions & 28 deletions docs/design/datacontracts/Loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,6 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer);
| `ArrayListBlock` | `Size` | Size of data section in block |
| `ArrayListBlock` | `ArrayStart` | Start of data section in block |
| `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator |
| `ImageDosHeader` | `Lfanew` | Offset to NT headers |
| `ImageNTHeaders` | `OptionalHeader` | Optional header |
| `ImageNTHeaders` | `FileHeader` | File header |
| `ImageOptionalHeader` | `SectionAlignment` | Alignment of sections in memory |
| `ImageFileHeader` | `NumberOfSections` | Number of sections in the PE file |
| `ImageFileHeader` | `SizeOfOptionalHeader` | Size of optional header on disk |
| `ImageSectionHeader` | `VirtualAddress` | Virtual address of the section |
| `ImageSectionHeader` | `VirtualSize` | Virtual size of the section |
| `ImageSectionHeader` | `PointerToRawData` | Offset to section data |
| `EETypeHashTable` | `Buckets` | Pointer to hash table buckets |
| `EETypeHashTable` | `Count` | Count of elements in the hash table |
| `EETypeHashTable` | `VolatileEntryValue` | The data stored in the hash table entry |
Expand Down Expand Up @@ -373,19 +364,19 @@ TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva)
else
{
// find NT headers using DOS header
uint dosHeaderLfanew = target.Read<uint>(baseAddress + /* ImageDosHeader::Lfanew offset */);
uint dosHeaderLfanew = target.Read<uint>(baseAddress + /* ImageDosHeader::LfanewOffset */);
TargetPointer ntHeadersPtr = baseAddress + dosHeaderLfanew;

TargetPointer optionalHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeader offset */;
uint sectionAlignment = target.Read<uint>(optionalHeaderPtr + /* ImageOptionalHeader::SectionAlignment offset */);
TargetPointer optionalHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeaderOffset */;
uint sectionAlignment = target.Read<uint>(optionalHeaderPtr + /* ImageOptionalHeader::SectionAlignmentOffset */);

// Get number of sections from file header
TargetPointer fileHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::FileHeader offset */;
uint numberOfSections = target.Read<uint>(fileHeaderPtr + /* ImageFileHeader::NumberOfSections offset */);
TargetPointer fileHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::FileHeaderOffset */;
uint numberOfSections = target.Read<uint>(fileHeaderPtr + /* ImageFileHeader::NumberOfSectionsOffset */);

// Calculate first section address (after NT headers and optional header)
uint imageFileHeaderSize = target.Read<ushort>(fileHeaderPtr + /* ImageFileHeader::SizeOfOptionalHeader offset */);
TargetPointer firstSectionPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeader offset */ + imageFileHeaderSize;
uint imageFileHeaderSize = target.Read<ushort>(fileHeaderPtr + /* ImageFileHeader::SizeOfOptionalHeaderOffset */);
TargetPointer firstSectionPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeaderOffset */ + imageFileHeaderSize;

// Find the section containing this RVA
TargetPointer sectionPtr = TargetPointer.Null;
Expand All @@ -394,28 +385,24 @@ TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva)
for (uint i = 0; i < numberOfSections; i++)
{
TargetPointer currentSectionPtr = firstSectionPtr + (i * sectionHeaderSize);
uint virtualAddress = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualAddress offset */);
uint virtualSize = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualSize offset */);
uint virtualAddress = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
uint virtualSize = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualSizeOffset */);
uint sizeOfRawData = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::SizeOfRawDataOffset */);

uint alignedVirtualSize = (virtualSize + sectionAlignment - 1) & ~(sectionAlignment - 1);
if (rva < VirtualAddress + alignedVirtualSize)
if (rva >= VirtualAddress && rva < VirtualAddress + SizeOfRawData)
{
if (rva < virtualAddress)
sectionPtr = TargetPointer.Null;
else
sectionPtr = currentSectionPtr;
break;
sectionPtr = currentSectionPtr;
}
}
if (sectionPtr == TargetPointer.Null)
{
offset = (uint)rva;
throw new InvalidOperationException("Failed to read from image.");
}
else
{
// Convert RVA to file offset using section information
uint sectionVirtualAddress = target.Read<uint>(sectionPtr + /* ImageSectionHeader::VirtualAddress offset */);
uint sectionPointerToRawData = target.Read<uint>(sectionPtr + /* ImageSectionHeader::PointerToRawData offset */);
uint sectionVirtualAddress = target.Read<uint>(sectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
uint sectionPointerToRawData = target.Read<uint>(sectionPtr + /* ImageSectionHeader::PointerToRawDataOffset */);
offset = ((rva - sectionVirtualAddress) + sectionPointerToRawData);
}
}
Expand Down
29 changes: 0 additions & 29 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -196,35 +196,6 @@ CDAC_TYPE_FIELD(PEImageLayout, /*uint32*/, Size, cdac_data<PEImageLayout>::Size)
CDAC_TYPE_FIELD(PEImageLayout, /*uint32*/, Flags, cdac_data<PEImageLayout>::Flags)
CDAC_TYPE_END(PEImageLayout)

CDAC_TYPE_BEGIN(ImageNTHeaders)
CDAC_TYPE_INDETERMINATE(ImageNTHeaders)
CDAC_TYPE_FIELD(ImageNTHeaders, /*uint32*/, OptionalHeader, offsetof(IMAGE_NT_HEADERS, OptionalHeader))
CDAC_TYPE_FIELD(ImageNTHeaders, /*uint16*/, FileHeader, offsetof(IMAGE_NT_HEADERS, FileHeader))
CDAC_TYPE_END(ImageNTHeaders)

CDAC_TYPE_BEGIN(ImageFileHeader)
CDAC_TYPE_INDETERMINATE(ImageFileHeader)
CDAC_TYPE_FIELD(ImageFileHeader, /*uint16*/, NumberOfSections, offsetof(IMAGE_FILE_HEADER, NumberOfSections))
CDAC_TYPE_FIELD(ImageFileHeader, /*uint16*/, SizeOfOptionalHeader, offsetof(IMAGE_FILE_HEADER, SizeOfOptionalHeader))
CDAC_TYPE_END(ImageFileHeader)

CDAC_TYPE_BEGIN(ImageOptionalHeader)
CDAC_TYPE_INDETERMINATE(ImageOptionalHeader)
CDAC_TYPE_FIELD(ImageOptionalHeader, /*uint32*/, SectionAlignment, offsetof(IMAGE_OPTIONAL_HEADER, SectionAlignment))
CDAC_TYPE_END(ImageOptionalHeader)

CDAC_TYPE_BEGIN(ImageSectionHeader)
CDAC_TYPE_SIZE(sizeof(IMAGE_SECTION_HEADER))
CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, VirtualAddress, offsetof(IMAGE_SECTION_HEADER, VirtualAddress))
CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, VirtualSize, offsetof(IMAGE_SECTION_HEADER, Misc.VirtualSize))
CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, PointerToRawData, offsetof(IMAGE_SECTION_HEADER, PointerToRawData))
CDAC_TYPE_END(ImageSectionHeader)

CDAC_TYPE_BEGIN(ImageDosHeader)
CDAC_TYPE_INDETERMINATE(ImageDosHeader)
CDAC_TYPE_FIELD(ImageDosHeader, /*uint32*/, Lfanew, offsetof(IMAGE_DOS_HEADER, e_lfanew))
CDAC_TYPE_END(ImageDosHeader)

CDAC_TYPE_BEGIN(CGrowableSymbolStream)
CDAC_TYPE_INDETERMINATE(CGrowableSymbolStream)
CDAC_TYPE_FIELD(CGrowableSymbolStream, /*pointer*/, Buffer, cdac_data<CGrowableStream>::Buffer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ public enum DataType
AssemblyBinder,
PEImage,
PEImageLayout,
ImageFileHeader,
ImageNTHeaders,
ImageOptionalHeader,
ImageSectionHeader,
ImageDosHeader,
CGrowableSymbolStream,
ProbeExtensionResult,
MethodTable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public abstract class Target
/// <typeparam name="T">Type of value to read</typeparam>
/// <param name="address">Address to start reading from</param>
/// <returns>Value read from the target</returns>
public abstract T Read<T>(ulong address) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>;
public abstract T Read<T>(ulong address, bool? isLittleEndian = null) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>;

/// <summary>
/// Read a value from the target in target endianness
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,6 @@ bool ILoader.TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer ba
return true;
}

private static uint AlignUp(uint value, uint alignment)
{
if (alignment == 0)
throw new ArgumentException("Alignment must be greater than zero.", nameof(alignment));
return (value + alignment - 1) & ~(alignment - 1);
}

private static bool IsMapped(Data.PEImageLayout peImageLayout)
{
return (peImageLayout.Flags & (uint)PEImageFlags.FLAG_MAPPED) != 0;
Expand All @@ -222,22 +215,17 @@ private TargetPointer RvaToSection(int rva, Data.PEImageLayout imageLayout)
{
TargetPointer ntHeadersPtr = FindNTHeaders(imageLayout);
Data.ImageNTHeaders ntHeaders = _target.ProcessedData.GetOrAdd<Data.ImageNTHeaders>(ntHeadersPtr);
Target.TypeInfo type = _target.GetTypeInfo(DataType.ImageNTHeaders);
int offset = type.Fields[nameof(Data.ImageNTHeaders.OptionalHeader)].Offset;
int offset = Data.ImageNTHeaders.OptionalHeaderOffset;
TargetPointer section = ntHeadersPtr + (uint)offset + ntHeaders.FileHeader.SizeOfOptionalHeader;
TargetPointer sectionEnd = section + _target.GetTypeInfo(DataType.ImageSectionHeader).Size!.Value * ntHeaders.FileHeader.NumberOfSections;
uint sectionAlignment = ntHeaders.OptionalHeader.SectionAlignment;
TargetPointer sectionEnd = section + Data.ImageSectionHeader.Size * ntHeaders.FileHeader.NumberOfSections;
while (section < sectionEnd)
{
Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd<Data.ImageSectionHeader>(section);
if (rva < sectionHeader.VirtualAddress + AlignUp(sectionHeader.VirtualSize, sectionAlignment))
if (rva >= sectionHeader.VirtualAddress && rva < sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData)
{
if (rva < sectionHeader.VirtualAddress)
return TargetPointer.Null;
else
return section;
return section;
}
section += _target.GetTypeInfo(DataType.ImageSectionHeader).Size!.Value;
section += Data.ImageSectionHeader.Size;
}
return TargetPointer.Null;
}
Expand All @@ -246,7 +234,7 @@ private uint RvaToOffset(int rva, Data.PEImageLayout imageLayout)
{
TargetPointer section = RvaToSection(rva, imageLayout);
if (section == TargetPointer.Null)
return (uint)rva;
throw new InvalidOperationException("Failed to read from image.");

Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd<Data.ImageSectionHeader>(section);
uint offset = (uint)(rva - sectionHeader.VirtualAddress) + sectionHeader.PointerToRawData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ internal sealed class ImageDosHeader : IData<ImageDosHeader>
{
static ImageDosHeader IData<ImageDosHeader>.Create(Target target, TargetPointer address)
=> new ImageDosHeader(target, address);
private const int LfanewOffset = 60;

public ImageDosHeader(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ImageDosHeader);
Lfanew = target.Read<int>(address + (ulong)type.Fields[nameof(Lfanew)].Offset);
Lfanew = target.Read<int>(address + LfanewOffset, true);
}
public int Lfanew { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ namespace Microsoft.Diagnostics.DataContractReader.Data;
internal sealed class ImageFileHeader : IData<ImageFileHeader>
{
static ImageFileHeader IData<ImageFileHeader>.Create(Target target, TargetPointer address) => new ImageFileHeader(target, address);
private const int NumberOfSectionsOffset = 2;
private const int SizeOfOptionalHeaderOffset = 16;
public ImageFileHeader(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ImageFileHeader);
NumberOfSections = target.Read<ushort>(address + (ulong)type.Fields[nameof(NumberOfSections)].Offset);
SizeOfOptionalHeader = target.Read<ushort>(address + (ulong)type.Fields[nameof(SizeOfOptionalHeader)].Offset);
NumberOfSections = target.Read<ushort>(address + NumberOfSectionsOffset, true);
SizeOfOptionalHeader = target.Read<ushort>(address + SizeOfOptionalHeaderOffset, true);
}
public ushort NumberOfSections { get; init; }
public ushort SizeOfOptionalHeader { get; init; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ namespace Microsoft.Diagnostics.DataContractReader.Data;
internal sealed class ImageNTHeaders : IData<ImageNTHeaders>
{
static ImageNTHeaders IData<ImageNTHeaders>.Create(Target target, TargetPointer address) => new ImageNTHeaders(target, address);
public const int FileHeaderOffset = 4;
public const int OptionalHeaderOffset = 24;
public ImageNTHeaders(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ImageNTHeaders);
OptionalHeader = target.ProcessedData.GetOrAdd<ImageOptionalHeader>(address + (ulong)type.Fields[nameof(OptionalHeader)].Offset);
FileHeader = target.ProcessedData.GetOrAdd<ImageFileHeader>(address + (ulong)type.Fields[nameof(FileHeader)].Offset);
FileHeader = target.ProcessedData.GetOrAdd<ImageFileHeader>(address + FileHeaderOffset);
OptionalHeader = target.ProcessedData.GetOrAdd<ImageOptionalHeader>(address + OptionalHeaderOffset);
}

public ImageOptionalHeader OptionalHeader { get; init; }
public ImageFileHeader FileHeader { get; init; }
public ImageOptionalHeader OptionalHeader { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Data;
internal sealed class ImageOptionalHeader : IData<ImageOptionalHeader>
{
static ImageOptionalHeader IData<ImageOptionalHeader>.Create(Target target, TargetPointer address) => new ImageOptionalHeader(target, address);
private const int SectionAlignmentOffset = 32;
public ImageOptionalHeader(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ImageOptionalHeader);
SectionAlignment = target.Read<uint>(address + (ulong)type.Fields[nameof(SectionAlignment)].Offset);
SectionAlignment = target.Read<uint>(address + SectionAlignmentOffset, true);
}
public uint SectionAlignment { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@ namespace Microsoft.Diagnostics.DataContractReader.Data;
internal sealed class ImageSectionHeader : IData<ImageSectionHeader>
{
static ImageSectionHeader IData<ImageSectionHeader>.Create(Target target, TargetPointer address) => new ImageSectionHeader(target, address);
private const int VirtualSizeOffset = 8;
private const int VirtualAddressOffset = 12;
private const int SizeOfRawDataOffset = 16;
private const int PointerToRawDataOffset = 20;
public const uint Size = 40;
public ImageSectionHeader(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ImageSectionHeader);

VirtualSize = target.Read<uint>(address + (ulong)type.Fields[nameof(VirtualSize)].Offset);
VirtualAddress = target.Read<uint>(address + (ulong)type.Fields[nameof(VirtualAddress)].Offset);
PointerToRawData = target.Read<uint>(address + (ulong)type.Fields[nameof(PointerToRawData)].Offset);
VirtualSize = target.Read<uint>(address + VirtualSizeOffset, true);
VirtualAddress = target.Read<uint>(address + VirtualAddressOffset, true);
SizeOfRawData = target.Read<uint>(address + SizeOfRawDataOffset, true);
PointerToRawData = target.Read<uint>(address + PointerToRawDataOffset, true);
}

public uint VirtualSize { get; init; }
public uint VirtualAddress { get; init; }
public uint SizeOfRawData { get; init; }
public uint PointerToRawData { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,10 @@ public override bool TryGetThreadContext(ulong threadId, uint contextFlags, Span
/// <typeparam name="T">Type of value to read</typeparam>
/// <param name="address">Address to start reading from</param>
/// <returns>Value read from the target</returns>
public override T Read<T>(ulong address)
public override T Read<T>(ulong address, bool? isLittleEndian = null)
{
if (!TryRead(address, _config.IsLittleEndian, _dataTargetDelegates, out T value))
bool useLittleEndian = isLittleEndian ?? _config.IsLittleEndian;
if (!TryRead(address, useLittleEndian, _dataTargetDelegates, out T value))
throw new InvalidOperationException($"Failed to read {typeof(T)} at 0x{address:x8}.");

return value;
Expand Down
Loading