diff options
-rw-r--r-- | Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp | 478 | ||||
-rw-r--r-- | Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp | 1052 |
2 files changed, 1528 insertions, 2 deletions
diff --git a/Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp b/Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp index 81471bb1b3..561f591663 100644 --- a/Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp +++ b/Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp @@ -1 +1,477 @@ -// This blog post originally appeared on David Broman's blog on 10/13/2005
#include "SigFormat.cpp"
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// This file does not compile on its own. It contains snippets of code you can add
// to a working profiler, so that your profiler will invoke instances of the SigFormat
// object to parse and pretty-print all the types in all modules as they're loaded.
//
// The functions are ordered from callees to callers (so no forward declarations are
// necessary). If you prefer a top-down approach to learning code, then start
// at the bottom of the file.
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// ****************************************************************
// HELPERS TO READ THROUGH METADATA, FIND SIGNATURES, AND INVOKE THE PARSER
// ****************************************************************
// Simple wrapper to create an instance of SigFormat and invoke it
HRESULT DoParse(sig_byte * sig, ULONG cbSig)
{
SigFormat sf;
HRESULT hr;
bool fRet = sf.Parse(sig, cbSig);
if (!fRet)
{
hr = E_FAIL;
goto Error;
}
hr = S_OK;
Cleanup:
return hr;
Error:
goto Cleanup;
}
// Takes an mdProperty, prints an intro line, then invokes the parser / printer
HRESULT PrintProperty(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdProperty md)
{
HRESULT hr;
mdTypeDef td;
WCHAR wszName[500];
ULONG cchName;
PCCOR_SIGNATURE sigMember;
ULONG cbSigMember;
DWORD dwAttr;
DWORD dwCPlusTypeFlag;
UVCP_CONSTANT pValue;
ULONG cchValue;
mdMethodDef mdSetter;
mdMethodDef mdGetter;
mdMethodDef aOtherMethods[100];
ULONG cOtherMethods;
hr = pMDImport->GetPropertyProps(md, // The member for which to get props.
&td, // Put member's class here.
wszName, // Put member's name here.
dimensionof(wszName), // Size of szMember buffer in wide chars.
&cchName, // Put actual size here
&dwAttr, // Put flags here.
&sigMember, // [OUT] point to the blob value of meta data
&cbSigMember, // [OUT] actual size of signature blob
&dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_*
&pValue, // [OUT] constant value
&cchValue,
&mdSetter, // [OUT] setter method of the property
&mdGetter, // [OUT] getter method of the property
aOtherMethods, // [OUT] other method of the property
dimensionof(aOtherMethods), // [IN] size of rmdOtherMethod
&cOtherMethods); // [OUT] total number of other method of this property
if (FAILED(hr))
{
goto Error;
}
printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);
DoParse((sig_byte *) sigMember, cbSigMember);
hr = S_OK;
Cleanup:
return hr;
Error:
goto Cleanup;
}
// Takes a field token, prints an intro line, then invokes the parser / printer
HRESULT PrintField(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdToken md)
{
HRESULT hr;
mdTypeDef td;
WCHAR wszName[500];
ULONG cchName;
PCCOR_SIGNATURE sigMember;
ULONG cbSigMember;
DWORD dwAttr;
DWORD dwCPlusTypeFlag;
UVCP_CONSTANT pValue;
ULONG cchValue;
hr = pMDImport->GetFieldProps(md, // The member for which to get props.
&td, // Put member's class here.
wszName, // Put member's name here.
dimensionof(wszName), // Size of szMember buffer in wide chars.
&cchName, // Put actual size here
&dwAttr, // Put flags here.
&sigMember, // [OUT] point to the blob value of meta data
&cbSigMember, // [OUT] actual size of signature blob
&dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_*
&pValue, // [OUT] constant value
&cchValue); // [OUT] size of constant string in chars, 0 for non-strings.
if (FAILED(hr))
{
goto Error;
}
printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);
DoParse((sig_byte *) sigMember, cbSigMember);
hr = S_OK;
Cleanup:
return hr;
Error:
goto Cleanup;
}
// Takes an mdMethodDef, prints an intro line, then invokes the parser / printer on its signature and its locals
HRESULT PrintMethodDef(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdMethodDef md)
{
HRESULT hr;
mdTypeDef td;
WCHAR wszMethod[500];
ULONG cchMethod;
DWORD dwAttr;
PCCOR_SIGNATURE sigParam;
PCCOR_SIGNATURE sigLocal;
ULONG cbSigParam;
ULONG cbSigLocal;
ULONG ulCodeRVA;
DWORD dwImplFlags;
BOOL fMore;
LPCBYTE pMethodHeader = NULL;
ULONG cbMethodSize;
IMAGE_COR_ILMETHOD_TINY* pimt = NULL;
IMAGE_COR_ILMETHOD_FAT* pimf = NULL;
hr = pMDImport->GetMethodProps(md, // The method for which to get props.
&td, // Put method's class here.
wszMethod, // Put method's name here.
dimensionof(wszMethod), // Size of szMethod buffer in wide chars.
&cchMethod, // Put actual size here
&dwAttr, // Put flags here.
&sigParam, // [OUT] point to the blob value of meta data
&cbSigParam, // [OUT] actual size of signature blob
&ulCodeRVA, // [OUT] codeRVA
&dwImplFlags); // [OUT] Impl. Flags
if (FAILED(hr))
{
goto Error;
}
printf("\n%S.%S (0x%x)\n", wszClassName, wszMethod, md);
// Method prototype signature parse
DoParse((sig_byte *) sigParam, cbSigParam);
// Method locals signature parse
hr = g_pProfilerInfo->GetILFunctionBody(moduleID,
md,
&pMethodHeader,
&cbMethodSize);
if (FAILED(hr))
{
goto EndLocal;
}
// The following odd-looking lines of code decode the method header, ensure
// it is in a format that contains local variables, and then grabs the local
// variable signature out of the header.
pimt = (IMAGE_COR_ILMETHOD_TINY*) pMethodHeader;
if ((pimt->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) != CorILMethod_FatFormat)
{
goto EndLocal;
}
pimf = (IMAGE_COR_ILMETHOD_FAT*) pMethodHeader;
if (pimf->LocalVarSigTok == 0)
{
goto EndLocal;
}
hr = pMDImport->GetSigFromToken(pimf->LocalVarSigTok,
&sigLocal,
&cbSigLocal);
DoParse((sig_byte *) sigLocal, cbSigLocal);
EndLocal:
hr = S_OK;
Cleanup:
return hr;
Error:
goto Cleanup;
}
// Simple helper to print an intro line for a class
void PrintHeader(LPCWSTR wszClassName, mdTypeDef td, LPCSTR szCategory)
{
printf("\n--------------------------------------------\n");
printf("%S (0x%x):\t%s\n", wszClassName, td, szCategory);
printf("--------------------------------------------\n\n");
}
// Combines above functions to print the methods, properties, and fields of a class
HRESULT PrintTypedef(ModuleID moduleID, IMetaDataImport* pMDImport, mdTypeDef td)
{
HRESULT hr;
HCORENUM hEnum = NULL;
mdMethodDef aMethods[100];
mdFieldDef aFields[100];
mdFieldDef aProperties[100];
ULONG cMethodDefs;
ULONG cFields;
ULONG cProperties;
ULONG i;
WCHAR wszTdName[200];
ULONG cchTdName;
DWORD dwTypeDefFlags;
mdToken tkExtends;
BOOL fMore;
hr = pMDImport->GetTypeDefProps(td, // [IN] TypeDef token for inquiry.
wszTdName, // [OUT] Put name here.
dimensionof(wszTdName), // [IN] size of name buffer in wide chars.
&cchTdName, // [OUT] put size of name (wide chars) here.
&dwTypeDefFlags, // [OUT] Put flags here.
&tkExtends); // [OUT] Put base class TypeDef/TypeRef here.
if (FAILED(hr))
{
goto Error;
}
PrintHeader(wszTdName, td, "METHODDEFS");
fMore = TRUE;
while (fMore)
{
hr = pMDImport->EnumMethods(&hEnum,
td, // [IN] TypeDef to scope the enumeration.
aMethods, // [OUT] Put MethodDefs here.
dimensionof(aMethods), // [IN] Max MethodDefs to put.
&cMethodDefs); // [OUT] Put # put here.
if (FAILED(hr))
{
goto Error;
}
if (hr == S_FALSE)
{
fMore = FALSE;
}
for (i=0; i < cMethodDefs; i++)
{
hr = PrintMethodDef(moduleID, pMDImport, wszTdName, aMethods[i]);
if (FAILED(hr))
{
// do you care? If so, do something about this.
}
}
}
pMDImport->CloseEnum(hEnum);
hEnum = NULL;
PrintHeader(wszTdName, td, "FIELDS");
fMore = TRUE;
while (fMore)
{
hr = pMDImport->EnumFields(&hEnum,
td,
Fields,
dimensionof(aFields),
&cFields);
if (FAILED(hr))
{
goto Error;
}
if (hr == S_FALSE)
{
fMore = FALSE;
}
for (i=0; i < cFields; i++)
{
hr = PrintField(moduleID, pMDImport, wszTdName, aFields[i]);
if (FAILED(hr))
{
// do you care? If so, do something about this.
}
}
}
pMDImport->CloseEnum(hEnum);
hEnum = NULL;
PrintHeader(wszTdName, td, "PROPERTIES");
fMore = TRUE;
while (fMore)
{
hr = pMDImport->EnumProperties(&hEnum,
td,
aProperties,
dimensionof(aProperties),
&cProperties);
if (FAILED(hr))
{
goto Error;
}
if (hr == S_FALSE)
{
fMore = FALSE;
}
for (i=0; i < cProperties; i++)
{
hr = PrintProperty(moduleID, pMDImport, wszTdName, aProperties[i]);
if (FAILED(hr))
{
// do you care? If so, do something about this.
}
}
}
pMDImport->CloseEnum(hEnum);
hEnum = NULL;
hr = S_OK;
Cleanup:
if (hEnum != NULL)
{
pMDImport->CloseEnum(hEnum);
}
return hr;
Error:
goto Cleanup;
}
// Enumerates the typedefs in a module via the metadata interface, and calls PrintTypedef
// on each one
HRESULT PrintMetadata(ModuleID moduleID, IMetaDataImport* pMDImport)
{
HRESULT hr;
HCORENUM hEnum = NULL;
mdTypeDef aTypeDefs[100];
ULONG cTypeDefs;
ULONG i;
BOOL fMoreTypeDefs = TRUE;
while (fMoreTypeDefs)
{
hr = pMDImport->EnumTypeDefs(&hEnum,
aTypeDefs,
dimensionof(aTypeDefs),
&cTypeDefs);
if (FAILED(hr))
{
goto Error;
}
if (hr == S_FALSE)
{
fMoreTypeDefs = FALSE;
}
for (i=0; i < cTypeDefs; i++)
{
hr = PrintTypedef(moduleID, pMDImport, aTypeDefs[i]);
if (FAILED(hr))
{
// do you care? If so, do something about this.
}
}
}
hr = S_OK;
Cleanup:
if (hEnum != NULL)
{
pMDImport->CloseEnum(hEnum);
}
return hr;
Error:
goto Cleanup;
}
// ****************************************************************
// Add this to your profiler's ICorProfilerCallback2::ModuleLoadFinished implementation.
// It is assumed your copy of the ICorProfilerInfo2 interface may be accessed via
// g_pProfilerInfo. Change the code to fit your profiler as appropriate.
// ****************************************************************
//
// As a module gets loaded, this callback implementation initiates the pretty-printer to
// log all the types to stdout.
HRESULT CYourProfImpl::ModuleLoadFinished( ModuleID moduleID, HRESULT hrStatus )
{
HRESULT hr;
LPCBYTE pbBaseLoadAddr;
WCHAR wszName[300];
ULONG cchNameIn = dimensionof(wszName);
ULONG cchNameOut;
AssemblyID assemblyID;
hr = g_pProfilerInfo->GetModuleInfo(moduleID,
&pbBaseLoadAddr,
cchNameIn,
&cchNameOut,
wszName,
&assemblyID);
if (FAILED(hr))
{
return hr;
}
printf("MODULE LOAD FINISHED: %S\n", wszName);
IMetaDataImport *pMDImport = NULL;
hr = g_pProfilerInfo->GetModuleMetaData(moduleID,
ofRead,
IID_IMetaDataImport,
(IUnknown **)&pMDImport );
if (FAILED(hr))
{
return hr;
}
hr = PrintMetadata(moduleID, pMDImport);
if (FAILED(hr))
{
// Do any error handling as appropriate
}
hr = S_OK;
Cleanup:
return hr;
Error:
goto Cleanup;
}
\ No newline at end of file +// This blog post originally appeared on David Broman's blog on 10/13/2005 + +#include "SigFormat.cpp" + + + // --------------------------------------------------------------------- + // --------------------------------------------------------------------- + // This file does not compile on its own. It contains snippets of code you can add + // to a working profiler, so that your profiler will invoke instances of the SigFormat + // object to parse and pretty-print all the types in all modules as they're loaded. + // + // The functions are ordered from callees to callers (so no forward declarations are + // necessary). If you prefer a top-down approach to learning code, then start + // at the bottom of the file. + // --------------------------------------------------------------------- + // --------------------------------------------------------------------- + + + // **************************************************************** + // HELPERS TO READ THROUGH METADATA, FIND SIGNATURES, AND INVOKE THE PARSER + // **************************************************************** + + // Simple wrapper to create an instance of SigFormat and invoke it +HRESULT DoParse(sig_byte * sig, ULONG cbSig) +{ + SigFormat sf; + HRESULT hr; + bool fRet = sf.Parse(sig, cbSig); + if (!fRet) + { + hr = E_FAIL; + goto Error; + } + + hr = S_OK; + + Cleanup: + return hr; + + Error: + goto Cleanup; +} + + // Takes an mdProperty, prints an intro line, then invokes the parser / printer +HRESULT PrintProperty(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdProperty md) +{ + HRESULT hr; + mdTypeDef td; + WCHAR wszName[500]; + ULONG cchName; + PCCOR_SIGNATURE sigMember; + ULONG cbSigMember; + DWORD dwAttr; + DWORD dwCPlusTypeFlag; + UVCP_CONSTANT pValue; + ULONG cchValue; + mdMethodDef mdSetter; + mdMethodDef mdGetter; + mdMethodDef aOtherMethods[100]; + ULONG cOtherMethods; + + hr = pMDImport->GetPropertyProps(md, // The member for which to get props. + &td, // Put member's class here. + wszName, // Put member's name here. + dimensionof(wszName), // Size of szMember buffer in wide chars. + &cchName, // Put actual size here + &dwAttr, // Put flags here. + &sigMember, // [OUT] point to the blob value of meta data + &cbSigMember, // [OUT] actual size of signature blob + &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + &pValue, // [OUT] constant value + &cchValue, + &mdSetter, // [OUT] setter method of the property + &mdGetter, // [OUT] getter method of the property + aOtherMethods, // [OUT] other method of the property + dimensionof(aOtherMethods), // [IN] size of rmdOtherMethod + &cOtherMethods); // [OUT] total number of other method of this property + if (FAILED(hr)) + { + goto Error; + } + + printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md); + DoParse((sig_byte *) sigMember, cbSigMember); + + hr = S_OK; + + Cleanup: + return hr; + + Error: + goto Cleanup; + +} + + + // Takes a field token, prints an intro line, then invokes the parser / printer +HRESULT PrintField(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdToken md) +{ + HRESULT hr; + mdTypeDef td; + WCHAR wszName[500]; + ULONG cchName; + PCCOR_SIGNATURE sigMember; + ULONG cbSigMember; + DWORD dwAttr; + DWORD dwCPlusTypeFlag; + UVCP_CONSTANT pValue; + ULONG cchValue; + + hr = pMDImport->GetFieldProps(md, // The member for which to get props. + &td, // Put member's class here. + wszName, // Put member's name here. + dimensionof(wszName), // Size of szMember buffer in wide chars. + &cchName, // Put actual size here + &dwAttr, // Put flags here. + &sigMember, // [OUT] point to the blob value of meta data + &cbSigMember, // [OUT] actual size of signature blob + &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + &pValue, // [OUT] constant value + &cchValue); // [OUT] size of constant string in chars, 0 for non-strings. + if (FAILED(hr)) + { + goto Error; + } + + printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md); + DoParse((sig_byte *) sigMember, cbSigMember); + + hr = S_OK; + + Cleanup: + return hr; + + Error: + goto Cleanup; + +} + + // Takes an mdMethodDef, prints an intro line, then invokes the parser / printer on its signature and its locals +HRESULT PrintMethodDef(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdMethodDef md) +{ + HRESULT hr; + mdTypeDef td; + WCHAR wszMethod[500]; + ULONG cchMethod; + DWORD dwAttr; + PCCOR_SIGNATURE sigParam; + PCCOR_SIGNATURE sigLocal; + ULONG cbSigParam; + ULONG cbSigLocal; + ULONG ulCodeRVA; + DWORD dwImplFlags; + BOOL fMore; + LPCBYTE pMethodHeader = NULL; + ULONG cbMethodSize; + IMAGE_COR_ILMETHOD_TINY* pimt = NULL; + IMAGE_COR_ILMETHOD_FAT* pimf = NULL; + + hr = pMDImport->GetMethodProps(md, // The method for which to get props. + &td, // Put method's class here. + wszMethod, // Put method's name here. + dimensionof(wszMethod), // Size of szMethod buffer in wide chars. + &cchMethod, // Put actual size here + &dwAttr, // Put flags here. + &sigParam, // [OUT] point to the blob value of meta data + &cbSigParam, // [OUT] actual size of signature blob + &ulCodeRVA, // [OUT] codeRVA + &dwImplFlags); // [OUT] Impl. Flags + if (FAILED(hr)) + { + goto Error; + } + + printf("\n%S.%S (0x%x)\n", wszClassName, wszMethod, md); + + // Method prototype signature parse + DoParse((sig_byte *) sigParam, cbSigParam); + + // Method locals signature parse + hr = g_pProfilerInfo->GetILFunctionBody(moduleID, + md, + &pMethodHeader, + &cbMethodSize); + if (FAILED(hr)) + { + goto EndLocal; + } + + // The following odd-looking lines of code decode the method header, ensure + // it is in a format that contains local variables, and then grabs the local + // variable signature out of the header. + + pimt = (IMAGE_COR_ILMETHOD_TINY*) pMethodHeader; + if ((pimt->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) != CorILMethod_FatFormat) + { + goto EndLocal; + } + + pimf = (IMAGE_COR_ILMETHOD_FAT*) pMethodHeader; + if (pimf->LocalVarSigTok == 0) + { + goto EndLocal; + } + + hr = pMDImport->GetSigFromToken(pimf->LocalVarSigTok, + &sigLocal, + &cbSigLocal); + + DoParse((sig_byte *) sigLocal, cbSigLocal); + + EndLocal: + + hr = S_OK; + + Cleanup: + return hr; + + Error: + goto Cleanup; +} + + + // Simple helper to print an intro line for a class +void PrintHeader(LPCWSTR wszClassName, mdTypeDef td, LPCSTR szCategory) +{ + printf("\n--------------------------------------------\n"); + printf("%S (0x%x):\t%s\n", wszClassName, td, szCategory); + printf("--------------------------------------------\n\n"); +} + + + // Combines above functions to print the methods, properties, and fields of a class +HRESULT PrintTypedef(ModuleID moduleID, IMetaDataImport* pMDImport, mdTypeDef td) +{ + HRESULT hr; + HCORENUM hEnum = NULL; + mdMethodDef aMethods[100]; + mdFieldDef aFields[100]; + mdFieldDef aProperties[100]; + ULONG cMethodDefs; + ULONG cFields; + ULONG cProperties; + ULONG i; + WCHAR wszTdName[200]; + ULONG cchTdName; + DWORD dwTypeDefFlags; + mdToken tkExtends; + BOOL fMore; + + hr = pMDImport->GetTypeDefProps(td, // [IN] TypeDef token for inquiry. + wszTdName, // [OUT] Put name here. + dimensionof(wszTdName), // [IN] size of name buffer in wide chars. + &cchTdName, // [OUT] put size of name (wide chars) here. + &dwTypeDefFlags, // [OUT] Put flags here. + &tkExtends); // [OUT] Put base class TypeDef/TypeRef here. + if (FAILED(hr)) + { + goto Error; + } + + PrintHeader(wszTdName, td, "METHODDEFS"); + fMore = TRUE; + while (fMore) + { + hr = pMDImport->EnumMethods(&hEnum, + td, // [IN] TypeDef to scope the enumeration. + aMethods, // [OUT] Put MethodDefs here. + dimensionof(aMethods), // [IN] Max MethodDefs to put. + &cMethodDefs); // [OUT] Put # put here. + if (FAILED(hr)) + { + goto Error; + } + + if (hr == S_FALSE) + { + fMore = FALSE; + } + + for (i=0; i < cMethodDefs; i++) + { + hr = PrintMethodDef(moduleID, pMDImport, wszTdName, aMethods[i]); + if (FAILED(hr)) + { + // do you care? If so, do something about this. + } + } + } + + pMDImport->CloseEnum(hEnum); + hEnum = NULL; + + PrintHeader(wszTdName, td, "FIELDS"); + fMore = TRUE; + while (fMore) + { + hr = pMDImport->EnumFields(&hEnum, + td, + Fields, + dimensionof(aFields), + &cFields); + + if (FAILED(hr)) + { + goto Error; + } + + if (hr == S_FALSE) + { + fMore = FALSE; + } + + for (i=0; i < cFields; i++) + { + hr = PrintField(moduleID, pMDImport, wszTdName, aFields[i]); + if (FAILED(hr)) + { + // do you care? If so, do something about this. + } + } + } + + pMDImport->CloseEnum(hEnum); + hEnum = NULL; + + PrintHeader(wszTdName, td, "PROPERTIES"); + fMore = TRUE; + while (fMore) + { + hr = pMDImport->EnumProperties(&hEnum, + td, + aProperties, + dimensionof(aProperties), + &cProperties); + if (FAILED(hr)) + { + goto Error; + } + + if (hr == S_FALSE) + { + fMore = FALSE; + } + + for (i=0; i < cProperties; i++) + { + hr = PrintProperty(moduleID, pMDImport, wszTdName, aProperties[i]); + if (FAILED(hr)) + { + // do you care? If so, do something about this. + } + } + } + + pMDImport->CloseEnum(hEnum); + hEnum = NULL; + + hr = S_OK; + + Cleanup: + if (hEnum != NULL) + { + pMDImport->CloseEnum(hEnum); + } + return hr; + + Error: + goto Cleanup; +} + + + // Enumerates the typedefs in a module via the metadata interface, and calls PrintTypedef + // on each one +HRESULT PrintMetadata(ModuleID moduleID, IMetaDataImport* pMDImport) +{ + HRESULT hr; + HCORENUM hEnum = NULL; + mdTypeDef aTypeDefs[100]; + ULONG cTypeDefs; + ULONG i; + BOOL fMoreTypeDefs = TRUE; + + while (fMoreTypeDefs) + { + hr = pMDImport->EnumTypeDefs(&hEnum, + aTypeDefs, + dimensionof(aTypeDefs), + &cTypeDefs); + if (FAILED(hr)) + { + goto Error; + } + + if (hr == S_FALSE) + { + fMoreTypeDefs = FALSE; + } + + for (i=0; i < cTypeDefs; i++) + { + hr = PrintTypedef(moduleID, pMDImport, aTypeDefs[i]); + if (FAILED(hr)) + { + // do you care? If so, do something about this. + } + } + } + + hr = S_OK; + + Cleanup: + if (hEnum != NULL) + { + pMDImport->CloseEnum(hEnum); + } + return hr; + + Error: + goto Cleanup; +} + + + // **************************************************************** + // Add this to your profiler's ICorProfilerCallback2::ModuleLoadFinished implementation. + // It is assumed your copy of the ICorProfilerInfo2 interface may be accessed via + // g_pProfilerInfo. Change the code to fit your profiler as appropriate. + // **************************************************************** + // + // As a module gets loaded, this callback implementation initiates the pretty-printer to + // log all the types to stdout. +HRESULT CYourProfImpl::ModuleLoadFinished( ModuleID moduleID, HRESULT hrStatus ) +{ + HRESULT hr; + LPCBYTE pbBaseLoadAddr; + WCHAR wszName[300]; + ULONG cchNameIn = dimensionof(wszName); + ULONG cchNameOut; + AssemblyID assemblyID; + + hr = g_pProfilerInfo->GetModuleInfo(moduleID, + &pbBaseLoadAddr, + cchNameIn, + &cchNameOut, + wszName, + &assemblyID); + if (FAILED(hr)) + { + return hr; + } + + printf("MODULE LOAD FINISHED: %S\n", wszName); + + IMetaDataImport *pMDImport = NULL; + hr = g_pProfilerInfo->GetModuleMetaData(moduleID, + ofRead, + IID_IMetaDataImport, + (IUnknown **)&pMDImport ); + if (FAILED(hr)) + { + return hr; + } + + hr = PrintMetadata(moduleID, pMDImport); + if (FAILED(hr)) + { + // Do any error handling as appropriate + } + + hr = S_OK; + + Cleanup: + return hr; + + Error: + goto Cleanup; +} diff --git a/Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp b/Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp index 0a273a044c..e62bb0021f 100644 --- a/Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp +++ b/Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp @@ -1 +1,1051 @@ -// This blog post originally appeared on David Broman's blog on 10/13/2005
// Sig ::= MethodDefSig | MethodRefSig | StandAloneMethodSig | FieldSig | PropertySig | LocalVarSig
// MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount) ParamCount RetType Param*
// MethodRefSig ::= [[HASTHIS] [EXPLICITTHIS]] VARARG ParamCount RetType Param* [SENTINEL Param+]
// StandAloneMethodSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|C|STDCALL|THISCALL|FASTCALL)
// ParamCount RetType Param* [SENTINEL Param+]
// FieldSig ::= FIELD CustomMod* Type
// PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*
// LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+
// -------------
// CustomMod ::= ( CMOD_OPT | CMOD_REQD ) ( TypeDefEncoded | TypeRefEncoded )
// Constraint ::= #define ELEMENT_TYPE_PINNED
// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )
// RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )
// Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |
// | VALUETYPE TypeDefOrRefEncoded
// | CLASS TypeDefOrRefEncoded
// | STRING
// | OBJECT
// | PTR CustomMod* VOID
// | PTR CustomMod* Type
// | FNPTR MethodDefSig
// | FNPTR MethodRefSig
// | ARRAY Type ArrayShape
// | SZARRAY CustomMod* Type
// | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type*
// | VAR Number
// | MVAR Number
// ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*
// TypeDefOrRefEncoded ::= TypeDefEncoded | TypeRefEncoded
// TypeDefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs
// TypeRefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs
// ParamCount ::= 29-bit-encoded-integer
// GenArgCount ::= 29-bit-encoded-integer
// Count ::= 29-bit-encoded-integer
// Rank ::= 29-bit-encoded-integer
// NumSizes ::= 29-bit-encoded-integer
// Size ::= 29-bit-encoded-integer
// NumLoBounds ::= 29-bit-encoded-integer
// LoBounds ::= 29-bit-encoded-integer
// Number ::= 29-bit-encoded-integer
#define ELEMENT_TYPE_END 0x00 //Marks end of a list
#define ELEMENT_TYPE_VOID 0x01
#define ELEMENT_TYPE_BOOLEAN 0x02
#define ELEMENT_TYPE_CHAR 0x03
#define ELEMENT_TYPE_I1 0x04
#define ELEMENT_TYPE_U1 0x05
#define ELEMENT_TYPE_I2 0x06
#define ELEMENT_TYPE_U2 0x07
#define ELEMENT_TYPE_I4 0x08
#define ELEMENT_TYPE_U4 0x09
#define ELEMENT_TYPE_I8 0x0a
#define ELEMENT_TYPE_U8 0x0b
#define ELEMENT_TYPE_R4 0x0c
#define ELEMENT_TYPE_R8 0x0d
#define ELEMENT_TYPE_STRING 0x0e
#define ELEMENT_TYPE_PTR 0x0f // Followed by type
#define ELEMENT_TYPE_BYREF 0x10 // Followed by type
#define ELEMENT_TYPE_VALUETYPE 0x11 // Followed by TypeDef or TypeRef token
#define ELEMENT_TYPE_CLASS 0x12 // Followed by TypeDef or TypeRef token
#define ELEMENT_TYPE_VAR 0x13 // Generic parameter in a generic type definition, represented as number
#define ELEMENT_TYPE_ARRAY 0x14 // type rank boundsCount bound1 … loCount lo1 …
#define ELEMENT_TYPE_GENERICINST 0x15 // Generic type instantiation. Followed by type type-arg-count type-1 ... type-n
#define ELEMENT_TYPE_TYPEDBYREF 0x16
#define ELEMENT_TYPE_I 0x18 // System.IntPtr
#define ELEMENT_TYPE_U 0x19 // System.UIntPtr
#define ELEMENT_TYPE_FNPTR 0x1b // Followed by full method signature
#define ELEMENT_TYPE_OBJECT 0x1c // System.Object
#define ELEMENT_TYPE_SZARRAY 0x1d // Single-dim array with 0 lower bound
#define ELEMENT_TYPE_MVAR 0x1e // Generic parameter in a generic method definition,represented as number
#define ELEMENT_TYPE_CMOD_REQD 0x1f // Required modifier : followed by a TypeDef or TypeRef token
#define ELEMENT_TYPE_CMOD_OPT 0x20 // Optional modifier : followed by a TypeDef or TypeRef token
#define ELEMENT_TYPE_INTERNAL 0x21 // Implemented within the CLI
#define ELEMENT_TYPE_MODIFIER 0x40 // Or’d with following element types
#define ELEMENT_TYPE_SENTINEL 0x41 // Sentinel for vararg method signature
#define ELEMENT_TYPE_PINNED 0x45 // Denotes a local variable that points at a pinned object
#define SIG_METHOD_DEFAULT 0x0 // default calling convention
#define SIG_METHOD_C 0x1 // C calling convention
#define SIG_METHOD_STDCALL 0x2 // Stdcall calling convention
#define SIG_METHOD_THISCALL 0x3 // thiscall calling convention
#define SIG_METHOD_FASTCALL 0x4 // fastcall calling convention
#define SIG_METHOD_VARARG 0x5 // vararg calling convention
#define SIG_FIELD 0x6 // encodes a field
#define SIG_LOCAL_SIG 0x7 // used for the .locals directive
#define SIG_PROPERTY 0x8 // used to encode a property
#define SIG_GENERIC 0x10 // used to indicate that the method has one or more generic parameters.
#define SIG_HASTHIS 0x20 // used to encode the keyword instance in the calling convention
#define SIG_EXPLICITTHIS 0x40 // used to encode the keyword explicit in the calling convention
#define SIG_INDEX_TYPE_TYPEDEF 0 // ParseTypeDefOrRefEncoded returns this as the out index type for typedefs
#define SIG_INDEX_TYPE_TYPEREF 1 // ParseTypeDefOrRefEncoded returns this as the out index type for typerefs
#define SIG_INDEX_TYPE_TYPESPEC 2 // ParseTypeDefOrRefEncoded returns this as the out index type for typespecs
typedef unsigned char sig_byte;
typedef unsigned char sig_elem_type;
typedef unsigned char sig_index_type;
typedef unsigned int sig_index;
typedef unsigned int sig_count;
typedef unsigned int sig_mem_number;
class SigParser
{
private:
sig_byte *pbBase;
sig_byte *pbCur;
sig_byte *pbEnd;
public:
bool Parse(sig_byte *blob, sig_count len);
private:
bool ParseByte(sig_byte *pbOut);
bool ParseNumber(sig_count *pOut);
bool ParseTypeDefOrRefEncoded(sig_index_type *pOutIndexType, sig_index *pOutIndex);
bool ParseMethod(sig_elem_type);
bool ParseField(sig_elem_type);
bool ParseProperty(sig_elem_type);
bool ParseLocals(sig_elem_type);
bool ParseLocal();
bool ParseOptionalCustomMods();
bool ParseOptionalCustomModsOrConstraint();
bool ParseCustomMod();
bool ParseRetType();
bool ParseType();
bool ParseParam();
bool ParseArrayShape();
protected:
// subtype these methods to create your parser side-effects
//----------------------------------------------------
// a method with given elem_type
virtual void NotifyBeginMethod(sig_elem_type elem_type) {}
virtual void NotifyEndMethod() {}
// total parameters for the method
virtual void NotifyParamCount(sig_count) {}
// starting a return type
virtual void NotifyBeginRetType() {}
virtual void NotifyEndRetType() {}
// starting a parameter
virtual void NotifyBeginParam() {}
virtual void NotifyEndParam() {}
// sentinel indication the location of the "..." in the method signature
virtual void NotifySentinal() {}
// number of generic parameters in this method signature (if any)
virtual void NotifyGenericParamCount(sig_count) {}
//----------------------------------------------------
// a field with given elem_type
virtual void NotifyBeginField(sig_elem_type elem_type) {}
virtual void NotifyEndField() {}
//----------------------------------------------------
// a block of locals with given elem_type (always just LOCAL_SIG for now)
virtual void NotifyBeginLocals(sig_elem_type elem_type) {}
virtual void NotifyEndLocals() {}
// count of locals with a block
virtual void NotifyLocalsCount(sig_count) {}
// starting a new local within a local block
virtual void NotifyBeginLocal() {}
virtual void NotifyEndLocal() {}
// the only constraint available to locals at the moment is ELEMENT_TYPE_PINNED
virtual void NotifyConstraint(sig_elem_type elem_type) {}
//----------------------------------------------------
// a property with given element type
virtual void NotifyBeginProperty(sig_elem_type elem_type) {}
virtual void NotifyEndProperty() {}
//----------------------------------------------------
// starting array shape information for array types
virtual void NotifyBeginArrayShape() {}
virtual void NotifyEndArrayShape() {}
// array rank (total number of dimensions)
virtual void NotifyRank(sig_count) {}
// number of dimensions with specified sizes followed by the size of each
virtual void NotifyNumSizes(sig_count) {}
virtual void NotifySize(sig_count) {}
// BUG BUG lower bounds can be negative, how can this be encoded?
// number of dimensions with specified lower bounds followed by lower bound of each
virtual void NotifyNumLoBounds(sig_count) {}
virtual void NotifyLoBound(sig_count) {}
//----------------------------------------------------
// starting a normal type (occurs in many contexts such as param, field, local, etc)
virtual void NotifyBeginType() {};
virtual void NotifyEndType() {};
virtual void NotifyTypedByref() {}
// the type has the 'byref' modifier on it -- this normally proceeds the type definition in the context
// the type is used, so for instance a parameter might have the byref modifier on it
// so this happens before the BeginType in that context
virtual void NotifyByref() {}
// the type is "VOID" (this has limited uses, function returns and void pointer)
virtual void NotifyVoid() {}
// the type has the indicated custom modifiers (which can be optional or required)
virtual void NotifyCustomMod(sig_elem_type cmod, sig_index_type indexType, sig_index index) {}
// the type is a simple type, the elem_type defines it fully
virtual void NotifyTypeSimple(sig_elem_type elem_type) {}
// the type is specified by the given index of the given index type (normally a type index in the type metadata)
// this callback is normally qualified by other ones such as NotifyTypeClass or NotifyTypeValueType
virtual void NotifyTypeDefOrRef(sig_index_type indexType, int index) {}
// the type is an instance of a generic
// elem_type indicates value_type or class
// indexType and index indicate the metadata for the type in question
// number indicates the number of type specifications for the generic types that will follow
virtual void NotifyTypeGenericInst(sig_elem_type elem_type, sig_index_type indexType, sig_index index, sig_mem_number number) {}
// the type is the type of the nth generic type parameter for the class
virtual void NotifyTypeGenericTypeVariable(sig_mem_number number) {}
// the type is the type of the nth generic type parameter for the member
virtual void NotifyTypeGenericMemberVariable(sig_mem_number number) {}
// the type will be a value type
virtual void NotifyTypeValueType() {}
// the type will be a class
virtual void NotifyTypeClass() {}
// the type is a pointer to a type (nested type notifications follow)
virtual void NotifyTypePointer() {}
// the type is a function pointer, followed by the type of the function
virtual void NotifyTypeFunctionPointer() {}
// the type is an array, this is followed by the array shape, see above, as well as modifiers and element type
virtual void NotifyTypeArray() {}
// the type is a simple zero-based array, this has no shape but does have custom modifiers and element type
virtual void NotifyTypeSzArray() {}
};
//----------------------------------------------------
bool SigParser::Parse(sig_byte *pb, sig_count cbBuffer)
{
pbBase = pb;
pbCur = pb;
pbEnd = pbBase + cbBuffer;
sig_elem_type elem_type;
if (!ParseByte(&elem_type))
return false;
switch (elem_type & 0xf)
{
case SIG_METHOD_DEFAULT: // default calling convention
case SIG_METHOD_C: // C calling convention
case SIG_METHOD_STDCALL: // Stdcall calling convention
case SIG_METHOD_THISCALL: // thiscall calling convention
case SIG_METHOD_FASTCALL: // fastcall calling convention
case SIG_METHOD_VARARG: // vararg calling convention
return ParseMethod(elem_type);
break;
case SIG_FIELD: // encodes a field
return ParseField(elem_type);
break;
case SIG_LOCAL_SIG: // used for the .locals directive
return ParseLocals(elem_type);
break;
case SIG_PROPERTY: // used to encode a property
return ParseProperty(elem_type);
break;
default:
// unknown signature
break;
}
return false;
}
bool SigParser::ParseByte(sig_byte *pbOut)
{
if (pbCur < pbEnd)
{
*pbOut = *pbCur;
pbCur++;
return true;
}
return false;
}
bool SigParser::ParseMethod(sig_elem_type elem_type)
{
// MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount)
// ParamCount RetType Param* [SENTINEL Param+]
NotifyBeginMethod(elem_type);
sig_count gen_param_count;
sig_count param_count;
if (elem_type & SIG_GENERIC)
{
if (!ParseNumber(&gen_param_count))
{
return false;
}
NotifyGenericParamCount(gen_param_count);
}
if (!ParseNumber(¶m_count))
{
return false;
}
NotifyParamCount(param_count);
if (!ParseRetType())
{
return false;
}
bool fEncounteredSentinal = false;
for (sig_count i = 0; i < param_count; i++)
{
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_SENTINEL)
{
if (fEncounteredSentinal)
{
return false;
}
fEncounteredSentinal = true;
NotifySentinal();
pbCur++;
}
if (!ParseParam())
{
return false;
}
}
NotifyEndMethod();
return true;
}
bool SigParser::ParseField(sig_elem_type elem_type)
{
// FieldSig ::= FIELD CustomMod* Type
NotifyBeginField(elem_type);
if (!ParseOptionalCustomMods())
{
return false;
}
if (!ParseType())
{
return false;
}
NotifyEndField();
return true;
}
bool SigParser::ParseProperty(sig_elem_type elem_type)
{
// PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*
NotifyBeginProperty(elem_type);
sig_count param_count;
if (!ParseNumber(¶m_count))
{
return false;
}
NotifyParamCount(param_count);
if (!ParseOptionalCustomMods())
{
return false;
}
if (!ParseType())
{
return false;
}
for (sig_count i = 0; i < param_count; i++)
{
if (!ParseParam())
{
return false;
}
}
NotifyEndProperty();
return true;
}
bool SigParser::ParseLocals(sig_elem_type elem_type)
{
// LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+
NotifyBeginLocals(elem_type);
sig_count local_count;
if (!ParseNumber(&local_count))
{
return false;
}
NotifyLocalsCount(local_count);
for (sig_count i = 0; i < local_count; i++)
{
if (!ParseLocal())
{
return false;
}
}
NotifyEndLocals();
return true;
}
bool SigParser::ParseLocal()
{
//TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type
NotifyBeginLocal();
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
{
NotifyTypedByref();
pbCur++;
goto Success;
}
if (!ParseOptionalCustomModsOrConstraint())
{
return false;
}
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_BYREF)
{
NotifyByref();
pbCur++;
}
if (!ParseType())
{
return false;
}
Success:
NotifyEndLocal();
return true;
}
bool SigParser::ParseOptionalCustomModsOrConstraint()
{
for (;;)
{
if (pbCur >= pbEnd)
{
return true;
}
switch (*pbCur)
{
case ELEMENT_TYPE_CMOD_OPT:
case ELEMENT_TYPE_CMOD_REQD:
if (!ParseCustomMod())
{
return false;
}
break;
case ELEMENT_TYPE_PINNED:
NotifyConstraint(*pbCur);
pbCur++;
break;
default:
return true;
}
}
return false;
}
bool SigParser::ParseOptionalCustomMods()
{
for (;;)
{
if (pbCur >= pbEnd)
{
return true;
}
switch (*pbCur)
{
case ELEMENT_TYPE_CMOD_OPT:
case ELEMENT_TYPE_CMOD_REQD:
if (!ParseCustomMod())
{
return false;
}
break;
default:
return true;
}
}
return false;
}
bool SigParser::ParseCustomMod()
{
sig_elem_type cmod = 0;
sig_index index;
sig_index_type indexType;
if (!ParseByte(&cmod))
{
return false;
}
if (cmod == ELEMENT_TYPE_CMOD_OPT || cmod == ELEMENT_TYPE_CMOD_REQD)
{
if (!ParseTypeDefOrRefEncoded(&indexType, &index))
{
return false;
}
NotifyCustomMod(cmod, indexType, index);
return true;
}
return false;
}
bool SigParser::ParseParam()
{
// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )
NotifyBeginParam();
if (!ParseOptionalCustomMods())
{
return false;
}
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
{
NotifyTypedByref();
pbCur++;
goto Success;
}
if (*pbCur == ELEMENT_TYPE_BYREF)
{
NotifyByref();
pbCur++;
}
if (!ParseType())
{
return false;
}
Success:
NotifyEndParam();
return true;
}
bool SigParser::ParseRetType()
{
// RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )
NotifyBeginRetType();
if (!ParseOptionalCustomMods())
{
return false;
}
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
{
NotifyTypedByref();
pbCur++;
goto Success;
}
if (*pbCur == ELEMENT_TYPE_VOID)
{
NotifyVoid();
pbCur++;
goto Success;
}
if (*pbCur == ELEMENT_TYPE_BYREF)
{
NotifyByref();
pbCur++;
}
if (!ParseType())
{
return false;
}
Success:
NotifyEndRetType();
return true;
}
bool SigParser::ParseArrayShape()
{
sig_count rank;
sig_count numsizes;
sig_count size;
// ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*
NotifyBeginArrayShape();
if (!ParseNumber(&rank))
{
return false;
}
NotifyRank(rank);
if (!ParseNumber(&numsizes))
{
return false;
}
NotifyNumSizes(numsizes);
for (sig_count i = 0; i < numsizes; i++)
{
if (!ParseNumber(&size))
{
return false;
}
NotifySize(size);
}
if (!ParseNumber(&numsizes))
{
return false;
}
NotifyNumLoBounds(numsizes);
for (sig_count i = 0; i < numsizes; i++)
{
if (!ParseNumber(&size))
{
return false;
}
NotifyLoBound(size);
}
NotifyEndArrayShape();
return true;
}
bool SigParser::ParseType()
{
// Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |
// | VALUETYPE TypeDefOrRefEncoded
// | CLASS TypeDefOrRefEncoded
// | STRING
// | OBJECT
// | PTR CustomMod* VOID
// | PTR CustomMod* Type
// | FNPTR MethodDefSig
// | FNPTR MethodRefSig
// | ARRAY Type ArrayShape
// | SZARRAY CustomMod* Type
// | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *
// | VAR Number
// | MVAR Number
NotifyBeginType();
sig_elem_type elem_type;
sig_index index;
sig_mem_number number;
sig_index_type indexType;
if (!ParseByte(&elem_type))
return false;
switch (elem_type)
{
case ELEMENT_TYPE_BOOLEAN:
case ELEMENT_TYPE_CHAR:
case ELEMENT_TYPE_I1:
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_I2:
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
case ELEMENT_TYPE_R4:
case ELEMENT_TYPE_R8:
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
case ELEMENT_TYPE_STRING:
case ELEMENT_TYPE_OBJECT:
// simple types
NotifyTypeSimple(elem_type);
break;
case ELEMENT_TYPE_PTR:
// PTR CustomMod* VOID
// PTR CustomMod* Type
NotifyTypePointer();
if (!ParseOptionalCustomMods())
{
return false;
}
if (pbCur >= pbEnd)
{
return false;
}
if (*pbCur == ELEMENT_TYPE_VOID)
{
pbCur++;
NotifyVoid();
break;
}
if (!ParseType())
{
return false;
}
break;
case ELEMENT_TYPE_CLASS:
// CLASS TypeDefOrRefEncoded
NotifyTypeClass();
if (!ParseTypeDefOrRefEncoded(&indexType, &index))
{
return false;
}
NotifyTypeDefOrRef(indexType, index);
break;
case ELEMENT_TYPE_VALUETYPE:
//VALUETYPE TypeDefOrRefEncoded
NotifyTypeValueType();
if (!ParseTypeDefOrRefEncoded(&indexType, &index))
{
return false;
}
NotifyTypeDefOrRef(indexType, index);
break;
case ELEMENT_TYPE_FNPTR:
// FNPTR MethodDefSig
// FNPTR MethodRefSig
NotifyTypeFunctionPointer();
if (!ParseByte(&elem_type))
{
return false;
}
if (!ParseMethod(elem_type))
{
return false;
}
break;
case ELEMENT_TYPE_ARRAY:
// ARRAY Type ArrayShape
NotifyTypeArray();
if (!ParseType())
{
return false;
}
if (!ParseArrayShape())
{
return false;
}
break;
case ELEMENT_TYPE_SZARRAY:
// SZARRAY CustomMod* Type
NotifyTypeSzArray();
if (!ParseOptionalCustomMods())
{
return false;
}
if (!ParseType())
{
return false;
}
break;
case ELEMENT_TYPE_GENERICINST:
// GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *
if (!ParseByte(&elem_type))
{
return false;
}
if (elem_type != ELEMENT_TYPE_CLASS && elem_type != ELEMENT_TYPE_VALUETYPE)
{
return false;
}
if (!ParseTypeDefOrRefEncoded(&indexType, &index))
{
return false;
}
if (!ParseNumber(&number))
{
return false;
}
NotifyTypeGenericInst(elem_type, indexType, index, number);
{
for (sig_mem_number i=0; i < number; i++)
{
if (!ParseType())
{
return false;
}
}
}
break;
case ELEMENT_TYPE_VAR:
// VAR Number
if (!ParseNumber(&number))
{
return false;
}
NotifyTypeGenericTypeVariable(number);
break;
case ELEMENT_TYPE_MVAR:
// MVAR Number
if (!ParseNumber(&number))
{
return false;
}
NotifyTypeGenericMemberVariable(number);
break;
}
NotifyEndType();
return true;
}
bool SigParser::ParseTypeDefOrRefEncoded(sig_index_type *pIndexTypeOut, sig_index *pIndexOut)
{
// parse an encoded typedef or typeref
sig_count encoded = 0;
if (!ParseNumber(&encoded))
{
return false;
}
*pIndexTypeOut = (sig_index_type) (encoded & 0x3);
*pIndexOut = (encoded >> 2);
return true;
}
bool SigParser::ParseNumber(sig_count *pOut)
{
// parse the variable length number format (0-4 bytes)
sig_byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
// at least one byte in the encoding, read that
if (!ParseByte(&b1))
{
return false;
}
if (b1 == 0xff)
{
// special encoding of 'NULL'
// not sure what this means as a number, don't expect to see it except for string lengths
// which we don't encounter anyway so calling it an error
return false;
}
// early out on 1 byte encoding
if ( (b1 & 0x80) == 0)
{
*pOut = (int)b1;
return true;
}
// now at least 2 bytes in the encoding, read 2nd byte
if (!ParseByte(&b2))
{
return false;
}
// early out on 2 byte encoding
if ( (b1 & 0x40) == 0)
{
*pOut = (((b1 & 0x3f) << 8) | b2);
return true;
}
// must be a 4 byte encoding
if ( (b1 & 0x20) != 0)
{
// 4 byte encoding has this bit clear -- error if not
return false;
}
if (!ParseByte(&b3))
{
return false;
}
if (!ParseByte(&b4))
{
return false;
}
*pOut = ((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4;
return true;
}
\ No newline at end of file +// This blog post originally appeared on David Broman's blog on 10/13/2005 + +// Sig ::= MethodDefSig | MethodRefSig | StandAloneMethodSig | FieldSig | PropertySig | LocalVarSig +// MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount) ParamCount RetType Param* +// MethodRefSig ::= [[HASTHIS] [EXPLICITTHIS]] VARARG ParamCount RetType Param* [SENTINEL Param+] +// StandAloneMethodSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|C|STDCALL|THISCALL|FASTCALL) +// ParamCount RetType Param* [SENTINEL Param+] +// FieldSig ::= FIELD CustomMod* Type +// PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param* +// LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ + +// ------------- + +// CustomMod ::= ( CMOD_OPT | CMOD_REQD ) ( TypeDefEncoded | TypeRefEncoded ) +// Constraint ::= #define ELEMENT_TYPE_PINNED +// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type ) +// RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type ) +// Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U | +// | VALUETYPE TypeDefOrRefEncoded +// | CLASS TypeDefOrRefEncoded +// | STRING +// | OBJECT +// | PTR CustomMod* VOID +// | PTR CustomMod* Type +// | FNPTR MethodDefSig +// | FNPTR MethodRefSig +// | ARRAY Type ArrayShape +// | SZARRAY CustomMod* Type +// | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type* +// | VAR Number +// | MVAR Number + +// ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound* + +// TypeDefOrRefEncoded ::= TypeDefEncoded | TypeRefEncoded +// TypeDefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs +// TypeRefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs + +// ParamCount ::= 29-bit-encoded-integer +// GenArgCount ::= 29-bit-encoded-integer +// Count ::= 29-bit-encoded-integer +// Rank ::= 29-bit-encoded-integer +// NumSizes ::= 29-bit-encoded-integer +// Size ::= 29-bit-encoded-integer +// NumLoBounds ::= 29-bit-encoded-integer +// LoBounds ::= 29-bit-encoded-integer +// Number ::= 29-bit-encoded-integer + + + #define ELEMENT_TYPE_END 0x00 //Marks end of a list + #define ELEMENT_TYPE_VOID 0x01 + #define ELEMENT_TYPE_BOOLEAN 0x02 + #define ELEMENT_TYPE_CHAR 0x03 + #define ELEMENT_TYPE_I1 0x04 + #define ELEMENT_TYPE_U1 0x05 + #define ELEMENT_TYPE_I2 0x06 + #define ELEMENT_TYPE_U2 0x07 + #define ELEMENT_TYPE_I4 0x08 + #define ELEMENT_TYPE_U4 0x09 + #define ELEMENT_TYPE_I8 0x0a + #define ELEMENT_TYPE_U8 0x0b + #define ELEMENT_TYPE_R4 0x0c + #define ELEMENT_TYPE_R8 0x0d + #define ELEMENT_TYPE_STRING 0x0e + #define ELEMENT_TYPE_PTR 0x0f // Followed by type + #define ELEMENT_TYPE_BYREF 0x10 // Followed by type + #define ELEMENT_TYPE_VALUETYPE 0x11 // Followed by TypeDef or TypeRef token + #define ELEMENT_TYPE_CLASS 0x12 // Followed by TypeDef or TypeRef token + #define ELEMENT_TYPE_VAR 0x13 // Generic parameter in a generic type definition, represented as number + #define ELEMENT_TYPE_ARRAY 0x14 // type rank boundsCount bound1 … loCount lo1 … + #define ELEMENT_TYPE_GENERICINST 0x15 // Generic type instantiation. Followed by type type-arg-count type-1 ... type-n + #define ELEMENT_TYPE_TYPEDBYREF 0x16 + #define ELEMENT_TYPE_I 0x18 // System.IntPtr + #define ELEMENT_TYPE_U 0x19 // System.UIntPtr + #define ELEMENT_TYPE_FNPTR 0x1b // Followed by full method signature + #define ELEMENT_TYPE_OBJECT 0x1c // System.Object + #define ELEMENT_TYPE_SZARRAY 0x1d // Single-dim array with 0 lower bound + + #define ELEMENT_TYPE_MVAR 0x1e // Generic parameter in a generic method definition,represented as number + #define ELEMENT_TYPE_CMOD_REQD 0x1f // Required modifier : followed by a TypeDef or TypeRef token + #define ELEMENT_TYPE_CMOD_OPT 0x20 // Optional modifier : followed by a TypeDef or TypeRef token + #define ELEMENT_TYPE_INTERNAL 0x21 // Implemented within the CLI + #define ELEMENT_TYPE_MODIFIER 0x40 // Or’d with following element types + #define ELEMENT_TYPE_SENTINEL 0x41 // Sentinel for vararg method signature + #define ELEMENT_TYPE_PINNED 0x45 // Denotes a local variable that points at a pinned object + + #define SIG_METHOD_DEFAULT 0x0 // default calling convention + #define SIG_METHOD_C 0x1 // C calling convention + #define SIG_METHOD_STDCALL 0x2 // Stdcall calling convention + #define SIG_METHOD_THISCALL 0x3 // thiscall calling convention + #define SIG_METHOD_FASTCALL 0x4 // fastcall calling convention + #define SIG_METHOD_VARARG 0x5 // vararg calling convention + #define SIG_FIELD 0x6 // encodes a field + #define SIG_LOCAL_SIG 0x7 // used for the .locals directive + #define SIG_PROPERTY 0x8 // used to encode a property + + + #define SIG_GENERIC 0x10 // used to indicate that the method has one or more generic parameters. + #define SIG_HASTHIS 0x20 // used to encode the keyword instance in the calling convention + #define SIG_EXPLICITTHIS 0x40 // used to encode the keyword explicit in the calling convention + + #define SIG_INDEX_TYPE_TYPEDEF 0 // ParseTypeDefOrRefEncoded returns this as the out index type for typedefs + #define SIG_INDEX_TYPE_TYPEREF 1 // ParseTypeDefOrRefEncoded returns this as the out index type for typerefs + #define SIG_INDEX_TYPE_TYPESPEC 2 // ParseTypeDefOrRefEncoded returns this as the out index type for typespecs + + +typedef unsigned char sig_byte; +typedef unsigned char sig_elem_type; +typedef unsigned char sig_index_type; +typedef unsigned int sig_index; +typedef unsigned int sig_count; +typedef unsigned int sig_mem_number; + +class SigParser +{ +private: + sig_byte *pbBase; + sig_byte *pbCur; + sig_byte *pbEnd; + +public: + bool Parse(sig_byte *blob, sig_count len); + +private: + bool ParseByte(sig_byte *pbOut); + bool ParseNumber(sig_count *pOut); + bool ParseTypeDefOrRefEncoded(sig_index_type *pOutIndexType, sig_index *pOutIndex); + + bool ParseMethod(sig_elem_type); + bool ParseField(sig_elem_type); + bool ParseProperty(sig_elem_type); + bool ParseLocals(sig_elem_type); + bool ParseLocal(); + bool ParseOptionalCustomMods(); + bool ParseOptionalCustomModsOrConstraint(); + bool ParseCustomMod(); + bool ParseRetType(); + bool ParseType(); + bool ParseParam(); + bool ParseArrayShape(); + +protected: + + // subtype these methods to create your parser side-effects + + //---------------------------------------------------- + + // a method with given elem_type + virtual void NotifyBeginMethod(sig_elem_type elem_type) {} + virtual void NotifyEndMethod() {} + + // total parameters for the method + virtual void NotifyParamCount(sig_count) {} + + // starting a return type + virtual void NotifyBeginRetType() {} + virtual void NotifyEndRetType() {} + + // starting a parameter + virtual void NotifyBeginParam() {} + virtual void NotifyEndParam() {} + + // sentinel indication the location of the "..." in the method signature + virtual void NotifySentinal() {} + + // number of generic parameters in this method signature (if any) + virtual void NotifyGenericParamCount(sig_count) {} + + //---------------------------------------------------- + + // a field with given elem_type + virtual void NotifyBeginField(sig_elem_type elem_type) {} + virtual void NotifyEndField() {} + + //---------------------------------------------------- + + // a block of locals with given elem_type (always just LOCAL_SIG for now) + virtual void NotifyBeginLocals(sig_elem_type elem_type) {} + virtual void NotifyEndLocals() {} + + // count of locals with a block + virtual void NotifyLocalsCount(sig_count) {} + + // starting a new local within a local block + virtual void NotifyBeginLocal() {} + virtual void NotifyEndLocal() {} + + // the only constraint available to locals at the moment is ELEMENT_TYPE_PINNED + virtual void NotifyConstraint(sig_elem_type elem_type) {} + + + //---------------------------------------------------- + + // a property with given element type + virtual void NotifyBeginProperty(sig_elem_type elem_type) {} + virtual void NotifyEndProperty() {} + + //---------------------------------------------------- + + // starting array shape information for array types + virtual void NotifyBeginArrayShape() {} + virtual void NotifyEndArrayShape() {} + + // array rank (total number of dimensions) + virtual void NotifyRank(sig_count) {} + + // number of dimensions with specified sizes followed by the size of each + virtual void NotifyNumSizes(sig_count) {} + virtual void NotifySize(sig_count) {} + + // BUG BUG lower bounds can be negative, how can this be encoded? + // number of dimensions with specified lower bounds followed by lower bound of each + virtual void NotifyNumLoBounds(sig_count) {} + virtual void NotifyLoBound(sig_count) {} + + //---------------------------------------------------- + + + // starting a normal type (occurs in many contexts such as param, field, local, etc) + virtual void NotifyBeginType() {}; + virtual void NotifyEndType() {}; + + virtual void NotifyTypedByref() {} + + // the type has the 'byref' modifier on it -- this normally proceeds the type definition in the context + // the type is used, so for instance a parameter might have the byref modifier on it + // so this happens before the BeginType in that context + virtual void NotifyByref() {} + + // the type is "VOID" (this has limited uses, function returns and void pointer) + virtual void NotifyVoid() {} + + // the type has the indicated custom modifiers (which can be optional or required) + virtual void NotifyCustomMod(sig_elem_type cmod, sig_index_type indexType, sig_index index) {} + + // the type is a simple type, the elem_type defines it fully + virtual void NotifyTypeSimple(sig_elem_type elem_type) {} + + // the type is specified by the given index of the given index type (normally a type index in the type metadata) + // this callback is normally qualified by other ones such as NotifyTypeClass or NotifyTypeValueType + virtual void NotifyTypeDefOrRef(sig_index_type indexType, int index) {} + + // the type is an instance of a generic + // elem_type indicates value_type or class + // indexType and index indicate the metadata for the type in question + // number indicates the number of type specifications for the generic types that will follow + virtual void NotifyTypeGenericInst(sig_elem_type elem_type, sig_index_type indexType, sig_index index, sig_mem_number number) {} + + // the type is the type of the nth generic type parameter for the class + virtual void NotifyTypeGenericTypeVariable(sig_mem_number number) {} + + // the type is the type of the nth generic type parameter for the member + virtual void NotifyTypeGenericMemberVariable(sig_mem_number number) {} + + // the type will be a value type + virtual void NotifyTypeValueType() {} + + // the type will be a class + virtual void NotifyTypeClass() {} + + // the type is a pointer to a type (nested type notifications follow) + virtual void NotifyTypePointer() {} + + // the type is a function pointer, followed by the type of the function + virtual void NotifyTypeFunctionPointer() {} + + // the type is an array, this is followed by the array shape, see above, as well as modifiers and element type + virtual void NotifyTypeArray() {} + + // the type is a simple zero-based array, this has no shape but does have custom modifiers and element type + virtual void NotifyTypeSzArray() {} +}; + + //---------------------------------------------------- + + +bool SigParser::Parse(sig_byte *pb, sig_count cbBuffer) +{ + pbBase = pb; + pbCur = pb; + pbEnd = pbBase + cbBuffer; + + sig_elem_type elem_type; + + if (!ParseByte(&elem_type)) + return false; + + switch (elem_type & 0xf) + { + case SIG_METHOD_DEFAULT: // default calling convention + case SIG_METHOD_C: // C calling convention + case SIG_METHOD_STDCALL: // Stdcall calling convention + case SIG_METHOD_THISCALL: // thiscall calling convention + case SIG_METHOD_FASTCALL: // fastcall calling convention + case SIG_METHOD_VARARG: // vararg calling convention + return ParseMethod(elem_type); + break; + + case SIG_FIELD: // encodes a field + return ParseField(elem_type); + break; + + case SIG_LOCAL_SIG: // used for the .locals directive + return ParseLocals(elem_type); + break; + + case SIG_PROPERTY: // used to encode a property + return ParseProperty(elem_type); + break; + + default: + // unknown signature + break; + } + + return false; +} + + +bool SigParser::ParseByte(sig_byte *pbOut) +{ + if (pbCur < pbEnd) + { + *pbOut = *pbCur; + pbCur++; + return true; + } + + return false; +} + + +bool SigParser::ParseMethod(sig_elem_type elem_type) +{ + // MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount) + // ParamCount RetType Param* [SENTINEL Param+] + + NotifyBeginMethod(elem_type); + + sig_count gen_param_count; + sig_count param_count; + + if (elem_type & SIG_GENERIC) + { + if (!ParseNumber(&gen_param_count)) + { + return false; + } + + NotifyGenericParamCount(gen_param_count); + } + + if (!ParseNumber(¶m_count)) + { + return false; + } + + NotifyParamCount(param_count); + + if (!ParseRetType()) + { + return false; + } + + bool fEncounteredSentinal = false; + + for (sig_count i = 0; i < param_count; i++) + { + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_SENTINEL) + { + if (fEncounteredSentinal) + { + return false; + } + + fEncounteredSentinal = true; + NotifySentinal(); + pbCur++; + } + + if (!ParseParam()) + { + return false; + } + } + + NotifyEndMethod(); + + return true; +} + + +bool SigParser::ParseField(sig_elem_type elem_type) +{ + // FieldSig ::= FIELD CustomMod* Type + + NotifyBeginField(elem_type); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (!ParseType()) + { + return false; + } + + NotifyEndField(); + + return true; +} + + +bool SigParser::ParseProperty(sig_elem_type elem_type) +{ + // PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param* + + NotifyBeginProperty(elem_type); + + sig_count param_count; + + if (!ParseNumber(¶m_count)) + { + return false; + } + + NotifyParamCount(param_count); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (!ParseType()) + { + return false; + } + + for (sig_count i = 0; i < param_count; i++) + { + if (!ParseParam()) + { + return false; + } + } + + NotifyEndProperty(); + + return true; +} + + +bool SigParser::ParseLocals(sig_elem_type elem_type) +{ + // LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ + + NotifyBeginLocals(elem_type); + + sig_count local_count; + + if (!ParseNumber(&local_count)) + { + return false; + } + + NotifyLocalsCount(local_count); + + for (sig_count i = 0; i < local_count; i++) + { + if (!ParseLocal()) + { + return false; + } + } + + NotifyEndLocals(); + + return true; +} + + +bool SigParser::ParseLocal() +{ + //TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type + NotifyBeginLocal(); + + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_TYPEDBYREF) + { + NotifyTypedByref(); + pbCur++; + goto Success; + } + + if (!ParseOptionalCustomModsOrConstraint()) + { + return false; + } + + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_BYREF) + { + NotifyByref(); + pbCur++; + } + + if (!ParseType()) + { + return false; + } + + Success: + NotifyEndLocal(); + return true; +} + + +bool SigParser::ParseOptionalCustomModsOrConstraint() +{ + for (;;) + { + if (pbCur >= pbEnd) + { + return true; + } + + switch (*pbCur) + { + case ELEMENT_TYPE_CMOD_OPT: + case ELEMENT_TYPE_CMOD_REQD: + if (!ParseCustomMod()) + { + return false; + } + break; + + case ELEMENT_TYPE_PINNED: + NotifyConstraint(*pbCur); + pbCur++; + break; + + default: + return true; + } + } + + return false; +} + + +bool SigParser::ParseOptionalCustomMods() +{ + for (;;) + { + if (pbCur >= pbEnd) + { + return true; + } + + switch (*pbCur) + { + case ELEMENT_TYPE_CMOD_OPT: + case ELEMENT_TYPE_CMOD_REQD: + if (!ParseCustomMod()) + { + return false; + } + break; + + default: + return true; + } + } + + return false; +} + + + +bool SigParser::ParseCustomMod() +{ + sig_elem_type cmod = 0; + sig_index index; + sig_index_type indexType; + + if (!ParseByte(&cmod)) + { + return false; + } + + if (cmod == ELEMENT_TYPE_CMOD_OPT || cmod == ELEMENT_TYPE_CMOD_REQD) + { + if (!ParseTypeDefOrRefEncoded(&indexType, &index)) + { + return false; + } + + NotifyCustomMod(cmod, indexType, index); + return true; + } + + return false; +} + + +bool SigParser::ParseParam() +{ + // Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type ) + + NotifyBeginParam(); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_TYPEDBYREF) + { + NotifyTypedByref(); + pbCur++; + goto Success; + } + + if (*pbCur == ELEMENT_TYPE_BYREF) + { + NotifyByref(); + pbCur++; + } + + if (!ParseType()) + { + return false; + } + + Success: + NotifyEndParam(); + return true; +} + + +bool SigParser::ParseRetType() +{ + // RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type ) + + NotifyBeginRetType(); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_TYPEDBYREF) + { + NotifyTypedByref(); + pbCur++; + goto Success; + } + + if (*pbCur == ELEMENT_TYPE_VOID) + { + NotifyVoid(); + pbCur++; + goto Success; + } + + if (*pbCur == ELEMENT_TYPE_BYREF) + { + NotifyByref(); + pbCur++; + } + + if (!ParseType()) + { + return false; + } + + Success: + NotifyEndRetType(); + return true; +} + +bool SigParser::ParseArrayShape() +{ + sig_count rank; + sig_count numsizes; + sig_count size; + + // ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound* + NotifyBeginArrayShape(); + if (!ParseNumber(&rank)) + { + return false; + } + + NotifyRank(rank); + + if (!ParseNumber(&numsizes)) + { + return false; + } + + NotifyNumSizes(numsizes); + + for (sig_count i = 0; i < numsizes; i++) + { + if (!ParseNumber(&size)) + { + return false; + } + + NotifySize(size); + } + + if (!ParseNumber(&numsizes)) + { + return false; + } + + NotifyNumLoBounds(numsizes); + + for (sig_count i = 0; i < numsizes; i++) + { + if (!ParseNumber(&size)) + { + return false; + } + + NotifyLoBound(size); + } + + NotifyEndArrayShape(); + return true; +} + +bool SigParser::ParseType() +{ + // Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U | + // | VALUETYPE TypeDefOrRefEncoded + // | CLASS TypeDefOrRefEncoded + // | STRING + // | OBJECT + // | PTR CustomMod* VOID + // | PTR CustomMod* Type + // | FNPTR MethodDefSig + // | FNPTR MethodRefSig + // | ARRAY Type ArrayShape + // | SZARRAY CustomMod* Type + // | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type * + // | VAR Number + // | MVAR Number + + NotifyBeginType(); + + sig_elem_type elem_type; + sig_index index; + sig_mem_number number; + sig_index_type indexType; + + if (!ParseByte(&elem_type)) + return false; + + switch (elem_type) + { + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_CHAR: + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + case ELEMENT_TYPE_R4: + case ELEMENT_TYPE_R8: + case ELEMENT_TYPE_I: + case ELEMENT_TYPE_U: + case ELEMENT_TYPE_STRING: + case ELEMENT_TYPE_OBJECT: + // simple types + NotifyTypeSimple(elem_type); + break; + + case ELEMENT_TYPE_PTR: + // PTR CustomMod* VOID + // PTR CustomMod* Type + + NotifyTypePointer(); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (pbCur >= pbEnd) + { + return false; + } + + if (*pbCur == ELEMENT_TYPE_VOID) + { + pbCur++; + NotifyVoid(); + break; + } + + if (!ParseType()) + { + return false; + } + + break; + + case ELEMENT_TYPE_CLASS: + // CLASS TypeDefOrRefEncoded + NotifyTypeClass(); + + if (!ParseTypeDefOrRefEncoded(&indexType, &index)) + { + return false; + } + + NotifyTypeDefOrRef(indexType, index); + break; + + case ELEMENT_TYPE_VALUETYPE: + //VALUETYPE TypeDefOrRefEncoded + NotifyTypeValueType(); + + if (!ParseTypeDefOrRefEncoded(&indexType, &index)) + { + return false; + } + + NotifyTypeDefOrRef(indexType, index); + break; + + case ELEMENT_TYPE_FNPTR: + // FNPTR MethodDefSig + // FNPTR MethodRefSig + NotifyTypeFunctionPointer(); + + if (!ParseByte(&elem_type)) + { + return false; + } + + if (!ParseMethod(elem_type)) + { + return false; + } + + break; + + case ELEMENT_TYPE_ARRAY: + // ARRAY Type ArrayShape + NotifyTypeArray(); + + if (!ParseType()) + { + return false; + } + + if (!ParseArrayShape()) + { + return false; + } + break; + + case ELEMENT_TYPE_SZARRAY: + // SZARRAY CustomMod* Type + + NotifyTypeSzArray(); + + if (!ParseOptionalCustomMods()) + { + return false; + } + + if (!ParseType()) + { + return false; + } + + break; + + case ELEMENT_TYPE_GENERICINST: + // GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type * + + if (!ParseByte(&elem_type)) + { + return false; + } + + if (elem_type != ELEMENT_TYPE_CLASS && elem_type != ELEMENT_TYPE_VALUETYPE) + { + return false; + } + + if (!ParseTypeDefOrRefEncoded(&indexType, &index)) + { + return false; + } + + if (!ParseNumber(&number)) + { + return false; + } + + NotifyTypeGenericInst(elem_type, indexType, index, number); + + { + for (sig_mem_number i=0; i < number; i++) + { + if (!ParseType()) + { + return false; + } + } + } + + break; + + case ELEMENT_TYPE_VAR: + // VAR Number + if (!ParseNumber(&number)) + { + return false; + } + + NotifyTypeGenericTypeVariable(number); + break; + + case ELEMENT_TYPE_MVAR: + // MVAR Number + if (!ParseNumber(&number)) + { + return false; + } + + NotifyTypeGenericMemberVariable(number); + break; + } + + NotifyEndType(); + + return true; +} + +bool SigParser::ParseTypeDefOrRefEncoded(sig_index_type *pIndexTypeOut, sig_index *pIndexOut) +{ + // parse an encoded typedef or typeref + + sig_count encoded = 0; + + if (!ParseNumber(&encoded)) + { + return false; + } + + *pIndexTypeOut = (sig_index_type) (encoded & 0x3); + *pIndexOut = (encoded >> 2); + return true; +} + +bool SigParser::ParseNumber(sig_count *pOut) +{ + // parse the variable length number format (0-4 bytes) + + sig_byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + + // at least one byte in the encoding, read that + + if (!ParseByte(&b1)) + { + return false; + } + + if (b1 == 0xff) + { + // special encoding of 'NULL' + // not sure what this means as a number, don't expect to see it except for string lengths + // which we don't encounter anyway so calling it an error + return false; + } + + // early out on 1 byte encoding + if ( (b1 & 0x80) == 0) + { + *pOut = (int)b1; + return true; + } + + // now at least 2 bytes in the encoding, read 2nd byte + if (!ParseByte(&b2)) + { + return false; + } + + // early out on 2 byte encoding + if ( (b1 & 0x40) == 0) + { + *pOut = (((b1 & 0x3f) << 8) | b2); + return true; + } + + // must be a 4 byte encoding + + if ( (b1 & 0x20) != 0) + { + // 4 byte encoding has this bit clear -- error if not + return false; + } + + if (!ParseByte(&b3)) + { + return false; + } + + if (!ParseByte(&b4)) + { + return false; + } + + *pOut = ((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4; + return true; +} |