diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 3cee2383c0..17bd2ffe62 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -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 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: \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: \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 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 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 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: * * * @@ -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)); diff --git a/src/shared/inc/sospriv.idl b/src/shared/inc/sospriv.idl index 141f597dcb..bc3d18d031 100644 --- a/src/shared/inc/sospriv.idl +++ b/src/shared/inc/sospriv.idl @@ -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 @@ -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); +} diff --git a/src/shared/pal/prebuilt/idl/sospriv_i.cpp b/src/shared/pal/prebuilt/idl/sospriv_i.cpp index 9e78203b96..9e11072b2f 100644 --- a/src/shared/pal/prebuilt/idl/sospriv_i.cpp +++ b/src/shared/pal/prebuilt/idl/sospriv_i.cpp @@ -139,6 +139,9 @@ 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 @@ -146,4 +149,3 @@ MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface17,0x2f4bb585,0xed50,0x479e,0xbb,0xe0, #endif - diff --git a/src/shared/pal/prebuilt/inc/sospriv.h b/src/shared/pal/prebuilt/inc/sospriv.h index 61c13f6895..ef90037888 100644 --- a/src/shared/pal/prebuilt/inc/sospriv.h +++ b/src/shared/pal/prebuilt/inc/sospriv.h @@ -462,7 +462,8 @@ typedef enum SOSStackSourceType { SOS_StackSourceIP = 0, - SOS_StackSourceFrame = ( SOS_StackSourceIP + 1 ) + SOS_StackSourceFrame = ( SOS_StackSourceIP + 1 ), + SOS_StackSourceOther = ( SOS_StackSourceFrame + 1 ) } SOSStackSourceType; typedef @@ -3767,9 +3768,8 @@ EXTERN_C const IID IID_ISOSDacInterface16; #ifndef _SOS_StressLogData #define _SOS_StressLogData - typedef struct _SOSStressLogData -{ + { unsigned int LoggedFacilities; unsigned int Level; unsigned int MaxSizePerThread; @@ -3778,33 +3778,31 @@ typedef struct _SOSStressLogData UINT64 TickFrequency; UINT64 StartTimestamp; UINT64 StartTime; -} SOSStressLogData; + } SOSStressLogData; -#endif //_SOS_StressLogData +#endif // _SOS_StressLogData #ifndef _SOS_ThreadStressLogData #define _SOS_ThreadStressLogData - typedef struct _SOSThreadStressLogData -{ + { CLRDATA_ADDRESS ThreadLogAddress; UINT64 ThreadId; -} SOSThreadStressLogData; + } SOSThreadStressLogData; -#endif //_SOS_ThreadStressLogData +#endif // _SOS_ThreadStressLogData #ifndef _SOS_StressMsgData #define _SOS_StressMsgData - typedef struct _SOSStressMsgData -{ + { unsigned int Facility; CLRDATA_ADDRESS FormatString; UINT64 Timestamp; unsigned int ArgumentCount; -} SOSStressMsgData; + } SOSStressMsgData; -#endif //_SOS_StressMsgData +#endif // _SOS_StressMsgData #ifndef __ISOSStressLogThreadEnum_INTERFACE_DEFINED__ #define __ISOSStressLogThreadEnum_INTERFACE_DEFINED__ @@ -3837,8 +3835,9 @@ EXTERN_C const IID IID_ISOSStressLogThreadEnum; HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISOSStressLogThreadEnum * This, - REFIID riid, - void **ppvObject); + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISOSStressLogThreadEnum * This); @@ -3848,14 +3847,14 @@ EXTERN_C const IID IID_ISOSStressLogThreadEnum; HRESULT ( STDMETHODCALLTYPE *Skip )( ISOSStressLogThreadEnum * This, - unsigned int count); + uint32_t count); HRESULT ( STDMETHODCALLTYPE *Reset )( ISOSStressLogThreadEnum * This); HRESULT ( STDMETHODCALLTYPE *GetCount )( ISOSStressLogThreadEnum * This, - unsigned int *pCount); + uint32_t *pCount); HRESULT ( STDMETHODCALLTYPE *Next )( ISOSStressLogThreadEnum * This, @@ -3871,8 +3870,42 @@ EXTERN_C const IID IID_ISOSStressLogThreadEnum; CONST_VTBL struct ISOSStressLogThreadEnumVtbl *lpVtbl; }; + + +#ifdef COBJMACROS + + +#define ISOSStressLogThreadEnum_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSStressLogThreadEnum_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSStressLogThreadEnum_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSStressLogThreadEnum_Skip(This,count) \ + ( (This)->lpVtbl -> Skip(This,count) ) + +#define ISOSStressLogThreadEnum_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) + +#define ISOSStressLogThreadEnum_GetCount(This,pCount) \ + ( (This)->lpVtbl -> GetCount(This,pCount) ) + + +#define ISOSStressLogThreadEnum_Next(This,count,values,pFetched) \ + ( (This)->lpVtbl -> Next(This,count,values,pFetched) ) + +#endif /* COBJMACROS */ + + #endif /* C style interface */ + + + #endif /* __ISOSStressLogThreadEnum_INTERFACE_DEFINED__ */ @@ -3913,8 +3946,9 @@ EXTERN_C const IID IID_ISOSStressLogMsgEnum; HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISOSStressLogMsgEnum * This, - REFIID riid, - void **ppvObject); + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISOSStressLogMsgEnum * This); @@ -3924,14 +3958,14 @@ EXTERN_C const IID IID_ISOSStressLogMsgEnum; HRESULT ( STDMETHODCALLTYPE *Skip )( ISOSStressLogMsgEnum * This, - unsigned int count); + uint32_t count); HRESULT ( STDMETHODCALLTYPE *Reset )( ISOSStressLogMsgEnum * This); HRESULT ( STDMETHODCALLTYPE *GetCount )( ISOSStressLogMsgEnum * This, - unsigned int *pCount); + uint32_t *pCount); HRESULT ( STDMETHODCALLTYPE *Next )( ISOSStressLogMsgEnum * This, @@ -3954,8 +3988,45 @@ EXTERN_C const IID IID_ISOSStressLogMsgEnum; CONST_VTBL struct ISOSStressLogMsgEnumVtbl *lpVtbl; }; + + +#ifdef COBJMACROS + + +#define ISOSStressLogMsgEnum_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSStressLogMsgEnum_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSStressLogMsgEnum_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSStressLogMsgEnum_Skip(This,count) \ + ( (This)->lpVtbl -> Skip(This,count) ) + +#define ISOSStressLogMsgEnum_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) + +#define ISOSStressLogMsgEnum_GetCount(This,pCount) \ + ( (This)->lpVtbl -> GetCount(This,pCount) ) + + +#define ISOSStressLogMsgEnum_Next(This,count,values,pFetched) \ + ( (This)->lpVtbl -> Next(This,count,values,pFetched) ) + +#define ISOSStressLogMsgEnum_GetArguments(This,messageIndex,argCount,args,pFetched) \ + ( (This)->lpVtbl -> GetArguments(This,messageIndex,argCount,args,pFetched) ) + +#endif /* COBJMACROS */ + + #endif /* C style interface */ + + + #endif /* __ISOSStressLogMsgEnum_INTERFACE_DEFINED__ */ @@ -3995,8 +4066,9 @@ EXTERN_C const IID IID_ISOSDacInterface17; HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISOSDacInterface17 * This, - REFIID riid, - void **ppvObject); + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ISOSDacInterface17 * This); @@ -4029,6 +4101,7 @@ EXTERN_C const IID IID_ISOSDacInterface17; #ifdef COBJMACROS + #define ISOSDacInterface17_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) @@ -4038,6 +4111,7 @@ EXTERN_C const IID IID_ISOSDacInterface17; #define ISOSDacInterface17_Release(This) \ ( (This)->lpVtbl -> Release(This) ) + #define ISOSDacInterface17_GetStressLogData(This,data) \ ( (This)->lpVtbl -> GetStressLogData(This,data) ) @@ -4053,9 +4127,184 @@ EXTERN_C const IID IID_ISOSDacInterface17; #endif /* C style interface */ + + #endif /* __ISOSDacInterface17_INTERFACE_DEFINED__ */ +#ifndef _SOS_GCInfoData +#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; + +#endif // _SOS_GCInfoData + +#ifndef __ISOSDacInterface18_INTERFACE_DEFINED__ +#define __ISOSDacInterface18_INTERFACE_DEFINED__ + +/* interface ISOSDacInterface18 */ +/* [uuid][local][object] */ + + +EXTERN_C const IID IID_ISOSDacInterface18; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3dccf95b-bca2-40ee-8b83-d8d7574a1df0") + ISOSDacInterface18 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetGCInfoHeader( + CLRDATA_ADDRESS ip, + SOSGCInfoHeader *header) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCInfoInterruptibleRanges( + CLRDATA_ADDRESS ip, + ULONG count, + SOSCodeRange *ranges, + ULONG *pNeeded) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCInfoSafePoints( + CLRDATA_ADDRESS ip, + ULONG count, + unsigned int *offsets, + ULONG *pNeeded) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCInfoSlotLifetimes( + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCSlotLifetime *lifetimes, + ULONG *pNeeded) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISOSDacInterface18Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISOSDacInterface18 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISOSDacInterface18 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISOSDacInterface18 * This); + + HRESULT ( STDMETHODCALLTYPE *GetGCInfoHeader )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + SOSGCInfoHeader *header); + + HRESULT ( STDMETHODCALLTYPE *GetGCInfoInterruptibleRanges )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + ULONG count, + SOSCodeRange *ranges, + ULONG *pNeeded); + + HRESULT ( STDMETHODCALLTYPE *GetGCInfoSafePoints )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + ULONG count, + unsigned int *offsets, + ULONG *pNeeded); + + HRESULT ( STDMETHODCALLTYPE *GetGCInfoSlotLifetimes )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCSlotLifetime *lifetimes, + ULONG *pNeeded); + + END_INTERFACE + } ISOSDacInterface18Vtbl; + + interface ISOSDacInterface18 + { + CONST_VTBL struct ISOSDacInterface18Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISOSDacInterface18_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSDacInterface18_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSDacInterface18_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSDacInterface18_GetGCInfoHeader(This,ip,header) \ + ( (This)->lpVtbl -> GetGCInfoHeader(This,ip,header) ) + +#define ISOSDacInterface18_GetGCInfoInterruptibleRanges(This,ip,count,ranges,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoInterruptibleRanges(This,ip,count,ranges,pNeeded) ) + +#define ISOSDacInterface18_GetGCInfoSafePoints(This,ip,count,offsets,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoSafePoints(This,ip,count,offsets,pNeeded) ) + +#define ISOSDacInterface18_GetGCInfoSlotLifetimes(This,ip,count,lifetimes,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoSlotLifetimes(This,ip,count,lifetimes,pNeeded) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISOSDacInterface18_INTERFACE_DEFINED__ */ + + /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ @@ -4066,4 +4315,3 @@ EXTERN_C const IID IID_ISOSDacInterface17; #endif - diff --git a/src/tests/SOS.UnitTests/Scripts/OtherCommands.script b/src/tests/SOS.UnitTests/Scripts/OtherCommands.script index eb7d49983c..5a15938672 100644 --- a/src/tests/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/tests/SOS.UnitTests/Scripts/OtherCommands.script @@ -99,8 +99,12 @@ SOSCOMMAND:IP2MD .*\s+()\s+SymbolTestApp\.Program\.Foo1.*\s+ VERIFY:.*\s+Method Name:\s+SymbolTestApp\.Program\.Foo1\(Int32, System\.String\)\s+ VERIFY:.*\s+Source file:\s+(?i:.*[\\|/]SymbolTestApp\.cs) @ 27\s+ -# Verify DumpMD -SOSCOMMAND:DumpMD \s+MethodDesc:\s+()\s+ +# Verify GCInfo (uses MethodDesc from IP2MD) +SOSCOMMAND:GCInfo \s+MethodDesc:\s+()\s+ +VERIFY:.*Code size:\s+[0-9a-fA-F]+\s* + +# Verify DumpMD (reuse MethodDesc captured by GCInfo's POUT above) +SOSCOMMAND:DumpMD VERIFY:.*\s+Method Name:\s+SymbolTestApp\.Program\.Foo1\(Int32, System\.String\)\s+ # Verify DumpClass