in src/Microsoft.Diagnostics.Runtime/src/Windows/CachedMemoryReader.cs [113:212]
internal int TryReadMemory(ulong address, int byteCount, IntPtr buffer)
{
ImmutableArray<MinidumpSegment> segments = _segments;
MinidumpSegment lastKnownSegment = segments[segments.Length - 1];
// quick check if the address is before our first segment or after our last
if ((address < segments[0].VirtualAddress) || (address > (lastKnownSegment.VirtualAddress + lastKnownSegment.Size)))
return 0;
int curSegmentIndex = -1;
MinidumpSegment targetSegment;
if (address < _lastAccessed.Segment.End && address >= _lastAccessed.Segment.VirtualAddress)
{
targetSegment = _lastAccessed.Segment;
curSegmentIndex = _lastAccessed.SegmentIndex;
}
else
{
int memorySegmentStartIndex = segments.Search(address, (x, addr) => (x.VirtualAddress <= addr && addr < x.VirtualAddress + x.Size) ? 0 : x.VirtualAddress.CompareTo(addr));
if (memorySegmentStartIndex >= 0)
{
curSegmentIndex = memorySegmentStartIndex;
}
else
{
// It would be beyond the end of the memory segments we have
if (memorySegmentStartIndex == ~segments.Length)
return 0;
// This is the index of the first segment of memory whose start address is GREATER than the given address.
int insertionIndex = ~memorySegmentStartIndex;
if (insertionIndex == 0)
return 0;
// Grab the segment before this one, as it must be the one that contains this address
curSegmentIndex = insertionIndex - 1;
}
targetSegment = segments[curSegmentIndex];
}
// This can only be true if we went into the else block above, located a segment BEYOND the given address, backed up one segment and the address
// isn't inside that segment. This means we don't have the requested memory in the dump.
if (address > targetSegment.End)
return 0;
IntPtr insertionPtr = buffer;
int totalBytes = 0;
int remainingBytes = byteCount;
while (true)
{
ReadBytesFromSegment(targetSegment, address, remainingBytes, insertionPtr, out int bytesRead);
totalBytes += bytesRead;
remainingBytes -= bytesRead;
if (remainingBytes == 0 || bytesRead == 0)
{
_lastAccessed.Segment = targetSegment;
_lastAccessed.SegmentIndex = curSegmentIndex;
return totalBytes;
}
insertionPtr += bytesRead;
address += (uint)bytesRead;
if ((curSegmentIndex + 1) == segments.Length)
{
_lastAccessed.Segment = targetSegment;
_lastAccessed.SegmentIndex = curSegmentIndex;
return totalBytes;
}
targetSegment = segments[++curSegmentIndex];
if (address != targetSegment.VirtualAddress)
{
int prevSegmentIndex = curSegmentIndex;
curSegmentIndex = segments.Search(address, (x, addr) => (x.VirtualAddress <= addr && addr < x.VirtualAddress + x.Size) ? 0 : x.VirtualAddress.CompareTo(addr));
if (curSegmentIndex == -1)
{
if (prevSegmentIndex >= 0)
{
_lastAccessed.SegmentIndex = prevSegmentIndex;
_lastAccessed.Segment = segments[_lastAccessed.SegmentIndex];
}
return totalBytes;
}
targetSegment = segments[curSegmentIndex];
}
}
}