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;
}