Add local to LocalVarSig
All source code is provided as is, with no warranties intended or implied. Use at your own risk.
// Parse
the local variables signature for the method we're rewriting, create a new
//
localvar signature containing one new local, and return the 0-based ordinal for
// that
new local.
UINT AddNewLocal()
{
// Get the metadata interfaces on the module
containing the method being rewritten.
HRESULT hr =
m_pICorProfilerInfo->GetModuleMetaData(
m_moduleId,
ofRead | ofWrite, IID_IMetaDataImport, (IUnknown**)&m_pMetaDataImport);
if (FAILED(hr))
{
return 0;
}
hr =
m_pMetaDataImport->QueryInterface(IID_IMetaDataEmit, (void**)&m_pMetaDataEmit);
if (FAILED(hr))
{
return 0;
}
// Here's a buffer into which we will write out the
modified signature. This sample
// code just bails out if it hits signatures that are
too big. Just one of many reasons
// why you use this code AT YOUR OWN RISK!
COR_SIGNATURE
rgbNewSig[4096];
// Use the signature token to look up the actual
signature
PCCOR_SIGNATURE
rgbOrigSig = NULL;
ULONG cbOrigSig;
hr =
m_pMetaDataImport->GetSigFromToken(m_tkLocalVarSig, &rgbOrigSig, &cbOrigSig);
if (FAILED(hr))
{
return 0;
}
// These are our running indices in the original and
new signature, respectively
UINT iOrigSig = 0;
UINT iNewSig = 0;
// First byte of signature must identify that it's a
locals signature!
assert(rgbOrigSig[iOrigSig] == SIG_LOCAL_SIG);
//
Copy SIG_LOCAL_SIG
if (iNewSig + 1 >
sizeof(rgbNewSig))
{
// We'll write one byte below but no room!
return 0;
}
rgbNewSig[iNewSig++]
= rgbOrigSig[iOrigSig++];
// Get original count of locals...
ULONG cOrigLocals;
ULONG cbOrigLocals;
ULONG cbNewLocals;
hr =
CorSigUncompressData(&rgbOrigSig[iOrigSig],
4, //
[IN] length of the signature
&cOrigLocals, //
[OUT] the expanded data
&cbOrigLocals); //
[OUT] length of the expanded data
if (FAILED(hr))
{
return 0;
}
// ...and write new count of locals (cOrigLocals+1)
if (iNewSig + 4 >
sizeof(rgbNewSig))
{
// CorSigCompressData will write up to 4 bytes but no
room!
return 0;
}
cbNewLocals =
CorSigCompressData(cOrigLocals+1, // [IN]
given uncompressed data
&rgbNewSig[iNewSig]);
// [OUT] buffer where data will be compressed and
stored.
iOrigSig +=
cbOrigLocals;
iNewSig +=
cbNewLocals;
// Copy the rest
if (iNewSig + cbOrigSig - iOrigSig >
sizeof(rgbNewSig))
{
// We'll copy cbOrigSig - iOrigSig bytes, but no room!
return 0;
}
memcpy(&rgbNewSig[iNewSig],
&rgbOrigSig[iOrigSig], cbOrigSig-iOrigSig);
iNewSig +=
cbOrigSig-iOrigSig;
// Manually append final local
ULONG cbLocalType;
if (iNewSig + 1 >
sizeof(rgbNewSig))
{
// We'll write one byte below but no room!
return 0;
}
rgbNewSig[iNewSig++] = ELEMENT_TYPE_VALUETYPE;
// You'll need to replace 0x01000002 with the
appropriate token that describes
// the type of this local (which, in turn, is the type
of the return value
// you're copying into that local). This can be
either a TypeDef or TypeRef,
// and it must be encoded (compressed).
if (iNewSig + 4 >
sizeof(rgbNewSig))
{
// CorSigCompressToken will write up to 4 bytes but no
room!
return 0;
}
cbLocalType =
CorSigCompressToken(0x01000002,
&rgbNewSig[iNewSig]);
iNewSig +=
cbLocalType;
// We're done building up the new signature blob. We
now need to add it to
// the metadata for this module, so we can get a token
back for it.
assert(iNewSig <=
sizeof(rgbNewSig));
hr =
m_pMetaDataEmit->GetTokenFromSig(&rgbNewSig[0],
// [IN] Signature to define.
iNewSig,
// [IN] Size of signature data.
&m_tkLocalVarSig);
// [OUT] returned signature token.
if (FAILED(hr))
{
return 0;
}
// 0-based index of new local = 0-based index of
original last local + 1
// = count of original
locals
return cOrigLocals;
}
Comments
- Anonymous
June 07, 2006
Previously, I posted about a bug with using the CLR Profiling API to inspect value-type return values....