diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index a27c3d57de..9cc7c472f0 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -1239,72 +1239,94 @@ DECLARE_API(DumpMT) if (bDumpMDTable) { - table.ReInit(4, POINTERSIZE_HEX, AlignRight); + table.ReInit(5, POINTERSIZE_HEX, AlignRight); table.SetColAlignment(3, AlignLeft); table.SetColWidth(2, 6); Print("--------------------------------------\n"); Print("MethodDesc Table\n"); - table.WriteRow("Entry", "MethodDesc", "JIT", "Name"); + table.WriteRow("Entry", "MethodDesc", "JIT", "Slot", "Name"); - for (DWORD n = 0; n < vMethTable.wNumMethods; n++) + ISOSMethodEnum *pMethodEnumerator; + if (SUCCEEDED(g_sos15->GetMethodTableSlotEnumerator(dwStartAddr, &pMethodEnumerator))) { - JITTypes jitType; - DWORD_PTR methodDesc=0; - DWORD_PTR gcinfoAddr; - - CLRDATA_ADDRESS entry; - if (g_sos->GetMethodTableSlot(dwStartAddr, n, &entry) != S_OK) + SOSMethodData entry; + unsigned int fetched; + while (SUCCEEDED(pMethodEnumerator->Next(1, &entry, &fetched)) && fetched != 0) { - PrintLn(""); - continue; - } + JITTypes jitType = TYPE_UNKNOWN; + DWORD_PTR methodDesc = (DWORD_PTR)entry.MethodDesc; + DWORD_PTR methodDescFromIP2MD = 0; + DWORD_PTR gcinfoAddr = 0; + + if (entry.Entrypoint != 0) + { + IP2MethodDesc((DWORD_PTR)entry.Entrypoint, methodDescFromIP2MD, jitType, gcinfoAddr); + if ((methodDescFromIP2MD != methodDesc) && methodDesc != 0) + { + ExtOut("MethodDesc from IP2MD does not match MethodDesc from enumerator\n"); + } + } - IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr); - table.WriteColumn(0, entry); - table.WriteColumn(1, MethodDescPtr(methodDesc)); + table.WriteColumn(0, entry.Entrypoint); + table.WriteColumn(1, MethodDescPtr(methodDesc)); - if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0) - { - // We can get a more accurate jitType from NativeCodeAddr of the methoddesc, - // because the methodtable entry hasn't always been patched. - DacpMethodDescData tmpMethodDescData; - if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) + if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0) { - DacpCodeHeaderData codeHeaderData; - if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK) + // We can get a more accurate jitType from NativeCodeAddr of the methoddesc, + // because the methodtable entry hasn't always been patched. + DacpMethodDescData tmpMethodDescData; + if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) { - jitType = (JITTypes) codeHeaderData.JITType; + DacpCodeHeaderData codeHeaderData; + if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK) + { + jitType = (JITTypes) codeHeaderData.JITType; + } } } - } - const char *pszJitType = "NONE"; - if (jitType == TYPE_JIT) - pszJitType = "JIT"; - else if (jitType == TYPE_PJIT) - pszJitType = "PreJIT"; - else - { - DacpMethodDescData MethodDescData; - if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) + const char *pszJitType = "NONE"; + if (jitType == TYPE_JIT) + pszJitType = "JIT"; + else if (jitType == TYPE_PJIT) + pszJitType = "PreJIT"; + else { - // Is it an fcall? - ULONG64 baseAddress = g_pRuntime->GetModuleAddress(); - ULONG64 size = g_pRuntime->GetModuleSize(); - if ((TO_TADDR(MethodDescData.NativeCodeAddr) >= TO_TADDR(baseAddress)) && - ((TO_TADDR(MethodDescData.NativeCodeAddr) < TO_TADDR(baseAddress + size)))) + DacpMethodDescData MethodDescData; + if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) { - pszJitType = "FCALL"; + // Is it an fcall? + ULONG64 baseAddress = g_pRuntime->GetModuleAddress(); + ULONG64 size = g_pRuntime->GetModuleSize(); + if ((TO_TADDR(MethodDescData.NativeCodeAddr) >= TO_TADDR(baseAddress)) && + ((TO_TADDR(MethodDescData.NativeCodeAddr) < TO_TADDR(baseAddress + size)))) + { + pszJitType = "FCALL"; + } } } - } - table.WriteColumn(2, pszJitType); + table.WriteColumn(2, pszJitType); + table.WriteColumn(3, entry.Slot); - NameForMD_s(methodDesc,g_mdName,mdNameLen); - table.WriteColumn(3, g_mdName); + if (methodDesc != 0) + NameForMD_s(methodDesc,g_mdName,mdNameLen); + else + { + DacpModuleData moduleData; + if(moduleData.Request(g_sos, entry.DefiningModule)==S_OK) + { + NameForToken_s(&moduleData, entry.Token, g_mdName, mdNameLen, true); + } + else + { + _snwprintf_s(g_mdName, mdNameLen, _TRUNCATE, W("Unknown Module!%08x"), entry.Token); + } + } + table.WriteColumn(4, g_mdName); + } } } return Status; diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 606451115a..c80a47079b 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -59,6 +59,7 @@ const char * const CorElementTypeNamespace[ELEMENT_TYPE_MAX]= IXCLRDataProcess *g_clrData = NULL; ISOSDacInterface *g_sos = NULL; +ISOSDacInterface15 *g_sos15 = NULL; #ifndef IfFailRet #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0) @@ -3930,6 +3931,154 @@ void ResetGlobals(void) Output::ResetIndent(); } +class SOSDacInterface15Simulator : public ISOSDacInterface15 +{ + class SOSMethodEnum : public ISOSMethodEnum + { + CLRDATA_ADDRESS pMT; + unsigned int index; + unsigned int slotCount; + ULONG refCount; + public: + SOSMethodEnum(CLRDATA_ADDRESS mt) : pMT(mt), refCount(1) + { + } + + virtual ~SOSMethodEnum() {} + + virtual HRESULT STDMETHODCALLTYPE Reset() + { + index = 0; + DacpMethodTableData vMethTable; + HRESULT hr = vMethTable.Request(g_sos, pMT); + if (FAILED(hr)) + return hr; + + slotCount = vMethTable.wNumMethods; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pc) + { + *pc = slotCount; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Skip(unsigned int skipCount) + { + index += skipCount; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Next( + /* [in] */ unsigned int count, + /* [length_is][size_is][out] */ SOSMethodData methods[ ], + /* [out] */ unsigned int *pFetched) + { + if (!pFetched) + return E_POINTER; + + if (!methods) + return E_POINTER; + + unsigned int i = 0; + while (i < count && index < slotCount) + { + SOSMethodData methodData = { 0 }; + + JITTypes jitType; + DWORD_PTR methodDesc=0; + DWORD_PTR gcinfoAddr; + + CLRDATA_ADDRESS entry; + methodData.Slot = index; + HRESULT hr = g_sos->GetMethodTableSlot(pMT, index++, &entry); + if (hr != S_OK) + { + PrintLn(""); + continue; + } + + IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr); + + methodData.MethodDesc = methodDesc; + methodData.Entrypoint = entry; + + methods[i++] = methodData; + } + + *pFetched = i; + return i < count ? S_FALSE : S_OK; + } + + STDMETHOD_(ULONG, AddRef)() { return ++refCount; } + STDMETHOD_(ULONG, Release)() + { + --refCount; + if (refCount == 0) + { + delete this; + return 0; + } + return refCount; + } + + STDMETHOD(QueryInterface)( + THIS_ + ___in REFIID InterfaceId, + ___out PVOID* Interface + ) + { + if (InterfaceId == IID_IUnknown || + InterfaceId == IID_ISOSMethodEnum) + { + *Interface = (ISOSMethodEnum*)this; + AddRef(); + return S_OK; + } + *Interface = NULL; + return E_NOINTERFACE; + } + }; + +public: + STDMETHOD_(ULONG, AddRef)() { return 1; }; + STDMETHOD_(ULONG, Release)() { return 1; }; + STDMETHOD(QueryInterface)( + THIS_ + ___in REFIID InterfaceId, + ___out PVOID* Interface + ) + { + if (InterfaceId == IID_IUnknown || + InterfaceId == IID_ISOSDacInterface15) + { + *Interface = (ISOSDacInterface15*)this; + return S_OK; + } + *Interface = NULL; + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlotEnumerator( + CLRDATA_ADDRESS mt, + ISOSMethodEnum **enumerator) + { + SOSMethodEnum *simulator = new(std::nothrow) SOSMethodEnum(mt); + *enumerator = simulator; + if (simulator == NULL) + { + return E_OUTOFMEMORY; + } + HRESULT hr = simulator->Reset(); + if (FAILED(hr)) + { + simulator->Release(); + } + return hr; + } +} SOSDacInterface15Simulator_Instance; + //--------------------------------------------------------------------------------------- // // Loads private DAC interface, and points g_clrData to it. @@ -3960,6 +4109,13 @@ HRESULT LoadClrDebugDll(void) g_sos = NULL; return hr; } + + // Always have an instance of the MethodTable enumerator + hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface15), (void**)&g_sos15); + if (FAILED(hr)) + { + g_sos15 = &SOSDacInterface15Simulator_Instance; + } return S_OK; } diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index dad6bf9c4a..3c2bfb8bb0 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -150,6 +150,7 @@ enum EEFLAVOR {UNKNOWNEE, MSCOREE, MSCORWKS, MSCOREND}; #include "sospriv.h" extern IXCLRDataProcess *g_clrData; extern ISOSDacInterface *g_sos; +extern ISOSDacInterface15 *g_sos15; #include "dacprivate.h" diff --git a/src/shared/inc/sospriv.idl b/src/shared/inc/sospriv.idl index 98cfa0afe9..141f597dcb 100644 --- a/src/shared/inc/sospriv.idl +++ b/src/shared/inc/sospriv.idl @@ -519,3 +519,46 @@ interface ISOSDacInterface14 : IUnknown HRESULT GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress); HRESULT GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus); } + +cpp_quote("#ifndef _SOS_MethodData") +cpp_quote("#define _SOS_MethodData") + +typedef struct _SOSMethodData +{ + // At least one of MethodDesc, Entrypoint, or Token/DefiningMethodTable/DefiningModule is guaranteed to be set. + // Multiple of them may be set as well + CLRDATA_ADDRESS MethodDesc; + + CLRDATA_ADDRESS Entrypoint; + + CLRDATA_ADDRESS DefininingMethodTable; // Useful for when the method is inherited from a parent type which is instantiated + CLRDATA_ADDRESS DefiningModule; + unsigned int Token; + + // Slot data, a given MethodDesc may be present in multiple slots for a single MethodTable + unsigned int Slot; // Will be set to 0xFFFFFFFF for EnC added methods +} SOSMethodData; + +cpp_quote("#endif //_SOS_MethodData") + +[ + object, + local, + uuid(3c0fe725-c324-4a4f-8100-d399588a662e) +] +interface ISOSMethodEnum : ISOSEnum +{ + HRESULT Next([in] unsigned int count, + [out, size_is(count), length_is(*pNeeded)] SOSMethodData handles[], + [out] unsigned int *pNeeded); +} + +[ + object, + local, + uuid(7ed81261-52a9-4a23-a358-c3313dea30a8) +] +interface ISOSDacInterface15 : IUnknown +{ + HRESULT GetMethodTableSlotEnumerator(CLRDATA_ADDRESS mt, ISOSMethodEnum **enumerator); +} diff --git a/src/shared/pal/prebuilt/idl/sospriv_i.cpp b/src/shared/pal/prebuilt/idl/sospriv_i.cpp index f070ae5816..579be51d35 100644 --- a/src/shared/pal/prebuilt/idl/sospriv_i.cpp +++ b/src/shared/pal/prebuilt/idl/sospriv_i.cpp @@ -121,6 +121,12 @@ MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface13,0x3176a8ed,0x597b,0x4f54,0xa7,0x1f, MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface14,0x9aa22aca,0x6dc6,0x4a0c,0xb4,0xe0,0x70,0xd2,0x41,0x6b,0x98,0x37); + +MIDL_DEFINE_GUID(IID, IID_ISOSMethodEnum,0x3c0fe725,0xc324,0x4a4f,0x81,0x00,0xd3,0x99,0x58,0x8a,0x66,0x2e); + + +MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface15,0x7ed81261,0x52a9,0x4a23,0xa3,0x58,0xc3,0x31,0x3d,0xea,0x30,0xa8); + #undef MIDL_DEFINE_GUID #ifdef __cplusplus diff --git a/src/shared/pal/prebuilt/inc/sospriv.h b/src/shared/pal/prebuilt/inc/sospriv.h index 64db79c792..a3d741f740 100644 --- a/src/shared/pal/prebuilt/inc/sospriv.h +++ b/src/shared/pal/prebuilt/inc/sospriv.h @@ -3333,6 +3333,27 @@ EXTERN_C const IID IID_ISOSDacInterface13; #define ISOSDacInterface13_TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) \ ( (This)->lpVtbl -> TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) ) +#define ISOSDacInterface13_GetDomainLoaderAllocator(This,domainAddress,pLoaderAllocator) \ + ( (This)->lpVtbl -> GetDomainLoaderAllocator(This,domainAddress,pLoaderAllocator) ) + +#define ISOSDacInterface13_GetLoaderAllocatorHeapNames(This,count,ppNames,pNeeded) \ + ( (This)->lpVtbl -> GetLoaderAllocatorHeapNames(This,count,ppNames,pNeeded) ) + +#define ISOSDacInterface13_GetLoaderAllocatorHeaps(This,loaderAllocator,count,pLoaderHeaps,pKinds,pNeeded) \ + ( (This)->lpVtbl -> GetLoaderAllocatorHeaps(This,loaderAllocator,count,pLoaderHeaps,pKinds,pNeeded) ) + +#define ISOSDacInterface13_GetHandleTableMemoryRegions(This,ppEnum) \ + ( (This)->lpVtbl -> GetHandleTableMemoryRegions(This,ppEnum) ) + +#define ISOSDacInterface13_GetGCBookkeepingMemoryRegions(This,ppEnum) \ + ( (This)->lpVtbl -> GetGCBookkeepingMemoryRegions(This,ppEnum) ) + +#define ISOSDacInterface13_GetGCFreeRegions(This,ppEnum) \ + ( (This)->lpVtbl -> GetGCFreeRegions(This,ppEnum) ) + +#define ISOSDacInterface13_LockedFlush(This) \ + ( (This)->lpVtbl -> LockedFlush(This) ) + #endif /* COBJMACROS */ @@ -3456,6 +3477,214 @@ EXTERN_C const IID IID_ISOSDacInterface14; #endif /* __ISOSDacInterface14_INTERFACE_DEFINED__ */ +/* interface __MIDL_itf_sospriv_0000_0019 */ +/* [local] */ + +#ifndef _SOS_MethodData +#define _SOS_MethodData +typedef struct _SOSMethodData + { + CLRDATA_ADDRESS MethodDesc; + CLRDATA_ADDRESS Entrypoint; + CLRDATA_ADDRESS DefininingMethodTable; + CLRDATA_ADDRESS DefiningModule; + unsigned int Token; + unsigned int Slot; + } SOSMethodData; + +#endif //_SOS_MethodData + + +extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0019_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0019_v0_0_s_ifspec; + +#ifndef __ISOSMethodEnum_INTERFACE_DEFINED__ +#define __ISOSMethodEnum_INTERFACE_DEFINED__ + +/* interface ISOSMethodEnum */ +/* [uuid][local][object] */ + + +EXTERN_C const IID IID_ISOSMethodEnum; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3c0fe725-c324-4a4f-8100-d399588a662e") + ISOSMethodEnum : public ISOSEnum + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [in] */ unsigned int count, + /* [length_is][size_is][out] */ SOSMethodData handles[ ], + /* [out] */ unsigned int *pNeeded) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISOSMethodEnumVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISOSMethodEnum * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISOSMethodEnum * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISOSMethodEnum * This); + + HRESULT ( STDMETHODCALLTYPE *Skip )( + ISOSMethodEnum * This, + /* [in] */ unsigned int count); + + HRESULT ( STDMETHODCALLTYPE *Reset )( + ISOSMethodEnum * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + ISOSMethodEnum * This, + /* [out] */ unsigned int *pCount); + + HRESULT ( STDMETHODCALLTYPE *Next )( + ISOSMethodEnum * This, + /* [in] */ unsigned int count, + /* [length_is][size_is][out] */ SOSMethodData handles[ ], + /* [out] */ unsigned int *pNeeded); + + END_INTERFACE + } ISOSMethodEnumVtbl; + + interface ISOSMethodEnum + { + CONST_VTBL struct ISOSMethodEnumVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISOSMethodEnum_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSMethodEnum_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSMethodEnum_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSMethodEnum_Skip(This,count) \ + ( (This)->lpVtbl -> Skip(This,count) ) + +#define ISOSMethodEnum_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) + +#define ISOSMethodEnum_GetCount(This,pCount) \ + ( (This)->lpVtbl -> GetCount(This,pCount) ) + + +#define ISOSMethodEnum_Next(This,count,handles,pNeeded) \ + ( (This)->lpVtbl -> Next(This,count,handles,pNeeded) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISOSMethodEnum_INTERFACE_DEFINED__ */ + + +#ifndef __ISOSDacInterface15_INTERFACE_DEFINED__ +#define __ISOSDacInterface15_INTERFACE_DEFINED__ + +/* interface ISOSDacInterface15 */ +/* [uuid][local][object] */ + + +EXTERN_C const IID IID_ISOSDacInterface15; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7ed81261-52a9-4a23-a358-c3313dea30a8") + ISOSDacInterface15 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlotEnumerator( + CLRDATA_ADDRESS mt, + ISOSMethodEnum **enumerator) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISOSDacInterface15Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISOSDacInterface15 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISOSDacInterface15 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISOSDacInterface15 * This); + + HRESULT ( STDMETHODCALLTYPE *GetMethodTableSlotEnumerator )( + ISOSDacInterface15 * This, + CLRDATA_ADDRESS mt, + ISOSMethodEnum **enumerator); + + END_INTERFACE + } ISOSDacInterface15Vtbl; + + interface ISOSDacInterface15 + { + CONST_VTBL struct ISOSDacInterface15Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISOSDacInterface15_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSDacInterface15_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSDacInterface15_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSDacInterface15_GetMethodTableSlotEnumerator(This,mt,enumerator) \ + ( (This)->lpVtbl -> GetMethodTableSlotEnumerator(This,mt,enumerator) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISOSDacInterface15_INTERFACE_DEFINED__ */ + + /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */