in src/Microsoft.Diagnostics.Runtime/DacImplementation/DacNativeHeaps.cs [239:291]
private IEnumerable<ClrNativeHeapInfo> LegacyEnumerateLoaderAllocatorHeaps(ulong loaderHeap, LoaderHeapKind loaderHeapKind, NativeHeapKind nativeHeapKind)
{
if (loaderHeap != 0)
{
List<ClrNativeHeapInfo>? result = null;
// The basic ISOSDacInterface doesn't understand the difference between the different kinds of runtime
// loader heaps. We have to adjust certain loader heap kinds based on the version of dac we are
// targeting. This includes .Net 7, and .Net 8 before ISOSDacInterface13 was implemented. Additionally,
// we don't know the version info for a lot of versions of single-file compilation. In all of those
// cases, we need to adjust the pointer.
bool normalNeedsAdjustment = false;
if (_clrInfo.Flavor == ClrFlavor.Core)
{
int versionMajor = _clrInfo.Version.Major;
normalNeedsAdjustment = versionMajor == 7 || versionMajor == 8 && _sos13 is null || versionMajor == 0;
}
ulong fixedHeapAddress = FixupHeapAddress(loaderHeap, loaderHeapKind, normalNeedsAdjustment);
HResult hr = _sos.TraverseLoaderHeap(fixedHeapAddress, (address, size, current) => {
result ??= new(8);
result.Add(new(MemoryRange.CreateFromLength(address, SanitizeSize(size)), nativeHeapKind, current != 0 ? ClrNativeHeapState.Active : ClrNativeHeapState.Inactive));
});
if (result is not null && result.Count > 0 && normalNeedsAdjustment)
{
// If we adjusted the pointer and we can't read the resulting addresses, try again with the
// opposite setting.
byte[] buffer = new byte[1];
if (result.Any(entry => _dataReader.Read(entry.MemoryRange.Start, buffer) == 0))
{
result.Clear();
fixedHeapAddress = FixupHeapAddress(loaderHeap, loaderHeapKind, !normalNeedsAdjustment);
hr = _sos.TraverseLoaderHeap(fixedHeapAddress, (address, size, current) => {
result ??= new(8);
result.Add(new(MemoryRange.CreateFromLength(address, SanitizeSize(size)), nativeHeapKind, current != 0 ? ClrNativeHeapState.Active : ClrNativeHeapState.Inactive));
});
}
}
// If TraverseLoaderHeap returns a failing HRESULT, it means that it encountered a bad block.
// This likely means that loaderHeap points to bad memory and we should ignore this entire
// enumeration.
if (hr && result != null)
return result;
}
return Enumerable.Empty<ClrNativeHeapInfo>();
}