internal int TryReadMemory()

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