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 (1)

  1. Previously, I posted about a bug with using the CLR Profiling API to inspect value-type return values….