HRESULT ProfilerInfoShim::GetILFunctionBody(ModuleID moduleId, mdMethodDef methodId, LPCBYTE *ppMethodHeader, ULONG *pcbMethodSize) { HRESULT result = m_wrappedInfo->GetILFunctionBody(moduleId, methodId, ppMethodHeader, pcbMethodSize); if (result != S_OK) return result; IMAGE_COR_ILMETHOD *method = (IMAGE_COR_ILMETHOD *)*ppMethodHeader; COR_ILMETHOD_FAT *fatImage = (COR_ILMETHOD_FAT *)&method->Fat; UINT codeSize = 0; BYTE *codeBytes = NULL; if (fatImage->IsFat()) { codeSize = fatImage->GetCodeSize(); codeBytes = fatImage->GetCode(); } else { COR_ILMETHOD_TINY *tinyImage = (COR_ILMETHOD_TINY *)&method->Tiny; codeSize = tinyImage->GetCodeSize(); codeBytes = tinyImage->GetCode(); } fprintf(m_stream, "Getting IL for "); IMetaDataImport2 *metadata = NULL; PrintMethodInfo(m_wrappedInfo, moduleId, methodId, m_stream, &metadata); if (codeBytes != NULL) PrintILMethodBody(m_wrappedInfo, metadata, moduleId, m_stream, codeBytes, codeSize); fflush(m_stream); metadata->Release(); return result; }
// emit the header (bestFormat) return amount emitted unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* header, BOOL moreSections, BYTE* outBuff) { #ifdef _DEBUG BYTE* origBuff = outBuff; #endif if (size == 1) { // Tiny format *outBuff++ = (BYTE) (CorILMethod_TinyFormat | (header->GetCodeSize() << 2)); } else { // Fat format _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned COR_ILMETHOD_FAT* fatHeader = (COR_ILMETHOD_FAT*) outBuff; outBuff += sizeof(COR_ILMETHOD_FAT); *fatHeader = *header; fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_FatFormat); _ASSERTE((fatHeader->GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat); if (moreSections) fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_MoreSects); fatHeader->SetSize(sizeof(COR_ILMETHOD_FAT) / 4); } _ASSERTE(&origBuff[size] == outBuff); return(size); }
/// <summary>Read the full method from the supplied buffer.</summary> void Method::ReadMethod(IMAGE_COR_ILMETHOD* pMethod) { BYTE* pCode; COR_ILMETHOD_FAT* fatImage = (COR_ILMETHOD_FAT*)&pMethod->Fat; if(!fatImage->IsFat()) { ATLTRACE(_T("TINY")); COR_ILMETHOD_TINY* tinyImage = (COR_ILMETHOD_TINY*)&pMethod->Tiny; m_header.CodeSize = tinyImage->GetCodeSize(); pCode = tinyImage->GetCode(); ATLTRACE(_T("TINY(%X) => (%d + 1) : %d"), m_header.CodeSize, m_header.CodeSize, m_header.MaxStack); } else { memcpy(&m_header, pMethod, fatImage->Size * sizeof(DWORD)); pCode = fatImage->GetCode(); ATLTRACE(_T("FAT(%X) => (%d + 12) : %d"), m_header.CodeSize, m_header.CodeSize, m_header.MaxStack); } SetBuffer(pCode); ReadBody(); }
// SetMethodIL -- This function will create a method within the class void QCALLTYPE COMDynamicWrite::SetMethodIL(QCall::ModuleHandle pModule, INT32 tk, BOOL fIsInitLocal, LPCBYTE pBody, INT32 cbBody, LPCBYTE pLocalSig, INT32 sigLength, UINT16 maxStackSize, ExceptionInstance * pExceptions, INT32 numExceptions, INT32 * pTokenFixups, INT32 numTokenFixups) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); _ASSERTE(pLocalSig); PCCOR_SIGNATURE pcSig = (PCCOR_SIGNATURE)pLocalSig; _ASSERTE(*pcSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); mdSignature pmLocalSigToken; if (sigLength==2 && pcSig[0]==0 && pcSig[1]==0) { //This is an empty local variable sig pmLocalSigToken=0; } else { IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( pcSig, sigLength, &pmLocalSigToken)); } COR_ILMETHOD_FAT fatHeader; // set fatHeader.Flags to CorILMethod_InitLocals if user wants to zero init the stack frame. // fatHeader.SetFlags(fIsInitLocal ? CorILMethod_InitLocals : 0); fatHeader.SetMaxStack(maxStackSize); fatHeader.SetLocalVarSigTok(pmLocalSigToken); fatHeader.SetCodeSize(cbBody); bool moreSections = (numExceptions != 0); unsigned codeSizeAligned = fatHeader.GetCodeSize(); if (moreSections) codeSizeAligned = AlignUp(codeSizeAligned, 4); // to insure EH section aligned unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, numExceptions != 0); //Create the exception handlers. CQuickArray<COR_ILMETHOD_SECT_EH_CLAUSE_FAT> clauses; if (numExceptions > 0) { clauses.AllocThrows(numExceptions); for (int i = 0; i < numExceptions; i++) { clauses[i].SetFlags((CorExceptionFlag)(pExceptions[i].m_type)); clauses[i].SetTryOffset(pExceptions[i].m_start); clauses[i].SetTryLength(pExceptions[i].m_end - pExceptions[i].m_start); clauses[i].SetHandlerOffset(pExceptions[i].m_handle); clauses[i].SetHandlerLength(pExceptions[i].m_handleEnd - pExceptions[i].m_handle); if (pExceptions[i].m_type == COR_ILEXCEPTION_CLAUSE_FILTER) { clauses[i].SetFilterOffset(pExceptions[i].m_filterOffset); } else if (pExceptions[i].m_type!=COR_ILEXCEPTION_CLAUSE_FINALLY) { clauses[i].SetClassToken(pExceptions[i].m_exceptionType); } else { clauses[i].SetClassToken(mdTypeRefNil); } } } unsigned ehSize = ExceptionHandlingSize(numExceptions, clauses.Ptr()); S_UINT32 totalSizeSafe = S_UINT32(headerSize) + S_UINT32(codeSizeAligned) + S_UINT32(ehSize); if (totalSizeSafe.IsOverflow()) COMPlusThrowOM(); UINT32 totalSize = totalSizeSafe.Value(); ICeeGen* pGen = pRCW->GetCeeGen(); BYTE* buf = NULL; ULONG methodRVA; pGen->AllocateMethodBuffer(totalSize, &buf, &methodRVA); if (buf == NULL) COMPlusThrowOM(); _ASSERTE(buf != NULL); _ASSERTE((((size_t) buf) & 3) == 0); // header is dword aligned #ifdef _DEBUG BYTE* endbuf = &buf[totalSize]; #endif BYTE * startBuf = buf; // Emit the header buf += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, buf); //Emit the code //The fatHeader.CodeSize is a workaround to see if we have an interface or an //abstract method. Force enough verification in native to ensure that //this is true. if (fatHeader.GetCodeSize()!=0) { memcpy(buf, pBody, fatHeader.GetCodeSize()); } buf += codeSizeAligned; // Emit the eh CQuickArray<ULONG> ehTypeOffsets; if (numExceptions > 0) { // Allocate space for the the offsets to the TypeTokens in the Exception headers // in the IL stream. ehTypeOffsets.AllocThrows(numExceptions); // Emit the eh. This will update the array ehTypeOffsets with offsets // to Exception type tokens. The offsets are with reference to the // beginning of eh section. buf += COR_ILMETHOD_SECT_EH::Emit(ehSize, numExceptions, clauses.Ptr(), false, buf, ehTypeOffsets.Ptr()); } _ASSERTE(buf == endbuf); //Get the IL Section. HCEESECTION ilSection; IfFailThrow(pGen->GetIlSection(&ilSection)); // Token Fixup data... ULONG ilOffset = methodRVA + headerSize; //Add all of the relocs based on the info which I saved from ILGenerator. //Add the Token Fixups for (int iTokenFixup=0; iTokenFixup<numTokenFixups; iTokenFixup++) { IfFailThrow(pGen->AddSectionReloc(ilSection, pTokenFixups[iTokenFixup] + ilOffset, ilSection, srRelocMapToken)); } // Add token fixups for exception type tokens. for (int iException=0; iException < numExceptions; iException++) { if (ehTypeOffsets[iException] != (ULONG) -1) { IfFailThrow(pGen->AddSectionReloc( ilSection, ehTypeOffsets[iException] + codeSizeAligned + ilOffset, ilSection, srRelocMapToken)); } } //nasty interface workaround. What does this mean for abstract methods? if (fatHeader.GetCodeSize() != 0) { // add the starting address of the il blob to the il blob hash table // we need to find this information from out of process for debugger inspection // APIs so we have to store this information where we can get it later pModule->SetDynamicIL(mdToken(tk), TADDR(startBuf), FALSE); DWORD dwImplFlags; //Set the RVA of the method. IfFailThrow(pRCW->GetMDImport()->GetMethodImplProps(tk, NULL, &dwImplFlags)); dwImplFlags |= (miManaged | miIL); IfFailThrow(pRCW->GetEmitter()->SetMethodProps(tk, (DWORD) -1, methodRVA, dwImplFlags)); } END_QCALL; }
/// <summary>Write the method to a supplied buffer</summary> /// <remarks><para>The buffer must be of the size supplied by <c>GetMethodSize</c>.</para> /// <para>Currently only write methods with 'Fat' headers and 'Fat' Sections - simpler.</para> /// <para>The buffer will normally be allocated by a call to <c>IMethodMalloc::Alloc</c></para></remarks> void Method::WriteMethod(IMAGE_COR_ILMETHOD* pMethod) { BYTE* pCode; COR_ILMETHOD_FAT* fatImage = (COR_ILMETHOD_FAT*)&pMethod->Fat; m_header.Flags &= ~CorILMethod_MoreSects; if (m_exceptions.size() > 0) { m_header.Flags |= CorILMethod_MoreSects; } memcpy(fatImage, &m_header, m_header.Size * sizeof(DWORD)); pCode = fatImage->GetCode(); SetBuffer(pCode); for (auto it = m_instructions.begin(); it != m_instructions.end(); ++it) { OperationDetails &details = Operations::m_mapNameOperationDetails[(*it)->m_operation]; if (details.op1 == REFPRE) { Write<BYTE>(details.op2); } else if (details.op1 == MOOT) { continue; } else { Write<BYTE>(details.op1); Write<BYTE>(details.op2); } switch(details.operandSize) { case Null: break; case Byte: Write<BYTE>((BYTE)(*it)->m_operand); break; case Word: Write<USHORT>((USHORT)(*it)->m_operand); break; case Dword: Write<ULONG>((ULONG)(*it)->m_operand); break; case Qword: Write<ULONGLONG>((*it)->m_operand); break; default: break; } if ((*it)->m_operation == CEE_SWITCH) { for (std::vector<long>::iterator offsetIter = (*it)->m_branchOffsets.begin(); offsetIter != (*it)->m_branchOffsets.end() ; offsetIter++) { Write<long>(*offsetIter); } } } WriteSections(); }