Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions src/SOS/Strike/strike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6689,6 +6689,172 @@ DECLARE_API(EHInfo)
return Status;
}

// Try to dump GC info using ISOSDacInterface18 (cDAC path).
// Returns S_OK if successful, or an error HRESULT if the interface is not available or fails.
static HRESULT TryDumpGCInfoViaInterface18(CLRDATA_ADDRESS ip)
{
ReleaseHolder<ISOSDacInterface18> pSos18;
HRESULT hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface18), (void**)&pSos18);
if (FAILED(hr) || pSos18 == NULL)
return E_NOINTERFACE;

// Get GC register names for the target platform
LPCSTR* gcRegNames = nullptr;
unsigned int gcRegCount = 0;
g_targetMachine->GetGCRegisters(&gcRegNames, &gcRegCount);

auto getRegName = [&](unsigned int regNum) -> const char* {
if (regNum < gcRegCount && gcRegNames != nullptr)
return gcRegNames[regNum];
return "???";
};

// Get the header
SOSGCInfoHeader header = {};
hr = pSos18->GetGCInfoHeader(ip, &header);
if (FAILED(hr))
return hr;

// Print header in legacy format
if (header.GenericsInstContextIsPresent)
ExtOut("GenericInst slot: sp%+d (kind=%u)\n", header.GenericsInstContextStackSlot, header.GenericsInstContextKind);
else
ExtOut("GenericInst slot: <none>\n");
ExtOut("Varargs: %d\n", header.IsVarArg ? 1 : 0);
if (header.StackBaseRegister != 0xFFFFFFFF)
ExtOut("Frame pointer: %s\n", getRegName(header.StackBaseRegister));
else
ExtOut("Frame pointer: <none>\n");
ExtOut("Wants Report Only Leaf: %d\n", header.WantsReportOnlyLeaf ? 1 : 0);
ExtOut("Size of parameter area: %x\n", header.SizeOfStackParameterArea);
if (header.GSCookieIsPresent)
ExtOut("GS Cookie: sp%+d, valid range [%04x, %04x)\n", header.GSCookieStackSlot, header.GSCookieValidRangeStart, header.GSCookieValidRangeEnd);
if (header.PSPSymIsPresent)
ExtOut("PSP sym: sp%+d\n", header.PSPSymStackSlot);
ExtOut("Has Tail Calls: %d\n", header.HasTailCalls ? 1 : 0);
ExtOut("Code size: %x\n", header.CodeSize);

// Get interruptible ranges
ULONG rangeCount = 0;
hr = pSos18->GetGCInfoInterruptibleRanges(ip, 0, nullptr, &rangeCount);
ArrayHolder<SOSCodeRange> ranges = nullptr;
if (SUCCEEDED(hr) && rangeCount > 0)
{
ranges = new NOTHROW SOSCodeRange[rangeCount];
if (ranges != NULL)
{
ULONG fetched = 0;
pSos18->GetGCInfoInterruptibleRanges(ip, rangeCount, ranges, &fetched);
rangeCount = fetched;
}
}

// Get slot lifetimes
ULONG slotCount = 0;
hr = pSos18->GetGCInfoSlotLifetimes(ip, 0, nullptr, &slotCount);
ArrayHolder<SOSGCSlotLifetime> slots = nullptr;
if (SUCCEEDED(hr) && slotCount > 0)
{
slots = new NOTHROW SOSGCSlotLifetime[slotCount];
if (slots != NULL)
{
ULONG fetched = 0;
pSos18->GetGCInfoSlotLifetimes(ip, slotCount, slots, &fetched);
slotCount = fetched;
}
}

const char* frameRegName = (header.StackBaseRegister != 0xFFFFFFFF) ? getRegName(header.StackBaseRegister) : "sp";

// Print untracked slots (those with BeginOffset=0, EndOffset=CodeSize)
if (slots != NULL)
{
for (ULONG i = 0; i < slotCount; i++)
{
if (slots[i].BeginOffset == 0 && slots[i].EndOffset == header.CodeSize)
{
if (slots[i].IsRegister)
ExtOut("Untracked: %s%s\n", slots[i].GcFlags & 0x2 ? "pinned " : "", getRegName(slots[i].RegisterNumber));
else
ExtOut("Untracked: %s+%s%+d\n", slots[i].GcFlags & 0x2 ? "pinned " : "", frameRegName, slots[i].SpOffset);
}
}
}

// Build timeline: interleave interruptible range transitions and slot live/dead transitions
// sorted by code offset
struct TimelineEvent
{
unsigned int offset;
int type; // 0=interruptible start, 1=interruptible end, 2=slot live, 3=slot dead
ULONG slotIndex;
};

std::vector<TimelineEvent> events;

if (ranges != NULL)
{
for (ULONG i = 0; i < rangeCount; i++)
{
events.push_back({ranges[i].BeginOffset, 0, 0});
events.push_back({ranges[i].EndOffset, 1, 0});
}
}

if (slots != NULL)
{
for (ULONG i = 0; i < slotCount; i++)
{
// Skip untracked (already printed above)
if (slots[i].BeginOffset == 0 && slots[i].EndOffset == header.CodeSize)
continue;
events.push_back({slots[i].BeginOffset, 2, i});
events.push_back({slots[i].EndOffset, 3, i});
}
}

// Sort by offset, then by type (interruptible transitions first)
std::sort(events.begin(), events.end(), [](const TimelineEvent& a, const TimelineEvent& b) {
if (a.offset != b.offset) return a.offset < b.offset;
return a.type < b.type;
});

// Print timeline
for (const auto& ev : events)
{
switch (ev.type)
{
case 0:
ExtOut("%08x interruptible\n", ev.offset);
break;
case 1:
ExtOut("%08x not interruptible\n", ev.offset);
break;
case 2:
{
const SOSGCSlotLifetime& s = slots[ev.slotIndex];
const char* prefix = s.GcFlags & 0x1 ? "&" : "+";
if (s.IsRegister)
ExtOut("%08x %s%s%s\n", ev.offset, s.GcFlags & 0x2 ? "pinned " : "", prefix, getRegName(s.RegisterNumber));
else
ExtOut("%08x %s%s%s%+d\n", ev.offset, s.GcFlags & 0x2 ? "pinned " : "", prefix, frameRegName, s.SpOffset);
break;
}
case 3:
{
const SOSGCSlotLifetime& s = slots[ev.slotIndex];
if (s.IsRegister)
ExtOut("%08x -%s\n", ev.offset, getRegName(s.RegisterNumber));
else
ExtOut("%08x -%s%+d\n", ev.offset, frameRegName, s.SpOffset);
break;
}
}
}

return S_OK;
}

/**********************************************************************\
* Routine Description: *
* *
Expand Down Expand Up @@ -6784,6 +6950,15 @@ DECLARE_API(GCInfo)
ExtOut("preJIT generated code\n");
}

// Try the new ISOSDacInterface18 path first (cDAC)
{
CLRDATA_ADDRESS methodIP = TO_CDADDR(codeHeaderData.MethodStart);
HRESULT hr18 = TryDumpGCInfoViaInterface18(methodIP);
if (SUCCEEDED(hr18))
return Status;
// Fall through to legacy raw-bytes path if Interface18 is not available
}

taGCInfoAddr = TO_TADDR(codeHeaderData.GCInfo);

ExtOut("GC info %p\n", SOS_PTR(taGCInfoAddr));
Expand Down
173 changes: 173 additions & 0 deletions src/shared/inc/sospriv.idl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ typedef enum SOSStackSourceType
{
SOS_StackSourceIP, // Instruction pointer in managed code
SOS_StackSourceFrame, // clr!Frame
SOS_StackSourceOther, // Roots which do not come from managed code or Frames
} SOSStackSourceType;

typedef enum SOSRefFlags
Expand Down Expand Up @@ -562,3 +563,175 @@ interface ISOSDacInterface15 : IUnknown
{
HRESULT GetMethodTableSlotEnumerator(CLRDATA_ADDRESS mt, ISOSMethodEnum **enumerator);
}

[
object,
local,
uuid(4ba12ff8-daac-4e43-ac56-98cf8d5c595d)
]
interface ISOSDacInterface16 : IUnknown
{
HRESULT GetGCDynamicAdaptationMode(int* pDynamicAdaptationMode);
}

cpp_quote("#ifndef _SOS_StressLogData")
cpp_quote("#define _SOS_StressLogData")

typedef struct _SOSStressLogData
{
unsigned int LoggedFacilities;
unsigned int Level;
unsigned int MaxSizePerThread;
unsigned int MaxSizeTotal;
int TotalChunks;
UINT64 TickFrequency;
UINT64 StartTimestamp;
UINT64 StartTime;
} SOSStressLogData;

cpp_quote("#endif //_SOS_StressLogData")

cpp_quote("#ifndef _SOS_ThreadStressLogData")
cpp_quote("#define _SOS_ThreadStressLogData")

typedef struct _SOSThreadStressLogData
{
CLRDATA_ADDRESS ThreadLogAddress;
UINT64 ThreadId;
} SOSThreadStressLogData;

cpp_quote("#endif //_SOS_ThreadStressLogData")

cpp_quote("#ifndef _SOS_StressMsgData")
cpp_quote("#define _SOS_StressMsgData")

typedef struct _SOSStressMsgData
{
unsigned int Facility;
CLRDATA_ADDRESS FormatString;
UINT64 Timestamp;
unsigned int ArgumentCount;
} SOSStressMsgData;

cpp_quote("#endif //_SOS_StressMsgData")

[
object,
local,
uuid(94a2bd3d-ab3d-43bf-81d8-3ae96b8e33cd)
]
interface ISOSStressLogThreadEnum : ISOSEnum
{
HRESULT Next([in] unsigned int count,
[out, size_is(count), length_is(*pFetched)] SOSThreadStressLogData values[],
[out] unsigned int *pFetched);
}

[
object,
local,
uuid(437cb033-afe7-4c0f-a4a7-82c891bc049e)
]
interface ISOSStressLogMsgEnum : ISOSEnum
{
HRESULT Next([in] unsigned int count,
[out, size_is(count), length_is(*pFetched)] SOSStressMsgData values[],
[out] unsigned int *pFetched);

HRESULT GetArguments([in] unsigned int messageIndex,
[in] unsigned int argCount,
[out, size_is(argCount), length_is(*pFetched)] CLRDATA_ADDRESS args[],
[out] unsigned int *pFetched);
}

[
object,
local,
uuid(2f4bb585-ed50-479e-bbe0-10a95a5da3bb)
]
interface ISOSDacInterface17 : IUnknown
{
HRESULT GetStressLogData([out] SOSStressLogData *data);
HRESULT GetStressLogThreadEnumerator([out] ISOSStressLogThreadEnum **ppEnum);
HRESULT GetStressLogMessageEnumerator([in] CLRDATA_ADDRESS threadStressLogAddress,
[out] ISOSStressLogMsgEnum **ppEnum);
}

cpp_quote("#ifndef _SOS_GCInfoData")
cpp_quote("#define _SOS_GCInfoData")

typedef struct _SOSCodeRange
{
unsigned int BeginOffset;
unsigned int EndOffset;
} SOSCodeRange;

typedef struct _SOSGCInfoHeader
{
ULONG SizeOf;

unsigned int GcInfoVersion;
unsigned int CodeSize;
unsigned int PrologSize;
unsigned int StackBaseRegister;
unsigned int SizeOfStackParameterArea;

BOOL IsVarArg;
BOOL WantsReportOnlyLeaf;
BOOL HasTailCalls;

BOOL GSCookieIsPresent;
int GSCookieStackSlot;
unsigned int GSCookieValidRangeStart;
unsigned int GSCookieValidRangeEnd;

BOOL PSPSymIsPresent;
int PSPSymStackSlot;

BOOL GenericsInstContextIsPresent;
int GenericsInstContextStackSlot;
unsigned int GenericsInstContextKind;
} SOSGCInfoHeader;

typedef struct _SOSGCSlotLifetime
{
unsigned int BeginOffset;
unsigned int EndOffset;
int IsRegister;
unsigned int RegisterNumber;
int SpOffset;
unsigned int BaseRegister;
unsigned int GcFlags;
} SOSGCSlotLifetime;

cpp_quote("#endif //_SOS_GCInfoData")

[
object,
local,
uuid(3dccf95b-bca2-40ee-8b83-d8d7574a1df0)
]
interface ISOSDacInterface18 : IUnknown
{
HRESULT GetGCInfoHeader(
[in] CLRDATA_ADDRESS ip,
[in, out] SOSGCInfoHeader* header);

HRESULT GetGCInfoInterruptibleRanges(
[in] CLRDATA_ADDRESS ip,
[in] ULONG count,
[out, size_is(count), length_is(*pNeeded)] SOSCodeRange* ranges,
[out] ULONG* pNeeded);

HRESULT GetGCInfoSafePoints(
[in] CLRDATA_ADDRESS ip,
[in] ULONG count,
[out, size_is(count), length_is(*pNeeded)] unsigned int* offsets,
[out] ULONG* pNeeded);

HRESULT GetGCInfoSlotLifetimes(
[in] CLRDATA_ADDRESS ip,
[in] ULONG count,
[out, size_is(count), length_is(*pNeeded)] SOSGCSlotLifetime* lifetimes,
[out] ULONG* pNeeded);
}
4 changes: 3 additions & 1 deletion src/shared/pal/prebuilt/idl/sospriv_i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,13 @@ MIDL_DEFINE_GUID(IID, IID_ISOSStressLogMsgEnum,0x437cb033,0xafe7,0x4c0f,0xa4,0xa

MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface17,0x2f4bb585,0xed50,0x479e,0xbb,0xe0,0x10,0xa9,0x5a,0x5d,0xa3,0xbb);


MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface18,0x3dccf95b,0xbca2,0x40ee,0x8b,0x83,0xd8,0xd7,0x57,0x4a,0x1d,0xf0);

#undef MIDL_DEFINE_GUID

#ifdef __cplusplus
}
#endif



Loading
Loading