I have received inquires from several people on how to use Get/SetILFunctionBody in the profiling interfaces properly.
To address these and future inquiries, I have created a working example of what can be done with ICorProfilerInfo::SetILFunctionBody in Rotor. This example replaces the Main method of managed application with a simple "Hello world" program. The tokens in the "Hello world" program are dynamically generated using IMetaDataEmit interface. To see the example in action: 1. go to sscli\samples\utilities\dnprofiler\profilercallback.cpp in the Rotor sources and replace the CProfilerCallback::JITCompilationStarted method with the following code fragment 2. build 3. activate profiling by running "profiling_on" script 4. run managed application. I have tried running "clix %TARGETCOMPLUS%\caspol.exe". It printed following for me: C:\sscli\samples\utilities\dnprofiler>clix %TARGETCOMPLUS%\caspol.exe Original: 1b 30 03 00 35 00 00 00 03 00 00 11 28 11 00 00 06 28 10 00 00 06 02 8e 69 2d 18 14 7e 1b 00 00 04 72 99 00 00 70 6f 0f 00 00 0a 15 28 2f 00 00 06 2b08 02 0a 06 28 16 00 00 06 de 03 26 de 00 2a 00 00 00 01 10 00 00 00 00 0a 00 27 31 00 03 0b 00 00 02 00 Replaced Hello world! -Jan ---------------------------------------------------- void Check(HRESULT hr) { if (FAILED(hr)) { fprintf(stderr, "FAILED\n"); exit(1); } } #if BIGENDIAN inline UINT32 VAL32(UINT32 x) { return (x >> 24) | ((x >> 8) & 0x0000FF00L) | ((x & 0x0000FF00L) << 8) | (x << 24); } #else #define VAL32(x) x #endif HRESULT CProfilerCallback::JITCompilationStarted(UINT functionId, BOOL fIsSafeToBlock) { wchar_t wszClass[512]; wchar_t wszMethod[512]; if (GetMethodNameFromFunctionId(functionId, wszClass, wszMethod)) { if (wcscmp(L"Main", wszMethod) == 0) { ClassID classId = 0; ModuleID moduleId = 0; mdToken tkMethod = 0; IMetaDataEmit* pMetaDataEmit = NULL; IMetaDataAssemblyEmit* pMetaDataAssemblyEmit = NULL; mdSignature msig = 0; IMethodMalloc* pMalloc = NULL; PVOID pReplacedMethod; LPCBYTE pMethodBytes; ULONG cbMethodSize; mdModuleRef tkMSCORLIB; mdTypeRef tkConsole; mdMemberRef tkWriteLine; mdString tkString; ULONG i; Check(m_pICorProfilerInfo->GetFunctionInfo( functionId, &classId, &moduleId, &tkMethod)); // get the code of the original function Check(m_pICorProfilerInfo->GetILFunctionBody( moduleId, tkMethod, &pMethodBytes, &cbMethodSize)); // print the original code of the function fprintf(stderr, "Original:"); for (i = 0; i < cbMethodSize; i++) { fprintf(stderr, " %02x", pMethodBytes[i]); } fprintf(stderr, "\n"); // replace the method with a simple "Hello world!" Check(m_pICorProfilerInfo->GetModuleMetaData( moduleId, ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown** )&pMetaDataEmit )); Check(pMetaDataEmit->QueryInterface(IID_IMetaDataAssemblyEmit, (void**)&pMetaDataAssemblyEmit)); // get token of the Console.WriteLine(string) ASSEMBLYMETADATA amd; ZeroMemory(&amd, sizeof(amd)); amd.usMajorVersion = 1; amd.usMinorVersion = 0; amd.usBuildNumber = 3300; amd.usRevisionNumber = 0; BYTE keyECMA[] = { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 }; Check(pMetaDataAssemblyEmit->DefineAssemblyRef(keyECMA, sizeof(keyECMA), L"mscorlib", &amd, NULL, 0, 0, &tkMSCORLIB)); Check(pMetaDataEmit->DefineTypeRefByName(tkMSCORLIB, L"System.Console", &tkConsole)); BYTE Sig_void_String[] = { 0, // IMAGE_CEE_CS_CALLCONV_DEFAULT 0x1, // argument count 0x1, // ret = ELEMENT_TYPE_VOID 0xe, // arg1 = ELEMENT_TYPE_STRING }; Check(pMetaDataEmit->DefineMemberRef(tkConsole, L"WriteLine", Sig_void_String, sizeof(Sig_void_String), &tkWriteLine)); // get token of "Hello world!" string LPCWSTR szString = L"Hello world!"; Check(pMetaDataEmit->DefineUserString(szString, wcslen(szString), &tkString)); #include <pshpack1.h> struct { BYTE Flags_CodeSize; BYTE ldstr; DWORD str_token; BYTE call; DWORD method_token; BYTE ret; } ILCode; #include <poppack.h> ILCode.Flags_CodeSize = 0x42; ILCode.ldstr = 0x72; ILCode.str_token = VAL32(tkString); ILCode.call = 0x28; ILCode.method_token = VAL32(tkWriteLine); ILCode.ret = 0x2A; Check(m_pICorProfilerInfo->GetILFunctionBodyAllocator( moduleId, &pMalloc )); pReplacedMethod = pMalloc->Alloc(sizeof(ILCode)); memcpy(pReplacedMethod, &ILCode, sizeof(ILCode)); Check(m_pICorProfilerInfo->SetILFunctionBody( moduleId, tkMethod, (LPCBYTE)pReplacedMethod)); pMalloc->Release(); pMetaDataEmit->Release(); pMetaDataAssemblyEmit->Release(); fprintf(stderr, "Replaced\n"); } ProfilerPrintf("JITCompilationStarted: %ls::%ls\n",wszClass,wszMethod); } else { ProfilerPrintf( "JITCompilationStarted\n" ); } ChangeNestingLevel( 1 ); return S_OK; } ---------------------------------------------------- This posting is provided "AS IS" with no warranties, and confers no rights.