HRESULT MicrosoftInstrumentationEngine::AssemblyInjector::ConvertILCode()

in src/InstrumentationEngine/AssemblyInjector.cpp [1424:1534]


HRESULT MicrosoftInstrumentationEngine::AssemblyInjector::ConvertILCode(_In_reads_bytes_(bufferSize) const BYTE* pSourceILCode, _Inout_updates_bytes_(bufferSize) BYTE* pTargetILCode, ULONG32 bufferSize)
{
    HRESULT hr = S_OK;

    for (ULONG32 cursor = 0; cursor < bufferSize;)
    {
        // MSIL opcodes can be either 1 byte or 2 bytes, possible followed by an inline value whose size is opcode dependent.
        ULONG32 opCode = pSourceILCode[cursor];
        pTargetILCode[cursor] = pSourceILCode[cursor];
        cursor++;
        // All valid 2 byte opcodes start with 0xFE, otherwise it is invalid or a 1 byte opcode.
        if (opCode == 0xFE)
        {
            if (cursor >= bufferSize)
                return E_FAIL;
            pTargetILCode[cursor] = pSourceILCode[cursor];
            opCode = pSourceILCode[cursor] + 256;
            cursor++;
        }
        // make sure we stay within the array
        if (opCode > MAX_MSIL_OPCODE)
            return E_FAIL;
        OPCLSA inlineValueKind = g_opcodeInlineValues[opCode];
        switch (inlineValueKind)
        {
        case opclsaInlineNone:
            break;

        case opclsaShortInlineI:		  // I1: signed  8-bit immediate value
        case opclsaShortInlineVar:		  // U1: local or arg index, unsigned 8-bit
        case opclsaShortInlineBrTarget:	   // I1: signed 8-bit offset from instruction after the branch
        {
            if (cursor + 1 > bufferSize)
                return E_FAIL;
            pTargetILCode[cursor] = pSourceILCode[cursor];
            cursor++;
            break;
        }

        case opclsaInlineVar:			  // U2: local or arg index, unsigned 16-bit
        {
            if (cursor + 2 > bufferSize)
                return E_FAIL;
            pTargetILCode[cursor] = pSourceILCode[cursor];
            pTargetILCode[cursor + 1] = pSourceILCode[cursor + 1];
            cursor += 2;
            break;
        }
        case opclsaInlineRVA:			  // U4: for ldptr
        {
            //FAILURE(L"Converting IL code with inline RVA not supported");
            return E_NOTIMPL;
        }
        case opclsaInlineSig:			  // T: Token for identifying a method signature (calli)
        {
            //FAILURE(L"Converting IL code with calli not supported");
            return E_NOTIMPL;
        }
        case opclsaInlineI:			  // I4: signed 32-bit immediate value
        case opclsaShortInlineR:      // R4: single precision real immediate
        case opclsaInlineBrTarget:		  // I4: signed 32-bit offset from instruction after the branch
        {
            if (cursor + 4 > bufferSize)
                return E_FAIL;
            memcpy_s(pTargetILCode + cursor, (bufferSize - cursor), pSourceILCode + cursor, 4);
            cursor += 4;
            break;
        }

        case opclsaInlineI8:	      // I8: signed 64-bit immediate value
        case opclsaInlineR:			  // R8: double precising real immediate
        {
            if (cursor + 8 > bufferSize)
                return E_FAIL;
            memcpy_s(pTargetILCode + cursor, (bufferSize - cursor), pSourceILCode + cursor, 8);
            cursor += 8;
            break;
        }

        case opclsaInlineSwitch:		  // Multiple operands for switch statement
        {
            if (cursor + 4 > bufferSize)
                return E_FAIL;
            ULONG32 numCases = *(ULONG32*)(pSourceILCode + cursor);
            memcpy_s(pTargetILCode + cursor, (bufferSize - cursor), pSourceILCode + cursor, 4);
            cursor += 4;
            if (cursor + 4 * numCases > bufferSize)
                return E_FAIL;
            memcpy_s(pTargetILCode + cursor, (bufferSize - cursor), pSourceILCode + cursor, 4 * numCases);
            cursor += 4 * numCases;
            break;
        }

        case opclsaInlineMethod:		  // T: Token for identifying a methods
        case opclsaInlineType: 		  // T: Token for identifying an object type (box, unbox, ldobj, cpobj, initobj, stobj, mkrefany, refanyval, castclass, isinst, newarr, ldelema)
        case opclsaInlineField:		  // T: Token for identifying a field (ldflda, ldsflda, ldfld, ldsfld, ldsfld, stfld, stsfld)
        case opclsaInlineTok:			  // T: Token for ldtoken
        case opclsaInlineString:		  // T: Token for identifying a string (ldstr)
        {
            if (cursor + 4 > bufferSize)
                return E_FAIL;
            mdToken tk = *(mdToken*)(pSourceILCode + cursor);
            IfFailRet(ConvertToken(tk, &tk));
            *(mdToken*)(pTargetILCode + cursor) = tk;
            cursor += 4;
            break;
        }
        }
    }
    return hr;
}