HRESULT MicrosoftInstrumentationEngine::CInstruction::GetSignatureInfoFromCallToken()

in src/InstrumentationEngine/Instruction.cpp [1510:1635]


HRESULT MicrosoftInstrumentationEngine::CInstruction::GetSignatureInfoFromCallToken(
    _In_ IMethodInfo* pMethodInfo,
    _Out_ PCCOR_SIGNATURE* ppSig,
    _Out_ DWORD* pSigLength,
    _Out_ CorCallingConvention* pCallConv,
    _Out_ DWORD* pParameterCount,
    _Out_ CorElementType* pRetTypeElementType
    )
{
    HRESULT hr = S_OK;

    ILOperandType operandType;
    IfFailRet(GetOperandType(&operandType));

    if (operandType != ILOperandType_Token)
    {
        CLogging::LogError(_T("CInstruction::GetStackImpact - Unexpected il operand type"));
        return E_FAIL;
    }

    COperandInstruction* pOperandThis = (COperandInstruction*)this;
    mdToken callToken = mdTokenNil;
    IfFailRet(pOperandThis->GetOperandValue(sizeof(mdToken), (BYTE*)&callToken));

    CComPtr<IModuleInfo> pModuleInfo;
    IfFailRet(pMethodInfo->GetModuleInfo(&pModuleInfo));

    CComPtr<IMetaDataImport> pMetaDataImport;
    IfFailRet(pModuleInfo->GetMetaDataImport((IUnknown**)&pMetaDataImport));

    // if the callToken is a methodSpec, get the parent MethodDef/MethodRef
    // to later retrieve the actual method signature
    if (TypeFromToken(callToken) == mdtMethodSpec)
    {
        CComPtr<IMetaDataImport2> pMetaDataImport2;
        IfFailRet(pMetaDataImport->QueryInterface(IID_IMetaDataImport2, (LPVOID*)&pMetaDataImport2));

        mdToken parentCallToken = mdTokenNil;
        IfFailRet(pMetaDataImport2->GetMethodSpecProps(
            callToken,
            &parentCallToken,
            NULL,
            NULL
        ));

        callToken = parentCallToken;
    }

    PCCOR_SIGNATURE pSigUntouched = nullptr;
    PCCOR_SIGNATURE pSig = nullptr;
    ULONG sigLength = 0;

    // Get the signature for the method token
    if (TypeFromToken(callToken) == mdtMemberRef)
    {
        mdToken targetToken = mdTokenNil;

        IfFailRet(pMetaDataImport->GetMemberRefProps(
            callToken,
            nullptr,
            nullptr,
            0,
            nullptr,
            &pSig,
            &sigLength
            ));
    }
    else if (TypeFromToken(callToken) == mdtMethodDef)
    {
        IfFailRet(pMetaDataImport->GetMemberProps(
            callToken,
            nullptr,
            nullptr,
            0,
            nullptr,
            nullptr,
            &pSig,
            &sigLength,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            nullptr
            ));
    }
    else if (TypeFromToken(callToken) == mdtSignature)
    {
        IfFailRet(pMetaDataImport->GetSigFromToken(
            callToken,
            &pSig,
            &sigLength
            ));
    }
    pSigUntouched = pSig;

    // get a method signature, which looks like this: "calling Conv" + "argument Cnt" + "return Type" + "arg1" + "arg2" + ...
    CorCallingConvention callConv = IMAGE_CEE_CS_CALLCONV_MAX; // = 0x10 - first invalid calling convention;
    pSig += CorSigUncompressData(pSig, (ULONG *)&callConv);
    if ((callConv == IMAGE_CEE_CS_CALLCONV_MAX) || (callConv == IMAGE_CEE_CS_CALLCONV_FIELD))
    {
        CLogging::LogError(_T("Unexpected calling convention on method"));
        return E_UNEXPECTED;
    }

    if (IsFlagSet(callConv, IMAGE_CEE_CS_CALLCONV_GENERIC))
    {
        DWORD dwGenericParameterCount;
        // get the generic argument count
        pSig += CorSigUncompressData(pSig, &dwGenericParameterCount);
    }

    ULONG parameterCount = 0;
    // get the argument count
    pSig += CorSigUncompressData(pSig, &parameterCount);

    CorElementType retTypeElementType;
    pSig += CorSigUncompressData(pSig, (ULONG *)&retTypeElementType);

    *ppSig = pSigUntouched;
    *pSigLength = sigLength;
    *pCallConv = callConv;
    *pParameterCount = parameterCount;
    *pRetTypeElementType = retTypeElementType;

    return hr;
}