HRESULT MicrosoftInstrumentationEngine::AssemblyInjector::ImportMethodDef()

in src/InstrumentationEngine/AssemblyInjector.cpp [529:762]


HRESULT MicrosoftInstrumentationEngine::AssemblyInjector::ImportMethodDef(_In_ mdMethodDef sourceMethodDef, _Out_ mdMethodDef *pTargetMethodDef)
{
    HRESULT hr = S_OK;

    IfFalseRet(sourceMethodDef != mdTokenNil && sourceMethodDef != mdMethodDefNil, E_FAIL);

    TokenMap::const_iterator itr = m_methodDefMap.find(sourceMethodDef);
    if (itr != m_methodDefMap.end())
    {
        *pTargetMethodDef = itr->second;
        return hr;
    }

    CLogging::XmlDumpHelper dumpLogHelper(L"ImportMethodDef", 1);
    dumpLogHelper.WriteUlongNode(L"token", sourceMethodDef);

    mdTypeDef tkClass = mdTypeDefNil;
    WCHAR szName[MAX_NAME] = { 0 };
    ULONG cchName = 0;
    DWORD dwAttr = 0;
    PCCOR_SIGNATURE pvSigBlob = nullptr;
    ULONG cbSigBlob = 0;
    ULONG ulCodeRVA = 0;
    DWORD dwImplFlags = 0;
    IfFailRet(m_pSourceImport->GetMethodProps(sourceMethodDef,
        &tkClass,
        szName,
        _countof(szName),
        &cchName,
        &dwAttr,
        &pvSigBlob,
        &cbSigBlob,
        &ulCodeRVA,
        &dwImplFlags));

    dumpLogHelper.WriteStringNode(L"Name", szName);
    dumpLogHelper.WriteUlongNode(L"Class", tkClass);

    mdTypeDef targetTypeDef = mdTypeDefNil;
    IfFailRet(ImportTypeDef(tkClass, &targetTypeDef));
    IfFailRet(ConvertNonTypeSignatureCached(&pvSigBlob, &cbSigBlob));

    //this type might already have method def if type was merged. Use existing methods in this situation
    HRESULT hrFound = m_pTargetImport->FindMethod(targetTypeDef, szName, pvSigBlob, cbSigBlob, pTargetMethodDef);
    if (hrFound == CLDB_E_RECORD_NOTFOUND)
    {
        IfFailRet(m_pTargetEmit->DefineMethod(targetTypeDef,
            szName,
            dwAttr,
            pvSigBlob,
            cbSigBlob,
            0,
            dwImplFlags,
            pTargetMethodDef));
    }
    else if (FAILED(hrFound))
    {
        IfFailRet(hrFound);
    }
    else
    {
        dumpLogHelper.WriteStringNode(L"UseExisting", L"true");
    }


    m_methodDefMap[sourceMethodDef] = *pTargetMethodDef;
    dumpLogHelper.WriteUlongNode(L"targetToken", *pTargetMethodDef);


    CMetadataEnumCloser<IMetaDataImport2> spHCorEnum(m_pSourceImport, nullptr);
    mdParamDef curSourceParam = mdParamDefNil;
    while (S_OK == (hr = m_pSourceImport->EnumParams(spHCorEnum.Get(), sourceMethodDef, &curSourceParam, 1, nullptr)))
    {
        mdParamDef curTargetParam = mdParamDefNil;
        IfFailRet(ImportParam(curSourceParam, &curTargetParam));
    }
    IfFailRet(hr);

    if ((dwAttr & mdPinvokeImpl) != 0)
    {
        DWORD dwMappingFlags = 0;
        WCHAR szImportName[MAX_NAME] = { 0 };
        ULONG cchImportName = 0;
        mdModuleRef sourceImportDll = mdModuleRefNil;
        IfFailRet(m_pSourceImport->GetPinvokeMap(sourceMethodDef,
            &dwMappingFlags,
            szImportName,
            _countof(szImportName),
            &cchImportName,
            &sourceImportDll));

        mdModuleRef targetImportDll = mdModuleRefNil;
        IfFailRet(ImportModuleRef(sourceImportDll, &targetImportDll));
        IfFailRet(m_pTargetEmit->DefinePinvokeMap(*pTargetMethodDef, dwMappingFlags, szImportName, targetImportDll));
    }

    spHCorEnum.Reset(nullptr);
    mdGenericParam curSourceGenericParam = mdGenericParamNil;
    while (S_OK == (hr = m_pSourceImport->EnumGenericParams(spHCorEnum.Get(), sourceMethodDef, &curSourceGenericParam, 1, nullptr)))
    {
        mdGenericParam targetGenericParam = mdGenericParamNil;
        IfFailRet(ImportGenericParam(curSourceGenericParam, &targetGenericParam));
    }
    IfFailRet(hr);

    if (ulCodeRVA != 0)
    {
        VOID* pSourceCode = (BYTE*)m_pSourceImageBaseAddress + ulCodeRVA; // lgtm[cpp/suspicious-pointer-scaling-char] lgtm[cpp/incorrect-pointer-scaling-char] lgtm[cpp/suspicious-pointer-scaling]
        const IMAGE_COR_ILMETHOD_TINY* pSourceCodeTinyHeader = (IMAGE_COR_ILMETHOD_TINY*)pSourceCode;
        const IMAGE_COR_ILMETHOD_FAT* pSourceCodeFatHeader = (IMAGE_COR_ILMETHOD_FAT*)pSourceCode;
        bool isTinyHeader = ((pSourceCodeTinyHeader->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) == CorILMethod_TinyFormat);
        ULONG ilCodeSize = 0;
        ULONG headerSize = 0;
        ULONG ehClauseHeaderRVA = 0;
        IMAGE_COR_ILMETHOD_SECT_FAT* pFatEHHeader = nullptr;
        IMAGE_COR_ILMETHOD_SECT_SMALL* pSmallEHHeader = nullptr;
        ULONG totalCodeBlobSize = 0;
        if (isTinyHeader)
        {
            ilCodeSize = (((unsigned)pSourceCodeTinyHeader->Flags_CodeSize) >> (CorILMethod_FormatShift - 1));
            headerSize = sizeof(IMAGE_COR_ILMETHOD_TINY);
            totalCodeBlobSize = ilCodeSize + headerSize;
        }
        else
        {
            ilCodeSize = pSourceCodeFatHeader->CodeSize;
            // IMAGE_COR_ILMETHOD_FAT->Size represents size in DWords of this structure (currently 3) - see cor.h for details
            headerSize = pSourceCodeFatHeader->Size * 4;
            if ((pSourceCodeFatHeader->Flags & CorILMethod_MoreSects) == 0)
            {
                totalCodeBlobSize = ilCodeSize + headerSize;
            }
            else
            {
                // EH section starts at the 4 byte aligned address after the code
                ehClauseHeaderRVA = ((ulCodeRVA + headerSize + ilCodeSize - 1) & ~3) + 4;
                VOID* pEHSectionHeader = (BYTE*)m_pSourceImageBaseAddress + ehClauseHeaderRVA; // lgtm[cpp/suspicious-pointer-scaling-char] lgtm[cpp/incorrect-pointer-scaling-char] lgtm[cpp/suspicious-pointer-scaling]
                BYTE kind = *(BYTE*)pEHSectionHeader;
                ULONG dataSize = 0;
                if (kind & CorILMethod_Sect_FatFormat)
                {
                    pFatEHHeader = (IMAGE_COR_ILMETHOD_SECT_FAT*)pEHSectionHeader;
                    dataSize = pFatEHHeader->DataSize;
                }
                else
                {
                    pSmallEHHeader = (IMAGE_COR_ILMETHOD_SECT_SMALL*)pEHSectionHeader;
                    dataSize = pSmallEHHeader->DataSize;
                }
                // take the difference between the RVAs to ensure we account for the padding
                // bytes between the end of the IL code and the start of the EH clauses
                totalCodeBlobSize = (ehClauseHeaderRVA - ulCodeRVA) + dataSize;
            }
        }

        VOID* pTargetCode = m_pTargetMethodMalloc->Alloc(totalCodeBlobSize);
        //IfNullRetOOM(pTargetCode);

        // convert header
        memcpy_s(pTargetCode, headerSize, pSourceCode, headerSize);
        if (!isTinyHeader)
        {
            IMAGE_COR_ILMETHOD_FAT* pTargetCodeFatHeader = (IMAGE_COR_ILMETHOD_FAT*)pTargetCode;
            IfFailRet(ImportLocalVarSig(pTargetCodeFatHeader->LocalVarSigTok, &(pTargetCodeFatHeader->LocalVarSigTok)));
        }

        // convert IL code
        IfFailRet(ConvertILCode((BYTE*)pSourceCode + headerSize, (BYTE*)pTargetCode + headerSize, ilCodeSize));

        //convert EH
        if (pFatEHHeader != nullptr)
        {
            IMAGE_COR_ILMETHOD_SECT_FAT* pTargetEHHeader = (IMAGE_COR_ILMETHOD_SECT_FAT*)((BYTE*)pTargetCode + (ehClauseHeaderRVA - ulCodeRVA));
            pTargetEHHeader->Kind = pFatEHHeader->Kind;
            pTargetEHHeader->DataSize = pFatEHHeader->DataSize;
            IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pSourceEHClause = (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)(pFatEHHeader + 1); // lgtm[cpp/suspicious-pointer-scaling]
            IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pTargetEHClause = (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)(pTargetEHHeader + 1); // lgtm[cpp/suspicious-pointer-scaling]
            int numClauses = (pTargetEHHeader->DataSize - 4) / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT);
            for (int i = 0; i < numClauses; i++)
            {
                pTargetEHClause->Flags = pSourceEHClause->Flags;
                pTargetEHClause->TryOffset = pSourceEHClause->TryOffset;
                pTargetEHClause->TryLength = pSourceEHClause->TryLength;
                pTargetEHClause->HandlerOffset = pSourceEHClause->HandlerOffset;
                pTargetEHClause->HandlerLength = pSourceEHClause->HandlerLength;
                if ((pSourceEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) != 0)
                {
                    IfFailRet(ConvertToken(pSourceEHClause->ClassToken, (mdToken*)&(pTargetEHClause->ClassToken)));
                }
                else
                {
                    pTargetEHClause->FilterOffset = pSourceEHClause->FilterOffset;
                }
                pTargetEHClause++;
                pSourceEHClause++;
            }
        }
        else if (pSmallEHHeader != nullptr)
        {
            IMAGE_COR_ILMETHOD_SECT_SMALL* pTargetEHHeader = (IMAGE_COR_ILMETHOD_SECT_SMALL*)((BYTE*)pTargetCode + (ehClauseHeaderRVA - ulCodeRVA));
            pTargetEHHeader->Kind = pSmallEHHeader->Kind;
            pTargetEHHeader->DataSize = pSmallEHHeader->DataSize;
            IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* pSourceEHClause = (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)(pSmallEHHeader + 1);  // lgtm[cpp/suspicious-pointer-scaling]
            IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* pTargetEHClause = (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)(pTargetEHHeader + 1); // lgtm[cpp/suspicious-pointer-scaling]
            int numClauses = (pSmallEHHeader->DataSize - 4) / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL);
            for (int i = 0; i < numClauses; i++)
            {
                pTargetEHClause->Flags = pSourceEHClause->Flags;
                pTargetEHClause->TryOffset = pSourceEHClause->TryOffset;
                pTargetEHClause->TryLength = pSourceEHClause->TryLength;
                pTargetEHClause->HandlerOffset = pSourceEHClause->HandlerOffset;
                pTargetEHClause->HandlerLength = pSourceEHClause->HandlerLength;
                if ((pSourceEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) != 0)
                {
                    IfFailRet(ConvertToken(pSourceEHClause->ClassToken, (mdToken*)&(pTargetEHClause->ClassToken)));
                }
                else
                {
                    pTargetEHClause->FilterOffset = pSourceEHClause->FilterOffset;
                }
                pTargetEHClause++;
                pSourceEHClause++;
            }
        }

        //because the metadata record wasn't created with an RVA, this connects the methodDef to the code
        IfFailRet(m_pProfilerInfo->SetILFunctionBody((ModuleID)m_pTargetImage, *pTargetMethodDef, (LPCBYTE)pTargetCode));
    }
    else
    {
    }

    return hr;
}