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