diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-11-24 06:42:38 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-11-24 06:42:38 -0800 |
commit | a39120ee1ce243fd6da501b77a55b50ad4627503 (patch) | |
tree | de4325d9435ae39e729e87f24df12ddac6103f82 /src/tools/metainfo | |
parent | 635f54a41de4b9c428cccb773e1a780ddf8ffed1 (diff) | |
download | coreclr-a39120ee1ce243fd6da501b77a55b50ad4627503.tar.gz coreclr-a39120ee1ce243fd6da501b77a55b50ad4627503.tar.bz2 coreclr-a39120ee1ce243fd6da501b77a55b50ad4627503.zip |
Open sourcing ILDASM
[tfs-changeset: 1551732]
Diffstat (limited to 'src/tools/metainfo')
-rw-r--r-- | src/tools/metainfo/.gitmirrorall | 1 | ||||
-rw-r--r-- | src/tools/metainfo/Native.rc | 9 | ||||
-rw-r--r-- | src/tools/metainfo/mdinfo.cpp | 4320 | ||||
-rw-r--r-- | src/tools/metainfo/mdinfo.h | 206 | ||||
-rw-r--r-- | src/tools/metainfo/mdobj.cpp | 299 | ||||
-rw-r--r-- | src/tools/metainfo/metainfo.cpp | 199 | ||||
-rw-r--r-- | src/tools/metainfo/metainfo.nativeproj | 42 |
7 files changed, 5076 insertions, 0 deletions
diff --git a/src/tools/metainfo/.gitmirrorall b/src/tools/metainfo/.gitmirrorall new file mode 100644 index 0000000000..9ee5c57b99 --- /dev/null +++ b/src/tools/metainfo/.gitmirrorall @@ -0,0 +1 @@ +This folder will be mirrored by the Git-TFS Mirror recursively.
\ No newline at end of file diff --git a/src/tools/metainfo/Native.rc b/src/tools/metainfo/Native.rc new file mode 100644 index 0000000000..13e7ae2af2 --- /dev/null +++ b/src/tools/metainfo/Native.rc @@ -0,0 +1,9 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#define FX_VER_FILEDESCRIPTION_STR "Microsoft Common Language Runtime Metadata Info\0" + +#include <fxver.h> +#include <fxver.rc> diff --git a/src/tools/metainfo/mdinfo.cpp b/src/tools/metainfo/mdinfo.cpp new file mode 100644 index 0000000000..b0db3591b9 --- /dev/null +++ b/src/tools/metainfo/mdinfo.cpp @@ -0,0 +1,4320 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include <stdio.h> +#include <windows.h> +#include <objbase.h> +#include <crtdbg.h> +#include <assert.h> + +#include <corpriv.h> +#include <cor.h> +#include "assert.h" +#include "corerror.h" +#include <winwrap.h> +#include <prettyprintsig.h> + +#include <cahlpr.h> +#include <limits.h> + +#include "mdinfo.h" + +#define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary +#define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE +#include "LegacyActivationShim.h" + +#define ENUM_BUFFER_SIZE 10 +#define TAB_SIZE 8 + +#define NumItems(s) (sizeof(s) / sizeof(s[0])) + +#define ISFLAG(p,x) if (Is##p##x(flags)) strcat_s(sFlags,STRING_BUFFER_LEN, "["#x "] "); + +extern HRESULT _FillVariant( + BYTE bCPlusTypeFlag, + void const *pValue, + ULONG cbValue, + VARIANT *pvar); + +// Validator declarations. +extern DWORD g_ValModuleType; +#include <ivehandler.h> + +// Tables for mapping element type to text +char *g_szMapElementType[] = +{ + "End", // 0x0 + "Void", // 0x1 + "Boolean", + "Char", + "I1", + "UI1", + "I2", // 0x6 + "UI2", + "I4", + "UI4", + "I8", + "UI8", + "R4", + "R8", + "String", + "Ptr", // 0xf + "ByRef", // 0x10 + "ValueClass", + "Class", + "Var", + "MDArray", // 0x14 + "GenericInst", + "TypedByRef", + "VALUEARRAY", + "I", + "U", + "R", // 0x1a + "FNPTR", + "Object", + "SZArray", + "MVar", + "CMOD_REQD", + "CMOD_OPT", + "INTERNAL", +}; + +char *g_szMapUndecorateType[] = +{ + "", // 0x0 + "void", + "boolean", + "Char", + "byte", + "unsigned byte", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "float", + "double", + "String", + "*", // 0xf + "ByRef", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "Function Pointer", + "Object", + "", + "", + "CMOD_REQD", + "CMOD_OPT", + "INTERNAL", +}; + +// Provide enough entries for IMAGE_CEE_CS_CALLCONV_MASK (defined in CorHdr.h) +char *g_strCalling[] = +{ + "[DEFAULT]", + "[C]", + "[STDCALL]", + "[THISCALL]", + "[FASTCALL]", + "[VARARG]", + "[FIELD]", + "[LOCALSIG]", + "[PROPERTY]", + "[UNMANAGED]", + "[GENERICINST]", + "[NATIVEVARARG]", + "[INVALID]", + "[INVALID]", + "[INVALID]", + "[INVALID]" +}; + +char *g_szNativeType[] = +{ + "NATIVE_TYPE_END(DEPRECATED!)", // = 0x0, //DEPRECATED + "NATIVE_TYPE_VOID(DEPRECATED!)", // = 0x1, //DEPRECATED + "NATIVE_TYPE_BOOLEAN", // = 0x2, // (4 byte boolean value: TRUE = non-zero, FALSE = 0) + "NATIVE_TYPE_I1", // = 0x3, + "NATIVE_TYPE_U1", // = 0x4, + "NATIVE_TYPE_I2", // = 0x5, + "NATIVE_TYPE_U2", // = 0x6, + "NATIVE_TYPE_I4", // = 0x7, + "NATIVE_TYPE_U4", // = 0x8, + "NATIVE_TYPE_I8", // = 0x9, + "NATIVE_TYPE_U8", // = 0xa, + "NATIVE_TYPE_R4", // = 0xb, + "NATIVE_TYPE_R8", // = 0xc, + "NATIVE_TYPE_SYSCHAR(DEPRECATED!)", // = 0xd, //DEPRECATED + "NATIVE_TYPE_VARIANT(DEPRECATED!)", // = 0xe, //DEPRECATED + "NATIVE_TYPE_CURRENCY", // = 0xf, + "NATIVE_TYPE_PTR(DEPRECATED!)", // = 0x10, //DEPRECATED + + "NATIVE_TYPE_DECIMAL(DEPRECATED!)", // = 0x11, //DEPRECATED + "NATIVE_TYPE_DATE(DEPRECATED!)", // = 0x12, //DEPRECATED + "NATIVE_TYPE_BSTR", // = 0x13, + "NATIVE_TYPE_LPSTR", // = 0x14, + "NATIVE_TYPE_LPWSTR", // = 0x15, + "NATIVE_TYPE_LPTSTR", // = 0x16, + "NATIVE_TYPE_FIXEDSYSSTRING", // = 0x17, + "NATIVE_TYPE_OBJECTREF(DEPRECATED!)", // = 0x18, //DEPRECATED + "NATIVE_TYPE_IUNKNOWN", // = 0x19, + "NATIVE_TYPE_IDISPATCH", // = 0x1a, + "NATIVE_TYPE_STRUCT", // = 0x1b, + "NATIVE_TYPE_INTF", // = 0x1c, + "NATIVE_TYPE_SAFEARRAY", // = 0x1d, + "NATIVE_TYPE_FIXEDARRAY", // = 0x1e, + "NATIVE_TYPE_INT", // = 0x1f, + "NATIVE_TYPE_UINT", // = 0x20, + + "NATIVE_TYPE_NESTEDSTRUCT(DEPRECATED!)", // = 0x21, //DEPRECATED (use "NATIVE_TYPE_STRUCT) + + "NATIVE_TYPE_BYVALSTR", // = 0x22, + + "NATIVE_TYPE_ANSIBSTR", // = 0x23, + + "NATIVE_TYPE_TBSTR", // = 0x24, // select BSTR or ANSIBSTR depending on platform + + + "NATIVE_TYPE_VARIANTBOOL", // = 0x25, // (2-byte boolean value: TRUE = -1, FALSE = 0) + "NATIVE_TYPE_FUNC", // = 0x26, + "NATIVE_TYPE_LPVOID", // = 0x27, // blind pointer (no deep marshaling) + + "NATIVE_TYPE_ASANY", // = 0x28, + "<UNDEFINED NATIVE TYPE 0x29>", + "NATIVE_TYPE_ARRAY", // = 0x2a, + "NATIVE_TYPE_LPSTRUCT", // = 0x2b, + "NATIVE_TYPE_CUSTOMMARSHALER", // = 0x2c, // Custom marshaler. + "NATIVE_TYPE_ERROR", // = 0x2d, // VT_HRESULT when exporting to a typelib. +}; + + +size_t g_cbCoffNames = 0; + +mdMethodDef g_tkEntryPoint = 0; // integration with ILDASM + + + +// helper to init signature buffer +void MDInfo::InitSigBuffer() +{ + strcpy_s((LPSTR)m_sigBuf.Ptr(), 1, ""); +} // void MDInfo::InitSigBuffer() + +// helper to append a string into the signature buffer. If size of signature buffer is not big enough, +// we will grow it. +HRESULT MDInfo::AddToSigBuffer(__in_z __in char *string) +{ + HRESULT hr; + size_t LL = strlen((LPSTR)m_sigBuf.Ptr()) + strlen(string) + 1; + IfFailRet( m_sigBuf.ReSizeNoThrow(LL) ); + strcat_s((LPSTR)m_sigBuf.Ptr(), LL, string); + return NOERROR; +} // HRESULT MDInfo::AddToSigBuffer() + +MDInfo::MDInfo(IMetaDataImport2 *pImport, IMetaDataAssemblyImport *pAssemblyImport, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter) +{ // This constructor is specific to ILDASM/MetaInfo integration + + _ASSERTE(pImport != NULL); + _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType)); + _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX); + + Init(inPBFn, (DUMP_FILTER)DumpFilter); + + m_pImport = pImport; + m_pImport->AddRef(); + if ((m_pAssemblyImport = pAssemblyImport)) + m_pAssemblyImport->AddRef(); + else + { + HRESULT hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport); + if (FAILED(hr)) + Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr); + } + +} // MDInfo::MDInfo() + +MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter) +{ + HRESULT hr = S_OK; + VARIANT value; + + _ASSERTE(pDispenser != NULL && inPBFn != NULL); + _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType)); + _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX); + + Init(inPBFn, (DUMP_FILTER)DumpFilter); + + // Attempt to open scope on given file + V_VT(&value) = VT_UI4; + V_UI4(&value) = MDImportOptionAll; + if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value))) + Error("SetOption failed.", hr); + + hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport); + if (hr == CLDB_E_BADUPDATEMODE) + { + V_VT(&value) = VT_UI4; + V_UI4(&value) = MDUpdateIncremental; + if (FAILED(hr = pDispenser->SetOption(MetaDataSetUpdate, &value))) + Error("SetOption failed.", hr); + hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport); + } + if (FAILED(hr)) + Error("OpenScope failed", hr); + + // Query for the IMetaDataAssemblyImport interface. + hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport); + if (FAILED(hr)) + Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr); + +} // MDInfo::MDInfo() + + +MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, PBYTE pbMetaData, DWORD dwSize, strPassBackFn inPBFn, ULONG DumpFilter) +{ + _ASSERTE(pDispenser != NULL && inPBFn != NULL); + _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType)); + _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX); + + Init(inPBFn, (DUMP_FILTER)DumpFilter); + + // Attempt to open scope on manifest. It's valid for this to fail, because + // the blob we open may just be the assembly resources (the space is + // overloaded until we remove LM -a assemblies, at which point this + // constructor should probably be removed too). + HRESULT hr; + VARIANT value; + V_VT(&value) = VT_UI4; + V_UI4(&value) = MDImportOptionAll; + if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value))) + Error("SetOption failed.", hr); + if (SUCCEEDED(hr = pDispenser->OpenScopeOnMemory(pbMetaData, dwSize, ofNoTransform, + IID_IMetaDataImport2, (IUnknown**)&m_pImport))) + { + // Query for the IMetaDataAssemblyImport interface. + hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport); + if (FAILED(hr)) + Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr); + } + +} // MDInfo::MDInfo() + +void MDInfo::Init( + strPassBackFn inPBFn, // Callback to write text. + DUMP_FILTER DumpFilter) // Flags to control the dump. +{ + m_VEHandlerReporterPtr = 0; + m_pbFn = inPBFn; + m_DumpFilter = DumpFilter; + m_pTables = NULL; + m_pTables2 = NULL; + m_pImport = NULL; + m_pAssemblyImport = NULL; +} // void MDInfo::Init() + +// Destructor +MDInfo::~MDInfo() +{ + if (m_pImport) + m_pImport->Release(); + if (m_pAssemblyImport) + m_pAssemblyImport->Release(); + if (m_pTables) + m_pTables->Release(); + if (m_pTables2) + m_pTables2->Release(); +} // MDInfo::~MDInfo() + +//===================================================================================================================== +//#define EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION +#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION + +HINSTANCE GetModuleInst() +{ + return NULL; +} // HINSTANCE GetModuleInst() + +typedef HRESULT (*REPORTFCTN)(LPCWSTR, VEContext, HRESULT); +HRESULT DefaultReporter( // Return status. + LPCWSTR szMsg, // Error message. + VEContext Context, // Error context (offset,token) + HRESULT hrRpt) // Original HRESULT +{ + if(szMsg) + { + printf("%S", szMsg); + // include token and offset from Context + if(Context.Token) printf(" [token:0x%08X]",Context.Token); + if(Context.uOffset) printf(" [at:0x%X]",Context.uOffset); + printf(" [hr:0x%08X]\n",hrRpt); + fflush(stdout); + } + return S_OK; +} // HRESULT DefaultReporter() + +class MDVEHandlerClass : public IVEHandler +{ +public: + LONG m_refCount; + REPORTFCTN m_fnReport; + + MDVEHandlerClass() { m_refCount=0; m_fnReport=DefaultReporter; }; + virtual ~MDVEHandlerClass() { }; + + //----------------------------------------------------------- + // IUnknown support + //----------------------------------------------------------- + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void** pInterface) + { + if (id == IID_IVEHandler) + *pInterface = (IVEHandler*)this; + /* + else if (id == IID_IUnknown) + *pInterface = (IUnknown*)(IVEHandler*)this; + */ + else + { + *pInterface = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } + ULONG STDMETHODCALLTYPE AddRef() + { + return InterlockedIncrement(&m_refCount); + } + + ULONG STDMETHODCALLTYPE Release() + { + LONG refCount = InterlockedDecrement(&m_refCount); + if (refCount == 0) delete this; + return (refCount); + } + //----------------------------------------------------------- + // IVEHandler support + //----------------------------------------------------------- + HRESULT STDMETHODCALLTYPE SetReporterFtn(__int64 lFnPtr) + { + m_fnReport = lFnPtr ? reinterpret_cast<REPORTFCTN>(lFnPtr) + : DefaultReporter; + return S_OK; + }; + +//***************************************************************************** +// The Verification Event Handler itself. Declared in VEHandler.h as virtual, may be overridden +//***************************************************************************** + HRESULT STDMETHODCALLTYPE VEHandler(HRESULT hrRpt, VEContext Context, SAFEARRAY *psa) + { + WCHAR rcBuf[1024]; // Resource string. + WCHAR rcMsg[1024]; // Error message. + BYTE *marker; // User text. + HRESULT hr; + ULONG32 k; + WCHAR *pWsz[1024]; // is more than 1024 string arguments likely? + + // Return warnings without text. + if (!FAILED(hrRpt)) + return (hrRpt); + memset(pWsz,0,sizeof(pWsz)); + + ULONG32 nVars; + // Convert safearray of variants into va_list + if(psa && (nVars = psa->rgsabound[0].cElements)) + { + WCHAR *pwsz; + VARIANT *pVar; + ULONG32 i,l; + BYTE *pval; + + _ASSERTE(psa->fFeatures & FADF_VARIANT); + _ASSERTE(psa->cDims == 1); + marker = new BYTE[nVars*sizeof(double)]; // double being the largest variant element + for(i=0,pVar=(VARIANT *)(psa->pvData),pval=marker; i < nVars; pVar++,i++) + { + switch(V_VT(pVar)) + { + case VT_I1: + *(int *)pval = V_I1(pVar); + pval += sizeof(int); + break; + + case VT_UI1: + *(int *)pval = V_UI1(pVar); + pval += sizeof(int); + break; + + + case VT_I2: + *(int *)pval = V_I2(pVar); + pval += sizeof(int); + break; + + case VT_UI2: + *(int *)pval = V_UI2(pVar); + pval += sizeof(int); + break; + + case VT_I8: + case VT_UI8: + *(INT64 *)pval = V_I8(pVar); + pval += sizeof(INT64); + break; + + + case VT_BYREF|VT_I1: + case VT_BYREF|VT_UI1: // it's ASCII string, convert it to UNICODE + { + PBYTE pb = V_UI1REF(pVar); + l = (ULONG32)strlen((char *)pb)+1; + pwsz = new WCHAR[l]; + WszMultiByteToWideChar(CP_ACP,0,(char*)pb,-1,pwsz,l); + for(k=0; pWsz[k]; k++); + pWsz[k] = pwsz; + + *(WCHAR **)pval = pwsz; + pval += sizeof(WCHAR *); + break; + } + + default: + *(int *)pval = V_I4(pVar); + pval += sizeof(int); + break; + } + } + } + else + marker = NULL; + + // If this is one of our errors, then grab the error from the rc file. + if (HRESULT_FACILITY(hrRpt) == FACILITY_URT) + { + hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true); + if (hr == S_OK) + { + // Format the error. + vswprintf_s(rcMsg, NumItems(rcMsg), rcBuf, (va_list) marker); + rcMsg[NumItems(rcMsg) - 1] = 0; + } + } + // Otherwise it isn't one of ours, so we need to see if the system can + // find the text for it. + else + { + if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + rcMsg, NumItems(rcMsg), 0)) + { + hr = S_OK; + + // System messages contain a trailing \r\n, which we don't want normally. + int iLen = lstrlenW(rcMsg); + if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n') + rcMsg[iLen - 2] = '\0'; + } + else + hr = HRESULT_FROM_WIN32(GetLastError()); + } + if(marker) delete [] marker; + + // If we failed to find the message anywhere, then issue a hard coded message. + if (FAILED(hr)) + { + swprintf_s(rcMsg, NumItems(rcMsg), L"COM+ Runtime Internal error: 0x%08x", hrRpt); + //DEBUG_STMT(DbgWriteEx(rcMsg)); + } + + // delete WCHAR buffers allocated above (if any) + for(k=0; pWsz[k]; k++) + { + if(pWsz[k]) + { + delete [] pWsz[k]; + pWsz[k] = NULL; + } + } + + return (m_fnReport(rcMsg, Context,hrRpt) == S_OK ? S_OK : E_FAIL); + }; + + static HRESULT STDMETHODCALLTYPE CreateObject(REFIID id, void **object) + { return E_NOTIMPL; } +}; + +#endif +//===================================================================================================================== +// DisplayMD() function +// +// Displays the meta data content of a file + +void MDInfo::DisplayMD() +{ + if ((m_DumpFilter & dumpAssem) && m_pAssemblyImport) + DisplayAssemblyInfo(); + WriteLine("==========================================================="); + // Metadata itself: Raw or normal view + if (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps)) + DisplayRaw(); + else + { + DisplayVersionInfo(); + DisplayScopeInfo(); + WriteLine("==========================================================="); + DisplayGlobalFunctions(); + DisplayGlobalFields(); + DisplayGlobalMemberRefs(); + DisplayTypeDefs(); + DisplayTypeRefs(); + DisplayTypeSpecs(); + DisplayMethodSpecs(); + DisplayModuleRefs(); + DisplaySignatures(); + DisplayAssembly(); + DisplayUserStrings(); + + // WriteLine("============================================================"); + // WriteLine("Unresolved MemberRefs"); + // DisplayMemberRefs(0x00000001, "\t"); + + VWrite("\n\nCoff symbol name overhead: %d\n", g_cbCoffNames); + } + WriteLine("==========================================================="); + if (m_DumpFilter & dumpUnsat) + DisplayUnsatInfo(); + WriteLine("==========================================================="); + if (m_DumpFilter & dumpValidate) + { + IMetaDataValidate *pValidate = 0; +#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION + MDVEHandlerClass *pVEHandler = 0; +#else + IVEHandler *pVEHandler = 0; +#endif + const char *szErrStr = 0; + HRESULT hr = S_OK; + + // Get a pointer to the Validator interface. + hr = m_pImport->QueryInterface(IID_IMetaDataValidate, (void **) &pValidate); + if (FAILED(hr)) + { + szErrStr = "QueryInterface failed for IMetaDataValidate."; + goto ErrExit; + } + + // Get a pointer to the VEHandler interface. +#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION + if((pVEHandler = new MDVEHandlerClass())) hr = S_OK; + else hr = E_FAIL; +#else + hr = CoCreateInstance(CLSID_VEHandlerClass, + NULL, + CLSCTX_INPROC_SERVER, + IID_IVEHandler, + (void **)&pVEHandler); +#endif + if (FAILED(hr)) + { +#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION + szErrStr = "Failed to create VEHandler."; +#else + szErrStr = "CoCreateInstance(VEHandler) failed."; +#endif + goto ErrExit; + } + + if(m_VEHandlerReporterPtr) pVEHandler->SetReporterFtn((__int64)m_VEHandlerReporterPtr); + + hr = pValidate->ValidatorInit(g_ValModuleType, pVEHandler); + if (FAILED(hr)) + { + szErrStr = "ValidatorInit failed."; + goto ErrExit; + } + + hr = pValidate->ValidateMetaData(); + if (FAILED(hr)) + { + szErrStr = "ValidateMetaData failed to run successfully."; + goto ErrExit; + } + if (hr == S_OK) + WriteLine("No warnings or errors found."); + else if (hr == VLDTR_S_WRN) + WriteLine("Warnings found."); + else if (hr == VLDTR_S_ERR) + WriteLine("Errors found."); + else if (hr == VLDTR_S_WRNERR) + WriteLine("Warnings and Errors found."); + else + VWriteLine("Validator returned unexpected success code, hr=0x%08x.", hr); +ErrExit: + if (pValidate) + pValidate->Release(); +#ifdef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION + if (pVEHandler) + pVEHandler->Release(); +#endif + if (szErrStr) + Error(szErrStr, hr); + } + WriteLine("==========================================================="); +} // MDVEHandlerClass() + +int MDInfo::WriteLine(__in_z __in char *str) +{ + ULONG32 count = (ULONG32) strlen(str); + + m_pbFn(str); + m_pbFn("\n"); + return count; +} // int MDInfo::WriteLine() + +int MDInfo::Write(__in_z __in char *str) +{ + ULONG32 count = (ULONG32) strlen(str); + + m_pbFn(str); + return count; +} // int MDInfo::Write() + +int MDInfo::VWriteLine(__in_z __in char *str, ...) +{ + va_list marker; + int count; + + va_start(marker, str); + count = VWriteMarker(str, marker); + m_pbFn("\n"); + va_end(marker); + return count; +} // int MDInfo::VWriteLine() + +int MDInfo::VWrite(__in_z __in char *str, ...) +{ + va_list marker; + int count; + + va_start(marker, str); + count = VWriteMarker(str, marker); + va_end(marker); + return count; +} // int MDInfo::VWrite() + +int MDInfo::VWriteMarker(__in_z __in char *str, va_list marker) +{ + HRESULT hr; + int count = -1; + // Used to allocate 1K, then if not enough, 2K, then 4K. + // Faster to allocate 32K right away and be done with it, + // we're not running on Commodore 64 + if (FAILED(hr = m_output.ReSizeNoThrow(STRING_BUFFER_LEN * 8))) + Error("ReSize failed.", hr); + else + { + count = vsprintf_s((char *)m_output.Ptr(), STRING_BUFFER_LEN * 8, str, marker); + m_pbFn((char *)m_output.Ptr()); + } + return count; +} // int MDInfo::VWriteToBuffer() + +// Error() function -- prints an error and returns +void MDInfo::Error(const char* szError, HRESULT hr) +{ + printf("\n%s\n",szError); + if (hr != S_OK) + { + printf("Failed return code: 0x%08x\n", hr); + + IErrorInfo *pIErr = NULL; // Error interface. + BSTR bstrDesc = NULL; // Description text. + + // Try to get an error info object and display the message. + if (GetErrorInfo(0, &pIErr) == S_OK && + pIErr->GetDescription(&bstrDesc) == S_OK) + { + printf("%ls ", bstrDesc); + SysFreeString(bstrDesc); + } + + // Free the error interface. + if (pIErr) + pIErr->Release(); + + } + LegacyActivationShim::CoUninitializeCor(); +#ifndef FEATURE_PAL + CoUninitialize(); +#endif + exit(hr); +} // void MDInfo::Error() + +// Print out the optional version info included in the MetaData. + +void MDInfo::DisplayVersionInfo() +{ + if (!(m_DumpFilter & MDInfo::dumpNoLogo)) + { + LPCUTF8 pVersionStr; + HRESULT hr = S_OK; + + if (m_pTables == 0) + { + if (m_pImport) + hr = m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables); + else if (m_pAssemblyImport) + hr = m_pAssemblyImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables); + else + return; + if (FAILED(hr)) + Error("QueryInterface failed for IID_IMetaDataTables.", hr); + } + + hr = m_pTables->GetString(1, &pVersionStr); + if (FAILED(hr)) + Error("GetString() failed.", hr); + if (strstr(pVersionStr, "Version of runtime against which the binary is built : ") + == pVersionStr) + { + WriteLine(const_cast<char *>(pVersionStr)); + } + } +} // void MDInfo::DisplayVersionInfo() + +// Prints out information about the scope + +void MDInfo::DisplayScopeInfo() +{ + HRESULT hr; + mdModule mdm; + GUID mvid; + WCHAR scopeName[STRING_BUFFER_LEN]; + WCHAR guidString[STRING_BUFFER_LEN]; + + hr = m_pImport->GetScopeProps( scopeName, STRING_BUFFER_LEN, 0, &mvid); + if (FAILED(hr)) Error("GetScopeProps failed.", hr); + + VWriteLine("ScopeName : %ls",scopeName); + + if (!(m_DumpFilter & MDInfo::dumpNoLogo)) + VWriteLine("MVID : %ls",GUIDAsString(mvid, guidString, STRING_BUFFER_LEN)); + + hr = m_pImport->GetModuleFromScope(&mdm); + if (FAILED(hr)) Error("GetModuleFromScope failed.", hr); + DisplayPermissions(mdm, ""); + DisplayCustomAttributes(mdm, "\t"); +} // void MDInfo::DisplayScopeInfo() + +void MDInfo::DisplayRaw() +{ + int iDump; // Level of info to dump. + + if (m_pTables == 0) + m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables); + if (m_pTables == 0) + Error("Can't get table info."); + if (m_pTables2 == 0) + m_pImport->QueryInterface(IID_IMetaDataTables2, (void**)&m_pTables2); + + if (m_DumpFilter & dumpCSV) + DumpRawCSV(); + if (m_DumpFilter & (dumpSchema | dumpHeader | dumpRaw | dumpStats)) + { + if (m_DumpFilter & dumpRaw) + iDump = 3; + else + if (m_DumpFilter & dumpSchema) + iDump = 2; + else + iDump = 1; + + DumpRaw(iDump, (m_DumpFilter & dumpStats) != 0); + } + if (m_DumpFilter & dumpRawHeaps) + DumpRawHeaps(); +} // void MDInfo::DisplayRaw() + +// return the name of the type of token passed in + +char *MDInfo::TokenTypeName(mdToken inToken) +{ + switch(TypeFromToken(inToken)) + { + case mdtTypeDef: return "TypeDef"; + case mdtInterfaceImpl: return "InterfaceImpl"; + case mdtMethodDef: return "MethodDef"; + case mdtFieldDef: return "FieldDef"; + case mdtTypeRef: return "TypeRef"; + case mdtMemberRef: return "MemberRef"; + case mdtCustomAttribute:return "CustomAttribute"; + case mdtParamDef: return "ParamDef"; + case mdtProperty: return "Property"; + case mdtEvent: return "Event"; + case mdtTypeSpec: return "TypeSpec"; + default: return "[UnknownTokenType]"; + } +} // char *MDInfo::TokenTypeName() + +// Prints out name of the given memberref +// + +LPCWSTR MDInfo::MemberRefName(mdMemberRef inMemRef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + HRESULT hr; + + + hr = m_pImport->GetMemberRefProps( inMemRef, NULL, buffer, bufLen, + NULL, NULL, NULL); + if (FAILED(hr)) Error("GetMemberRefProps failed.", hr); + + return buffer; +} // LPCWSTR MDInfo::MemberRefName() + + +// Prints out information about the given memberref +// + +void MDInfo::DisplayMemberRefInfo(mdMemberRef inMemRef, const char *preFix) +{ + HRESULT hr; + WCHAR memRefName[STRING_BUFFER_LEN]; + ULONG nameLen; + mdToken token; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + char newPreFix[STRING_BUFFER_LEN]; + + + hr = m_pImport->GetMemberRefProps( inMemRef, &token, memRefName, STRING_BUFFER_LEN, + &nameLen, &pbSigBlob, &ulSigBlob); + if (FAILED(hr)) Error("GetMemberRefProps failed.", hr); + + VWriteLine("%s\t\tMember: (%8.8x) %ls: ", preFix, inMemRef, memRefName); + + if (ulSigBlob) + DisplaySignature(pbSigBlob, ulSigBlob, preFix); + else + VWriteLine("%s\t\tERROR: no valid signature ", preFix); + + sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix); + DisplayCustomAttributes(inMemRef, newPreFix); +} // void MDInfo::DisplayMemberRefInfo() + +// Prints out information about all memberrefs of the given typeref +// + +void MDInfo::DisplayMemberRefs(mdToken tkParent, const char *preFix) +{ + HCORENUM memRefEnum = NULL; + HRESULT hr; + mdMemberRef memRefs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + + + while (SUCCEEDED(hr = m_pImport->EnumMemberRefs( &memRefEnum, tkParent, + memRefs, NumItems(memRefs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("%s\tMemberRef #%d (%08x)", preFix, totalCount, memRefs[i]); + VWriteLine("%s\t-------------------------------------------------------", preFix); + DisplayMemberRefInfo(memRefs[i], preFix); + } + } + m_pImport->CloseEnum( memRefEnum); +} // void MDInfo::DisplayMemberRefs() + +// Prints out information about all resources in the com object +// + +// Iterates through each typeref and prints out the information of each +// + +void MDInfo::DisplayTypeRefs() +{ + HCORENUM typeRefEnum = NULL; + mdTypeRef typeRefs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount=1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pImport->EnumTypeRefs( &typeRefEnum, + typeRefs, NumItems(typeRefs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("TypeRef #%d (%08x)", totalCount, typeRefs[i]); + WriteLine("-------------------------------------------------------"); + DisplayTypeRefInfo(typeRefs[i]); + DisplayMemberRefs(typeRefs[i], ""); + WriteLine(""); + } + } + m_pImport->CloseEnum( typeRefEnum); +} // void MDInfo::DisplayTypeRefs() + +void MDInfo::DisplayTypeSpecs() +{ + HCORENUM typespecEnum = NULL; + mdTypeSpec typespecs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount=1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pImport->EnumTypeSpecs( &typespecEnum, + typespecs, NumItems(typespecs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("TypeSpec #%d (%08x)", totalCount, typespecs[i]); + WriteLine("-------------------------------------------------------"); + DisplayTypeSpecInfo(typespecs[i], ""); + DisplayMemberRefs(typespecs[i], ""); + WriteLine(""); + } + } + m_pImport->CloseEnum( typespecEnum); +} // void MDInfo::DisplayTypeSpecs() + +void MDInfo::DisplayMethodSpecs() +{ + HCORENUM MethodSpecEnum = NULL; + mdMethodSpec MethodSpecs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount=1; +///// HRESULT hr; + + +///// HACK until I implement EnumMethodSpecs! +///// while (SUCCEEDED(hr = m_pImport->EnumMethodSpecs( &MethodSpecEnum, +///// MethodSpecs, NumItems(MethodSpecs), &count)) && +///// count > 0) + for (ULONG rid=1; m_pImport->IsValidToken(TokenFromRid(rid, mdtMethodSpec)); ++rid) + { +// More hackery +count = 1; +MethodSpecs[0] = TokenFromRid(rid, mdtMethodSpec); +// More hackery + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("MethodSpec #%d (%08x)", totalCount, MethodSpecs[i]); + DisplayMethodSpecInfo(MethodSpecs[i], ""); + WriteLine(""); + } + } + m_pImport->CloseEnum( MethodSpecEnum); +} // void MDInfo::DisplayMethodSpecs() + + + +// Called to display the information about all typedefs in the object. +// + +void MDInfo::DisplayTypeDefs() +{ + HCORENUM typeDefEnum = NULL; + mdTypeDef typeDefs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pImport->EnumTypeDefs( &typeDefEnum, + typeDefs, NumItems(typeDefs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("TypeDef #%d (%08x)", totalCount, typeDefs[i]); + WriteLine("-------------------------------------------------------"); + DisplayTypeDefInfo(typeDefs[i]); + WriteLine(""); + } + } + m_pImport->CloseEnum( typeDefEnum); +} // void MDInfo::DisplayTypeDefs() + +// Called to display the information about all modulerefs in the object. +// + +void MDInfo::DisplayModuleRefs() +{ + HCORENUM moduleRefEnum = NULL; + mdModuleRef moduleRefs[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pImport->EnumModuleRefs( &moduleRefEnum, + moduleRefs, NumItems(moduleRefs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("ModuleRef #%d (%08x)", totalCount, moduleRefs[i]); + WriteLine("-------------------------------------------------------"); + DisplayModuleRefInfo(moduleRefs[i]); + DisplayMemberRefs(moduleRefs[i], ""); + WriteLine(""); + } + } + m_pImport->CloseEnum( moduleRefEnum); +} // void MDInfo::DisplayModuleRefs() + +// Prints out information about the given moduleref +// + +void MDInfo::DisplayModuleRefInfo(mdModuleRef inModuleRef) +{ + HRESULT hr; + WCHAR moduleRefName[STRING_BUFFER_LEN]; + ULONG nameLen; + + + hr = m_pImport->GetModuleRefProps( inModuleRef, moduleRefName, STRING_BUFFER_LEN, + &nameLen); + if (FAILED(hr)) Error("GetModuleRefProps failed.", hr); + + VWriteLine("\t\tModuleRef: (%8.8x) %ls: ", inModuleRef, moduleRefName); + DisplayCustomAttributes(inModuleRef, "\t\t"); +} // void MDInfo::DisplayModuleRefInfo() + + +// Called to display the information about all signatures in the object. +// + +void MDInfo::DisplaySignatures() +{ + HCORENUM signatureEnum = NULL; + mdSignature signatures[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pImport->EnumSignatures( &signatureEnum, + signatures, NumItems(signatures), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("Signature #%d (%#08x)", totalCount, signatures[i]); + WriteLine("-------------------------------------------------------"); + DisplaySignatureInfo(signatures[i]); + WriteLine(""); + } + } + m_pImport->CloseEnum( signatureEnum); +} // void MDInfo::DisplaySignatures() + + +// Prints out information about the given signature +// + +void MDInfo::DisplaySignatureInfo(mdSignature inSignature) +{ + HRESULT hr; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + + + hr = m_pImport->GetSigFromToken( inSignature, &pbSigBlob, &ulSigBlob ); + if (FAILED(hr)) Error("GetSigFromToken failed.", hr); + if(ulSigBlob) + DisplaySignature(pbSigBlob, ulSigBlob, ""); + else + VWriteLine("\t\tERROR: no valid signature "); +} // void MDInfo::DisplaySignatureInfo() + + +// returns the passed-in buffer which is filled with the name of the given +// member in wide characters +// + +LPCWSTR MDInfo::MemberName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + HRESULT hr; + + + hr = m_pImport->GetMemberProps( inToken, NULL, buffer, bufLen, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (FAILED(hr)) Error("GetMemberProps failed.", hr); + + return (buffer); +} // LPCWSTR MDInfo::MemberName() + + +// displays information for the given method +// + +void MDInfo::DisplayMethodInfo(mdMethodDef inMethod, DWORD *pflags) +{ + HRESULT hr; + mdTypeDef memTypeDef; + WCHAR memberName[STRING_BUFFER_LEN]; + ULONG nameLen; + DWORD flags; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + ULONG ulCodeRVA; + ULONG ulImplFlags; + + + hr = m_pImport->GetMethodProps( inMethod, &memTypeDef, memberName, STRING_BUFFER_LEN, + &nameLen, &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags); + if (FAILED(hr)) Error("GetMethodProps failed.", hr); + if (pflags) + *pflags = flags; + + VWriteLine("\t\tMethodName: %ls (%8.8X)", memberName, inMethod); + + char sFlags[STRING_BUFFER_LEN]; + + sFlags[0] = 0; + ISFLAG(Md, Public); + ISFLAG(Md, Private); + ISFLAG(Md, Family); + ISFLAG(Md, Assem); + ISFLAG(Md, FamANDAssem); + ISFLAG(Md, FamORAssem); + ISFLAG(Md, PrivateScope); + ISFLAG(Md, Static); + ISFLAG(Md, Final); + ISFLAG(Md, Virtual); + ISFLAG(Md, HideBySig); + ISFLAG(Md, ReuseSlot); + ISFLAG(Md, NewSlot); + ISFLAG(Md, Abstract); + ISFLAG(Md, SpecialName); + ISFLAG(Md, RTSpecialName); + ISFLAG(Md, PinvokeImpl); + ISFLAG(Md, UnmanagedExport); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + if (IsMdInstanceInitializerW(flags, memberName)) strcat_s(sFlags, STRING_BUFFER_LEN, "[.ctor] "); + if (IsMdClassConstructorW(flags, memberName)) strcat_s(sFlags,STRING_BUFFER_LEN, "[.cctor] "); + // "Reserved" flags + ISFLAG(Md, HasSecurity); + ISFLAG(Md, RequireSecObject); + + VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags); + VWriteLine("\t\tRVA : 0x%08x", ulCodeRVA); + + flags = ulImplFlags; + sFlags[0] = 0; + ISFLAG(Mi, Native); + ISFLAG(Mi, IL); + ISFLAG(Mi, OPTIL); + ISFLAG(Mi, Runtime); + ISFLAG(Mi, Unmanaged); + ISFLAG(Mi, Managed); + ISFLAG(Mi, ForwardRef); + ISFLAG(Mi, PreserveSig); + ISFLAG(Mi, InternalCall); + ISFLAG(Mi, Synchronized); + ISFLAG(Mi, NoInlining); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\t\tImplFlags : %s (%08x)", sFlags, flags); + + if (ulSigBlob) + DisplaySignature(pbSigBlob, ulSigBlob, ""); + else + VWriteLine("\t\tERROR: no valid signature "); + + DisplayGenericParams(inMethod, "\t\t"); + +} // void MDInfo::DisplayMethodInfo() + +// displays the member information for the given field +// + +void MDInfo::DisplayFieldInfo(mdFieldDef inField, DWORD *pdwFlags) +{ + HRESULT hr; + mdTypeDef memTypeDef; + WCHAR memberName[STRING_BUFFER_LEN]; + ULONG nameLen; + DWORD flags; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + DWORD dwCPlusTypeFlag; + void const *pValue; + ULONG cbValue; + VARIANT defaultValue; + + + ::VariantInit(&defaultValue); + hr = m_pImport->GetFieldProps( inField, &memTypeDef, memberName, STRING_BUFFER_LEN, + &nameLen, &flags, &pbSigBlob, &ulSigBlob, &dwCPlusTypeFlag, + &pValue, &cbValue); + if (FAILED(hr)) Error("GetFieldProps failed.", hr); + + if (pdwFlags) + *pdwFlags = flags; + + _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue); + + char sFlags[STRING_BUFFER_LEN]; + + sFlags[0] = 0; + ISFLAG(Fd, Public); + ISFLAG(Fd, Private); + ISFLAG(Fd, Family); + ISFLAG(Fd, Assembly); + ISFLAG(Fd, FamANDAssem); + ISFLAG(Fd, FamORAssem); + ISFLAG(Fd, PrivateScope); + ISFLAG(Fd, Static); + ISFLAG(Fd, InitOnly); + ISFLAG(Fd, Literal); + ISFLAG(Fd, NotSerialized); + ISFLAG(Fd, SpecialName); + ISFLAG(Fd, RTSpecialName); + ISFLAG(Fd, PinvokeImpl); + // "Reserved" flags + ISFLAG(Fd, HasDefault); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\t\tField Name: %ls (%8.8X)", memberName, inField); + VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags); + if (IsFdHasDefault(flags)) + VWriteLine("\tDefltValue: (%s) %ls", g_szMapElementType[dwCPlusTypeFlag], VariantAsString(&defaultValue)); + if (!ulSigBlob) // Signature size should be non-zero for fields + VWriteLine("\t\tERROR: no valid signature "); + else + DisplaySignature(pbSigBlob, ulSigBlob, ""); + + ::VariantClear(&defaultValue); +} // void MDInfo::DisplayFieldInfo() + +// displays the RVA for the given global field. +void MDInfo::DisplayFieldRVA(mdFieldDef inFieldDef) +{ + HRESULT hr; + ULONG ulRVA; + + hr = m_pImport->GetRVA(inFieldDef, &ulRVA, 0); + if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetRVA failed.", hr); + + VWriteLine("\t\tRVA : 0x%08x", ulRVA); +} // void MDInfo::DisplayFieldRVA() + +// displays information about every global function. +void MDInfo::DisplayGlobalFunctions() +{ + WriteLine("Global functions"); + WriteLine("-------------------------------------------------------"); + DisplayMethods(mdTokenNil); + WriteLine(""); +} // void MDInfo::DisplayGlobalFunctions() + +// displays information about every global field. +void MDInfo::DisplayGlobalFields() +{ + WriteLine("Global fields"); + WriteLine("-------------------------------------------------------"); + DisplayFields(mdTokenNil, NULL, 0); + WriteLine(""); +} // void MDInfo::DisplayGlobalFields() + +// displays information about every global memberref. +void MDInfo::DisplayGlobalMemberRefs() +{ + WriteLine("Global MemberRefs"); + WriteLine("-------------------------------------------------------"); + DisplayMemberRefs(mdTokenNil, ""); + WriteLine(""); +} // void MDInfo::DisplayGlobalMemberRefs() + +// displays information about every method in a given typedef +// + +void MDInfo::DisplayMethods(mdTypeDef inTypeDef) +{ + HCORENUM methodEnum = NULL; + mdToken methods[ENUM_BUFFER_SIZE]; + DWORD flags; + ULONG count, totalCount = 1; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumMethods( &methodEnum, inTypeDef, + methods, NumItems(methods), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\tMethod #%d (%08x) %s", totalCount, methods[i], (methods[i] == g_tkEntryPoint) ? "[ENTRYPOINT]" : ""); + WriteLine("\t-------------------------------------------------------"); + DisplayMethodInfo(methods[i], &flags); + DisplayParams(methods[i]); + DisplayCustomAttributes(methods[i], "\t\t"); + DisplayPermissions(methods[i], "\t"); + DisplayMemberRefs(methods[i], "\t"); + + // P-invoke data if present. + if (IsMdPinvokeImpl(flags)) + DisplayPinvokeInfo(methods[i]); + + WriteLine(""); + } + } + m_pImport->CloseEnum( methodEnum); +} // void MDInfo::DisplayMethods() + + +// displays information about every field in a given typedef +// + +void MDInfo::DisplayFields(mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset) +{ + HCORENUM fieldEnum = NULL; + mdToken fields[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + DWORD flags; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumFields( &fieldEnum, inTypeDef, + fields, NumItems(fields), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\tField #%d (%08x)",totalCount, fields[i]); + WriteLine("\t-------------------------------------------------------"); + DisplayFieldInfo(fields[i], &flags); + DisplayCustomAttributes(fields[i], "\t\t"); + DisplayPermissions(fields[i], "\t"); + DisplayFieldMarshal(fields[i]); + + // RVA if its a global field. + if (inTypeDef == mdTokenNil) + DisplayFieldRVA(fields[i]); + + // P-invoke data if present. + if (IsFdPinvokeImpl(flags)) + DisplayPinvokeInfo(fields[i]); + + // Display offset if present. + if (cFieldOffset) + { + bool found = false; + for (ULONG iLayout = 0; i < cFieldOffset; ++iLayout) + { + if (RidFromToken(rFieldOffset[iLayout].ridOfField) == RidFromToken(fields[i])) + { + found = true; + VWriteLine("\t\tOffset : 0x%08x", rFieldOffset[iLayout].ulOffset); + break; + } + } + _ASSERTE(found); + } + WriteLine(""); + } + } + m_pImport->CloseEnum( fieldEnum); +} // void MDInfo::DisplayFields() + + +// displays information about every methodImpl in a given typedef +// + +void MDInfo::DisplayMethodImpls(mdTypeDef inTypeDef) +{ + HCORENUM methodImplEnum = NULL; + mdMethodDef rtkMethodBody[ENUM_BUFFER_SIZE]; + mdMethodDef rtkMethodDecl[ENUM_BUFFER_SIZE]; + + ULONG count, totalCount=1; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumMethodImpls( &methodImplEnum, inTypeDef, + rtkMethodBody, rtkMethodDecl, NumItems(rtkMethodBody), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\n\tMethodImpl #%d (%08x)", totalCount, totalCount); + WriteLine("\t-------------------------------------------------------"); + VWriteLine("\t\tMethod Body Token : 0x%08x", rtkMethodBody[i]); + VWriteLine("\t\tMethod Declaration Token : 0x%08x", rtkMethodDecl[i]); + WriteLine(""); + } + } + m_pImport->CloseEnum( methodImplEnum); +} // void MDInfo::DisplayMethodImpls() + +// displays information about the given parameter +// + +void MDInfo::DisplayParamInfo(mdParamDef inParamDef) +{ + mdMethodDef md; + ULONG num; + WCHAR paramName[STRING_BUFFER_LEN]; + ULONG nameLen; + DWORD flags; + VARIANT defValue; + DWORD dwCPlusFlags; + void const *pValue; + ULONG cbValue; + + + ::VariantInit(&defValue); + HRESULT hr = m_pImport->GetParamProps( inParamDef, &md, &num, paramName, NumItems(paramName), + &nameLen, &flags, &dwCPlusFlags, &pValue, &cbValue); + if (FAILED(hr)) Error("GetParamProps failed.", hr); + + _FillVariant((BYTE)dwCPlusFlags, pValue, cbValue, &defValue); + + char sFlags[STRING_BUFFER_LEN]; + sFlags[0] = 0; + ISFLAG(Pd, In); + ISFLAG(Pd, Out); + ISFLAG(Pd, Optional); + // "Reserved" flags. + ISFLAG(Pd, HasDefault); + ISFLAG(Pd, HasFieldMarshal); + if (!*sFlags) + strcpy_s(sFlags,STRING_BUFFER_LEN, "[none]"); + + VWrite("\t\t\t(%ld) ParamToken : (%08x) Name : %ls flags: %s (%08x)", num, inParamDef, paramName, sFlags, flags); + if (IsPdHasDefault(flags)) + VWriteLine(" Default: (%s) %ls", g_szMapElementType[dwCPlusFlags], VariantAsString(&defValue)); + else + VWriteLine(""); + DisplayCustomAttributes(inParamDef, "\t\t\t"); + + ::VariantClear(&defValue); +} // void MDInfo::DisplayParamInfo() + + +// displays all parameters for a given memberdef +// + +void MDInfo::DisplayParams(mdMethodDef inMethodDef) +{ + HCORENUM paramEnum = NULL; + mdParamDef params[ENUM_BUFFER_SIZE]; + ULONG count, paramCount; + bool first = true; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumParams( ¶mEnum, inMethodDef, + params, NumItems(params), &count)) && + count > 0) + { + if (first) + { + m_pImport->CountEnum( paramEnum, ¶mCount); + VWriteLine("\t\t%d Parameters", paramCount); + } + for (ULONG i = 0; i < count; i++) + { + DisplayParamInfo(params[i]); + DisplayFieldMarshal(params[i]); + } + first = false; + } + m_pImport->CloseEnum( paramEnum); +} // void MDInfo::DisplayParams() + +void MDInfo::DisplayGenericParams(mdToken tk, const char *prefix) +{ + HCORENUM paramEnum = NULL; + mdParamDef params[ENUM_BUFFER_SIZE]; + ULONG count, paramCount; + bool first = true; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumGenericParams( ¶mEnum, tk, + params, NumItems(params), &count)) && + count > 0) + { + if (first) + { + m_pImport->CountEnum( paramEnum, ¶mCount); + VWriteLine("%s%d Generic Parameters", prefix, paramCount); + } + for (ULONG i = 0; i < count; i++) + { + DisplayGenericParamInfo(params[i], prefix); + } + first = false; + } + m_pImport->CloseEnum( paramEnum); +} + +void MDInfo::DisplayGenericParamInfo(mdGenericParam tkParam, const char *prefix) +{ + ULONG ulSeq; + WCHAR paramName[STRING_BUFFER_LEN]; + ULONG nameLen; + DWORD flags; + mdToken tkOwner; + char newprefix[30]; + HCORENUM constraintEnum = NULL; + mdParamDef constraints[4]; + ULONG count, constraintCount; + mdToken constraint; + mdToken owner; + bool first = true; + + HRESULT hr = m_pImport->GetGenericParamProps(tkParam, &ulSeq, &flags, &tkOwner, NULL, paramName, NumItems(paramName), &nameLen); + if (FAILED(hr)) Error("GetGenericParamProps failed.", hr); + + VWriteLine("%s\t(%ld) GenericParamToken : (%08x) Name : %ls flags: %08x Owner: %08x", prefix, ulSeq, tkParam, paramName, flags, tkOwner); + + // Any constraints for the GenericParam + while (SUCCEEDED(hr = m_pImport->EnumGenericParamConstraints(&constraintEnum, tkParam, + constraints, NumItems(constraints), &count)) && + count > 0) + { + if (first) + { + m_pImport->CountEnum( constraintEnum, &constraintCount); + VWriteLine("%s\t\t%d Constraint(s)", prefix, constraintCount); + } + VWrite("%s\t\t", prefix); + for (ULONG i=0; i< count; ++i) + { + hr = m_pImport->GetGenericParamConstraintProps(constraints[i], &owner, &constraint); + if (owner != tkParam) + VWrite("%08x (owner: %08x) ", constraint, owner); + else + VWrite("%08x ", constraint); + } + VWriteLine(""); + } + m_pImport->CloseEnum(constraintEnum); + + sprintf_s(newprefix, 30, "%s\t", prefix); + DisplayCustomAttributes(tkParam, newprefix); +} + +LPCWSTR MDInfo::TokenName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + LPCUTF8 pName; // Token name in UTF8. + + if (IsNilToken(inToken)) + return L""; + + m_pImport->GetNameFromToken(inToken, &pName); + + WszMultiByteToWideChar(CP_UTF8,0, pName,-1, buffer,bufLen); + + return buffer; +} // LPCWSTR MDInfo::TokenName() + +// prints out name of typeref or typedef +// + +LPCWSTR MDInfo::TypeDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + if (RidFromToken(inToken)) + { + if (TypeFromToken(inToken) == mdtTypeDef) + return (TypeDefName((mdTypeDef) inToken, buffer, bufLen)); + else if (TypeFromToken(inToken) == mdtTypeRef) + return (TypeRefName((mdTypeRef) inToken, buffer, bufLen)); + else if (TypeFromToken(inToken) == mdtTypeSpec) + return L"[TypeSpec]"; + else + return (L"[InvalidReference]"); + } + else + return (L""); +} // LPCWSTR MDInfo::TypeDeforRefName() + +LPCWSTR MDInfo::MemberDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + if (RidFromToken(inToken)) + { + if (TypeFromToken(inToken) == mdtMethodDef || TypeFromToken(inToken) == mdtFieldDef) + return (MemberName(inToken, buffer, bufLen)); + else if (TypeFromToken(inToken) == mdtMemberRef) + return (MemberRefName((mdMemberRef) inToken, buffer, bufLen)); + else + return (L"[InvalidReference]"); + } + else + return (L""); +} // LPCWSTR MDInfo::MemberDeforRefName() + +// prints out only the name of the given typedef +// +// + +LPCWSTR MDInfo::TypeDefName(mdTypeDef inTypeDef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + HRESULT hr; + + hr = m_pImport->GetTypeDefProps( + // [IN] The import scope. + inTypeDef, // [IN] TypeDef token for inquiry. + buffer, // [OUT] Put name here. + bufLen, // [IN] size of name buffer in wide chars. + NULL, // [OUT] put size of name (wide chars) here. + NULL, // [OUT] Put flags here. + NULL); // [OUT] Put base class TypeDef/TypeRef here. + if (FAILED(hr)) + { + swprintf_s(buffer, bufLen, L"[Invalid TypeDef]"); + } + + return buffer; +} // LPCWSTR MDInfo::TypeDefName() + +// prints out all the properties of a given typedef +// + +void MDInfo::DisplayTypeDefProps(mdTypeDef inTypeDef) +{ + HRESULT hr; + WCHAR typeDefName[STRING_BUFFER_LEN]; + ULONG nameLen; + DWORD flags; + mdToken extends; + ULONG dwPacking; // Packing size of class, if specified. + ULONG dwSize; // Total size of class, if specified. + + hr = m_pImport->GetTypeDefProps( + inTypeDef, // [IN] TypeDef token for inquiry. + typeDefName, // [OUT] Put name here. + STRING_BUFFER_LEN, // [IN] size of name buffer in wide chars. + &nameLen, // [OUT] put size of name (wide chars) here. + &flags, // [OUT] Put flags here. + &extends); // [OUT] Put base class TypeDef/TypeRef here. + if (FAILED(hr)) Error("GetTypeDefProps failed.", hr); + + char sFlags[STRING_BUFFER_LEN]; + WCHAR szTempBuf[STRING_BUFFER_LEN]; + + VWriteLine("\tTypDefName: %ls (%8.8X)",typeDefName,inTypeDef); + VWriteLine("\tFlags : %s (%08x)",ClassFlags(flags, sFlags), flags); + VWriteLine("\tExtends : %8.8X [%s] %ls",extends,TokenTypeName(extends), + TypeDeforRefName(extends, szTempBuf, NumItems(szTempBuf))); + + hr = m_pImport->GetClassLayout(inTypeDef, &dwPacking, 0,0,0, &dwSize); + if (hr == S_OK) + VWriteLine("\tLayout : Packing:%d, Size:%d", dwPacking, dwSize); + + if (IsTdNested(flags)) + { + mdTypeDef tkEnclosingClass; + + hr = m_pImport->GetNestedClassProps(inTypeDef, &tkEnclosingClass); + if (hr == S_OK) + { + VWriteLine("\tEnclosingClass : %ls (%8.8X)", TypeDeforRefName(tkEnclosingClass, + szTempBuf, NumItems(szTempBuf)), tkEnclosingClass); + } + else if (hr == CLDB_E_RECORD_NOTFOUND) + WriteLine("ERROR: EnclosingClass not found for NestedClass"); + else + Error("GetNestedClassProps failed.", hr); + } +} // void MDInfo::DisplayTypeDefProps() + +// Prints out the name of the given TypeRef +// + +LPCWSTR MDInfo::TypeRefName(mdTypeRef tr, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen) +{ + HRESULT hr; + + hr = m_pImport->GetTypeRefProps( + tr, // The class ref token. + NULL, // Resolution scope. + buffer, // Put the name here. + bufLen, // Size of the name buffer, wide chars. + NULL); // Put actual size of name here. + if (FAILED(hr)) + { + swprintf_s(buffer, bufLen, L"[Invalid TypeRef]"); + } + + return (buffer); +} // LPCWSTR MDInfo::TypeRefName() + +// Prints out all the info of the given TypeRef +// + +void MDInfo::DisplayTypeRefInfo(mdTypeRef tr) +{ + HRESULT hr; + mdToken tkResolutionScope; + WCHAR typeRefName[STRING_BUFFER_LEN]; + ULONG nameLen; + + hr = m_pImport->GetTypeRefProps( + tr, // The class ref token. + &tkResolutionScope, // ResolutionScope. + typeRefName, // Put the name here. + STRING_BUFFER_LEN, // Size of the name buffer, wide chars. + &nameLen); // Put actual size of name here. + + if (FAILED(hr)) Error("GetTypeRefProps failed.", hr); + + VWriteLine("Token: 0x%08x", tr); + VWriteLine("ResolutionScope: 0x%08x", tkResolutionScope); + VWriteLine("TypeRefName: %ls",typeRefName); + + DisplayCustomAttributes(tr, "\t"); +} // void MDInfo::DisplayTypeRefInfo() + + +void MDInfo::DisplayTypeSpecInfo(mdTypeSpec ts, const char *preFix) +{ + HRESULT hr; + PCCOR_SIGNATURE pvSig; + ULONG cbSig; + ULONG cb; + + InitSigBuffer(); + + hr = m_pImport->GetTypeSpecFromToken( + ts, // The class ref token. + &pvSig, + &cbSig); + + if (FAILED(hr)) Error("GetTypeSpecFromToken failed.", hr); + +// DisplaySignature(pvSig, cbSig, preFix); + + if (FAILED(hr = GetOneElementType(pvSig, cbSig, &cb))) + goto ErrExit; + + VWriteLine("%s\tTypeSpec :%s", preFix, (LPSTR)m_sigBuf.Ptr()); + + // Hex, too? + if (m_DumpFilter & dumpMoreHex) + { + char rcNewPrefix[80]; + sprintf_s(rcNewPrefix, 80, "%s\tSignature", preFix); + DumpHex(rcNewPrefix, pvSig, cbSig, false, 24); + } +ErrExit: + return; +} // void MDInfo::DisplayTypeSpecInfo() + +void MDInfo::DisplayMethodSpecInfo(mdMethodSpec ms, const char *preFix) +{ + HRESULT hr; + PCCOR_SIGNATURE pvSig; + ULONG cbSig; + mdToken tk; + + InitSigBuffer(); + + hr = m_pImport->GetMethodSpecProps( + ms, // The MethodSpec token + &tk, // The MethodDef or MemberRef + &pvSig, // Signature. + &cbSig); // Size of signature. + + VWriteLine("%s\tParent : 0x%08x", preFix, tk); + DisplaySignature(pvSig, cbSig, preFix); +//ErrExit: + return; +} // void MDInfo::DisplayMethodSpecInfo() + +// Return the passed-in buffer filled with a string detailing the class flags +// associated with the class. +// + +char *MDInfo::ClassFlags(DWORD flags, __out_ecount(STRING_BUFFER_LEN) char *sFlags) +{ + sFlags[0] = 0; + ISFLAG(Td, NotPublic); + ISFLAG(Td, Public); + ISFLAG(Td, NestedPublic); + ISFLAG(Td, NestedPrivate); + ISFLAG(Td, NestedFamily); + ISFLAG(Td, NestedAssembly); + ISFLAG(Td, NestedFamANDAssem); + ISFLAG(Td, NestedFamORAssem); + ISFLAG(Td, AutoLayout); + ISFLAG(Td, SequentialLayout); + ISFLAG(Td, ExplicitLayout); + ISFLAG(Td, Class); + ISFLAG(Td, Interface); + ISFLAG(Td, Abstract); + ISFLAG(Td, Sealed); + ISFLAG(Td, SpecialName); + ISFLAG(Td, Import); + ISFLAG(Td, Serializable); + ISFLAG(Td, AnsiClass); + ISFLAG(Td, UnicodeClass); + ISFLAG(Td, AutoClass); + ISFLAG(Td, BeforeFieldInit); + ISFLAG(Td, Forwarder); + // "Reserved" flags + ISFLAG(Td, RTSpecialName); + ISFLAG(Td, HasSecurity); + ISFLAG(Td, WindowsRuntime); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + return sFlags; +} // char *MDInfo::ClassFlags() + +// prints out all info on the given typeDef, including all information that +// is specific to a given typedef +// + +void MDInfo::DisplayTypeDefInfo(mdTypeDef inTypeDef) +{ + DisplayTypeDefProps(inTypeDef); + + // Get field layout information. + HRESULT hr = NOERROR; + COR_FIELD_OFFSET *rFieldOffset = NULL; + ULONG cFieldOffset = 0; + hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, 0, &cFieldOffset, NULL); + if (SUCCEEDED(hr) && cFieldOffset) + { + rFieldOffset = new COR_FIELD_OFFSET[cFieldOffset]; + if (rFieldOffset == NULL) + Error("_calloc failed.", E_OUTOFMEMORY); + hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, cFieldOffset, &cFieldOffset, NULL); + if (FAILED(hr)) { delete [] rFieldOffset; Error("GetClassLayout() failed.", hr); } + } + + //No reason to display members if we're displaying fields and methods separately + DisplayGenericParams(inTypeDef, "\t"); + DisplayFields(inTypeDef, rFieldOffset, cFieldOffset); + delete [] rFieldOffset; + DisplayMethods(inTypeDef); + DisplayProperties(inTypeDef); + DisplayEvents(inTypeDef); + DisplayMethodImpls(inTypeDef); + DisplayPermissions(inTypeDef, ""); + + DisplayInterfaceImpls(inTypeDef); + DisplayCustomAttributes(inTypeDef, "\t"); +} // void MDInfo::DisplayTypeDefInfo() + +// print out information about every the given typeDef's interfaceImpls +// + +void MDInfo::DisplayInterfaceImpls(mdTypeDef inTypeDef) +{ + HCORENUM interfaceImplEnum = NULL; + mdTypeRef interfaceImpls[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + while(SUCCEEDED(hr = m_pImport->EnumInterfaceImpls( &interfaceImplEnum, + inTypeDef,interfaceImpls,NumItems(interfaceImpls), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\tInterfaceImpl #%d (%08x)", totalCount, interfaceImpls[i]); + WriteLine("\t-------------------------------------------------------"); + DisplayInterfaceImplInfo(interfaceImpls[i]); + DisplayPermissions(interfaceImpls[i], "\t"); + WriteLine(""); + } + } + m_pImport->CloseEnum( interfaceImplEnum); +} // void MDInfo::DisplayInterfaceImpls() + +// print the information for the given interface implementation +// + +void MDInfo::DisplayInterfaceImplInfo(mdInterfaceImpl inImpl) +{ + mdTypeDef typeDef; + mdToken token; + HRESULT hr; + + WCHAR szTempBuf[STRING_BUFFER_LEN]; + + hr = m_pImport->GetInterfaceImplProps( inImpl, &typeDef, &token); + if (FAILED(hr)) Error("GetInterfaceImplProps failed.", hr); + + VWriteLine("\t\tClass : %ls",TypeDeforRefName(typeDef, szTempBuf, NumItems(szTempBuf))); + VWriteLine("\t\tToken : %8.8X [%s] %ls",token,TokenTypeName(token), TypeDeforRefName(token, szTempBuf, NumItems(szTempBuf))); + + DisplayCustomAttributes(inImpl, "\t\t"); +} // void MDInfo::DisplayInterfaceImplInfo() + +// displays the information for a particular property +// + +void MDInfo::DisplayPropertyInfo(mdProperty inProp) +{ + HRESULT hr; + mdTypeDef typeDef; + WCHAR propName[STRING_BUFFER_LEN]; + DWORD flags; + VARIANT defaultValue; + void const *pValue; + ULONG cbValue; + DWORD dwCPlusTypeFlag; + mdMethodDef setter, getter, otherMethod[ENUM_BUFFER_SIZE]; + ULONG others; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + + + ::VariantInit(&defaultValue); + + hr = m_pImport->GetPropertyProps( + inProp, // [IN] property token + &typeDef, // [OUT] typedef containing the property declarion. + + propName, // [OUT] Property name + STRING_BUFFER_LEN, // [IN] the count of wchar of szProperty + NULL, // [OUT] actual count of wchar for property name + + &flags, // [OUT] property flags. + + &pbSigBlob, // [OUT] Signature Blob. + &ulSigBlob, // [OUT] Number of bytes in the signature blob. + + &dwCPlusTypeFlag, // [OUT] default value + &pValue, + &cbValue, + + &setter, // [OUT] setter method of the property + &getter, // [OUT] getter method of the property + + otherMethod, // [OUT] other methods of the property + ENUM_BUFFER_SIZE, // [IN] size of rmdOtherMethod + &others); // [OUT] total number of other method of this property + + if (FAILED(hr)) Error("GetPropertyProps failed.", hr); + + VWriteLine("\t\tProp.Name : %ls (%8.8X)",propName,inProp); + + char sFlags[STRING_BUFFER_LEN]; + + sFlags[0] = 0; + ISFLAG(Pr, SpecialName); + ISFLAG(Pr, RTSpecialName); + ISFLAG(Pr, HasDefault); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags); + + if (ulSigBlob) + DisplaySignature(pbSigBlob, ulSigBlob, ""); + else + VWriteLine("\t\tERROR: no valid signature "); + + WCHAR szTempBuf[STRING_BUFFER_LEN]; + + _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue); + VWriteLine("\t\tDefltValue: %ls",VariantAsString(&defaultValue)); + + VWriteLine("\t\tSetter : (%08x) %ls",setter,MemberDeforRefName(setter, szTempBuf, NumItems(szTempBuf))); + VWriteLine("\t\tGetter : (%08x) %ls",getter,MemberDeforRefName(getter, szTempBuf, NumItems(szTempBuf))); + + // do something with others? + VWriteLine("\t\t%ld Others",others); + DisplayCustomAttributes(inProp, "\t\t"); + + ::VariantClear(&defaultValue); +} // void MDInfo::DisplayPropertyInfo() + +// displays info for each property +// + +void MDInfo::DisplayProperties(mdTypeDef inTypeDef) +{ + HCORENUM propEnum = NULL; + mdProperty props[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + + while(SUCCEEDED(hr = m_pImport->EnumProperties( &propEnum, + inTypeDef,props,NumItems(props), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\tProperty #%d (%08x)", totalCount, props[i]); + WriteLine("\t-------------------------------------------------------"); + DisplayPropertyInfo(props[i]); + DisplayPermissions(props[i], "\t"); + WriteLine(""); + } + } + m_pImport->CloseEnum( propEnum); +} // void MDInfo::DisplayProperties() + +// Display all information about a particular event +// + +void MDInfo::DisplayEventInfo(mdEvent inEvent) +{ + HRESULT hr; + mdTypeDef typeDef; + WCHAR eventName[STRING_BUFFER_LEN]; + DWORD flags; + mdToken eventType; + mdMethodDef addOn, removeOn, fire, otherMethod[ENUM_BUFFER_SIZE]; + ULONG totalOther; + + + hr = m_pImport->GetEventProps( + // [IN] The scope. + inEvent, // [IN] event token + &typeDef, // [OUT] typedef containing the event declarion. + + eventName, // [OUT] Event name + STRING_BUFFER_LEN, // [IN] the count of wchar of szEvent + NULL, // [OUT] actual count of wchar for event's name + + &flags, // [OUT] Event flags. + &eventType, // [OUT] EventType class + + &addOn, // [OUT] AddOn method of the event + &removeOn, // [OUT] RemoveOn method of the event + &fire, // [OUT] Fire method of the event + + otherMethod, // [OUT] other method of the event + NumItems(otherMethod), // [IN] size of rmdOtherMethod + &totalOther); // [OUT] total number of other method of this event + if (FAILED(hr)) Error("GetEventProps failed.", hr); + + VWriteLine("\t\tName : %ls (%8.8X)",eventName,inEvent); + + char sFlags[STRING_BUFFER_LEN]; + + sFlags[0] = 0; + ISFLAG(Ev, SpecialName); + ISFLAG(Ev, RTSpecialName); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags); + + WCHAR szTempBuf[STRING_BUFFER_LEN]; + + VWriteLine("\t\tEventType : %8.8X [%s]",eventType,TokenTypeName(eventType)); + VWriteLine("\t\tAddOnMethd: (%08x) %ls",addOn,MemberDeforRefName(addOn, szTempBuf, NumItems(szTempBuf))); + VWriteLine("\t\tRmvOnMethd: (%08x) %ls",removeOn,MemberDeforRefName(removeOn, szTempBuf, NumItems(szTempBuf))); + VWriteLine("\t\tFireMethod: (%08x) %ls",fire,MemberDeforRefName(fire, szTempBuf, NumItems(szTempBuf))); + + VWriteLine("\t\t%ld OtherMethods",totalOther); + + DisplayCustomAttributes(inEvent, "\t\t"); +} // void MDInfo::DisplayEventInfo() + +// Display information about all events in a typedef +// +void MDInfo::DisplayEvents(mdTypeDef inTypeDef) +{ + HCORENUM eventEnum = NULL; + mdProperty events[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + + while(SUCCEEDED(hr = m_pImport->EnumEvents( &eventEnum, + inTypeDef,events,NumItems(events), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("\tEvent #%d (%08x)", totalCount, events[i]); + WriteLine("\t-------------------------------------------------------"); + DisplayEventInfo(events[i]); + DisplayPermissions(events[i], "\t"); + WriteLine(""); + } + } + m_pImport->CloseEnum( eventEnum); +} // void MDInfo::DisplayEvents() + + +// print info for the passed-in custom attribute +// This function is used to print the custom attribute information for both TypeDefs and +// MethodDefs which need slightly different formatting. preFix helps fix it up. +// + +void MDInfo::DisplayCustomAttributeInfo(mdCustomAttribute inValue, const char *preFix) +{ + const BYTE *pValue; // The custom value. + ULONG cbValue; // Length of the custom value. + HRESULT hr; // A result. + mdToken tkObj; // Attributed object. + mdToken tkType; // Type of the custom attribute. + mdToken tk; // For name lookup. + LPCUTF8 pMethName=0; // Name of custom attribute ctor, if any. + CQuickBytes qSigName; // Buffer to pretty-print signature. + PCCOR_SIGNATURE pSig=0; // Signature of ctor. + ULONG cbSig; // Size of the signature. + BOOL bCoffSymbol = false; // true for coff symbol CA's. + WCHAR rcName[MAX_CLASS_NAME]; // Name of the type. + + hr = m_pImport->GetCustomAttributeProps( // S_OK or error. + inValue, // The attribute. + &tkObj, // The attributed object + &tkType, // The attributes type. + (const void**)&pValue, // Put pointer to data here. + &cbValue); // Put size here. + if (FAILED(hr)) Error("GetCustomAttributeProps failed.", hr); + + VWriteLine("%s\tCustomAttribute Type: %08x", preFix, tkType); + + // Get the name of the memberref or methoddef. + tk = tkType; + rcName[0] = L'\0'; + // Get the member name, and the parent token. + switch (TypeFromToken(tk)) + { + case mdtMemberRef: + hr = m_pImport->GetNameFromToken(tk, &pMethName); + if (FAILED(hr)) Error("GetNameFromToken failed.", hr); + hr = m_pImport->GetMemberRefProps( tk, &tk, 0, 0, 0, &pSig, &cbSig); + if (FAILED(hr)) Error("GetMemberRefProps failed.", hr); + break; + case mdtMethodDef: + hr = m_pImport->GetNameFromToken(tk, &pMethName); + if (FAILED(hr)) Error("GetNameFromToken failed.", hr); + hr = m_pImport->GetMethodProps(tk, &tk, 0, 0, 0, 0, &pSig, &cbSig, 0, 0); + if (FAILED(hr)) Error("GetMethodProps failed.", hr); + break; + } // switch + + // Get the type name. + switch (TypeFromToken(tk)) + { + case mdtTypeDef: + hr = m_pImport->GetTypeDefProps(tk, rcName,MAX_CLASS_NAME,0, 0,0); + if (FAILED(hr)) Error("GetTypeDefProps failed.", hr); + break; + case mdtTypeRef: + hr = m_pImport->GetTypeRefProps(tk, 0, rcName,MAX_CLASS_NAME,0); + if (FAILED(hr)) Error("GetTypeRefProps failed.", hr); + break; + } // switch + + + if (pSig && pMethName) + { + int iLen; + LPWSTR pwzName = (LPWSTR)(new WCHAR[iLen= 1+(ULONG32)strlen(pMethName)]); + if(pwzName) + { + WszMultiByteToWideChar(CP_UTF8,0, pMethName,-1, pwzName,iLen); + PrettyPrintSigLegacy(pSig, cbSig, pwzName, &qSigName, m_pImport); + delete [] pwzName; + } + } + + VWrite("%s\tCustomAttributeName: %ls", preFix, rcName); + if (pSig && pMethName) + VWrite(" :: %S", qSigName.Ptr()); + + // Keep track of coff overhead. + if (!wcscmp(L"__DecoratedName", rcName)) + { + bCoffSymbol = true; + g_cbCoffNames += cbValue + 6; + } + WriteLine(""); + + VWriteLine("%s\tLength: %ld", preFix, cbValue); + char newPreFix[40]; + sprintf_s(newPreFix, 40, "%s\tValue ", preFix); + DumpHex(newPreFix, pValue, cbValue); + if (bCoffSymbol) + VWriteLine("%s\t %s", preFix, pValue); + + // Try to decode the constructor blob. This is incomplete, but covers the most popular cases. + if (pSig) + { // Interpret the signature. + PCCOR_SIGNATURE ps = pSig; + ULONG cb; + ULONG ulData; + ULONG cParams; + ULONG ulVal; + UINT8 u1 = 0; + UINT16 u2 = 0; + UINT32 u4 = 0; + UINT64 u8 = 0; + unsigned __int64 uI64; + double dblVal; + ULONG cbVal; + LPCUTF8 pStr; + CustomAttributeParser CA(pValue, cbValue); + CA.ValidateProlog(); + + // Get the calling convention. + cb = CorSigUncompressData(ps, &ulData); + ps += cb; + // Get the count of params. + cb = CorSigUncompressData(ps, &cParams); + ps += cb; + // Get the return value. + cb = CorSigUncompressData(ps, &ulData); + ps += cb; + if (ulData == ELEMENT_TYPE_VOID) + { + VWrite("%s\tctor args: (", preFix); + // For each param... + for (ULONG i=0; i<cParams; ++i) + { // Get the next param type. + cb = CorSigUncompressData(ps, &ulData); + ps += cb; + if (i) Write(", "); + DoObject: + switch (ulData) + { + // For ET_OBJECT, the next byte in the blob is the ET of the actual data. + case ELEMENT_TYPE_OBJECT: + CA.GetU1(&u1); + ulData = u1; + goto DoObject; + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + CA.GetU1(&u1); + ulVal = u1; + goto PrintVal; + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + CA.GetU2(&u2); + ulVal = u2; + goto PrintVal; + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + CA.GetU4(&u4); + ulVal = u4; + PrintVal: + VWrite("%d", ulVal); + break; + case ELEMENT_TYPE_STRING: + CA.GetString(&pStr, &cbVal); + VWrite("\"%s\"", pStr); + break; + // The only class type that we accept is Type, which is stored as a string. + case ELEMENT_TYPE_CLASS: + // Eat the class type. + cb = CorSigUncompressData(ps, &ulData); + ps += cb; + // Get the name of the type. + CA.GetString(&pStr, &cbVal); + VWrite("typeof(%s)", pStr); + break; + case SERIALIZATION_TYPE_TYPE: + CA.GetString(&pStr, &cbVal); + VWrite("typeof(%s)", pStr); + break; + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + CA.GetU8(&u8); + uI64 = u8; + VWrite("%#lx", uI64); + break; + case ELEMENT_TYPE_R4: + dblVal = CA.GetR4(); + VWrite("%f", dblVal); + break; + case ELEMENT_TYPE_R8: + dblVal = CA.GetR8(); + VWrite("%f", dblVal); + break; + default: + // bail... + i = cParams; + Write(" <can not decode> "); + break; + } + } + WriteLine(")"); + } + + } + WriteLine(""); +} // void MDInfo::DisplayCustomAttributeInfo() + +// Print all custom values for the given token +// This function is used to print the custom value information for all tokens. +// which need slightly different formatting. preFix helps fix it up. +// + +void MDInfo::DisplayCustomAttributes(mdToken inToken, const char *preFix) +{ + HCORENUM customAttributeEnum = NULL; + mdTypeRef customAttributes[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + while(SUCCEEDED(hr = m_pImport->EnumCustomAttributes( &customAttributeEnum, inToken, 0, + customAttributes, NumItems(customAttributes), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("%sCustomAttribute #%d (%08x)", preFix, totalCount, customAttributes[i]); + VWriteLine("%s-------------------------------------------------------", preFix); + DisplayCustomAttributeInfo(customAttributes[i], preFix); + } + } + m_pImport->CloseEnum( customAttributeEnum); +} // void MDInfo::DisplayCustomAttributes() + +// Show the passed-in token's permissions +// +// + +void MDInfo::DisplayPermissions(mdToken tk, const char *preFix) +{ + HCORENUM permissionEnum = NULL; + mdPermission permissions[ENUM_BUFFER_SIZE]; + ULONG count, totalCount = 1; + HRESULT hr; + + + while (SUCCEEDED(hr = m_pImport->EnumPermissionSets( &permissionEnum, + tk, 0, permissions, NumItems(permissions), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("%s\tPermission #%d (%08x)", preFix, totalCount, permissions[i]); + VWriteLine("%s\t-------------------------------------------------------", preFix); + DisplayPermissionInfo(permissions[i], preFix); + WriteLine(""); + } + } + m_pImport->CloseEnum( permissionEnum); +} // void MDInfo::DisplayPermissions() + +// print properties of given rolecheck +// +// + +void MDInfo::DisplayPermissionInfo(mdPermission inPermission, const char *preFix) +{ + DWORD dwAction; + const BYTE *pvPermission; + ULONG cbPermission; + char *flagDesc = NULL; + char newPreFix[STRING_BUFFER_LEN]; + HRESULT hr; + + + hr = m_pImport->GetPermissionSetProps( inPermission, &dwAction, + (const void**)&pvPermission, &cbPermission); + if (FAILED(hr)) Error("GetPermissionSetProps failed.", hr); + + switch(dwAction) + { + case dclActionNil: flagDesc = "ActionNil"; break; + case dclRequest: flagDesc = "Request"; break; + case dclDemand: flagDesc = "Demand"; break; + case dclAssert: flagDesc = "Assert"; break; + case dclDeny: flagDesc = "Deny"; break; + case dclPermitOnly: flagDesc = "PermitOnly"; break; + case dclLinktimeCheck: flagDesc = "LinktimeCheck"; break; + case dclInheritanceCheck: flagDesc = "InheritanceCheck"; break; + case dclRequestMinimum: flagDesc = "RequestMinimum"; break; + case dclRequestOptional: flagDesc = "RequestOptional"; break; + case dclRequestRefuse: flagDesc = "RequestRefuse"; break; + case dclPrejitGrant: flagDesc = "PrejitGrant"; break; + case dclPrejitDenied: flagDesc = "PrejitDenied"; break; + case dclNonCasDemand: flagDesc = "NonCasDemand"; break; + case dclNonCasLinkDemand: flagDesc = "NonCasLinkDemand"; break; + case dclNonCasInheritance: flagDesc = "NonCasInheritance"; break; + + } + VWriteLine("%s\t\tAction : %s", preFix, flagDesc); + VWriteLine("%s\t\tBlobLen : %d", preFix, cbPermission); + if (cbPermission) + { + sprintf_s(newPreFix, STRING_BUFFER_LEN, "%s\tBlob", preFix); + DumpHex(newPreFix, pvPermission, cbPermission, false, 24); + } + + sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix); + DisplayCustomAttributes(inPermission, newPreFix); +} // void MDInfo::DisplayPermissionInfo() + + +// simply prints out the given GUID in standard form + +LPWSTR MDInfo::GUIDAsString(GUID inGuid, __out_ecount(bufLen) LPWSTR guidString, ULONG bufLen) +{ + StringFromGUID2(inGuid, guidString, bufLen); + return guidString; +} // LPWSTR MDInfo::GUIDAsString() + +LPWSTR MDInfo::VariantAsString(VARIANT *pVariant) +{ + HRESULT hr = S_OK; + if (V_VT(pVariant) == VT_UNKNOWN) + { + _ASSERTE(V_UNKNOWN(pVariant) == NULL); + return (L"<NULL>"); + } + else if (SUCCEEDED(hr = ::VariantChangeType(pVariant, pVariant, 0, VT_BSTR))) + return V_BSTR(pVariant); + else if (hr == DISP_E_BADVARTYPE && V_VT(pVariant) == VT_I8) + { + // allocate the bstr. + char szStr[32]; + WCHAR wszStr[32]; + // Set variant type to bstr. + V_VT(pVariant) = VT_BSTR; + // Create the ansi string. + sprintf_s(szStr, 32, "%I64d", V_CY(pVariant).int64); + // Convert to unicode. + WszMultiByteToWideChar(CP_ACP, 0, szStr, -1, wszStr, 32); + // convert to bstr and set variant value. + V_BSTR(pVariant) = ::SysAllocString(wszStr); + if (V_BSTR(pVariant) == NULL) + Error("SysAllocString() failed.", E_OUTOFMEMORY); + return V_BSTR(pVariant); + } + else + return (L"ERROR"); + +} // LPWSTR MDInfo::VariantAsString() + +bool TrySigUncompress(PCCOR_SIGNATURE pData, // [IN] compressed data + ULONG *pDataOut, // [OUT] the expanded *pData + ULONG *cbCur) +{ + ULONG ulSize = CorSigUncompressData(pData, pDataOut); + if (ulSize == (ULONG)-1) + { + *cbCur = ulSize; + return false; + } else + { + *cbCur += ulSize; + return true; + } +} + +void MDInfo::DisplayFieldMarshal(mdToken inToken) +{ + PCCOR_SIGNATURE pvNativeType; // [OUT] native type of this field + ULONG cbNativeType; // [OUT] the count of bytes of *ppvNativeType + HRESULT hr; + + + hr = m_pImport->GetFieldMarshal( inToken, &pvNativeType, &cbNativeType); + if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetFieldMarshal failed.", hr); + if (hr != CLDB_E_RECORD_NOTFOUND) + { + ULONG cbCur = 0; + ULONG ulData; + ULONG ulStrLoc; + + char szNTDesc[STRING_BUFFER_LEN]; + + while (cbCur < cbNativeType) + { + ulStrLoc = 0; + + ulData = NATIVE_TYPE_MAX; + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + if (ulData >= sizeof(g_szNativeType)/sizeof(*g_szNativeType)) + { + cbCur = (ULONG)-1; + continue; + } + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "%s ", g_szNativeType[ulData]); + switch (ulData) + { + case NATIVE_TYPE_FIXEDSYSSTRING: + { + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{StringElementCount: %d} ",ulData); + } + } + break; + case NATIVE_TYPE_FIXEDARRAY: + { + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementCount: %d",ulData); + + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", ArrayElementType(NT): %d",ulData); + } + + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc,"}"); + } + } + break; + case NATIVE_TYPE_ARRAY: + { + if (cbCur < cbNativeType) + { + BOOL bElemTypeSpecified; + + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + if (ulData != NATIVE_TYPE_MAX) + { + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementType(NT): %d", ulData); + bElemTypeSpecified = TRUE; + } + else + { + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{"); + bElemTypeSpecified = FALSE; + } + + if (cbCur < cbNativeType) + { + if (bElemTypeSpecified) + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", "); + + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "SizeParamIndex: %d",ulData); + + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeParamMultiplier: %d",ulData); + + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeConst: %d",ulData); + } + } + } + + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}"); + } + } + break; + case NATIVE_TYPE_SAFEARRAY: + { + if (cbCur < cbNativeType) + { + if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur)) + continue; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{SafeArraySubType(VT): %d, ",ulData); + + // Extract the element type name if it is specified. + if (cbCur < cbNativeType) + { + LPUTF8 strTemp = NULL; + int strLen = 0; + int ByteCountLength = 0; + + strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength); + cbCur += ByteCountLength; + strTemp = (LPUTF8)(new char[strLen + 1]); + if(strTemp) + { + memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen); + strTemp[strLen] = 0; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: %s}", strTemp); + cbCur += strLen; + _ASSERTE(cbCur == cbNativeType); + delete [] strTemp; + } + } + else + { + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: }"); + } + } + } + break; + case NATIVE_TYPE_CUSTOMMARSHALER: + { + LPUTF8 strTemp = NULL; + int strLen = 0; + int ByteCountLength = 0; + + // Extract the typelib GUID. + strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength); + cbCur += ByteCountLength; + strTemp = (LPUTF8)(new char[strLen + 1]); + if(strTemp) + { + memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen); + strTemp[strLen] = 0; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{Typelib: %s, ", strTemp); + cbCur += strLen; + _ASSERTE(cbCur < cbNativeType); + delete [] strTemp; + } + // Extract the name of the native type. + strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength); + cbCur += ByteCountLength; + strTemp = (LPUTF8)(new char[strLen + 1]); + if(strTemp) + { + memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen); + strTemp[strLen] = 0; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Native: %s, ", strTemp); + cbCur += strLen; + _ASSERTE(cbCur < cbNativeType); + delete [] strTemp; + } + + // Extract the name of the custom marshaler. + strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength); + cbCur += ByteCountLength; + strTemp = (LPUTF8)(new char[strLen + 1]); + if(strTemp) + { + memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen); + strTemp[strLen] = 0; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Marshaler: %s, ", strTemp); + cbCur += strLen; + _ASSERTE(cbCur < cbNativeType); + delete [] strTemp; + } + // Extract the cookie string. + strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength); + cbCur += ByteCountLength; + if (strLen > 0) + { + strTemp = (LPUTF8)(new char[strLen + 1]); + if(strTemp) + { + memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen); + strTemp[strLen] = 0; + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: "); + + // Copy the cookie string and transform the embedded nulls into \0's. + for (int i = 0; i < strLen - 1; i++, cbCur++) + { + if (strTemp[i] == 0) + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "\\0"); + else + szNTDesc[ulStrLoc++] = strTemp[i]; + } + szNTDesc[ulStrLoc++] = strTemp[strLen - 1]; + cbCur++; + delete [] strTemp; + } + } + else + { + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: "); + } + + // Finish the custom marshaler native type description. + ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}"); + _ASSERTE(cbCur <= cbNativeType); + } + break; + default: + { + // normal nativetype element: do nothing + } + } + VWriteLine("\t\t\t\t%s",szNTDesc); + if (ulData >= NATIVE_TYPE_MAX) + break; + } + if (cbCur == (ULONG)-1) + { + // There was something that we didn't grok in the signature. + // Just dump out the blob as hex + VWrite("\t\t\t\t{", szNTDesc); + while (cbNativeType--) + VWrite(" %2.2X", *pvNativeType++); + VWriteLine(" }"); + } + } +} // void MDInfo::DisplayFieldMarshal() + +void MDInfo::DisplayPinvokeInfo(mdToken inToken) +{ + HRESULT hr = NOERROR; + DWORD flags; + WCHAR rcImport[512]; + mdModuleRef tkModuleRef; + + char sFlags[STRING_BUFFER_LEN]; + + hr = m_pImport->GetPinvokeMap(inToken, &flags, rcImport, + NumItems(rcImport), 0, &tkModuleRef); + if (FAILED(hr)) + { + if (hr != CLDB_E_RECORD_NOTFOUND) + VWriteLine("ERROR: GetPinvokeMap failed.", hr); + return; + } + + WriteLine("\t\tPinvoke Map Data:"); + VWriteLine("\t\tEntry point: %S", rcImport); + VWriteLine("\t\tModule ref: %08x", tkModuleRef); + + sFlags[0] = 0; + ISFLAG(Pm, NoMangle); + ISFLAG(Pm, CharSetNotSpec); + ISFLAG(Pm, CharSetAnsi); + ISFLAG(Pm, CharSetUnicode); + ISFLAG(Pm, CharSetAuto); + ISFLAG(Pm, SupportsLastError); + ISFLAG(Pm, CallConvWinapi); + ISFLAG(Pm, CallConvCdecl); + ISFLAG(Pm, CallConvStdcall); + ISFLAG(Pm, CallConvThiscall); + ISFLAG(Pm, CallConvFastcall); + + ISFLAG(Pm, BestFitEnabled); + ISFLAG(Pm, BestFitDisabled); + ISFLAG(Pm, BestFitUseAssem); + ISFLAG(Pm, ThrowOnUnmappableCharEnabled); + ISFLAG(Pm, ThrowOnUnmappableCharDisabled); + ISFLAG(Pm, ThrowOnUnmappableCharUseAssem); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\t\tMapping flags: %s (%08x)", sFlags, flags); +} // void MDInfo::DisplayPinvokeInfo() + + +///////////////////////////////////////////////////////////////////////// +// void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob); +// +// Display COM+ signature -- taken from cordump.cpp's DumpSignature +///////////////////////////////////////////////////////////////////////// +void MDInfo::DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix) +{ + ULONG cbCur = 0; + ULONG cb; + // 428793: Prefix complained correctly about unitialized data. + ULONG ulData = (ULONG) IMAGE_CEE_CS_CALLCONV_MAX; + ULONG ulArgs; + HRESULT hr = NOERROR; + ULONG ulSigBlobStart = ulSigBlob; + + // initialize sigBuf + InitSigBuffer(); + + cb = CorSigUncompressData(pbSigBlob, &ulData); + VWriteLine("%s\t\tCallCnvntn: %s", preFix, (g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK])); + if (cb>ulSigBlob) + goto ErrExit; + cbCur += cb; + ulSigBlob -= cb; + + if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS) + VWriteLine("%s\t\thasThis ", preFix); + if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) + VWriteLine("%s\t\texplicit ", preFix); + if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC) + VWriteLine("%s\t\tgeneric ", preFix); + + // initialize sigBuf + InitSigBuffer(); + if ( isCallConv(ulData,IMAGE_CEE_CS_CALLCONV_FIELD) ) + { + + // display field type + if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) + goto ErrExit; + VWriteLine("%s\t\tField type: %s", preFix, (LPSTR)m_sigBuf.Ptr()); + if (cb>ulSigBlob) + goto ErrExit; + cbCur += cb; + ulSigBlob -= cb; + } + else + { + if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + ULONG ulTyArgs; + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTyArgs); + if (cb>ulSigBlob) + goto ErrExit; + cbCur += cb; + ulSigBlob -= cb; + VWriteLine("%s\t\tType Arity:%d ", preFix, ulTyArgs); + } + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulArgs); + if (cb>ulSigBlob) + goto ErrExit; + cbCur += cb; + ulSigBlob -= cb; + + if (ulData != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG && ulData != IMAGE_CEE_CS_CALLCONV_GENERICINST) + { + // display return type when it is not a local varsig + if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) + goto ErrExit; + VWriteLine("%s\t\tReturnType:%s", preFix, (LPSTR)m_sigBuf.Ptr()); + if (cb>ulSigBlob) + goto ErrExit; + cbCur += cb; + ulSigBlob -= cb; + } + + // display count of argument + // display arguments + if (ulSigBlob) + VWriteLine("%s\t\t%ld Arguments", preFix, ulArgs); + else + VWriteLine("%s\t\tNo arguments.", preFix); + + ULONG i = 0; + while (i < ulArgs && ulSigBlob > 0) + { + ULONG ulDataTemp; + + // Handle the sentinal for varargs because it isn't counted in the args. + CorSigUncompressData(&pbSigBlob[cbCur], &ulDataTemp); + ++i; + + // initialize sigBuf + InitSigBuffer(); + + if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) + goto ErrExit; + + VWriteLine("%s\t\t\tArgument #%ld: %s",preFix, i, (LPSTR)m_sigBuf.Ptr()); + + if (cb>ulSigBlob) + goto ErrExit; + + cbCur += cb; + ulSigBlob -= cb; + } + } + + // Nothing consumed but not yet counted. + cb = 0; + +ErrExit: + // We should have consumed all signature blob. If not, dump the sig in hex. + // Also dump in hex if so requested. + if (m_DumpFilter & dumpMoreHex || ulSigBlob != 0) + { + // Did we not consume enough, or try to consume too much? + if (cb > ulSigBlob) + WriteLine("\tERROR IN SIGNATURE: Signature should be larger."); + else + if (cb < ulSigBlob) + { + VWrite("\tERROR IN SIGNATURE: Not all of signature blob was consumed. %d byte(s) remain", ulSigBlob); + // If it is short, just append it to the end. + if (ulSigBlob < 4) + { + Write(": "); + for (; ulSigBlob; ++cbCur, --ulSigBlob) + VWrite("%02x ", pbSigBlob[cbCur]); + WriteLine(""); + goto ErrExit2; + } + WriteLine(""); + } + + // Any appropriate error message has been issued. Dump sig in hex, as determined + // by error or command line switch. + cbCur = 0; + ulSigBlob = ulSigBlobStart; + char rcNewPrefix[80]; + sprintf_s(rcNewPrefix, 80, "%s\t\tSignature ", preFix); + DumpHex(rcNewPrefix, pbSigBlob, ulSigBlob, false, 24); + } +ErrExit2: + if (FAILED(hr)) + Error("ERROR!! Bad signature blob value!"); + return; +} // void MDInfo::DisplaySignature() + + +///////////////////////////////////////////////////////////////////////// +// HRESULT GetOneElementType(mdScope tkScope, BYTE *pbSigBlob, ULONG ulSigBlob, ULONG *pcb) +// +// Adds description of element type to the end of buffer -- caller must ensure +// buffer is large enough. +///////////////////////////////////////////////////////////////////////// +HRESULT MDInfo::GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb) +{ + HRESULT hr = S_OK; // A result. + ULONG cbCur = 0; + ULONG cb; + ULONG ulData = ELEMENT_TYPE_MAX; + ULONG ulTemp; + int iTemp = 0; + mdToken tk; + + cb = CorSigUncompressData(pbSigBlob, &ulData); + cbCur += cb; + + // Handle the modifiers. + if (ulData & ELEMENT_TYPE_MODIFIER) + { + if (ulData == ELEMENT_TYPE_SENTINEL) + IfFailGo(AddToSigBuffer("<ELEMENT_TYPE_SENTINEL>")); + else if (ulData == ELEMENT_TYPE_PINNED) + IfFailGo(AddToSigBuffer("PINNED")); + else + { + hr = E_FAIL; + goto ErrExit; + } + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + goto ErrExit; + } + + // Handle the underlying element types. + if (ulData >= ELEMENT_TYPE_MAX) + { + hr = E_FAIL; + goto ErrExit; + } + while (ulData == ELEMENT_TYPE_PTR || ulData == ELEMENT_TYPE_BYREF) + { + IfFailGo(AddToSigBuffer(" ")); + IfFailGo(AddToSigBuffer(g_szMapElementType[ulData])); + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); + cbCur += cb; + } + IfFailGo(AddToSigBuffer(" ")); + IfFailGo(AddToSigBuffer(g_szMapElementType[ulData])); + if (CorIsPrimitiveType((CorElementType)ulData) || + ulData == ELEMENT_TYPE_TYPEDBYREF || + ulData == ELEMENT_TYPE_OBJECT || + ulData == ELEMENT_TYPE_I || + ulData == ELEMENT_TYPE_U) + { + // If this is a primitive type, we are done + goto ErrExit; + } + if (ulData == ELEMENT_TYPE_VALUETYPE || + ulData == ELEMENT_TYPE_CLASS || + ulData == ELEMENT_TYPE_CMOD_REQD || + ulData == ELEMENT_TYPE_CMOD_OPT) + { + cb = CorSigUncompressToken(&pbSigBlob[cbCur], &tk); + cbCur += cb; + + // get the name of type ref. Don't care if truncated + if (TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtTypeRef) + { + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %ls",TypeDeforRefName(tk, m_szTempBuf, NumItems(m_szTempBuf))); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + } + else + { + _ASSERTE(TypeFromToken(tk) == mdtTypeSpec); + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %8x", tk); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + } + if (ulData == ELEMENT_TYPE_CMOD_REQD || + ulData == ELEMENT_TYPE_CMOD_OPT) + { + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + } + + goto ErrExit; + } + if (ulData == ELEMENT_TYPE_SZARRAY) + { + // display the base type of SZARRAY + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + goto ErrExit; + } + // instantiated type + if (ulData == ELEMENT_TYPE_GENERICINST) + { + // display the type constructor + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + ULONG numArgs; + cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs); + cbCur += cb; + IfFailGo(AddToSigBuffer("<")); + + while (numArgs > 0) + { + if (cbCur > ulSigBlob) + goto ErrExit; + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + --numArgs; + if (numArgs > 0) + IfFailGo(AddToSigBuffer(",")); + } + IfFailGo(AddToSigBuffer(">")); + goto ErrExit; + } + if (ulData == ELEMENT_TYPE_VAR) + { + ULONG index; + cb = CorSigUncompressData(&pbSigBlob[cbCur], &index); + cbCur += cb; + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!%d", index); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + goto ErrExit; + } + if (ulData == ELEMENT_TYPE_MVAR) + { + ULONG index; + cb = CorSigUncompressData(&pbSigBlob[cbCur], &index); + cbCur += cb; + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!!%d", index); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + goto ErrExit; + } + if (ulData == ELEMENT_TYPE_FNPTR) + { + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); + cbCur += cb; + if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) + IfFailGo(AddToSigBuffer(" explicit")); + if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS) + IfFailGo(AddToSigBuffer(" hasThis")); + + IfFailGo(AddToSigBuffer(" ")); + IfFailGo(AddToSigBuffer(g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK])); + + // Get number of args + ULONG numArgs; + cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs); + cbCur += cb; + + // do return type + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + + IfFailGo(AddToSigBuffer("(")); + while (numArgs > 0) + { + if (cbCur > ulSigBlob) + goto ErrExit; + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + --numArgs; + if (numArgs > 0) + IfFailGo(AddToSigBuffer(",")); + } + IfFailGo(AddToSigBuffer(" )")); + goto ErrExit; + } + + if(ulData != ELEMENT_TYPE_ARRAY) return E_FAIL; + + // display the base type of SDARRAY + if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) + goto ErrExit; + cbCur += cb; + + // display the rank of MDARRAY + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); + cbCur += cb; + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + if (ulData == 0) + // we are done if no rank specified + goto ErrExit; + + // how many dimensions have size specified? + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); + cbCur += cb; + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + while (ulData) + { + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTemp); + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulTemp); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + cbCur += cb; + ulData--; + } + // how many dimensions have lower bounds specified? + cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); + cbCur += cb; + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + while (ulData) + { + + cb = CorSigUncompressSignedInt(&pbSigBlob[cbCur], &iTemp); + sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", iTemp); + IfFailGo(AddToSigBuffer(m_tempFormatBuffer)); + cbCur += cb; + ulData--; + } + +ErrExit: + if (cbCur > ulSigBlob) + hr = E_FAIL; + *pcb = cbCur; + return hr; +} // HRESULT MDInfo::GetOneElementType() + +// Display the fields of the N/Direct custom value structure. + +void MDInfo::DisplayCorNativeLink(COR_NATIVE_LINK *pCorNLnk, const char *preFix) +{ + // Print the LinkType. + char *curField = "\tLink Type : "; + switch(pCorNLnk->m_linkType) + { + case nltNone: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nltNone", pCorNLnk->m_linkType); + break; + case nltAnsi: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAnsi", pCorNLnk->m_linkType); + break; + case nltUnicode: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nltUnicode", pCorNLnk->m_linkType); + break; + case nltAuto: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAuto", pCorNLnk->m_linkType); + break; + default: + _ASSERTE(!"Invalid Native Link Type!"); + } + + // Print the link flags + curField = "\tLink Flags : "; + switch(pCorNLnk->m_flags) + { + case nlfNone: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfNone", pCorNLnk->m_flags); + break; + case nlfLastError: + VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfLastError", pCorNLnk->m_flags); + break; + default: + _ASSERTE(!"Invalid Native Link Flags!"); + } + + // Print the entry point. + WCHAR memRefName[STRING_BUFFER_LEN]; + HRESULT hr; + hr = m_pImport->GetMemberRefProps( pCorNLnk->m_entryPoint, NULL, memRefName, + STRING_BUFFER_LEN, NULL, NULL, NULL); + if (FAILED(hr)) Error("GetMemberRefProps failed.", hr); + VWriteLine("%s\tEntry Point : %ls (0x%08x)", preFix, memRefName, pCorNLnk->m_entryPoint); +} // void MDInfo::DisplayCorNativeLink() + +// Fills given varaint with value given in pValue and of type in bCPlusTypeFlag +// +// Taken from MetaInternal.cpp + +HRESULT _FillVariant( + BYTE bCPlusTypeFlag, + const void *pValue, + ULONG cbValue, + VARIANT *pvar) +{ + HRESULT hr = NOERROR; + switch (bCPlusTypeFlag) + { + case ELEMENT_TYPE_BOOLEAN: + V_VT(pvar) = VT_BOOL; + V_BOOL(pvar) = *((BYTE*)pValue); //*((UNALIGNED VARIANT_BOOL *)pValue); + break; + case ELEMENT_TYPE_I1: + V_VT(pvar) = VT_I1; + V_I1(pvar) = *((CHAR*)pValue); + break; + case ELEMENT_TYPE_U1: + V_VT(pvar) = VT_UI1; + V_UI1(pvar) = *((BYTE*)pValue); + break; + case ELEMENT_TYPE_I2: + V_VT(pvar) = VT_I2; + V_I2(pvar) = GET_UNALIGNED_VAL16(pValue); + break; + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_CHAR: + V_VT(pvar) = VT_UI2; + V_UI2(pvar) = GET_UNALIGNED_VAL16(pValue); + break; + case ELEMENT_TYPE_I4: + V_VT(pvar) = VT_I4; + V_I4(pvar) = GET_UNALIGNED_VAL32(pValue); + break; + case ELEMENT_TYPE_U4: + V_VT(pvar) = VT_UI4; + V_UI4(pvar) = GET_UNALIGNED_VAL32(pValue); + break; + case ELEMENT_TYPE_R4: + { + V_VT(pvar) = VT_R4; + __int32 Value = GET_UNALIGNED_VAL32(pValue); + V_R4(pvar) = (float &)Value; + } + break; + case ELEMENT_TYPE_R8: + { + V_VT(pvar) = VT_R8; + __int64 Value = GET_UNALIGNED_VAL64(pValue); + V_R8(pvar) = (double &) Value; + } + + break; + case ELEMENT_TYPE_STRING: + { + V_VT(pvar) = VT_BSTR; + WCHAR *TempString;; +#if BIGENDIAN + TempString = (WCHAR *)alloca(cbValue); + memcpy(TempString, pValue, cbValue); + SwapStringLength(TempString, cbValue/sizeof(WCHAR)); +#else + TempString = (WCHAR *)pValue; +#endif + // allocated bstr here + V_BSTR(pvar) = ::SysAllocStringLen((LPWSTR)TempString, cbValue/sizeof(WCHAR)); + if (V_BSTR(pvar) == NULL) + hr = E_OUTOFMEMORY; + } + break; + case ELEMENT_TYPE_CLASS: + V_VT(pvar) = VT_UNKNOWN; + V_UNKNOWN(pvar) = NULL; + // _ASSERTE( GET_UNALIGNED_VAL32(pValue) == 0); + break; + case ELEMENT_TYPE_I8: + V_VT(pvar) = VT_I8; + V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue); + break; + case ELEMENT_TYPE_U8: + V_VT(pvar) = VT_UI8; + V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue); + break; + case ELEMENT_TYPE_VOID: + V_VT(pvar) = VT_EMPTY; + break; + default: + _ASSERTE(!"bad constant value type!"); + } + + return hr; +} // HRESULT _FillVariant() + +void MDInfo::DisplayAssembly() +{ + if (m_pAssemblyImport) + { + DisplayAssemblyInfo(); + DisplayAssemblyRefs(); + DisplayFiles(); + DisplayExportedTypes(); + DisplayManifestResources(); + } +} // void MDInfo::DisplayAssembly() + +void MDInfo::DisplayAssemblyInfo() +{ + HRESULT hr; + mdAssembly mda; + const BYTE *pbPublicKey; + ULONG cbPublicKey; + ULONG ulHashAlgId; + WCHAR szName[STRING_BUFFER_LEN]; + ASSEMBLYMETADATA MetaData; + DWORD dwFlags; + + hr = m_pAssemblyImport->GetAssemblyFromScope(&mda); + if (hr == CLDB_E_RECORD_NOTFOUND) + return; + else if (FAILED(hr)) Error("GetAssemblyFromScope() failed.", hr); + + // Get the required sizes for the arrays of locales, processors etc. + ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA)); + hr = m_pAssemblyImport->GetAssemblyProps(mda, + NULL, NULL, // Public Key. + NULL, // Hash Algorithm. + NULL, 0, NULL, // Name. + &MetaData, + NULL); // Flags. + if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr); + + // Allocate space for the arrays in the ASSEMBLYMETADATA structure. + if (MetaData.cbLocale) + MetaData.szLocale = new WCHAR[MetaData.cbLocale]; + if (MetaData.ulProcessor) + MetaData.rProcessor = new DWORD[MetaData.ulProcessor]; + if (MetaData.ulOS) + MetaData.rOS = new OSINFO[MetaData.ulOS]; + + hr = m_pAssemblyImport->GetAssemblyProps(mda, + (const void **)&pbPublicKey, &cbPublicKey, + &ulHashAlgId, + szName, STRING_BUFFER_LEN, NULL, + &MetaData, + &dwFlags); + if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr); + WriteLine("Assembly"); + WriteLine("-------------------------------------------------------"); + VWriteLine("\tToken: 0x%08x", mda); + VWriteLine("\tName : %ls", szName); + DumpHex("\tPublic Key ", pbPublicKey, cbPublicKey, false, 24); + VWriteLine("\tHash Algorithm : 0x%08x", ulHashAlgId); + DisplayASSEMBLYMETADATA(&MetaData); + if(MetaData.szLocale) delete [] MetaData.szLocale; + if(MetaData.rProcessor) delete [] MetaData.rProcessor; + if(MetaData.rOS) delete [] MetaData.rOS; + + char sFlags[STRING_BUFFER_LEN]; + DWORD flags = dwFlags; + + sFlags[0] = 0; + ISFLAG(Af, PublicKey); + ISFLAG(Af, Retargetable); + ISFLAG(AfContentType_, WindowsRuntime); + + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags); + DisplayCustomAttributes(mda, "\t"); + DisplayPermissions(mda, "\t"); + WriteLine(""); +} // void MDInfo::DisplayAssemblyInfo() + +void MDInfo::DisplayAssemblyRefs() +{ + HCORENUM assemblyRefEnum = NULL; + mdAssemblyRef AssemblyRefs[ENUM_BUFFER_SIZE]; + ULONG count; + ULONG totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pAssemblyImport->EnumAssemblyRefs( &assemblyRefEnum, + AssemblyRefs, NumItems(AssemblyRefs), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("AssemblyRef #%d (%08x)", totalCount, AssemblyRefs[i]); + WriteLine("-------------------------------------------------------"); + DisplayAssemblyRefInfo(AssemblyRefs[i]); + WriteLine(""); + } + } + m_pAssemblyImport->CloseEnum(assemblyRefEnum); +} // void MDInfo::DisplayAssemblyRefs() + +void MDInfo::DisplayAssemblyRefInfo(mdAssemblyRef inAssemblyRef) +{ + HRESULT hr; + const BYTE *pbPublicKeyOrToken; + ULONG cbPublicKeyOrToken; + WCHAR szName[STRING_BUFFER_LEN]; + ASSEMBLYMETADATA MetaData; + const BYTE *pbHashValue; + ULONG cbHashValue; + DWORD dwFlags; + + VWriteLine("\tToken: 0x%08x", inAssemblyRef); + + // Get sizes for the arrays in the ASSEMBLYMETADATA structure. + ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA)); + hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef, + NULL, NULL, // Public Key or Token. + NULL, 0, NULL, // Name. + &MetaData, + NULL, NULL, // HashValue. + NULL); // Flags. + if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr); + + // Allocate space for the arrays in the ASSEMBLYMETADATA structure. + if (MetaData.cbLocale) + MetaData.szLocale = new WCHAR[MetaData.cbLocale]; + if (MetaData.ulProcessor) + MetaData.rProcessor = new DWORD[MetaData.ulProcessor]; + if (MetaData.ulOS) + MetaData.rOS = new OSINFO[MetaData.ulOS]; + + hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef, + (const void **)&pbPublicKeyOrToken, &cbPublicKeyOrToken, + szName, STRING_BUFFER_LEN, NULL, + &MetaData, + (const void **)&pbHashValue, &cbHashValue, + &dwFlags); + if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr); + + DumpHex("\tPublic Key or Token", pbPublicKeyOrToken, cbPublicKeyOrToken, false, 24); + VWriteLine("\tName: %ls", szName); + DisplayASSEMBLYMETADATA(&MetaData); + if(MetaData.szLocale) delete [] MetaData.szLocale; + if(MetaData.rProcessor) delete [] MetaData.rProcessor; + if(MetaData.rOS) delete [] MetaData.rOS; + DumpHex("\tHashValue Blob", pbHashValue, cbHashValue, false, 24); + + char sFlags[STRING_BUFFER_LEN]; + DWORD flags = dwFlags; + + sFlags[0] = 0; + ISFLAG(Af, PublicKey); + ISFLAG(Af, Retargetable); + ISFLAG(AfContentType_, WindowsRuntime); +#if 0 + ISFLAG(Af, LegacyLibrary); + ISFLAG(Af, LegacyPlatform); + ISFLAG(Af, Library); + ISFLAG(Af, Platform); +#endif + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags); + DisplayCustomAttributes(inAssemblyRef, "\t"); + WriteLine(""); +} // void MDInfo::DisplayAssemblyRefInfo() + +void MDInfo::DisplayFiles() +{ + HCORENUM fileEnum = NULL; + mdFile Files[ENUM_BUFFER_SIZE]; + ULONG count; + ULONG totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pAssemblyImport->EnumFiles( &fileEnum, + Files, NumItems(Files), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("File #%d (%08x)", totalCount, Files[i]); + WriteLine("-------------------------------------------------------"); + DisplayFileInfo(Files[i]); + WriteLine(""); + } + } + m_pAssemblyImport->CloseEnum(fileEnum); +} // void MDInfo::DisplayFiles() + +void MDInfo::DisplayFileInfo(mdFile inFile) +{ + HRESULT hr; + WCHAR szName[STRING_BUFFER_LEN]; + const BYTE *pbHashValue; + ULONG cbHashValue; + DWORD dwFlags; + + VWriteLine("\tToken: 0x%08x", inFile); + + hr = m_pAssemblyImport->GetFileProps(inFile, + szName, STRING_BUFFER_LEN, NULL, + (const void **)&pbHashValue, &cbHashValue, + &dwFlags); + if (FAILED(hr)) Error("GetFileProps() failed.", hr); + VWriteLine("\tName : %ls", szName); + DumpHex("\tHashValue Blob ", pbHashValue, cbHashValue, false, 24); + + char sFlags[STRING_BUFFER_LEN]; + DWORD flags = dwFlags; + + sFlags[0] = 0; + ISFLAG(Ff, ContainsMetaData); + ISFLAG(Ff, ContainsNoMetaData); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags); + DisplayCustomAttributes(inFile, "\t"); + WriteLine(""); + +} // MDInfo::DisplayFileInfo() + +void MDInfo::DisplayExportedTypes() +{ + HCORENUM comTypeEnum = NULL; + mdExportedType ExportedTypes[ENUM_BUFFER_SIZE]; + ULONG count; + ULONG totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pAssemblyImport->EnumExportedTypes( &comTypeEnum, + ExportedTypes, NumItems(ExportedTypes), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("ExportedType #%d (%08x)", totalCount, ExportedTypes[i]); + WriteLine("-------------------------------------------------------"); + DisplayExportedTypeInfo(ExportedTypes[i]); + WriteLine(""); + } + } + m_pAssemblyImport->CloseEnum(comTypeEnum); +} // void MDInfo::DisplayExportedTypes() + +void MDInfo::DisplayExportedTypeInfo(mdExportedType inExportedType) +{ + HRESULT hr; + WCHAR szName[STRING_BUFFER_LEN]; + mdToken tkImplementation; + mdTypeDef tkTypeDef; + DWORD dwFlags; + char sFlags[STRING_BUFFER_LEN]; + + VWriteLine("\tToken: 0x%08x", inExportedType); + + hr = m_pAssemblyImport->GetExportedTypeProps(inExportedType, + szName, STRING_BUFFER_LEN, NULL, + &tkImplementation, + &tkTypeDef, + &dwFlags); + if (FAILED(hr)) Error("GetExportedTypeProps() failed.", hr); + VWriteLine("\tName: %ls", szName); + VWriteLine("\tImplementation token: 0x%08x", tkImplementation); + VWriteLine("\tTypeDef token: 0x%08x", tkTypeDef); + VWriteLine("\tFlags : %s (%08x)",ClassFlags(dwFlags, sFlags), dwFlags); + DisplayCustomAttributes(inExportedType, "\t"); + WriteLine(""); +} // void MDInfo::DisplayExportedTypeInfo() + +void MDInfo::DisplayManifestResources() +{ + HCORENUM manifestResourceEnum = NULL; + mdManifestResource ManifestResources[ENUM_BUFFER_SIZE]; + ULONG count; + ULONG totalCount = 1; + HRESULT hr; + + while (SUCCEEDED(hr = m_pAssemblyImport->EnumManifestResources( &manifestResourceEnum, + ManifestResources, NumItems(ManifestResources), &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++, totalCount++) + { + VWriteLine("ManifestResource #%d (%08x)", totalCount, ManifestResources[i]); + WriteLine("-------------------------------------------------------"); + DisplayManifestResourceInfo(ManifestResources[i]); + WriteLine(""); + } + } + m_pAssemblyImport->CloseEnum(manifestResourceEnum); +} // void MDInfo::DisplayManifestResources() + +void MDInfo::DisplayManifestResourceInfo(mdManifestResource inManifestResource) +{ + HRESULT hr; + WCHAR szName[STRING_BUFFER_LEN]; + mdToken tkImplementation; + DWORD dwOffset; + DWORD dwFlags; + + VWriteLine("\tToken: 0x%08x", inManifestResource); + + hr = m_pAssemblyImport->GetManifestResourceProps(inManifestResource, + szName, STRING_BUFFER_LEN, NULL, + &tkImplementation, + &dwOffset, + &dwFlags); + if (FAILED(hr)) Error("GetManifestResourceProps() failed.", hr); + VWriteLine("Name: %ls", szName); + VWriteLine("Implementation token: 0x%08x", tkImplementation); + VWriteLine("Offset: 0x%08x", dwOffset); + + char sFlags[STRING_BUFFER_LEN]; + DWORD flags = dwFlags; + + sFlags[0] = 0; + ISFLAG(Mr, Public); + ISFLAG(Mr, Private); + if (!*sFlags) + strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]"); + + VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags); + DisplayCustomAttributes(inManifestResource, "\t"); + WriteLine(""); +} // void MDInfo::DisplayManifestResourceInfo() + +void MDInfo::DisplayASSEMBLYMETADATA(ASSEMBLYMETADATA *pMetaData) +{ + ULONG i; + + VWriteLine("\tVersion: %d.%d.%d.%d", pMetaData->usMajorVersion, pMetaData->usMinorVersion, pMetaData->usBuildNumber, pMetaData->usRevisionNumber); + VWriteLine("\tMajor Version: 0x%08x", pMetaData->usMajorVersion); + VWriteLine("\tMinor Version: 0x%08x", pMetaData->usMinorVersion); + VWriteLine("\tBuild Number: 0x%08x", pMetaData->usBuildNumber); + VWriteLine("\tRevision Number: 0x%08x", pMetaData->usRevisionNumber); + VWriteLine("\tLocale: %ls", pMetaData->cbLocale ? pMetaData->szLocale : L"<null>"); + for (i = 0; i < pMetaData->ulProcessor; i++) + VWriteLine("\tProcessor #%ld: 0x%08x", i+1, pMetaData->rProcessor[i]); + for (i = 0; i < pMetaData->ulOS; i++) + { + VWriteLine("\tOS #%ld:", i+1); + VWriteLine("\t\tOS Platform ID: 0x%08x", pMetaData->rOS[i].dwOSPlatformId); + VWriteLine("\t\tOS Major Version: 0x%08x", pMetaData->rOS[i].dwOSMajorVersion); + VWriteLine("\t\tOS Minor Version: 0x%08x", pMetaData->rOS[i].dwOSMinorVersion); + } +} // void MDInfo::DisplayASSEMBLYMETADATA() + +void MDInfo::DisplayUserStrings() +{ + HCORENUM stringEnum = NULL; // string enumerator. + mdString Strings[ENUM_BUFFER_SIZE]; // String tokens from enumerator. + CQuickArray<WCHAR> rUserString; // Buffer to receive string. + WCHAR *szUserString; // Working pointer into buffer. + ULONG chUserString; // Size of user string. + CQuickArray<char> rcBuf; // Buffer to hold the BLOB version of the string. + char *szBuf; // Working pointer into buffer. + ULONG chBuf; // Saved size of the user string. + ULONG count; // Items returned from enumerator. + ULONG totalCount = 1; // Running count of strings. + bool bUnprint = false; // Is an unprintable character found? + HRESULT hr; // A result. + while (SUCCEEDED(hr = m_pImport->EnumUserStrings( &stringEnum, + Strings, NumItems(Strings), &count)) && + count > 0) + { + if (totalCount == 1) + { // If only one, it is the NULL string, so don't print it. + WriteLine("User Strings"); + WriteLine("-------------------------------------------------------"); + } + for (ULONG i = 0; i < count; i++, totalCount++) + { + do { // Try to get the string into the existing buffer. + hr = m_pImport->GetUserString( Strings[i], rUserString.Ptr(),(ULONG32)rUserString.MaxSize(), &chUserString); + if (hr == CLDB_S_TRUNCATION) + { // Buffer wasn't big enough, try to enlarge it. + if (FAILED(rUserString.ReSizeNoThrow(chUserString))) + Error("malloc failed.", E_OUTOFMEMORY); + continue; + } + } while (hr == CLDB_S_TRUNCATION); + if (FAILED(hr)) Error("GetUserString failed.", hr); + + szUserString = rUserString.Ptr(); + chBuf = chUserString; + + VWrite("%08x : (%2d) L\"", Strings[i], chUserString); + for (ULONG j=0; j<chUserString; j++) + { + switch (*szUserString) + { + case 0: + Write("\\0"); break; + case L'\r': + Write("\\r"); break; + case L'\n': + Write("\\n"); break; + case L'\t': + Write("\\t"); break; + default: + if (iswprint(*szUserString)) + VWrite("%lc", *szUserString); + else + { + bUnprint = true; + Write("."); + } + break; + } + ++szUserString; + if((j>0)&&((j&0x7F)==0)) WriteLine(""); + } + WriteLine("\""); + + // Print the user string as a blob if an unprintable character is found. + if (bUnprint) + { + bUnprint = false; + szUserString = rUserString.Ptr(); + if (FAILED(hr = rcBuf.ReSizeNoThrow(81))) //(chBuf * 5 + 1); + Error("ReSize failed.", hr); + szBuf = rcBuf.Ptr(); + ULONG j,k; + WriteLine("\t\tUser string has unprintables, hex format below:"); + for (j = 0,k=0; j < chBuf; j++) + { + sprintf_s (&szBuf[k*5], 81, "%04x ", szUserString[j]); + k++; + if((k==16)||(j == (chBuf-1))) + { + szBuf[k*5] = '\0'; + VWriteLine("\t\t%s", szBuf); + k=0; + } + } + } + } + } + if (stringEnum) + m_pImport->CloseEnum(stringEnum); +} // void MDInfo::DisplayUserStrings() + +void MDInfo::DisplayUnsatInfo() +{ + HRESULT hr = S_OK; + + HCORENUM henum = 0; + mdToken tk; + ULONG cMethods; + + Write("\nUnresolved Externals\n"); + Write("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + + while ( (hr = m_pImport->EnumUnresolvedMethods( + &henum, + &tk, + 1, + &cMethods)) == S_OK && cMethods ) + { + if ( TypeFromToken(tk) == mdtMethodDef ) + { + // a method definition without implementation + DisplayMethodInfo( tk ); + } + else if ( TypeFromToken(tk) == mdtMemberRef ) + { + // an unresolved MemberRef to a global function + DisplayMemberRefInfo( tk, "" ); + } + else + { + _ASSERTE(!"Unknown token kind!"); + } + } + m_pImport->CloseEnum(henum); +} // void MDInfo::DisplayUnsatInfo() + +//******************************************************************************* +// This code is used for debugging purposes only. This will just print out the +// entire database. +//******************************************************************************* +const char *MDInfo::DumpRawNameOfType(ULONG iType) +{ + if (iType <= iRidMax) + { + const char *pNameTable; + m_pTables->GetTableInfo(iType, 0,0,0,0, &pNameTable); + return pNameTable; + } + else + // Is the field a coded token? + if (iType <= iCodedTokenMax) + { + int iCdTkn = iType - iCodedToken; + const char *pNameCdTkn; + m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn); + return pNameCdTkn; + } + + // Fixed type. + switch (iType) + { + case iBYTE: + return "BYTE"; + case iSHORT: + return "short"; + case iUSHORT: + return "USHORT"; + case iLONG: + return "long"; + case iULONG: + return "ULONG"; + case iSTRING: + return "string"; + case iGUID: + return "GUID"; + case iBLOB: + return "blob"; + } + // default: + static char buf[30]; + sprintf_s(buf, 30, "unknown type 0x%02x", iType); + return buf; +} // const char *MDInfo::DumpRawNameOfType() + +void MDInfo::DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats) +{ + ULONG ulType; // Type of a column. + ULONG ulVal; // Value of a column. + LPCUTF8 pString; // Pointer to a string. + const void *pBlob; // Pointer to a blob. + ULONG cb; // Size of something. + + m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal); + m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0); + + if (ulType <= iRidMax) + { + const char *pNameTable; + m_pTables->GetTableInfo(ulType, 0,0,0,0, &pNameTable); + VWrite("%s[%x]", pNameTable, ulVal); + } + else + // Is the field a coded token? + if (ulType <= iCodedTokenMax) + { + int iCdTkn = ulType - iCodedToken; + const char *pNameCdTkn; + m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn); + VWrite("%s[%08x]", pNameCdTkn, ulVal); + } + else + { + // Fixed type. + switch (ulType) + { + case iBYTE: + VWrite("%02x", ulVal); + break; + case iSHORT: + case iUSHORT: + VWrite("%04x", ulVal); + break; + case iLONG: + case iULONG: + VWrite("%08x", ulVal); + break; + case iSTRING: + if (ulVal && (m_DumpFilter & dumpNames)) + { + m_pTables->GetString(ulVal, &pString); + VWrite("(%x)\"%s\"", ulVal, pString); + } + else + VWrite("string#%x", ulVal); + if (bStats && ulVal) + { + m_pTables->GetString(ulVal, &pString); + cb = (ULONG) strlen(pString) + 1; + VWrite("(%d)", cb); + } + break; + case iGUID: + VWrite("guid#%x", ulVal); + if (bStats && ulVal) + { + VWrite("(16)"); + } + break; + case iBLOB: + VWrite("blob#%x", ulVal); + if (bStats && ulVal) + { + m_pTables->GetBlob(ulVal, &cb, &pBlob); + cb += 1; + if (cb > 128) + cb += 1; + if (cb > 16535) + cb += 1; + VWrite("(%d)", cb); + } + break; + default: + VWrite("unknown type 0x%04x", ulVal); + break; + } + } +} // void MDInfo::DumpRawCol() + +ULONG MDInfo::DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows) +{ + ULONG rslt = 0; + ULONG ulType; // Type of a column. + ULONG ulVal; // Value of a column. + LPCUTF8 pString; // Pointer to a string. + const void *pBlob; // Pointer to a blob. + ULONG cb; // Size of something. + + m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0); + + if (IsHeapType(ulType)) + { + for (ULONG rid=1; rid<=cRows; ++rid) + { + m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal); + // Fixed type. + switch (ulType) + { + case iSTRING: + if (ulVal) + { + m_pTables->GetString(ulVal, &pString); + cb = (ULONG) strlen(pString); + rslt += cb + 1; + } + break; + case iGUID: + if (ulVal) + rslt += 16; + break; + case iBLOB: + if (ulVal) + { + m_pTables->GetBlob(ulVal, &cb, &pBlob); + rslt += cb + 1; + if (cb > 128) + rslt += 1; + if (cb > 16535) + rslt += 1; + } + break; + default: + break; + } + } + } + return rslt; +} // ULONG MDInfo::DumpRawColStats() + +int MDInfo::DumpHex( + const char *szPrefix, // String prefix for first line. + const void *pvData, // The data to print. + ULONG cbData, // Bytes of data to print. + int bText, // If true, also dump text. + ULONG nLine) // Bytes per line to print. +{ + const BYTE *pbData = static_cast<const BYTE*>(pvData); + ULONG i; // Loop control. + ULONG nPrint; // Number to print in an iteration. + ULONG nSpace; // Spacing calculations. + ULONG nPrefix; // Size of the prefix. + ULONG nLines=0; // Number of lines printed. + const char *pPrefix; // For counting spaces in the prefix. + + // Round down to 8 characters. + nLine = nLine & ~0x7; + + for (nPrefix=0, pPrefix=szPrefix; *pPrefix; ++pPrefix) + { + if (*pPrefix == '\t') + nPrefix = (nPrefix + 8) & ~7; + else + ++nPrefix; + } + //nPrefix = strlen(szPrefix); + do + { // Write the line prefix. + if (szPrefix) + VWrite("%s:", szPrefix); + else + VWrite("%*s:", nPrefix, ""); + szPrefix = 0; + ++nLines; + + // Calculate spacing. + nPrint = min(cbData, nLine); + nSpace = nLine - nPrint; + + // dump in hex. + for(i=0; i<nPrint; i++) + { + if ((i&7) == 0) + Write(" "); + VWrite("%02x ", pbData[i]); + } + if (bText) + { + // Space out to the text spot. + if (nSpace) + VWrite("%*s", nSpace*3+nSpace/8, ""); + // Dump in text. + Write(">"); + for(i=0; i<nPrint; i++) + VWrite("%c", (isprint(pbData[i])) ? pbData[i] : ' '); + // Space out the text, and finish the line. + VWrite("%*s<", nSpace, ""); + } + VWriteLine(""); + + // Next data to print. + cbData -= nPrint; + pbData += nPrint; + } + while (cbData > 0); + + return nLines; +} // int MDInfo::DumpHex() + +void MDInfo::DumpRawHeaps() +{ + HRESULT hr; // A result. + ULONG ulSize; // Bytes in a heap. + const BYTE *pData; // Pointer to a blob. + ULONG cbData; // Size of a blob. + ULONG oData; // Offset of current blob. + char rcPrefix[30]; // To format line prefix. + + m_pTables->GetBlobHeapSize(&ulSize); + VWriteLine(""); + VWriteLine("Blob Heap: %d(%#x) bytes", ulSize,ulSize); + oData = 0; + do + { + m_pTables->GetBlob(oData, &cbData, (const void**)&pData); + sprintf_s(rcPrefix, 30, "%5x,%-2x", oData, cbData); + DumpHex(rcPrefix, pData, cbData); + hr = m_pTables->GetNextBlob(oData, &oData); + } + while (hr == S_OK); + + m_pTables->GetStringHeapSize(&ulSize); + VWriteLine(""); + VWriteLine("String Heap: %d(%#x) bytes", ulSize,ulSize); + oData = 0; + const char *pString; + do + { + m_pTables->GetString(oData, &pString); + if (m_DumpFilter & dumpMoreHex) + { + sprintf_s(rcPrefix, 30, "%08x", oData); + DumpHex(rcPrefix, pString, (ULONG)strlen(pString)+1); + } + else + if (*pString != 0) + VWrite("%08x: %s\n", oData, pString); + hr = m_pTables->GetNextString(oData, &oData); + } + while (hr == S_OK); + VWriteLine(""); + + DisplayUserStrings(); + +} // void MDInfo::DumpRawHeaps() + + +void MDInfo::DumpRaw(int iDump, bool bunused) +{ + ULONG cTables; // Tables in the database. + ULONG cCols; // Columns in a table. + ULONG cRows; // Rows in a table. + ULONG cbRow; // Bytes in a row of a table. + ULONG iKey; // Key column of a table. + const char *pNameTable; // Name of a table. + ULONG oCol; // Offset of a column. + ULONG cbCol; // Size of a column. + ULONG ulType; // Type of a column. + const char *pNameColumn; // Name of a column. + ULONG ulSize; + + // Heaps is easy -- there is a specific bit for that. + bool bStats = (m_DumpFilter & dumpStats) != 0; + // Rows are harder. Was there something else that limited data? + BOOL bRows = (m_DumpFilter & (dumpSchema | dumpHeader)) == 0; + BOOL bSchema = bRows || (m_DumpFilter & dumpSchema); + // (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps)) + + if (m_pTables2) + { + // Get the raw metadata header. + const BYTE *pbData = NULL; + const BYTE *pbStream = NULL; // One of the stream.s + const BYTE *pbMd = NULL; // The metadata stream. + ULONG cbData = 0; + ULONG cbStream = 0; // One of the streams. + ULONG cbMd = 0; // The metadata stream. + const char *pName; + HRESULT hr = S_OK; + ULONG ix; + + m_pTables2->GetMetaDataStorage((const void**)&pbData, &cbData); + + // Per the ECMA spec, the section data looks like this: + struct MDSTORAGESIGNATURE + { + ULONG lSignature; // "Magic" signature. + USHORT iMajorVer; // Major file version. + USHORT iMinorVer; // Minor file version. + ULONG iExtraData; // Offset to next structure of information + ULONG iVersionString; // Length of version string + BYTE pVersion[0]; // Version string + }; + struct MDSTORAGEHEADER + { + BYTE fFlags; // STGHDR_xxx flags. + BYTE pad; + USHORT iStreams; // How many streams are there. + }; + const MDSTORAGESIGNATURE *pStorage = (const MDSTORAGESIGNATURE *) pbData; + const MDSTORAGEHEADER *pSHeader = (const MDSTORAGEHEADER *)(pbData + sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString); + + VWriteLine("Metadata section: 0x%08x, version: %d.%d, extra: %d, version len: %d, version: %s", pStorage->lSignature, pStorage->iMajorVer, pStorage->iMinorVer, pStorage->iExtraData, pStorage->iVersionString, pStorage->pVersion); + VWriteLine(" flags: 0x%02x, streams: %d", pSHeader->fFlags, pSHeader->iStreams); + if (m_DumpFilter & dumpMoreHex) + { + const BYTE *pbEnd = pbData; + ULONG cb = sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString + sizeof(MDSTORAGEHEADER); + hr = m_pTables2->GetMetaDataStreamInfo(0, &pName, (const void**)&pbEnd, &cbStream); + if (hr == S_OK) + cb = (ULONG)(pbEnd - pbData); + DumpHex(" ", pbData, cb); + } + + for (ix=0; hr == S_OK; ++ix) + { + hr = m_pTables2->GetMetaDataStreamInfo(ix, &pName, (const void**)&pbStream, &cbStream); + if (hr != S_OK) + break; + if (strcmp(pName, "#~") == 0 || strcmp(pName, "#-") == 0) + { + pbMd = pbStream; + cbMd = cbStream; + } + + VWriteLine("Stream %d: name: %s, size %d", ix, pName, cbStream); + // hex for individual stream headers in metadata section dump. hex for + // the streams themselves distributed throughout the dump. + } + + if (pbMd) + { + // Per ECMA, the metadata header looks like this: + struct MD + { + ULONG m_ulReserved; // Reserved, must be zero. + BYTE m_major; // Version numbers. + BYTE m_minor; + BYTE m_heaps; // Bits for heap sizes. + BYTE m_rid; // log-base-2 of largest rid. + unsigned __int64 m_maskvalid; // Bit mask of present table counts. + unsigned __int64 m_sorted; // Bit mask of sorted tables. }; + }; + + const MD *pMd; + pMd = (const MD *)pbMd; + + VWriteLine("Metadata header: %d.%d, heaps: 0x%02x, rid: 0x%02x, valid: 0x%016I64x, sorted: 0x%016I64x", + pMd->m_major, pMd->m_minor, pMd->m_heaps, pMd->m_rid, + (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_maskvalid)), + (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_sorted))); + + if (m_DumpFilter & dumpMoreHex) + { + DumpHex(" ", pbMd, sizeof(MD)); + } + } + VWriteLine(""); + } + + m_pTables->GetNumTables(&cTables); + + m_pTables->GetStringHeapSize(&ulSize); + VWrite("Strings: %d(%#x)", ulSize, ulSize); + m_pTables->GetBlobHeapSize(&ulSize); + VWrite(", Blobs: %d(%#x)", ulSize, ulSize); + m_pTables->GetGuidHeapSize(&ulSize); + VWrite(", Guids: %d(%#x)", ulSize, ulSize); + m_pTables->GetUserStringHeapSize(&ulSize); + VWriteLine(", User strings: %d(%#x)", ulSize, ulSize); + + for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl) + { + m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, &iKey, &pNameTable); + + if (bRows) // when dumping rows, print a break between row data and schema + VWriteLine("================================================="); + VWriteLine("%2d(%#x): %-20s cRecs:%5d(%#x), cbRec:%3d(%#x), cbTable:%6d(%#x)", + ixTbl, ixTbl, pNameTable, cRows, cRows, cbRow, cbRow, cbRow * cRows, cbRow * cRows); + + if (!bSchema && !bRows) + continue; + + // Dump column definitions for the table. + ULONG ixCol; + for (ixCol=0; ixCol<cCols; ++ixCol) + { + m_pTables->GetColumnInfo(ixTbl, ixCol, &oCol, &cbCol, &ulType, &pNameColumn); + + VWrite(" col %2x:%c %-12s oCol:%2x, cbCol:%x, %-7s", + ixCol, ((ixCol==iKey)?'*':' '), pNameColumn, oCol, cbCol, DumpRawNameOfType(ulType)); + + if (bStats) + { + ulSize = DumpRawColStats(ixTbl, ixCol, cRows); + if (ulSize) + VWrite("(%d)", ulSize); + } + VWriteLine(""); + } + + if (!bRows) + continue; + + // Dump the rows. + for (ULONG rid = 1; rid <= cRows; ++rid) + { + if (rid == 1) + VWriteLine("-------------------------------------------------"); + VWrite(" %3x == ", rid); + for (ixCol=0; ixCol < cCols; ++ixCol) + { + if (ixCol) VWrite(", "); + VWrite("%d:", ixCol); + DumpRawCol(ixTbl, ixCol, rid, bStats); + } + VWriteLine(""); + } + } +} // void MDInfo::DumpRaw() + +void MDInfo::DumpRawCSV() +{ + ULONG cTables; // Tables in the database. + ULONG cCols; // Columns in a table. + ULONG cRows; // Rows in a table. + ULONG cbRow; // Bytes in a row of a table. + const char *pNameTable; // Name of a table. + ULONG ulSize; + + m_pTables->GetNumTables(&cTables); + + VWriteLine("Name,Size,cRecs,cbRec"); + + m_pTables->GetStringHeapSize(&ulSize); + VWriteLine("Strings,%d", ulSize); + + m_pTables->GetBlobHeapSize(&ulSize); + VWriteLine("Blobs,%d", ulSize); + + m_pTables->GetGuidHeapSize(&ulSize); + VWriteLine("Guids,%d", ulSize); + + for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl) + { + m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, NULL, &pNameTable); + VWriteLine("%s,%d,%d,%d", pNameTable, cbRow*cRows, cRows, cbRow); + } + +} // void MDInfo::DumpRawCSV() + diff --git a/src/tools/metainfo/mdinfo.h b/src/tools/metainfo/mdinfo.h new file mode 100644 index 0000000000..077a89da9b --- /dev/null +++ b/src/tools/metainfo/mdinfo.h @@ -0,0 +1,206 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _mdinfo_h +#define _mdinfo_h + +#include "winwrap.h" +#include "cor.h" +#include "corhlprpriv.h" + +#ifdef FEATURE_PAL +#include <oleauto.h> +#endif + +#define STRING_BUFFER_LEN 4096 + +typedef void (*strPassBackFn)(const char *str); + +class MDInfo { +public: + enum DUMP_FILTER + { + dumpDefault = 0x00000000, // Dump everything but debugger data. + dumpSchema = 0x00000002, // Dump the metadata schema. + dumpRaw = 0x00000004, // Dump the metadata in raw table format. + dumpHeader = 0x00000008, // Dump just the metadata header info. + dumpCSV = 0x00000010, // Dump the metadata header info in CSV format. + dumpUnsat = 0x00000020, // Dump unresolved methods or memberref + dumpAssem = 0x00000040, + dumpStats = 0x00000080, // Dump more statistics about tables. + dumpMoreHex = 0x00000100, // Dump more things in hex. + dumpValidate = 0x00000200, // Validate MetaData. + dumpRawHeaps = 0x00000400, // Also dump the heaps in the raw dump. + dumpNoLogo = 0x00000800, // Don't display the logo or MVID + dumpNames = 0x00001000, // In a hex dump, display the names, as well as string #'s. + }; + + +public: + MDInfo(IMetaDataImport2* pImport, IMetaDataAssemblyImport* pAssemblyImport, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter); + MDInfo(IMetaDataDispenserEx *pDispenser, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter=dumpDefault); + MDInfo(IMetaDataDispenserEx *pDispenser, PBYTE pManifest, DWORD dwSize, strPassBackFn inPBFn, ULONG DumpFilter=dumpDefault); + ~MDInfo(); + + void DisplayMD(void); + + LPWSTR VariantAsString(VARIANT *pVariant); + + void DisplayVersionInfo(void); + + void DisplayScopeInfo(void); + + void DisplayGlobalFunctions(void); + void DisplayGlobalFields(void); + void DisplayFieldRVA(mdFieldDef field); + void DisplayGlobalMemberRefs(void); + + void DisplayTypeDefs(void); + void DisplayTypeDefInfo(mdTypeDef inTypeDef); + void DisplayTypeDefProps(mdTypeDef inTypeDef); + + void DisplayModuleRefs(void); + void DisplayModuleRefInfo(mdModuleRef inModuleRef); + + void DisplaySignatures(void); + void DisplaySignatureInfo(mdSignature inSignature); + + LPCWSTR TokenName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + + LPCWSTR TypeDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + LPCWSTR TypeDefName(mdTypeDef inTypeDef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + LPCWSTR TypeRefName(mdTypeRef tr, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + + LPCWSTR MemberDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + LPCWSTR MemberRefName(mdToken inMemRef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + LPCWSTR MemberName(mdToken inMember, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + + LPCWSTR MethodName(mdMethodDef inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + LPCWSTR FieldName(mdFieldDef inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen); + + char *ClassFlags(DWORD flags, __out_ecount(STRING_BUFFER_LEN) char *sFlags); + + void DisplayTypeRefs(void); + void DisplayTypeRefInfo(mdTypeRef tr); + void DisplayTypeSpecs(void); + void DisplayTypeSpecInfo(mdTypeSpec ts, const char *preFix); + void DisplayMethodSpecs(void); + void DisplayMethodSpecInfo(mdMethodSpec ms, const char *preFix); + + void DisplayCorNativeLink(COR_NATIVE_LINK *pCorNLnk, const char *preFix); + void DisplayCustomAttributeInfo(mdCustomAttribute inValue, const char *preFix); + void DisplayCustomAttributes(mdToken inToken, const char *preFix); + + void DisplayInterfaceImpls(mdTypeDef inTypeDef); + void DisplayInterfaceImplInfo(mdInterfaceImpl inImpl); + + LPWSTR GUIDAsString(GUID inGuid, __out_ecount(bufLen) LPWSTR guidString, ULONG bufLen); + + char *TokenTypeName(mdToken inToken); + + void DisplayMemberInfo(mdToken inMember); + void DisplayMethodInfo(mdMethodDef method, DWORD *pflags = 0); + void DisplayFieldInfo(mdFieldDef field, DWORD *pflags = 0); + + void DisplayMethods(mdTypeDef inTypeDef); + void DisplayFields(mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset); + + void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix); + HRESULT GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb); + + void DisplayMemberRefs(mdToken tkParent, const char *preFix); + void DisplayMemberRefInfo(mdMemberRef inMemRef, const char *preFix); + + void DisplayMethodImpls(mdTypeDef inTypeDef); + + void DisplayParams(mdMethodDef inMthDef); + void DisplayParamInfo(mdParamDef inParam); + + void DisplayGenericParams(mdToken tk, const char *prefix); + void DisplayGenericParamInfo(mdGenericParam tkparam, const char *prefix); + + void DisplayPropertyInfo(mdProperty inProp); + void DisplayProperties(mdTypeDef inTypeDef); + + void DisplayEventInfo(mdEvent inEvent); + void DisplayEvents(mdTypeDef inTypeDef); + + void DisplayPermissions(mdToken tk, const char *preFix); + void DisplayPermissionInfo(mdPermission inPermission, const char *preFix); + + void DisplayFieldMarshal(mdToken inToken); + + void DisplayPinvokeInfo(mdToken inToken); + + void DisplayAssembly(); + + void DisplayAssemblyInfo(); + + void DisplayAssemblyRefs(); + void DisplayAssemblyRefInfo(mdAssemblyRef inAssemblyRef); + + void DisplayFiles(); + void DisplayFileInfo(mdFile inFile); + + void DisplayExportedTypes(); + void DisplayExportedTypeInfo(mdExportedType inExportedType); + + void DisplayManifestResources(); + void DisplayManifestResourceInfo(mdManifestResource inManifestResource); + + void DisplayASSEMBLYMETADATA(ASSEMBLYMETADATA *pMetaData); + + void DisplayUserStrings(); + + void DisplayUnsatInfo(); + + void DisplayRaw(); + void DumpRawHeaps(); + void DumpRaw(int iDump=1, bool bStats=false); + void DumpRawCSV(); + void DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats); + ULONG DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows); + const char *DumpRawNameOfType(ULONG ulType); + void SetVEHandlerReporter(__int64 VEHandlerReporterPtr) { m_VEHandlerReporterPtr = VEHandlerReporterPtr; }; + + static void Error(const char *szError, HRESULT hr = S_OK); +private: + void Init(strPassBackFn inPBFn, DUMP_FILTER DumpFilter); // Common initialization code. + + int DumpHex(const char *szPrefix, const void *pvData, ULONG cbData, int bText=true, ULONG nLine=16); + + int Write(__in_z __in char *str); + int WriteLine(__in_z __in char *str); + + int VWrite(__in_z __in char *str, ...); + int VWriteLine(__in_z __in char *str, ...); + int VWriteMarker(__in_z __in char *str, va_list marker); + + void InitSigBuffer(); + HRESULT AddToSigBuffer(__in_z __in char *string); + + IMetaDataImport2 *m_pRegImport; + IMetaDataImport2 *m_pImport; + IMetaDataAssemblyImport *m_pAssemblyImport; + strPassBackFn m_pbFn; + __int64 m_VEHandlerReporterPtr; + IMetaDataTables *m_pTables; + IMetaDataTables2 *m_pTables2; + + CQuickBytes m_output; + DUMP_FILTER m_DumpFilter; + + // temporary buffer for TypeDef or TypeRef name. Consume immediately + // because other functions may overwrite it. + WCHAR m_szTempBuf[STRING_BUFFER_LEN]; + + // temporary buffer for formatted string. Consume immediately before any function calls. + char m_tempFormatBuffer[STRING_BUFFER_LEN]; + + // Signature buffer. + CQuickBytes m_sigBuf; +}; + +#endif diff --git a/src/tools/metainfo/mdobj.cpp b/src/tools/metainfo/mdobj.cpp new file mode 100644 index 0000000000..956d4c6f76 --- /dev/null +++ b/src/tools/metainfo/mdobj.cpp @@ -0,0 +1,299 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include <stdio.h> +#include <ctype.h> +#include <crtdbg.h> +#include "mdinfo.h" + +#ifndef STRING_BUFFER_LEN +#define STRING_BUFFER_LEN 4096 +#endif + +#define OBJ_EXT ".obj" +#define OBJ_EXT_W L".obj" +#define OBJ_EXT_LEN 4 +#define LIB_EXT ".lib" +#define LIB_EXT_W L".lib" +#define LIB_EXT_LEN 4 + +extern IMetaDataDispenserEx *g_pDisp; +extern DWORD g_ValModuleType; + +// This function is copied from peparse.c file. Making this static, so we won't end up with +// duplicate definitions causing confusion. +static const char g_szCORMETA[] = ".cormeta"; +static HRESULT FindObjMetaData(PVOID pImage, PVOID *ppMetaData, long *pcbMetaData) +{ + IMAGE_FILE_HEADER *pImageHdr; // Header for the .obj file. + IMAGE_SECTION_HEADER *pSectionHdr; // Section header. + WORD i; // Loop control. + + // Get a pointer to the header and the first section. + pImageHdr = (IMAGE_FILE_HEADER *) pImage; + pSectionHdr = (IMAGE_SECTION_HEADER *)(pImageHdr + 1); + + // Avoid confusion. + *ppMetaData = NULL; + *pcbMetaData = 0; + + // Walk each section looking for .cormeta. + for (i=0; i<VAL16(pImageHdr->NumberOfSections); i++, pSectionHdr++) + { + // Simple comparison to section name. + if (strcmp((const char *) pSectionHdr->Name, g_szCORMETA) == 0) + { + *pcbMetaData = VAL32(pSectionHdr->SizeOfRawData); + *ppMetaData = (void *) ((UINT_PTR)pImage + VAL32(pSectionHdr->PointerToRawData)); + break; + } + } + + // Check for errors. + if (*ppMetaData == NULL || *pcbMetaData == 0) + return (E_FAIL); + return (S_OK); +} + + +// This function returns the address to the MapView of file and file size. +void GetMapViewOfFile(__in wchar_t *szFile, PBYTE *ppbMap, DWORD *pdwFileSize) +{ + HANDLE hMapFile; + DWORD dwHighSize; + + HANDLE hFile = WszCreateFile(szFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + MDInfo::Error("CreateFileA failed!"); + + *pdwFileSize = GetFileSize(hFile, &dwHighSize); + + if ((*pdwFileSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) + { + CloseHandle(hFile); + MDInfo::Error("GetFileSize failed!"); + } + _ASSERTE(dwHighSize == 0); + + hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(hFile); + if (!hMapFile) + MDInfo::Error("CreateFileMappingA failed!"); + + *ppbMap = (PBYTE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + CloseHandle(hMapFile); + + if (!*ppbMap) + MDInfo::Error("MapViewOfFile failed!"); +} // void GetMapViewOfFile() + +// This function skips a member given the pointer to the member header +// and returns a pointer to the next header. +PBYTE SkipMember(PBYTE pbMapAddress) +{ + PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr; + ULONG ulMemSize; + int j; + + pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress; + + // Get size of the member. + ulMemSize = 0; + for (j = 0; j < 10; j++) + { + if (pMemHdr->Size[j] < '0' || pMemHdr->Size[j] > '9') + break; + else + ulMemSize = ulMemSize * 10 + pMemHdr->Size[j] - '0'; + } + + // Skip past the header. + pbMapAddress += IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR + ulMemSize; + // Find the next even address if the current one is not even. + if ((ULONG_PTR)pbMapAddress % 2) + pbMapAddress++; + + return pbMapAddress; +} // void SkipMember() + +// This function returns the name of the given Obj. If the name fits in the header, +// szBuf will be filled in and returned from the function. Else an offset into the long +// names section will be returned. +char *GetNameOfObj(PBYTE pbLongNames, PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr, char szBuf[17]) +{ + if (pMemHdr->Name[0] == '/') + { + ULONG ulOffset = 0; + + // Long Names section must exist if the .obj file name starts with '/'. + _ASSERTE(pbLongNames && + "Corrupt archive file - .obj file name in the header starts with " + "'/' but no long names section present in the archive file."); + + // Calculate the offset into the long names section. + for (int j = 1; j < 16; j++) + { + if (pMemHdr->Name[j] < '0' || pMemHdr->Name[j] > '9') + break; + else + ulOffset = ulOffset * 10 + pMemHdr->Name[j] - '0'; + } + return (char *)(pbLongNames + ulOffset); + } + else + { + int j; + for (j = 0; j < 16; j++) + if ((szBuf[j] = pMemHdr->Name[j]) == '/') + break; + szBuf[j] = '\0'; + return szBuf; + } +} // char *GetNameOfObj() + +// DisplayArchive() function +// +// Opens the .LIB file, and displays the metadata in the specified object files. + +void DisplayArchive(__in_z __in wchar_t* szFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString) +{ + PBYTE pbMapAddress; + PBYTE pbStartAddress; + PBYTE pbLongNameAddress; + PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr; + DWORD dwFileSize; + PVOID pvMetaData; + char *szName; + wchar_t wzName[1024]; + char szBuf[17]; + long cbMetaData; + int i; + HRESULT hr; + char szString[1024]; + + GetMapViewOfFile(szFile, &pbMapAddress, &dwFileSize); + pbStartAddress = pbMapAddress; + + // Verify and skip archive signature. + if (dwFileSize < IMAGE_ARCHIVE_START_SIZE || + strncmp((char *)pbMapAddress, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) + { + MDInfo::Error("Bad file format - archive signature mis-match!"); + } + pbMapAddress += IMAGE_ARCHIVE_START_SIZE; + + // Skip linker member 1, linker member 2. + for (i = 0; i < 2; i++) + pbMapAddress = SkipMember(pbMapAddress); + + // Save address of the long name member and skip it if there exists one. + pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress; + if (pMemHdr->Name[0] == '/' && pMemHdr->Name[1] == '/') + { + pbLongNameAddress = pbMapAddress + IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR; + pbMapAddress = SkipMember(pbMapAddress); + } + else + pbLongNameAddress = 0; + + pDisplayString ("\n"); + // Get the MetaData for each object file and display it. + while (DWORD(pbMapAddress - pbStartAddress) < dwFileSize) + { + if((szName = GetNameOfObj(pbLongNameAddress, (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress, szBuf))!=NULL) + { + if (Wsz_mbstowcs(wzName, szName, 1024) == -1) + MDInfo::Error("Conversion from Multi-Byte to Wide-Char failed."); + + // Display metadata only for object files. + // If szObjName is specified, display metadata only for that one object file. + if (!_stricmp(&szName[strlen(szName) - OBJ_EXT_LEN], OBJ_EXT) && + (!szObjName || !_wcsicmp(szObjName, wzName))) + { + // Try to find the MetaData section in the current object file. + hr = FindObjMetaData(pbMapAddress+IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR, &pvMetaData, &cbMetaData); + if (SUCCEEDED(hr)) + { + sprintf_s (szString,1024,"MetaData for object file %s:\n", szName); + pDisplayString(szString); + MDInfo archiveInfo(g_pDisp, + (PBYTE)pvMetaData, + cbMetaData, + pDisplayString, + DumpFilter); + archiveInfo.DisplayMD(); + } + else + { + sprintf_s(szString,1024,"MetaData not found for object file %s!\n\n", szName); + pDisplayString(szString); + } + } + } + + // Skip past the object file. + pbMapAddress = SkipMember(pbMapAddress); + } + + UnmapViewOfFile(pbStartAddress); +} // void DisplayArchive() + +// DisplayFile() function +// +// Opens the meta data content of a .EXE, .CLB, .CLASS, .TLB, .DLL or .LIB file, and +// calls RawDisplay() + +void DisplayFile(__in_z __in wchar_t* szFile, BOOL isFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString) +{ + // Open the emit scope + + // We need to make sure this file isn't too long. Checking _MAX_PATH is probably safe, but since we have a much + // larger buffer, we might as well use it all. + if (wcslen(szFile) > 1000) + return; + + + WCHAR szScope[1024]; + char szString[1024]; + + if (isFile) + { + wcscpy_s(szScope, 1024, L"file:"); + wcscat_s(szScope, 1024, szFile); + } + else + wcscpy_s(szScope, 1024, szFile); + + // print bar that separates different files + pDisplayString("////////////////////////////////////////////////////////////////\n"); + wchar_t rcFname[_MAX_FNAME], rcExt[_MAX_EXT]; + + _wsplitpath_s(szFile, NULL, 0, NULL, 0, rcFname, _MAX_FNAME, rcExt, _MAX_EXT); + sprintf_s(szString,1024,"\nFile %S%S: \n",rcFname, rcExt); + pDisplayString(szString); + + if (DumpFilter & MDInfo::dumpValidate) + { + if (!_wcsicmp(rcExt, OBJ_EXT_W) || !_wcsicmp(rcExt, LIB_EXT_W)) + g_ValModuleType = ValidatorModuleTypeObj; + else + g_ValModuleType = ValidatorModuleTypePE; + } + + if (!_wcsicmp(rcExt, LIB_EXT_W)) + DisplayArchive(szFile, DumpFilter, szObjName, pDisplayString); + else + { + MDInfo metaDataInfo(g_pDisp, szScope, pDisplayString, DumpFilter); + metaDataInfo.DisplayMD(); + } +} // void DisplayFile() + diff --git a/src/tools/metainfo/metainfo.cpp b/src/tools/metainfo/metainfo.cpp new file mode 100644 index 0000000000..0ebca52094 --- /dev/null +++ b/src/tools/metainfo/metainfo.cpp @@ -0,0 +1,199 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include <stdio.h> +#include <ctype.h> +#include <crtdbg.h> +#include <utilcode.h> +#include "mdinfo.h" +#include <ndpversion.h> + +// Provide custom LoadLibrary implementation. +#define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary +#define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE +#include "LegacyActivationShim.h" + +#ifdef FEATURE_PAL +#include <palstartupw.h> +#endif + +// Global variables +bool g_bSchema = false; +bool g_bRaw = false; +bool g_bDebug = false; +bool g_bHeader = false; + +// Validator module type. +DWORD g_ValModuleType = ValidatorModuleTypeInvalid; + +IMetaDataImport2 *g_pImport = NULL; +IMetaDataDispenserEx *g_pDisp = NULL; + +void DisplayFile(__in_z __in wchar_t* szFile, BOOL isFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjFile, strPassBackFn pDisplayString); +void DisplayArchive(__in_z __in wchar_t* szFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString); + +void PrintLogo() +{ + printf("Microsoft (R) .Net Frameworks Runtime Meta Data Dump Utility Version %s\n", VER_FILEVERSION_STR); + printf("%S", VER_LEGALCOPYRIGHT_LOGO_STR_L); + printf("\n"); +}// PrintLogo + +void Usage() +{ + printf("\n"); + printf("metainfo [-? | -header | -schema | -raw | -validate] [-nologo] [-obj <obj file name>] [<filname> | <file pattern>]\n"); + printf(" -? Displays this text.\n"); + printf(" -hex Prints more things in hex as well as words.\n"); + printf(" -header Prints MetaData header information and sizes.\n"); + printf(" -csv Prints the header sizes in Comma Separated format.\n"); + printf(" -unsat Prints unresolved externals.\n"); + printf(" -assem Prints only the Assembly information.\n"); + printf(" -schema Prints the MetaData schema information.\n"); + printf(" -raw Prints the raw MetaData tables.\n"); + printf(" -heaps Prints the raw heaps (only if -raw).\n"); + printf(" -names Prints string columns (only if -raw).\n"); + printf(" -validate Validate the consistency of the metadata.\n"); + printf(" -nologo Do not display the logo and MVID.\n"); + printf(" -obj <objFileName>\n"); + printf(" Prints the MetaData for the specified obj file in the given \n"); + printf(" archive(.lib) - e.g metainfo libc.lib -obj wMSILWinCRTStartup.obj\n"); + + MDInfo::Error(""); +} + +void DisplayString(__in_z __in const char *str) +{ + printf("%s", str); +} + +extern "C" int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv) +{ + wchar_t *pArg = NULL; + wchar_t *szObjName = NULL; + ULONG DumpFilter = MDInfo::dumpDefault; + HRESULT hr = 0; + BOOL fWantHelp=FALSE; + +#if FEATURE_PAL + if (!PAL_RegisterLibrary(L"rotor_palrt") || + !PAL_RegisterLibrary(L"sscoree")) + { + MDInfo::Error("Unable to register libraries", 1); + } +#endif // FEATURE_PAL + + // Validate incoming arguments + for (int i=1; i<argc; i++) + { + const wchar_t *szArg = argv[i]; + if (*szArg == L'-' || *szArg == L'/') + { + if (_wcsicmp(szArg + 1, L"?") == 0) + fWantHelp=TRUE; + + else if (_wcsicmp(szArg + 1, L"nologo") == 0) + DumpFilter |= MDInfo::dumpNoLogo; + + else if (_wcsicmp(szArg + 1, L"Hex") == 0) + DumpFilter |= MDInfo::dumpMoreHex; + + else if (_wcsicmp(szArg + 1, L"header") == 0) + DumpFilter |= MDInfo::dumpHeader; + + else if (_wcsicmp(szArg + 1, L"csv") == 0) + DumpFilter |= MDInfo::dumpCSV; + + else if (_wcsicmp(szArg + 1, L"raw") == 0) + DumpFilter |= MDInfo::dumpRaw; + + else if (_wcsicmp(szArg + 1, L"heaps") == 0) + DumpFilter |= MDInfo::dumpRawHeaps; + + else if (_wcsicmp(szArg + 1, L"names") == 0) + DumpFilter |= MDInfo::dumpNames; + + else if (_wcsicmp(szArg + 1, L"schema") == 0) + DumpFilter |= MDInfo::dumpSchema; + + else if (_wcsicmp(szArg + 1, L"unsat") == 0) + DumpFilter |= MDInfo::dumpUnsat; + + else if (_wcsicmp(szArg + 1, L"stats") == 0) + DumpFilter |= MDInfo::dumpStats; + + else if (_wcsicmp(szArg + 1, L"assem") == 0) + DumpFilter |= MDInfo::dumpAssem; + + else if (_wcsicmp(szArg + 1, L"validate") == 0) + DumpFilter |= MDInfo::dumpValidate; + + else if (_wcsicmp(szArg + 1, L"obj") == 0) + { + if (++i == argc) + Usage(); + else + szObjName = argv[i]; + } + } + else + pArg = argv[i]; + } + + // Print banner. + if (!(DumpFilter & MDInfo::dumpNoLogo)) + PrintLogo(); + + + if (!pArg || fWantHelp) + Usage(); + + +#ifndef FEATURE_PAL + // Init and run. + CoInitialize(0); +#endif + + LegacyActivationShim::CoInitializeCor(0); + + hr = LegacyActivationShim::ClrCoCreateInstance( + CLSID_CorMetaDataDispenser, NULL, CLSCTX_INPROC_SERVER, + IID_IMetaDataDispenserEx, (void **) &g_pDisp); + if(FAILED(hr)) MDInfo::Error("Unable to CoCreate Meta-data Dispenser", hr); + + // Loop through all files in the file pattern passed + WIN32_FIND_DATA fdFiles; + HANDLE hFind; + wchar_t szSpec[_MAX_PATH]; + wchar_t szDrive[_MAX_DRIVE]; + wchar_t szDir[_MAX_DIR]; + + hFind = WszFindFirstFile(pArg, &fdFiles); + + if (hFind == INVALID_HANDLE_VALUE) + { + DisplayFile(pArg, false, DumpFilter, szObjName, DisplayString); + } + else + { + // Convert relative paths to full paths. + LPWSTR szFname; + WszGetFullPathName(pArg, _MAX_PATH, szSpec, &szFname); + SplitPath(szSpec, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, NULL, 0, NULL, 0); + do + { + MakePath(szSpec, szDrive, szDir, fdFiles.cFileName, NULL); + // display the meta data of the file + DisplayFile(szSpec, true, DumpFilter, szObjName, DisplayString); + } while (WszFindNextFile(hFind, &fdFiles)) ; + FindClose(hFind); + } + g_pDisp->Release(); + LegacyActivationShim::CoUninitializeCor(); +#ifndef FEATURE_PAL + CoUninitialize(); +#endif + return 0; +} diff --git a/src/tools/metainfo/metainfo.nativeproj b/src/tools/metainfo/metainfo.nativeproj new file mode 100644 index 0000000000..7591a40d63 --- /dev/null +++ b/src/tools/metainfo/metainfo.nativeproj @@ -0,0 +1,42 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + <!--Leaf project Properties--> + <PropertyGroup> + <OutputName>metainfo</OutputName> + <FileToMarkForSigning>$(BinariesDirectory)\metainfo.exe</FileToMarkForSigning> + <TargetType>PROGRAM</TargetType> + <LinkSubsystem>console</LinkSubsystem> + <EntryPoint>wmain</EntryPoint> + <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions> + <LinkGenerateManifest>true</LinkGenerateManifest> + <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions> + </PropertyGroup> + <!--Leaf Project Items--> + <ItemGroup> + <LinkPreCrtLibs Include="$(ClrLibPath)\utilcodenohost.lib"> + <ProjectReference>$(ClrSrcDirectory)utilcode\dyncrtnohost\dyncrtnohost.nativeproj</ProjectReference> + </LinkPreCrtLibs> + <LinkPreCrtLibs Include="$(ClrLibPath)\MDHotData.lib" /> + + <TargetLib Include="$(ClrLibPath)\corguids.lib" /> + <TargetLib Include="$(SdkLibPath)\mscoree.lib" /> + <TargetLib Include="$(SdkLibPath)\ole32.lib" /> + <TargetLib Include="$(SdkLibPath)\user32.lib" /> + <TargetLib Include="$(SdkLibPath)\uuid.lib" /> + <TargetLib Include="$(SdkLibPath)\oleaut32.lib" /> + <ProjectReference Include="$(ClrSrcDirectory)md\hotdata\full\mdhotdata.nativeproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <RCResourceFile Include="native.rc" /> + </ItemGroup> + <ItemGroup> + <CppCompile Include="mdinfo.cpp" /> + <CppCompile Include="mdobj.cpp" /> + <CppCompile Include="metainfo.cpp" /> + </ItemGroup> + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> |