diff -rupN original/ProfilerCallback.cpp modified/ProfilerCallback.cpp --- original/ProfilerCallback.cpp 2001-09-02 15:21:24.000000000 +0200 +++ modified/ProfilerCallback.cpp 2013-02-19 23:02:05.000000000 +0100 @@ -14,10 +14,140 @@ ULONG CProfilerCallback::Release() } HRESULT CProfilerCallback::QueryInterface( REFIID riid, void **ppInterface ) { - return E_NOTIMPL; + if ( riid == IID_IUnknown ) + *ppInterface = static_cast( this ); + else if ( riid == IID_ICorProfilerCallback ) + *ppInterface = static_cast( this ); + else if ( riid == IID_ICorProfilerCallback2 ) + *ppInterface = static_cast( this ); + else + { + *ppInterface = NULL; + return E_NOINTERFACE; + } + + reinterpret_cast( *ppInterface )->AddRef(); + + return S_OK; } //==================================================== +CProfilerCallback* cpc = 0; + +void __stdcall clbck_FunctionEnter2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo) +{ +// if (0 != clientData) +// __asm nop; +// if (0 != func) +// __asm nop; +// if (0 != argumentInfo) +// __asm nop; + +// ClassID classId; +// ModuleID moduleId; +// mdToken token; +// ULONG32 cArgs; +// cpc->m_pICorProfilerInfo->GetFunctionInfo2(funcId, func, &classId, &moduleId, &token, 0, &cArgs, 0); + + wchar_t wszClass[512]; + wchar_t wszMethod[512]; + + if ( cpc->GetMethodNameFromFunctionId( funcId, wszClass, wszMethod ) ) + { + cpc->ProfilerPrintf("FunctionEnter: %ls::%ls\n",wszClass,wszMethod); + } + else + { + cpc->ProfilerPrintf( "FunctionEnter\n" ); + } + + cpc->ChangeNestingLevel(1); +} + +void __stdcall clbck_FunctionLeave2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange) +{ + cpc->ChangeNestingLevel(-1); + + wchar_t wszClass[512]; + wchar_t wszMethod[512]; + + if ( cpc->GetMethodNameFromFunctionId( funcId, wszClass, wszMethod ) ) + { + cpc->ProfilerPrintf("FunctionLeave: %ls::%ls\n",wszClass,wszMethod); + } + else + { + cpc->ProfilerPrintf( "FunctionLeave\n" ); + } +} + +void __stdcall clbck_FunctionTailcall2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func) +{ + +} + +void __declspec(naked) __stdcall clbck_asm_FunctionEnter2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo) +{ + __asm + { + pushad ; +32 + sub esp, 108 ; +140 + fnsave [esp] + + push dword PTR [esp + 140 + 4 + 3*4] + push dword PTR [esp + 144 + 4 + 2*4] + push dword PTR [esp + 148 + 4 + 1*4] + push dword PTR [esp + 152 + 4 + 0*4] + call clbck_FunctionEnter2 + + frstor [esp] + add esp, 108 + popad + ret 4*4 + } +} + +void __declspec(naked) __stdcall clbck_asm_FunctionLeave2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange) +{ + __asm + { + pushad ; +32 + sub esp, 108 ; +140 + fnsave [esp] + + push dword PTR [esp + 140 + 4 + 3*4] + push dword PTR [esp + 144 + 4 + 2*4] + push dword PTR [esp + 148 + 4 + 1*4] + push dword PTR [esp + 152 + 4 + 0*4] + call clbck_FunctionLeave2 + + frstor [esp] + add esp, 108 + popad + ret 4*4 + } +} + +void __declspec(naked) __stdcall clbck_asm_FunctionTailcall2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func) +{ + __asm + { + pushad ; +32 + sub esp, 108 ; +140 + fnsave [esp] + + push dword PTR [esp + 144 + 4 + 2*4] + push dword PTR [esp + 148 + 4 + 1*4] + push dword PTR [esp + 152 + 4 + 0*4] + call clbck_FunctionTailcall2 + + frstor [esp] + add esp, 108 + popad + ret 3*4 + } +} + HRESULT CProfilerCallback::Initialize(IUnknown * pICorProfilerInfoUnk ) { GetInititializationParameters(); @@ -28,7 +158,7 @@ HRESULT CProfilerCallback::Initialize(IU // Get the ICorProfilerInfo interface we need, and stuff it away in // a member variable. HRESULT hr = - pICorProfilerInfoUnk->QueryInterface( IID_ICorProfilerInfo, + pICorProfilerInfoUnk->QueryInterface( IID_ICorProfilerInfo2, (LPVOID *)&m_pICorProfilerInfo ); if ( FAILED(hr) ) return E_INVALIDARG; @@ -50,6 +180,11 @@ HRESULT CProfilerCallback::Initialize(IU ProfilerPrintf( "Initialize\n" ); + cpc = this; + + m_pICorProfilerInfo->SetEnterLeaveFunctionHooks2(clbck_asm_FunctionEnter2, clbck_asm_FunctionLeave2, clbck_asm_FunctionTailcall2); + Sleep(100); + return S_OK; } @@ -777,24 +912,27 @@ HRESULT CProfilerCallback::ExceptionCLRC //============================================================================= // Helper functions -bool CProfilerCallback::GetMethodNameFromFunctionId(FunctionID functionId, - LPWSTR wszClass, LPWSTR wszMethod) +bool CProfilerCallback::GetMethodNameFromFunctionId(FunctionID functionId, LPWSTR wszClass, LPWSTR wszMethod) { + if (m_methodsMap.find(functionId) != m_methodsMap.end()) + { + + } + mdToken dwToken; IMetaDataImport * pIMetaDataImport = 0; - HRESULT hr = m_pICorProfilerInfo->GetTokenAndMetaDataFromFunction( - functionId, IID_IMetaDataImport, - (LPUNKNOWN *)&pIMetaDataImport, &dwToken ); - if ( FAILED(hr) ) return false; + HRESULT hr = m_pICorProfilerInfo->GetTokenAndMetaDataFromFunction( functionId, IID_IMetaDataImport, (LPUNKNOWN *)&pIMetaDataImport, &dwToken ); + if ( FAILED(hr) ) + return false; wchar_t _wszMethod[512]; DWORD cchMethod = sizeof(_wszMethod)/sizeof(_wszMethod[0]); mdTypeDef mdClass; - hr = pIMetaDataImport->GetMethodProps( dwToken, &mdClass, _wszMethod, - cchMethod, &cchMethod, 0, 0, 0, 0, 0 ); - if ( FAILED(hr) ) return false; + hr = pIMetaDataImport->GetMethodProps( dwToken, &mdClass, _wszMethod, cchMethod, &cchMethod, 0, 0, 0, 0, 0 ); + if ( FAILED(hr) ) + return false; lstrcpyW( wszMethod, _wszMethod ); @@ -804,9 +942,9 @@ bool CProfilerCallback::GetMethodNameFro if ( mdClass == 0x02000000 ) mdClass = 0x02000001; - hr = pIMetaDataImport->GetTypeDefProps( mdClass, wszTypeDef, cchTypeDef, - &cchTypeDef, 0, 0 ); - if ( FAILED(hr) ) return false; + hr = pIMetaDataImport->GetTypeDefProps( mdClass, wszTypeDef, cchTypeDef, &cchTypeDef, 0, 0 ); + if ( FAILED(hr) ) + return false; lstrcpyW( wszClass, wszTypeDef ); @@ -828,15 +966,32 @@ bool CProfilerCallback::GetClassNameFrom wszClass[0] = 0; - HRESULT hr = m_pICorProfilerInfo->GetClassIDInfo( classId, &moduleId, - &typeDef ); + HRESULT hr = m_pICorProfilerInfo->GetClassIDInfo( classId, &moduleId, &typeDef ); if ( FAILED(hr) ) return false; + bool isArray = false; if ( typeDef == 0 ) // ::GetClassIDInfo can fail, yet not set HRESULT { // __asm int 3 - return false; + CorElementType corElement; + ClassID baseClass; + ULONG rank; + hr = m_pICorProfilerInfo->IsArrayClass(classId, &corElement, &baseClass, &rank); + if ( FAILED(hr) ) + return false; + + hr = m_pICorProfilerInfo->GetClassIDInfo( baseClass, &moduleId, &typeDef ); + if ( FAILED(hr) ) + return false; + + if (0 == typeDef) + return false; + + isArray = true; + // + //return false; + //__asm nop; } IMetaDataImport * pIMetaDataImport = 0; @@ -857,7 +1012,13 @@ bool CProfilerCallback::GetClassNameFrom if ( FAILED(hr) ) return false; - lstrcpyW( wszClass, wszTypeDef ); + if (isArray) + { + lstrcatW(wszClass, L"array of "); + lstrcatW(wszClass, wszTypeDef); + } + else + lstrcpyW( wszClass, wszTypeDef ); // // If we were ambitious, we'd save the ClassID away in a map to avoid @@ -928,3 +1089,80 @@ void CProfilerCallback::GetInititializat m_bBreakOnInitialize = true; } } + +// ICorProfilerCallback2 +HRESULT CProfilerCallback::ThreadNameChanged( + /* [in] */ ThreadID threadId, + /* [in] */ ULONG cchName, + /* [in] */ + __in_ecount_opt(cchName) WCHAR name[ ]) +{ + ProfilerPrintf( "ThreadNameChanged\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::GarbageCollectionStarted( + /* [in] */ int cGenerations, + /* [size_is][in] */ BOOL generationCollected[ ], + /* [in] */ COR_PRF_GC_REASON reason) +{ + ProfilerPrintf( "GarbageCollectionStarted\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::SurvivingReferences( + /* [in] */ ULONG cSurvivingObjectIDRanges, + /* [size_is][in] */ ObjectID objectIDRangeStart[ ], + /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]) +{ + ProfilerPrintf( "SurvivingReferences\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::GarbageCollectionFinished(void) +{ + ProfilerPrintf( "GarbageCollectionFinished\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::FinalizeableObjectQueued( + /* [in] */ DWORD finalizerFlags, + /* [in] */ ObjectID objectID) +{ + ProfilerPrintf( "FinalizeableObjectQueued\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::RootReferences2( + /* [in] */ ULONG cRootRefs, + /* [size_is][in] */ ObjectID rootRefIds[ ], + /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ], + /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ], + /* [size_is][in] */ UINT_PTR rootIds[ ]) +{ + ProfilerPrintf( "RootReferences2\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::HandleCreated( + /* [in] */ GCHandleID handleId, + /* [in] */ ObjectID initialObjectId) +{ + ProfilerPrintf( "HandleCreated\n" ); + + return E_NOTIMPL; +} + +HRESULT CProfilerCallback::HandleDestroyed( + /* [in] */ GCHandleID handleId) +{ + ProfilerPrintf( "HandleDestroyed\n" ); + + return E_NOTIMPL; +} diff -rupN original/ProfilerCallback.h modified/ProfilerCallback.h --- original/ProfilerCallback.h 2001-09-02 15:06:20.000000000 +0200 +++ modified/ProfilerCallback.h 2013-02-19 22:54:56.000000000 +0100 @@ -5,14 +5,15 @@ //========================================== #include #include +#include -class CProfilerCallback : public ICorProfilerCallback +class CProfilerCallback : public ICorProfilerCallback2 { STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHOD(QueryInterface)( REFIID riid, void **ppInterface ); -// ICorProfilerCallback + // ICorProfilerCallback STDMETHOD(Initialize)(IUnknown * pICorProfilerInfoUnk); STDMETHOD(Shutdown)(); STDMETHOD(AppDomainCreationStarted)(UINT appDomainId); @@ -96,8 +97,43 @@ class CProfilerCallback : public ICorPro REFGUID implementedIID, void *pVTable); STDMETHOD(ExceptionCLRCatcherFound)(void); STDMETHOD(ExceptionCLRCatcherExecute)(void); + // End of ICorProfilerCallback interface -// End of ICorProfilerCallback interface + // ICorProfilerCallback2 + STDMETHOD(ThreadNameChanged)( + /* [in] */ ThreadID threadId, + /* [in] */ ULONG cchName, + /* [in] */ + __in_ecount_opt(cchName) WCHAR name[ ]); + STDMETHOD(GarbageCollectionStarted)( + /* [in] */ int cGenerations, + /* [size_is][in] */ BOOL generationCollected[ ], + /* [in] */ COR_PRF_GC_REASON reason); + + STDMETHOD(SurvivingReferences)( + /* [in] */ ULONG cSurvivingObjectIDRanges, + /* [size_is][in] */ ObjectID objectIDRangeStart[ ], + /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]); + + STDMETHOD(GarbageCollectionFinished)(void); + + STDMETHOD(FinalizeableObjectQueued)( + /* [in] */ DWORD finalizerFlags, + /* [in] */ ObjectID objectID); + + STDMETHOD(RootReferences2)( + /* [in] */ ULONG cRootRefs, + /* [size_is][in] */ ObjectID rootRefIds[ ], + /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ], + /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ], + /* [size_is][in] */ UINT_PTR rootIds[ ]); + + STDMETHOD(HandleCreated)( + /* [in] */ GCHandleID handleId, + /* [in] */ ObjectID initialObjectId); + + STDMETHOD(HandleDestroyed)( + /* [in] */ GCHandleID handleId); private: @@ -119,6 +155,11 @@ private: bool GetMethodNameFromFunctionId( FunctionID, LPWSTR wszClass, LPWSTR wszFunction); bool GetClassNameFromClassId( ClassID classID, LPWSTR wszClass ); - ICorProfilerInfo * m_pICorProfilerInfo; + ICorProfilerInfo2 * m_pICorProfilerInfo; bool m_bBreakOnInitialize; + + std::hash_map m_methodsMap; + + friend void __stdcall clbck_FunctionEnter2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo); + friend void __stdcall clbck_FunctionLeave2(FunctionID funcId, UINT_PTR clientData, COR_PRF_FRAME_INFO func, COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange); }; \ No newline at end of file