Skip to content

WIP: Add ISOSDacInterface18 for GCInfo inspection APIs#129761

Draft
max-charlamb wants to merge 3 commits into
dotnet:mainfrom
max-charlamb:dev/max-charlamb/isosdacinterface18-gcinfo
Draft

WIP: Add ISOSDacInterface18 for GCInfo inspection APIs#129761
max-charlamb wants to merge 3 commits into
dotnet:mainfrom
max-charlamb:dev/max-charlamb/isosdacinterface18-gcinfo

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Add ISOSDacInterface18 COM interface exposing GCInfo inspection APIs through the cDAC, enabling SOS and diagnostic tools to query GC information for managed methods.

APIs

  • GetGCInfoHeader - Get GC info header for a code range
  • GetGCInfoInterruptibleRanges - Enumerate interruptible code ranges
  • GetGCInfoSafePoints - Enumerate GC safe points
  • GetGCInfoRegisterLifetimes - Enumerate register-based GC slot lifetimes
  • GetGCInfoStackSlotLifetimes - Enumerate stack-based GC slot lifetimes

Status

Work in progress - needs build verification and e2e testing.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new SOS-DAC COM interface (ISOSDacInterface18) intended to expose GCInfo inspection APIs (header, safe points, interruptible ranges, and slot lifetimes), alongside expanding the managed cDAC IGCInfo contract and decoder surface to project the same data.

Changes:

  • Add ISOSDacInterface18 (IDL + prebuilt headers + C# GeneratedComInterface) and wire it up through DAC QueryInterface.
  • Implement GCInfo inspection entrypoints in the native DAC (ClrDataAccess) using GcInfoDecoder / GcInfoDumper, and extend the managed GCInfo decoder/contracts with header/safe point/lifetime APIs.
  • Extend GCInfo platform traits to include PSP symbol encoding base across architectures; add placeholder (E_NOTIMPL) stubs in the managed legacy SOS DAC implementation.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs Adds ISOSDacInterface18 exposure but currently returns E_NOTIMPL for all new methods.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs Defines GCInfo structs and ISOSDacInterface18 managed COM declarations.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/X86/GCInfo.cs Implements newly added IGCInfoDecoder members on x86 by throwing NotSupportedException.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/RISCV64GCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/LoongArch64GCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/InterpreterGCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/IGCInfoTraits.cs Extends traits interface with PSP_SYM_STACK_SLOT_ENCBASE.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/ARMGCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/ARM64GCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/AMD64GCInfoTraits.cs Adds PSP symbol stack-slot encoding base.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/IGCInfoDecoder.cs Expands decoder interface to include header/safe points/lifetimes.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/GCInfoDecoder.cs Adds decoding/projection for header/safe points/lifetimes (includes a correctness issue in safe-point lookup and a potentially expensive lifetime algorithm).
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/GCInfo_1.cs Plumbs new IGCInfo contract methods to the decoder implementation.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IGCInfo.cs Adds public contract types (header/lifetime records) and new IGCInfo methods.
src/coreclr/pal/prebuilt/inc/sospriv.h Updates prebuilt SOS-DAC header with new interface and structs.
src/coreclr/pal/prebuilt/idl/sospriv_i.cpp Adds GUID definitions for new SOS-DAC interfaces/enums.
src/coreclr/inc/sospriv.idl Adds IDL definitions for GCInfo structs and ISOSDacInterface18.
src/coreclr/debug/daccess/request.cpp Implements ClrDataAccess::GetGCInfo* methods and supporting helpers.
src/coreclr/debug/daccess/dacimpl.h Extends ClrDataAccess inheritance and declares ISOSDacInterface17/18 methods.
src/coreclr/debug/daccess/daccess.cpp Extends QueryInterface to support ISOSDacInterface17/18.

Comment on lines 937 to 942
EnsureDecodedTo(DecodePoints.InterruptibleRanges);

if (_gcVersion < 4)
codeOffset--;

uint normBreakOffset = TTraits.NormalizeCodeOffset(codeOffset);
Comment on lines +1008 to +1033
for (uint offset = 0; offset <= _codeLength; offset++)
{
while (interruptibleRangeIndex < _interruptibleRanges.Count &&
_interruptibleRanges[interruptibleRangeIndex].EndOffset <= offset)
{
interruptibleRangeIndex++;
}

bool isInterruptible =
interruptibleRangeIndex < _interruptibleRanges.Count &&
_interruptibleRanges[interruptibleRangeIndex].StartOffset <= offset &&
offset < _interruptibleRanges[interruptibleRangeIndex].EndOffset;
bool isSafePoint = safePoints.Contains(offset);

HashSet<uint> currentLiveSlots = [];
EnumerateLiveSlots(
offset,
new GcSlotEnumerationOptions
{
IsActiveFrame = !isSafePoint,
IsExecutionAborted = !isSafePoint && !isInterruptible,
IsParentOfFuncletStackFrame = false,
SuppressUntrackedSlots = true,
ReportFPBasedSlotsOnly = false,
},
(uint slotIndex, GcSlotDesc slot, uint gcFlags) =>
Comment on lines +7354 to +7358
int ISOSDacInterface18.GetGCInfoHeader(ClrDataAddress ip, SOSGCInfoHeader* header)
{
// TODO(cdac): Implement ISOSDacInterface18 GCInfo support.
return HResults.E_NOTIMPL;
}
Comment on lines +539 to +596
public GCInfoHeader GetHeader()
{
EnsureDecodedTo(DecodePoints.ReversePInvoke);

GcInfoHeaderFlags genericsInstContextFlags = _headerFlags & GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_MASK;
SpecialSlot? gsCookie = _gsCookieStackSlot != TTraits.NO_GS_COOKIE ? new SpecialSlot(_gsCookieStackSlot) : null;
SpecialSlot? pspSym = _pspSymStackSlot != TTraits.NO_PSP_SYM ? new SpecialSlot(_pspSymStackSlot) : null;
SpecialSlot? genericsInstContext = _genericsInstContextStackSlot != TTraits.NO_GENERICS_INST_CONTEXT ? new SpecialSlot(_genericsInstContextStackSlot) : null;

GenericsContextKind genericsContextKind = genericsInstContextFlags switch
{
GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_MD => GenericsContextKind.MethodDesc,
GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_MT => GenericsContextKind.MethodHandle,
GcInfoHeaderFlags.GC_INFO_HAS_GENERICS_INST_CONTEXT_THIS => GenericsContextKind.This,
_ => GenericsContextKind.MethodDesc,
};

bool flag80Set = _headerFlags.HasFlag(GcInfoHeaderFlags.GC_INFO_WANTS_REPORT_ONLY_LEAF);
bool wantsReportOnlyLeaf = _arch == RuntimeInfoArchitecture.X64 && _gcVersion < 4 ? flag80Set : true;
bool hasTailCalls = _arch is RuntimeInfoArchitecture.Arm or RuntimeInfoArchitecture.Arm64 or RuntimeInfoArchitecture.LoongArch64 or RuntimeInfoArchitecture.RiscV64
&& flag80Set;

return new GCInfoHeader(
Version: _gcVersion,
CodeSize: _codeLength,
PrologSize: _validRangeStart,
StackBaseRegister: _stackBaseRegister,
SizeOfStackParameterArea: _fixedStackParameterScratchArea,
IsVarArg: _headerFlags.HasFlag(GcInfoHeaderFlags.GC_INFO_IS_VARARG),
WantsReportOnlyLeaf: wantsReportOnlyLeaf,
HasTailCalls: hasTailCalls,
GSCookie: gsCookie,
GSCookieValidRangeStart: _validRangeStart,
GSCookieValidRangeEnd: _validRangeEnd,
PSPSym: pspSym,
GenericsInstContext: genericsInstContext,
GenericsInstContextKind: genericsContextKind,
ReturnKind: _returnKind);
}

public IReadOnlyList<uint> GetSafePoints()
{
EnsureDecodedTo(DecodePoints.InterruptibleRanges);

List<uint> safePoints = new((int)_numSafePoints);
int bitOffset = _safePointBitOffset;
uint numBitsPerOffset = CeilOfLog2(TTraits.NormalizeCodeOffset(_codeLength));
for (uint i = 0; i < _numSafePoints; i++)
{
uint offset = TTraits.DenormalizeCodeOffset((uint)_reader.ReadBits((int)numBitsPerOffset, ref bitOffset));
if (_gcVersion < 4)
offset++;

safePoints.Add(offset);
}

return safePoints;
}
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/isosdacinterface18-gcinfo branch from 646c0fb to 5310bc9 Compare June 23, 2026 18:28
Copilot AI review requested due to automatic review settings June 23, 2026 18:48
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/isosdacinterface18-gcinfo branch from 5310bc9 to 2f24300 Compare June 23, 2026 18:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment on lines +7422 to +7444
if (pNeeded is null)
return HResults.E_POINTER;

*pNeeded = 0;

(Contracts.IGCInfoHandle handle, Contracts.IGCInfo gcInfo) = ResolveGCInfo(ip);
IReadOnlyList<Contracts.InterruptibleRange> interruptibleRanges = gcInfo.GetInterruptibleRanges(handle);

*pNeeded = (uint)interruptibleRanges.Count;

if (ranges is not null)
{
uint toWrite = Math.Min(count, (uint)interruptibleRanges.Count);
for (uint i = 0; i < toWrite; i++)
{
ranges[i] = new SOSCodeRange
{
BeginOffset = interruptibleRanges[(int)i].StartOffset,
EndOffset = interruptibleRanges[(int)i].EndOffset,
};
}
hr = toWrite < (uint)interruptibleRanges.Count ? HResults.S_FALSE : HResults.S_OK;
}
Comment on lines +7395 to +7398
header->GSCookieIsPresent = h.GSCookie.HasValue ? 1 : 0;
header->GSCookieStackSlot = h.GSCookie?.SpOffset ?? 0;
header->GSCookieValidRangeStart = h.GSCookieValidRangeStart;
header->GSCookieValidRangeEnd = h.GSCookieValidRangeEnd;
Comment on lines +45 to +62
/// <summary>Header fields decoded from the GC info stream for a method.</summary>
public readonly record struct GCInfoHeader(
uint Version,
uint CodeSize,
uint PrologSize,
uint StackBaseRegister,
uint SizeOfStackParameterArea,
bool IsVarArg,
bool WantsReportOnlyLeaf,
bool HasTailCalls,
SpecialSlot? GSCookie,
uint GSCookieValidRangeStart,
uint GSCookieValidRangeEnd,
SpecialSlot? PSPSym,
SpecialSlot? GenericsInstContext,
GenericsContextKind GenericsInstContextKind,
uint? ReturnKind);

Comment on lines +939 to +941
if (_gcVersion < 4)
codeOffset--;

Comment on lines +556 to +576
bool flag80Set = _headerFlags.HasFlag(GcInfoHeaderFlags.GC_INFO_WANTS_REPORT_ONLY_LEAF);
bool wantsReportOnlyLeaf = _arch == RuntimeInfoArchitecture.X64 && _gcVersion < 4 ? flag80Set : true;
bool hasTailCalls = _arch is RuntimeInfoArchitecture.Arm or RuntimeInfoArchitecture.Arm64 or RuntimeInfoArchitecture.LoongArch64 or RuntimeInfoArchitecture.RiscV64
&& flag80Set;

return new GCInfoHeader(
Version: _gcVersion,
CodeSize: _codeLength,
PrologSize: _validRangeStart,
StackBaseRegister: _stackBaseRegister,
SizeOfStackParameterArea: _fixedStackParameterScratchArea,
IsVarArg: _headerFlags.HasFlag(GcInfoHeaderFlags.GC_INFO_IS_VARARG),
WantsReportOnlyLeaf: wantsReportOnlyLeaf,
HasTailCalls: hasTailCalls,
GSCookie: gsCookie,
GSCookieValidRangeStart: _validRangeStart,
GSCookieValidRangeEnd: _validRangeEnd,
PSPSym: pspSym,
GenericsInstContext: genericsInstContext,
GenericsInstContextKind: genericsContextKind,
ReturnKind: _returnKind);
Comment on lines +1008 to +1023
for (uint offset = 0; offset <= _codeLength; offset++)
{
while (interruptibleRangeIndex < _interruptibleRanges.Count &&
_interruptibleRanges[interruptibleRangeIndex].EndOffset <= offset)
{
interruptibleRangeIndex++;
}

bool isInterruptible =
interruptibleRangeIndex < _interruptibleRanges.Count &&
_interruptibleRanges[interruptibleRangeIndex].StartOffset <= offset &&
offset < _interruptibleRanges[interruptibleRangeIndex].EndOffset;
bool isSafePoint = safePoints.Contains(offset);

HashSet<uint> currentLiveSlots = [];
EnumerateLiveSlots(
Comment on lines +7372 to +7379
int ISOSDacInterface18.GetGCInfoHeader(ClrDataAddress ip, SOSGCInfoHeader* header)
{
int hr = HResults.S_OK;
try
{
if (header is null)
return HResults.E_POINTER;

@max-charlamb max-charlamb force-pushed the dev/max-charlamb/isosdacinterface18-gcinfo branch from 2f24300 to 36cbff5 Compare June 23, 2026 21:06
Copilot AI review requested due to automatic review settings June 24, 2026 14:44
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/isosdacinterface18-gcinfo branch from 36cbff5 to 487271d Compare June 24, 2026 14:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Add ISOSDacInterface18 with GCInfo inspection APIs (cDAC-only):
- GetGCInfoHeader
- GetGCInfoInterruptibleRanges
- GetGCInfoSafePoints
- GetGCInfoRegisterLifetimes
- GetGCInfoStackSlotLifetimes

Add efficient single-pass GetSlotLifetimes to GCInfoDecoder that
walks the chunk transition table once instead of calling
EnumerateLiveSlots at every byte offset (O(numTransitions) vs
O(codeLength * numSlots)).

GetRegisterLifetimes/GetStackSlotLifetimes now delegate to
GetSlotLifetimes with filtering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace GetGCInfoRegisterLifetimes + GetGCInfoStackSlotLifetimes with
  single GetGCInfoSlotLifetimes returning unified SOSGCSlotLifetime struct
- Eagerly decode safe points in DecodeSafePoints (cached in _safePoints list)
- FindSafePoint now searches cached list instead of re-reading bit stream
- Reorder GetSafePoints next to GetInterruptibleRanges in all interfaces
- Remove _gcVersion < 4 guard from safe point decoding
- ISOSDacInterface18 now has 4 methods: Header, InterruptibleRanges,
  SafePoints, SlotLifetimes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Comment on lines +686 to +693
// End of chunk state
if (currentState != 0 && !activeSlots.ContainsKey(slotIndex))
activeSlots[slotIndex] = DenormInterruptibleOffset(prevNormOffset);
else if (currentState == 0 && activeSlots.TryGetValue(slotIndex, out uint begin))
{
EmitSlotLifetime(slotIndex, begin, DenormInterruptibleOffset(prevNormOffset), lifetimes);
activeSlots.Remove(slotIndex);
}
Comment on lines +7358 to +7361
Contracts.CodeBlockHandle? cbh = eman.GetCodeBlockHandle(ip.ToTargetCodePointer(_target));
if (cbh is null)
throw new ArgumentException("No code block found for the given IP");

Comment on lines +1337 to +1341
int GetGCInfoSlotLifetimes(
ClrDataAddress ip,
uint count,
[In, Out, MarshalUsing(CountElementName = nameof(count))] SOSGCSlotLifetime[]? lifetimes,
uint* pNeeded);
Comment on lines +45 to +60
/// <summary>Header fields decoded from the GC info stream for a method.</summary>
public readonly record struct GCInfoHeader(
uint Version,
uint CodeSize,
uint PrologSize,
uint StackBaseRegister,
uint SizeOfStackParameterArea,
bool IsVarArg,
bool WantsReportOnlyLeaf,
bool HasTailCalls,
SpecialSlot? GSCookie,
uint GSCookieValidRangeStart,
uint GSCookieValidRangeEnd,
SpecialSlot? PSPSym,
SpecialSlot? GenericsInstContext,
GenericsContextKind GenericsInstContextKind);
GetSlotLifetimes was returning only untracked slots for methods
without interruptible ranges (safe-point-only methods). Now decodes
the per-safe-point live slot bitmaps and builds lifetime ranges from
consecutive safe points where slots transition between live/dead.

Supports both direct bitmap and indirect (RLE) safe point encodings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 25, 2026 14:55
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/isosdacinterface18-gcinfo branch from bbd22fa to 7d34213 Compare June 25, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.

Comment on lines +7357 to +7360
Contracts.IExecutionManager eman = _target.Contracts.ExecutionManager;
Contracts.CodeBlockHandle? cbh = eman.GetCodeBlockHandle(ip.ToTargetCodePointer(_target));
if (cbh is null)
throw new ArgumentException("No code block found for the given IP");
Comment on lines +7431 to +7443
if (ranges is not null)
{
uint toWrite = Math.Min(count, (uint)interruptibleRanges.Count);
for (uint i = 0; i < toWrite; i++)
{
ranges[i] = new SOSCodeRange
{
BeginOffset = interruptibleRanges[(int)i].StartOffset,
EndOffset = interruptibleRanges[(int)i].EndOffset,
};
}
hr = toWrite < (uint)interruptibleRanges.Count ? HResults.S_FALSE : HResults.S_OK;
}
Comment on lines +7472 to +7480
if (offsets is not null)
{
uint toWrite = Math.Min(count, (uint)safePoints.Count);
for (uint i = 0; i < toWrite; i++)
{
offsets[i] = safePoints[(int)i];
}
hr = toWrite < (uint)safePoints.Count ? HResults.S_FALSE : HResults.S_OK;
}
Comment on lines +7509 to +7527
if (lifetimes is not null)
{
uint toWrite = Math.Min(count, (uint)allLifetimes.Count);
for (uint i = 0; i < toWrite; i++)
{
Contracts.GCSlotLifetime s = allLifetimes[(int)i];
lifetimes[i] = new SOSGCSlotLifetime
{
BeginOffset = s.BeginOffset,
EndOffset = s.EndOffset,
IsRegister = s.IsRegister ? 1 : 0,
RegisterNumber = s.RegisterNumber,
SpOffset = s.SpOffset,
BaseRegister = s.BaseRegister,
GcFlags = s.GcFlags,
};
}
hr = toWrite < (uint)allLifetimes.Count ? HResults.S_FALSE : HResults.S_OK;
}
Comment on lines 4 to 9
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using ILCompiler.Reflection.ReadyToRun;
Comment on lines 130 to 135
private uint _numSafePoints;
private uint _numInterruptibleRanges;
private List<InterruptibleRange> _interruptibleRanges = [];
private List<uint> _safePoints = [];
private int _safePointBitOffset;

Comment on lines 337 to 338
_safePointBitOffset = _bitOffset;
// skip over safe point data
uint numBitsPerOffset = CeilOfLog2(TTraits.NormalizeCodeOffset(_codeLength));
Comment on lines 45 to +105
@@ -54,7 +99,10 @@ public interface IGCInfo : IContract
uint GetSizeOfStackParameterArea(IGCInfoHandle handle) => throw new NotImplementedException();
uint GetCalleePoppedArgumentsSize(IGCInfoHandle handle) => throw new NotImplementedException();
IReadOnlyList<InterruptibleRange> GetInterruptibleRanges(IGCInfoHandle handle) => throw new NotImplementedException();
IReadOnlyList<uint> GetSafePoints(IGCInfoHandle handle) => throw new NotImplementedException();
IReadOnlyList<LiveSlot> EnumerateLiveSlots(IGCInfoHandle handle, uint instructionOffset, GcSlotEnumerationOptions options) => throw new NotImplementedException();
GCInfoHeader GetHeader(IGCInfoHandle handle) => throw new NotImplementedException();
IReadOnlyList<GCSlotLifetime> GetSlotLifetimes(IGCInfoHandle handle) => throw new NotImplementedException();
Comment on lines +7372 to +7495
int ISOSDacInterface18.GetGCInfoHeader(ClrDataAddress ip, SOSGCInfoHeader* header)
{
int hr = HResults.S_OK;
try
{
if (header is null)
return HResults.E_POINTER;

*header = default;

(Contracts.IGCInfoHandle handle, Contracts.IGCInfo gcInfo) = ResolveGCInfo(ip);
Contracts.GCInfoHeader h = gcInfo.GetHeader(handle);

header->SizeOf = (uint)sizeof(SOSGCInfoHeader);
header->GcInfoVersion = h.Version;
header->CodeSize = h.CodeSize;
header->PrologSize = h.PrologSize;
header->StackBaseRegister = h.StackBaseRegister;
header->SizeOfStackParameterArea = h.SizeOfStackParameterArea;
header->IsVarArg = h.IsVarArg ? 1 : 0;
header->WantsReportOnlyLeaf = h.WantsReportOnlyLeaf ? 1 : 0;
header->HasTailCalls = h.HasTailCalls ? 1 : 0;
header->GSCookieIsPresent = h.GSCookie.HasValue ? 1 : 0;
header->GSCookieStackSlot = h.GSCookie?.SpOffset ?? 0;
header->GSCookieValidRangeStart = h.GSCookieValidRangeStart;
header->GSCookieValidRangeEnd = h.GSCookieValidRangeEnd;
header->PSPSymIsPresent = h.PSPSym.HasValue ? 1 : 0;
header->PSPSymStackSlot = h.PSPSym?.SpOffset ?? 0;
header->GenericsInstContextIsPresent = h.GenericsInstContext.HasValue ? 1 : 0;
header->GenericsInstContextStackSlot = h.GenericsInstContext?.SpOffset ?? 0;
header->GenericsInstContextKind = (uint)h.GenericsInstContextKind;
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

return hr;
}

int ISOSDacInterface18.GetGCInfoInterruptibleRanges(
ClrDataAddress ip,
uint count,
SOSCodeRange[]? ranges,
uint* pNeeded)
{
int hr = HResults.S_OK;
try
{
if (pNeeded is null)
return HResults.E_POINTER;

*pNeeded = 0;

(Contracts.IGCInfoHandle handle, Contracts.IGCInfo gcInfo) = ResolveGCInfo(ip);
IReadOnlyList<Contracts.InterruptibleRange> interruptibleRanges = gcInfo.GetInterruptibleRanges(handle);

*pNeeded = (uint)interruptibleRanges.Count;

if (ranges is not null)
{
uint toWrite = Math.Min(count, (uint)interruptibleRanges.Count);
for (uint i = 0; i < toWrite; i++)
{
ranges[i] = new SOSCodeRange
{
BeginOffset = interruptibleRanges[(int)i].StartOffset,
EndOffset = interruptibleRanges[(int)i].EndOffset,
};
}
hr = toWrite < (uint)interruptibleRanges.Count ? HResults.S_FALSE : HResults.S_OK;
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

return hr;
}

int ISOSDacInterface18.GetGCInfoSafePoints(
ClrDataAddress ip,
uint count,
uint[]? offsets,
uint* pNeeded)
{
int hr = HResults.S_OK;
try
{
if (pNeeded is null)
return HResults.E_POINTER;

*pNeeded = 0;

(Contracts.IGCInfoHandle handle, Contracts.IGCInfo gcInfo) = ResolveGCInfo(ip);
IReadOnlyList<uint> safePoints = gcInfo.GetSafePoints(handle);

*pNeeded = (uint)safePoints.Count;

if (offsets is not null)
{
uint toWrite = Math.Min(count, (uint)safePoints.Count);
for (uint i = 0; i < toWrite; i++)
{
offsets[i] = safePoints[(int)i];
}
hr = toWrite < (uint)safePoints.Count ? HResults.S_FALSE : HResults.S_OK;
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

return hr;
}

int ISOSDacInterface18.GetGCInfoSlotLifetimes(
ClrDataAddress ip,
uint count,
SOSGCSlotLifetime[]? lifetimes,
uint* pNeeded)
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants