From 3b97e9dd04894e07b43c14ef309845eadf002c85 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Tue, 23 Jun 2026 16:22:54 -0400 Subject: [PATCH 1/2] Use ISOSDacInterface18 for GCInfo when available Add ISOSDacInterface18 consumption in !GCInfo command with fallback to the existing raw-bytes decoding path when the interface is not available (non-cDAC scenarios). The new path queries the cDAC for: - GC info header (code size, prolog, stack base, etc.) - Interruptible ranges - Safe points - Register lifetimes - Stack slot lifetimes Also adds a basic GCInfo verification to OtherCommands.script. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/SOS/Strike/strike.cpp | 121 +++++++ src/shared/inc/sospriv.idl | 186 ++++++++++ src/shared/pal/prebuilt/idl/sospriv_i.cpp | 4 +- src/shared/pal/prebuilt/inc/sospriv.h | 319 ++++++++++++++++-- .../Scripts/OtherCommands.script | 5 + 5 files changed, 610 insertions(+), 25 deletions(-) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 3cee2383c0..a7d6658afc 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -6689,6 +6689,118 @@ 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 and print the header + SOSGCInfoHeader header = {}; + hr = pSos18->GetGCInfoHeader(ip, &header); + if (FAILED(hr)) + return hr; + + ExtOut("GC Info Header:\n"); + ExtOut(" GcInfoVersion: %u\n", header.GcInfoVersion); + ExtOut(" CodeSize: %u (0x%x)\n", header.CodeSize, header.CodeSize); + ExtOut(" PrologSize: %u\n", header.PrologSize); + ExtOut(" StackBaseRegister: %u\n", header.StackBaseRegister); + ExtOut(" SizeOfStackParameterArea: %u\n", header.SizeOfStackParameterArea); + ExtOut(" ReturnKind: %u\n", header.ReturnKind); + ExtOut(" IsVarArg: %s\n", header.IsVarArg ? "true" : "false"); + ExtOut(" WantsReportOnlyLeaf: %s\n", header.WantsReportOnlyLeaf ? "true" : "false"); + ExtOut(" HasTailCalls: %s\n", header.HasTailCalls ? "true" : "false"); + if (header.GSCookieIsPresent) + ExtOut(" GS Cookie: slot %d, valid range [%u, %u]\n", header.GSCookieStackSlot, header.GSCookieValidRangeStart, header.GSCookieValidRangeEnd); + if (header.PSPSymIsPresent) + ExtOut(" PSP Sym: slot %d\n", header.PSPSymStackSlot); + if (header.GenericsInstContextIsPresent) + ExtOut(" Generics Inst Context: slot %d, kind %u\n", header.GenericsInstContextStackSlot, header.GenericsInstContextKind); + + // Get and print interruptible ranges + ULONG rangeCount = 0; + hr = pSos18->GetGCInfoInterruptibleRanges(ip, 0, nullptr, &rangeCount); + if (SUCCEEDED(hr) && rangeCount > 0) + { + ExtOut("\nInterruptible Ranges (%u):\n", rangeCount); + ArrayHolder ranges = new NOTHROW SOSCodeRange[rangeCount]; + if (ranges != NULL) + { + ULONG fetched = 0; + hr = pSos18->GetGCInfoInterruptibleRanges(ip, rangeCount, ranges, &fetched); + if (SUCCEEDED(hr)) + { + for (ULONG i = 0; i < fetched; i++) + ExtOut(" [0x%04x - 0x%04x)\n", ranges[i].BeginOffset, ranges[i].EndOffset); + } + } + } + + // Get and print safe points + ULONG safePointCount = 0; + hr = pSos18->GetGCInfoSafePoints(ip, 0, nullptr, &safePointCount); + if (SUCCEEDED(hr) && safePointCount > 0) + { + ExtOut("\nSafe Points (%u):\n", safePointCount); + ArrayHolder offsets = new NOTHROW unsigned int[safePointCount]; + if (offsets != NULL) + { + ULONG fetched = 0; + hr = pSos18->GetGCInfoSafePoints(ip, safePointCount, offsets, &fetched); + if (SUCCEEDED(hr)) + { + for (ULONG i = 0; i < fetched; i++) + ExtOut(" 0x%04x\n", offsets[i]); + } + } + } + + // Get and print register lifetimes + ULONG regCount = 0; + hr = pSos18->GetGCInfoRegisterLifetimes(ip, 0, nullptr, ®Count); + if (SUCCEEDED(hr) && regCount > 0) + { + ExtOut("\nRegister Lifetimes (%u):\n", regCount); + ArrayHolder regs = new NOTHROW SOSGCRegisterLifetime[regCount]; + if (regs != NULL) + { + ULONG fetched = 0; + hr = pSos18->GetGCInfoRegisterLifetimes(ip, regCount, regs, &fetched); + if (SUCCEEDED(hr)) + { + for (ULONG i = 0; i < fetched; i++) + ExtOut(" reg %u [0x%04x - 0x%04x) flags=0x%x\n", regs[i].RegisterNumber, regs[i].BeginOffset, regs[i].EndOffset, regs[i].GcFlags); + } + } + } + + // Get and print stack slot lifetimes + ULONG stackCount = 0; + hr = pSos18->GetGCInfoStackSlotLifetimes(ip, 0, nullptr, &stackCount); + if (SUCCEEDED(hr) && stackCount > 0) + { + ExtOut("\nStack Slot Lifetimes (%u):\n", stackCount); + ArrayHolder stacks = new NOTHROW SOSGCStackSlotLifetime[stackCount]; + if (stacks != NULL) + { + ULONG fetched = 0; + hr = pSos18->GetGCInfoStackSlotLifetimes(ip, stackCount, stacks, &fetched); + if (SUCCEEDED(hr)) + { + for (ULONG i = 0; i < fetched; i++) + ExtOut(" sp%+d base=%u [0x%04x - 0x%04x) flags=0x%x\n", stacks[i].SpOffset, stacks[i].BaseRegister, stacks[i].BeginOffset, stacks[i].EndOffset, stacks[i].GcFlags); + } + } + } + + ExtOut("\n"); + return S_OK; +} + /**********************************************************************\ * Routine Description: * * * @@ -6784,6 +6896,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..4e96d84819 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,188 @@ 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; + unsigned int ReturnKind; + + 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 _SOSGCRegisterLifetime +{ + unsigned int BeginOffset; + unsigned int EndOffset; + unsigned int RegisterNumber; + unsigned int GcFlags; +} SOSGCRegisterLifetime; + +typedef struct _SOSGCStackSlotLifetime +{ + unsigned int BeginOffset; + unsigned int EndOffset; + int SpOffset; + unsigned int BaseRegister; + unsigned int GcFlags; +} SOSGCStackSlotLifetime; + +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 GetGCInfoRegisterLifetimes( + [in] CLRDATA_ADDRESS ip, + [in] ULONG count, + [out, size_is(count), length_is(*pNeeded)] SOSGCRegisterLifetime* lifetimes, + [out] ULONG* pNeeded); + + HRESULT GetGCInfoStackSlotLifetimes( + [in] CLRDATA_ADDRESS ip, + [in] ULONG count, + [out, size_is(count), length_is(*pNeeded)] SOSGCStackSlotLifetime* 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..d3d1ac8261 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,207 @@ 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; + unsigned int ReturnKind; + 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 _SOSGCRegisterLifetime + { + unsigned int BeginOffset; + unsigned int EndOffset; + unsigned int RegisterNumber; + unsigned int GcFlags; + } SOSGCRegisterLifetime; + +typedef struct _SOSGCStackSlotLifetime + { + unsigned int BeginOffset; + unsigned int EndOffset; + int SpOffset; + unsigned int BaseRegister; + unsigned int GcFlags; + } SOSGCStackSlotLifetime; + +#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 GetGCInfoRegisterLifetimes( + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCRegisterLifetime *lifetimes, + ULONG *pNeeded) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCInfoStackSlotLifetimes( + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCStackSlotLifetime *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 *GetGCInfoRegisterLifetimes )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCRegisterLifetime *lifetimes, + ULONG *pNeeded); + + HRESULT ( STDMETHODCALLTYPE *GetGCInfoStackSlotLifetimes )( + ISOSDacInterface18 * This, + CLRDATA_ADDRESS ip, + ULONG count, + SOSGCStackSlotLifetime *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_GetGCInfoRegisterLifetimes(This,ip,count,lifetimes,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoRegisterLifetimes(This,ip,count,lifetimes,pNeeded) ) + +#define ISOSDacInterface18_GetGCInfoStackSlotLifetimes(This,ip,count,lifetimes,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoStackSlotLifetimes(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 +4338,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..d7309bdd96 100644 --- a/src/tests/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/tests/SOS.UnitTests/Scripts/OtherCommands.script @@ -99,6 +99,11 @@ 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 GCInfo (uses MethodDesc from IP2MD) +SOSCOMMAND:GCInfo \s+MethodDesc:\s+()\s+ +VERIFY:.*GC Info Header:\s* +VERIFY:.*CodeSize:\s+\d+.* + # Verify DumpMD SOSCOMMAND:DumpMD \s+MethodDesc:\s+()\s+ VERIFY:.*\s+Method Name:\s+SymbolTestApp\.Program\.Foo1\(Int32, System\.String\)\s+ From 26a0263cff4f18aa3918b51da60eadd869f01a04 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 24 Jun 2026 19:01:22 -0400 Subject: [PATCH 2/2] Update ISOSDacInterface18 to unified slot lifetime API with timeline output - Replace SOSGCRegisterLifetime + SOSGCStackSlotLifetime with unified SOSGCSlotLifetime struct - Replace GetGCInfoRegisterLifetimes + GetGCInfoStackSlotLifetimes with single GetGCInfoSlotLifetimes - Remove ReturnKind from SOSGCInfoHeader (matches runtime change) - TryDumpGCInfoViaInterface18 now outputs legacy-compatible timeline format: header fields, untracked slots, then chronological interruptible/slot events - Update OtherCommands.script GCInfo verification to match timeline output Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/SOS/Strike/strike.cpp | 182 ++++++++++++------ src/shared/inc/sospriv.idl | 23 +-- src/shared/pal/prebuilt/inc/sospriv.h | 41 +--- .../Scripts/OtherCommands.script | 7 +- 4 files changed, 135 insertions(+), 118 deletions(-) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index a7d6658afc..17bd2ffe62 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -6698,106 +6698,160 @@ static HRESULT TryDumpGCInfoViaInterface18(CLRDATA_ADDRESS ip) if (FAILED(hr) || pSos18 == NULL) return E_NOINTERFACE; - // Get and print the header + // 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; - ExtOut("GC Info Header:\n"); - ExtOut(" GcInfoVersion: %u\n", header.GcInfoVersion); - ExtOut(" CodeSize: %u (0x%x)\n", header.CodeSize, header.CodeSize); - ExtOut(" PrologSize: %u\n", header.PrologSize); - ExtOut(" StackBaseRegister: %u\n", header.StackBaseRegister); - ExtOut(" SizeOfStackParameterArea: %u\n", header.SizeOfStackParameterArea); - ExtOut(" ReturnKind: %u\n", header.ReturnKind); - ExtOut(" IsVarArg: %s\n", header.IsVarArg ? "true" : "false"); - ExtOut(" WantsReportOnlyLeaf: %s\n", header.WantsReportOnlyLeaf ? "true" : "false"); - ExtOut(" HasTailCalls: %s\n", header.HasTailCalls ? "true" : "false"); + // 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: slot %d, valid range [%u, %u]\n", header.GSCookieStackSlot, header.GSCookieValidRangeStart, header.GSCookieValidRangeEnd); + ExtOut("GS Cookie: sp%+d, valid range [%04x, %04x)\n", header.GSCookieStackSlot, header.GSCookieValidRangeStart, header.GSCookieValidRangeEnd); if (header.PSPSymIsPresent) - ExtOut(" PSP Sym: slot %d\n", header.PSPSymStackSlot); - if (header.GenericsInstContextIsPresent) - ExtOut(" Generics Inst Context: slot %d, kind %u\n", header.GenericsInstContextStackSlot, header.GenericsInstContextKind); + 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 and print interruptible ranges + // Get interruptible ranges ULONG rangeCount = 0; hr = pSos18->GetGCInfoInterruptibleRanges(ip, 0, nullptr, &rangeCount); + ArrayHolder ranges = nullptr; if (SUCCEEDED(hr) && rangeCount > 0) { - ExtOut("\nInterruptible Ranges (%u):\n", rangeCount); - ArrayHolder ranges = new NOTHROW SOSCodeRange[rangeCount]; + ranges = new NOTHROW SOSCodeRange[rangeCount]; if (ranges != NULL) { ULONG fetched = 0; - hr = pSos18->GetGCInfoInterruptibleRanges(ip, rangeCount, ranges, &fetched); - if (SUCCEEDED(hr)) - { - for (ULONG i = 0; i < fetched; i++) - ExtOut(" [0x%04x - 0x%04x)\n", ranges[i].BeginOffset, ranges[i].EndOffset); - } + pSos18->GetGCInfoInterruptibleRanges(ip, rangeCount, ranges, &fetched); + rangeCount = fetched; } } - // Get and print safe points - ULONG safePointCount = 0; - hr = pSos18->GetGCInfoSafePoints(ip, 0, nullptr, &safePointCount); - if (SUCCEEDED(hr) && safePointCount > 0) + // Get slot lifetimes + ULONG slotCount = 0; + hr = pSos18->GetGCInfoSlotLifetimes(ip, 0, nullptr, &slotCount); + ArrayHolder slots = nullptr; + if (SUCCEEDED(hr) && slotCount > 0) { - ExtOut("\nSafe Points (%u):\n", safePointCount); - ArrayHolder offsets = new NOTHROW unsigned int[safePointCount]; - if (offsets != NULL) + slots = new NOTHROW SOSGCSlotLifetime[slotCount]; + if (slots != NULL) { ULONG fetched = 0; - hr = pSos18->GetGCInfoSafePoints(ip, safePointCount, offsets, &fetched); - if (SUCCEEDED(hr)) - { - for (ULONG i = 0; i < fetched; i++) - ExtOut(" 0x%04x\n", offsets[i]); - } + pSos18->GetGCInfoSlotLifetimes(ip, slotCount, slots, &fetched); + slotCount = fetched; } } - // Get and print register lifetimes - ULONG regCount = 0; - hr = pSos18->GetGCInfoRegisterLifetimes(ip, 0, nullptr, ®Count); - if (SUCCEEDED(hr) && regCount > 0) + const char* frameRegName = (header.StackBaseRegister != 0xFFFFFFFF) ? getRegName(header.StackBaseRegister) : "sp"; + + // Print untracked slots (those with BeginOffset=0, EndOffset=CodeSize) + if (slots != NULL) { - ExtOut("\nRegister Lifetimes (%u):\n", regCount); - ArrayHolder regs = new NOTHROW SOSGCRegisterLifetime[regCount]; - if (regs != NULL) + for (ULONG i = 0; i < slotCount; i++) { - ULONG fetched = 0; - hr = pSos18->GetGCInfoRegisterLifetimes(ip, regCount, regs, &fetched); - if (SUCCEEDED(hr)) + if (slots[i].BeginOffset == 0 && slots[i].EndOffset == header.CodeSize) { - for (ULONG i = 0; i < fetched; i++) - ExtOut(" reg %u [0x%04x - 0x%04x) flags=0x%x\n", regs[i].RegisterNumber, regs[i].BeginOffset, regs[i].EndOffset, regs[i].GcFlags); + 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); } } } - // Get and print stack slot lifetimes - ULONG stackCount = 0; - hr = pSos18->GetGCInfoStackSlotLifetimes(ip, 0, nullptr, &stackCount); - if (SUCCEEDED(hr) && stackCount > 0) + // 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) { - ExtOut("\nStack Slot Lifetimes (%u):\n", stackCount); - ArrayHolder stacks = new NOTHROW SOSGCStackSlotLifetime[stackCount]; - if (stacks != NULL) + for (ULONG i = 0; i < rangeCount; i++) { - ULONG fetched = 0; - hr = pSos18->GetGCInfoStackSlotLifetimes(ip, stackCount, stacks, &fetched); - if (SUCCEEDED(hr)) - { - for (ULONG i = 0; i < fetched; i++) - ExtOut(" sp%+d base=%u [0x%04x - 0x%04x) flags=0x%x\n", stacks[i].SpOffset, stacks[i].BaseRegister, stacks[i].BeginOffset, stacks[i].EndOffset, stacks[i].GcFlags); - } + 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; + } } } - ExtOut("\n"); return S_OK; } diff --git a/src/shared/inc/sospriv.idl b/src/shared/inc/sospriv.idl index 4e96d84819..bc3d18d031 100644 --- a/src/shared/inc/sospriv.idl +++ b/src/shared/inc/sospriv.idl @@ -675,7 +675,6 @@ typedef struct _SOSGCInfoHeader unsigned int PrologSize; unsigned int StackBaseRegister; unsigned int SizeOfStackParameterArea; - unsigned int ReturnKind; BOOL IsVarArg; BOOL WantsReportOnlyLeaf; @@ -694,22 +693,16 @@ typedef struct _SOSGCInfoHeader unsigned int GenericsInstContextKind; } SOSGCInfoHeader; -typedef struct _SOSGCRegisterLifetime +typedef struct _SOSGCSlotLifetime { unsigned int BeginOffset; unsigned int EndOffset; + int IsRegister; unsigned int RegisterNumber; - unsigned int GcFlags; -} SOSGCRegisterLifetime; - -typedef struct _SOSGCStackSlotLifetime -{ - unsigned int BeginOffset; - unsigned int EndOffset; int SpOffset; unsigned int BaseRegister; unsigned int GcFlags; -} SOSGCStackSlotLifetime; +} SOSGCSlotLifetime; cpp_quote("#endif //_SOS_GCInfoData") @@ -736,15 +729,9 @@ interface ISOSDacInterface18 : IUnknown [out, size_is(count), length_is(*pNeeded)] unsigned int* offsets, [out] ULONG* pNeeded); - HRESULT GetGCInfoRegisterLifetimes( - [in] CLRDATA_ADDRESS ip, - [in] ULONG count, - [out, size_is(count), length_is(*pNeeded)] SOSGCRegisterLifetime* lifetimes, - [out] ULONG* pNeeded); - - HRESULT GetGCInfoStackSlotLifetimes( + HRESULT GetGCInfoSlotLifetimes( [in] CLRDATA_ADDRESS ip, [in] ULONG count, - [out, size_is(count), length_is(*pNeeded)] SOSGCStackSlotLifetime* lifetimes, + [out, size_is(count), length_is(*pNeeded)] SOSGCSlotLifetime* lifetimes, [out] ULONG* pNeeded); } diff --git a/src/shared/pal/prebuilt/inc/sospriv.h b/src/shared/pal/prebuilt/inc/sospriv.h index d3d1ac8261..ef90037888 100644 --- a/src/shared/pal/prebuilt/inc/sospriv.h +++ b/src/shared/pal/prebuilt/inc/sospriv.h @@ -4148,7 +4148,6 @@ typedef struct _SOSGCInfoHeader unsigned int PrologSize; unsigned int StackBaseRegister; unsigned int SizeOfStackParameterArea; - unsigned int ReturnKind; BOOL IsVarArg; BOOL WantsReportOnlyLeaf; BOOL HasTailCalls; @@ -4163,22 +4162,16 @@ typedef struct _SOSGCInfoHeader unsigned int GenericsInstContextKind; } SOSGCInfoHeader; -typedef struct _SOSGCRegisterLifetime +typedef struct _SOSGCSlotLifetime { unsigned int BeginOffset; unsigned int EndOffset; + int IsRegister; unsigned int RegisterNumber; - unsigned int GcFlags; - } SOSGCRegisterLifetime; - -typedef struct _SOSGCStackSlotLifetime - { - unsigned int BeginOffset; - unsigned int EndOffset; int SpOffset; unsigned int BaseRegister; unsigned int GcFlags; - } SOSGCStackSlotLifetime; + } SOSGCSlotLifetime; #endif // _SOS_GCInfoData @@ -4213,16 +4206,10 @@ EXTERN_C const IID IID_ISOSDacInterface18; unsigned int *offsets, ULONG *pNeeded) = 0; - virtual HRESULT STDMETHODCALLTYPE GetGCInfoRegisterLifetimes( + virtual HRESULT STDMETHODCALLTYPE GetGCInfoSlotLifetimes( CLRDATA_ADDRESS ip, ULONG count, - SOSGCRegisterLifetime *lifetimes, - ULONG *pNeeded) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetGCInfoStackSlotLifetimes( - CLRDATA_ADDRESS ip, - ULONG count, - SOSGCStackSlotLifetime *lifetimes, + SOSGCSlotLifetime *lifetimes, ULONG *pNeeded) = 0; }; @@ -4265,18 +4252,11 @@ EXTERN_C const IID IID_ISOSDacInterface18; unsigned int *offsets, ULONG *pNeeded); - HRESULT ( STDMETHODCALLTYPE *GetGCInfoRegisterLifetimes )( + HRESULT ( STDMETHODCALLTYPE *GetGCInfoSlotLifetimes )( ISOSDacInterface18 * This, CLRDATA_ADDRESS ip, ULONG count, - SOSGCRegisterLifetime *lifetimes, - ULONG *pNeeded); - - HRESULT ( STDMETHODCALLTYPE *GetGCInfoStackSlotLifetimes )( - ISOSDacInterface18 * This, - CLRDATA_ADDRESS ip, - ULONG count, - SOSGCStackSlotLifetime *lifetimes, + SOSGCSlotLifetime *lifetimes, ULONG *pNeeded); END_INTERFACE @@ -4311,11 +4291,8 @@ EXTERN_C const IID IID_ISOSDacInterface18; #define ISOSDacInterface18_GetGCInfoSafePoints(This,ip,count,offsets,pNeeded) \ ( (This)->lpVtbl -> GetGCInfoSafePoints(This,ip,count,offsets,pNeeded) ) -#define ISOSDacInterface18_GetGCInfoRegisterLifetimes(This,ip,count,lifetimes,pNeeded) \ - ( (This)->lpVtbl -> GetGCInfoRegisterLifetimes(This,ip,count,lifetimes,pNeeded) ) - -#define ISOSDacInterface18_GetGCInfoStackSlotLifetimes(This,ip,count,lifetimes,pNeeded) \ - ( (This)->lpVtbl -> GetGCInfoStackSlotLifetimes(This,ip,count,lifetimes,pNeeded) ) +#define ISOSDacInterface18_GetGCInfoSlotLifetimes(This,ip,count,lifetimes,pNeeded) \ + ( (This)->lpVtbl -> GetGCInfoSlotLifetimes(This,ip,count,lifetimes,pNeeded) ) #endif /* COBJMACROS */ diff --git a/src/tests/SOS.UnitTests/Scripts/OtherCommands.script b/src/tests/SOS.UnitTests/Scripts/OtherCommands.script index d7309bdd96..5a15938672 100644 --- a/src/tests/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/tests/SOS.UnitTests/Scripts/OtherCommands.script @@ -101,11 +101,10 @@ VERIFY:.*\s+Source file:\s+(?i:.*[\\|/]SymbolTestApp\.cs) @ 27\s+ # Verify GCInfo (uses MethodDesc from IP2MD) SOSCOMMAND:GCInfo \s+MethodDesc:\s+()\s+ -VERIFY:.*GC Info Header:\s* -VERIFY:.*CodeSize:\s+\d+.* +VERIFY:.*Code size:\s+[0-9a-fA-F]+\s* -# Verify DumpMD -SOSCOMMAND:DumpMD \s+MethodDesc:\s+()\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