summaryrefslogtreecommitdiff
path: root/Documentation/Profiling/davbr-blog-archive/samples
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/Profiling/davbr-blog-archive/samples')
-rw-r--r--Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp478
-rw-r--r--Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp1052
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(&param_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(&param_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;
+}