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